cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mole_dissociate.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 #include "cddefines.h"
4 #include "h2_priv.h"
5 #include "hmi.h"
6 #include "rfield.h"
7 #include "ipoint.h"
8 #include "mole.h"
9 
11 
13 {
14  DEBUG_ENTRY( "diatomics::Read_Mol_Diss_cross_sections()" );
15 
16  FILE *ioDATA;
17 
18  char chPath[FILENAME_PATH_LENGTH_2],
19  chDirectory[FILENAME_PATH_LENGTH_2],
20  chLine[FILENAME_PATH_LENGTH_2];
21 
22  /* these can be generalized later for other molecules */
23  const int ipNUM_FILES = 1;
24 
25  char chFileNames[ipNUM_FILES][17] =
26  {"cont_diss.dat"} ;
27 
28  // these cross sections are not meaningful without big H2 enabled.
29  ASSERT( lgEnabled );
30 
31  // for the summed-over-final-state rates, allocate space for all states in model.
32  // Will be zero-filled and overwritten with whatever data is available.
34  for( int iElecLo=0; iElecLo<n_elec_states; ++iElecLo )
35  {
36  Cont_Dissoc_Rate.reserve( iElecLo, nVib_hi[iElecLo]+1 );
37  for( int iVibLo=0; iVibLo<=nVib_hi[iElecLo]; ++iVibLo )
38  {
39  Cont_Dissoc_Rate.reserve( iElecLo, iVibLo, nRot_hi[iElecLo][iVibLo]+1 );
40  }
41  }
43 
44  /* drill down to the directory where H2_cont_diss.dat lives */
45 # ifdef _WIN32
46  strcpy( chDirectory, "h2\\" );
47 # else
48  strcpy( chDirectory, "h2/" );
49 # endif
50 
51  /* now open the data file */
52  strcpy( chPath, chDirectory );
53  strcat( chPath, chFileNames[0] );
54  ioDATA = open_data( chPath, "r" );
55 
56  Diss_Trans.clear();
57 
58  /* track number of datasets in file */
59  while( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) != NULL )
60  {
61  static bool skipData = false;
62  long ini=0, inf, iv, ij;
63 
64  /* ignore all lines that begin with a '#', unless they are telling us the next quantum numbers. If so,
65  * then read the quantum numbers and start a new dataset */
66  if(sizeof(chLine) >= 2 && chLine[0] == '#' && chLine[1] == '!' && chLine[4] == 'n' && chLine[5] =='e' )
67  {
68  sscanf(chLine,"#! nei=%li, nef=%li, vi= %li, ji= %li",&ini, &inf, &iv, &ij);
69  // skip data that is for levels beyond our model
70  if( ini > n_elec_states )
71  skipData = true;
72  else if( iv > nVib_hi[ini] )
73  skipData = true;
74  else if( ij > nRot_hi[ini][iv] )
75  skipData = true;
76  else
77  {
78  skipData = false;
79  diss_level Leveli = {ini, iv, ij};
80  diss_level Levelf = {inf, -1, -1};
81  diss_tran thisTran( Leveli, Levelf );
82  Diss_Trans.push_back( thisTran );
83  }
84  }
85 
86  if( skipData )
87  continue;
88 
89  /* if line does not begin with a '#', then they are numbers in the datset. Read in energy in
90  * wavenumbers and cross section in Angstroms ^2 */
91  if(chLine[0] != '#')
92  {
93  double energy, xsection;
94  const double AngSquared = 1e-16;
95  sscanf(chLine,"%lf,%lf",&energy, &xsection);
96 
97  /* convert energy in wavenumbers to Ryd */
98  Diss_Trans.back().energies.push_back( energy*WAVNRYD );
99 
100  /* convert cross section from Angstrom^2 to cm^2 by multiplying by 1e-16 */
101  Diss_Trans.back().xsections.push_back( xsection*AngSquared );
102  }
103  }
104 
105  fclose(ioDATA);
106  return;
107 }
108 
109 double diatomics::MolDissocOpacity( const diss_tran& tran, const double& Mol_Ene )
110 {
111  DEBUG_ENTRY( "diatomics::MolDissocOpacity()" );
112 
113  double cross_section = MolDissocCrossSection( tran, Mol_Ene ) *
114  states[ ipEnergySort[ tran.initial.n ][ tran.initial.v ][ tran.initial.j ] ].Pop();
115  return cross_section;
116 }
117 
118 double MolDissocCrossSection( const diss_tran& tran, const double& Mol_Ene )
119 {
120  DEBUG_ENTRY( "MolDissocCrossSection()" );
121 
122  double photodiss_cs = 0.;
123 
124  /* if energy is less than threshold, then set cross section is zero */
125  if (Mol_Ene < tran.energies[0])
126  photodiss_cs = 0.;
127  /* if energy is greater than the highest energy defined in Philip's data, set
128  * cross section to zero for now. This may need to be changed later */
129  else if(Mol_Ene > tran.energies.back())
130  photodiss_cs = tran.xsections.back()/sqrt(powi(Mol_Ene/tran.energies.back(),7));
131  /* If energy is in between high and low energy limits, do linear interpolation
132  * on Philip's data to compute cross section */
133  else
134  {
135  ASSERT( Mol_Ene > tran.energies[0] && Mol_Ene < tran.energies.back() );
136  photodiss_cs = linint(&tran.energies[0],
137  &tran.xsections[0],
138  tran.xsections.size(),
139  Mol_Ene);
140  }
141 
142  return photodiss_cs;
143 }
144 
146 {
147  DEBUG_ENTRY( "diatomics::Mol_Photo_Diss_Rates()" );
148 
149  /* Start Calculation of H2 continuum dissociation rate here */
150 
151  // these cross sections are not meaningful without big H2 enabled.
153 
154  /* Zero out dissociation rates */
158 
159  for_each( Diss_Trans.begin(), Diss_Trans.end(), GetDissociationRateCoeff );
160  for( vector< diss_tran >::const_iterator dt = Diss_Trans.begin(); dt != Diss_Trans.end(); ++dt )
161  {
162  double rate = (*this).GetDissociationRate( *dt );
163  // this is summed over final electron state, tran.rate_coeff is not (because it's used to conserve energy)
164  Cont_Dissoc_Rate[dt->initial.n][dt->initial.v][dt->initial.j] += dt->rate_coeff;
165  if( states[ ipEnergySort[dt->initial.n][dt->initial.v][dt->initial.j] ].energy().WN() > ENERGY_H2_STAR && hmi.lgLeiden_Keep_ipMH2s )
166  {
167  /* Add up total rate due to levels which are above arbitrarily defined
168  * H2* threshold. Call this dissociation rate of H2* */
169  Cont_Dissoc_Rate_H2s += rate;
170  }
171  else
172  {
173  /* Add up total rate due to levels which are below arbitrarily defined
174  * H2* threshold. Call this dissociation rate of H2g (H2 ground) */
175  Cont_Dissoc_Rate_H2g += rate;
176  }
177  }
178 
179  /* This has current units of cm-3 s-1. We want just the total rate coefficient for
180  * insertion into h_step. Therefore, divide rate by density of H2* and H2g to get rate
181  * coefficient for reaction */
184 
185  return;
186 }
187 
189 {
190  DEBUG_ENTRY( "GetDissociationRateCoeff()" );
191 
192  long index_min = ipoint( tran.energies[0] );
193  long index_max = ipoint( tran.energies.back() );
194  index_max = MIN2( index_max, rfield.nflux-1 );
195 
196  tran.rate_coeff = 0.;
197  for(long i = index_min; i <= index_max; ++i)
198  {
199  /* Find cross section at given n, v, j, and photon energy */
200  double photodiss_cs = MolDissocCrossSection( tran, rfield.anu(i) );
201 
202  /* Compute integral of cross section and photon energy -- rate coefficient */
203  tran.rate_coeff += photodiss_cs*( rfield.flux[0][i] + rfield.ConInterOut[i]+
204  rfield.outlin[0][i]+ rfield.outlin_noplot[i] );
205  }
206 }
207 
209 {
210  DEBUG_ENTRY( "diatomics::GetDissociationRate()" );
211 
212  long iElecLo = tran.initial.n;
213  long iVibLo = tran.initial.v;
214  long iRotLo = tran.initial.j;
215 
216  /* Compute rate, product of rate coefficient times density */
217  return states[ ipEnergySort[iElecLo][iVibLo][iRotLo] ].Pop() * tran.rate_coeff;
218 }
219 
221 {
222  DEBUG_ENTRY( "diatomics::Cont_Diss_Heat_Rate()" );
223 
224  /* 29 Jul 10 - NPA - this tells code to not compute detailed H2 dissociation heating rate
225  * if Stancil rate is not used. However, we also do not want to compute this rate if Stancil
226  * rate is on, but small H2 molecule is used. Insert logic hear to not use rate if
227  * small H2 atom is on */
228 
229  if( !mole_global.lgStancil || !lgEnabled )
230  return 0.;
231 
233 
234  double Cont_Dissoc_Heat_Rate = 0.0;
235  for( vector< diss_tran >::const_iterator dt = Diss_Trans.begin(); dt != Diss_Trans.end(); ++dt )
236  Cont_Dissoc_Heat_Rate += (*this).GetHeatRate( *dt );
237 
238  return Cont_Dissoc_Heat_Rate;
239 }
240 
241 double diatomics::GetHeatRate( const diss_tran& tran )
242 {
243  DEBUG_ENTRY( "diatomics::GetHeatRate()" );
244 
245  long index_min = ipoint( tran.energies[0] );
246  long index_max = ipoint( tran.energies.back() );
247  index_max = MIN2( index_max, rfield.nflux-1 );
248 
249  long iElecLo = tran.initial.n;
250  long iVibLo = tran.initial.v;
251  long iRotLo = tran.initial.j;
252  double rate = 0.;
253 
254  for( long i = index_min; i<= index_max; ++i )
255  {
256  /* Photon energy minus threshold (Cloudy convention) */
257  double energy = MAX2( 0., rfield.anu(i) - tran.energies[0] );
258 
259  /* The density of the current H2(v,J) level */
260  double density = states[ ipEnergySort[iElecLo][iVibLo][iRotLo] ].Pop();
261 
262  double photodiss_cs = MolDissocCrossSection( tran, rfield.anu(i) );
263  double Rate_Coeff = photodiss_cs*( rfield.flux[0][i] + rfield.ConInterOut[i]+
264  rfield.outlin[0][i]+ rfield.outlin_noplot[i] );
265 
266  /* The heating rate. This is the product of the H2(v,J) density, the dissociation rate,
267  * and the energy of the photon (minus threshold). Units are erg cm-3 s-1.
268  * Sum over all possible H2 levels and dissociation energies. */
269  rate += EN1RYD * energy * Rate_Coeff * density;
270  }
271 
272  return rate;
273 }
274 
t_mole_global mole_global
Definition: mole.cpp:7
bool lgStancil
Definition: mole.h:337
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:765
const double ENERGY_H2_STAR
Definition: h2_priv.h:449
const int FILENAME_PATH_LENGTH_2
Definition: cddefines.h:296
long int n_elec_states
Definition: h2_priv.h:416
realnum ** flux
Definition: rfield.h:68
bool lgLeiden_Keep_ipMH2s
Definition: hmi.h:219
realnum * outlin_noplot
Definition: rfield.h:189
double Cont_Dissoc_Rate_H2g
Definition: h2_priv.h:285
realnum ** outlin
Definition: rfield.h:189
double H2_den_g
Definition: h2_priv.h:543
#define MIN2(a, b)
Definition: cddefines.h:803
double anu(size_t i) const
Definition: mesh.h:120
vector< diss_tran > Diss_Trans
Definition: h2_priv.h:432
multi_arr< double, 3 > Cont_Dissoc_Rate
Definition: h2_priv.h:286
long n
Definition: h2_priv.h:41
multi_arr< long int, 3 > ipEnergySort
Definition: h2_priv.h:551
long ipoint(double energy_ryd)
Definition: cont_ipoint.cpp:15
vector< double > energies
Definition: h2_priv.h:56
double energy(const genericState &gs)
#define STATIC
Definition: cddefines.h:118
bool lgEnabled
Definition: h2_priv.h:352
double H2_den_s
Definition: h2_priv.h:543
void Mol_Photo_Diss_Rates(void)
t_rfield rfield
Definition: rfield.cpp:9
realnum * ConInterOut
Definition: rfield.h:154
double MolDissocOpacity(const diss_tran &tran, const double &Mol_Ene)
double powi(double, long int)
Definition: service.cpp:594
long v
Definition: h2_priv.h:41
void Read_Mol_Diss_cross_sections(void)
double GetHeatRate(const diss_tran &tran)
#define ASSERT(exp)
Definition: cddefines.h:613
double density(const genericState &gs)
void reserve(size_type i1)
qList states
Definition: h2_priv.h:429
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
double Cont_Dissoc_Rate_H2s
Definition: h2_priv.h:284
double linint(const double x[], const double y[], long n, double xval)
STATIC double cross_section(double EgammaRyd, double EthRyd, long nelem, long n, long l, long s)
#define MAX2(a, b)
Definition: cddefines.h:824
valarray< long > nRot_hi[N_ELEC]
Definition: h2_priv.h:477
sys_float SDIV(sys_float x)
Definition: cddefines.h:1002
STATIC void GetDissociationRateCoeff(diss_tran &tran)
char * read_whole_line(char *chLine, int nChar, FILE *ioIN)
Definition: service.cpp:70
double rate_coeff
Definition: h2_priv.h:58
long j
Definition: h2_priv.h:41
t_hmi hmi
Definition: hmi.cpp:5
double MolDissocCrossSection(const diss_tran &tran, const double &Mol_Ene)
long int nflux
Definition: rfield.h:46
double GetDissociationRate(const diss_tran &tran)
long int nVib_hi[N_ELEC]
Definition: h2_priv.h:475
vector< double > xsections
Definition: h2_priv.h:57
diss_level initial
Definition: h2_priv.h:54
double Cont_Diss_Heat_Rate(void)