cloudy  trunk
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
maincl.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*main program that reads input and calls cloudy to compute a single model, or
4  * try to optimize an observed model. Routine returns 0 if model is ok,
5  * and 1 if problems occurred. */
6 #include "cddefines.h"
7 #include "cddrive.h"
8 #include "input.h"
9 #include "prt.h"
10 #include "punch.h"
11 #include "assertresults.h"
12 #include "grains.h"
13 
14 int main( int argc, char *argv[] )
15 {
16  /* these will be used to count number of various problems */
17  long int NumberWarnings,
18  NumberCautions,
19  NumberNotes,
20  NumberSurprises,
21  NumberTempFailures,
22  NumberPresFailures,
23  NumberIonFailures,
24  NumberNeFailures;
25 
26  bool lgAbort_exit,
27  lgFileIO,
28  lgBadExit;
29  /* number of lines we can still read in */
30  int nread=0;
31 
32  int i,
33  lenp,
34  leno,
35  leni,
36  lena;
37  char *s,
38  *prefix = NULL,
39  *filename,
40  outtag[] = ".out",
41  intag[] = ".in";
42 
43  /* the length of the following vector will be the longest line image
44  * the code will be able to read here. Cloudy itself will ignore anything
45  * beyond INPUT_LINE_LENGTH, and checks that no information exists beyond it.
46  * The code will stop if the input line is longer than INPUT_LINE_LENGTH
47  * since extra characters would become a new command line due to buffer overrun */
48  char chLine[INPUT_LINE_LENGTH];
49 
50  /* change following to true to write to debugging file */
51  lgFileIO = false;
52 
53  DEBUG_ENTRY( "main()" );
54 
55  try {
56  /*
57  * Handle argument input -- written generally, but presently handles
58  * only `-p prefix' or `-pprefix' to set input file as `prefix.in',
59  * output file as `prefix.out' and the punch prefix.
60  */
61  for(i=1; i<argc; i++)
62  {
63  s = argv[i];
64  if(*s != '-')
65  {
66  fprintf(stderr,"%s: argument %d `%s' not understood\n",argv[0],i,s);
67  cdEXIT( EXIT_FAILURE );
68  }
69  else
70  {
71  while (s != NULL && *(++s)) {
72  switch (*s)
73  {
74  case 'a':
75  cpu.setAssertAbort( true );
76  break;
77  case 'p':
78  if(s[1] != '\0')
79  {
80  prefix = s+1;
81  }
82  else
83  {
84  if(++i == argc || argv[i][0] == '-') {
85  fprintf(stderr,"%s: no argument given for -p flag\n",
86  argv[0]);
87  cdEXIT( EXIT_FAILURE );
88  }
89  prefix = argv[i];
90  }
91  s = NULL;
92  lgFileIO = true;
93  break;
94  default:
95  fprintf(stderr,"%s: argument %d, `%s': flag -%c not understood\n",
96  argv[0],i,argv[i],*s);
97  cdEXIT( EXIT_FAILURE );
98  }
99  }
100  }
101  }
102 
103  /* initialize the code for this run */
104  cdInit();
105 
106  /* following should be set true to print to file instead of std output */
107  if( lgFileIO )
108  {
109  FILE *ioOut, *ioInp;
110  if(prefix == NULL)
111  {
112  /* this is an option to direct code to a file rather than stdout*/
113  /* following used for passing output to temp file*/
114  if( (ioOut = fopen("c:\\projects\\cloudy\\tests\\CallCloudy.txt", "w" ))==NULL)
115  BadOpen();
116  cdOutp(ioOut);
117  }
118  else
119  {
120  leno = (int)strlen(outtag);
121  leni = (int)strlen(intag);
122  lenp = (int)strlen(prefix);
123  if(leno > leni)
124  lena = lenp+leno+1;
125  else
126  lena = lenp+leni+1;
127  filename = (char *)MALLOC((unsigned)lena*sizeof(char));
128  if(filename == NULL)
129  {
130  fprintf(stderr,"%s: can't allocate memory\n",argv[0]);
131  cdEXIT( EXIT_FAILURE );
132  }
133  strcpy(filename,prefix);
134  strcpy(filename+lenp,outtag);
135  if( (ioOut = fopen(filename, "w" ))==NULL)
136  BadOpen();
137  cdOutp(ioOut);
138  strcpy(filename+lenp,intag);
139  if( (ioInp = fopen(filename, "r" ))==NULL)
140  BadOpen();
141  cdInp(ioInp);
142  strcpy( punch.chFilenamePrefix , prefix );
143  free(filename);
144  }
145  }
146 
147  nread = 1;
148  /* keep reading input lines until end of file */
149  while( read_whole_line(chLine, (int)sizeof(chLine), ioStdin)!= NULL )
150  {
151  char *chChar;
152  /* when running from command prompt, last line can be \n or
153  * \r (this can happen with gcc under cygwin in windows)
154  * or space, so check for each here, and break if present,
155  * check on chLine[23] is for case where we are reading cloudy output */
156  /*fprintf(ioQQQ,"DEBUG char0 %i\n", (int)chLine[0] );*/
157  if( chLine[0] == '\n' || chLine[0] == '\r' ||
158  ( chLine[0] == ' ' && chLine[23] != '*' ) )
159  break;
160 
161  /* read entire line of input - lgAbort set true if lines too long */
162  if( !lgInputComment(chLine) )
163  {
164 
165  if( (chChar = strchr(chLine , '\"' ) ) ==NULL )
166  {
167  /* check for underscore, probably meant as a space */
168  while( (chChar = strchr(chLine , '_' ) ) !=NULL )
169  {
170  *chChar = ' ';
171  input.lgUnderscoreFound = true;
172  }
173  }
174 
175  /* change _, [, and ] to space if no filename occurs on line
176  * >>chng 06 sep 04 use routine to check for comments
177  * do not remove _, [, and ] in comments */
178  /* check for left or right bracket, probably meant as a space */
179  while( (chChar = strchr(chLine , '[' ) ) !=NULL )
180  {
181  *chChar = ' ';
182  input.lgBracketFound = true;
183  }
184 
185  while( (chChar = strchr(chLine , ']' ) ) !=NULL )
186  {
187  *chChar = ' ';
188  input.lgBracketFound = true;
189  }
190  }
191 
192  /* this is trick so that cloudy input can read cloudy output */
193  /* are first 25 char of input string equal to output? */
194  if( strncmp(chLine," * ",25) == 0 )
195  {
196  /* reading cloudy output, send in shifted input */
197  nread = cdRead( chLine+25 );
198  }
199  else
200  {
201  /* stuff the command line into the internal stack */
202  nread = cdRead( chLine );
203  }
204  }
205 
206  if( lgAbort )
207  {
208  /* input parser hit something REALLY bad */
209  lgBadExit = true;
210  return(lgBadExit);
211  }
212 
213  if( nread <= 0 )
214  fprintf(ioQQQ," Warning: limit to number of lines exceeded, %i\n", nread);
215 
216  /* actually call the code. This routine figures out whether the code will do
217  * a single model or be used to optimize on a spectrum, by looking for the
218  * keyword VARY on command lines. It will call routine cloudy if no vary commands
219  * occur, and lgOptimize_do if VARY does occur.
220  * cdDrive returns 0 if calculation is ok, 1 if problems happened */
221  if( cdDrive() )
222  lgBadExit = true;
223  else
224  lgBadExit = false;
225 
226  /* the last line of output will contain some interesting information about the model*/
227  cdNwcns(
228  /* abort status, this better be false, 0 */
229  &lgAbort_exit,
230  /* the number of warnings, cautions, notes, and surprises */
231  &NumberWarnings,
232  &NumberCautions,
233  &NumberNotes,
234  &NumberSurprises,
235  /* the number of temperature convergence failures */
236  &NumberTempFailures,
237  /* the number of pressure convergence failures */
238  &NumberPresFailures,
239  /* the number of ionization convergence failures */
240  &NumberIonFailures,
241  /* the number of electron density convergence failures */
242  &NumberNeFailures );
243 
244  fprintf( ioQQQ,
245  " Cloudy ends:%4ld zone" ,
246  nzone);
247 
248  /* put an s in iteration if more than one */
249  if( nzone > 1 )
250  fprintf( ioQQQ,"s");
251 
252  fprintf( ioQQQ,
253  ", %3ld iteration" ,
254  iteration );
255 
256  /* put an s in iteration if more than one */
257  if( iteration > 1 )
258  fprintf( ioQQQ,"s");
259 
260  if( lgAbort_exit )
261  {
262  fprintf( ioQQQ,
263  ", ABORT DISASTER PROBLEM" );
264  }
265 
266  if( NumberWarnings > 0 )
267  {
268  fprintf( ioQQQ,
269  ",%3ld warning",
270  NumberWarnings);
271 
272  /* put an s in iteration if more than one */
273  if( NumberWarnings > 1 )
274  {
275  fprintf( ioQQQ,"s");
276  }
277  /* this indicates error */
278  lgBadExit = 1;
279  }
280 
281  if( NumberCautions > 0 )
282  {
283  fprintf( ioQQQ,
284  ",%3ld caution",
285  NumberCautions);
286 
287  /* put an s in iteration if more than one */
288  if( NumberCautions > 1 )
289  fprintf( ioQQQ,"s");
290  }
291 
292  /* this flag was set in lgCheckAsserts*/
293  if( !lgAssertsOK )
294  {
295  fprintf(ioQQQ,", ");
296  /* some botches were three sigma */
297  if( lgBigBotch )
298  fprintf(ioQQQ,"BIG ");
299  fprintf(ioQQQ,"BOTCHED ASSERTS!!!");
300  /* this indicates error */
301  lgBadExit = 1;
302  }
303 
304  if( NumberTempFailures+NumberPresFailures +NumberIonFailures+NumberNeFailures >0 )
305  {
306  fprintf( ioQQQ,
307  ". Failures:%3ld thermal,%3ld pressure,%3ld ionization,%3ld electron density",
308  NumberTempFailures,
309  NumberPresFailures ,
310  NumberIonFailures,
311  NumberNeFailures);
312  }
313 
314  /* NB DO NOT CHANGE ANY ASPECT OF THE FOLLOWING STRINGS - THEY ARE USED TO RECORD
315  * EXEC TIME BY A PERL SCRIPT */
316  if( prt.lgPrintTime )
317  {
318  /* print execution time [s] by default,
319  * need spaces around number so that logging perl script picks up correct number
320  * ir_extime.pl script will delete through "ExecTime(s)" and remainder of line must be number */
321  fprintf( ioQQQ, ". ExecTime(s) %.2f", cdExecTime());
322  }
323 
324  fprintf( ioQQQ, "\n");
325 
326  /* return memory used by the grains */
327  ReturnGrainBins();
328 
329  /* cdDrive returned 1 if something bad happened, and 0 if everything is ok. We will
330  * return 0 if everything is ok, and 1 if something bad happened.*/
331  cdEXIT(lgBadExit);
332  }
333  catch( bad_alloc )
334  {
335  fprintf( ioQQQ, " DISASTER - A memory allocation has failed. Bailing out...\n" );
336  cdExit(EXIT_FAILURE);
337  }
338  catch( out_of_range& e )
339  {
340  fprintf( ioQQQ, " DISASTER - An out_of_range exception was caught, what() = %s. Bailing out...\n",
341  e.what() );
342  cdExit(EXIT_FAILURE);
343  }
344  catch( bad_assert& e )
345  {
346  MyAssert( e.file(), e.line() );
347  cdExit(EXIT_FAILURE);
348  }
349 #ifdef CATCH_SIGNAL
350  catch( bad_signal& e )
351  {
352  if( ioQQQ != NULL )
353  {
354  if( e.sig() == SIGINT )
355  fprintf( ioQQQ, " User interrupt request. Bailing out...\n" );
356  else if( e.sig() == SIGTERM )
357  fprintf( ioQQQ, " Termination request. Bailing out...\n" );
358  else if( e.sig() == SIGILL )
359  fprintf( ioQQQ, " DISASTER - An illegal instruction was found. Bailing out...\n" );
360  else if( e.sig() == SIGFPE )
361  fprintf( ioQQQ, " DISASTER - A floating point exception occurred. Bailing out...\n" );
362  else if( e.sig() == SIGSEGV )
363  fprintf( ioQQQ, " DISASTER - A segmentation violation occurred. Bailing out...\n" );
364 # ifdef SIGBUS
365  else if( e.sig() == SIGBUS )
366  fprintf( ioQQQ, " DISASTER - A bus error occurred. Bailing out...\n" );
367 # endif
368  else
369  fprintf( ioQQQ, " DISASTER - A signal %d was caught. Bailing out...\n", e.sig() );
370 
371  }
372  cdExit(EXIT_FAILURE);
373  }
374 #endif
375  catch( cloudy_exit& e )
376  {
377  if( ioQQQ != NULL )
378  {
379  ostringstream oss;
380  oss << " [Stop in " << e.routine();
381  oss << " at " << e.file() << ":" << e.line();
382  if( e.exit_status() == 0 )
383  oss << ", Cloudy exited OK]";
384  else
385  oss << ", something went wrong]";
386  fprintf( ioQQQ, "%s\n", oss.str().c_str() );
387  }
388  cdExit(e.exit_status());
389  }
390  catch( std::exception& e )
391  {
392  fprintf( ioQQQ, " DISASTER - An unknown exception was caught, what() = %s. Bailing out...\n",
393  e.what() );
394  cdExit(EXIT_FAILURE);
395  }
396  // generic catch-all in case we forget any specific exception above... so this MUST be the last one.
397  catch( ... )
398  {
399  fprintf( ioQQQ, " DISASTER - An unknown exception was caught. Bailing out...\n" );
400  cdExit(EXIT_FAILURE);
401  }
402 }

Generated for cloudy by doxygen 1.8.1.1