cloudy trunk
|
00001 /* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and 00002 * others. For conditions of distribution and use see copyright notice in license.txt */ 00003 /*main program that reads input and calls cloudy to compute a single model, or 00004 * try to optimize an observed model. Routine returns 0 if model is ok, 00005 * and 1 if problems occurred. */ 00006 #include "cddefines.h" 00007 #include "cddrive.h" 00008 #include "input.h" 00009 #include "prt.h" 00010 #include "punch.h" 00011 #include "assertresults.h" 00012 #include "grains.h" 00013 00014 int main( int argc, char *argv[] ) 00015 { 00016 /* these will be used to count number of various problems */ 00017 long int NumberWarnings, 00018 NumberCautions, 00019 NumberNotes, 00020 NumberSurprises, 00021 NumberTempFailures, 00022 NumberPresFailures, 00023 NumberIonFailures, 00024 NumberNeFailures; 00025 00026 bool lgAbort_exit, 00027 lgFileIO, 00028 lgBadExit; 00029 /* number of lines we can still read in */ 00030 int nread=0; 00031 00032 int i, 00033 lenp, 00034 leno, 00035 leni, 00036 lena; 00037 char *s, 00038 *prefix = NULL, 00039 *filename, 00040 outtag[] = ".out", 00041 intag[] = ".in"; 00042 00043 /* the length of the following vector will be the longest line image 00044 * the code will be able to read here. Cloudy itself will ignore anything 00045 * beyond INPUT_LINE_LENGTH, and checks that no information exists beyond it. 00046 * The code will stop if the input line is longer than INPUT_LINE_LENGTH 00047 * since extra characters would become a new command line due to buffer overrun */ 00048 char chLine[INPUT_LINE_LENGTH]; 00049 00050 /* change following to true to write to debugging file */ 00051 lgFileIO = false; 00052 00053 DEBUG_ENTRY( "main()" ); 00054 00055 try { 00056 /* 00057 * Handle argument input -- written generally, but presently handles 00058 * only `-p prefix' or `-pprefix' to set input file as `prefix.in', 00059 * output file as `prefix.out' and the punch prefix. 00060 */ 00061 for(i=1; i<argc; i++) 00062 { 00063 s = argv[i]; 00064 if(*s != '-') 00065 { 00066 fprintf(stderr,"%s: argument %d `%s' not understood\n",argv[0],i,s); 00067 cdEXIT( EXIT_FAILURE ); 00068 } 00069 else 00070 { 00071 while (s != NULL && *(++s)) { 00072 switch (*s) 00073 { 00074 case 'a': 00075 cpu.setAssertAbort( true ); 00076 break; 00077 case 'p': 00078 if(s[1] != '\0') 00079 { 00080 prefix = s+1; 00081 } 00082 else 00083 { 00084 if(++i == argc || argv[i][0] == '-') { 00085 fprintf(stderr,"%s: no argument given for -p flag\n", 00086 argv[0]); 00087 cdEXIT( EXIT_FAILURE ); 00088 } 00089 prefix = argv[i]; 00090 } 00091 s = NULL; 00092 lgFileIO = true; 00093 break; 00094 default: 00095 fprintf(stderr,"%s: argument %d, `%s': flag -%c not understood\n", 00096 argv[0],i,argv[i],*s); 00097 cdEXIT( EXIT_FAILURE ); 00098 } 00099 } 00100 } 00101 } 00102 00103 /* initialize the code for this run */ 00104 cdInit(); 00105 00106 /* following should be set true to print to file instead of std output */ 00107 if( lgFileIO ) 00108 { 00109 FILE *ioOut, *ioInp; 00110 if(prefix == NULL) 00111 { 00112 /* this is an option to direct code to a file rather than stdout*/ 00113 /* following used for passing output to temp file*/ 00114 if( (ioOut = fopen("c:\\projects\\cloudy\\tests\\CallCloudy.txt", "w" ))==NULL) 00115 BadOpen(); 00116 cdOutp(ioOut); 00117 } 00118 else 00119 { 00120 leno = (int)strlen(outtag); 00121 leni = (int)strlen(intag); 00122 lenp = (int)strlen(prefix); 00123 if(leno > leni) 00124 lena = lenp+leno+1; 00125 else 00126 lena = lenp+leni+1; 00127 filename = (char *)MALLOC((unsigned)lena*sizeof(char)); 00128 if(filename == NULL) 00129 { 00130 fprintf(stderr,"%s: can't allocate memory\n",argv[0]); 00131 cdEXIT( EXIT_FAILURE ); 00132 } 00133 strcpy(filename,prefix); 00134 strcpy(filename+lenp,outtag); 00135 if( (ioOut = fopen(filename, "w" ))==NULL) 00136 BadOpen(); 00137 cdOutp(ioOut); 00138 strcpy(filename+lenp,intag); 00139 if( (ioInp = fopen(filename, "r" ))==NULL) 00140 BadOpen(); 00141 cdInp(ioInp); 00142 strcpy( punch.chFilenamePrefix , prefix ); 00143 free(filename); 00144 } 00145 } 00146 00147 nread = 1; 00148 /* keep reading input lines until end of file */ 00149 while( read_whole_line(chLine, (int)sizeof(chLine), ioStdin)!= NULL ) 00150 { 00151 char *chChar; 00152 /* when running from command prompt, last line can be \n or 00153 * \r (this can happen with gcc under cygwin in windows) 00154 * or space, so check for each here, and break if present, 00155 * check on chLine[23] is for case where we are reading cloudy output */ 00156 /*fprintf(ioQQQ,"DEBUG char0 %i\n", (int)chLine[0] );*/ 00157 if( chLine[0] == '\n' || chLine[0] == '\r' || 00158 ( chLine[0] == ' ' && chLine[23] != '*' ) ) 00159 break; 00160 00161 /* read entire line of input - lgAbort set true if lines too long */ 00162 if( !lgInputComment(chLine) ) 00163 { 00164 00165 if( (chChar = strchr(chLine , '\"' ) ) ==NULL ) 00166 { 00167 /* check for underscore, probably meant as a space */ 00168 while( (chChar = strchr(chLine , '_' ) ) !=NULL ) 00169 { 00170 *chChar = ' '; 00171 input.lgUnderscoreFound = true; 00172 } 00173 } 00174 00175 /* change _, [, and ] to space if no filename occurs on line 00176 * >>chng 06 sep 04 use routine to check for comments 00177 * do not remove _, [, and ] in comments */ 00178 /* check for left or right bracket, probably meant as a space */ 00179 while( (chChar = strchr(chLine , '[' ) ) !=NULL ) 00180 { 00181 *chChar = ' '; 00182 input.lgBracketFound = true; 00183 } 00184 00185 while( (chChar = strchr(chLine , ']' ) ) !=NULL ) 00186 { 00187 *chChar = ' '; 00188 input.lgBracketFound = true; 00189 } 00190 } 00191 00192 /* this is trick so that cloudy input can read cloudy output */ 00193 /* are first 25 char of input string equal to output? */ 00194 if( strncmp(chLine," * ",25) == 0 ) 00195 { 00196 /* reading cloudy output, send in shifted input */ 00197 nread = cdRead( chLine+25 ); 00198 } 00199 else 00200 { 00201 /* stuff the command line into the internal stack */ 00202 nread = cdRead( chLine ); 00203 } 00204 } 00205 00206 if( lgAbort ) 00207 { 00208 /* input parser hit something REALLY bad */ 00209 lgBadExit = true; 00210 return(lgBadExit); 00211 } 00212 00213 if( nread <= 0 ) 00214 fprintf(ioQQQ," Warning: limit to number of lines exceeded, %i\n", nread); 00215 00216 /* actually call the code. This routine figures out whether the code will do 00217 * a single model or be used to optimize on a spectrum, by looking for the 00218 * keyword VARY on command lines. It will call routine cloudy if no vary commands 00219 * occur, and lgOptimize_do if VARY does occur. 00220 * cdDrive returns 0 if calculation is ok, 1 if problems happened */ 00221 if( cdDrive() ) 00222 lgBadExit = true; 00223 else 00224 lgBadExit = false; 00225 00226 /* the last line of output will contain some interesting information about the model*/ 00227 cdNwcns( 00228 /* abort status, this better be false, 0 */ 00229 &lgAbort_exit, 00230 /* the number of warnings, cautions, notes, and surprises */ 00231 &NumberWarnings, 00232 &NumberCautions, 00233 &NumberNotes, 00234 &NumberSurprises, 00235 /* the number of temperature convergence failures */ 00236 &NumberTempFailures, 00237 /* the number of pressure convergence failures */ 00238 &NumberPresFailures, 00239 /* the number of ionization convergence failures */ 00240 &NumberIonFailures, 00241 /* the number of electron density convergence failures */ 00242 &NumberNeFailures ); 00243 00244 fprintf( ioQQQ, 00245 " Cloudy ends:%4ld zone" , 00246 nzone); 00247 00248 /* put an s in iteration if more than one */ 00249 if( nzone > 1 ) 00250 fprintf( ioQQQ,"s"); 00251 00252 fprintf( ioQQQ, 00253 ", %3ld iteration" , 00254 iteration ); 00255 00256 /* put an s in iteration if more than one */ 00257 if( iteration > 1 ) 00258 fprintf( ioQQQ,"s"); 00259 00260 if( lgAbort_exit ) 00261 { 00262 fprintf( ioQQQ, 00263 ", ABORT DISASTER PROBLEM" ); 00264 } 00265 00266 if( NumberWarnings > 0 ) 00267 { 00268 fprintf( ioQQQ, 00269 ",%3ld warning", 00270 NumberWarnings); 00271 00272 /* put an s in iteration if more than one */ 00273 if( NumberWarnings > 1 ) 00274 { 00275 fprintf( ioQQQ,"s"); 00276 } 00277 /* this indicates error */ 00278 lgBadExit = 1; 00279 } 00280 00281 if( NumberCautions > 0 ) 00282 { 00283 fprintf( ioQQQ, 00284 ",%3ld caution", 00285 NumberCautions); 00286 00287 /* put an s in iteration if more than one */ 00288 if( NumberCautions > 1 ) 00289 fprintf( ioQQQ,"s"); 00290 } 00291 00292 /* this flag was set in lgCheckAsserts*/ 00293 if( !lgAssertsOK ) 00294 { 00295 fprintf(ioQQQ,", "); 00296 /* some botches were three sigma */ 00297 if( lgBigBotch ) 00298 fprintf(ioQQQ,"BIG "); 00299 fprintf(ioQQQ,"BOTCHED ASSERTS!!!"); 00300 /* this indicates error */ 00301 lgBadExit = 1; 00302 } 00303 00304 if( NumberTempFailures+NumberPresFailures +NumberIonFailures+NumberNeFailures >0 ) 00305 { 00306 fprintf( ioQQQ, 00307 ". Failures:%3ld thermal,%3ld pressure,%3ld ionization,%3ld electron density", 00308 NumberTempFailures, 00309 NumberPresFailures , 00310 NumberIonFailures, 00311 NumberNeFailures); 00312 } 00313 00314 /* NB DO NOT CHANGE ANY ASPECT OF THE FOLLOWING STRINGS - THEY ARE USED TO RECORD 00315 * EXEC TIME BY A PERL SCRIPT */ 00316 if( prt.lgPrintTime ) 00317 { 00318 /* print execution time [s] by default, 00319 * need spaces around number so that logging perl script picks up correct number 00320 * ir_extime.pl script will delete through "ExecTime(s)" and remainder of line must be number */ 00321 fprintf( ioQQQ, ". ExecTime(s) %.2f", cdExecTime()); 00322 } 00323 00324 fprintf( ioQQQ, "\n"); 00325 00326 /* return memory used by the grains */ 00327 ReturnGrainBins(); 00328 00329 /* cdDrive returned 1 if something bad happened, and 0 if everything is ok. We will 00330 * return 0 if everything is ok, and 1 if something bad happened.*/ 00331 cdEXIT(lgBadExit); 00332 } 00333 catch( bad_alloc ) 00334 { 00335 fprintf( ioQQQ, " DISASTER - A memory allocation has failed. Bailing out...\n" ); 00336 cdExit(EXIT_FAILURE); 00337 } 00338 catch( out_of_range& e ) 00339 { 00340 fprintf( ioQQQ, " DISASTER - An out_of_range exception was caught, what() = %s. Bailing out...\n", 00341 e.what() ); 00342 cdExit(EXIT_FAILURE); 00343 } 00344 catch( bad_assert& e ) 00345 { 00346 MyAssert( e.file(), e.line() ); 00347 cdExit(EXIT_FAILURE); 00348 } 00349 #ifdef CATCH_SIGNAL 00350 catch( bad_signal& e ) 00351 { 00352 if( ioQQQ != NULL ) 00353 { 00354 if( e.sig() == SIGINT ) 00355 fprintf( ioQQQ, " User interrupt request. Bailing out...\n" ); 00356 else if( e.sig() == SIGTERM ) 00357 fprintf( ioQQQ, " Termination request. Bailing out...\n" ); 00358 else if( e.sig() == SIGILL ) 00359 fprintf( ioQQQ, " DISASTER - An illegal instruction was found. Bailing out...\n" ); 00360 else if( e.sig() == SIGFPE ) 00361 fprintf( ioQQQ, " DISASTER - A floating point exception occurred. Bailing out...\n" ); 00362 else if( e.sig() == SIGSEGV ) 00363 fprintf( ioQQQ, " DISASTER - A segmentation violation occurred. Bailing out...\n" ); 00364 # ifdef SIGBUS 00365 else if( e.sig() == SIGBUS ) 00366 fprintf( ioQQQ, " DISASTER - A bus error occurred. Bailing out...\n" ); 00367 # endif 00368 else 00369 fprintf( ioQQQ, " DISASTER - A signal %d was caught. Bailing out...\n", e.sig() ); 00370 00371 } 00372 cdExit(EXIT_FAILURE); 00373 } 00374 #endif 00375 catch( cloudy_exit& e ) 00376 { 00377 if( ioQQQ != NULL ) 00378 { 00379 ostringstream oss; 00380 oss << " [Stop in " << e.routine(); 00381 oss << " at " << e.file() << ":" << e.line(); 00382 if( e.exit_status() == 0 ) 00383 oss << ", Cloudy exited OK]"; 00384 else 00385 oss << ", something went wrong]"; 00386 fprintf( ioQQQ, "%s\n", oss.str().c_str() ); 00387 } 00388 cdExit(e.exit_status()); 00389 } 00390 catch( std::exception& e ) 00391 { 00392 fprintf( ioQQQ, " DISASTER - An unknown exception was caught, what() = %s. Bailing out...\n", 00393 e.what() ); 00394 cdExit(EXIT_FAILURE); 00395 } 00396 // generic catch-all in case we forget any specific exception above... so this MUST be the last one. 00397 catch( ... ) 00398 { 00399 fprintf( ioQQQ, " DISASTER - An unknown exception was caught. Bailing out...\n" ); 00400 cdExit(EXIT_FAILURE); 00401 } 00402 }