cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
prt_final.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 /*PrtFinal create PrtFinal pages of printout, emission line intensities, etc */
4 /*StuffComment routine to stuff comments into the stack of comments, def in lines.h */
5 /*gett2o3 analyze computed [OIII] spectrum to get t^2 */
6 /*gett2 analyze computed structure to get structural t^2 */
7 #include "cddefines.h"
8 #include "iso.h"
9 #include "cddrive.h"
10 #include "dynamics.h"
11 #include "lines.h"
12 #include "taulines.h"
13 #include "warnings.h"
14 #include "phycon.h"
15 #include "dense.h"
16 #include "grainvar.h"
17 #include "h2.h"
18 #include "hmi.h"
19 #include "thermal.h"
20 #include "hydrogenic.h"
21 #include "rt.h"
22 #include "atmdat.h"
23 #include "timesc.h"
24 #include "opacity.h"
25 #include "struc.h"
26 #include "pressure.h"
27 #include "conv.h"
28 #include "geometry.h"
29 #include "called.h"
30 #include "iterations.h"
31 #include "version.h"
32 #include "colden.h"
33 #include "input.h"
34 #include "radius.h"
35 #include "peimbt.h"
36 #include "ipoint.h"
37 #include "mean.h"
38 #include "wind.h"
39 #include "prt.h"
40 #include "rfield.h"
41 #include "freebound.h"
42 #include "lines_service.h"
43 
44 // helper routine to center a line in the output
45 STATIC void PrintCenterLine(FILE* io, // file pointer
46  const char chLine[], // string to print, should not end with '\n'
47  size_t ArrLen, // length of chLine
48  size_t LineLen) // width of the line
49 {
50  unsigned long StrLen = min(strlen(chLine),ArrLen);
51  ASSERT( StrLen < LineLen );
52  unsigned long pad = (LineLen-StrLen)/2;
53  for( unsigned long i=0; i < pad; ++i )
54  fprintf( io, " " );
55  fprintf( io, "%s\n", chLine );
56 }
57 
58 /*gett2o3 analyze computed [OIII] spectrum to get t^2 */
59 STATIC void gett2o3(realnum *tsqr);
60 
61 /*gett2 analyze computed structure to get structural t^2 */
62 STATIC void gett2(realnum *tsqr);
63 
64 /* helper routine for printing averaged quantities */
65 inline void PrintRatio(double q1, double q2)
66 {
67  double ratio = ( q2 > SMALLFLOAT ) ? q1/q2 : 0.;
68  fprintf( ioQQQ, " " );
69  fprintf( ioQQQ, PrintEfmt("%9.2e", ratio) );
70  return;
71 }
72 
74 {
75  vector<realnum> sclsav, scaled;
76  vector<long int> ipSortLines;
77  vector<double> xLog_line_lumin;
78  vector<short int> lgPrt;
79  vector<long> Slines;
80 
81  long int
82  i,
83  ipEmType,
84  iprnt,
85  nline,
86  j,
87  ipNegIntensity[33],
88  nNegIntenLines;
89 
90  double a,
91  /* N.B. 8 is used for following preset in loop */
92  d[8],
93  snorm;
94 
95 
96  DEBUG_ENTRY( "PrintSpectrum()" );
97 
98 
99  /*----------------------------------------------------------
100  *
101  * first set scaled lines */
102 
103  /* get space for scaled */
104  scaled.resize(LineSave.nsum);
105 
106  /* get space for xLog_line_lumin */
107  xLog_line_lumin.resize(LineSave.nsum);
108 
109  /* this is option to not print certain contributions */
110  /* gjf 98 jun 10, get space for array lgPrt */
111  lgPrt.resize(LineSave.nsum);
112 
113  /* get space for sclsav */
114  sclsav.resize(LineSave.nsum );
115 
116  Slines.resize(LineSave.nsum);
117 
118  /* get space for array of indices for lines, for possible sorting */
119  ipSortLines.resize(LineSave.nsum );
120 
121  ASSERT( LineSave.ipNormWavL >= 0 );
122 
123  /* option to also print usual first two sets of line arrays
124  * but for two sets of cumulative arrays for time-dependent sims too */
125  int nEmType = 2;
127  nEmType = 4;
128 
129  for( ipEmType=0; ipEmType<nEmType; ++ipEmType )
130  {
131  if( ! prt.lgPrintBlockIntrinsic && (ipEmType == 0 || ipEmType == 2) )
132  continue;
133  if( ! prt.lgPrintBlockEmergent && (ipEmType == 1 || ipEmType == 3) )
134  continue;
135 
136  if( ipEmType > 1 && strcmp( rfield.chCumuType, "NONE" ) == 0 )
137  continue;
138 
139  /* this is the intensity of the line spectrum will be normalized to */
140  snorm = LineSave.lines[LineSave.ipNormWavL].SumLine(ipEmType);
141 
142  /* check that this line has positive intensity */
143  if( ((snorm <= SMALLDOUBLE ) || (LineSave.ipNormWavL < 0)) || (LineSave.ipNormWavL > LineSave.nsum) )
144  {
145  char wl_str[20] = "";
146  sprt_wl( wl_str, LineSave.lines[LineSave.ipNormWavL].wavelength() );
147  fprintf(ioQQQ,
148  "\n\n"
149  " >>PROBLEM Normalization line (\"%s\" %s) has small or zero intensity, its value was %.2e and its intensity was set to 1.\n"
150  " >>Please consider using another normalization line (this is set with the NORMALIZE command).\n",
151  LineSave.lines[LineSave.ipNormWavL].chALab(), wl_str, snorm);
152  fprintf( ioQQQ, " >>The relative intensities will be meaningless, and many lines may appear too faint.\n" );
153  snorm = 1.;
154  }
155  for( i=0; i < LineSave.nsum; i++ )
156  {
157  /* Do only for emergent lines */
158  if( ipEmType == 1 || ipEmType == 3 )
159  LineSave.lines[i].checkEmergent( ipEmType );
160 
161  /* when normalization line is off-scale small (generally a model
162  * with mis-set parameters) the scaled intensity can be larger than
163  * a realnum - this is not actually a problem since the number will
164  * overflow the format and hence be unreadable */
165  double scale = LineSave.lines[i].SumLine(ipEmType)/snorm*LineSave.ScaleNormLine;
166  /* this will become a realnum, so limit dynamic range */
167  scale = MIN2(BIGFLOAT , scale );
168  scale = MAX2( -BIGFLOAT , scale );
169 
170  /* find logs of ALL line intensities/luminosities */
171  scaled[i] = (realnum)scale;
172 
173  // the keyword volatile works around a bug in g++
174  // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65425
175  volatile double line_lumin = LineSave.lines[i].SumLine(ipEmType) * radius.Conv2PrtInten;
176  xLog_line_lumin[i] = ( line_lumin > 0. ) ? log10(line_lumin) : 0.;
177  }
178 
179  /* now find which lines to print, which to ignore because they are the wrong type */
180  for( i=0; i < LineSave.nsum; i++ )
181  {
182  /* never print unit normalization check, at least in main list */
183  if( LineSave.lines[i].isUnit() || LineSave.lines[i].isUnitD() )
184  lgPrt[i] = false;
185  else if( !prt.lgPrnColl && LineSave.lines[i].isCollisional() )
186  lgPrt[i] = false;
187  else if( !prt.lgPrnPump && LineSave.lines[i].isPump() )
188  lgPrt[i] = false;
189  else if( !prt.lgPrnInwd && ( LineSave.lines[i].isInward() ||
190  LineSave.lines[i].isInwardContinuum() ||
191  LineSave.lines[i].isInwardTotal() )
192  )
193  lgPrt[i] = false;
194  else if( !prt.lgPrnHeat && LineSave.lines[i].isHeat() )
195  lgPrt[i] = false;
196  else
197  lgPrt[i] = true;
198  }
199 
200  /* do not print relatively faint lines unless requested */
201  nNegIntenLines = 0;
202 
203  /* set ipNegIntensity to bomb to make sure set in following */
204  for(i=0; i< 32; i++ )
205  {
206  ipNegIntensity[i] = LONG_MAX;
207  }
208 
209  for(i=0;i<8;++i)
210  {
211  d[i] = -DBL_MAX;
212  }
213 
214  /* create header for blocks of emission line intensities */
215  const char chIntensityType[4][100]=
216  {" Intrinsic" , " Emergent" , "Cumulative intrinsic" , "Cumulative emergent" };
217  ASSERT( ipEmType==0 || ipEmType==1 || ipEmType==2 || ipEmType==3 );
218  /* if true then printing in 4 columns of lines, this is offset to
219  * center the title */
220  fprintf( ioQQQ, "\n" );
221  if( prt.lgPrtLineArray )
222  fprintf( ioQQQ, " " );
223  fprintf( ioQQQ, "%s" , chIntensityType[ipEmType] );
224  fprintf( ioQQQ, " line intensities\n" );
225  // caution about emergent intensities when outward optical
226  // depths are not yet known
227  if( ipEmType==1 && iteration==1 )
228  fprintf(ioQQQ," Caution: emergent intensities are not reliable on the "
229  "first iteration.\n");
230 
231  /* option to only print brighter lines */
232  if( prt.lgFaintOn )
233  {
234  iprnt = 0;
235  for( i=0; i < LineSave.nsum; i++ )
236  {
237  /* this insanity can happen when arrays overrun */
238  ASSERT( iprnt <= i);
239  if( scaled[i] >= prt.TooFaint && lgPrt[i] )
240  {
241  if( prt.lgPrtLineLog )
242  {
243  xLog_line_lumin[iprnt] = log10(LineSave.lines[i].SumLine(ipEmType) * radius.Conv2PrtInten);
244  }
245  else
246  {
247  xLog_line_lumin[iprnt] = LineSave.lines[i].SumLine(ipEmType) * radius.Conv2PrtInten;
248  }
249  sclsav[iprnt] = scaled[i];
250  /* check that null is correct, string overruns have
251  * been a problem in the past */
252  Slines[iprnt] = i;
253  ++iprnt;
254  }
255  else if( -scaled[i] > prt.TooFaint && lgPrt[i] )
256  {
257  /* negative intensities occur if line absorbs continuum */
258  ipNegIntensity[nNegIntenLines] = i;
259  nNegIntenLines = MIN2(32,nNegIntenLines+1);
260  }
261  /* special labels to give id for blocks of lines
262  * do not add these labels when sorting by wavelength since invalid */
263  else if( LineSave.lines[i].isSeparator() &&!prt.lgSortLines )
264  {
265  xLog_line_lumin[iprnt] = 0.;
266  sclsav[iprnt] = 0.;
267  Slines[iprnt] = i;
268  ++iprnt;
269  }
270  }
271  }
272 
273  else
274  {
275  /* print everything */
276  iprnt = LineSave.nsum;
277  for( i=0; i < LineSave.nsum; i++ )
278  {
279  if( LineSave.lines[i].isSeparator() )
280  {
281  xLog_line_lumin[i] = 0.;
282  sclsav[i] = 0.;
283  }
284  else
285  {
286  sclsav[i] = scaled[i];
287  }
288  Slines[i] = i;
289  if( scaled[i] < 0. )
290  {
291  ipNegIntensity[nNegIntenLines] = i;
292  nNegIntenLines = MIN2(32,nNegIntenLines+1);
293  }
294  }
295  }
296 
297  /* reorder lines according to wavelength for comparison with spectrum
298  * including writing out the results */
299  if( prt.lgSortLines )
300  {
301  int lgFlag;
303  {
304  /* first check if wavelength range specified */
305  if( prt.wlSort1 >-0.1 )
306  {
307  j = 0;
308  /* skip over those lines not desired */
309  for( i=0; i<iprnt; ++i )
310  {
311  realnum wavelength=LineSave.lines[Slines[i]].wavelength();
312  if( wavelength>= prt.wlSort1 && wavelength<= prt.wlSort2 )
313  {
314  if( j!=i )
315  {
316  sclsav[j] = sclsav[i];
317  /* >>chng 05 feb 03, add this, had been left out,
318  * thanks to Marcus Copetti for discovering the bug */
319  xLog_line_lumin[j] = xLog_line_lumin[i];
320  Slines[j] = Slines[i];
321  }
322  ++j;
323  }
324  }
325  iprnt = j;
326  }
327 
328  vector<realnum> wavelength(iprnt);
329  for( i=0; i<iprnt; ++i )
330  {
331  wavelength[i] = LineSave.lines[Slines[i]].wavelength();
332  }
333 
334  /*spsort netlib routine to sort array returning sorted indices */
335  if( iprnt > 0 )
336  {
337  spsort(&wavelength[0],
338  iprnt,
339  &ipSortLines[0],
340  /* flag saying what to do - 1 sorts into increasing order, not changing
341  * the original routine */
342  1,
343  &lgFlag);
344  if( lgFlag )
345  {
346  fprintf(ioQQQ," >>> PROBLEM spsort reports error\n");
347  TotalInsanity();
348  }
349  }
350  }
351  else if( prt.lgSortLineIntensity )
352  {
353  if( iprnt > 0 )
354  {
355  /*spsort netlib routine to sort array returning sorted indices */
356  spsort(&sclsav[0],
357  iprnt,
358  &ipSortLines[0],
359  /* flag saying what to do - -1 sorts into decreasing order, not changing
360  * the original routine */
361  -1,
362  &lgFlag);
363  if( lgFlag )
364  TotalInsanity();
365  }
366  }
367  else
368  {
369  /* only to keep lint happen, or in case vars clobbered */
370  TotalInsanity();
371  }
372  }
373  else
374  {
375  /* do not sort lines (usual case) simply print in incoming order */
376  for( i=0; i<iprnt; ++i )
377  {
378  ipSortLines[i] = i;
379  }
380  }
381 
382  /* the number of lines to print better be positive */
383  if (iprnt == 0)
384  fprintf(ioQQQ," >>>> No strong lines found <<<<\n");
385 
386  /* print out all lines which made it through the faint filter,
387  * there are iprnt lines to print
388  * can print in either 4 column (the default ) or one long
389  * column of lines */
390  if( prt.lgPrtLineArray )
391  {
392  /* four or three columns ? - depends on how many sig figs */
393  if( LineSave.sig_figs >= 5 )
394  {
395  nline = (iprnt + 2)/3;
396  }
397  else
398  {
399  /* nline will be the number of horizontal lines -
400  * the 4 represents the 4 columns */
401  nline = (iprnt + 3)/4;
402  }
403  }
404  else
405  {
406  /* this option print a single column of emission lines */
407  nline = iprnt;
408  }
409 
410  /* now loop over the spectrum, printing lines */
411  for( i=0; i < nline; i++ )
412  {
413 
414  /* this skips over nline per step, to go to the next column in
415  * the output */
416  for( j=i; j<iprnt; j = j + nline)
417  {
418  /* index with possibly reordered set of lines */
419  long ipLin = ipSortLines[j];
420  /* this is the actual print statement for the emission line
421  * spectrum*/
422  if( LineSave.lines[Slines[ipLin]].isSeparator() )
423  {
424  /* special labels */
425  /*fprintf( ioQQQ, "1111222223333333444444444 " ); */
426  /* this string was set in */
428  (int)LineSave.lines[Slines[ipLin]].wavelength()] );
429  }
430  else
431  {
432  /* the label for the line */
433  LineSave.lines[Slines[ipLin]].prt(ioQQQ);
434 
435  /* print the log of the intensity/luminosity of the
436  * lines, the usual case */
437  fprintf( ioQQQ, " " );
438  if( prt.lgPrtLineLog )
439  {
440  fprintf( ioQQQ, "%*.3f", prt_linecol.absint_len, xLog_line_lumin[ipLin] );
441  }
442  else
443  {
444  /* print linear quantity instead */
445  fprintf( ioQQQ, " %*.2e", prt_linecol.absint_len, xLog_line_lumin[ipLin] );
446  }
447 
448  /* print scaled intensity with various formats,
449  * depending on order of magnitude. value is
450  * always the same but the format changes. */
451  fprintf( ioQQQ, " " );
452  if( sclsav[ipLin] < 9999.5 )
453  {
454  fprintf( ioQQQ, "%*.4f", prt_linecol.relint_len, sclsav[ipLin] );
455  }
456  else if( sclsav[ipLin] < 99999.5 )
457  {
458  fprintf( ioQQQ, "%*.3f", prt_linecol.relint_len, sclsav[ipLin] );
459  }
460  else if( sclsav[ipLin] < 999999.5 )
461  {
462  fprintf( ioQQQ, "%*.2f", prt_linecol.relint_len, sclsav[ipLin] );
463  }
464  else if( sclsav[ipLin] < 9999999.5 )
465  {
466  fprintf( ioQQQ, "%*.1f", prt_linecol.relint_len, sclsav[ipLin] );
467  }
468  else
469  {
470  fprintf( ioQQQ, "%s", prt_linecol.relint_outrange.c_str() );
471  }
472  }
473 
474  /* now end the block with some spaces to set next one off */
475  if( j+nline < iprnt )
476  fprintf( ioQQQ, "%s", prt_linecol.col_gap.c_str() );
477  }
478  /* now end the lines */
479  fprintf( ioQQQ, "\n" );
480  }
481 
482  if( nNegIntenLines > 0 )
483  {
484  fprintf( ioQQQ, " Lines with negative intensities - Linear intensities relative to normalize line.\n" );
485  fprintf( ioQQQ, " " );
486 
487  for( i=0; i < nNegIntenLines; ++i )
488  {
489  fprintf( ioQQQ, "%ld %s %.1e, ",
490  ipNegIntensity[i],
491  LineSave.lines[ipNegIntensity[i]].label().c_str(),
492  scaled[ipNegIntensity[i]] );
493  }
494  fprintf( ioQQQ, "\n" );
495  }
496  }
497 
498 
499  /* now find which were the very strongest, more that 5% of cooling */
500  j = 0;
501  for( i=0; i < LineSave.nsum; i++ )
502  {
503  a = (double)LineSave.lines[i].SumLine(0)/(double)thermal.totcol;
504  if( (a >= 0.05) && LineSave.lines[i].chSumTyp() == 'c' )
505  {
506  ipNegIntensity[j] = i;
507  d[j] = a;
508  j = MIN2(j+1,7);
509  }
510  }
511 
512  fprintf( ioQQQ, "\n\n\n %s\n", input.chTitle );
513  if( j != 0 )
514  {
515  fprintf( ioQQQ, " Cooling: " );
516  for( i=0; i < j; i++ )
517  {
518  fprintf( ioQQQ, " ");
519  LineSave.lines[ipNegIntensity[i]].prt(ioQQQ);
520  fprintf( ioQQQ, ":%5.3f",
521  d[i] );
522  }
523  fprintf( ioQQQ, " \n" );
524  }
525 
526  /* now find strongest heating, more that 5% of total */
527  j = 0;
528  for( i=0; i < LineSave.nsum; i++ )
529  {
530  a = safe_div((double)LineSave.lines[i].SumLine(0),(double)thermal.power,0.0);
531  if( (a >= 0.05) && LineSave.lines[i].chSumTyp() == 'h' )
532  {
533  ipNegIntensity[j] = i;
534  d[j] = a;
535  j = MIN2(j+1,7);
536  }
537  }
538 
539  if( j != 0 )
540  {
541  fprintf( ioQQQ, " Heating: " );
542  for( i=0; i < j; i++ )
543  {
544  fprintf( ioQQQ, " ");
545  LineSave.lines[ipNegIntensity[i]].prt(ioQQQ);
546  fprintf( ioQQQ, ":%5.3f",
547  d[i] );
548  }
549  fprintf( ioQQQ, " \n" );
550  }
551 
552  return;
553 }
554 
555 void PrtFinal(void)
556 {
557  char chCKey[5],
558  chGeo[7],
559  chPlaw[21];
560  const char* chUnit;
561 
562  long int
563  i,
564  ip2500,
565  ip2kev,
566  j;
567  double o4363,
568  bacobs,
569  absint,
570  bacthn,
571  hbcab,
572  hbeta,
573  o5007;
574 
575  double a,
576  ajmass,
577  ajmin,
578  alfox,
579  bot,
580  bottom,
581  bremtk,
582  coleff,
583  dmean,
584  ferode,
585  he4686,
586  he5876,
587  heabun,
588  hescal,
589  pion,
590  plow,
591  powerl,
592  qion,
593  qlow,
594  rate,
595  ratio,
596  reclin,
597  rjeans,
598  tmean,
599  top,
600  THI,/* HI 21 cm spin temperature */
601  uhel,
602  uhl,
603  usp,
604  wmean,
605  znit;
606 
607  double bac,
608  tel,
609  x;
610 
611  DEBUG_ENTRY( "PrtFinal()" );
612 
613  /* return if not talking */
614  /* >>chng 05 nov 11, also if nzone is zero, sign of abort before model got started */
615  if( !called.lgTalk || (lgAbort && nzone< 1) )
616  {
617  return;
618  }
619 
620  /* print out header, or parts that were saved */
621 
622  /* this would be a major logical error */
623  ASSERT( LineSave.nsum > 1 );
624 
625  /* print name and version number */
626  fprintf( ioQQQ, "\f\n");
627  fprintf( ioQQQ, "%23c", ' ' );
628  int len = (int)strlen(t_version::Inst().chVersion);
629  int repeat = (72-len)/2;
630  for( i=0; i < repeat; ++i )
631  fprintf( ioQQQ, "*" );
632  fprintf( ioQQQ, "> Cloudy %s <", t_version::Inst().chVersion );
633  for( i=0; i < 72-repeat-len; ++i )
634  fprintf( ioQQQ, "*" );
635  fprintf( ioQQQ, "\n" );
636 
637  for( i=0; i <= input.nSave; i++ )
638  {
639  if( input.InclLevel[i] > 0 || !input.lgVisible[i] )
640  continue;
641 
642  /* copy start of command to key, making it into capitals */
643  cap4(chCKey,input.chCardSav[i]);
644 
645  /* print if not continue */
646  if( strcmp(chCKey,"CONT") != 0 )
647  fprintf( ioQQQ, "%23c* %-80s*\n", ' ', input.chCardSav[i] );
648  }
649 
650  /* print log of ionization parameter if greater than zero - U==0 for PDR calcs */
651  if( rfield.uh > 0. )
652  {
653  a = log10(rfield.uh);
654  }
655  else
656  {
657  a = -37.;
658  }
659 
660  fprintf( ioQQQ,
661  " *********************************> Log(U):%6.2f <*********************************\n",
662  a );
663 
664  if( t_version::Inst().nBetaVer > 0 )
665  {
666  fprintf( ioQQQ,
667  "\n This is a beta test version of the code, and is intended for testing only.\n\n" );
668  }
669 
670  if( warnings.lgWarngs )
671  {
672  fprintf( ioQQQ, " \n" );
673  fprintf( ioQQQ, " >>>>>>>>>> Warning!\n" );
674  fprintf( ioQQQ, " >>>>>>>>>> Warning!\n" );
675  fprintf( ioQQQ, " >>>>>>>>>> Warning! Warnings exist, this calculation has serious problems.\n" );
676  fprintf( ioQQQ, " >>>>>>>>>> Warning!\n" );
677  fprintf( ioQQQ, " >>>>>>>>>> Warning!\n" );
678  fprintf( ioQQQ, " \n" );
679  }
680  else if( warnings.lgCautns )
681  {
682  fprintf( ioQQQ,
683  " >>>>>>>>>> Cautions are present.\n" );
684  }
685 
686  if( conv.lgBadStop )
687  {
688  fprintf( ioQQQ,
689  " >>>>>>>>>> The calculation stopped for unintended reasons.\n" );
690  }
691 
692  if( iterations.lgIterAgain )
693  {
694  fprintf( ioQQQ,
695  " >>>>>>>>>> Another iteration is needed. Use the ITERATE command.\n" );
696  }
697 
698  /* open or closed geometry?? */
699  if( geometry.lgSphere )
700  {
701  strcpy( chGeo, "Closed" );
702  }
703  else
704  {
705  strcpy( chGeo, " Open" );
706  }
707 
708  /* now give description of pressure law */
709  if( strcmp(dense.chDenseLaw,"CPRE") == 0 )
710  {
711  strcpy( chPlaw, " Constant Pressure " );
712  }
713 
714  else if( strcmp(dense.chDenseLaw,"CDEN") == 0 )
715  {
716  strcpy( chPlaw, " Constant Density " );
717  }
718 
719  else if( (strcmp(dense.chDenseLaw,"POWD") == 0 || strcmp(dense.chDenseLaw
720  ,"POWR") == 0) || strcmp(dense.chDenseLaw,"POWC") == 0 )
721  {
722  strcpy( chPlaw, " Power Law Density " );
723  }
724 
725  else if( strcmp(dense.chDenseLaw,"SINE") == 0 )
726  {
727  strcpy( chPlaw, " Rapid Fluctuations " );
728  }
729 
730  else if( strncmp(dense.chDenseLaw , "DLW" , 3) == 0 )
731  {
732  strcpy( chPlaw, " Special Density Lw " );
733  }
734 
735  else if( strcmp(dense.chDenseLaw,"HYDR") == 0 )
736  {
737  strcpy( chPlaw, " Hydrostatic Equlib " );
738  }
739 
740  else if( strcmp(dense.chDenseLaw,"WIND") == 0 )
741  {
742  strcpy( chPlaw, " Radia Driven Wind " );
743  }
744 
745  else if( strcmp(dense.chDenseLaw,"DYNA") == 0 )
746  {
747  strcpy( chPlaw, " Dynamical Flow " );
748  }
749 
750  else if( strcmp(dense.chDenseLaw,"GLOB") == 0 )
751  {
752  strcpy( chPlaw, " Globule " );
753  }
754 
755  else
756  {
757  strcpy( chPlaw, " UNRECOGNIZED CPRES " );
758  }
759 
760  fprintf( ioQQQ,
761  "\n Emission Line Spectrum. %20.20sModel. %6.6s geometry. Iteration %ld of %ld.\n",
762  chPlaw, chGeo, iteration, iterations.itermx + 1 );
763 
764  /* emission lines as logs of total luminosity */
766  {
767  char chLine[INPUT_LINE_LENGTH];
768  if( geometry.iEmissPower == 1 && !geometry.lgSizeSet )
769  chUnit = "/arcsec";
770  else if( geometry.iEmissPower == 0 && !geometry.lgSizeSet )
771  chUnit = "/arcsec^2";
772  else
773  chUnit = "";
774 
775  sprintf( chLine, "Flux observed at the Earth (erg/s/cm^2%s).", chUnit );
776  PrintCenterLine( ioQQQ, chLine, sizeof(chLine), 130 );
777  }
778  else if( prt.lgSurfaceBrightness )
779  {
780  char chLine[INPUT_LINE_LENGTH];
782  chUnit = "sr";
783  else
784  chUnit = "arcsec^2";
785 
786  sprintf( chLine, "Surface brightness (erg/s/cm^2/%s).", chUnit );
787  PrintCenterLine( ioQQQ, chLine, sizeof(chLine), 130 );
788  }
789  else if( radius.lgPredLumin )
790  {
791  char chLine[INPUT_LINE_LENGTH];
792  if( geometry.iEmissPower == 2 )
793  chUnit = "erg/s";
794  else if( geometry.iEmissPower == 1 )
795  chUnit = "erg/s/cm";
796  else if( geometry.iEmissPower == 0 )
797  chUnit = "erg/s/cm^2";
798  else
799  TotalInsanity();
800 
801  char chCoverage[INPUT_LINE_LENGTH/2];
802  if( fp_equal( geometry.covgeo, realnum(1.) ) )
803  sprintf( chCoverage, "with full coverage" );
804  else
805  sprintf( chCoverage, "with a covering factor of %.1f%%", geometry.covgeo*100. );
806 
807  if( radius.lgCylnOn )
808  sprintf( chLine, "Luminosity (%s) emitted by a partial cylinder %s.", chUnit, chCoverage );
809  else
810  sprintf( chLine, "Luminosity (%s) emitted by a shell %s.", chUnit, chCoverage );
811  PrintCenterLine( ioQQQ, chLine, sizeof(chLine), 130 );
812 
813  if( geometry.iEmissPower != 2 )
814  {
815  const char* chAper;
816  if( geometry.iEmissPower == 1 )
817  chAper = "long slit";
818  else if( geometry.iEmissPower == 0 )
819  chAper = "pencil beam";
820  else
821  TotalInsanity();
822 
823  sprintf( chLine, "Observed through a %s with aperture covering factor %.1f%%.",
824  chAper, geometry.covaper*100. );
825  PrintCenterLine( ioQQQ, chLine, sizeof(chLine), 130 );
826  }
827  }
828  else
829  {
830  char chLine[INPUT_LINE_LENGTH];
831  sprintf( chLine, "Intensity (erg/s/cm^2)." );
832  PrintCenterLine( ioQQQ, chLine, sizeof(chLine), 130 );
833  }
834 
835  fprintf( ioQQQ, "\n" );
836 
837  /******************************************************************
838  * kill Hummer & Storey case b predictions if outside their table *
839  ******************************************************************/
840 
841  /* >>chng 02 aug 29, from lgHCaseBOK to following - caught by Ryan Porter */
842  if( !atmdat.lgHCaseBOK[1][ipHYDROGEN] )
843  {
844  static const int NWLH = 21;
845  /* list of all H case b lines */
846  realnum wlh[NWLH] = { 6562.81e0f, 4861.33e0f, 4340.46e0f, 4101.73e0f, 1.87510e4f, 1.28180e4f,
847  1.09380e4f, 1.00493e4f, 2.62513e4f, 2.16551e4f, 1.94454e4f, 7.45777e4f,
848  4.65247e4f, 3.73951e4f, 4.05113e4f, 7.45777e4f, 3.29607e4f, 1215.67e0f,
849  1025.72e0f, 972.537e0f, 949.743e0f };
850 
851  /* table exceeded - kill all H case b predictions*/
852  for( i=0; i < LineSave.nsum; i++ )
853  {
854  /* >>chng 04 jun 21, kill both case a and b at same time,
855  * actually lgHCaseBOK has separate A and B flags, but
856  * this is simpler */
857  if( LineSave.lines[i].isCaseB() ||
858  LineSave.lines[i].isCaseA() )
859  {
860  realnum errorwave;
861  /* this logic must be kept parallel with which H lines are
862  * added as case B in lines_hydro - any automatic hosing of
863  * case b would kill both H I and He II */
864  errorwave = WavlenErrorGet( LineSave.lines[i].wavelength(), LineSave.sig_figs );
865  for( j=0; j<NWLH; ++j )
866  {
867  if( fabs(LineSave.lines[i].wavelength()-wlh[j] ) <= errorwave )
868  {
869  LineSave.lines[i].SumLineZero();
870  break;
871  }
872  }
873  }
874  }
875  }
876 
877  if( !atmdat.lgHCaseBOK[1][ipHELIUM] )
878  {
879  /* table exceeded - kill all He case b predictions*/
880  static const int NWLHE = 20;
881  realnum wlhe[NWLHE] = {1640.43e0f, 1215.13e0f, 1084.94e0f, 1025.27e0f, 4685.64e0f, 3203.04e0f,
882  2733.24e0f, 2511.15e0f, 1.01233e4f, 6559.91e0f, 5411.37e0f, 4859.18e0f,
883  1.86362e4f, 1.16260e4f, 9344.62, 8236.51e0f, 303.784e0f, 256.317e0f,
884  243.027e0f, 237.331e0f};
885  for( i=0; i < LineSave.nsum; i++ )
886  {
887  if( LineSave.lines[i].isCaseB() ||
888  LineSave.lines[i].isCaseA() )
889  {
890  realnum errorwave;
891  /* this logic must be kept parallel with which H lines are
892  * added as case B in lines_hydro - any automatic hosing of
893  * case b would kill both H I and He II */
894  errorwave = WavlenErrorGet( LineSave.lines[i].wavelength(), LineSave.sig_figs );
895  for( j=0; j<NWLHE; ++j )
896  {
897  if( fabs(LineSave.lines[i].wavelength()-wlhe[j] ) <= errorwave )
898  {
899  LineSave.lines[i].SumLineZero();
900  break;
901  }
902  }
903  }
904  }
905  }
906 
907  /**********************************************************
908  *analyse line arrays for abundances, temp, etc *
909  **********************************************************/
910 
911  /* find apparent helium abundance, will not find these if helium is turned off */
912 
913  if( cdLine("H 1",wlAirVac(4861.33),&hbeta,&absint)<=0 )
914  {
915  if( dense.lgElmtOn[ipHYDROGEN] )
916  {
917  /* this is a major logical error if hydrogen is turned on */
918  fprintf( ioQQQ, " PrtFinal could not find H 1 4861.33 with cdLine.\n" );
920  }
921  else
922  {
923  hbeta = 0;
924  absint = -37.;
925  }
926  }
927 
928  if( dense.lgElmtOn[ipHELIUM] )
929  {
930  /* get HeI 5876 */
931  /* >>chng 06 may 15, changed this so that it works for up to six sig figs. */
932  if( cdLine("He 1",wlAirVac(5875.64),&he5876,&absint)<=0 )
933  {
934  /* 06 aug 28, from numLevels_max to _local. */
935  if( iso_sp[ipHE_LIKE][ipHELIUM].numLevels_local >= 14 )
936  {
937  /* this is a major logical error if helium is turned on */
938  fprintf( ioQQQ, " PrtFinal could not find He 1 5876 with cdLine.\n" );
940  }
941  }
942 
943  /* get HeII 4686 */
944  /* >>chng 06 may 15, changed this so that it works for up to six sig figs. */
945  if( cdLine("He 2",wlAirVac(4685.64),&he4686,&absint)<=0 )
946  {
947  /* 06 aug 28, from numLevels_max to _local. */
948  if( iso_sp[ipH_LIKE][ipHELIUM].numLevels_local > 5 )
949  {
950  /* this is a major logical error if helium is turned on
951  * and the model atom has enough levels */
952  fprintf( ioQQQ, " PrtFinal could not find He 2 4686 with cdLine.\n" );
954  }
955  }
956  }
957  else
958  {
959  he5876 = 0.;
960  absint = 0.;
961  he4686 = 0.;
962  }
963 
964  if( hbeta > 0. )
965  {
966  heabun = (he4686*0.078 + he5876*0.739)/hbeta;
967  }
968  else
969  {
970  heabun = 0.;
971  }
972 
973  if( dense.lgElmtOn[ipHELIUM] )
974  {
975  hescal = heabun/(dense.gas_phase[ipHELIUM]/dense.gas_phase[ipHYDROGEN]);
976  }
977  else
978  {
979  hescal = 0.;
980  }
981 
982  /* get temperature from [OIII] spectrum, o may be turned off,
983  * but lines still dumped into stack */
985  {
986 
987  if( cdLine("blnd",5007,&o5007,&absint)<=0 )
988  {
989  if( dense.lgElmtOn[ipOXYGEN] )
990  {
991  /* this is a major logical error if hydrogen is turned on */
992  fprintf( ioQQQ, " PrtFinal could not find O 3 5007 with cdLine.\n" );
994  }
995  }
996 
997  if( cdLine("blnd",4363,&o4363,&absint)<=0 )
998  {
999  if( dense.lgElmtOn[ipOXYGEN] )
1000  {
1001  /* this is a major logical error if hydrogen is turned on */
1002  fprintf( ioQQQ, " PrtFinal could not find H 1 4363 with cdLine.\n" );
1004  }
1005  }
1006 
1007  // Energy ratio of O3 lines -- better to get this from transition structures
1008  realnum o3enro = (realnum)(4.56e-12/3.98e-12);
1009  /* first find low density limit OIII zone temp */
1010  if( (o4363 != 0.) && (o5007 != 0.) )
1011  {
1012  /* following will assume coll excitation only, so correct
1013  * for 4363's that cascade as 5007 */
1014  bot = o5007 - o4363/o3enro;
1015 
1016  if( bot > 0. )
1017  {
1018  ratio = o4363/bot;
1019  }
1020  else
1021  {
1022  ratio = 0.178;
1023  }
1024 
1025  if( ratio > 0.177 )
1026  {
1027  /* ratio was above infinite temperature limit */
1028  peimbt.toiiir = 1e10;
1029  }
1030  else
1031  {
1032  /* o iii 5007+4959, As 96 NIST */
1033  /*The cs of the transitions 3P0,1,2 to 1D2 are added together to give oiii_cs3P1D2 */
1034  /*the cs of the transition 1D2-1S0 is mentioned as oiii_cs1D21S0*/
1035  /*The cs of the transitions 3P0,1,2 to 1S0 are added together to give oiii_cs3P1S0*/
1036  realnum o3cs12 = 2.2347f;
1037  realnum o3cs13 = 0.29811f;
1038  double a31 = 0.2262;
1039  double a32 = 1.685;
1040  realnum o3ex23 = 32947.;
1041  realnum o3br32 = (realnum)(a32/(a31 + a32));
1042 
1043  /* data for following set in OIII cooling routine
1044  * ratio of collision strengths, factor of 4/3 makes 5007+4959
1045  * >>chng 96 sep 07, reset cs to values at 10^4K,
1046  * had been last temp in model */
1047  /*>>chng 06 jul 25, update to recent data */
1048  ratio = ratio/1.3333/(o3cs13/o3cs12);
1049  /* ratio of energies and branching ratio for 4363 */
1050  ratio = ratio/o3enro/o3br32;
1051  peimbt.toiiir = (realnum)(-o3ex23/log(ratio));
1052  }
1053  }
1054  else
1055  {
1056  peimbt.toiiir = 0.;
1057  }
1058  }
1059 
1060  if( geometry.iEmissPower == 2 )
1061  {
1062  /* find temperature from Balmer continuum */
1063  if( cdLine("Bac ",3646.,&bacobs,&absint)<=0 )
1064  {
1065  fprintf( ioQQQ, " PrtFinal could not find Bac 3646 with cdLine.\n" );
1067  }
1068 
1069  /* we pulled hbeta out of stack with cdLine above */
1070  if( hbeta > 0. )
1071  {
1072  bac = bacobs/hbeta;
1073  }
1074  else
1075  {
1076  bac = 0.;
1077  }
1078  }
1079  else
1080  {
1081  bac = 0.;
1082  }
1083 
1084  if( bac > 0. )
1085  {
1086  /*----------------------------------------------------------*
1087  ***** TableCurve c:\tcwin2\balcon.for Sep 6, 1994 11:13:38 AM
1088  ***** log bal/Hbet
1089  ***** X= log temp
1090  ***** Y=
1091  ***** Eqn# 6503 y=a+b/x+c/x^2+d/x^3+e/x^4+f/x^5
1092  ***** r2=0.9999987190883581
1093  ***** r2adj=0.9999910336185065
1094  ***** StdErr=0.001705886369042427
1095  ***** Fval=312277.1895753243
1096  ***** a= -4.82796940090671
1097  ***** b= 33.08493347410885
1098  ***** c= -56.08886262205931
1099  ***** d= 52.44759454803217
1100  ***** e= -25.07958990094209
1101  ***** f= 4.815046760060006
1102  *----------------------------------------------------------*
1103  * bac is double precision!!!! */
1104  x = 1.e0/log10(bac);
1105  tel = -4.827969400906710 + x*(33.08493347410885 + x*(-56.08886262205931 +
1106  x*(52.44759454803217 + x*(-25.07958990094209 + x*(4.815046760060006)))));
1107 
1108  if( tel > 1. && tel < 5. )
1109  {
1110  peimbt.tbac = (realnum)exp10(tel);
1111  }
1112  else
1113  {
1114  peimbt.tbac = 0.;
1115  }
1116  }
1117  else
1118  {
1119  peimbt.tbac = 0.;
1120  }
1121 
1122  if( geometry.iEmissPower == 2 )
1123  {
1124  /* find temperature from optically thin Balmer continuum and case B H-beta */
1125  if( cdLine("thin",3646.,&bacthn,&absint)<=0 )
1126  {
1127  fprintf( ioQQQ, " PrtFinal could not find thin 3646 with cdLine.\n" );
1129  }
1130 
1131  /* >>chng 06 may 15, changed this so that it works for up to six sig figs. */
1132  if( cdLine("Ca B",wlAirVac(4861.33),&hbcab,&absint)<=0 )
1133  {
1134  fprintf( ioQQQ, " PrtFinal could not find Ca B 4861.33 with cdLine.\n" );
1136  }
1137 
1138  if( hbcab > 0. )
1139  {
1140  bacthn /= hbcab;
1141  }
1142  else
1143  {
1144  bacthn = 0.;
1145  }
1146  }
1147  else
1148  {
1149  bacthn = 0.;
1150  }
1151 
1152  if( bacthn > 0. )
1153  {
1154  /*----------------------------------------------------------*
1155  ***** TableCurve c:\tcwin2\balcon.for Sep 6, 1994 11:13:38 AM
1156  ***** log bal/Hbet
1157  ***** X= log temp
1158  ***** Y=
1159  ***** Eqn# 6503 y=a+b/x+c/x^2+d/x^3+e/x^4+f/x^5
1160  ***** r2=0.9999987190883581
1161  ***** r2adj=0.9999910336185065
1162  ***** StdErr=0.001705886369042427
1163  ***** Fval=312277.1895753243
1164  ***** a= -4.82796940090671
1165  ***** b= 33.08493347410885
1166  ***** c= -56.08886262205931
1167  ***** d= 52.44759454803217
1168  ***** e= -25.07958990094209
1169  ***** f= 4.815046760060006
1170  *----------------------------------------------------------*
1171  * bac is double precision!!!! */
1172  x = 1.e0/log10(bacthn);
1173  tel = -4.827969400906710 + x*(33.08493347410885 + x*(-56.08886262205931 +
1174  x*(52.44759454803217 + x*(-25.07958990094209 + x*(4.815046760060006)))));
1175 
1176  if( tel > 1. && tel < 5. )
1177  {
1178  peimbt.tbcthn = (realnum)exp10(tel);
1179  }
1180  else
1181  {
1182  peimbt.tbcthn = 0.;
1183  }
1184  }
1185  else
1186  {
1187  peimbt.tbcthn = 0.;
1188  }
1189 
1190  /* we now have temps from OIII ratio and BAC ratio, now
1191  * do Peimbert analysis, getting To and t^2 */
1192 
1193  peimbt.tohyox = (realnum)((8.5*peimbt.toiiir - 7.5*peimbt.tbcthn - 228200. +
1194  sqrt(POW2(8.5*peimbt.toiiir-7.5*peimbt.tbcthn-228200.)+9.128e5*
1195  peimbt.tbcthn))/2.);
1196 
1197  if( peimbt.tohyox > 0. )
1198  {
1200  }
1201  else
1202  {
1203  peimbt.t2hyox = 0.;
1204  }
1205 
1206  if( prt.lgPrintBlock )
1207  PrintSpectrum();
1208 
1209  // don't print this text twice...
1210  if( !prt.lgPrtCitations )
1211  {
1212  fprintf( ioQQQ, "\n" );
1214  }
1215 
1216  /* print out ionization parameters and radiation making it through */
1217  qlow = 0.;
1218  plow = 0.;
1219  for( i=0; i < (iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].ipIsoLevNIonCon - 1); i++ )
1220  {
1221  /* N.B. in following en1ryd prevents overflow */
1222  plow += (rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i])*
1223  EN1RYD*rfield.anu(i);
1224  qlow += rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i];
1225  }
1226 
1227  qlow *= radius.r1r0sq;
1228  plow *= radius.r1r0sq;
1229  if( plow > 0. )
1230  {
1231  qlow = log10(qlow * radius.Conv2PrtInten);
1232  plow = log10(plow * radius.Conv2PrtInten);
1233  }
1234  else
1235  {
1236  qlow = 0.;
1237  plow = 0.;
1238  }
1239 
1240  qion = 0.;
1241  pion = 0.;
1242  for( i=iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].ipIsoLevNIonCon-1; i < rfield.nflux; i++ )
1243  {
1244  /* N.B. in following en1ryd prevents overflow */
1245  pion += (rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i])*
1246  EN1RYD*rfield.anu(i);
1247  qion += rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i];
1248  }
1249 
1250  qion *= radius.r1r0sq;
1251  pion *= radius.r1r0sq;
1252 
1253  if( pion > 0. )
1254  {
1255  qion = log10(qion * radius.Conv2PrtInten);
1256  pion = log10(pion * radius.Conv2PrtInten);
1257  }
1258  else
1259  {
1260  qion = 0.;
1261  pion = 0.;
1262  }
1263 
1264  /* derive ionization parameter for spherical geometry */
1265  if( rfield.qhtot > 0. )
1266  {
1267  if( rfield.lgUSphON )
1268  {
1269  /* RSTROM is stromgren radius */
1271  2.998e10/dense.gas_phase[ipHYDROGEN];
1272  usp = log10(usp);
1273  }
1274  else
1275  {
1276  /* no stromgren radius found, use outer radius */
1278  usp = log10(usp);
1279  }
1280  }
1281 
1282  else
1283  {
1284  usp = -37.;
1285  }
1286 
1287  if( rfield.uh > 0. )
1288  {
1289  uhl = log10(rfield.uh);
1290  }
1291  else
1292  {
1293  uhl = -37.;
1294  }
1295 
1296  if( rfield.uheii > 0. )
1297  {
1298  uhel = log10(rfield.uheii);
1299  }
1300  else
1301  {
1302  uhel = -37.;
1303  }
1304 
1305  fprintf( ioQQQ,
1306  "\n IONIZE PARMET: U(1-)%8.4f U(4-):%8.4f U(sp):%6.2f "
1307  "Q(ion): %7.3f L(ion)%7.3f Q(low):%7.3f L(low)%7.3f\n",
1308  uhl, uhel, usp, qion, pion, qlow, plow );
1309 
1310  a = safe_div(fabs((thermal.power-thermal.totcol)*100.),thermal.power,0.0);
1311  /* output power and total cooling; can be neg for shocks, collisional ioniz */
1312  if( thermal.power > 0. )
1313  {
1314  powerl = log10(thermal.power * radius.Conv2PrtInten);
1315  }
1316  else
1317  {
1318  powerl = 0.;
1319  }
1320 
1321  if( thermal.totcol > 0. )
1322  {
1324  }
1325  else
1326  {
1327  thermal.totcol = 0.;
1328  }
1329 
1330  if( thermal.FreeFreeTotHeat > 0. )
1331  {
1333  }
1334  else
1335  {
1336  thermal.FreeFreeTotHeat = 0.;
1337  }
1338 
1339  /* following is recombination line intensity */
1340  reclin = totlin('r');
1341  if( reclin > 0. )
1342  {
1343  reclin = log10(reclin * radius.Conv2PrtInten);
1344  }
1345  else
1346  {
1347  reclin = 0.;
1348  }
1349 
1350  fprintf( ioQQQ,
1351  " ENERGY BUDGET: Heat:%8.3f Coolg:%8.3f Error:%5.1f%% Rec Lin:%8.3f F-F H%7.3f P(rad/tot)max ",
1352  powerl,
1353  thermal.totcol,
1354  a,
1355  reclin,
1358  // resolving power in fine continuum for this run
1359  fprintf(ioQQQ," R(F Con):%.3e",
1360  SPEEDLIGHT / rfield.fine_opac_velocity_width );
1361 
1362  fprintf( ioQQQ, "\n");
1363 
1364  /* effective x-ray column density, from 0.5keV attenuation, no scat
1365  * IPXRY is pointer to 73.5 Ryd */
1366  coleff = opac.TauAbsGeo[0][rt.ipxry-1] - rt.tauxry;
1367  coleff /= 2.14e-22;
1368 
1369  /* find t^2 from H II structure */
1370  gett2(&peimbt.t2hstr);
1371 
1372  /* find t^2 from OIII structure */
1374 
1375  fprintf( ioQQQ, "\n Col(Heff): ");
1376  PrintE93(ioQQQ, coleff);
1377  fprintf( ioQQQ, " snd travl time ");
1379  fprintf( ioQQQ, " sec Te-low: ");
1381  fprintf( ioQQQ, " Te-hi: ");
1383 
1384  /* this is the intensity of the UV continuum at the illuminated face, relative to the Habing value, as
1385  * defined by Tielens & Hollenbach 1985 */
1386  fprintf( ioQQQ, " G0TH85: ");
1388  /* this is the intensity of the UV continuum at the illuminated face, relative to the Habing value, as
1389  * defined by Draine & Bertoldi 1985 */
1390  fprintf( ioQQQ, " G0DB96:");
1392 
1393  fprintf( ioQQQ, "\n");
1394 
1395  fprintf( ioQQQ, " Emiss Measure n(e)n(p) dl ");
1397  fprintf( ioQQQ, " n(e)n(He+)dl ");
1399  fprintf( ioQQQ, " En(e)n(He++) dl ");
1401  fprintf( ioQQQ, " ne nC+:");
1403  fprintf( ioQQQ, "\n");
1404 
1405  /* following is wl where gas goes thick to bremsstrahlung, in cm */
1406  if( rfield.EnergyBremsThin > 0. )
1407  {
1408  bremtk = RYDLAM*1e-8/rfield.EnergyBremsThin;
1409  }
1410  else
1411  {
1412  bremtk = 1e30;
1413  }
1414 
1415  /* apparent helium abundance */
1416  fprintf( ioQQQ, " He/Ha:");
1417  PrintE82( ioQQQ, heabun);
1418 
1419  /* he/h relative to correct helium abundance */
1420  fprintf(ioQQQ, " =%7.2f*true Lthin:",hescal);
1421 
1422  /* wavelength were structure is optically thick to bremsstrahlung absorption */
1423  PrintE82( ioQQQ, bremtk);
1424 
1425  /* this is ratio of conv.nTotalIoniz, the number of times ConvBase
1426  * was called during the model, over the number of zones.
1427  * This is a measure of the convergence of the model -
1428  * includes initial search so worse for short calculations.
1429  * It is a measure of how hard the model was to converge */
1430  if( nzone > 0 )
1431  {
1432  /* >>chng 07 feb 23, subtract n calls to do initial solution
1433  * so this is the number of calls needed to converge the zones.
1434  * different is to discount careful approach to molecular solutions
1435  * in one zone models */
1436  znit = (double)(conv.nTotalIoniz-conv.nTotalIoniz_start)/(double)(nzone);
1437  }
1438  else
1439  {
1440  znit = 0.;
1441  }
1442  /* >>chng 02 jan 09, format from 5.3f to 5.2f */
1443  fprintf(ioQQQ, " itr/zn:%5.2f",znit);
1444 
1445  /* sort-of same thing for large H2 molecule - number is number of level pop solutions per zone */
1446  fprintf(ioQQQ, " H2 itr/zn:%6.2f",h2.H2_itrzn());
1447 
1448  /* say whether we used stored opacities (T) or derived them from scratch (F) */
1449  fprintf(ioQQQ, " File Opacity: F" );
1450 
1451  /* log of total mass in grams if spherical, or gm/cm2 if plane parallel */
1452  /* this is mass per unit inner area */
1453  double xmass;
1454  // if spherical change to total mass, if pp leave gm/cm2
1455  if( radius.pirsq > 0. )
1456  {
1457  chUnit = "(gm)";
1458  xmass = dense.xMassTotal * exp10( (double)radius.pirsq ) ;
1459  }
1460  else
1461  {
1462  chUnit = "(gm/cm^2)";
1463  xmass = dense.xMassTotal;
1464  }
1465  fprintf(ioQQQ," MassTot %.2e %s", xmass, chUnit );
1466  fprintf(ioQQQ,"\n");
1467 
1468  /* this block is a series of prints dealing with 21 cm quantities
1469  * first this is the temperature derived from Lya - 21 cm optical depths
1470  * get harmonic mean HI temperature, as needed for 21 cm spin temperature */
1471  if( cdTemp( "opti",0,&THI,"volume" ) )
1472  {
1473  fprintf(ioQQQ,"\n>>>>>>>>>>>>>>>>> PrtFinal, impossible problem getting 21cm opt.\n");
1474  TotalInsanity();
1475  }
1476  fprintf( ioQQQ, " Temps(21 cm) T(21cm/Ly a) ");
1477  PrintE82(ioQQQ, THI );
1478 
1479  /* get harmonic mean HI gas kin temperature, as needed for 21 cm spin temperature
1480  * >>chng 06 jul 21, this was over volume but hazy said radius - change to radius,
1481  * bug discovered by Eric Pellegrini & Jack Baldwin */
1482  /*if( cdTemp( "21cm",0,&THI,"volume" ) )*/
1483  if( cdTemp( "21cm",0,&THI,"radius" ) )
1484  {
1485  fprintf(ioQQQ,"\n>>>>>>>>>>>>>>>>> PrtFinal, impossible problem getting 21cm temp.\n");
1486  TotalInsanity();
1487  }
1488  fprintf(ioQQQ, " T(<nH/Tkin>) ");
1489  PrintE82(ioQQQ, THI);
1490 
1491  /* get harmonic mean HI 21 21 spin temperature, as needed for 21 cm spin temperature
1492  * for this, always weighted by radius, volume would be ignored were it present */
1493  if( cdTemp( "spin",0,&THI,"radius" ) )
1494  {
1495  fprintf(ioQQQ,"\n>>>>>>>>>>>>>>>>> PrtFinal, impossible problem getting 21cm spin.\n");
1496  TotalInsanity();
1497  }
1498  fprintf(ioQQQ, " T(<nH/Tspin>) ");
1499  PrintE82(ioQQQ, THI);
1500 
1501  /* now convert this HI spin temperature into a brightness temperature */
1502  THI *= (1. - sexp( HFLines[0].Emis().TauIn() ) );
1503  fprintf( ioQQQ, " TB21cm:");
1504  PrintE82(ioQQQ, THI);
1505  fprintf( ioQQQ, "\n");
1506 
1507  fprintf( ioQQQ, " N(H0/Tspin) ");
1509  fprintf( ioQQQ, " N(OH/Tkin) ");
1511 
1512  /* mean B weighted wrt 21 cm absorption */
1513  bot = cdB21cm();
1514  fprintf( ioQQQ, " B(21cm) ");
1515  PrintE82(ioQQQ, bot );
1516 
1517  /* end prints for 21 cm */
1518  fprintf(ioQQQ, "\n");
1519 
1520  /* timescale (sec here) for photoerosion of Fe-Ni */
1521  rate = timesc.TimeErode*2e-26;
1522  if( rate > SMALLFLOAT )
1523  {
1524  ferode = 1./rate;
1525  }
1526  else
1527  {
1528  ferode = 0.;
1529  }
1530 
1531  /* mean acceleration */
1532  if( wind.acldr > 0. )
1533  {
1534  wind.AccelAver /= wind.acldr;
1535  }
1536  else
1537  {
1538  wind.AccelAver = 0.;
1539  }
1540 
1541  /* DMEAN is mean density (gm per cc); mean temp is weighted by mass density */
1542  /* >>chng 02 aug 21, from radius.depth_x_fillfac to integral of radius times fillfac */
1544  tmean = colden.tmas/SDIV(colden.TotMassColl);
1545  /* mean mass per particle */
1546  wmean = colden.wmas/SDIV(colden.TotMassColl);
1547 
1548  fprintf( ioQQQ, " <a>:");
1550  fprintf( ioQQQ, " erdeFe");
1551  PrintE71(ioQQQ , ferode);
1552  fprintf( ioQQQ, " Tcompt");
1554  fprintf( ioQQQ, " Tthr");
1556  fprintf( ioQQQ, " <Tden>: ");
1557  PrintE82(ioQQQ , tmean);
1558  fprintf( ioQQQ, " <dens>:");
1559  PrintE82(ioQQQ , dmean);
1560  fprintf( ioQQQ, " <MolWgt>");
1561  PrintE82(ioQQQ , wmean);
1562  fprintf(ioQQQ,"\n");
1563 
1564  /* log of Jeans length and mass - this is mean over model */
1565  if( tmean > 0. )
1566  {
1567  rjeans = (log10(JEANS)+log10(tmean) - log10(dense.wmole) - log10(dense.xMassDensity*
1568  geometry.FillFac))/2.;
1569  }
1570  else
1571  {
1572  /* tmean undefined, set rjeans to large value so 0 printed below */
1573  rjeans = 40.f;
1574  }
1575 
1576  if( rjeans < 36. )
1577  {
1578  rjeans = exp10(rjeans);
1579  /* AJMASS is Jeans mass in solar units */
1580  ajmass = 3.*log10(rjeans/2.) + log10(4.*PI/3.*dense.xMassDensity*
1581  geometry.FillFac) - log10(SOLAR_MASS);
1582  if( ajmass < 37 )
1583  {
1584  ajmass = exp10(ajmass);
1585  }
1586  else
1587  {
1588  ajmass = 0.;
1589  }
1590  }
1591  else
1592  {
1593  rjeans = 0.;
1594  ajmass = 0.;
1595  }
1596 
1597  /* Jeans length and mass - this is smallest over model */
1598  ajmin = colden.ajmmin - log10(SOLAR_MASS);
1599  if( ajmin < 37 )
1600  {
1601  ajmin = exp10(ajmin);
1602  }
1603  else
1604  {
1605  ajmin = 0.;
1606  }
1607 
1608  /* estimate alpha (o-x) */
1609  if( rfield.anu(rfield.nflux-1) > 150. )
1610  {
1611  /* generate pointers to energies where alpha ox will be evaluated */
1612  ip2kev = ipoint(147.);
1613  ip2500 = ipoint(0.3648);
1614 
1615  /* now get fluxes there */
1616  bottom = rfield.flux[0][ip2500-1]*
1617  rfield.anu(ip2500-1)/rfield.widflx(ip2500-1);
1618 
1619  top = rfield.flux[0][ip2kev-1]*
1620  rfield.anu(ip2kev-1)/rfield.widflx(ip2kev-1);
1621 
1622  /* generate alpha ox if denominator is non-zero */
1623  if( bottom > 1e-30 && top > 1e-30 )
1624  {
1625  ratio = log10(top) - log10(bottom);
1626  if( ratio < 36. && ratio > -36. )
1627  {
1628  ratio = exp10(ratio);
1629  }
1630  else
1631  {
1632  ratio = 0.;
1633  }
1634  }
1635 
1636  else
1637  {
1638  ratio = 0.;
1639  }
1640 
1641  if( ratio > 0. )
1642  {
1643  // the separate variable freq_ratio is needed to work around a bug in icc 10.0
1644  double freq_ratio = rfield.anu(ip2kev-1)/rfield.anu(ip2500-1);
1645  alfox = log(ratio)/log(freq_ratio);
1646  }
1647  else
1648  {
1649  alfox = 0.;
1650  }
1651  }
1652  else
1653  {
1654  alfox = 0.;
1655  }
1656 
1657  if( colden.rjnmin < 37 )
1658  {
1660  }
1661  else
1662  {
1663  colden.rjnmin = FLT_MAX;
1664  }
1665 
1666  fprintf( ioQQQ, " Mean Jeans l(cm)");
1667  PrintE82(ioQQQ, rjeans);
1668  fprintf( ioQQQ, " M(sun)");
1669  PrintE82(ioQQQ, ajmass);
1670  fprintf( ioQQQ, " smallest: len(cm):");
1672  fprintf( ioQQQ, " M(sun):");
1673  PrintE82(ioQQQ, ajmin);
1674  fprintf( ioQQQ, " a_ox tran:%6.2f\n" , alfox);
1675 
1676  fprintf( ioQQQ, " Rion:");
1677  double R_ion;
1678  if( rfield.lgUSphON )
1679  R_ion = rfield.rstrom;
1680  else
1681  R_ion = radius.Radius;
1682  PrintE93(ioQQQ, R_ion);
1683  fprintf( ioQQQ, " Dist:");
1685  fprintf( ioQQQ, " Diam:");
1686  if( radius.distance > 0. )
1687  PrintE93(ioQQQ, 2.*R_ion*AS1RAD/radius.distance);
1688  else
1689  PrintE93(ioQQQ, 0.);
1690  fprintf( ioQQQ, "\n");
1691 
1692  if( prt.lgPrintTime )
1693  {
1694  /* print execution time by default */
1695  alfox = cdExecTime();
1696  }
1697  else
1698  {
1699  /* flag set false with no time command, so that different runs can
1700  * compare exactly */
1701  alfox = 0.;
1702  }
1703 
1704  /* some details about the hydrogen and helium ions */
1705  fprintf( ioQQQ,
1706  " Hatom level%3ld HatomType:%4.4s HInducImp %2c"
1707  " He tot level:%3ld He2 level: %3ld ExecTime%8.1f\n",
1708  /* 06 aug 28, from numLevels_max to _local. */
1709  iso_sp[ipH_LIKE][ipHYDROGEN].numLevels_local,
1710  hydro.chHTopType,
1712  /* 06 aug 28, from numLevels_max to _local. */
1714  /* 06 aug 28, from numLevels_max to _local. */
1715  iso_sp[ipH_LIKE][ipHELIUM].numLevels_local ,
1716  alfox );
1717 
1718  /* now give an indication of the convergence error budget */
1719  fprintf( ioQQQ,
1720  " ConvrgError(%%) <eden>%7.3f MaxEden%7.3f <H-C>%7.2f Max(H-C)%8.2f <Press>%8.3f MaxPrs er%7.3f\n",
1721  conv.AverEdenError/nzone*100. ,
1722  conv.BigEdenError*100. ,
1723  conv.AverHeatCoolError/nzone*100. ,
1724  conv.BigHeatCoolError*100. ,
1725  conv.AverPressError/nzone*100. ,
1726  conv.BigPressError*100. );
1727 
1728  fprintf(ioQQQ,
1729  " Continuity(%%) chng Te%6.1f elec den%6.1f n(H2)%7.1f n(CO) %7.1f\n",
1730  phycon.BigJumpTe*100. ,
1731  phycon.BigJumpne*100. ,
1732  phycon.BigJumpH2*100. ,
1733  phycon.BigJumpCO*100. );
1734 
1735  /* print out some average quantities */
1736  fprintf( ioQQQ, "\n Averaged Quantities\n" );
1737  fprintf( ioQQQ, " Te Te(Ne) Te(NeNp) Te(NeHe+)Te(NeHe2+) Te(NeO+) Te(NeO2+)"
1738  " Te(H2) N(H) Ne(O2+) Ne(Np)\n" );
1739  static const char* weight[3] = { "Radius", "Area", "Volume" };
1740  int dmax = geometry.lgGeoPP ? 1 : 3;
1741  for( int dim=0; dim < dmax; ++dim )
1742  {
1743  fprintf( ioQQQ, " %6s:", weight[dim] );
1744  // <Te>/<1>
1745  PrintRatio( mean.TempMean[dim][0], mean.TempMean[dim][1] );
1746  // <Te*ne>/<ne>
1747  PrintRatio( mean.TempEdenMean[dim][0], mean.TempEdenMean[dim][1] );
1748  // <Te*ne*nion>/<ne*nion>
1749  PrintRatio( mean.TempIonEdenMean[dim][ipHYDROGEN][1][0], mean.TempIonEdenMean[dim][ipHYDROGEN][1][1] );
1750  PrintRatio( mean.TempIonEdenMean[dim][ipHELIUM][1][0], mean.TempIonEdenMean[dim][ipHELIUM][1][1] );
1751  PrintRatio( mean.TempIonEdenMean[dim][ipHELIUM][2][0], mean.TempIonEdenMean[dim][ipHELIUM][2][1] );
1752  PrintRatio( mean.TempIonEdenMean[dim][ipOXYGEN][1][0], mean.TempIonEdenMean[dim][ipOXYGEN][1][1] );
1753  PrintRatio( mean.TempIonEdenMean[dim][ipOXYGEN][2][0], mean.TempIonEdenMean[dim][ipOXYGEN][2][1] );
1754  // <Te*nH2>/<nH2>
1755  PrintRatio( mean.TempIonMean[dim][ipHYDROGEN][2][0], mean.TempIonMean[dim][ipHYDROGEN][2][1] );
1756  // <nH>/<1>
1757  PrintRatio( mean.xIonMean[dim][ipHYDROGEN][0][1], mean.TempMean[dim][1] );
1758  // <ne*nion>/<nion>
1759  PrintRatio( mean.TempIonEdenMean[dim][ipOXYGEN][2][1], mean.TempIonMean[dim][ipOXYGEN][2][1] );
1760  PrintRatio( mean.TempIonEdenMean[dim][ipHYDROGEN][1][1], mean.TempIonMean[dim][ipHYDROGEN][1][1] );
1761  fprintf( ioQQQ, "\n" );
1762  }
1763 
1764  /* print out Peimbert analysis, tsqden default 1e7, changed
1765  * with set tsqden command */
1767  {
1768  fprintf( ioQQQ, " \n" );
1769 
1770  /* temperature from the [OIII] 5007/4363 ratio */
1771  fprintf( ioQQQ, " Peimbert T(OIIIr)");
1773 
1774  /* temperature from predicted Balmer jump relative to Hbeta */
1775  fprintf( ioQQQ, " T(Bac)");
1776  PrintE82( ioQQQ , peimbt.tbac);
1777 
1778  /* temperature predicted from optically thin Balmer jump rel to Hbeta */
1779  fprintf( ioQQQ, " T(Hth)");
1781 
1782  /* t^2 predicted from the structure, weighted by H */
1783  fprintf( ioQQQ, " t2(Hstrc)");
1784  fprintf( ioQQQ,PrintEfmt("%9.2e", peimbt.t2hstr));
1785 
1786  /* temperature from both [OIII] and the Balmer jump rel to Hbeta */
1787  fprintf( ioQQQ, " T(O3-BAC)");
1789 
1790  /* t2 from both [OIII] and the Balmer jump rel to Hbeta */
1791  fprintf( ioQQQ, " t2(O3-BC)");
1792  fprintf( ioQQQ,PrintEfmt("%9.2e", peimbt.t2hyox));
1793 
1794  /* structural t2 from the O+2 predicted radial dependence */
1795  fprintf( ioQQQ, " t2(O3str)");
1796  fprintf( ioQQQ,PrintEfmt("%9.2e", peimbt.t2o3str));
1797 
1798  fprintf( ioQQQ, "\n");
1799 
1800  if( gv.lgDustOn() )
1801  {
1802  fprintf( ioQQQ, " Be careful: grains exist. This spectrum was not corrected for reddening before analysis.\n" );
1803  }
1804  }
1805 
1806  /* print average (over radius) grain dust parameters if lgDustOn() is true,
1807  * average quantities are incremented in radius_increment, zeroed in IterStart */
1808  if( gv.lgDustOn() && gv.lgGrainPhysicsOn )
1809  {
1810  char chQHeat;
1811  double AV , AB;
1812  double total_dust2gas = 0.;
1813 
1814  fprintf( ioQQQ, "\n Average Grain Properties (over radius):\n" );
1815 
1816  for( size_t i0=0; i0 < gv.bin.size(); i0 += 10 )
1817  {
1818  if( i0 > 0 )
1819  fprintf( ioQQQ, "\n" );
1820 
1821  /* this is upper limit to how many grain species we will print across line */
1822  size_t i1 = min(i0+10,gv.bin.size());
1823 
1824  fprintf( ioQQQ, " " );
1825  for( size_t nd=i0; nd < i1; nd++ )
1826  {
1827  chQHeat = (char)(gv.bin[nd]->lgEverQHeat ? '*' : ' ');
1828  fprintf( ioQQQ, "%-12.12s%c", gv.bin[nd]->chDstLab, chQHeat );
1829  }
1830  fprintf( ioQQQ, "\n" );
1831 
1832  fprintf( ioQQQ, " nd:" );
1833  for( size_t nd=i0; nd < i1; nd++ )
1834  {
1835  if( nd != i0 ) fprintf( ioQQQ," " );
1836  fprintf( ioQQQ, "%7ld ", (unsigned long)nd );
1837  }
1838  fprintf( ioQQQ, "\n" );
1839 
1840  fprintf( ioQQQ, " <Tgr>:" );
1841  for( size_t nd=i0; nd < i1; nd++ )
1842  {
1843  if( nd != i0 ) fprintf( ioQQQ," " );
1844  fprintf( ioQQQ,PrintEfmt("%10.3e", gv.bin[nd]->avdust/radius.depth_x_fillfac));
1845  }
1846  fprintf( ioQQQ, "\n" );
1847 
1848  fprintf( ioQQQ, " <Vel>:" );
1849  for( size_t nd=i0; nd < i1; nd++ )
1850  {
1851  if( nd != i0 ) fprintf( ioQQQ," " );
1852  fprintf( ioQQQ,PrintEfmt("%10.3e", gv.bin[nd]->avdft/radius.depth_x_fillfac));
1853  }
1854  fprintf( ioQQQ, "\n" );
1855 
1856  fprintf( ioQQQ, " <Pot>:" );
1857  for( size_t nd=i0; nd < i1; nd++ )
1858  {
1859  if( nd != i0 ) fprintf( ioQQQ," " );
1860  fprintf( ioQQQ,PrintEfmt("%10.3e", gv.bin[nd]->avdpot/radius.depth_x_fillfac));
1861  }
1862  fprintf( ioQQQ, "\n" );
1863 
1864  fprintf( ioQQQ, " <D/G>:" );
1865  for( size_t nd=i0; nd < i1; nd++ )
1866  {
1867  if( nd != i0 ) fprintf( ioQQQ," " );
1868  fprintf( ioQQQ,PrintEfmt("%10.3e", gv.bin[nd]->avDGRatio/radius.depth_x_fillfac));
1869  /* add up total dust to gas mass ratio */
1870  total_dust2gas += gv.bin[nd]->avDGRatio/radius.depth_x_fillfac;
1871  }
1872  fprintf( ioQQQ, "\n" );
1873  }
1874 
1875  fprintf(ioQQQ," Dust to gas ratio (by mass):");
1876  fprintf(ioQQQ,PrintEfmt("%10.3e", total_dust2gas));
1877 
1878  /* total extinction (conv to mags) at V and B per hydrogen, this includes
1879  * forward scattering as an extinction process, so is what would be measured
1880  * for a star, but not for an extended source where forward scattering
1881  * should be discounted */
1884  /* print A_V/N(Htot) for point and extended sources */
1885  fprintf(ioQQQ,", A(V)/N(H)(pnt):%.3e, (ext):%.3e",
1886  AV,
1888 
1889  /* ratio of total to selective extinction */
1890  fprintf(ioQQQ,", R:");
1891 
1892  /* gray grains have AB - AV == 0 */
1893  if( fabs(AB-AV)>SMALLFLOAT )
1894  {
1895  fprintf(ioQQQ,"%.3e", AV/(AB-AV) );
1896  }
1897  else
1898  {
1899  fprintf(ioQQQ,"%.3e", 0. );
1900  }
1901  fprintf(ioQQQ," AV(ext):%.3e (pnt):%.3e\n",
1904  }
1905 
1906  /* option to make short printout */
1907  if( !prt.lgPrtShort && called.lgTalk )
1908  {
1909  /* print log of optical depths,
1910  * calls prtmet if print line optical depths command entered */
1911  PrtAllTau();
1912 
1913  /* only print mean ionization and emergent continuum on last iteration */
1914  if( iterations.lgLastIt )
1915  {
1916  /* option to print column densities, set with print column density command */
1917  if( prt.lgPrintColumns )
1918  PrtColumns(ioQQQ);
1919  /* print mean ionization fractions for all elements */
1920  PrtMeanIon('i', false, ioQQQ);
1921  /* print mean ionization fractions for all elements with density weighting*/
1922  PrtMeanIon('i', true , ioQQQ);
1923  /* print mean temperature fractions for all elements */
1924  PrtMeanIon('t', false, ioQQQ);
1925  /* print mean temperature fractions for all elements with density weighting */
1926  PrtMeanIon('t', true , ioQQQ);
1927  }
1928  }
1929 
1930  /* print input title for model */
1931  fprintf( ioQQQ, "%s\n\n", input.chTitle );
1932  fflush(ioQQQ);
1933  return;
1934 }
1935 
1936 /* routine to stuff comments into the stack of comments,
1937  * return is index to this comment */
1938 long int StuffComment( const char * chComment )
1939 {
1940  int n , i;
1941 
1942  DEBUG_ENTRY( "StuffComment()" );
1943 
1944  /* only do this one time per core load */
1945  if( LineSave.ipass == 0 )
1946  {
1948  {
1949  fprintf( ioQQQ, " Too many comments have been entered into line array; increase the value of NHOLDCOMMENTS.\n" );
1951  }
1952 
1953  strcpy( LineSave.chHoldComments[LineSave.nComment], chComment );
1954 
1955  /* current length of this string */
1956  n = (long)strlen( LineSave.chHoldComments[LineSave.nComment] );
1957  for( i=0; i<prt_linecol.column_len-n; ++i )
1958  {
1959  strcat( LineSave.chHoldComments[LineSave.nComment], ".");
1960  }
1961 
1962 #if 0
1963  for( i=0; i<6; ++i )
1964  {
1965  strcat( LineSave.chHoldComments[LineSave.nComment], " ");
1966  }
1967 #endif
1968  }
1969 
1970  ++LineSave.nComment;
1971  return( LineSave.nComment-1 );
1972 }
1973 
1974 /*gett2 analyze computed structure to get structural t^2 */
1975 STATIC void gett2(realnum *tsqr)
1976 {
1977  long int i;
1978 
1979  double tmean;
1980  double a,
1981  as,
1982  b;
1983 
1984  DEBUG_ENTRY( "gett2()" );
1985 
1986  /* get T, t^2 */
1987  a = 0.;
1988  b = 0.;
1989 
1990  ASSERT( nzone < struc.nzlim);
1991  // struc.volstr[] is radius.dVeffAper saved as a function of nzone
1992  // we need this version of radius.dVeff since we want to compare to
1993  // emission lines that react to the APERTURE command
1994  for( i=0; i < nzone; i++ )
1995  {
1996  as = (double)(struc.volstr[i])*(double)(struc.hiistr[i])*
1997  (double)(struc.ednstr[i]);
1998  a += (double)(struc.testr[i])*as;
1999  /* B is used twice below */
2000  b += as;
2001  }
2002 
2003  if( b <= 0. )
2004  {
2005  *tsqr = 0.;
2006  }
2007  else
2008  {
2009  /* following is H+ weighted mean temp over vol */
2010  tmean = a/b;
2011  a = 0.;
2012 
2013  ASSERT( nzone < struc.nzlim );
2014  for( i=0; i < nzone; i++ )
2015  {
2016  as = (double)(struc.volstr[i])*(double)(struc.hiistr[i])*
2017  struc.ednstr[i];
2018  a += (POW2((double)(struc.testr[i]-tmean)))*as;
2019  }
2020  *tsqr = (realnum)(a/(b*(POW2(tmean))));
2021  }
2022 
2023  return;
2024 }
2025 
2026 /*gett2o3 analyze computed [OIII] spectrum to get t^2 */
2028 {
2029  long int i;
2030  double tmean;
2031  double a,
2032  as,
2033  b;
2034 
2035  DEBUG_ENTRY( "gett2o3()" );
2036 
2037  /* get T, t^2 */ a = 0.;
2038  b = 0.;
2040  // struc.volstr[] is radius.dVeffAper saved as a function of nzone
2041  // we need this version of radius.dVeff since we want to compare to
2042  // emission lines that react to the APERTURE command
2043  for( i=0; i < nzone; i++ )
2044  {
2045  as = (double)(struc.volstr[i])*(double)(struc.o3str[i])*
2046  (double)(struc.ednstr[i]);
2047  a += (double)(struc.testr[i])*as;
2048 
2049  /* B is used twice below */
2050  b += as;
2051  }
2052 
2053  if( b <= 0. )
2054  {
2055  *tsqr = 0.;
2056  }
2057 
2058  else
2059  {
2060  /* following is H+ weighted mean temp over vol */
2061  tmean = a/b;
2062  a = 0.;
2063  ASSERT( nzone < struc.nzlim );
2064  for( i=0; i < nzone; i++ )
2065  {
2066  as = (double)(struc.volstr[i])*(double)(struc.o3str[i])*
2067  struc.ednstr[i];
2068  a += (POW2((double)(struc.testr[i]-tmean)))*as;
2069  }
2070  *tsqr = (realnum)(a/(b*(POW2(tmean))));
2071  }
2072  return;
2073 }
long int nSave
Definition: input.h:102
realnum toiiir
Definition: peimbt.h:18
bool lgIterAgain
Definition: iterations.h:53
realnum tbac
Definition: peimbt.h:18
realnum wlSort2
Definition: prt.h:150
void PrtFinal(void)
Definition: prt_final.cpp:555
realnum BigJumpTe
Definition: phycon.h:116
realnum t2hyox
Definition: peimbt.h:18
double Radius
Definition: radius.h:31
realnum t2hstr
Definition: peimbt.h:18
t_atmdat atmdat
Definition: atmdat.cpp:6
t_line_col prt_linecol
Definition: prt.cpp:15
t_thermal thermal
Definition: thermal.cpp:6
void PrintE93(FILE *, double)
Definition: service.cpp:923
double power
Definition: thermal.h:169
t_colden colden
Definition: colden.cpp:5
realnum TimeErode
Definition: timesc.h:61
realnum WavlenErrorGet(realnum wavelength, long sig_figs)
double exp10(double x)
Definition: cddefines.h:1368
const int ipHE_LIKE
Definition: iso.h:65
NORETURN void TotalInsanity(void)
Definition: service.cpp:971
double widflx(size_t i) const
Definition: mesh.h:156
t_input input
Definition: input.cpp:12
t_opac opac
Definition: opacity.cpp:5
realnum ** flux
Definition: rfield.h:68
t_struc struc
Definition: struc.cpp:6
realnum UV_Cont_rel2_Draine_DB96_face
Definition: hmi.h:84
double FreeFreeTotHeat
Definition: thermal.h:178
bool lgPrnHeat
Definition: prt.h:188
const realnum SMALLFLOAT
Definition: cpu.h:246
bool lgPrintLineCumulative
Definition: prt.h:268
realnum EnergyBremsThin
Definition: rfield.h:227
bool lgCylnOn
Definition: radius.h:127
realnum * outlin_noplot
Definition: rfield.h:189
STATIC void PrintCenterLine(FILE *io, const char chLine[], size_t ArrLen, size_t LineLen)
Definition: prt_final.cpp:45
char TorF(bool l)
Definition: cddefines.h:749
const int ipOXYGEN
Definition: cddefines.h:356
#define PrintEfmt(F, V)
Definition: cddefines.h:1349
realnum fine_opac_velocity_width
Definition: rfield.h:371
double tcmptn
Definition: timesc.h:26
long int iEmissPower
Definition: geometry.h:71
const double SMALLDOUBLE
Definition: cpu.h:250
realnum BigJumpH2
Definition: phycon.h:116
t_warnings warnings
Definition: warnings.cpp:11
realnum BigHeatCoolError
Definition: conv.h:174
t_conv conv
Definition: conv.cpp:5
realnum * ednstr
Definition: struc.h:25
realnum tmas
Definition: colden.h:61
STATIC void gett2(realnum *tsqr)
Definition: prt_final.cpp:1975
long int nTotalIoniz_start
Definition: conv.h:164
double distance
Definition: radius.h:71
TransitionList HFLines("HFLines",&AnonStates)
t_phycon phycon
Definition: phycon.cpp:6
t_LineSave LineSave
Definition: lines.cpp:10
string relint_outrange
Definition: prt.h:332
realnum AccelAver
Definition: wind.h:46
int cdTemp(const char *chLabel, long int IonStage, double *TeMean, const char *chWeight)
Definition: cddrive.cpp:1311
sys_float sexp(sys_float x)
Definition: service.cpp:999
realnum AverPressError
Definition: conv.h:179
char chVersion[INPUT_LINE_LENGTH]
Definition: version.h:19
realnum * volstr
Definition: struc.h:25
realnum BigPressError
Definition: conv.h:178
realnum ajmmin
Definition: colden.h:59
bool lgHInducImp
Definition: hydrogenic.h:132
realnum covgeo
Definition: geometry.h:45
bool lgHCaseBOK[2][HS_NZ]
Definition: atmdat.h:342
realnum ** outlin
Definition: rfield.h:189
FILE * ioQQQ
Definition: cddefines.cpp:7
realnum AverHeatCoolError
Definition: conv.h:175
void PrtMeanIon(char chType, bool lgDensity, FILE *)
Definition: prt_meanion.cpp:11
realnum FillFac
Definition: geometry.h:29
char chTitle[INPUT_LINE_LENGTH]
Definition: input.h:80
long int nzone
Definition: cddefines.cpp:14
bool lgTalk
Definition: called.h:12
realnum rjnmin
Definition: colden.h:59
bool lgPrtCitations
Definition: prt.h:294
t_dynamics dynamics
Definition: dynamics.cpp:42
realnum wlSort1
Definition: prt.h:150
realnum t2o3str
Definition: peimbt.h:18
realnum BigJumpne
Definition: phycon.h:116
vector< freeBound > fb
Definition: iso.h:481
#define MIN2(a, b)
Definition: cddefines.h:803
void cap4(char *chCAP, const char *chLab)
Definition: service.cpp:261
double anu(size_t i) const
Definition: mesh.h:120
void PrtAllTau(void)
Definition: prt_alltau.cpp:15
vector< LinSv > lines
Definition: lines.h:132
bool lgSortLineIntensity
Definition: prt.h:146
t_dense dense
Definition: global.cpp:15
realnum tohyox
Definition: peimbt.h:18
static t_version & Inst()
Definition: cddefines.h:209
bool lgBadStop
Definition: conv.h:246
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:11
double depth_x_fillfac
Definition: radius.h:80
bool lgPrintBlockIntrinsic
Definition: prt.h:134
realnum tauxry
Definition: rt.h:184
Wind wind
Definition: wind.cpp:5
bool lgSphere
Definition: geometry.h:34
long int iteration
Definition: cddefines.cpp:16
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:854
realnum wmas
Definition: colden.h:61
double rinner
Definition: radius.h:31
t_geometry geometry
Definition: geometry.cpp:5
bool lgdBaseSourceExists[LIMELM][LIMELM+1]
Definition: atmdat.h:452
void PrintE71(FILE *, double)
Definition: service.cpp:873
long ipoint(double energy_ryd)
Definition: cont_ipoint.cpp:15
realnum TooFaint
Definition: prt.h:244
#define POW2
Definition: cddefines.h:979
double dlnenCp
Definition: colden.h:49
const int ipH1s
Definition: iso.h:29
#define STATIC
Definition: cddefines.h:118
multi_arr< double, 2 > TempEdenMean
Definition: mean.h:38
realnum tlowst
Definition: thermal.h:68
bool lgSurfaceBrightness
Definition: prt.h:179
realnum qhtot
Definition: rfield.h:341
realnum BigJumpCO
Definition: phycon.h:116
bool lgPrintBlockEmergent
Definition: prt.h:138
t_pressure pressure
Definition: pressure.cpp:9
t_rfield rfield
Definition: rfield.cpp:9
double dlnenHep
Definition: colden.h:43
t_mean mean
Definition: mean.cpp:16
bool lgVisible[NKRD]
Definition: input.h:96
realnum * ConInterOut
Definition: rfield.h:154
STATIC void gett2o3(realnum *tsqr)
Definition: prt_final.cpp:2027
float realnum
Definition: cddefines.h:124
realnum uh
Definition: rfield.h:349
#define EXIT_FAILURE
Definition: cddefines.h:168
int relint_len
Definition: prt.h:321
double H0_ov_Tspin
Definition: colden.h:52
const realnum BIGFLOAT
Definition: cpu.h:244
double OH_ov_Tspin
Definition: colden.h:55
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
multi_arr< double, 4 > TempIonEdenMean
Definition: mean.h:26
realnum uheii
Definition: rfield.h:352
bool lgFaintOn
Definition: prt.h:245
realnum thist
Definition: thermal.h:68
bool lgSurfaceBrightness_SR
Definition: prt.h:179
t_hydro hydro
Definition: hydrogenic.cpp:5
#define cdEXIT(FAIL)
Definition: cddefines.h:482
realnum RadBetaMax
Definition: pressure.h:96
bool lgRadiusKnown
Definition: radius.h:122
double totcol
Definition: thermal.h:130
long min(int a, long b)
Definition: cddefines.h:762
bool lgGrainPhysicsOn
Definition: grainvar.h:479
diatomics h2("h2", 4100.,&hmi.H2_total, Yan_H2_CS)
bool lgGeoPP
Definition: geometry.h:21
realnum wlAirVac(double wlAir)
sys_float safe_div(sys_float x, sys_float y, sys_float res_0by0)
Definition: cddefines.h:1011
STATIC void PrintSpectrum()
Definition: prt_final.cpp:73
bool lgPrintTime
Definition: prt.h:161
t_iterations iterations
Definition: iterations.cpp:6
realnum rstrom
Definition: rfield.h:357
void PrtColumns(FILE *ioMEAN)
Definition: prt_columns.cpp:14
long int sig_figs
Definition: lines.h:109
bool lgPrtShort
Definition: prt.h:219
realnum UV_Cont_rel2_Habing_TH85_face
Definition: hmi.h:74
double cdExecTime()
Definition: cddrive.cpp:478
t_radius radius
Definition: radius.cpp:5
t_timesc timesc
Definition: timesc.cpp:7
realnum tsqden
Definition: peimbt.h:18
t_prt prt
Definition: prt.cpp:14
realnum pirsq
Definition: radius.h:149
long int nTotalIoniz
Definition: conv.h:159
bool lgPrtLineLog
Definition: prt.h:264
bool lgElmtOn[LIMELM]
Definition: dense.h:160
realnum TotMassColl
Definition: colden.h:61
double extin_mag_V_point
Definition: rfield.h:258
bool lgPredLumin
Definition: radius.h:145
string col_gap
Definition: prt.h:335
long int nzlim
Definition: struc.h:19
realnum gas_phase[LIMELM]
Definition: dense.h:76
bool lgPrintBlock
Definition: prt.h:130
double totlin(int chInfo)
long int itermx
Definition: iterations.h:37
double dlnenp
Definition: colden.h:40
double Conv2PrtInten
Definition: radius.h:153
realnum wmole
Definition: dense.h:111
bool lgSortLines
Definition: prt.h:142
#define ASSERT(exp)
Definition: cddefines.h:613
void sprt_wl(char *chString, realnum wl)
Definition: prt.cpp:56
realnum covaper
Definition: geometry.h:54
bool lgLastIt
Definition: iterations.h:47
double sound
Definition: timesc.h:40
t_peimbt peimbt
Definition: peimbt.cpp:5
double cdB21cm()
Definition: cddrive.cpp:1270
char chDenseLaw[5]
Definition: dense.h:176
long int nComment
Definition: lines.h:90
long int cdLine(const char *chLabel, realnum wavelength, double *relint, double *absint)
Definition: cddrive.cpp:1067
double extin_mag_B_point
Definition: rfield.h:258
double extin_mag_V_extended
Definition: rfield.h:262
long int ipNormWavL
Definition: lines.h:102
const int ipH_LIKE
Definition: iso.h:64
multi_arr< double, 4 > TempIonMean
Definition: mean.h:24
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
const int ipHELIUM
Definition: cddefines.h:350
void PrintRatio(double q1, double q2)
Definition: prt_final.cpp:65
realnum xMassDensity
Definition: dense.h:101
static vector< realnum > wavelength
vector< GrainBin * > bin
Definition: grainvar.h:583
realnum AverEdenError
Definition: conv.h:171
multi_arr< double, 2 > TempMean
Definition: mean.h:36
bool lgPrnPump
Definition: prt.h:188
void DatabasePrintReference()
Definition: service.cpp:1798
char chHTopType[5]
Definition: hydrogenic.h:117
realnum ** TauAbsGeo
Definition: opacity.h:91
static const int NHOLDCOMMENTS
Definition: lines.h:72
bool lgPrintFluxEarth
Definition: prt.h:175
realnum xMassTotal
Definition: dense.h:117
#define MAX2(a, b)
Definition: cddefines.h:824
bool lgPrintColumns
Definition: prt.h:157
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
multi_arr< double, 4 > xIonMean
Definition: mean.h:17
int absint_len
Definition: prt.h:318
sys_float SDIV(sys_float x)
Definition: cddefines.h:1002
long int n_initial_relax
Definition: dynamics.h:132
double dlnenHepp
Definition: colden.h:46
long int nsum
Definition: lines.h:87
realnum * testr
Definition: struc.h:25
bool lgSizeSet
Definition: geometry.h:80
char chCardSav[NKRD][INPUT_LINE_LENGTH]
Definition: input.h:74
GrainVar gv
Definition: grainvar.cpp:5
t_hmi hmi
Definition: hmi.cpp:5
double r1r0sq
Definition: radius.h:31
bool lgCautns
Definition: warnings.h:44
long int ipxry
Definition: rt.h:181
bool lgUSphON
Definition: rfield.h:355
char chHoldComments[NHOLDCOMMENTS][INPUT_LINE_LENGTH]
Definition: lines.h:99
void PrintE82(FILE *, double)
Definition: service.cpp:824
char chCumuType[5]
Definition: rfield.h:335
double time_therm_long
Definition: timesc.h:29
bool lgPrnColl
Definition: prt.h:188
bool lgDustOn() const
Definition: grainvar.h:475
const int ipHYDROGEN
Definition: cddefines.h:349
realnum BigEdenError
Definition: conv.h:213
long int nflux
Definition: rfield.h:46
realnum * hiistr
Definition: struc.h:25
realnum acldr
Definition: wind.h:46
realnum colden[NCOLD]
Definition: colden.h:32
realnum tbcthn
Definition: peimbt.h:18
double H2_itrzn(void)
Definition: mole_h2.cpp:263
long int numLevels_local
Definition: iso.h:529
bool lgWarngs
Definition: warnings.h:44
long int ipass
Definition: lines.h:96
t_called called
Definition: called.cpp:4
realnum * o3str
Definition: struc.h:25
bool lgPrnInwd
Definition: prt.h:188
bool lgAbort
Definition: cddefines.cpp:10
bool lgSortLineWavelength
Definition: prt.h:146
void spsort(realnum x[], long int n, long int iperm[], int kflag, int *ier)
Definition: service.cpp:1222
int column_len
Definition: prt.h:325
double ScaleNormLine
Definition: lines.h:117
bool lgPrtLineArray
Definition: prt.h:260
int InclLevel[NKRD]
Definition: input.h:91
long int StuffComment(const char *chComment)
Definition: prt_final.cpp:1938
t_rt rt
Definition: rt.cpp:5