cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cddrive.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2022 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*cdDrive main routine to call cloudy under all circumstances) */
4 /*cdReasonGeo write why the model stopped and type of geometry on io file */
5 /*cdWarnings write all warnings entered into comment stack */
6 /*cdEms obtain the local emissivity for a line, for the last computed zone */
7 /*cdColm get the column density for a constituent */
8 /*cdLine get the predicted line intensity, also index for line in stack */
9 /*cdLine_ip get the predicted line intensity, using index for line in stack */
10 /*cdCautions print out all cautions after calculation, on arbitrary io unit */
11 /*cdTemp_last routine to query results and return temperature of last zone */
12 /*cdDepth_depth get depth structure from previous iteration */
13 /*cdTimescales returns thermal, recombination, and H2 formation timescales */
14 /*cdSurprises print out all surprises on arbitrary unit number */
15 /*cdNotes print stack of notes about current calculation */
16 /*cdPressure_last routine to query results and return pressure of last zone */
17 /*cdTalk tells the code whether to print results or be silent */
18 /*cdOutput redirect output to arbitrary file */
19 /*cdInput redirect input from arbitrary file */
20 /*cdRead routine to read in command lines when cloudy used as subroutine */
21 /*cdErrors produce summary of all warnings, cautions, etc, on arbitrary io unit */
22 /*cdIonFrac get ionization fractions for a constituent */
23 /*cdTemp get mean electron temperature for any element */
24 /*cdCooling_last routine to query results and return cooling of last zone */
25 /*cdHeating_last routine to query results and return heating of last zone */
26 /*cdEDEN_last return electron density of last zone */
27 /*cdNoExec call this routine to tell code not to actually execute */
28 /*cdDate - puts date of code into string */
29 /*cdVersion produces string that gives version number of the code */
30 /*cdExecTime any routine can call this, find the time [s] since cdInit was called */
31 /*cdPrintCommands( FILE *) prints all input commands into file */
32 /*cdDrive main routine to call cloudy under all circumstances) */
33 /*cdNwcns get the number of cautions and warnings, to tell if calculation is ok */
34 /*debugLine provides a debugging hook into the main line array */
35 /*cdEms_ip obtain the local emissivity for a line with known index */
36 /*cdnZone gets number of zones */
37 /*cdClosePunchFiles closes all the save files that have been used */
38 /*cdB21cm - returns B as measured by 21 cm */
39 /*cdPrtWL print line wavelengths in Angstroms in the standard format */
40 #include "cddefines.h"
41 #include "cddrive.h"
42 
43 #include "trace.h"
44 #include "conv.h"
45 #include "init.h"
46 #include "lines.h"
47 #include "pressure.h"
48 #include "dense.h"
49 #include "radius.h"
50 #include "struc.h"
51 #include "mole.h"
52 #include "elementnames.h"
53 #include "mean.h"
54 #include "phycon.h"
55 #include "called.h"
56 #include "parse.h"
57 #include "input.h"
58 #include "taulines.h"
59 #include "version.h"
60 #include "thermal.h"
61 #include "grid.h"
62 #include "timesc.h"
63 #include "cloudy.h"
64 #include "warnings.h"
65 #include "broke.h"
66 #include "iso.h"
67 #include "save.h"
68 #include "rfield.h"
69 #include "lines_service.h"
70 #include "service.h"
71 #include "parser.h"
72 #include "generic_state.h"
73 #include "prt.h"
74 
75 /*************************************************************************
76  *
77  * cdDrive - main routine to call cloudy - returns 0 if all ok, 1 if problems
78  *
79  ************************************************************************/
80 
81 int cdDrive()
82 {
83  bool lgBAD;
84 
85  DEBUG_ENTRY( "cdDrive()" );
86  /*********************************
87  * main routine to call cloudy *
88  *********************************/
89 
90  /* this is set false when code loaded, set true when cdInit called,
91  * this is check that cdInit was called first */
92  if( !lgcdInitCalled )
93  {
94  printf(" cdInit was not called first - this must be the first call.\n");
96  }
97 
98  if( trace.lgTrace )
99  {
100  fprintf( ioQQQ,
101  "cdDrive: lgOptimr=%1i lgVaryOn=%1i lgNoVary=%1i input.nSave:%li\n",
103  }
104 
105  /* should we call cloudy, or the optimization driver?
106  * possible to have VARY on line without OPTIMIZE being set
107  * lgNoVary set with "no optimize" command */
109  optimize.lgVaryOn = true;
110  else
111  optimize.lgVaryOn = false;
112 
113  /* set up the frequency mesh, the SET CONTINUUM RESOLUTION factor was already parsed in cdRead() */
114  /* the bool 'false' inidicates that the cell for the unit test is the highest entry in the regular mesh */
115  rfield.InitMesh(false);
117  /* there must be a cell above nflux for us to pass unity through the vol integrator */
118  /*>>chng 04 oct 10, from nflux = nupper to nupper-1 since vectors must malloc to nupper, but
119  * will address [nflux] for unit continuum test */
122 
123  /* one time initialization of core load - returns if already called
124  * called here rather than in cdInit since at this point we know if
125  * single sim or grid */
126  InitCoreload();
127 
128  if( optimize.lgVaryOn )
129  {
130  /* this branch called if optimizing or grid calculation */
131  if( trace.lgTrace )
132  fprintf( ioQQQ, "cdDrive: calling grid_do\n");
133  /* option to drive optimizer set if OPTIMIZE was in input stream */
134  lgBAD = grid_do();
135  }
136  else
137  {
138  if( trace.lgTrace )
139  fprintf( ioQQQ, "cdDrive: calling cloudy\n");
140 
141  /* optimize did not occur, only compute one model, call cloudy */
142  lgBAD = cloudy();
143  }
144 
145  /* reset flag saying that cdInit has not been called */
146  lgcdInitCalled = false;
147 
148  if( lgAbort || lgBAD )
149  {
150  if( trace.lgTrace )
151  fprintf( ioQQQ, "cdDrive: returning failure during call. \n");
152  /* lgAbort set true if something wrong, so return lgBAD false. */
153  return 1;
154  }
155  else
156  {
157  /* everything is ok, return 0 */
158  return 0;
159  }
160 }
161 
162 
163 /*************************************************************************
164  *
165  * cdReasonGeo write why the model stopped and type of geometry on io file
166  *
167  ************************************************************************/
168 
169 /*cdReasonGeo write why the model stopped and type of geometry on io file */
170 void cdReasonGeo(FILE * ioOUT)
171 {
172 
173  DEBUG_ENTRY( "cdReasonGeo()" );
174 
175  /*this is the reason the calculation stopped*/
176  fprintf( ioOUT, "%s", warnings.chRgcln[0] );
177  fprintf( ioOUT , "\n" );
178  /* this is the geometry */
179  fprintf( ioOUT, "%s", warnings.chRgcln[1] );
180  fprintf( ioOUT , "\n" );
181  return;
182 }
183 
184 
185 /*************************************************************************
186  *
187  * cdWarnings write all warnings entered into comment stack
188  *
189  ************************************************************************/
190 
191 /*cdWarnings write all warnings entered into comment stack */
192 void cdWarnings(FILE *ioPNT )
193 {
194  long int i;
195 
196  DEBUG_ENTRY( "cdWarnings()" );
197 
198  if( warnings.nwarn > 0 )
199  {
200  for( i=0; i < warnings.nwarn; i++ )
201  {
202  /* these are all warnings that were entered in comment */
203  fprintf( ioPNT, "%s", warnings.chWarnln[i] );
204  fprintf( ioPNT, "\n" );
205  }
206  }
207 
208  return;
209 }
210 
211 
212 /*************************************************************************
213  *
214  * cdCautions print out all cautions after calculation, on arbitrary io unit
215  *
216  ************************************************************************/
217 
218 /*cdCautions print out all cautions after calculation, on arbitrary io unit */
219 void cdCautions(FILE * ioOUT)
220 {
221  long int i;
222 
223  DEBUG_ENTRY( "cdCautions()" );
224 
225  if( warnings.ncaun > 0 )
226  {
227  for( i=0; i < warnings.ncaun; i++ )
228  {
229  fprintf( ioOUT, "%s", warnings.chCaunln[i] );
230  fprintf( ioOUT, "\n" );
231  }
232  }
233  return;
234 }
235 
236 /*************************************************************************
237  *
238  * cdTimescales returns thermal, recombination, and H2 formation timescales
239  *
240  ************************************************************************/
241 
243  /* the thermal cooling timescale */
244  double *TTherm ,
245  /* the hydrogen recombination timescale */
246  double *THRecom ,
247  /* the H2 formation timescale */
248  double *TH2 )
249 {
250 
251  DEBUG_ENTRY( "cdTimescales()" );
252 
253  /* these were all evaluated in AgeCheck, which was called by PrtComment */
254 
255  /* thermal or cooling timescale */
256  *TTherm = timesc.time_therm_long;
257 
258  /* the hydrogen recombination timescale */
259  *THRecom = timesc.time_Hrecom_long;
260 
261  /* longer of the the H2 formation and destruction timescales */
263  return;
264 }
265 
266 
267 /*************************************************************************
268  *
269  * cdSurprises print out all surprises on arbitrary unit number
270  *
271  ************************************************************************/
272 
273 /*cdSurprises print out all surprises on arbitrary unit number */
274 void cdSurprises(FILE * ioOUT)
275 {
276  long int i;
277 
278  DEBUG_ENTRY( "cdSurprises()" );
279 
280  if( warnings.nbang > 0 )
281  {
282  for( i=0; i < warnings.nbang; i++ )
283  {
284  fprintf( ioOUT, "%s\n", warnings.chBangln[i] );
285  }
286  }
287 
288  if ( broke.lgPrintFixits )
289  {
290  fprintf (ioOUT, "\nActive fixits for this run\n");
291  for (vector<string>::iterator it = FixitList::Inst().list.begin();
292  it != FixitList::Inst().list.end(); ++it)
293  {
294  fprintf(ioOUT,"%s\n",it->c_str());
295  }
296  fprintf (ioOUT, "\n");
297  }
298 
299  return;
300 }
301 
302 
303 /*************************************************************************
304  *
305  * cdNotes print stack of notes about current calculation
306  *
307  ************************************************************************/
308 
309 /*cdNotes print stack of notes about current calculation */
310 void cdNotes(FILE * ioOUT)
311 {
312  long int i;
313 
314  DEBUG_ENTRY( "cdNotes()" );
315 
316  if( warnings.nnote > 0 )
317  {
318  for( i=0; i < warnings.nnote; i++ )
319  {
320  fprintf( ioOUT, "%s", warnings.chNoteln[i] );
321  fprintf( ioOUT, "\n" );
322  }
323  }
324  return;
325 }
326 
327 /*************************************************************************
328  *
329  * cdCooling_last routine to query results and return cooling of last zone
330  *
331  ************************************************************************/
332 
333 /*cdCooling_last routine to query results and return cooling of last zone */
334 double cdCooling_last() /* return cooling for last zone */
335 {
336  return thermal.ctot;
337 }
338 
339 /*************************************************************************
340  *
341  * cdVersion - puts version number of code into string
342  * incoming string must have sufficient length and will become null
343  * terminated string
344  *
345  ************************************************************************/
346 
347 void cdVersion(char chString[])
348 {
349  strcpy( chString , t_version::Inst().chVersion );
350  return;
351 }
352 
353 /*************************************************************************
354  *
355  * cdDate - puts date of code into string
356  * incoming string must have at least 8 char and will become null
357  * terminated string
358  *
359  ************************************************************************/
360 
361 /* cdDate - puts date of code into string */
362 void cdDate(char chString[])
363 {
364  strcpy( chString , t_version::Inst().chDate );
365  return;
366 }
367 
368 
369 /*************************************************************************
370  *
371  * cdHeating_last routine to query results and return heating of last zone
372  *
373  ************************************************************************/
374 
375 /*cdHeating_last routine to query results and return heating of last zone */
376 double cdHeating_last() /* return heating for last zone */
377 {
378  return thermal.htot;
379 }
380 
381 
382 /*************************************************************************
383  *
384  * cdEDEN_last return electron density of last zone
385  *
386  ************************************************************************/
387 
388 /*cdEDEN_last return electron density of last zone */
389 double cdEDEN_last() /* return electron density for last zone */
390 {
391  return dense.eden;
392 }
393 
394 /*************************************************************************
395  *
396  * cdNoExec call this routine to tell code not to actually execute
397  *
398  ************************************************************************/
399 
400 /*cdNoExec call this routine to tell code not to actually execute */
401 #include "noexec.h"
402 
403 void cdNoExec()
404 {
405 
406  DEBUG_ENTRY( "cdNoExec()" );
407 
408  /* option to read in all input quantiles and NOT execute the actual model
409  * only check on input parameters - set by calling cdNoExec */
410  noexec.lgNoExec = true;
411 
412  return;
413 }
414 
415 
416 /*************************************************************************
417  *
418  * cdSetExecTime routine to initialize variables keeping track of time at start of calculation
419  *
420  ************************************************************************/
421 
422 /* set to false initially, then to true when cdSetExecTime() is called to
423  * initialize the clock */
424 static bool lgCalled=false;
425 
426 #if defined(_MSC_VER)
427 /* _MSC_VER branches assume getrusage isn't implemented by MS */
428 struct timeval {
429  long tv_sec; /* seconds */
430  long tv_usec; /* microseconds */
431 };
432 #else
433 #include <sys/time.h>
434 #include <sys/resource.h>
435 #endif
436 
437 /* will be used to save initial time */
438 static struct timeval before;
439 
440 /* cdClock stores time since arbitrary datum in clock_dat */
441 STATIC void cdClock(struct timeval *clock_dat)
442 {
443  DEBUG_ENTRY( "cdClock()" );
444 
445 /* >>chng 06 sep 2 rjrw: use long recurrence, fine grain UNIX clock *
446  * -- maintain system dependences in a single routine */
447 #if defined(_MSC_VER)
448  clock_t clock_val;
449  /* >>chng 05 dec 21, from above to below due to negative exec times */
450  /*return (double)(clock() - before) / (double)CLOCKS_PER_SEC;*/
451  clock_val = clock();
452  clock_dat->tv_sec = clock_val/CLOCKS_PER_SEC;
453  clock_dat->tv_usec = 1000000*(clock_val-(clock_dat->tv_sec*CLOCKS_PER_SEC))/CLOCKS_PER_SEC;
454  /*>>chng 06 oct 05, this produced very large number, time typically 50% too long
455  clock_dat->tv_usec = 0;*/
456 #else
457  struct rusage rusage;
458  if(getrusage(RUSAGE_SELF,&rusage) != 0)
459  {
460  fprintf( ioQQQ, "DISASTER cdClock called getrusage with invalid arguments.\n" );
461  fprintf( ioQQQ, "Sorry.\n" );
463  }
464  clock_dat->tv_sec = rusage.ru_utime.tv_sec;
465  clock_dat->tv_usec = rusage.ru_utime.tv_usec;
466 #endif
467 
468 }
469 /* cdSetExecTime is called by cdInit when everything is initialized,
470  * so that every time cdExecTime is called the elapsed time is returned */
472 {
473  cdClock(&before);
474  lgCalled = true;
475 }
476 /* cdExecTime returns the elapsed time cpu time (sec) that has elapsed
477  * since cdInit called cdSetExecTime.*/
478 double cdExecTime()
479 {
480  DEBUG_ENTRY( "cdExecTime()" );
481 
482  struct timeval clock_dat;
483  /* check that we were properly initialized */
484  if( lgCalled)
485  {
486  cdClock(&clock_dat);
487  /*fprintf(ioQQQ,"\n DEBUG sec %.2e usec %.2e\n",
488  (double)(clock_dat.tv_sec-before.tv_sec),
489  1e-6*(double)(clock_dat.tv_usec-before.tv_usec));*/
490  return (double)(clock_dat.tv_sec-before.tv_sec)+1e-6*(double)(clock_dat.tv_usec-before.tv_usec);
491  }
492  else
493  {
494  /* this is a big problem, we were asked for the elapsed time but
495  * the timer was not initialized by calling SetExecTime */
496  fprintf( ioQQQ, "DISASTER cdExecTime was called before cdSetExecTime, impossible.\n" );
497  fprintf( ioQQQ, "Sorry.\n" );
499  }
500 }
501 
502 // Maximum memory used, in kB
503 long cdMemory()
504 {
505 #if defined(_MSC_VER)
506  return 0L;
507 #else
508  struct rusage usage;
509  if(getrusage(RUSAGE_SELF,&usage) != 0)
510  {
511  fprintf( ioQQQ, "DISASTER cdMemory called getrusage with invalid arguments.\n" );
512  fprintf( ioQQQ, "Sorry.\n" );
514  }
515  return usage.ru_maxrss;
516 #endif
517 }
518 
519 /*************************************************************************
520  *
521  * cdPrintCommands prints all input commands into file
522  *
523  ************************************************************************/
524 
525 /* cdPrintCommands( FILE *)
526  * prints all input commands into file */
527 void cdPrintCommands( FILE * ioOUT )
528 {
529  long int i;
530  fprintf( ioOUT, " Input commands follow:\n" );
531  fprintf( ioOUT, "c ======================\n" );
532 
533  for( i=0; i <= input.nSave; i++ )
534  {
535  // exclude lines from init files
536  if( input.InclLevel[i] == 0 )
537  fprintf( ioOUT, "%s\n", input.chCardSav[i] );
538  }
539  fprintf( ioOUT, "c ======================\n" );
540 }
541 
542 
543 /*************************************************************************
544  *
545  * cdEmis obtain the local emissivity for a line, for the last computed zone
546  *
547  ************************************************************************/
548 
552 void cdEmis(
553  const char *chLabel,
555  /* the vol emissivity of this line in last computed zone */
556  double *emiss ,
557  // intrinsic or emergent
558  bool lgEmergent )
559 {
560  DEBUG_ENTRY( "cdEmis()" );
561 
562  long ipobs = LineSave.findline(chLabel, wavelength);
563  if (ipobs)
564  cdEmis(&LineSave.lines[ipobs],emiss,lgEmergent);
565  else
566  *emiss = 0.0;
567  return;
568 }
569 
571  /* index of the line in the stack */
572  long int ipLine,
573  /* the vol emissivity of this line in last computed zone */
574  double *emiss ,
575  // intrinsic or emergent
576  bool lgEmergent )
577 {
578  DEBUG_ENTRY( "cdEmis_ip()" );
579 
580  /* returns the emissivity in a line - implements save lines structure
581  * this version uses previously stored line index to save speed */
582  ASSERT( ipLine >= 0 && ipLine < LineSave.nsum );
583  cdEmis(&LineSave.lines[ipLine],emiss,lgEmergent);
584 }
585 
586 /*************************************************************************
587  *
588  * cdColm get the column density for a constituent - 0 return if ok, 1 if problems
589  *
590  ************************************************************************/
591 
592 int cdColm(
593  /* return value is zero if all ok, 1 if errors happened */
594  /* 4-char + eol string that is first
595  * 4 char of element name as spelled by Cloudy, upper or lower case */
596  const char *chLabel,
597 
598  /* integer stage of ionization, 1 for atom, 2 for A+, etc,
599  * 0 is special flag for CO, H2, OH, or excited state */
600  long int ion,
601 
602  /* the column density derived by the code [cm-2] */
603  double *theocl )
604 {
605  long int nelem;
606  /* use following to store local image of character strings */
607  char chLABEL_CAPS[NCHLAB];
608 
609  DEBUG_ENTRY( "cdColm()" );
610  *theocl = 0.;
611 
612  if( strlen(chLabel) > NCHLAB-1 )
613  {
614  fprintf( ioQQQ, " PROBLEM cdColm called with insane chLabel (between quotes) \"%s\", must be no more than %d characters long.\n",
615  chLabel, NCHLAB-1 );
616  return 1;
617  }
618 
619  strcpy( chLABEL_CAPS, chLabel );
620 
621  /* convert element label to all caps */
622  caps(chLABEL_CAPS);
623  trimTrailingWhiteSpace( chLABEL_CAPS );
624 
625  genericState gs;
626 
627  /* zero ionization stage has special meaning. The quantities recognized are
628  * the molecules, "H2 ", "OH ", "CO ", etc
629  * "CII*" excited state C+ */
630  if( ion < 0 )
631  {
632  fprintf( ioQQQ, " PROBLEM cdColm called with insane ion, =%li\n",
633  ion );
634  return 1;
635  }
636 
637  else if( ion == 0 )
638  {
639  /* this case molecular column density */
640  /* want the *total* molecular hydrogen H2 column density */
641  if( strcmp( chLABEL_CAPS , "H2" )==0 )
642  {
643  *theocl = findspecieslocal("H2")->column + findspecieslocal("H2*")->column;
644  }
645  /* H2g - ground H2 column density */
646  else if( strcmp( chLABEL_CAPS , "H2G" )==0 )
647  {
648  gs.sp = findspecieslocal("H2");
649  *theocl = column(gs);
650  }
651  /* H2* - excited H2 - column density */
652  else if( strcmp( chLABEL_CAPS , "H2*" )==0 )
653  {
654  gs.sp = findspecieslocal("H2*");
655  *theocl = column(gs);
656  }
657  /* special option, "H2vJ" */
658  else if( strncmp(chLABEL_CAPS , "H2" , 2 ) == 0 &&
659  isdigit(chLABEL_CAPS[2]) && isdigit(chLABEL_CAPS[3]) )
660  {
661  long int iVib = chLABEL_CAPS[2] - '0';
662  long int iRot = chLABEL_CAPS[3] - '0';
663  if( iVib<0 || iRot < 0 )
664  {
665  fprintf( ioQQQ, " PROBLEM cdColm called with insane v,J for H2=\"%s\" caps=\"%s\"\n",
666  chLabel , chLABEL_CAPS );
667  return 1;
668  }
669  *theocl = cdH2_colden( iVib , iRot );
670  }
671 
672  /* ===========================================================*/
673  /* end special case molecular column densities, start special cases
674  * excited state column densities */
675  else if( strcmp( chLABEL_CAPS , "HE1*" )==0 )
676  {
677  if (dense.lgElmtOn[ipHELIUM])
678  {
680  }
681  *theocl = column(gs);
682  }
683  /* general case */
684  else
685  {
686  vector<genericState> v = matchGeneric(chLabel,false);
687  *theocl = 0.;
688  for (size_t i=0; i<v.size(); ++i)
689  {
690  *theocl += column(v[i]);
691  }
692  }
693  }
694  else
695  {
696  /* this case, ionization stage of some element */
697  /* find which element this is */
698  nelem = 0;
699  while( nelem < LIMELM &&
700  strncmp(chLABEL_CAPS,elementnames.chElementNameShort[nelem],4) != 0 )
701  {
702  ++nelem;
703  }
704 
705  /* this is true if we have one of the first 30 elements in the label,
706  * nelem is on C scale */
707  if( nelem < LIMELM )
708  {
709 
710  /* sanity check - does this ionization stage exist?
711  * max2 is to pick up H2 as H 3 */
712  if( ion > MAX2(3,nelem + 2) )
713  {
714  fprintf( ioQQQ,
715  " cdColm asked to return ionization stage %ld for element \"%s\" but this is not physical.\n",
716  ion, chLabel );
717  return 1;
718  }
719 
720  /* the column density, ion is on physics scale, but means are on C scale */
721  *theocl = mean.xIonMean[0][nelem][ion-1][0];
722  /*>>chng 06 jan 23, div by factor of two
723  * special case of H2 when being tricked as H 3 - this stores 2H_2 so that
724  * the fraction of H in H0 and H+ is correct - need to remove this extra
725  * factor of two here */
726  if( nelem==ipHYDROGEN && ion==3 )
727  *theocl /= 2.;
728  }
729  else
730  {
731  fprintf( ioQQQ,
732  " cdColm did not understand this combination of label \"%s\" and ion %4ld.\n",
733  chLabel, ion );
734  return 1;
735  }
736  }
737  return 0;
738 }
739 
740 
741 /*************************************************************************
742  *
743  *cdErrors produce summary of all warnings, cautions, etc, on arbitrary io unit
744  *
745  ************************************************************************/
746 
747 void cdErrors(FILE *ioOUT)
748 {
749  long int nc,
750  nn,
751  npe,
752  ns,
753  nte,
754  nw ,
755  nIone,
756  nEdene;
757  bool lgAbort_loc;
758 
759  DEBUG_ENTRY( "cdErrors()" );
760 
761  /* first check for number of warnings, cautions, etc */
762  cdNwcns(&lgAbort_loc,&nw,&nc,&nn,&ns,&nte,&npe, &nIone, &nEdene );
763 
764  /* only say something is one of these problems is nonzero */
765  if( nw || nc || nte || npe || nIone || nEdene || lgAbort_loc )
766  {
767  /* say the title of the model */
768  fprintf( ioOUT, "%75.75s\n", input.chTitle );
769 
770  if( lgAbort_loc )
771  fprintf(ioOUT," Calculation ended with abort!\n");
772 
773  /* print warnings on the io unit */
774  if( nw != 0 )
775  {
776  cdWarnings(ioOUT);
777  }
778 
779  /* print cautions on the io unit */
780  if( nc != 0 )
781  {
782  cdCautions(ioOUT);
783  }
784 
785  if( nte != 0 )
786  {
787  fprintf( ioOUT , "Te failures=%4ld\n", nte );
788  }
789 
790  if( npe != 0 )
791  {
792  fprintf( ioOUT , "Pressure failures=%4ld\n", npe );
793  }
794 
795  if( nIone != 0 )
796  {
797  fprintf( ioOUT , "Ionization failures=%4ld\n", nte );
798  }
799 
800  if( nEdene != 0 )
801  {
802  fprintf( ioOUT , "Electron density failures=%4ld\n", npe );
803  }
804  }
805  return;
806 }
807 
808 /*************************************************************************
809  *
810  *cdDepth_depth get depth structure from previous iteration
811  *
812  ************************************************************************/
813 void cdDepth_depth( double cdDepth[] )
814 {
815  long int nz;
816 
817  DEBUG_ENTRY( "cdDepth_depth()" );
818 
819  for( nz = 0; nz<nzone; ++nz )
820  {
821  cdDepth[nz] = struc.depth[nz];
822  }
823  return;
824 }
825 
826 /*************************************************************************
827  *
828  *cdPressure_depth routine to query results and return pressure of last iteration
829  *
830  ************************************************************************/
831 
832 /*
833  * cdPressure_depth
834  * This returns the pressure and its constituents for the last iteration.
835  * space was allocated in the calling routine for the vectors -
836  * before calling this, cdnZone should have been called to get the number of
837  * zones, then space allocated for the arrays */
839  /* total pressure, all forms*/
840  double TotalPressure[],
841  /* gas pressure */
842  double GasPressure[],
843  /* line radiation pressure */
844  double RadiationPressure[])
845 {
846  long int nz;
847 
848  DEBUG_ENTRY( "cdPressure_depth()" );
849 
850  for( nz = 0; nz<nzone; ++nz )
851  {
852  TotalPressure[nz] = struc.pressure[nz];
853  GasPressure[nz] = struc.GasPressure[nz];
854  RadiationPressure[nz] = struc.pres_radiation_lines_curr[nz];
855  }
856  return;
857 }
858 
859 /*************************************************************************
860  *
861  *cdPressure_last routine to query results and return pressure of last zone
862  *
863  ************************************************************************/
864 
866  double *PresTotal, /* total pressure, all forms, for the last computed zone*/
867  double *PresGas, /* gas pressure */
868  double *PresRad) /* line radiation pressure */
869 {
870 
871  DEBUG_ENTRY( "cdPressure_last()" );
872 
873  *PresGas = pressure.PresGasCurr;
875  *PresTotal = pressure.PresTotlCurr;
876  return;
877 }
878 
879 /*************************************************************************
880  *
881  *cdnZone gets number of zones
882  *
883  ************************************************************************/
884 
885 /* returns number of zones */
886 long int cdnZone()
887 {
888  return nzone;
889 }
890 
891 /*************************************************************************
892  *
893  *cdTemp_last routine to query results and return temperature of last zone
894  *
895  ************************************************************************/
896 
897 
898 double cdTemp_last()
899 {
900  return phycon.te;
901 }
902 
903 /*************************************************************************
904  *
905  *cdIonFrac get ionization fractions for a constituent
906  *
907  ************************************************************************/
908 
910  /* four char string, null terminated, giving the element name */
911  const char *chLabel,
912  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
913  * 0 says special case */
914  long int IonStage,
915  /* will be fractional ionization */
916  double *fracin,
917  /* how to weight the average, must be "VOLUME" or "RADIUS" */
918  const char *chWeight ,
919  /* if true then weighting also has electron density, if false then only volume or radius */
920  bool lgDensity )
921  /* return value is 0 if element was found, non-zero if failed */
922 {
923  long int ip,
924  ion, /* used as index within aaa vector*/
925  nelem;
926  realnum aaa[LIMELM + 1];
927  /* use following to store local image of character strings */
928  char chCARD[INPUT_LINE_LENGTH];
929 
930  DEBUG_ENTRY( "cdIonFrac()" );
931 
932  strcpy( chCARD, chWeight );
933  /* make sure chWeight is all caps */
934  caps(chCARD);/* convert to caps */
935 
936  int dim;
937  if( strcmp(chCARD,"RADIUS") == 0 )
938  dim = 0;
939  else if( strcmp(chCARD,"AREA") == 0 )
940  dim = 1;
941  else if( strcmp(chCARD,"VOLUME") == 0 )
942  dim = 2;
943  else
944  {
945  fprintf( ioQQQ, " cdIonFrac: chWeight=%6.6s makes no sense to me, valid options are RADIUS, AREA, and VOLUME\n",
946  chWeight );
947  *fracin = 0.;
948  return 1;
949  }
950 
951  /* first ensure that chLabel is all caps */
952  strcpy( chCARD, chLabel );
953  /* make sure chLabel is all caps */
954  caps(chCARD);/* convert to caps */
955  trimTrailingWhiteSpace(chCARD);
956 
957  if( IonStage==0 )
958  {
959  /* special case */
960  if( strcmp(chCARD,"H2" ) == 0 )
961  {
962  /* this will be request for H2, treated as third stage of hydrogen */
963  nelem = 0;
964  IonStage = 3;
965  }
966  else
967  {
968  fprintf( ioQQQ, " cdIonFrac: ion stage of zero and element %s makes no sense to me\n",
969  chCARD );
970  *fracin = 0.;
971  return 1;
972  }
973  }
974 
975  else
976  {
977  /* find which element this is */
978  nelem = 0;
979  while( nelem < LIMELM &&
980  strcmp(chCARD,elementnames.chElementNameShort[nelem]) != 0 )
981  {
982  ++nelem;
983  }
984  }
985 
986  /* if element not recognized and above loop falls through, nelem is LIMELM */
987  if( nelem >= LIMELM )
988  {
989  fprintf( ioQQQ, " cdIonFrac called with unknown element chLabel, =%4.4s\n",
990  chLabel );
991  return 1;
992  }
993 
994  /* sanity check - does this ionization stage exist?
995  * IonStage is on spectroscopic scale and nelem is on C scale */
996 
997  /* ion will be used as pointer within the aaa array that contains average values,
998  * convert to C scale */
999  ion = IonStage - 1;
1000 
1001  if( (ion > nelem+1 || ion < 0 ) && !(nelem==ipHYDROGEN&&ion==2))
1002  {
1003  fprintf( ioQQQ, " cdIonFrac asked to return ionization stage %ld for element %4.4s but this is not physical.\n",
1004  IonStage, chLabel );
1005  *fracin = -1.;
1006  return 1;
1007  }
1008 
1009  /* get average, aaa is filled in from 0 */
1010  /* aaa is dim'd LIMELM+1 so largest argument is LIMELM
1011  * 'i' means ionization, not temperature */
1012  /* last argument says whether to include electron density */
1013  /* MeanIon uses c scale for nelem */
1014  mean.MeanIon('i',nelem,dim,&ip,aaa,lgDensity);
1015  *fracin = exp10((double)aaa[ion]);
1016 
1017  /* we succeeded - say so */
1018  return 0;
1019 }
1020 
1021 /*************************************************************************
1022  *
1023  * debugLine provides a debugging hook into the main line array
1024  *
1025  ************************************************************************/
1026 
1027  /* debugLine provides a debugging hook into the main line array
1028  * loops over whole array and finds every line that matches length,
1029  * the wavelength, the argument to the function
1030  * put breakpoint inside if test
1031  * return value is number of matches, also prints all matches*/
1033 {
1034  long j, kount;
1035  realnum errorwave;
1036 
1037  kount = 0;
1038 
1039  /* get the error associated with specified significant figures */
1040  errorwave = WavlenErrorGet( wavelength, LineSave.sig_figs );
1041 
1042  for( j=0; j < LineSave.nsum; j++ )
1043  {
1044  /* check wavelength and chLabel for a match */
1045  /* if( fabs(LineSave.lines[j].wavelength- wavelength)/MAX2(DELTA,wavelength) < errorwave ) */
1046  if( fabs(LineSave.lines[j].wavelength()-wavelength) < errorwave )
1047  {
1048  LineSave.lines[j].prt(stdout);
1049  printf("\n");
1050  ++kount;
1051  }
1052  }
1053  printf(" hits = %li\n", kount );
1054  return kount;
1055 }
1056 
1057 /*************************************************************************
1058  *
1059  *cdLine get the predicted line intensity, also index for line in stack
1060  *
1061  ************************************************************************/
1062 
1063 // returns array index for line in array stack if we found the line,
1064 // return negative of total number of lines as debugging aid if line not found
1065 // return <0 if problems
1066 // emergent or intrinsic not specified - use intrinsic
1067 long int cdLine(
1068  const char *chLabel,
1069  /* wavelength of line in angstroms, not format printed by code */
1071  /* linear intensity relative to normalization line*/
1072  double *relint,
1073  /* log of luminosity or intensity of line */
1074  double *absint )
1075 {
1076  DEBUG_ENTRY( "cdLine()" );
1077  long int i = cdLine( chLabel , wavelength , relint , absint, 0 );
1078  return i;
1079 }
1080 long int cdLine(
1081  const char *chLabel,
1082  /* wavelength of line in angstroms, not format printed by code */
1084  /* linear intensity relative to normalization line*/
1085  double *relint,
1086  /* log of luminosity or intensity of line */
1087  double *absint ,
1088  // 0 is intrinsic,
1089  // 1 emergent
1090  // 2 is intrinsic cumulative,
1091  // 3 emergent cumulative
1092  int LineType )
1093 {
1094  DEBUG_ENTRY( "cdLine()" );
1095 
1096  *absint = 0.;
1097  *relint = 0.;
1098 
1099  long ipobs = LineSave.findline(chLabel, wavelength);
1100  if (ipobs > 0)
1101  cdLine_ip(ipobs,relint,absint,LineType);
1102  // printf("%s\t %g\t ip = %ld\t absint = %g\n", chLabel, wavelength, ipobs, *absint);
1103 
1104  return ipobs;
1105 }
1106 
1107 
1108 
1109 /*cdLine_ip get the predicted line intensity, using index for line in stack */
1110 void cdLine_ip(long int ipLine,
1111  /* linear intensity relative to normalization line*/
1112  double *relint,
1113  /* log of luminosity or intensity of line */
1114  double *absint )
1115 {
1116 
1117  DEBUG_ENTRY( "cdLine_ip()" );
1118  cdLine_ip( ipLine , relint , absint , 0 );
1119 }
1120 void cdLine_ip(long int ipLine,
1121  /* linear intensity relative to normalization line*/
1122  double *relint,
1123  /* log of luminosity or intensity of line */
1124  double *absint ,
1125  // 0 is intrinsic,
1126  // 1 emergent
1127  // 2 is intrinsic cumulative,
1128  // 3 emergent cumulative
1129  int LineType )
1130 {
1131 
1132  DEBUG_ENTRY( "cdLine_ip()" );
1133 
1134  *relint = 0.;
1135  *absint = 0.;
1136 
1137  if( LineType<0 || LineType>3 )
1138  {
1139  fprintf( ioQQQ, " PROBLEM cdLine_ip called with insane nLineType - it must be between 0 and 3.\n");
1140  return;
1141  }
1142 
1143  /* this is zero when cdLine called with cdNoExec called too */
1144  if( LineSave.nsum == 0 )
1145  {
1146  return;
1147  }
1148  ASSERT( LineSave.ipNormWavL >= 0);
1149  ASSERT( LineSave.nsum > 0);
1150 
1151  /* does the normalization line have a positive intensity */
1152  if( LineSave.lines[LineSave.ipNormWavL].SumLine(LineType) > 0. )
1153  *relint = LineSave.lines[ipLine].SumLine(LineType)/
1154  LineSave.lines[LineSave.ipNormWavL].SumLine(LineType)*
1156 
1157  /* return log of current line intensity if it is positive */
1158  if( LineSave.lines[ipLine].SumLine(LineType) > 0. )
1159  *absint = LineSave.lines[ipLine].SumLine(LineType) *
1161 
1162  return;
1163 }
1164 
1165 
1166 
1167 /*************************************************************************
1168  *
1169  *cdNwcns get the number of cautions and warnings, to tell if calculation is ok
1170  *
1171  ************************************************************************/
1172 
1173 void cdNwcns(
1174  /* abort status, this better be false */
1175  bool *lgAbort_ret ,
1176  /* the number of warnings, cautions, notes, and surprises */
1177  long int *NumberWarnings,
1178  long int *NumberCautions,
1179  long int *NumberNotes,
1180  long int *NumberSurprises,
1181  /* the number of temperature convergence failures */
1182  long int *NumberTempFailures,
1183  /* the number of pressure convergence failures */
1184  long int *NumberPresFailures,
1185  /* the number of ionization convergence failures */
1186  long int *NumberIonFailures,
1187  /* the number of electron density convergence failures */
1188  long int *NumberNeFailures )
1189 {
1190 
1191  DEBUG_ENTRY( "cdNwcns()" );
1192 
1193  /* this would be set true if code ended with abort - very very bad */
1194  *lgAbort_ret = lgAbort;
1195  /* this sub is called after comment, to find the number of various comments */
1196  *NumberWarnings = warnings.nwarn;
1197  *NumberCautions = warnings.ncaun;
1198  *NumberNotes = warnings.nnote;
1199  *NumberSurprises = warnings.nbang;
1200 
1201  /* these are counters that were incremented during convergence failures */
1202  *NumberTempFailures = conv.nTeFail;
1203  *NumberPresFailures = conv.nPreFail;
1204  *NumberIonFailures = conv.nIonFail;
1205  *NumberNeFailures = conv.nNeFail;
1206  return;
1207 }
1208 
1209 void cdOutput( const string& filename, const char *mode )
1210 {
1211  DEBUG_ENTRY( "cdOutput()" );
1212 
1213  if( ioQQQ != stdout && ioQQQ != NULL )
1214  fclose(ioQQQ);
1215  FILE *fp = stdout;
1216  if( !filename.empty() )
1217  fp = open_data( filename.c_str(), mode, AS_LOCAL_ONLY );
1218  save.chOutputFile = filename;
1219  ioQQQ = fp;
1220 }
1221 
1222 void cdOutput( const string& filename, FILE* fp )
1223 {
1224  DEBUG_ENTRY( "cdOutput()" );
1225 
1226  if( ioQQQ != stdout && ioQQQ != NULL )
1227  fclose(ioQQQ);
1228  save.chOutputFile = filename;
1229  ioQQQ = ( fp != NULL ) ? fp : stdout;
1230 }
1231 
1232 void cdInput( const string& filename, const char *mode )
1233 {
1234  DEBUG_ENTRY( "cdInput()" );
1235 
1236  if( ioStdin != stdin && ioStdin != NULL )
1237  fclose(ioStdin);
1238  FILE *fp = stdin;
1239  if( !filename.empty() )
1240  {
1241  fp = open_data( filename.c_str(), mode, AS_LOCAL_ONLY_TRY );
1242  if( fp == NULL )
1243  {
1244  fprintf( ioQQQ, " input file \"%s\" not found\n", filename.c_str() );
1245  cdEXIT(ES_FAILURE);
1246  }
1247  }
1248  ioStdin = fp;
1249 }
1250 
1251 /*************************************************************************
1252  *
1253  * cdTalk tells the code whether to print results or be silent
1254  *
1255  ************************************************************************/
1256 
1257 void cdTalk(bool lgTOn)
1258 {
1259 
1260  DEBUG_ENTRY( "cdTalk()" );
1261 
1262  /* MPI talking rules must be obeyed, otherwise loss of output may result */
1263  called.lgTalk = lgTOn && cpu.i().lgMPI_talk();
1264  /* has talk been forced off? */
1265  called.lgTalkForcedOff = !lgTOn;
1266  return;
1267 }
1268 
1269 /*cdB21cm - returns B as measured by 21 cm */
1270 double cdB21cm()
1271 {
1272  double ret;
1273 
1274  DEBUG_ENTRY( "cdB21cm()" );
1275 
1276  // return average over radius
1277  if( mean.TempB_HarMean[0][1] > SMALLFLOAT )
1278  {
1279  ret = mean.TempB_HarMean[0][0]/mean.TempB_HarMean[0][1];
1280  }
1281  else
1282  {
1283  ret = 0.;
1284  }
1285  return ret;
1286 }
1287 
1288 /*************************************************************************
1289  *
1290  * cdTemp get mean electron temperature for any element
1291  *
1292  ************************************************************************/
1293 
1294 /* This routine finds the mean electron temperature for any ionization stage
1295  * It returns 0 if it could find the species, 1 if it could not find the species.
1296  * The first argument is a null terminated 4 char string that gives the element
1297  * name as spelled by Cloudy.
1298  * The second argument is ion stage, 1 for atom, 2 for first ion, etc
1299  * This third argument will be returned as result,
1300  * Last parameter is either "RADIUS", "AREA", or "VOLUME" to give weighting
1301  *
1302  * if the ion stage is zero then the element label will have a special meaning.
1303  * The string "21CM" will return the 21 cm temperature.
1304  * The string "H2 " will return the temperature weighted wrt the H2 density
1305  * There are several other options as listed below */
1309 /* return value is o if things are ok and element was found,
1310  * non-zero if element not found or there are problems */
1312  /* four char string, null terminated, giving the element name */
1313  const char *chLabel,
1314  /* IonStage is ionization stage, 1 for atom, up to Z+1 where Z is atomic number,
1315  * 0 means that chLabel is a special case */
1316  long int IonStage,
1317  /* will be temperature */
1318  double *TeMean,
1319  /* how to weight the average, must be "RADIUS", "AREA, or "VOLUME" */
1320  const char *chWeight )
1321 {
1322  long int ip,
1323  ion, /* used as pointer within aaa vector*/
1324  nelem;
1325  realnum aaa[LIMELM + 1];
1326  /* use following to store local image of character strings */
1327  char chWGHT[INPUT_LINE_LENGTH] , chELEM[INPUT_LINE_LENGTH];
1328 
1329  DEBUG_ENTRY( "cdTemp()" );
1330 
1331  /* make sure strings are all caps */
1332  strcpy( chWGHT, chWeight );
1333  caps(chWGHT);
1334  strcpy( chELEM, chLabel );
1335  caps(chELEM);
1336  trimTrailingWhiteSpace(chELEM);
1337 
1338  /* now see which weighting */
1339  int dim;
1340  if( strcmp(chWGHT,"RADIUS") == 0 )
1341  dim = 0;
1342  else if( strcmp(chWGHT,"AREA") == 0 )
1343  dim = 1;
1344  else if( strcmp(chWGHT,"VOLUME") == 0 )
1345  dim = 2;
1346  else
1347  {
1348  fprintf( ioQQQ, " cdTemp: chWeight=%6.6s makes no sense to me, the options are RADIUS, AREA, and VOLUME.\n",
1349  chWeight );
1350  *TeMean = 0.;
1351  return 1;
1352  }
1353 
1354  if( IonStage == 0 )
1355  {
1356  /* return atomic hydrogen weighted harmonic mean of gas kinetic temperature */
1357  if( strcmp(chELEM,"21CM") == 0 )
1358  {
1359  if( mean.TempHarMean[dim][1] > SMALLFLOAT )
1360  *TeMean = mean.TempHarMean[dim][0]/mean.TempHarMean[dim][1];
1361  else
1362  *TeMean = 0.;
1363  }
1364  /* return atomic hydrogen weighted harmonic mean 21 cm spin temperature,
1365  * using actual level populations with 1s of H0 */
1366  else if( strcmp(chELEM,"SPIN") == 0 )
1367  {
1368  if( mean.TempH_21cmSpinMean[dim][1] > SMALLFLOAT )
1369  *TeMean = mean.TempH_21cmSpinMean[dim][0] / mean.TempH_21cmSpinMean[dim][1];
1370  else
1371  *TeMean = 0.;
1372  }
1373  /* return temperature deduced from ratio of 21 cm and Lya optical depths */
1374  else if( strcmp(chELEM,"OPTI") == 0 )
1375  {
1376  if( HFLines[0].Emis().TauCon() > SMALLFLOAT )
1377  *TeMean = 3.84e-7 * iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).Emis().TauCon() /
1378  HFLines[0].Emis().TauCon();
1379  else
1380  *TeMean = 0.;
1381  }
1382  /* mean temp weighted by H2 density */
1383  else if( strcmp(chELEM,"H2") == 0 )
1384  {
1385  if( mean.TempIonMean[dim][ipHYDROGEN][2][1] > SMALLFLOAT )
1386  *TeMean = mean.TempIonMean[dim][ipHYDROGEN][2][0] /
1387  mean.TempIonMean[dim][ipHYDROGEN][2][1];
1388  else
1389  *TeMean = 0.;
1390  }
1391  /* this is temperature weighted by eden */
1392  else if( strcmp(chELEM,"TENE") == 0 )
1393  {
1394  if( mean.TempEdenMean[dim][1] > SMALLFLOAT )
1395  *TeMean = mean.TempEdenMean[dim][0]/mean.TempEdenMean[dim][1];
1396  else
1397  *TeMean = 0.;
1398  }
1399  /* four spaces mean to return simple mean of Te */
1400  else if( strcmp(chELEM,"") == 0 )
1401  {
1402  if( mean.TempMean[dim][1] > SMALLFLOAT )
1403  *TeMean = mean.TempMean[dim][0]/mean.TempMean[dim][1];
1404  else
1405  *TeMean = 0.;
1406  }
1407  else
1408  {
1409  fprintf( ioQQQ, " cdTemp called with ion=0 and unknown quantity, =%4.4s\n",
1410  chLabel );
1411  return 1;
1412  }
1413 
1414  /* say things are ok */
1415  return 0;
1416  }
1417 
1418  /* find which element this is */
1419  nelem = 0;
1420  while( nelem < LIMELM &&
1421  strcmp(chELEM,elementnames.chElementNameShort[nelem]) != 0 )
1422  {
1423  ++nelem;
1424  }
1425 
1426  /* if element not recognized and above loop falls through, nelem is LIMELM */
1427  if( nelem >= LIMELM )
1428  {
1429  fprintf( ioQQQ, " cdTemp called with unknown element chLabel, =%4.4s\n",
1430  chLabel );
1431  return 1;
1432  }
1433 
1434  /* sanity check - does this ionization stage exist?
1435  * IonStage on spectroscopic scale, nelem on c */
1436 
1437  /* ion will be used as pointer within the aaa array that contains average values,
1438  * done this way to prevent lint from false problem in access to aaa array */
1439  ion = IonStage - 1;
1440 
1441  if( ion > nelem+1 || ion < 0 )
1442  {
1443  fprintf( ioQQQ, " cdTemp asked to return ionization stage %ld for element %4.4s but this is not physical.\n",
1444  IonStage, chLabel );
1445  return 1;
1446  }
1447 
1448  /* get average, aaa is filled in from 0 */
1449  /* aaa is dim'd LIMELM+1 so largest arg is LIMELM */
1450  /* MeanIon uses C scale for nelem */
1451  mean.MeanIon('t', nelem,dim,&ip,aaa,false);
1452  *TeMean = exp10((double)aaa[ion]);
1453  return 0;
1454 }
1455 
1456 /*************************************************************************
1457  *
1458  * cdRead routine to read in command lines
1459  * called by user when cloudy used as subroutine
1460  * called by cdMain and ParseInit when used as standalone program
1461  *
1462  ************************************************************************/
1463 
1464 /* returns the number of lines available in command stack
1465  * this is limit to how many more commands can be read */
1466 int cdRead( const char *chInputLine ) /* the string containing the command */
1467 {
1468  const bool COLUMN0 = true;
1469  const bool KEEP_VISIBLE = false;
1470  const bool STRIP_VISIBLE = true;
1471 
1472  DEBUG_ENTRY( "cdRead()" );
1473 
1474  /* this is set false when code loaded, set true when cdInit called,
1475  * this is check that cdInit was called first */
1476  if( !lgcdInitCalled )
1477  {
1478  printf(" cdInit was not called first - this must be the first call.\n");
1480  }
1481 
1482  /* totally ignore hidden comment lines but want to include visible
1483  * comments since they are copied to output */
1484  if( lgIsCommentSeq( chInputLine, COLUMN0, KEEP_VISIBLE ) )
1485  {
1486  /* return value is number of lines that can still be stuffed in */
1487  return NKRD - input.nSave;
1488  }
1489 
1490  /***************************************************************************
1491  * validate a location to store this line image, then store the version *
1492  * that has been truncated from special end of line characters *
1493  * stored image will have < INPUT_LINE_LENGTH valid characters *
1494  ***************************************************************************/
1495 
1496  /* this will now point to the next free slot in the line image save array
1497  * this is where we will stuff this line image */
1498  ++input.nSave;
1499 
1500  if( input.nSave >= NKRD )
1501  {
1502  /* too many input commands were entered - bail */
1503  fprintf( ioQQQ, " Too many line images entered to cdRead. The limit is %d.\n", NKRD );
1504  fprintf( ioQQQ, " This limit is set by the variable NKRD which appears in input.h\n" );
1506  }
1507 
1508  string chLocal( chInputLine );
1509 
1510  /* this indicates an overlong input string */
1511  if( chLocal.length() >= INPUT_LINE_LENGTH )
1512  {
1513  chLocal.erase(INPUT_LINE_LENGTH-1);
1514  fprintf(ioQQQ," PROBLEM cdRead, while parsing the following input line:\n %s\n",
1515  chInputLine);
1516  fprintf(ioQQQ," found that the line is longer than %i characters, the longest possible line.\n",
1517  INPUT_LINE_LENGTH-1);
1518  fprintf(ioQQQ," Please make the command line no longer than this limit.\n");
1519  }
1520 
1521  /* now kill hidden comments
1522  * this stops info user wants ignored from entering after here
1523  * also remove eol character and possible underscores, etc */
1524  StripComment( chLocal, KEEP_VISIBLE );
1525 
1526  /* save string in master array for later use in output */
1527  strcpy( input.chCardSav[input.nSave], chLocal.c_str() );
1528 
1529  /* now kill visible comment part of the input line */
1530  StripComment( chLocal, STRIP_VISIBLE );
1531 
1532  /* pad with two spaces to avoid spurious problems with parsing */
1533  size_t npad = min(2,INPUT_LINE_LENGTH-1-chLocal.length());
1534  chLocal.append( npad, ' ' );
1535 
1536  /* save string in master array for later use in parser */
1537  strcpy( input.chCardStrip[input.nSave], chLocal.c_str() );
1538 
1539  /* keep track of include level of this line */
1541 
1542  Parser p;
1543  p.setline(chLocal.c_str());
1544 
1545  /* check whether this is a trace command, turn on printout if so */
1546  if( p.hasCommand("TRACE") )
1547  trace.lgTrace = true;
1548 
1549  if( p.hasCommand("NO ") && p.nMatch("VARY") )
1550  optimize.lgNoVary = true;
1551 
1552  /* prt.lgPrintTime can be used by check_data() before regular parsing starts */
1553  if( p.hasCommand("NO ") && p.nMatch("TIME") )
1554  prt.lgPrintTime = false;
1555 
1556  if( p.hasCommand("GRID") )
1557  {
1558  optimize.lgOptimr = true;
1559  grid.lgGrid = true;
1560  ++grid.nGridCommands;
1561  }
1562 
1563  /* NO BUFFERING turn off buffered io for standard output,
1564  * used to get complete output when code crashes */
1565  if( p.hasCommand("NO ") && p.nMatch("BUFF") )
1566  {
1567  /* if output has already been redirected (e.g. using cdOutput()) then
1568  * ignore this command, a warning will be printed in ParseDont() */
1569  /* stdout may be a preprocessor macro, so lets be really careful here */
1570  FILE *test = stdout;
1571  if( ioQQQ == test )
1572  {
1573  fprintf( ioQQQ, " cdRead found NO BUFFERING command, redirecting output to stderr now.\n" );
1574  /* make sure output is not lost */
1575  fflush( ioQQQ );
1576  /* stderr is always unbuffered */
1577  /* don't use setvbuf() here since we cannot guarantee
1578  * that no operations have been performed on stdout */
1579  ioQQQ = stderr;
1580  /* will be used to generate comment at end */
1581  input.lgSetNoBuffering = true;
1582  }
1583  else if( !save.chOutputFile.empty() )
1584  {
1585  fprintf( ioQQQ, " cdRead found NO BUFFERING command, reopening file %s now.\n",
1586  save.chOutputFile.c_str() );
1587  fclose( ioQQQ );
1588  // using AS_SILENT_TRY assures that open_data will not write to ioQQQ
1589  ioQQQ = open_data( save.chOutputFile.c_str(), "a", AS_SILENT_TRY );
1590  if( ioQQQ == NULL )
1591  {
1592  // ioQQQ is no longer valid, so switch to stderr and abort...
1593  ioQQQ = stderr;
1594  fprintf( ioQQQ, " cdRead failed to reopen %s, aborting!\n",
1595  save.chOutputFile.c_str() );
1597  }
1598  if( setvbuf( ioQQQ, NULL, _IONBF, 0 ) != 0 )
1599  fprintf( ioQQQ, " PROBLEM -- cdRead failed to set NO BUFFERING mode.\n" );
1600  else
1601  input.lgSetNoBuffering = true;
1602  }
1603  }
1604 
1605  /* optimize command read in */
1606  if( p.hasCommand("OPTI") )
1607  optimize.lgOptimr = true;
1608 
1609  if( p.hasCommand("SET ") && p.nMatch("CONT") && p.nMatch("RESO") )
1610  {
1611  double factor = p.getNumberDefault("",1.);
1612  /* negative numbers are always logs */
1613  if( factor <= 0. )
1614  factor = exp10(factor);
1616  }
1617 
1618  /* if the command is an init command, process it immediately
1619  * so that the lines in the init file can be inserted in situ */
1620  if( p.hasCommand("INIT") )
1621  {
1622  ParseInit(p);
1623  input.lgInitPresent = true;
1624  }
1625 
1626  /* here we check for specific keywords, avoiding the TITLE command since
1627  * that contains free text, which could lead to spurious matches... */
1628  if( ! p.hasCommand("TITL") )
1629  {
1630  /* now check whether VARY is specified */
1631  if( p.nMatch("VARY") )
1632  /* a optimize flag was on the line image */
1633  optimize.lgVaryOn = true;
1634  }
1635 
1636  /* print input lines if trace specified */
1637  if( trace.lgTrace )
1638  fprintf( ioQQQ,"cdRead [%d] =%s=\n",input.curInclLevel,input.chCardSav[input.nSave] );
1639 
1640  return NKRD - input.nSave;
1641 }
1642 
1643 /* wrapper to close all save files */
1645 {
1646 
1647  DEBUG_ENTRY( "cdClosePunchFiles()" );
1648 
1649  CloseSaveFiles( true );
1650  return;
1651 }
void cdDate(char chString[])
Definition: cddrive.cpp:362
multi_arr< double, 2 > TempH_21cmSpinMean
Definition: mean.h:34
long int nSave
Definition: input.h:102
long int nTeFail
Definition: conv.h:201
bool nMatch(const char *chKey) const
Definition: parser.h:150
static bool lgCalled
Definition: cddrive.cpp:424
void cdNotes(FILE *ioOUT)
Definition: cddrive.cpp:310
void cdLine_ip(long int ipLine, double *relint, double *absint)
Definition: cddrive.cpp:1110
bool hasCommand(const char *s2)
Definition: parser.cpp:746
double htot
Definition: thermal.h:169
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:765
void cdPrintCommands(FILE *ioOUT)
Definition: cddrive.cpp:527
t_thermal thermal
Definition: thermal.cpp:6
qList st
Definition: iso.h:482
realnum WavlenErrorGet(realnum wavelength, long sig_figs)
double exp10(double x)
Definition: cddefines.h:1368
const int ipHE_LIKE
Definition: iso.h:65
const int NKRD
Definition: input.h:12
t_input input
Definition: input.cpp:12
bool lgGrid
Definition: grid.h:41
void setline(const char *const card)
Definition: parser.h:82
t_struc struc
Definition: struc.cpp:6
double cdHeating_last()
Definition: cddrive.cpp:376
bool cloudy()
Definition: cloudy.cpp:37
long findline(const char *chLabel, realnum wavelength)
Definition: lines.cpp:294
const realnum SMALLFLOAT
Definition: cpu.h:246
t_cpu_i & i()
Definition: cpu.h:419
void cdPressure_last(double *PresTotal, double *PresGas, double *PresRad)
Definition: cddrive.cpp:865
bool lgInitPresent
Definition: input.h:108
int cdDrive()
Definition: cddrive.cpp:81
void cdCautions(FILE *ioOUT)
Definition: cddrive.cpp:219
const int ipHe2s3S
Definition: iso.h:46
int curInclLevel
Definition: input.h:92
t_warnings warnings
Definition: warnings.cpp:11
int cdIonFrac(const char *chLabel, long int IonStage, double *fracin, const char *chWeight, bool lgDensity)
Definition: cddrive.cpp:909
void cdWarnings(FILE *ioPNT)
Definition: cddrive.cpp:192
t_conv conv
Definition: conv.cpp:5
long int nNeFail
Definition: conv.h:210
TransitionList HFLines("HFLines",&AnonStates)
char chWarnln[LIMWCN][INPUT_LINE_LENGTH]
Definition: warnings.h:38
t_phycon phycon
Definition: phycon.cpp:6
t_LineSave LineSave
Definition: lines.cpp:10
void CloseSaveFiles(bool lgFinal)
void cdTimescales(double *TTherm, double *THRecom, double *TH2)
Definition: cddrive.cpp:242
int cdTemp(const char *chLabel, long int IonStage, double *TeMean, const char *chWeight)
Definition: cddrive.cpp:1311
vector< genericState > matchGeneric(const char *chLabel, bool lgValidate)
void cdDepth_depth(double cdDepth[])
Definition: cddrive.cpp:813
realnum column
Definition: mole.h:422
bool lgVaryOn
Definition: optimize.h:173
t_noexec noexec
Definition: noexec.cpp:4
bool lgcdInitCalled
Definition: cdinit.cpp:27
FILE * ioQQQ
Definition: cddefines.cpp:7
long int ncaun
Definition: warnings.h:28
molezone * findspecieslocal(const char buf[])
void InitMesh(bool lgUnitCell)
Definition: mesh.h:63
char chTitle[INPUT_LINE_LENGTH]
Definition: input.h:80
long int nzone
Definition: cddefines.cpp:14
bool lgTalk
Definition: called.h:12
char chRgcln[2][INPUT_LINE_LENGTH]
Definition: warnings.h:34
int cdRead(const char *chInputLine)
Definition: cddrive.cpp:1466
STATIC void cdClock(struct timeval *clock_dat)
Definition: cddrive.cpp:441
char chCardStrip[NKRD][INPUT_LINE_LENGTH]
Definition: input.h:77
Definition: parser.h:43
double PresTotlCurr
Definition: pressure.h:46
vector< LinSv > lines
Definition: lines.h:132
bool lgNoExec
Definition: noexec.h:14
void setResolutionScaleFactor(double fac)
Definition: mesh.h:105
void trimTrailingWhiteSpace(string &str)
Definition: service.cpp:153
double pres_radiation_lines_curr
Definition: pressure.h:61
bool lgIsCommentSeq(const char *s, bool lgColumn0, bool lgReportVisible)
Definition: input.cpp:31
t_dense dense
Definition: global.cpp:15
void cdNoExec()
Definition: cddrive.cpp:403
void StripComment(string &s, bool lgStripVisible)
Definition: input.cpp:98
static FixitList & Inst()
Definition: cddefines.h:209
void cdEmis_ip(long int ipLine, double *emiss, bool lgEmergent)
Definition: cddrive.cpp:570
double time_H2_Dest_longest
Definition: timesc.h:48
void cdInput(const string &filename, const char *mode)
Definition: cddrive.cpp:1232
t_elementnames elementnames
Definition: elementnames.cpp:5
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:11
long int nflux_with_check
Definition: rfield.h:49
bool lgOptimr
Definition: optimize.h:178
t_trace trace
Definition: trace.cpp:5
double cdH2_colden(long iVib, long iRot)
Definition: mole_h2.cpp:2320
realnum * depth
Definition: struc.h:25
multi_arr< double, 2 > TempB_HarMean
Definition: mean.h:29
long int nbang
Definition: warnings.h:28
char chNoteln[LIMWCN][INPUT_LINE_LENGTH]
Definition: warnings.h:38
const int ipH1s
Definition: iso.h:29
char chCaunln[LIMWCN][INPUT_LINE_LENGTH]
Definition: warnings.h:38
#define STATIC
Definition: cddefines.h:118
bool lgTrace
Definition: trace.h:12
realnum * GasPressure
Definition: struc.h:25
EmissionList::reference Emis() const
Definition: transition.h:447
multi_arr< double, 2 > TempEdenMean
Definition: mean.h:38
void cdSetExecTime()
Definition: cddrive.cpp:471
long debugLine(realnum wavelength)
Definition: cddrive.cpp:1032
t_pressure pressure
Definition: pressure.cpp:9
t_rfield rfield
Definition: rfield.cpp:9
t_mean mean
Definition: mean.cpp:16
bool lgPrintFixits
Definition: broke.h:34
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
#define cdEXIT(FAIL)
Definition: cddefines.h:482
bool lgMPI_talk() const
Definition: cpu.h:397
t_broke broke
Definition: broke.cpp:10
long min(int a, long b)
Definition: cddefines.h:762
bool lgPrintTime
Definition: prt.h:161
void cdPressure_depth(double TotalPressure[], double GasPressure[], double RadiationPressure[])
Definition: cddrive.cpp:838
double column(const genericState &gs)
double PresGasCurr
Definition: pressure.h:46
long int sig_figs
Definition: lines.h:109
const molezone * sp
Definition: generic_state.h:19
t_optimize optimize
Definition: optimize.cpp:6
char chElementNameShort[LIMELM][CHARS_ELEMENT_NAME_SHORT]
Definition: elementnames.h:21
t_grid grid
Definition: grid.cpp:5
double cdExecTime()
Definition: cddrive.cpp:478
t_radius radius
Definition: radius.cpp:5
t_timesc timesc
Definition: timesc.cpp:7
double cdTemp_last()
Definition: cddrive.cpp:898
t_prt prt
Definition: prt.cpp:14
bool lgInsideGrid
Definition: grid.h:43
bool lgElmtOn[LIMELM]
Definition: dense.h:160
TransitionProxy trans(const long ipHi, const long ipLo)
Definition: iso.h:473
double time_Hrecom_long
Definition: timesc.h:36
void ParseInit(Parser &p)
Definition: parse_init.cpp:10
double Conv2PrtInten
Definition: radius.h:153
const int ipH2p
Definition: iso.h:31
long int nPreFail
Definition: conv.h:207
bool grid_do(void)
Definition: grid_do.cpp:19
double cdEDEN_last()
Definition: cddrive.cpp:389
#define ASSERT(exp)
Definition: cddefines.h:613
long int nnote
Definition: warnings.h:28
double cdB21cm()
Definition: cddrive.cpp:1270
void MeanIon(char chType, long nelem, long dim, long *n, realnum arlog[], bool lgDensity) const
Definition: mean.cpp:151
long int cdnZone()
Definition: cddrive.cpp:886
realnum & TauCon() const
Definition: emission.h:510
void cdEmis(const char *chLabel, realnum wavelength, double *emiss, bool lgEmergent)
Definition: cddrive.cpp:552
long int cdLine(const char *chLabel, realnum wavelength, double *relint, double *absint)
Definition: cddrive.cpp:1067
long int ipNormWavL
Definition: lines.h:102
const int ipH_LIKE
Definition: iso.h:64
const int LIMELM
Definition: cddefines.h:308
void cdClosePunchFiles()
Definition: cddrive.cpp:1644
int cdColm(const char *chLabel, long int ion, double *theocl)
Definition: cddrive.cpp:592
multi_arr< double, 4 > TempIonMean
Definition: mean.h:24
string chOutputFile
Definition: save.h:439
void cdErrors(FILE *ioOUT)
Definition: cddrive.cpp:747
long cdMemory()
Definition: cddrive.cpp:503
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
void cdVersion(char chString[])
Definition: cddrive.cpp:347
const int ipHELIUM
Definition: cddefines.h:350
double cdCooling_last()
Definition: cddrive.cpp:334
bool lgTalkForcedOff
Definition: called.h:19
static vector< realnum > wavelength
void cdTalk(bool lgTOn)
Definition: cddrive.cpp:1257
multi_arr< double, 2 > TempMean
Definition: mean.h:36
double getNumberDefault(const char *chDesc, double fdef)
Definition: parser.cpp:401
double eden
Definition: dense.h:201
bool lgSetNoBuffering
Definition: input.h:122
void cdOutput(const string &filename, const char *mode)
Definition: cddrive.cpp:1209
void InitCoreload(void)
void cdSurprises(FILE *ioOUT)
Definition: cddrive.cpp:274
void cdNwcns(bool *lgAbort_ret, long int *NumberWarnings, long int *NumberCautions, long int *NumberNotes, long int *NumberSurprises, long int *NumberTempFailures, long int *NumberPresFailures, long int *NumberIonFailures, long int *NumberNeFailures)
Definition: cddrive.cpp:1173
const int NCHLAB
Definition: cddefines.h:304
#define MAX2(a, b)
Definition: cddefines.h:824
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
multi_arr< double, 4 > xIonMean
Definition: mean.h:17
void cdReasonGeo(FILE *ioOUT)
Definition: cddrive.cpp:170
long int nIonFail
Definition: conv.h:216
vector< string > list
Definition: broke.h:17
long ncells() const
Definition: mesh.h:89
long int nsum
Definition: lines.h:87
long int nwarn
Definition: warnings.h:28
void caps(char *chCard)
Definition: service.cpp:295
char chCardSav[NKRD][INPUT_LINE_LENGTH]
Definition: input.h:74
static t_cpu cpu
Definition: cpu.h:427
t_save save
Definition: save.cpp:5
double te
Definition: phycon.h:21
bool lgNoVary
Definition: optimize.h:175
double time_H2_Form_longest
Definition: timesc.h:48
double time_therm_long
Definition: timesc.h:29
const int ipHYDROGEN
Definition: cddefines.h:349
long int nGridCommands
Definition: grid.h:56
qStateConstProxy q
Definition: generic_state.h:20
char chBangln[LIMWCN][INPUT_LINE_LENGTH]
Definition: warnings.h:38
long int nflux
Definition: rfield.h:46
long int nPositive
Definition: rfield.h:53
static long int * ipLine
Definition: prt_linesum.cpp:14
t_called called
Definition: called.cpp:4
EmissionList & Emis()
Definition: transition.h:363
bool lgAbort
Definition: cddefines.cpp:10
realnum * pressure
Definition: struc.h:25
double ctot
Definition: thermal.h:130
double ScaleNormLine
Definition: lines.h:117
FILE * ioStdin
Definition: cddefines.cpp:8
int InclLevel[NKRD]
Definition: input.h:91
multi_arr< double, 2 > TempHarMean
Definition: mean.h:32
realnum * pres_radiation_lines_curr
Definition: struc.h:25
static struct timeval before
Definition: cddrive.cpp:438