cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lines_service.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2013 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*GetGF convert Einstein A into oscillator strength */
4 /*abscf convert gf into absorption coefficient */
5 /*RefIndex calculates the index of refraction of air using the line energy in wavenumbers,
6  * used to convert vacuum wavelengths to air wavelengths. */
7 /*eina convert a gf into an Einstein A */
8 /*WavlenErrorGet - find difference between two wavelengths */
9 /*linadd enter lines into the line storage array, called once per zone */
10 /*lindst add local line intensity to line luminosity stack */
11 /*PntForLine generate pointer for forbidden line */
12 /*totlin sum total intensity of cooling, recombination, or intensity lines */
13 /*FndLineHt search through line heat arrays to find the strongest heat source */
14 /*ConvRate2CS convert down coll rate back into electron cs in case other parts of code need this for reference */
15 #include "cddefines.h"
16 #include "lines_service.h"
17 #include "dense.h"
18 #include "geometry.h"
19 #include "hydrogenic.h"
20 #include "ipoint.h"
21 #include "iso.h"
22 #include "lines.h"
23 #include "trace.h"
24 #include "opacity.h"
25 #include "physconst.h"
26 #include "radius.h"
27 #include "rfield.h"
28 #include "rt.h"
29 #include "taulines.h"
30 #include "thirdparty.h"
31 
33 {
34  DEBUG_ENTRY( "LineStackCreate()" );
35 
36  // set up emission line intensity stack
37  /* there are three types of calls to lines()
38  * ipass = -1, first call, only count number of lines
39  * ipass = 0, second pass, save labels and wavelengths
40  * ipass = 1, integrate intensity*/
41  LineSave.ipass = -1;
42  lines();
43  ASSERT( LineSave.nsum > 0 );
44 
45  /* in a grid or MPI run this may not be the first time here,
46  * return old memory and grab new appropriate for this size,
47  * since number of lines to be stored can change */
48  if( LineSv != NULL )
49  free( LineSv );
50  if( LineSvSortWL != NULL )
51  free( LineSvSortWL );
52 
53  /* this is the large main line array */
54  LineSv = (LinSv*)MALLOC((unsigned)LineSave.nsum*sizeof( LinSv ) );
55  LineSvSortWL = (LinSv*)MALLOC((unsigned)LineSave.nsum*sizeof( LinSv ));
56 
57  /* this will be used as sanity check in future iterations and grid points */
59 
60  /* this is only done on first iteration since will integrate over time */
61  for( long i=0; i < LineSave.nsum; i++ )
62  {
63  for( long j =0; j<4; ++j )
64  LineSv[i].SumLine[j] = 0;
65  }
66 
67  /* there are three calls to lines()
68  * first call with ipass = -1 was above, only counted number
69  * of lines and malloced space. This is second call and will do
70  * one-time creation of line labels */
71  LineSave.ipass = 0;
72  lines();
73  /* has to be positive */
74  ASSERT( LineSave.nsum > 0);
75  /* in the future calls to lines will result in integrations */
76  LineSave.ipass = 1;
77 
78  if( trace.lgTrace )
79  fprintf( ioQQQ, "%7ld lines printed in main line array\n",
80  LineSave.nsum );
81 }
82 
83 /*eina convert a gf into an Einstein A */
84 double eina(double gf,
85  double enercm,
86  double gup)
87 {
88  double eina_v;
89 
90  DEBUG_ENTRY( "eina()" );
91 
92  /* derive the transition prob, given the following
93  * call to function is gf, energy in cm^-1, g_up
94  * gf is product of g and oscillator strength
95  * eina = ( gf / 1.499e-8 ) / (wl/1e4)**2 / gup */
96  eina_v = (gf/gup)*TRANS_PROB_CONST*POW2(enercm);
97  return( eina_v );
98 }
99 
100 /*GetGF convert Einstein A into oscillator strength */
101 double GetGF(double trans_prob,
102  double enercm,
103  double gup)
104 {
105  double GetGF_v;
106 
107  DEBUG_ENTRY( "GetGF()" );
108 
109  ASSERT( enercm > 0. );
110  ASSERT( trans_prob > 0. );
111  ASSERT( gup > 0.);
112 
113  /* derive the transition prob, given the following
114  * call to function is gf, energy in cm^-1, g_up
115  * gf is product of g and oscillator strength
116  * trans_prob = ( GetGF/gup) / 1.499e-8 / ( 1e4/enercm )**2 */
117  GetGF_v = trans_prob*gup/TRANS_PROB_CONST/POW2(enercm);
118  return( GetGF_v );
119 }
120 
121 /*abscf convert gf into absorption coefficient */
122 double abscf(double gf,
123  double enercm,
124  double gl)
125 {
126  double abscf_v;
127 
128  DEBUG_ENTRY( "abscf()" );
129 
130  ASSERT(gl > 0. && enercm > 0. && gf > 0. );
131 
132  /* derive line absorption coefficient, given the following:
133  * gf, enercm, g_low
134  * gf is product of g and oscillator strength */
135  abscf_v = 1.4974e-6*(gf/gl)*(1e4/enercm);
136  return( abscf_v );
137 }
138 
139 /*RefIndex calculates the index of refraction of air using the line energy in wavenumbers,
140  * used to convert vacuum wavelengths to air wavelengths. */
141 double RefIndex(double EnergyWN )
142 {
143  double RefIndex_v,
144  WaveMic,
145  xl,
146  xn;
147 
148  DEBUG_ENTRY( "RefIndex()" );
149 
150  ASSERT( EnergyWN > 0. );
151 
152  /* the wavelength in microns */
153  WaveMic = 1.e4/EnergyWN;
154 
155  /* only do index of refraction if longward of 2000A */
156  if( WaveMic > 0.2 )
157  {
158  /* longward of 2000A
159  * xl is 1/WaveMic^2 */
160  xl = 1.0/WaveMic/WaveMic;
161  /* use a formula from
162  *>>refer air index refraction Allen, C.W. 1973, Astrophysical quantities,
163  *>>refercon 3rd Edition (AQ), p.124 */
164  xn = 255.4/(41. - xl);
165  xn += 29498.1/(146. - xl);
166  xn += 64.328;
167  RefIndex_v = xn/1.e6 + 1.;
168  }
169  else
170  {
171  RefIndex_v = 1.;
172  }
173  ASSERT( RefIndex_v >= 1. );
174  return( RefIndex_v );
175 }
176 
177 /*WavlenErrorGet - given the real wavelength in A for a line
178  * routine will find the error expected between the real
179  * wavelength and the wavelength printed in the output, with 4 sig figs,
180  * function returns difference between exact and 4 sig fig wl, so
181  * we have found correct line is fabs(d wl) < return */
183 {
184  double a;
185  realnum errorwave;
186 
187  DEBUG_ENTRY( "WavlenErrorGet()" );
188 
189  ASSERT( LineSave.sig_figs <= 6 );
190 
191  if( wavelength > 0. )
192  {
193  /* normal case, positive (non zero) wavelength */
194  a = log10( wavelength+FLT_EPSILON);
195  a = floor(a);
196  }
197  else
198  {
199  /* might be called with wl of zero, this is that case */
200  /* errorwave = 1e-4f; */
201  a = 0.;
202  }
203 
204  errorwave = 5.f * (realnum)pow( 10., a - (double)LineSave.sig_figs );
205  return errorwave;
206 }
207 
208 /*linadd enter lines into the line storage array, called once per zone for each line*/
210  double xInten, /* xInten - local emissivity per unit vol, no fill fac */
211  realnum wavelength, /* realnum wavelength */
212  const char *chLab,/* string label for ion */
213  // ipnt offset of line in continuum mesh
214  long int ipnt,
215  char chInfo, /* character type of entry for line - given below */
216  /* 'c' cooling, 'h' heating, 'i' info only, 'r' recom line */
217  // *chComment string explaining line
218  const char *chComment,
219  // lgAdd says whether we've come in via linadd (true) or lindst (false)
220  bool lgAdd)
221 {
222  DEBUG_ENTRY( "lincom()" );
223 
224  /* main routine to actually enter lines into the line storage array
225  * called at top level within routine lines
226  * called series of times in routine PutLine for lines transferred
227  */
228 
229  /* three values, -1 is just counting, 0 if init, 1 for calculation */
230  if( LineSave.ipass > 0 )
231  {
232  /* >>chng 06 feb 08, add test on xInten positive, no need to evaluate
233  * for majority of zero */
234  if (lgAdd || xInten > 0.)
235  {
236  /* not first pass, sum lines only
237  * total emission from vol */
238  /* LineSave.ipass > 0, integration across simulation, sum lines only
239  * emissivity, emission per unit vol, for this zone */
240  LineSv[LineSave.nsum].SumLine[0] += xInten*radius.dVeffAper;
241  /* local emissivity in line */
242  /* integrated intensity or luminosity, the emissivity times the volume */
243  LineSv[LineSave.nsum].emslin[0] = xInten;
244  }
245 
246  if (lgAdd)
247  {
248  if (wavelength > 0 )
249  {
250  /* no need to increment or set [1] version since this is called with no continuum
251  * index, don't know what to do */
252  /* only put informational lines, like "Q(H) 4861", in this stack
253  * many continua have a wavelength of zero and are proper intensities,
254  * it would be wrong to predict their transferred intensity */
257  }
258  }
259  else
260  {
261  if ( xInten > 0. && ipnt <= rfield.nflux )
262  {
263  /* emergent_line accounts for destruction by absorption outside
264  * the line-forming region */
265  const double saveemis = emergent_line(
266  xInten*rt.fracin , xInten*(1.-rt.fracin) , ipnt );
267  LineSv[LineSave.nsum].emslin[1] = saveemis;
268  LineSv[LineSave.nsum].SumLine[1] += saveemis*radius.dVeffAper;
269  }
270  }
271  }
272 
273  else if( LineSave.ipass == 0 )
274  {
275  /* first call to stuff lines in array, confirm that label is one of
276  * the four correct ones */
277  ASSERT( (chInfo == 'c') || (chInfo == 'h') || (chInfo == 'i') || (chInfo == 'r' ) );
278  /* then save it into array */
279  LineSv[LineSave.nsum].chSumTyp = (char)chInfo;
280  LineSv[LineSave.nsum].emslin[0] = 0.;
281  LineSv[LineSave.nsum].emslin[1] = 0.;
282  LineSv[LineSave.nsum].chComment = chComment;
283  /* check that null is correct, string overruns have
284  * been a problem in the past */
285  ASSERT( strlen( chLab )<5 );
286  strcpy( LineSv[LineSave.nsum].chALab, chLab );
287 
288  if (lgAdd)
289  {
291  }
292  else
293  {
294  // number of lines ok, set parameters for first pass
295  // negative wavelengh means it is just label, possibly not correct
296  LineSv[LineSave.nsum].wavelength = fabs(wavelength);
297  LineSv[LineSave.nsum].SumLine[0] = 0.;
298  LineSv[LineSave.nsum].SumLine[1] = 0.;
299 
300  // check that line wavelength and continuum index agree to some extent
301  // this check cannot be very precise because some lines have
302  // "wavelengths" that are set by common usage rather than the correct
303  // wavelength derived from energy and index of refraction of air
304  ASSERT( ipnt > 0 );
305 # ifndef NDEBUG
306  double error = MAX2(0.1*rfield.AnuOrg[ipnt-1] , rfield.widflx[ipnt-1] );
307  ASSERT( wavelength<=0 ||
308  fabs( rfield.AnuOrg[ipnt-1] - RYDLAM / wavelength) < error );
309 # endif
310  }
311  }
312 
313  /* increment the line counter */
314  ++LineSave.nsum;
315 
316  /* routine can be called with negative LineSave.ipass, in this case
317  * we are just counting number of lines for current setup */
318 }
319 
320 /*linadd enter lines into the line storage array, called once per zone for each line*/
321 void linadd(
322  double xInten, /* xInten - local emissivity per unit vol, no fill fac */
323  realnum wavelength, /* realnum wavelength */
324  const char *chLab,/* string label for ion */
325  char chInfo, /* character type of entry for line - given below */
326  /* 'c' cooling, 'h' heating, 'i' info only, 'r' recom line */
327  const char *chComment )
328 {
329  DEBUG_ENTRY( "linadd()" );
330 
331  // Values added to get common interface with lindst
332  const long int ipnt = LONG_MAX;
333 
334  lincom( xInten, wavelength, chLab, ipnt, chInfo, chComment, true );
335 }
336 
337 
338 /*emergent_line find emission from surface of cloud after correcting for
339  * extinction due to continuous opacity for inward & outward directed emission */
341  /* emiemission in inward direction */
342  double emissivity_in ,
343  /* emission in outward direction */
344  double emissivity_out ,
345  /* array index for continuum frequency on fortran scale */
346  long int ipCont )
347 {
348 
349  double emergent_in , emergent_out;
350  long int i = ipCont-1;
351 
352  DEBUG_ENTRY( "emergent_line()" );
353 
354  ASSERT( i >= 0 && i < rfield.nupper-1 );
355 
356  /* do nothing if first iteration since we do not know the outward-looking
357  * optical depths. In version C07.02.00 we assumed an infinite optical
358  * depth in the outward direction, which would be appropriate for a
359  * HII region on the surface of a molecular cloud. This converged onto
360  * the correct solution in later iterations, but on the first iteration
361  * this underestimated total emission if the infinite cloud were not
362  * present. With C07.02.01 we make no assuptions about what is in the
363  * outward direction and simply use the local emission.
364  * Behavior is unchanged on later iterations */
365  if( iteration == 1 )
366  {
367  /* first iteration - do not know outer optical depths so assume very large
368  * optical depths */
369  emergent_in = emissivity_in*opac.E2TauAbsFace[i];
370  emergent_out = emissivity_out;
371  }
372  else
373  {
374  if( geometry.lgSphere )
375  {
376  /* second or later iteration in closed or spherical geometry */
377  /* inwardly directed emission must get to central hole then across entire
378  * far side of shell */
379  emergent_in = emissivity_in * opac.E2TauAbsFace[i] *opac.E2TauAbsTotal[i];
380 
381  /* E2 is outwardly directed emission to get to outer edge of cloud */
382  emergent_out = emissivity_out * opac.E2TauAbsOut[i];
383  }
384  else
385  {
386  /* open geometry in second or later iteration, outer optical depths are known
387  * this is light emitted into the outer direction and backscattered
388  * into the inner */
389  double reflected = emissivity_out * opac.albedo[i] * (1.-opac.E2TauAbsOut[i]);
390  /* E2 is to get to central hole */
391  emergent_in = (emissivity_in + reflected) * opac.E2TauAbsFace[i];
392  /* E2 is to get to outer edge */
393  emergent_out = (emissivity_out - reflected) * opac.E2TauAbsOut[i];
394  }
395  }
396  /* return the net emission that makes it to the surface */
397  return( emergent_in + emergent_out );
398 }
399 
400 /* outline_base - calls outline_base_bin after deciding whether to add impulse or resolved line */
401 void outline_base(double dampXvel, double damp, bool lgTransStackLine, long int ip, double phots, realnum inwd,
402  double nonScatteredFraction)
403 {
404  DEBUG_ENTRY( "outline_base()" );
405 
406  static const bool DO_PROFILE = false;
407 
408  if( !DO_PROFILE || !rfield.lgDoLineTrans )
409  outline_base_bin(lgTransStackLine, ip, phots, inwd, nonScatteredFraction);
410  else
411  {
412  ASSERT( damp > 0. );
413  double LineWidth = dampXvel/damp;
414  LineWidth = MIN2( 0.1 * SPEEDLIGHT, LineWidth );
415  double sigma = (LineWidth/SPEEDLIGHT);
416  long ip3SigmaRed = ipoint( MAX2( rfield.emm, rfield.anu[ip] - 3.*sigma*rfield.anu[ip] ) );
417  long ip3SigmaBlue = ipoint( MIN2( rfield.egamry, rfield.anu[ip] + 3.*sigma*rfield.anu[ip] ) );
418  ASSERT( ip3SigmaBlue >= ip3SigmaRed );
419  long numBins = ip3SigmaBlue - ip3SigmaRed + 1;
420 
421  if( numBins < 3 )
422  outline_base_bin(lgTransStackLine, ip, phots, inwd, nonScatteredFraction);
423  else
424  {
425  valarray<realnum> x(numBins);
426  valarray<realnum> profile(numBins);
427 
428  for( long ipBin=ip3SigmaRed; ipBin<=ip3SigmaBlue; ipBin++ )
429  x[ipBin] = (rfield.anu[ip] - rfield.anu[ipBin])/rfield.anu[ip]/sigma;
430  // this profile must have unit normalization to conserve energy -> use U(a,v)
431  VoigtU(damp,get_ptr(x),get_ptr(profile),numBins);
432 
433  for( long ipBin=ip3SigmaRed; ipBin<=ip3SigmaBlue; ipBin++ )
434  outline_base_bin(lgTransStackLine, ipBin, phots*profile[ipBin-ip3SigmaRed], inwd, nonScatteredFraction);
435  }
436  }
437 }
438 
439 /*outline_base_bin - adds line photons to bins of reflin and outlin */
440 void outline_base_bin(bool lgTransStackLine, long int ip, double phots, realnum inwd,
441  double nonScatteredFraction)
442 {
443  DEBUG_ENTRY( "outline_base_bin()" );
444 
445  if (lgTransStackLine)
446  {
448  (realnum)phots;
449 
450  /* the reflected part */
451  rfield.reflin[0][ip] +=
452  (realnum)(inwd*phots*radius.BeamInIn);
453 
454  /* inward beam that goes out since sphere set */
455  rfield.outlin[0][ip] +=
456  (realnum)(inwd*phots*radius.BeamInOut*opac.tmn[ip]*nonScatteredFraction);
457 
458  /* outward part */
459  rfield.outlin[0][ip] +=
460  (realnum)((1.-inwd)*phots*radius.BeamOutOut*opac.tmn[ip]*nonScatteredFraction);
461  }
462  else
463  {
464  rfield.reflin[0][ip] +=
465  (realnum)(phots*radius.dVolReflec);
466 
467  rfield.outlin[0][ip] +=
468  (realnum)(phots*radius.dVolOutwrd*opac.ExpZone[ip]);
469  }
470 }
471 
472 /*lindst add line with destruction and outward */
473 void lindst(
474  // xInten - local emissivity per unit vol
475  double xInten,
476  // wavelength of line in Angstroms
478  // *chLab string label for ion
479  const char *chLab,
480  // ipnt offset of line in continuum mesh
481  long int ipnt,
482  // chInfo character type of entry for line - 'c' cooling, 'h' heating, 'i' info only, 'r' recom line
483  char chInfo,
484  // lgOutToo should line be included in outward beam?
485  bool lgOutToo,
486  // *chComment string explaining line
487  const char *chComment )
488 {
489  DEBUG_ENTRY( "lindst()" );
490 
491  // do not add information lines to outward beam
492  ASSERT( !lgOutToo || chInfo!='i' );
493 
494  lincom(xInten, wavelength, chLab, ipnt, chInfo, chComment, false );
495 
496  if( LineSave.ipass > 0 )
497  {
498  /* >>chng 06 feb 08, add test on xInten positive, no need to evaluate
499  * for majority of zero */
500  if (lgOutToo && xInten > 0.)
501  {
502  /* add line to outward beam
503  * there are lots of lines that are sums of other lines, or
504  * just for info of some sort. These have flag lgOutToo false.
505  * Note that the EnergyRyd variable only has a rational
506  * value if PntForLine was called just before this routine - in all
507  * cases where this did not happen the flag is false. */
508  const bool lgTransStackLine = false;
509  const long int ip = ipnt - 1;
510  const double phots = xInten/(rfield.anu[ipnt-1]*EN1RYD);
511  const realnum inwd = (realnum)(1.0-(1.+geometry.covrt)/2.);
512  const double nonScatteredFraction = 1.;
513 
514  outline_base_bin(lgTransStackLine, ip, phots, inwd, nonScatteredFraction);
515  }
516  }
517 }
518 
519 /*lindst add line with destruction and outward */
520 void lindst(
521  double dampXvel,
522  double damp,
523  // xInten - local emissivity per unit vol
524  double xInten,
525  // wavelength of line in Angstroms
527  // *chLab string label for ion
528  const char *chLab,
529  // ipnt offset of line in continuum mesh
530  long int ipnt,
531  // chInfo character type of entry for line - 'c' cooling, 'h' heating, 'i' info only, 'r' recom line
532  char chInfo,
533  // lgOutToo should line be included in outward beam?
534  bool lgOutToo,
535  // *chComment string explaining line
536  const char *chComment )
537 {
538  DEBUG_ENTRY( "lindst()" );
539 
540  // do not add information lines to outward beam
541  ASSERT( !lgOutToo || chInfo!='i' );
542 
543  lincom(xInten, wavelength, chLab, ipnt, chInfo, chComment, false );
544 
545  if( LineSave.ipass > 0 )
546  {
547  /* >>chng 06 feb 08, add test on xInten positive, no need to evaluate
548  * for majority of zero */
549  if (lgOutToo && xInten > 0.)
550  {
551  /* add line to outward beam
552  * there are lots of lines that are sums of other lines, or
553  * just for info of some sort. These have flag lgOutToo false.
554  * Note that the EnergyRyd variable only has a rational
555  * value if PntForLine was called just before this routine - in all
556  * cases where this did not happen the flag is false. */
557  const bool lgTransStackLine = false;
558  const long int ip = ipnt - 1;
559  const double phots = xInten/(rfield.anu[ipnt-1]*EN1RYD);
560  const realnum inwd = (realnum)(1.0-(1.+geometry.covrt)/2.);
561  const double nonScatteredFraction = 1.;
562 
563  outline_base(dampXvel, damp, lgTransStackLine, ip, phots, inwd, nonScatteredFraction);
564  }
565  }
566 }
567 
568 /*lindst add line with destruction and outward */
569 void lindst(
570  const TransitionProxy& t,
571  // *chLab string label for ion
572  const char *chLab,
573  // chInfo character type of entry for line - 'c' cooling, 'h' heating, 'i' info only, 'r' recom line
574  char chInfo,
575  // lgOutToo should line be included in outward beam?
576  bool lgOutToo,
577  // *chComment string explaining line
578  const char *chComment )
579 {
580  DEBUG_ENTRY( "lindst()" );
581 
582  lindst( t.Emis().dampXvel(), t.Emis().damp(), t.Emis().xIntensity(), t.WLAng(), chLab, t.ipCont(), chInfo,
583  lgOutToo, chComment );
584 
585 }
586 
587 /*PntForLine generate pointer for forbidden line */
589  /* wavelength of transition in Angstroms */
590  double wavelength,
591  /* label for this line */
592  const char *chLabel,
593  /* this is array index on the f, not c scale,
594  * for the continuum cell holding the line */
595  long int *ipnt)
596 {
597  /*
598  * maximum number of forbidden lines - this is a good bet since
599  * new lines do not go into this group, and lines are slowly
600  * moving to level 1
601  */
602  const int MAXFORLIN = 1000;
603  static long int ipForLin[MAXFORLIN]={0};
604 
605  /* number of forbidden lines entered into continuum array */
606  static long int nForLin;
607 
608  DEBUG_ENTRY( "PntForLine()" );
609 
610  /* must be 0 or greater */
611  ASSERT( wavelength >= 0. );
612 
613  if( wavelength == 0. )
614  {
615  /* zero is special flag to initialize */
616  nForLin = 0;
617  }
618  else
619  {
620 
621  if( LineSave.ipass > 0 )
622  {
623  /* not first pass, sum lines only */
624  *ipnt = ipForLin[nForLin];
625  }
626  else if( LineSave.ipass == 0 )
627  {
628  /* check if number of lines in arrays exceeded */
629  if( nForLin >= MAXFORLIN )
630  {
631  fprintf( ioQQQ, "PROBLEM %5ld lines is too many for PntForLine.\n",
632  nForLin );
633  fprintf( ioQQQ, " Increase the value of maxForLine everywhere in the code.\n" );
635  }
636 
637  /* ipLineEnergy will only put in line label if nothing already there */
638  const double EnergyRyd = RYDLAM/wavelength;
639  ipForLin[nForLin] = ipLineEnergy(EnergyRyd,chLabel , 0);
640  *ipnt = ipForLin[nForLin];
641  }
642  else
643  {
644  /* this is case where we are only counting lines */
645  *ipnt = 0;
646  }
647  ++nForLin;
648  }
649  return;
650 }
651 
652 /*ConvRate2CS convert down coll rate back into electron cs in case other parts of code need this for reference */
653 double ConvRate2CS( realnum gHi , realnum rate )
654 {
655 
656  double cs;
657 
658  DEBUG_ENTRY( "ConvRate2CS()" );
659 
660  /* return is collision strength, convert from collision rate from
661  * upper to lower, this assumes pure electron collisions, but that will
662  * also be assumed by anything that uses cs, for self-consistency */
663  cs = rate * gHi / dense.cdsqte;
664 
665  /* change assert to non-negative - there can be cases (Iin H2) where cs has
666  * underflowed to 0 on some platforms */
667  ASSERT( cs >= 0. );
668  return cs;
669 }
670 
671 /*ConvCrossSect2CollStr convert collisional deexcitation cross section for into collision strength */
672 double ConvCrossSect2CollStr( double CrsSectCM2, double gLo, double E_ProjectileRyd, double reduced_mass_grams )
673 {
674  double CollisionStrength;
675 
676  DEBUG_ENTRY( "ConvCrossSect2CollStr()" );
677 
678  ASSERT( CrsSectCM2 >= 0. );
679  ASSERT( gLo >= 0. );
680  ASSERT( E_ProjectileRyd >= 0. );
681  ASSERT( reduced_mass_grams >= 0. );
682 
683  CollisionStrength = CrsSectCM2 * gLo * E_ProjectileRyd / (PI*BOHR_RADIUS_CM*BOHR_RADIUS_CM);
684 
685  // this part is being tested.
686 #if 0
687  CollisionStrength *= reduced_mass_grams / ELECTRON_MASS;
688 #endif
689 
690  ASSERT( CollisionStrength >= 0. );
691  return CollisionStrength;
692 }
693 
694 /*totlin sum total intensity of cooling, recombination, or intensity lines */
695 double totlin(
696  /* chInfor is 1 char,
697  'i' information,
698  'r' recombination or
699  'c' collision */
700  int chInfo)
701 {
702  long int i;
703  double totlin_v;
704 
705  DEBUG_ENTRY( "totlin()" );
706 
707  /* routine goes through set of entered line
708  * intensities and picks out those which have
709  * types agreeing with chInfo. Valid types are
710  * 'c', 'r', and 'i'
711  *begin sanity check */
712  if( (chInfo != 'i' && chInfo != 'r') && chInfo != 'c' )
713  {
714  fprintf( ioQQQ, " TOTLIN does not understand chInfo=%c\n",
715  chInfo );
717  }
718  /*end sanity check */
719 
720  /* now find sum of lines of type chInfo */
721  totlin_v = 0.;
722  for( i=0; i < LineSave.nsum; i++ )
723  {
724  if( LineSv[i].chSumTyp == chInfo )
725  {
726  totlin_v += LineSv[i].SumLine[0];
727  }
728  }
729  return( totlin_v );
730 }
731 
732 
733 /*FndLineHt search through line heat arrays to find the strongest heat source */
734 const TransitionProxy FndLineHt(long int *level)
735 {
736  long int i;
737  TransitionProxy t;
738  DEBUG_ENTRY( "FndLineHt()" );
739 
740  double Strong = -1.;
741  *level = 0;
742 
743  /* do the level 1 lines, 0 is dummy line, <=nLevel1 is correct for c scale */
744  for( i=1; i <= nLevel1; i++ )
745  {
746  /* check if a line was the major heat agent */
747  if( TauLines[i].Coll().heat() > Strong )
748  {
749  *level = 1;
750  t = TauLines[i];
751  Strong = TauLines[i].Coll().heat();
752  }
753  }
754 
755  /* now do the level 2 lines */
756  for( i=0; i < nWindLine; i++ )
757  {
758  if( (*TauLine2[i].Hi()).IonStg() < (*TauLine2[i].Hi()).nelem()+1-NISO )
759  {
760  /* check if a line was the major heat agent */
761  if( TauLine2[i].Coll().heat() > Strong )
762  {
763  *level = 2;
764  t = TauLine2[i];
765  Strong = TauLine2[i].Coll().heat();
766  }
767  }
768  }
769 
770  /* now do the hyperfine structure lines */
771  for( i=0; i < nHFLines; i++ )
772  {
773  /* check if a line was the major heat agent */
774  if( HFLines[i].Coll().heat() > Strong )
775  {
776  *level = 3;
777  t = HFLines[i];
778  Strong = HFLines[i].Coll().heat();
779  }
780  }
781 
782  /* lines from external databases */
783  for (int ipSpecies=0; ipSpecies < nSpecies; ++ipSpecies)
784  {
785  for( EmissionList::iterator em=dBaseTrans[ipSpecies].Emis().begin();
786  em != dBaseTrans[ipSpecies].Emis().end(); ++em)
787  {
788  /* check if a line was the major heat agent */
789  if( (*em).Tran().Coll().heat() > Strong )
790  {
791  *level = 4;
792  t = (*em).Tran();
793  Strong = t.Coll().heat();
794  }
795  }
796  }
797 
798  fixit(); // all other line stacks need to be included here.
799  // can we just sweep over line stack? Is that ready yet?
800 
801  ASSERT( t.associated() );
802  return t;
803 }
804 
#define MIN2
Definition: cddefines.h:765
double cdsqte
Definition: dense.h:235
realnum * widflx
Definition: rfield.h:65
void lindst(double xInten, realnum wavelength, const char *chLab, long int ipnt, char chInfo, bool lgOutToo, const char *chComment)
double * albedo
Definition: opacity.h:104
T * get_ptr(T *v)
Definition: cddefines.h:1083
t_opac opac
Definition: opacity.cpp:5
long int nLevel1
Definition: taulines.cpp:28
realnum * DiffuseLineEmission
Definition: rfield.h:203
double abscf(double gf, double enercm, double gl)
const int NISO
Definition: cddefines.h:265
double eina(double gf, double enercm, double gup)
static realnum * wavelength
#define MAX2
Definition: cddefines.h:786
TransitionList HFLines("HFLines",&AnonStates)
realnum emm
Definition: rfield.h:49
t_LineSave LineSave
Definition: lines.cpp:5
t_dense dense
Definition: dense.cpp:24
realnum wavelength
Definition: lines.h:131
double RefIndex(double EnergyWN)
const double RYDLAM
Definition: physconst.h:176
realnum ** outlin
Definition: rfield.h:199
FILE * ioQQQ
Definition: cddefines.cpp:7
realnum * E2TauAbsTotal
Definition: opacity.h:126
TransitionList TauLine2("TauLine2",&AnonStates)
long int nSpecies
Definition: taulines.cpp:21
double * ExpZone
Definition: opacity.h:120
const double SPEEDLIGHT
Definition: physconst.h:100
void PntForLine(double wavelength, const char *chLabel, long int *ipnt)
double SumLine[4]
Definition: lines.h:125
bool associated() const
Definition: transition.h:50
double dVolReflec
Definition: radius.h:98
void lines(void)
Definition: prt_lines.cpp:34
realnum egamry
Definition: rfield.h:52
long int nupper
Definition: rfield.h:46
bool lgSphere
Definition: geometry.h:24
long int iteration
Definition: cddefines.cpp:16
void outline_base_bin(bool lgTransStackLine, long int ip, double phots, realnum inwd, double nonScatteredFraction)
t_trace trace
Definition: trace.cpp:5
#define MALLOC(exp)
Definition: cddefines.h:505
char chSumTyp
Definition: lines.h:114
t_geometry geometry
Definition: geometry.cpp:5
long ipoint(double energy_ryd)
Definition: cont_ipoint.cpp:16
const double TRANS_PROB_CONST
Definition: physconst.h:237
#define POW2
Definition: cddefines.h:933
double ConvRate2CS(realnum gHi, realnum rate)
LinSv * LineSv
Definition: cdinit.cpp:70
double & heat() const
Definition: collision.h:194
#define STATIC
Definition: cddefines.h:101
bool lgTrace
Definition: trace.h:12
realnum & dampXvel() const
Definition: emission.h:553
double & xIntensity() const
Definition: emission.h:483
EmissionList::reference Emis() const
Definition: transition.h:408
long ipLineEnergy(double energy, const char *chLabel, long ipIonEnergy)
realnum * E2TauAbsOut
Definition: opacity.h:127
t_rfield rfield
Definition: rfield.cpp:8
long & ipCont() const
Definition: transition.h:450
const TransitionProxy FndLineHt(long int *level)
float realnum
Definition: cddefines.h:107
#define EXIT_FAILURE
Definition: cddefines.h:144
double BeamInIn
Definition: radius.h:102
void LineStackCreate(void)
#define cdEXIT(FAIL)
Definition: cddefines.h:438
long int nsumAllocated
Definition: lines.h:66
realnum covrt
Definition: geometry.h:51
realnum fracin
Definition: rt.h:239
char chALab[5]
Definition: lines.h:117
long nWindLine
Definition: cdinit.cpp:19
long int sig_figs
Definition: lines.h:91
const double EN1RYD
Definition: physconst.h:179
t_radius radius
Definition: radius.cpp:5
realnum ** reflin
Definition: rfield.h:206
bool lgDoLineTrans
Definition: rfield.h:117
double totlin(int chInfo)
struct t_tag_LineSv LinSv
double dVolOutwrd
Definition: radius.h:97
double BeamInOut
Definition: radius.h:105
#define ASSERT(exp)
Definition: cddefines.h:582
double emslin[2]
Definition: lines.h:128
double * anu
Definition: rfield.h:58
const double BOHR_RADIUS_CM
Definition: physconst.h:222
double GetGF(double trans_prob, double enercm, double gup)
TransitionList TauLines("TauLines",&AnonStates)
const char * chComment
Definition: lines.h:134
void VoigtU(realnum a, const realnum v[], realnum y[], int n)
Definition: thirdparty.h:364
CollisionProxy Coll() const
Definition: transition.h:424
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
const double ELECTRON_MASS
Definition: physconst.h:91
realnum * E2TauAbsFace
Definition: opacity.h:124
double BeamOutOut
Definition: radius.h:108
void outline_base(double dampXvel, double damp, bool lgTransStackLine, long int ip, double phots, realnum inwd, double nonScatteredFraction)
double * AnuOrg
Definition: rfield.h:62
LinSv * LineSvSortWL
Definition: cdinit.cpp:71
double ConvCrossSect2CollStr(double CrsSectCM2, double gLo, double E_ProjectileRyd, double reduced_mass_grams)
realnum & damp() const
Definition: emission.h:563
long int nHFLines
Definition: taulines.cpp:31
double emergent_line(double emissivity_in, double emissivity_out, long int ipCont)
long int nsum
Definition: lines.h:62
realnum * tmn
Definition: opacity.h:136
void linadd(double xInten, realnum wavelength, const char *chLab, char chInfo, const char *chComment)
vector< TransitionList > dBaseTrans
Definition: taulines.cpp:17
void fixit(void)
Definition: service.cpp:991
realnum WavlenErrorGet(realnum wavelength)
long int nflux
Definition: rfield.h:43
realnum & WLAng() const
Definition: transition.h:429
long int ipass
Definition: lines.h:75
STATIC void lincom(double xInten, realnum wavelength, const char *chLab, long int ipnt, char chInfo, const char *chComment, bool lgAdd)
double dVeffAper
Definition: radius.h:87
const double PI
Definition: physconst.h:29
t_rt rt
Definition: rt.cpp:5