cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mole_h2_create.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 /*H2_Create create variables for the H2 molecule, called by ContCreatePointers after continuum
4  * mesh has been set up */
5 #include "cddefines.h"
6 #include "collision.h"
7 #include "physconst.h"
8 #include "taulines.h"
9 #include "lines_service.h"
10 #include "opacity.h"
11 #include "hmi.h"
12 #include "ipoint.h"
13 #include "grainvar.h"
14 #include "h2.h"
15 #include "h2_priv.h"
16 #include "mole.h"
17 #include "dense.h"
18 
19 /* this integer is added to rotation quantum number J for the test of whether
20  * a particular J state is ortho or para - the state is ortho if J+below is odd,
21  * and para if J+below is even */
22 int H2_nRot_add_ortho_para[N_ELEC] = {0 , 1 , 1 , 0, 1, 1 , 0};
23 
24 /* if this is set true then code will print energies and stop */
25 enum {DEBUG_ENER=false};
26 
27 /* this is equation 8 of Takahashi 2001, clearer definition is given in
28  * equation 5 and following discussion of
29  * >>refer H2 formation Takahashi, J., & Uehara, H., 2001, ApJ, 561, 843-857
30  * 0.27eV, convert into wavenumbers */
31 static double XVIB[H2_TOP] = { 0.70 , 0.60 , 0.20 };
32 static double Xdust[H2_TOP] = { 0.04 , 0.10 , 0.40 };
33 
34 /* this is energy difference between bottom of potential well and 0,0
35  * the Takahashi energy scale is from the bottom,
36  * 2201.9 wavenumbers */
37 static const double energy_off = 0.273*FREQ_1EV/SPEEDLIGHT;
38 
39 STATIC double EH2_eval( int ipH2, double DissocEnergy, double energy_wn )
40 {
41  double EH2_here;
42  double Evm = DissocEnergy * XVIB[ipH2] + energy_off;
43 
44  double Ev = (energy_wn+energy_off);
45  /* equation 9 of Takahashi 2001 which is only an approximation
46  * equation 1, 2 of
47  * Takahashi, Junko, & Uehara, Hideya, 2001, ApJ, 561, 843-857,
48  * this is heat deposited on grain by H2 formation in this state */
49  double Edust = DissocEnergy * Xdust[ipH2] *
50  ( 1. - ( (Ev - Evm) / (DissocEnergy+energy_off-Evm)) *
51  ( (1.-Xdust[ipH2])/2.) );
52  ASSERT( Edust >= 0. );
53 
54  /* energy is total binding energy less energy lost on grain surface
55  * and energy offset */
56  EH2_here = DissocEnergy +energy_off - Edust;
57  ASSERT( EH2_here >= 0.);
58 
59  return EH2_here;
60 }
61 
62 /*H2_vib_dist evaluates the vibration distribution for H2 formed on grains */
63 STATIC double H2_vib_dist( int ipH2 , double EH2, double DissocEnergy, double energy_wn)
64 {
65  double G1[H2_TOP] = { 0.3 , 0.4 , 0.9 };
66  double G2[H2_TOP] = { 0.6 , 0.6 , 0.4 };
67  double Evm = DissocEnergy * XVIB[ipH2] + energy_off;
68  double Fv;
69  if( (energy_wn+energy_off) <= Evm )
70  {
71  /* equation 4 of Takahashi 2001 */
72  Fv = sexp( POW2( (energy_wn+energy_off - Evm)/(G1[ipH2]* Evm ) ) );
73  }
74  else
75  {
76  /* equation 5 of Takahashi 2001 */
77  Fv = sexp( POW2( (energy_wn+energy_off - Evm)/(G2[ipH2]*(EH2 - Evm ) ) ) );
78  }
79  return Fv;
80 }
81 
83 {
84  //quantumState_diatoms *Hi = static_cast<quantumState_diatoms*>( tr.Hi );
85  qList::iterator Lo = (*tr).Lo() ;
86  //if( Lo->n==0 && lgH2_radiative[ ipEnergySort[(*Hi).n][(*Hi).v][(*Hi).J] ][ ipEnergySort[Lo->n][Lo->v][Lo->J] ] )
87  if( (*Lo).n()==0 && (*tr).Emis().Aul() > 1.01e-30 )
88  return true;
89  else
90  return false;
91 }
92 
94 {
95  if( lgRadiative( tr1 ) && !lgRadiative( tr2 ) )
96  return true;
97  else
98  return false;
99 }
100 
102 {
103  if( st1.energy().Ryd() <= st2.energy().Ryd() )
104  return true;
105  else
106  return false;
107 }
108 
109 /* create variables for the H2 molecule, called by
110  * ContCreatePointers after continuum mesh has been set up */
111 void diatomics::init(void)
112 {
113  /* this is flag set above - when true h2 code is not executed - this is way to
114  * avoid this code when it is not working */
115  /* only malloc vectors one time per core load */
116  if( lgREAD_DATA || !lgEnabled )
117  return;
118 
119  DEBUG_ENTRY( "H2_Create()" );
120 
121  /* print string if H2 debugging is enabled */
122  if( nTRACE )
123  fprintf(ioQQQ," H2_Create called in DEBUG mode.\n");
124 
125  // find the species in the chemistry network
126  sp = findspecies( label.c_str() );
127  ASSERT( sp != null_mole );
128 
129  // find the same species with the excitation marker
130  string strSpStar = shortlabel + "*";
131  sp_star = findspecies( strSpStar.c_str() );
132  ASSERT( sp != null_mole );
133 
135  ASSERT( mass_amu > 0. );
136 
138 
139  /* This does more than just read energies... it actually defines the states */
140  H2_ReadEnergies();
141 
142  // now sort states into energy order
143  fixit(); // this doesn't work!
144  //sort( states.begin(), states.end(), compareEnergies );
145 
146  ASSERT( n_elec_states > 0 );
147  /* create a vector of sorted energies */
149  for( long iElecHi=0; iElecHi<n_elec_states; ++iElecHi )
150  {
151  ipEnergySort.reserve(iElecHi,nVib_hi[iElecHi]+1);
152  for( long iVibHi = 0; iVibHi <= nVib_hi[iElecHi]; ++iVibHi )
153  {
154  ipEnergySort.reserve(iElecHi,iVibHi,nRot_hi[iElecHi][iVibHi]+1);
155  }
156  }
158 
159  /* create arrays for energy sorted referencing of e, v, J */
160  ipElec_H2_energy_sort.resize( states.size() );
161  ipVib_H2_energy_sort.resize( states.size() );
162  ipRot_H2_energy_sort.resize( states.size() );
163  for( unsigned nEner = 0; nEner < states.size(); ++nEner )
164  {
165  long iElec = states[nEner].n();
166  long iVib = states[nEner].v();
167  long iRot = states[nEner].J();
168  ipElec_H2_energy_sort[nEner] = iElec;
169  ipVib_H2_energy_sort[nEner] = iVib;
170  ipRot_H2_energy_sort[nEner] = iRot;
171  ipEnergySort[iElec][iVib][iRot] = nEner;
172  /* following will print quantum indices and energies */
173  /*fprintf(ioQQQ,"%li\t%li\t%li\t%.3e\n", iElec, iVib, iRot,
174  states[nEner].energy().WN() );*/
175  }
176 
179 
180  /* set all statistical weights - ours is total statistical weight -
181  * including nuclear spin */
182  for( qList::iterator st = states.begin(); st != states.end(); ++st )
183  {
184  /* unlike atoms, for H2 nuclear spin is taken into account - so the
185  * statistical weight of even and odd J states differ by factor of 3 - see page 166, sec par
186  * >>>refer H2 H2_stat wght Shull, J.M., & Beckwith, S., 1982, ARAA, 20, 163-188 */
187  if( is_odd( (*st).J() + H2_nRot_add_ortho_para[(*st).n()]) )
188  {
189  /* ortho */
190  H2_lgOrtho[(*st).n()][(*st).v()][(*st).J()] = true;
191  H2_stat[(*st).n()][(*st).v()][(*st).J()] = 3.f*(2.f*(*st).J()+1.f);
192  }
193  else
194  {
195  /* para */
196  H2_lgOrtho[(*st).n()][(*st).v()][(*st).J()] = false;
197  H2_stat[(*st).n()][(*st).v()][(*st).J()] = (2.f*(*st).J()+1.f);
198  }
199  (*st).g() = H2_stat[(*st).n()][(*st).v()][(*st).J()];
200  }
201 
202  if( nTRACE >= n_trace_full )
203  {
204  for( long iElec=0; iElec<n_elec_states; ++iElec)
205  {
206  /* print the number of levels within iElec */
207  fprintf(ioQQQ,"\t(%li %li)", iElec , nLevels_per_elec[iElec] );
208  }
209  fprintf(ioQQQ,
210  " H2_Create: there are %li electronic levels, in each level there are",
211  n_elec_states);
212  fprintf(ioQQQ,
213  " for a total of %li levels.\n", (long int) states.size() );
214  }
215 
216  /* now find number of levels in H2g */
217  for( long nEner=0; nEner<nLevels_per_elec[0]; ++nEner )
218  {
219  if( states[nEner].energy().WN() > ENERGY_H2_STAR && hmi.lgLeiden_Keep_ipMH2s )
220  break;
221  nEner_H2_ground = nEner;
222  }
223  /* need to increment it so that this is the number of levels, not the index
224  * of the highest level */
225  ++nEner_H2_ground;
226 
227  /* this is the number of levels to do with the matrix - set with the
228  * atom h2 matrix command, keyword ALL means to do all of X in the matrix
229  * but number of levels within X was not known when the command was parsed,
230  * so this was set to -1 to defer setting to all until now */
231  if( nXLevelsMatrix<0 )
232  {
233  nXLevelsMatrix = nLevels_per_elec[0];
234  }
235  else if( nXLevelsMatrix > nLevels_per_elec[0] )
236  {
237  fprintf( ioQQQ,
238  " The total number of levels used in the matrix solver was set to %li but there are only %li levels in X.\n Sorry.\n",
240  nLevels_per_elec[0]);
242  }
243 
244  /* at this stage the full electronic, vibration, and rotation energies have been defined,
245  * this is an option to print the energies */
246  {
247  /* set following true to get printout, false to not print energies */
248  if( DEBUG_ENER )
249  {
250  /* print title for quantum numbers and energies */
251  /*fprintf(ioQQQ,"elec\tvib\trot\tenergy\n");*/
252  for( qList::const_iterator st = states.begin(); st != states.end(); ++st )
253  {
254  fprintf(ioQQQ,"%li\t%li\t%li\t%.5e\n", (*st).n(), (*st).v(), (*st).J(), (*st).energy().WN() );
255  }
256  /* this will exit the program after printing the level energies */
258  }
259  }
260 
261  /* this will prevent data from being read twice */
262  lgREAD_DATA = true;
263 
264  /* create space for the electronic levels */
265  H2_populations_LTE.reserve(n_elec_states);
266  pops_per_vib.reserve(n_elec_states);
267  H2_dissprob.reserve(n_elec_states);
268 
269  for( long iElec = 0; iElec<n_elec_states; ++iElec )
270  {
271 
272  if( nTRACE >= n_trace_full )
273  fprintf(ioQQQ,"elec %li highest vib= %li\n", iElec , nVib_hi[iElec] );
274 
275  ASSERT( nVib_hi[iElec] > 0 );
276 
277  /* nVib_hi is now the highest vibrational level before dissociation,
278  * now allocate space to hold the number of rotation levels */
279  H2_populations_LTE.reserve(iElec,nVib_hi[iElec]+1);
280  pops_per_vib.reserve(iElec,nVib_hi[iElec]+1);
281 
282  /* now loop over all vibrational levels, and find out how many rotation levels there are */
283  /* ground is special since use tabulated data - there are 14 vib states,
284  * ivib=14 is highest */
285  for( long iVib = 0; iVib <= nVib_hi[iElec]; ++iVib )
286  {
287  /* lastly create the space for the rotation quantum number */
288  H2_populations_LTE.reserve(iElec,iVib,nRot_hi[iElec][iVib]+1);
289  }
290  }
291 
298  // this has a different geometry than the above
300 
301  H2_dissprob.zero();
302  H2_disske.zero();
303 
304  /* set this one time, will never be set again, but might be printed */
306 
307  /* these do not have electronic levels - all within X */
308  H2_ipPhoto.reserve(nVib_hi[0]+1);
309 
310  /* space for the vibration levels */
311  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
312  {
313  /* space for the rotation quantum number */
314  H2_ipPhoto.reserve(iVib,nRot_hi[0][iVib]+1);
315  }
316 
317  H2_ipPhoto.alloc();
329 
330  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
331  {
332  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
333  {
334  /* >>chng 04 jun 14, set these to bad numbers */
335  H2_rad_rate_in[iVib][iRot] = -BIGFLOAT;
336  H2_coll_dissoc_rate_coef[iVib][iRot] = -BIGFLOAT;
337  H2_coll_dissoc_rate_coef_H2[iVib][iRot] = -BIGFLOAT;
338  }
339  }
340  /* zero out the matrices */
341  H2_X_colden.zero();
345  /* rates [cm-3 s-1] from elec excited states into X only vib and rot */
347  /* rates [s-1] to elec excited states from X only vib and rot */
349 
350  /* distribution function for populations following formation from H minus H- */
352  for( long i=0; i<nTE_HMINUS; ++i )
353  {
355  /* space for the vibration levels */
356  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
357  {
359  }
360  }
364 
365  /* >>chng 05 jun 20, do not use this, which is highly processed - use ab initio
366  * rates of excitation to electronic levels instead */
367  /* read in cosmic ray distribution information
368  H2_Read_Cosmicray_distribution(); */
369 
370  /* grain formation matrix */
372  for( long ipH2=0; ipH2<(int)H2_TOP; ++ipH2 )
373  {
375 
376  /* space for the vibration levels */
377  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
378  {
380  }
381  }
384 
385  for( long iElec=0; iElec<n_elec_states; ++iElec )
386  {
387  /* get dissociation probabilities and energies - ground state is stable */
388  if( iElec > 0 )
389  H2_ReadDissprob(iElec);
390  }
391 
392  /* >>02 oct 18, add photodissociation, H2 + hnu => 2H + KE */
393  /* we now have ro-vib energies, now set up threshold array offsets
394  * for photodissociation */
395  for( qList::const_iterator st = states.begin(); st != states.end(); ++st )
396  {
397  long iElec = (*st).n();
398  if( iElec > 0 ) continue;
399  long iVib = (*st).v();
400  long iRot = (*st).J();
401  /* this is energy needed to get up to n=3 electronic continuum
402  * H2 cannot dissociate following absorption of a continuum photon into the
403  * continuum above X (which would require little energy)
404  * because that process violates momentum conservation
405  * these would be the triplet states - permitted are into singlets
406  * the effective full wavelength range of this process is from Lya to
407  * Lyman limit in shielded regions
408  * tests show limits are between 850A and 1220A - so Lya is included */
410  /*>>KEYWORD Allison & Dalgarno; continuum dissociation; */
411  double thresh = (H2_DissocEnergies[1] - (*st).energy().WN())*WAVNRYD;
412  /*fprintf(ioQQQ,"DEBUG\t%.2f\t%f\n", RYDLAM/thresh , thresh);*/
413  /* in theory we should be able to assert that thesh just barely reaches
414  * lya, but actual numbers reach down to 0.749 ryd */
415  ASSERT( thresh > 0.74 );
416  H2_ipPhoto[iVib][iRot] = ipoint(thresh);
417  fixit(); // this needs to be generalized
418  }
419 
420  CollRateCoeff.reserve( nLevels_per_elec[0] );
421  for( long j = 1; j < nLevels_per_elec[0]; ++j )
422  {
423  CollRateCoeff.reserve( j, j );
424  for( long k = 0; k < j; ++k )
425  {
427  }
428  }
431 
432  fixit(); // Does RateCoefTable only need to be N_X_COLLIDER long?
433  RateCoefTable.resize(ipNCOLLIDER);
434  /* now read in the various sets of collision data */
435  for( long nColl=0; nColl<N_X_COLLIDER; ++nColl )
436  {
437  /* ground state has tabulated data */
438  H2_CollidRateRead(nColl);
439  }
440 
443 
444  /* option to add gaussian random mole */
445  if( lgH2_NOISE )
446  {
447  for( long ipHi = 1; ipHi < nLevels_per_elec[0]; ++ipHi )
448  {
449  for( long ipLo = 0; ipLo < ipHi; ++ipLo )
450  {
451  for( long nColl=0; nColl<N_X_COLLIDER; ++nColl )
452  {
453  /* this returns the log of the random noise */
455  CollRateErrFac[ipHi][ipLo][nColl] = pow((realnum)10.f,r);
456  }
457  }
458  }
459  }
460 
461  /* this will be total collision rate from an upper to a lower level within X */
462  H2_X_source.resize( nLevels_per_elec[0] );
463  H2_X_sink.resize( nLevels_per_elec[0] );
464 
465  H2_X_coll_rate.reserve(nLevels_per_elec[0]);
466  /* now expand out to include all lower levels as lower state */
467  for( long i=1; i<nLevels_per_elec[0]; ++i )
468  {
469  H2_X_coll_rate.reserve(i,i);
470  }
472 
474  for( unsigned nEner = 1; nEner < states.size(); ++nEner )
475  ipTransitionSort.reserve( nEner, nEner );
480 
481  trans.resize( (states.size() * (states.size()-1))/2 );
482  AllTransitions.push_back(trans);
483  qList initStates(1);
484  TransitionList initlist("H2InitList",&initStates);
485  vector<TransitionList::iterator> initptrs;
486  initlist.resize(trans.size());
487  initlist.states() = &states;
488  initptrs.resize(trans.size());
489 
490  {
491  long lineIndex = 0;
492  TransitionList::iterator tr = initlist.begin();
493  for( unsigned ipHi=1; ipHi< states.size(); ++ipHi )
494  {
495  for( unsigned ipLo=0; ipLo<ipHi; ++ipLo )
496  {
497  (*tr).Junk();
498  (*tr).setHi(ipHi);
499  (*tr).setLo(ipLo);
500  (*tr).Zero();
501  initptrs[lineIndex] = tr;
502  ipTransitionSort[ipHi][ipLo] = lineIndex;
503  lineIndex++;
504  ++tr;
505  }
506  }
507  }
508 
509  /* create the main array of lines */
510  H2_SaveLine.reserve(n_elec_states);
511  for( long iElecHi=0; iElecHi<n_elec_states; ++iElecHi )
512  {
513  H2_SaveLine.reserve(iElecHi,nVib_hi[iElecHi]+1);
514  for( long iVibHi=0; iVibHi<=nVib_hi[iElecHi]; ++iVibHi )
515  {
516  H2_SaveLine.reserve(iElecHi,iVibHi,nRot_hi[iElecHi][iVibHi]+1);
517  for( long iRotHi=Jlowest[iElecHi]; iRotHi<=nRot_hi[iElecHi][iVibHi]; ++iRotHi )
518  {
519  /* now the lower levels */
520  /* NB - X is the only lower level considered here, since we are only
521  * concerned with excited electronic levels as a photodissociation process
522  * code exists to relax this assumption - simply change following to iElecHi */
523  long int lim_elec_lo = 0;
524  H2_SaveLine.reserve(iElecHi,iVibHi,iRotHi,lim_elec_lo+1);
525  for( long iElecLo=0; iElecLo<=lim_elec_lo; ++iElecLo )
526  {
527  H2_SaveLine.reserve(iElecHi,iVibHi,iRotHi,iElecLo,nVib_hi[iElecLo]+1);
528  for( long iVibLo=0; iVibLo<=nVib_hi[iElecLo]; ++iVibLo )
529  {
530  H2_SaveLine.reserve(iElecHi,iVibHi,iRotHi,iElecLo,iVibLo,nRot_hi[iElecLo][iVibLo]+1);
531  }
532  }
533  }
534  }
535  }
536 
537  H2_SaveLine.alloc();
538 
539  /* zero out array used to save emission line intensities */
540  H2_SaveLine.zero();
541 
542  /* space for the energy vector is now malloced, must read trans probs from table */
543  for( long iElec=0; iElec<n_elec_states; ++iElec )
544  {
545  /* ground state has tabulated data */
546  H2_ReadTransprob(iElec,initlist);
547  }
548 
549  // sort sys.trans so that radiative lines are at the beginning
550  stable_sort( initptrs.begin(), initptrs.end(), compareEmis );
551  rad_end = trans.begin();
552  // rad_end will be used for the end of the range (non-inclusive) for operations on radiative lines
553  {
555  vector<TransitionList::iterator>::iterator ptr = initptrs.begin();
556  for (size_t i=0; i < initptrs.size(); ++i, ++tr, ++ptr)
557  {
558  (*tr).copy(*(*ptr));
559  if (lgRadiative(tr))
560  {
561  rad_end = tr;
562  }
563  }
564  }
565  ++rad_end;
566  ASSERT( rad_end != trans.end() );
567  // after above sorting, ipTransitionSort is now invalid. Fix here
568  for( unsigned i = 0; i < trans.size(); ++i )
569  {
570  qList::iterator Hi = trans[i].Hi();
571  qList::iterator Lo = trans[i].Lo();
572  ipTransitionSort[ ipEnergySort[(*Hi).n()][(*Hi).v()][(*Hi).J()] ][ ipEnergySort[(*Lo).n()][(*Lo).v()][(*Lo).J()] ] = i;
573  trans[i].ipHi() = ipEnergySort[(*Hi).n()][(*Hi).v()][(*Hi).J()];
574  trans[i].ipLo() = ipEnergySort[(*Lo).n()][(*Lo).v()][(*Lo).J()];
575  }
576 
577  // link level and line stacks to species in the chemistry network
578  mole.species[ sp->index ].levels = &states;
579  mole.species[ sp->index ].lines = &trans;
580 
581  // after above sorting, ipTransitionSort is now invalid. Fix here
582  for( unsigned i = 0; i < trans.size(); ++i )
583  {
584  qList::iterator Hi = trans[i].Hi();
585  qList::iterator Lo = trans[i].Lo();
586  ipTransitionSort[ ipEnergySort[(*Hi).n()][(*Hi).v()][(*Hi).J()] ][ ipEnergySort[(*Lo).n()][(*Lo).v()][(*Lo).J()] ] = i;
587  //trans[i].ipHi() = ipEnergySort[(*Hi).n()][(*Hi).v()][(*Hi).J()];
588  //trans[i].ipLo() = ipEnergySort[(*Lo).n()][(*Lo).v()][(*Lo).J()];
589  }
590 
591  // this loop is over all transitions
592  for( TransitionList::iterator tr = trans.begin(); tr != trans.end(); ++tr )
593  {
594  (*tr).EnergyWN() = (realnum)((*(*tr).Hi()).energy().WN() - (*(*tr).Lo()).energy().WN());
595  /*wavelength of transition in Angstroms */
596  if( (*tr).EnergyWN() > SMALLFLOAT)
597  (*tr).WLAng() = (realnum)(1.e8f/(*tr).EnergyWN() / RefIndex( (*tr).EnergyWN() ) );
598 
599  (*tr).Coll().col_str() = 0.;
600  }
601 
602  // this loop is over only radiative transitions. Notice the end iterator.
603  for( TransitionList::iterator tr = trans.begin(); tr != rad_end; ++tr )
604  {
605  /* line redistribution function - will use complete redistribution */
606  /* >>chng 04 mar 26, should include damping wings, especially for electronic
607  * transitions, had used doppler core only */
608  (*tr).resetEmis();
609  (*tr).Emis().iRedisFun() = ipCRDW;
610  /* line optical depths in direction towards source of ionizing radiation */
611  (*tr).Emis().TauIn() = opac.taumin;
612  (*tr).Emis().TauCon() = opac.taumin;
613  /* outward optical depth */
614  (*tr).Emis().TauTot() = 1e20f;
615 
616  (*tr).Emis().dampXvel() = (realnum)( (*tr).Emis().Aul()/(*tr).EnergyWN()/PI4);
617  (*tr).Emis().gf() = (realnum)(GetGF( (*tr).Emis().Aul(),(*tr).EnergyWN(), (*(*tr).Hi()).g() ) );
618 
619  /* derive the absorption coefficient, call to function is gf, wl (A), g_low */
620  (*tr).Emis().opacity() = (realnum)( abscf( (*tr).Emis().gf(), (*tr).EnergyWN(), (*(*tr).Lo()).g()) );
621 
622  qList::iterator Hi = (*tr).Hi() ;
623 
624  if( (*Hi).n() == 0 )
625  {
626  /* the ground electronic state, most excitations are not direct pumping
627  * (rather indirect, which does not count for ColOvTot) */
628  (*tr).Emis().ColOvTot() = 1.;
629  }
630  else
631  {
632  /* these are excited electronic states, mostly pumped, except for supras */
634  (*tr).Emis().ColOvTot() = 0.;
635  }
636 
637  fixit(); // why not include this for excitations within X as well?
638  if( (*Hi).n() > 0 )
639  {
640  /* cosmic ray and non-thermal suprathermal excitation
641  * to singlet state of H2 (B,C,B',D)
642  * cross section is equation 5 of
643  *>>refer H2 cs Liu, W. & Dalgarno, A. 1994, ApJ, 428, 769
644  * relative to H I Lya cross section
645  * this is used to derive H2 electronic excitations
646  * from the H I Lya rate
647  * the following is dimensionless scale factor for excitation
648  * relative to H I Lya
649  */
650  (*tr).Coll().col_str() = (realnum)(
651  pow3( (*tr).WLAng()*1e-8 ) *
652  ( (*(*tr).Hi()).g()/(*(*tr).Lo()).g()) *
653  (*tr).Emis().Aul() *
654  log(3.)*HPLANCK/(160.f*pow3(PI)*0.5*1e-8*EN1EV)/6.e-17);
655  ASSERT( (*tr).Coll().col_str()>0.);
656  }
657  }
658 
659  /* Read continuum photodissociation cross section files */
660  if( mole_global.lgStancil )
662 
663  /* define branching ratios for deposition of H2 formed on grain surfaces,
664  * set true to use Takahashi distribution, false to use Draine & Bertoldi */
665 
666  /* loop over all types of grain surfaces */
667  /* >>chng 02 oct 08, resolved grain types */
668  /* number of different grain types H2_TOP is set in grainvar.h,
669  * types are ice, silicate, graphite */
670  for( long ipH2=0; ipH2<(int)H2_TOP; ++ipH2 )
671  {
672  realnum sum = 0., sumj = 0., sumv = 0., sumo = 0., sump = 0.;
673 
674  /* first is Draine distribution */
675  if( hmi.chGrainFormPump == 'D' )
676  {
677  long iElec = 0;
678  /* H2 formation temperature, for equation 19, page 271, of
679  * >>refer H2 formation distribution Draine, B.T., & Bertoldi, F., 1996, ApJ, 468, 269-289
680  */
681  double T_H2_FORM = 50000.;
682  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
683  {
684  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
685  {
686  /* no distinction between grain surface composition */
688  /* first term is nuclear H2_stat weight */
689  (1.f+2.f*H2_lgOrtho[iElec][iVib][iRot]) * (1.f+iVib) *
690  (realnum)sexp( states[ ipEnergySort[iElec][iVib][iRot] ].energy().K()/T_H2_FORM );
691  sum += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
692  sumj += iRot * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
693  sumv += iVib * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
694  if( H2_lgOrtho[iElec][iVib][iRot] )
695  {
696  sumo += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
697  }
698  else
699  {
700  /* >>chng 02 nov 14, [0][iVib][iRot] -> [ipH2][iVib][iRot], PvH */
701  sump += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
702  }
703  }
704  }
705  }
706  else if( hmi.chGrainFormPump == 'T' )
707  {
708  /* Takahashi 2001 distribution */
709  double Xrot[H2_TOP] = { 0.14 , 0.15 , 0.15 };
710  double Xtrans[H2_TOP] = { 0.12 , 0.15 , 0.25 };
711  /* first normalize the vibration distribution function */
712  double sumvib = 0.;
713  double EH2;
714  long iElec = 0;
715 
716  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
717  {
718  double vibdist;
719  EH2 = EH2_eval( ipH2, H2_DissocEnergies[0], states[ ipEnergySort[0][iVib][0] ].energy().WN() );
720  vibdist = H2_vib_dist( ipH2 , EH2, H2_DissocEnergies[0], states[ ipEnergySort[0][iVib][0] ].energy().WN() );
721  sumvib += vibdist;
722  }
723  /* this branch, use distribution function from
724  * >>refer grain physics Takahashi, Junko, 2001, ApJ, 561, 254-263 */
725  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
726  {
727  double Ev = states[ ipEnergySort[iElec][iVib][0] ].energy().WN()+energy_off;
728  double Fv;
729  /* equation 10 of Takahashi 2001, extra term is energy offset between bottom of potential
730  * the 0,0 level */
731  double Erot;
732  /*fprintf(ioQQQ," Evvvv\t%i\t%li\t%.3e\n", ipH2 ,iVib , Ev*WAVNRYD*EVRYD);*/
733 
734  EH2 = EH2_eval( ipH2, H2_DissocEnergies[0], states[ ipEnergySort[0][iVib][0] ].energy().WN() );
735 
736  /* equation 3 of Taktahashi & Uehara */
737  Erot = (EH2 - Ev) * Xrot[ipH2] / (Xrot[ipH2] + Xtrans[ipH2]);
738 
739  /* email exchange with Junko Takahashi -
740  Thank you for your E-mail.
741  I did not intend to generate negative Erot.
742  I cut off the populations if their energy levels are negative, and made the total
743  population be unity by using normalization factors (see, e.g., Eq. 12).
744 
745  I hope that my answer is of help to you and your work is going well.
746  With best wishes,
747  Junko
748 
749  >Thanks for the reply. By cutting off the population, should we set the
750  >population to zero when Erot becomes negative, or should we set Erot to
751  >a small positive number?
752 
753  I just set the population to zero when Erot becomes negative.
754  Our model is still a rough one for the vibration-rotation distribution function
755  of H2 newly formed on dust, because we have not yet had any exact
756  experimental or theoretical data about it.
757  With best wishes,
758  Junko
759 
760  */
761 
762  if( Erot > 0. )
763  {
764  /* the vibrational distribution */
765  Fv = H2_vib_dist( ipH2 , EH2, H2_DissocEnergies[0], states[ ipEnergySort[0][iVib][0] ].energy().WN() ) / sumvib;
766  /*fprintf(ioQQQ," vibbb\t%li\t%.3e\n", iVib , Fv );*/
767 
768  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
769  {
770  double deltaE = states[ ipEnergySort[iElec][iVib][iRot] ].energy().WN() -
771  states[ ipEnergySort[iElec][iVib][0] ].energy().WN();
772  /* equation 6 of Takahashi 2001 */
773  double gaussian = sexp( POW2( (deltaE - Erot) / (0.5 * Erot) ) );
774  /* equation 7 of Takahashi 2001 */
775  double thermal_dist = sexp( deltaE / Erot );
776 
777  /* take the mean of the two */
778  double aver = ( gaussian + thermal_dist ) / 2.;
779  /*fprintf(ioQQQ,"rottt\t%i\t%li\t%li\t%.3e\t%.3e\t%.3e\t%.3e\n",
780  ipH2,iVib,iRot,
781  deltaE*WAVNRYD*EVRYD,
782  gaussian, thermal_dist , aver );*/
783 
784  /* thermal_dist does become > 1 since Erot can become negative */
785  ASSERT( gaussian <= 1. /*&& thermal_dist <= 10.*/ );
786 
788  /* first term is nuclear H2_stat weight */
789  (1.f+2.f*H2_lgOrtho[iElec][iVib][iRot]) * Fv * (2.*iRot+1.) * aver );
790 
791  sum += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
792  sumj += iRot * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
793  sumv += iVib * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
794  if( H2_lgOrtho[iElec][iVib][iRot] )
795  {
796  sumo += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
797  }
798  else
799  {
800  sump += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
801  }
802 
803  }
804  }
805  else
806  {
807  /* this branch Erot is non-positive, so no distribution */
808  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
809  {
810  H2_X_grain_formation_distribution[ipH2][iVib][iRot] = 0.;
811  }
812  }
813  }
814  }
815  else if( hmi.chGrainFormPump == 't' )
816  {
817  /* thermal distribution at 1.5 eV, as suggested by Amiel & Jaques */
818  /* thermal distribution, upper right column of page 239 of
819  *>>refer H2 formation Le Bourlot, J, 1991, A&A, 242, 235
820  * set with command
821  * set h2 grain formation pumping thermal */
822  double T_H2_FORM = 17329.;
823  long iElec = 0;
824  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
825  {
826  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
827  {
828  /* no distinction between grain surface composition */
830  /* first term is nuclear H2_stat weight */
831  H2_stat[0][iVib][iRot] *
832  (realnum)sexp( states[ ipEnergySort[0][iVib][iRot] ].energy().K()/T_H2_FORM );
833  sum += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
834  sumj += iRot * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
835  sumv += iVib * H2_X_grain_formation_distribution[ipH2][iVib][iRot];
836  if( H2_lgOrtho[iElec][iVib][iRot] )
837  {
838  sumo += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
839  }
840  else
841  {
842  /* >>chng 02 nov 14, [0][iVib][iRot] -> [ipH2][iVib][iRot], PvH */
843  sump += H2_X_grain_formation_distribution[ipH2][iVib][iRot];
844  }
845  }
846  }
847  }
848  else
849  TotalInsanity();
850 
851  if( nTRACE >= n_trace_full )
852  fprintf(ioQQQ, "H2 form grains mean J= %.3f mean v = %.3f ortho/para= %.3f\n",
853  sumj/sum , sumv/sum , sumo/sump );
854 
855  //iElec = 0;
856  /* now rescale so that integral is unity */
857  for( long iVib = 0; iVib <= nVib_hi[0]; ++iVib )
858  {
859  for( long iRot=Jlowest[0]; iRot<=nRot_hi[0][iVib]; ++iRot )
860  {
861  H2_X_grain_formation_distribution[ipH2][iVib][iRot] /= sum;
862  /* print the distribution function */
863  /*if( states[ ipEnergySort[iElec][iVib][iRot] ].energy().WN() < 5200. )
864  fprintf(ioQQQ,"disttt\t%i\t%li\t%li\t%li\t%.4e\t%.4e\t%.4e\t%.4e\n",
865  ipH2, iVib , iRot, (long)H2_stat[0][iVib][iRot] ,
866  states[ ipEnergySort[iElec][iVib][iRot] ].energy().WN(),
867  states[ ipEnergySort[iElec][iVib][iRot] ].energy().K(),
868  H2_X_grain_formation_distribution[ipH2][iVib][iRot],
869  H2_X_grain_formation_distribution[ipH2][iVib][iRot]/H2_stat[0][iVib][iRot]
870  );*/
871  }
872  }
873  }
874 
875  return;
876 }
multi_arr< double, 2 > H2_rad_rate_in
Definition: h2_priv.h:650
int nTRACE
Definition: h2_priv.h:396
multi_arr< double, 2 > H2_col_rate_out
Definition: h2_priv.h:649
const int N_ELEC
Definition: h2_priv.h:21
t_mole_global mole_global
Definition: mole.cpp:6
multi_arr< realnum, 3 > H2_dissprob
Definition: h2_priv.h:629
bool lgStancil
Definition: mole.h:289
char chGrainFormPump
Definition: hmi.h:171
const double ENERGY_H2_STAR
Definition: h2_priv.h:582
size_t size(void) const
Definition: transition.h:297
bool is_odd(int j)
Definition: cddefines.h:718
molecule * null_mole
double H2_DissocEnergies[N_ELEC]
Definition: h2_priv.h:606
NORETURN void TotalInsanity(void)
Definition: service.cpp:886
Energy & energy() const
Definition: quantumstate.h:153
t_opac opac
Definition: opacity.cpp:5
long int n_elec_states
Definition: h2_priv.h:406
STATIC bool compareEmis(const TransitionList::iterator &tr1, const TransitionList::iterator &tr2)
double abscf(double gf, double enercm, double gl)
realnum mass_amu
Definition: h2_priv.h:393
const realnum SMALLFLOAT
Definition: cpu.h:178
bool lgLeiden_Keep_ipMH2s
Definition: hmi.h:208
int n_trace_full
Definition: h2_priv.h:399
multi_arr< double, 2 > pops_per_vib
Definition: h2_priv.h:597
multi_arr< realnum, 2 > H2_coll_dissoc_rate_coef_H2
Definition: h2_priv.h:668
molecule * sp_star
Definition: h2_priv.h:561
bool lgREAD_DATA
Definition: h2_priv.h:249
valarray< long > ipVib_H2_energy_sort
Definition: h2_priv.h:684
long int Jlowest[N_ELEC]
Definition: h2_priv.h:613
const int nTE_HMINUS
Definition: h2_priv.h:18
double xSTDNoise
Definition: h2_priv.h:388
void H2_CollidRateRead(long int nColl)
vector< CollRateCoeffArray > RateCoefTable
Definition: h2_priv.h:620
iterator begin(void)
Definition: transition.h:305
sys_float sexp(sys_float x)
Definition: service.cpp:914
double RefIndex(double EnergyWN)
int H2_nRot_add_ortho_para[N_ELEC]
static double * g
Definition: species2.cpp:28
T pow3(T a)
Definition: cddefines.h:942
FILE * ioQQQ
Definition: cddefines.cpp:7
multi_arr< realnum, 2 > H2_coll_dissoc_rate_coef
Definition: h2_priv.h:665
static double Xdust[H2_TOP]
void H2_Read_hminus_distribution(void)
Definition: mole_h2_io.cpp:986
static double XVIB[H2_TOP]
TransitionList trans
Definition: h2_priv.h:563
void resize(size_t i)
Definition: quantumstate.h:83
const double SPEEDLIGHT
Definition: physconst.h:100
long int nEner_H2_ground
Definition: h2_priv.h:594
multi_arr< realnum, 3 > CollRateErrFac
Definition: h2_priv.h:619
multi_arr< realnum, 2 > H2_X_formation
Definition: h2_priv.h:653
const double PI4
Definition: physconst.h:35
multi_arr< realnum, 3 > CollRateCoeff
Definition: h2_priv.h:618
multi_arr< realnum, 3 > H2_stat
Definition: h2_priv.h:638
valarray< realnum > H2_X_sink
Definition: h2_priv.h:672
static const double energy_off
multi_arr< long int, 3 > ipEnergySort
Definition: h2_priv.h:687
multi_arr< double, 3 > H2_old_populations
Definition: h2_priv.h:634
molecule * sp
Definition: h2_priv.h:558
qList *& states()
Definition: transition.h:325
const multi_geom< d, ALLOC > & clone() const
multi_arr< realnum, 3 > H2_disske
Definition: h2_priv.h:630
void resize(size_t newsize)
Definition: transition.h:285
void H2_ReadEnergies()
Definition: mole_h2_io.cpp:674
long ipoint(double energy_ryd)
Definition: cont_ipoint.cpp:16
multi_arr< realnum, 3 > H2_X_hminus_formation_distribution
Definition: h2_priv.h:682
#define POW2
Definition: cddefines.h:933
long int nLevels_per_elec[N_ELEC]
Definition: h2_priv.h:615
#define STATIC
Definition: cddefines.h:101
double xMeanNoise
Definition: h2_priv.h:388
const double WAVNRYD
Definition: physconst.h:173
bool lgEnabled
Definition: h2_priv.h:342
multi_arr< double, 3 > H2_populations_LTE
Definition: h2_priv.h:636
string label
Definition: h2_priv.h:568
STATIC double EH2_eval(int ipH2, double DissocEnergy, double energy_wn)
t_mole_local mole
Definition: mole.cpp:7
molecule * findspecies(const char buf[])
bool lgH2_NOISE
Definition: h2_priv.h:380
const int N_X_COLLIDER
Definition: h2_priv.h:13
float realnum
Definition: cddefines.h:107
valarray< class molezone > species
Definition: mole.h:355
#define EXIT_FAILURE
Definition: cddefines.h:144
multi_arr< realnum, 2 > H2_X_colden_LTE
Definition: h2_priv.h:659
multi_arr< bool, 2 > lgH2_radiative
Definition: h2_priv.h:711
const realnum BIGFLOAT
Definition: cpu.h:176
long int nXLevelsMatrix
Definition: h2_priv.h:692
size_t size() const
Definition: quantumstate.h:116
multi_arr< realnum, 2 > H2_X_Hmin_back
Definition: h2_priv.h:655
#define cdEXIT(FAIL)
Definition: cddefines.h:438
int index
Definition: mole.h:169
multi_arr< realnum, 6 > H2_SaveLine
Definition: h2_priv.h:707
multi_arr< double, 3 > H2_rad_rate_out
Definition: h2_priv.h:631
valarray< long > ipElec_H2_energy_sort
Definition: h2_priv.h:685
double RandGauss(double xMean, double s)
Definition: service.cpp:1643
void Read_Mol_Diss_cross_sections(void)
multi_arr< realnum, 3 > H2_X_grain_formation_distribution
Definition: h2_priv.h:676
const double EN1EV
Definition: physconst.h:192
iterator end(void)
Definition: transition.h:309
iterator end()
Definition: quantumstate.h:345
#define ASSERT(exp)
Definition: cddefines.h:582
void H2_ReadTransprob(long int nelec, TransitionList &trans)
Definition: mole_h2_io.cpp:430
multi_arr< double, 2 > H2_X_rate_to_elec_excited
Definition: h2_priv.h:663
void reserve(size_type i1)
double GetGF(double trans_prob, double enercm, double gup)
string shortlabel
Definition: h2_priv.h:569
multi_arr< double, 2 > H2_X_rate_from_elec_excited
Definition: h2_priv.h:661
qList states
Definition: h2_priv.h:562
double Ryd() const
Definition: energy.h:26
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
iterator begin()
Definition: quantumstate.h:337
multi_arr< long int, 2 > ipTransitionSort
Definition: h2_priv.h:688
bool compareEnergies(qStateProxy st1, qStateProxy st2)
realnum mole_mass
Definition: mole.h:165
TransitionList::iterator rad_end
Definition: h2_priv.h:564
void H2_ReadDissocEnergies(void)
Definition: mole_h2_io.cpp:831
valarray< long > nRot_hi[N_ELEC]
Definition: h2_priv.h:610
const double FREQ_1EV
Definition: physconst.h:213
vector< TransitionList > AllTransitions
Definition: taulines.cpp:8
valarray< long > ipRot_H2_energy_sort
Definition: h2_priv.h:686
valarray< realnum > H2_X_source
Definition: h2_priv.h:671
void init(void)
t_hmi hmi
Definition: hmi.cpp:5
multi_arr< double, 3 > H2_Boltzmann
Definition: h2_priv.h:635
void H2_ReadDissprob(long int nelec)
Definition: mole_h2_io.cpp:895
void fixit(void)
Definition: service.cpp:991
STATIC double H2_vib_dist(int ipH2, double EH2, double DissocEnergy, double energy_wn)
const double ATOMIC_MASS_UNIT
Definition: physconst.h:88
multi_arr< realnum, 2 > H2_X_coll_rate
Definition: h2_priv.h:603
long int nVib_hi[N_ELEC]
Definition: h2_priv.h:608
STATIC bool lgRadiative(const TransitionList::iterator &tr)
realnum taumin
Definition: opacity.h:154
const double HPLANCK
Definition: physconst.h:103
multi_arr< double, 2 > H2_col_rate_in
Definition: h2_priv.h:648
const int ipCRDW
Definition: cddefines.h:298
multi_arr< realnum, 2 > H2_X_colden
Definition: h2_priv.h:657
const double PI
Definition: physconst.h:29
Definition: collision.h:17
multi_arr< int, 2 > H2_ipPhoto
Definition: h2_priv.h:647
#define EXIT_SUCCESS
Definition: cddefines.h:142
multi_arr< bool, 3 > H2_lgOrtho
Definition: h2_priv.h:640