cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
prt_lines_hydro.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 /*lines_hydro put H-like iso sequence into line intensity stack */
4 #include "cddefines.h"
5 #include "atmdat.h"
6 #include "dense.h"
7 #include "prt.h"
8 #include "hydrogenic.h"
9 #include "iso.h"
10 #include "rfield.h"
11 #include "geometry.h"
12 #include "lines.h"
13 #include "phycon.h"
14 #include "radius.h"
15 #include "secondaries.h"
16 #include "trace.h"
17 #include "two_photon.h"
18 #include "lines_service.h"
19 #include "elementnames.h"
20 
21 static bool isSkipTransSet = false;
22 static vector< vector< pair<long, long> > > skipTrans( LIMELM );
23 
24 /* This loop is identical to the one in lines_hydro() that brings together
25  * the Balmer series, and resets all but one of the fine structure lines
26  * to a zero intensity. */
27 static void collectSkipTrans( void )
28 {
29  long ipISO = ipH_LIKE;
30 
31  for( long nelem=0; nelem < LIMELM; nelem++ )
32  {
33  if( dense.IonHigh[nelem] == nelem + 1 )
34  {
35  vector< pair<long, long> > thisElm_skipTrans;
36 
37  /* bring nL - n'L' emission together as n-n' emission. */
38  for( long ipHi=1; ipHi < iso_sp[ipH_LIKE][nelem].numLevels_max; ipHi++ )
39  {
40  long index_of_nHi_P;
41 
42  /* is ipHi is collapsed level, index_of_nHi_P is ipHi */
43  if( N_(ipHi) > iso_sp[ipH_LIKE][nelem].n_HighestResolved_max )
44  index_of_nHi_P = ipHi;
45  else
46  index_of_nHi_P = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ N_(ipHi) ][1][2];
47 
48  /* only need to consider resolved lower level here */
49  for( long ipLo=0; ipLo < ipHi; ipLo++ )
50  {
51  long index_of_nLo_S = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ N_(ipLo) ][0][2];
52 
53  /* jump out if ipLo is collapsed
54  * NB this must be up to n_HighestResolved_local and not n_HighestResolved_max */
55  if( N_(ipLo) > iso_sp[ipH_LIKE][nelem].n_HighestResolved_local || N_(ipLo) == N_(ipHi) )
56  break;
57 
58  if( iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().Aul() <= iso_ctrl.SmallA )
59  continue;
60 
61  /* add everything into nP - n'S, skip if current indices are those levels. */
62  if( ipHi == index_of_nHi_P && ipLo == index_of_nLo_S )
63  continue;
64  else
65  {
66  thisElm_skipTrans.push_back( pair<long, long>( ipLo, ipHi ) );
67  if( 0 )
68  {
69  fprintf( ioQQQ,
70  "%2s\t index_of_nHi_P= %2ld (%5s)\t index_of_nLo_S= %2ld (%5s)\t"
71  " ipHi= %2ld (%5s)\t ipLo= %2ld (%5s)\t %10g %10g\t Dwl= %g\n",
72  elementnames.chElementSym[ nelem ],
73  index_of_nHi_P,
74  iso_sp[ipISO][nelem].st[index_of_nHi_P].chConfig().c_str(),
75  index_of_nLo_S,
76  iso_sp[ipISO][nelem].st[index_of_nLo_S].chConfig().c_str(),
77  ipHi,
78  iso_sp[ipISO][nelem].st[ipHi].chConfig().c_str(),
79  ipLo,
80  iso_sp[ipISO][nelem].st[ipLo].chConfig().c_str(),
81  iso_sp[ipISO][nelem].trans(index_of_nHi_P,index_of_nLo_S).WLAng(),
82  iso_sp[ipISO][nelem].trans(ipHi,ipLo).WLAng(),
83  iso_sp[ipISO][nelem].trans(index_of_nHi_P,index_of_nLo_S).WLAng() -
84  iso_sp[ipISO][nelem].trans(ipHi,ipLo).WLAng() );
85  }
86  }
87  }
88  }
89  skipTrans[ nelem ] = thisElm_skipTrans;
90  }
91  }
92 
93  isSkipTransSet = true;
94 }
95 
96 static long this_ipLo, this_ipHi;
97 static bool isSkipped( const pair< long, long > level_indices )
98 {
99  return level_indices.first == this_ipLo &&
100  level_indices.second == this_ipHi;
101 }
102 
103 static bool isTransSkipped( long nelem, long ipLo, long ipHi )
104 {
105  this_ipLo = ipLo;
106  this_ipHi = ipHi;
107 
108  vector< pair<long, long> >::iterator sti;
109  sti = find_if( skipTrans[ nelem ].begin(), skipTrans[ nelem ].end(), isSkipped );
110 
111  bool skippedTrans = true;
112  if( sti == skipTrans[ nelem ].end() )
113  skippedTrans = false;
114  return skippedTrans;
115 }
116 
117 string iso_comment_tran_levels( long ipISO, long nelem, long ipLo, long ipHi )
118 {
119  string isoSeq = "H-like, ";
120  if( ipISO == ipHE_LIKE )
121  isoSeq = "He-like, ";
122 
123  // Terrible hack to get transitions into n=2 to not be
124  // reported in the comments of 'save lines labels' as
125  // into only 2^2S or 2^2P.
126  if( ipISO == ipH_LIKE && (ipLo == 1 || ipLo == 2 ) )
127  {
128  return isoSeq + db_comment_tran_levels( ipLo+1, ipHi+1 ) + ", n= 2 - "
129  + (*iso_sp[ipISO][nelem].trans(ipHi,ipLo).Hi()).chConfig();
130  }
131 
132  return isoSeq + db_comment_tran_levels( ipLo+1, ipHi+1 ) + ", "
133  + GenerateTransitionConfiguration( iso_sp[ipISO][nelem].trans(ipHi,ipLo) );
134 }
135 
136 void lines_hydro(void)
137 {
138  long ipISO = ipH_LIKE;
139  long int i, nelem, ipHi, ipLo;
140  string chLabel=" ";
141 
142  double hbetab,
143  em ,
144  caseb;
145 
146  DEBUG_ENTRY( "lines_hydro()" );
147 
148  if( trace.lgTrace )
149  fprintf( ioQQQ, " lines_hydro called\n" );
150 
151  // this can be changed with the atom levels command but must be at least 3
152  ASSERT( iso_sp[ipH_LIKE][ipHYDROGEN].n_HighestResolved_max >= 3 );
153  ASSERT( iso_sp[ipH_LIKE][ipHELIUM].n_HighestResolved_max >= 3 );
154 
155  i = StuffComment( "H-like iso-sequence" );
156  linadd( 0., (realnum)i , "####", 'i',
157  " start H -like iso sequence ");
158 
159  /*fprintf(ioQQQ," debugg\t%.2e\t%.2e\t%.2e\n",
160  radius.drad,
161  iso_sp[ipH_LIKE][ipHYDROGEN].xLineTotCool ,
162  iso_sp[ipH_LIKE][ipHYDROGEN].cLya_cool);*/
163 
164  /* >>chng 95 jun 25 changed from info to cooling to pick this up in primal.in */
165  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHYDROGEN].cLya_cool),1215.67,"Cool",'i',
166  "collisionally excited La cooling ");
167 
168  linadd(MAX2(0.,-iso_sp[ipH_LIKE][ipHYDROGEN].cLya_cool),1215.67,"Heat",'i',
169  " collisionally de-excited La heating ");
170 
171  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHYDROGEN].cLyrest_cool),960,"Crst",'i',
172  " cooling due to n>2 Lyman lines ");
173 
174  linadd(MAX2(0.,-iso_sp[ipH_LIKE][ipHYDROGEN].cLyrest_cool),960,"Hrst",'i',
175  " heating due to n>2 Lyman lines ");
176 
177  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHYDROGEN].cBal_cool),4861.33,"Crst",'i',
178  " cooling due to n>3 Balmer lines ");
179 
180  linadd(MAX2(0.,-iso_sp[ipH_LIKE][ipHYDROGEN].cBal_cool),4861.33,"Hrst",'i',
181  " heating due to n>3 Balmer lines ");
182 
183  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHYDROGEN].cRest_cool),0,"Crst",'i',
184  " cooling due to higher Paschen lines ");
185 
186  linadd(MAX2(0.,-iso_sp[ipH_LIKE][ipHYDROGEN].cRest_cool),0,"Hrst",'i',
187  " heating due to higher Paschen lines ");
188 
189  /* remember largest fractional ionization of H due to secondaries */
191 
192  /* remember fraction of H ionizations due to ct */
194 
195  /* remember largest fraction of thermal collisional ionization of H ground state */
196  hydro.HCollIonMax =
198 
199  linadd(secondaries.x12tot*iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH1s].Pop()*1.634e-11,1215.67,"LA X" ,'i',
200  "Lya contribution from suprathermal secondaries from ground ");
201 
202  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHYDROGEN].coll_ion),0,"CION",'c',
203  "collision ionization cooling of hydrogen ");
204 
205  linadd(MAX2(-iso_sp[ipH_LIKE][ipHYDROGEN].coll_ion,0.),0,"3bHt",'h',
206  " this is the heating due to 3-body recombination ");
207 
208  linadd(MAX2(0.,iso_sp[ipH_LIKE][ipHELIUM].coll_ion),0,"He2C",'c',
209  "collision ionization cooling of He+ ");
210 
211  linadd(MAX2(-iso_sp[ipH_LIKE][ipHELIUM].coll_ion,0.),0,"He2H",'h',
212  " this is the heating due to 3-body recombination onto He+");
213 
214  fixit("why is there a zero here?");
215  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2p].Pop()*0.*iso_sp[ipH_LIKE][ipHYDROGEN].ex[ipH2p][ipH1s].pestrk*1.634e-11,1215.67,"Strk",'i',
216  " Stark broadening contribution to line ");
217 
218  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH3s].Pop()*iso_sp[ipH_LIKE][ipHYDROGEN].ex[ipH3s][ipH2p].pestrk*3.025e-12,
219  6562.81,"Strk",'i',
220  " Stark broadening contribution to line ");
221 
222  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH4s].Pop()*iso_sp[ipH_LIKE][ipHYDROGEN].ex[ipH4s][ipH2p].pestrk*4.084e-12,
223  4861.33,"Strk",'i',
224  "Stark broadening contribution to line ");
225 
226  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH4p].Pop()*iso_sp[ipH_LIKE][ipHYDROGEN].ex[ipH4p][ipH3s].pestrk*1.059e-12,
227  18751,"Strk",'i',
228  " Stark broadening contribution to line ");
229 
230  /* pestrk[5,4] is A[4,5]*pest[4,5]
231  * Stark broadening contribution to line */
232  if( iso_sp[ipH_LIKE][ipHYDROGEN].n_HighestResolved_max >= 5 )
233  {
234  long ip5p = iso_sp[ipH_LIKE][ipHYDROGEN].QuantumNumbers2Index[5][1][2];
235  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ip5p].Pop()*iso_sp[ipH_LIKE][ipHYDROGEN].ex[ip5p][ipH4s].pestrk*4.900e-13,40512,"Strk",'i',
236  "Stark broadening part of line");
237  }
238  /* this can fail if RT_line_all never updates the ots rates, a logic error,
239  * but only assert this during actual calculation (ipass>0), */
240  ASSERT( LineSave.ipass <1 ||
242 
243  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).Emis().ots()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).EnergyErg(), 1215.67,"Dest",'i',
244  " portion of line lost due to absorp by background opacity ");
245 
246  /* portion of line lost due to absorb by background opacity */
247  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH3p,ipH2s).Emis().ots()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH3p,ipH2s).EnergyErg(), 6562.81,"Dest",'i',
248  "Ha destroyed by background opacity");
249 
250  /* portion of line lost due to absorp by background opacity */
251  if( iso_sp[ipH_LIKE][ipHYDROGEN].n_HighestResolved_max >= 5 )
252  {
253  long ip5p = iso_sp[ipH_LIKE][ipHYDROGEN].QuantumNumbers2Index[5][1][2];
254  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ip5p,ipH4s).Emis().ots()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ip5p,ipH4s).EnergyErg(),40516, "Dest",'i',
255  "portion of line lost due to absorb by background opacity");
256  }
257 
258  /* portion of line lost due to absorb by background opacity */
259  if( iso_sp[ipH_LIKE][ipHYDROGEN].numLevels_max > ipH4p )
260  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH4p,ipH2s).Emis().ots()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH4p,ipH2s).EnergyErg(), 4861.33,"Dest",'i',
261  "portion of line lost due to absorb by background opacity");
262 
263  /* portion of line lost due to absorb by background opacity */
264  if( iso_sp[ipH_LIKE][ipHYDROGEN].numLevels_max > ipH4p )
265  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH4p,ipH3s).Emis().ots()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH4p,ipH3s).EnergyErg() ,18751, "Dest",'i',
266  "portion of line lost due to absorb by background opacity");
267 
268  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2p].Pop()*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).Emis().Aul()*
269  hydro.dstfe2lya*iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).EnergyErg() , 1215.67 , "Fe 2" , 'i',
270  "Ly-alpha destroyed by overlap with FeII " );
271 
272  linadd(iso_sp[ipH_LIKE][ipHYDROGEN].RadRec_caseB*dense.xIonDense[ipHYDROGEN][1]*dense.eden * 1.64e-11,1215.67,"Ca B",'i',
273  " simple high-density case b intensity of Ly-alpha, no two photon ");
274 
275  /* these entries only work correctly if the APERTURE command is not in effect */
276  if( geometry.iEmissPower == 2 )
277  {
278  /* H-beta computed from Q(H) and specified covering factor */
279  if( nzone == 1 )
280  {
281  /* evaluate the case b emissivity by interpolating on the hummer & storey tables */
282  caseb = rfield.qhtot*
284  /* the atmdat_HS_caseB returned -1 if the physical conditions were outside range of validity.
285  * In this case use simple approximation with no temperature or density dependence */
286  if( caseb < 0 )
287  {
288  caseb = rfield.qhtot*4.75e-13;
289  }
290  LineSave.lines[LineSave.nsum].SumLineZero();
291  }
292  else
293  {
294  caseb = 0.;
295  }
296  /* H-beta computed from Q(H) and specified covering factor */
297  linadd( caseb/radius.dVeffAper*geometry.covgeo , 4861.33 , "Q(H)" , 'i' ,
298  "Case B H-beta computed from Q(H) and specified covering factor");
299 
300  if( nzone == 1 )
301  {
302  // the cast to double prevents an FPE with Solaris Studio 12.4 (limit_compton_hi_t.in)
303  caseb = rfield.qhtot*double(iso_sp[ipH_LIKE][ipHYDROGEN].trans(ipH2p,ipH1s).EnergyErg());
304  LineSave.lines[LineSave.nsum].SumLineZero();
305  }
306  else
307  {
308  caseb = 0.;
309  }
310  /* >>chng 02 nov 05, better approximation for Lya for temperature of first zone */
311  linadd( caseb/radius.dVeffAper*geometry.covgeo , 1215.67 , "Q(H)" , 'i',
312  "Ly-alpha from Q(H), high-dens lim, specified covering factor" );
313  }
314 
315  /* this is the main printout, where line intensities are entered into the stack */
316  for( nelem=ipISO; nelem < LIMELM; nelem++ )
317  {
318  if( dense.lgElmtOn[nelem] )
319  {
320  ASSERT( iso_sp[ipH_LIKE][nelem].n_HighestResolved_max >= 3 );
321 
322  for( ipHi=1; ipHi < iso_sp[ipISO][nelem].numLevels_max; ipHi++ )
323  {
324  for( ipLo=0; ipLo < ipHi; ipLo++ )
325  {
326  if( iso_sp[ipISO][nelem].trans(ipHi,ipLo).Emis().Aul() <= iso_ctrl.SmallA )
327  continue;
328 
329  set_xIntensity( iso_sp[ipISO][nelem].trans(ipHi,ipLo) );
330  }
331  }
332  }
333  }
334 
335  if( ! isSkipTransSet )
336  {
338  }
339 
340  /* create emissivity or intensity for hydrogenic species,
341  * first combine/bring balmer series together */
342  for( nelem=0; nelem < LIMELM; nelem++ )
343  {
344  if( dense.IonHigh[nelem] == nelem + 1 )
345  {
346  /* bring nL - n'L' emission together as n-n' emission. */
347  for( ipHi=1; ipHi < iso_sp[ipH_LIKE][nelem].numLevels_max; ipHi++ )
348  {
349  long index_of_nHi_P;
350 
351  /* is ipHi is collapsed level, index_of_nHi_P is ipHi */
352  if( N_(ipHi) > iso_sp[ipH_LIKE][nelem].n_HighestResolved_max )
353  index_of_nHi_P = ipHi;
354  else
355  index_of_nHi_P = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ N_(ipHi) ][1][2];
356 
357  /* only need to consider resolved lower level here */
358  for( ipLo=0; ipLo < ipHi; ipLo++ )
359  {
360  long index_of_nLo_S = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ N_(ipLo) ][0][2];
361 
362  /* jump out if ipLo is collapsed
363  * NB this must be up to n_HighestResolved_local and not n_HighestResolved_max */
364  if( N_(ipLo) > iso_sp[ipH_LIKE][nelem].n_HighestResolved_local || N_(ipLo) == N_(ipHi) )
365  break;
366 
367  if( iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().Aul() <= iso_ctrl.SmallA )
368  continue;
369 
370  /* add everything into nP - n'S, skip if current indices are those levels. */
371  if( ipHi == index_of_nHi_P && ipLo == index_of_nLo_S )
372  continue;
373  else
374  {
375  /* add resolved line to nP - n'S */
376  iso_sp[ipH_LIKE][nelem].trans(index_of_nHi_P,index_of_nLo_S).Emis().xIntensity() +=
377  iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().xIntensity();
378  iso_sp[ipH_LIKE][nelem].trans(index_of_nHi_P,index_of_nLo_S).Emis().xObsIntensity() +=
379  iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().xObsIntensity();
380  /* zero out the resolved line */
381  iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().xIntensity() = 0;
382  iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).Emis().xObsIntensity() = 0;
383  //ASSERT( iso_sp[ipH_LIKE][nelem].trans(index_of_nHi_P,index_of_nLo_S).Emis().xIntensity() >= 0. );
384  //ASSERT( iso_sp[ipH_LIKE][nelem].trans(index_of_nHi_P,index_of_nLo_S).Emis().xObsIntensity() >= 0. );
385  }
386  }
387  }
388  }
389  }
390 
391  /* H beta recombination, assuming old case B */
392  hbetab = (double)((exp10(-20.89 - 0.10612*POW2(phycon.alogte - 4.4)))/
393  phycon.te);
394  /* need to pass this assert if CaBo is to have valid array indices for ipCont */
395  /* 06 aug 28, from numLevels_max to _local. */
396  /* 06 dec 21, change from numLevels_max to _local was mistake for this entire file. Undo. */
397  ASSERT( iso_sp[ipH_LIKE][ipHYDROGEN].numLevels_max > 4 );
398  hbetab *= dense.xIonDense[ipHYDROGEN][1]*dense.eden;
399 
400  lindst(hbetab, -4861.33 ,"CaBo",
401  1 ,'i',false,
402  " this is old case b based on Ferland (1980) PASP ");
403 
404  if( dense.lgElmtOn[ipHELIUM] )
405  {
406  /* need to pass this assert if CaBo is to have valid array indices for ipCont */
407  /* 06 aug 28, from numLevels_max to _local. */
408  /* 06 dec 21, change from numLevels_max to _local was mistake for this entire file. Undo. */
409  ASSERT( iso_sp[ipH_LIKE][ipHELIUM].numLevels_max > 4 );
410  /* 1640 1640 1640 */
411  em = 2.03e-20/(phycon.te70*phycon.te10*phycon.te03);
412  em *= dense.xIonDense[ipHELIUM][2]*dense.eden;
413 
414  lindst(em,-1640,"CaBo",
415  1,'i',false,
416  " old prediction of He II 1640, Case B at low densities");
417 
418  /* hydrogenic helium */
419  /* old prediction of He II 4686, case B */
420  em = 2.52e-20/(pow(phycon.te,1.05881));
421  em *= dense.xIonDense[ipHELIUM][2]*dense.eden;
422 
423  lindst(em,-4685.64,"CaBo", 1,'i',false,
424  " old prediction of He II 4686, Case B at low densities");
425  }
426 
427  /* predict case b intensities of hydrogen lines */
428  if( LineSave.ipass <= 0 )
429  {
430  for(nelem=0; nelem<HS_NZ; ++nelem )
431  {
432  atmdat.lgHCaseBOK[0][nelem] = true;
433  atmdat.lgHCaseBOK[1][nelem] = true;
434  }
435  }
436  /* this is the main printout, where line intensities are entered into the stack */
437  for( nelem=0; nelem < LIMELM; nelem++ )
438  {
439  if( dense.lgElmtOn[nelem] )
440  {
441  /* HS_NZ is limit to charge of elements in HS predictions, now 8 == oxygen */
442  /* but don't do the minor elements, Li, Be, B - these were not read in and so should not be
443  * printed - remove equivalent if statement in atmdat_readin.cpp to read them in */
444  if( nelem < HS_NZ && (nelem<2 || nelem>4) )
445  {
446  int iCase;
447  for( iCase=0; iCase<2; ++iCase )
448  {
449  char chAB[2]={'A','B'};
450  char chLab[5]="Ca ";
451 
452  /* adding iCase means start from n=1 for case A, n=2 for Case B,
453  * note that principal quantum number is on physics scale, not C */
454  /* 06 aug 28, both of these from numLevels_max to _local. */
455  /* 06 dec 21, change from numLevels_max to _local was mistake for this entire file. Undo. */
456  /* HS data file extends to ipHi == atmdat.ncut[iCase][nelem]==25, report all possible values for comparisons */
457  for( ipLo=1+iCase; ipLo<MIN2(atmdat.ncut[iCase][nelem]-1,iso_sp[ipH_LIKE][nelem].n_HighestResolved_max + iso_sp[ipH_LIKE][nelem].nCollapsed_max); ++ipLo )
458  {
459  for( ipHi=ipLo+1; ipHi< MIN2(atmdat.ncut[iCase][nelem],iso_sp[ipH_LIKE][nelem].n_HighestResolved_max + iso_sp[ipH_LIKE][nelem].nCollapsed_max+1); ++ipHi )
460  {
461  realnum wl;
462  double case_b_Intensity;
463  long int ipCHi , ipCLo;
464  /* Put case b predictions into line stack
465  * NB NB NB each Hummer & Storey case b line must be
466  * explicitly clobbered by hand in routine final if
467  * atmdat.lgHCaseBOK[iCase][nelem] flag is set false
468  * since this indicates that we exceeded bounds of table,
469  * DO NOT want to print lines in that case */
470 
471  /* first do case b emissivity of balmer lines */
472 
473  /* get HS predictions */
474  case_b_Intensity = atmdat_HS_caseB( ipHi,ipLo , nelem+1, phycon.te , dense.eden, chAB[iCase] );
475  if( case_b_Intensity<=0. )
476  {
477  atmdat.lgHCaseBOK[iCase][nelem] = false;
478  case_b_Intensity = 0.;
479  }
480 
481  case_b_Intensity *= dense.xIonDense[nelem][nelem+1-ipISO]*dense.eden;
482 
483  if( iCase==0 && ipLo==1 )
484  {
485  /* get physical scal prin quant numbers onto cloudy c scale */
486  ipCHi = ipHi;
487  ipCLo = 0;
488  }
489  else
490  {
491  /* get physical scal prin quant numbers onto cloudy c scale */
492  ipCHi = ipHi;
493  ipCLo = ipLo;
494  }
495 
496  /* make label either Ca A or Ca B */
497  chLab[3] = chAB[iCase];
498 
499  /* new treatment is different from old for indices greater than 2. */
500  if( ipCHi > 2 )
501  {
502  if( ipCLo > 2 )
503  {
504  /* if both indices above two, just treat as nP to n'S transition. */
505  ipCHi = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ipCHi][1][2];
506  ipCLo = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ipCLo][0][2];
507  }
508  else if( ipCLo == 2 )
509  {
510  /* treat as nS to 2P transition. */
511  ipCHi = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ipCHi][0][2];
512  }
513  else if( ipCLo == 1 || ipCLo == 0 )
514  {
515  /* treat as nP to n'S transition. */
516  ipCHi = iso_sp[ipH_LIKE][nelem].QuantumNumbers2Index[ipCHi][1][2];
517  }
518  }
519 
520  /* this is wavelength of interpolated case b from HS tables */
521  wl = iso_sp[ipH_LIKE][nelem].trans(ipCHi,ipCLo).WLAng();
522  atmdat.WaveLengthCaseB[nelem][ipHi][ipLo] = wl;
523 
524  lindst(case_b_Intensity,wl,chLab,iso_sp[ipH_LIKE][nelem].trans(ipCHi,ipCLo).ipCont(),'i',false,
525  " case a or case b from Hummer & Storey tables" );
526  }
527  }
528  }
529  }
530 
531  // add two-photon details here
532  if( LineSave.ipass == 0 )
533  {
534  /* chIonLbl is function that generates a null terminated 4 char string, of form "C 2"
535  * the result, chLable, is only used when ipass == 0, can be undefined otherwise */
536  chLabel = chIonLbl(nelem+1, nelem+1-ipISO);
537  }
538  for( vector<two_photon>::iterator tnu = iso_sp[ipH_LIKE][nelem].TwoNu.begin(); tnu != iso_sp[ipH_LIKE][nelem].TwoNu.end(); ++tnu )
539  {
540  fixit("This was multiplied by Pesc when treated as a line, now what? Only used for printout?");
541  fixit("below should be 'i' instead of 'r' ?");
542 
543  string tpc_comment = "";
544  if( LineSave.ipass == 0 )
545  {
546  tpc_comment = " two photon continuum, " +
547  iso_comment_tran_levels( ipISO, nelem, (*tnu).ipLo, (*tnu).ipHi );
548  }
549  linadd( tnu->AulTotal * tnu->E2nu * EN1RYD * (*tnu->Pop),
550  2. * wn2ang( iso_sp[ipH_LIKE][nelem].trans( (*tnu).ipHi, (*tnu).ipLo ).EnergyWN() ),
551  chLabel.c_str(), 'r', tpc_comment.c_str() );
552  }
553 
554  /* NB NB - low and high must be in this order so that all balmer, paschen,
555  * etc series line up correctly in final printout */
556  for( ipLo=ipH1s; ipLo < iso_sp[ipH_LIKE][nelem].numLevels_max-1; ipLo++ )
557  {
558  /* don't bother with decays to 2p since we set them to zero above */
559  if( ipLo==ipH2p )
560  continue;
561 
562  /* set number of levels we want to print, first is default,
563  * only print real levels, second is set with "print line
564  * iso collapsed" command */
565  long int nLoop = iso_sp[ipH_LIKE][nelem].numLevels_max - iso_sp[ipH_LIKE][nelem].nCollapsed_max;
566  if( prt.lgPrnIsoCollapsed )
567  nLoop = iso_sp[ipH_LIKE][nelem].numLevels_max;
568 
569  for( ipHi=ipLo+1; ipHi < nLoop; ipHi++ )
570  {
571  // skip non-radiative transitions
572  if( iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo).ipCont() < 1 )
573  continue;
574 
575  // skip 2s-1s, so that 2p-1s comes first and cdLine finds LyA instead of the M2 transition.
576  if( ipHi==1 && ipLo==0 )
577  continue;
578 
579  if( isTransSkipped( nelem, ipLo, ipHi ) )
580  continue;
581 
582  string comment_trans = "";
583  if( LineSave.ipass == 0 )
584  {
585  comment_trans = iso_comment_tran_levels( ipISO, nelem, ipLo, ipHi );
586  }
587  PutLine(iso_sp[ipH_LIKE][nelem].trans(ipHi,ipLo), comment_trans.c_str());
588  }
589  }
590  }
591  }
592 
593  if( trace.lgTrace )
594  {
595  fprintf( ioQQQ, " lines_hydro returns\n" );
596  }
597  return;
598 }
599 
realnum x12tot
Definition: secondaries.h:65
double wn2ang(double fenergyWN)
realnum WaveLengthCaseB[8][25][24]
Definition: atmdat.h:355
double & ots() const
Definition: emission.h:700
t_atmdat atmdat
Definition: atmdat.cpp:6
string chIonLbl(const TransitionProxy &t)
Definition: transition.cpp:233
realnum EnergyErg() const
Definition: transition.h:90
qList st
Definition: iso.h:482
double te03
Definition: phycon.h:58
double exp10(double x)
Definition: cddefines.h:1368
const int ipHE_LIKE
Definition: iso.h:65
realnum H_ion_frac_collis
Definition: hydrogenic.h:126
double RadRec_caseB
Definition: iso.h:544
t_isoCTRL iso_ctrl
Definition: iso.cpp:9
long int IonHigh[LIMELM+1]
Definition: dense.h:130
void set_xIntensity(const TransitionProxy &t)
void lindst(double xEmiss, realnum wavelength, const char *chLab, long int ipnt, char chInfo, bool lgOutToo, const char *chComment)
long int iEmissPower
Definition: geometry.h:71
long int nCollapsed_max
Definition: iso.h:518
realnum HCollIonMax
Definition: hydrogenic.h:123
t_phycon phycon
Definition: phycon.cpp:6
t_LineSave LineSave
Definition: lines.cpp:10
long int ncut[2][HS_NZ]
Definition: atmdat.h:337
string iso_comment_tran_levels(long ipISO, long nelem, long ipLo, long ipHi)
static void collectSkipTrans(void)
realnum covgeo
Definition: geometry.h:45
bool lgHCaseBOK[2][HS_NZ]
Definition: atmdat.h:342
static bool isSkipTransSet
FILE * ioQQQ
Definition: cddefines.cpp:7
long int nzone
Definition: cddefines.cpp:14
double HIonFracMax
Definition: atmdat.h:317
#define MIN2(a, b)
Definition: cddefines.h:803
vector< LinSv > lines
Definition: lines.h:132
realnum SecHIonMax
Definition: secondaries.h:42
t_dense dense
Definition: global.cpp:15
t_elementnames elementnames
Definition: elementnames.cpp:5
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:11
realnum SmallA
Definition: iso.h:391
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:135
t_trace trace
Definition: trace.cpp:5
t_geometry geometry
Definition: geometry.cpp:5
bool lgPrnIsoCollapsed
Definition: prt.h:195
vector< two_photon > TwoNu
Definition: iso.h:598
long int n_HighestResolved_max
Definition: iso.h:536
#define POW2
Definition: cddefines.h:979
const int ipH1s
Definition: iso.h:29
realnum sec2total
Definition: secondaries.h:39
bool lgTrace
Definition: trace.h:12
static bool isSkipped(const pair< long, long > level_indices)
void lines_hydro(void)
double & xIntensity() const
Definition: emission.h:540
EmissionList::reference Emis() const
Definition: transition.h:447
static vector< vector< pair< long, long > > > skipTrans(LIMELM)
LinSv * linadd(double xEmiss, realnum wavelength, const char *chLab, char chInfo, const char *chComment)
#define N_(A_)
Definition: iso.h:22
realnum qhtot
Definition: rfield.h:341
t_rfield rfield
Definition: rfield.cpp:9
float realnum
Definition: cddefines.h:124
const int ipH4p
Definition: iso.h:36
string GenerateTransitionConfiguration(const TransitionProxy &t)
Definition: transition.cpp:312
qList::iterator Hi() const
Definition: transition.h:435
t_hydro hydro
Definition: hydrogenic.cpp:5
double atmdat_HS_caseB(long int iHi, long int iLo, long int iZ, double TempIn, double DenIn, char chCase)
static bool isTransSkipped(long nelem, long ipLo, long ipHi)
const int ipH3s
Definition: iso.h:32
t_radius radius
Definition: radius.cpp:5
multi_arr< long, 3 > QuantumNumbers2Index
Definition: iso.h:490
t_prt prt
Definition: prt.cpp:14
bool lgElmtOn[LIMELM]
Definition: dense.h:160
TransitionProxy trans(const long ipHi, const long ipLo)
Definition: iso.h:473
char chElementSym[LIMELM][CHARS_ELEMENT_SYM]
Definition: elementnames.h:25
const int ipH2p
Definition: iso.h:31
static long this_ipLo
#define HS_NZ
Definition: atmdat.h:267
void PutLine(const TransitionProxy &t, const char *chComment, const char *chLabelTemp, const ExtraInten &extra)
Definition: transition.cpp:318
#define ASSERT(exp)
Definition: cddefines.h:613
const int ipH2s
Definition: iso.h:30
const int ipH_LIKE
Definition: iso.h:64
const int LIMELM
Definition: cddefines.h:308
string db_comment_tran_levels(long ipLoFile, long ipHiFile)
Definition: atmdat.h:515
realnum dstfe2lya
Definition: hydrogenic.h:97
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
const int ipHELIUM
Definition: cddefines.h:350
double te10
Definition: phycon.h:58
double eden
Definition: dense.h:201
double HIonFrac
Definition: atmdat.h:314
#define MAX2(a, b)
Definition: cddefines.h:824
static long this_ipHi
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
double te70
Definition: phycon.h:58
double & xObsIntensity() const
Definition: emission.h:545
const int ipH4s
Definition: iso.h:35
double alogte
Definition: phycon.h:92
long int numLevels_max
Definition: iso.h:524
long int nsum
Definition: lines.h:87
#define fixit(a)
Definition: cddefines.h:417
t_secondaries secondaries
Definition: secondaries.cpp:5
double te
Definition: phycon.h:21
const int ipHYDROGEN
Definition: cddefines.h:349
const int ipH3p
Definition: iso.h:33
realnum & WLAng() const
Definition: transition.h:468
long int ipass
Definition: lines.h:96
double dVeffAper
Definition: radius.h:93
long int StuffComment(const char *chComment)
Definition: prt_final.cpp:1938