cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mole_reactions.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2017 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 #include "cdstd.h"
4 #include "cddefines.h"
5 #include "prt.h"
6 #include "version.h"
7 #include "hmi.h"
8 #include "conv.h"
9 #include "thermal.h"
10 #include "grainvar.h"
11 #include "ionbal.h"
12 #include "opacity.h"
13 #include "radius.h"
14 #include "atmdat.h"
15 #include "trace.h"
16 #include "deuterium.h"
17 #include "grains.h"
18 #include "mole_priv.h"
19 #include "gammas.h"
20 #include "mole.h"
21 #include "freebound.h"
22 #include "dense.h"
23 
24 /*
25  * HOWTO:- add a reaction to the new CO network, as at 2006 December 18.
26  *
27  * add a line of the form
28  * O,C2=>CO,C:hmrate:SCALE:B:C # Data source
29  * to the relevant data file for the new reaction. The first component is
30  * the chemical reaction, the second is a string naming the function which
31  * is used to evaluate the rate coefficients.
32  *
33  * SCALE is an overall constant by which the reaction rate is scaled,
34  * the remaining arguments constants used by this function.
35  *
36  * If all the species have previously been defined, and the parser in
37  * mole_co_etc.c can understand the reaction string, then that's it
38  * (unless the rate function is of a different form to those already
39  * defined).
40  *
41  * The sources and sinks to other networks will need to be defined,
42  * as this hasn't been made generic yet.
43  *
44  */
45 
46 enum {UDFA = 0}; /* UDFA = 1 for: make UDFA comparison and stop */
47 
48 STATIC void newreact(const char label[], const char fun[], double a, double b, double c);
49 STATIC long parse_reaction( count_ptr<mole_reaction>& rate, const char label[] );
50 STATIC string canonicalize_reaction_label( const char label[] );
54 /* run through all reactions and report which ones do not have a reverse reaction */
56 STATIC double mole_get_equilibrium_condition( const char buf[] );
57 STATIC double mole_get_equilibrium_condition( const mole_reaction* const rate );
58 STATIC double mole_partition_function( const molecule* const sp);
59 STATIC void mole_generate_isotopologue_reactions( string atom_old, string atom_new );
60 
61 STATIC double sticking_probability_H_func( double T_gas, double T_grain );
62 // Calculate sticking probability of H on grains according to Hollenback and McKee 1979.
63 STATIC double sticking_probability_H_HM79( double T_gas, double T_grain );
64 
65 /* Save PBM of network coupling matrix fill */
66 STATIC void plot_sparsity(void);
67 
68 #ifndef NDEBUG
69 /* Check invariants for defined reaction (species and charge totals) */
71 #endif
72 
73 /* Functions to read UDFA database and compare results with Cloudy's internal reaction set */
74 STATIC void read_data(const char file[], void (*parse)(char *s));
75 STATIC void parse_base(char *s);
76 STATIC void parse_udfa(char *s);
78 
79 /* Nick Abel, 06 Nov 27 states:
80  "In all the crnu reactions, the factor of two is the albedo factor 1/(1-albedo)."
81  Can this be obtained from the grain physics? */
82 static realnum albedo = 0.5;
83 
84 
85 namespace {
86 /* Define ratefunc type to make specification of newfunc and findfunc clearer */
87  typedef count_ptr<mole_reaction> ratefunc;
88  template<class T> void newfunc()
89  {
90  ratefunc fun = count_ptr<mole_reaction>(new T);
91  ASSERT( mole_priv::functab.find(fun->name()) == mole_priv::functab.end() );
92  mole_priv::functab[fun->name()] = fun;
93  }
94  ratefunc findfunc(const char name[]);
95 
96 /* The functions which define the reaction rates -- must all have same template */
97  class mole_reaction_hmrate;
98  double hmrate(const mole_reaction *rate);
99  class mole_reaction_th85rate;
100  double th85rate(const mole_reaction *rate);
101  class mole_reaction_crnurate_noalbedo;
102  double crnurate_noalbedo(const mole_reaction *rate);
103 /* >>chng 07 Dec 11, add photodesorption of molecules frozen on grain surfaces */
104 /* >>chng 07 Dec 11, add grain surface reactions to chemistry. Now two molecules adsorbed on a grain can interact to form a new molecule */
105  class mole_reaction_grn_react;
106  double grn_react(const mole_reaction *rate);
107  class mole_reaction_h2_collh_excit;
108  double h2_collh_excit(const mole_reaction *rate);
109  class mole_reaction_h2_collh2_excit;
110  double h2_collh2_excit(const mole_reaction *rate);
111  class mole_reaction_h2_collh_deexc;
112  double h2_collh_deexc(const mole_reaction *rate);
113  class mole_reaction_h2_collh2_deexc;
114  double h2_collh2_deexc(const mole_reaction *rate);
115  class mole_reaction_rh2g_dis_h;
116  double rh2g_dis_h(const mole_reaction *rate);
117  class mole_reaction_rh2s_dis_h;
118  double rh2s_dis_h(const mole_reaction *rate);
119  class mole_reaction_rh2g_dis_h2;
120  double rh2g_dis_h2(const mole_reaction *rate);
121  class mole_reaction_rh2s_dis_h2;
122  double rh2s_dis_h2(const mole_reaction *rate);
123  class mole_reaction_rh2s_dis_h2_nodeexcit;
124  double rh2s_dis_h2_nodeexcit(const mole_reaction *rate);
125  class mole_reaction_bh2g_dis_h;
126  double bh2g_dis_h(const mole_reaction *rate);
127  class mole_reaction_bh2s_dis_h;
128  double bh2s_dis_h(const mole_reaction *rate);
129  class mole_reaction_bh2g_dis_h2;
130  double bh2g_dis_h2(const mole_reaction *rate);
131  class mole_reaction_hneut;
132  double hneut(const mole_reaction *rate);
133  class mole_reaction_cionhm;
134  double cionhm(const mole_reaction *rate);
135 }
136 
137 /*
138  * Functions to specify chemical rates -- note that the rate->a overall scale
139  * factor is applied in mole_update_rks
140  *
141  */
142 
143 #include "phycon.h"
144 #include "doppvel.h"
145 
146 namespace
147 {
148  class mole_reaction_null : public mole_reaction
149  {
150  typedef mole_reaction_null T;
151  public:
152  virtual T* Create() const {return new T;}
153  virtual const char* name() {return "null";}
154  double rk() const
155  {
156  ASSERT( false );
157  return 0.0;
158  }
159  };
160 }
161 
162 
163 /* Add in non-equilibrium chemistry. This is done by assuming
164  * that turbulence reduces the temperature barrier, thereby
165  * enhancing reaction rates for molecules such as CH+. The
166  * "effective temperature is defined according to
167  * >>refer Federman et al. 1996, MNRAS. L41-46 */
168 
169 namespace {
170 /* The effective temperature is defined as:
171  * T(effective) = T + (1/3)*reduced_mass*turbulent_velocity^2/BOLTZMANN_CONSTANT
172  */
173  STATIC double noneq_offset(const mole_reaction *rate)
174  {
175  /* This logic could be cached by using distinct rate functions in newreact */
176  int nreact, n;
177  bool lgFact;
178 
179  DEBUG_ENTRY( "noneq_offset()" );
180 
181  lgFact = false;
183  {
185  {
186  lgFact = true;
187  }
188  else
189  {
190  nreact = rate->nreactants;
191  for(n=0;n<nreact;n++)
192  {
193  if (rate->reactants[n]->charge != 0)
194  {
195  lgFact = true;
196  break;
197  }
198  }
199  }
200  }
201 
202  if( lgFact )
203  return 0.333f*POW2(DoppVel.TurbVel)/BOLTZMANN*rate->reduced_mass;
204  else
205  return 0.;
206  }
207  double hmrate(const mole_reaction *rate)
208  {
209  double te;
210 
211  DEBUG_ENTRY( "hmrate()" );
212 
213  te = phycon.te+noneq_offset(rate);
214 
215  if( rate->c < 0. )
216  ASSERT( -rate->c/te < 10. );
217 
218  double r = 1.;
219  if( rate->b != 0. )
220  r *= pow(te/300.,rate->b);
221  if( rate->c != 0. )
222  r *= exp(-rate->c/te);
223  return r;
224  }
225 
226  class mole_reaction_hmrate_exo : public mole_reaction
227  {
228  typedef mole_reaction_hmrate_exo T;
229  public:
230  virtual T* Create() const {return new T;}
231 
232  virtual const char* name() {return "hmrate_exo";}
233 
234  double rk() const
235  {
236  double te;
237 
238  DEBUG_ENTRY( "hmrate_exo()" );
239 
240  te = phycon.te+noneq_offset(this);
241 
242  if( this->c < 0. )
243  te = MIN2( te, -10. * this->c );
244 
245  return pow(te/300.,this->b)*exp(-te/this->c);
246  }
247  };
248 
249  class mole_reaction_hmrate : public mole_reaction
250  {
251  typedef mole_reaction_hmrate T;
252  public:
253  virtual T* Create() const {return new T;}
254  virtual const char* name() {return "hmrate";}
255  double rk() const
256  {
257  return hmrate(this);
258  }
259  };
260 
261  class mole_reaction_constrate : public mole_reaction
262  {
263  typedef mole_reaction_constrate T;
264  public:
265  virtual T* Create() const {return new T;}
266  virtual const char* name() {return "constrate";}
267  double rk() const
268  {
269  return 1.;
270  }
271  };
272 
273  /* hmi.UV_Cont_rel2_Habing_TH85_depth is field relative to Habing background, dimensionless */
274  /* >>chng 04 apr 01, move from TH85 to DB96, also correct leading coef to use
275  * UMIST database value */
276  /* CO_photo_dissoc_rate = 1.67e-10f*hmi.UV_Cont_rel2_Habing_TH85_depth;*/
277 
278  /* TRY MOVING PHOTORATES OUT OF LOOP */
279 
280  /* >>chng 02 jul 04 -- The following are dissociation rates for various molecular species
281  For right now we will calculate this rate by the standard form:
282  (alpha)*Go*exp(-Beta*AV)
283  when the command "set Leiden hack UMIST rates" is used. Otherwise we
284  will just let cloudy calculate the value of the UV radiation field */
285 }
286 #include "rfield.h"
287 namespace {
288  double th85rate(const mole_reaction *rate)
289  {
290  double rk;
291 
292  DEBUG_ENTRY( "th85rate()" );
293 
294  if (!mole_global.lgLeidenHack || rate->c == 0.0)
295  {
297  }
298  else
299  {
301  }
302 
303  return rk;
304  }
305  class mole_reaction_th85rate : public mole_reaction
306  {
307  typedef mole_reaction_th85rate T;
308  public:
309  virtual T* Create() const {return new T;}
310  virtual const char* name() {return "th85rate";}
311  double rk() const
312  {
313  return th85rate(this);
314  }
315  };
316 }
317 
318 #include "secondaries.h"
319 namespace {
320  /* >> chng aug 24, 05 NPA This is the cosmic ray ionization rate used in the molecular network.
321  * TH85 and the e-mail from Amiel Sternberg has each cosmic ray ionization rate as a
322  * leading coefficient multiplied by a scale factor.
323  * The leading coefficient is defined as the cosmic ray rate for H + CRPHOT = > H+
324  * + e- . For molecules in the heavy element molecular network, this scale
325  * factor is derived by taking the rate for:
326 
327  X + CRPHOT => Y + Z
328  and dividing it by the rate:
329  H + CRPHOTP => H+ + e-
330 
331  This scale factor is 2.17 for all cosmic ray reactions in this network
332  crnu_rate = secondaries.csupra[ipHYDROGEN][0];*/
333  double crnurate_noalbedo(const mole_reaction *)
334  {
335  return 2.17*secondaries.csupra[ipHYDROGEN][0];
336  }
337  class mole_reaction_crnurate_noalbedo : public mole_reaction
338  {
339  typedef mole_reaction_crnurate_noalbedo T;
340  public:
341  virtual T* Create() const {return new T;}
342 
343  virtual const char* name() {return "crnurate_noalbedo";}
344  double rk() const
345  {
346  return crnurate_noalbedo(this);
347  }
348  };
349 
350  class mole_reaction_crnurate : public mole_reaction
351  {
352  typedef mole_reaction_crnurate T;
353  public:
354  virtual T* Create() const {return new T;}
355  virtual const char* name() {return "crnurate";}
356  double rk() const
357  {
358  return crnurate_noalbedo(this)/(1.0-albedo);
359  }
360  };
361 }
362 #include "hextra.h"
363 namespace {
364 /* Can this be found directly from radiation field?? */
365  class mole_reaction_cryden_ov_bg : public mole_reaction
366  {
367  typedef mole_reaction_cryden_ov_bg T;
368  public:
369  virtual T* Create() const {return new T;}
370  virtual const char* name() {return "cryden_ov_bg";}
371  double rk() const
372  {
374  }
375  };
376 
377  class mole_reaction_co_lnu_c_o_lnu : public mole_reaction
378  {
379  typedef mole_reaction_co_lnu_c_o_lnu T;
380  public:
381  virtual T* Create() const {return new T;}
382  virtual const char* name() {return "co_lnu_c_o_lnu";}
383  double rk() const
384  {
385  double val = 0;
386  int ns, ion;
387  /* inner shell photoionization of CO, assume rates are same as K 1s and 2s
388  * shell of C and O */
389  /* >>chng 04 may 26, upper limit should be ns<2, had been ns<2 so picked up
390  * valence shell, which was incorrect */
391 
392  DEBUG_ENTRY( "co_lnu_c_o_lnu()" );
393 
394  for( ns=0; ns<2; ++ns )
395  {
396  ion = 0;
397  val += ionbal.PhotoRate_Shell[ipCARBON][ion][ns][0];
398  val += ionbal.PhotoRate_Shell[ipOXYGEN][ion][ns][0];
399  }
400 
401  return val;
402  }
403  };
404 
405  /******************************** Gas-Grain Chemistry**********************************/
406 
407  /* The Gas-Grain Chemistry rates are taken from:
408  >>refer Hasegawa, T. I. & Herbst, E. 1993, MNRAS, 261, 83
409 
410  So far only CO depletion onto grains is considered, however, this code can be generalized
411  if desired to other molecules, using the data in the above paper. There are three important reactions
412  to determine the abundance of a molecule on grain surfaces deep in molecular clouds. The
413  rate of accretion of molecule X onto grains is
414 
415  R(accretion) = PI*[grain_radius]^2*[thermal velocity]*[density_of_grains]
416 
417  Two processes remove molecule X from the grain surface, and that is thermal evaporation, due
418  to the heat of the grain, and cosmic ray deabsorption. The first of these rates come from the
419  above paper, and depends primarily on the dust temperature. The cosmic ray rate is a constant,
420  calculated in Hasegawa and Herbst.
421 
422  For each molecule desired, I have created a new species which is the density of that molecule
423  on the grain surface */
424 
425 
426  /* evaporation rate of molecule on grain is:
427 
428  k(evap) = [vibrational absorption frequency]*exp[-binding_energy/dust_temperature]
429 
430  The binding energies come from Hasegawa and Herbst, Table 4. The vibrational frequency comes from
431  equation 3 of >>refer Hasegawa, T. I., Herbst, E., & Leung, C. M. 1992, ApJSS, 82, 167
432 
433  [vibrational absorption frequency] =
434  SQRT[[2*number_of_sites_for_grain_absorption*binding_energy]/[PI^2*mass_of_molecule]]
435 
436  **********************************************************************************************/
437 
438  class mole_reaction_vib_evap : public mole_reaction
439  {
440  typedef mole_reaction_vib_evap T;
441  public:
442  virtual T* Create() const {return new T;}
443  virtual const char* name() {return "vib_evap";}
444  double rk() const
445  {
446  double binding_energy, exponent, vib_freq;
447 
448  DEBUG_ENTRY( "vib_evap()" );
449 
450  exponent = 0.0;
451 
452  binding_energy = this->b;
453  double bin_total=0.0;
454  for( size_t nd=0; nd < gv.bin.size() ; nd++ )
455  {
456  double bin_area = gv.bin[nd]->IntArea*gv.bin[nd]->cnv_H_pCM3;
457  exponent += exp(-binding_energy/gv.bin[nd]->tedust)*bin_area;
458  bin_total += bin_area;
459  }
460  exponent /= bin_total;
461  const double surface_density_of_sites = 1.5e15;
462 
463  /* >> chng 07 dec 08 rjrw -- add 0.3*BOLTZMANN factor from Hasegawa & Herbst */
464  vib_freq = sqrt(2*surface_density_of_sites*(0.3*BOLTZMANN)*binding_energy/(PI*PI*this->reactants[0]->mole_mass));
465  //fprintf(ioQQQ,"Vib freq %g for mass %g\n",vib_freq,rate->reactants[0]->mole_mass);
466 
467  /*>>chng 06 jan 11, NPA - In some H+ regions the grain temperatures are so low
468  that molecular freeze out occurs. This should not happen, because the ices
469  should sublimate in such a harsh environment. Therefore, we introduce an
470  artificial sublimation rate to destroy ices. THIS IS NOT A PHYSICAL RATE!!!!
471  only a rate that gets the desired, realistic result */
472  /*>>chng 06 sep 03 rjrw -- include this in standard evaporation rate coeff (the artificial part is the sexp term) */
474  /* Rate comes from Table curve and assumes that rate is high (~1) in H+
475  * region and negligible ( < 1e-30) in molecular cloud - designed to stop
476  * freeze-out above 100 K */
477 
478  return vib_freq*exponent +sexp( 555.89/phycon.sqrte - 5.55 );
479  }
480  };
481 
482  class mole_reaction_grn_abs : public mole_reaction
483  {
484  typedef mole_reaction_grn_abs T;
485  public:
486  virtual T* Create() const {return new T;}
487  virtual const char* name() {return "grn_abs";}
488  double rk() const
489  {
490  double mass;
491 
492  DEBUG_ENTRY( "grn_abs()" );
493 
494  /* Can't rely on order, as it is standardized using mole_cmp */
495  if (this->reactants[0]->n_nuclei() != 0)
496  mass = this->reactants[0]->mole_mass;
497  else
498  mass = this->reactants[1]->mole_mass;
499 
500  return sqrt(8.*BOLTZMANN*phycon.te/(PI*mass));
501  }
502  };
503 
504  class mole_reaction_grn_react : public mole_reaction
505  {
506  typedef mole_reaction_grn_react T;
507  public:
508  virtual T* Create() const {return new T;}
509  virtual const char* name() {return "grn_react";}
510  double rk() const
511  {
512  return grn_react(this);
513  }
514  };
515  double grn_react(const mole_reaction *rate)
516  {
517  /* This function computes the formation of a new molecule on the surface of
518  * of a grain due to the interaction between two species on the grain surface.
519  * We already do this type of reaction for H + H --> H2, but now we are doing
520  * it for other species as well. The rate depends on:
521 
522  1) The ability of each species to move on the surface
523  2) The ability of each species to interact and form a new molecule
524  3) The ability of each species to not evaporate away before interacting
525 
526  * The variable "number_of_sites" tells us how many sites there are which
527  * a molecule can attach itself to a grain. quant_barrier tells us the size
528  * of the quantum mechanical barrier between the two atoms. E_i and E_j
529  * relates to how well a species can stay on a grain of temperature T(dust). Finally,
530  * activ_barrier provides information on how well two atoms on the surface of a grain
531  * can actually interact to form a new molecule. The formalism below is taken from
532  * the Hasegawa, Herbst, and Leung paper from 1992 (referenced above)*/
533 
534  DEBUG_ENTRY( "grn_react()" );
535 
536  double quant_barrier = 1e-8; /* 1 Angstrom rectangular barrier */
537  double surface_density_of_sites = 1.5e15; /* number of sites available for adsorption */
538  fixit("rate->a is _always_ overall scaling factor");
539  ASSERT( rate->nreactants == 2 ); // this routine seems coded to only work with 2 reactants
540  double E_i = rate->reactants[0]->form_enthalpy; /* adsorption energy barrier (w/ grain) for first reactant */
541  double E_j = rate->reactants[1]->form_enthalpy; /* adsorption energy barrier (w/ grain)for second reactant */
542  double activ_barrier = rate->c; /* energy barrier between atoms on the grain */
543 
544  /* Each species has a vibrational frequency, dependent on its adsorption energy barrier */
545  fixit("Ordering of reactants may have switched");
546  double vib_freq_i = sqrt(2*surface_density_of_sites*(0.3*BOLTZMANN)*E_i/(PI*PI*rate->reactants[0]->mole_mass));
547  double vib_freq_j = sqrt(2*surface_density_of_sites*(0.3*BOLTZMANN)*E_j/(PI*PI*rate->reactants[1]->mole_mass));
548 
549  double Exp_i = 0.0;
550  double Exp_j = 0.0;
551  double dust_density = 0.0;
552 
553  /* Compute thermal evaporation terms along with total dust number density */
554  fixit("should there be an area weighting to exponential terms?");
555 
556  for( size_t nd=0; nd < gv.bin.size(); nd++ )
557  {
558  double bin_density = gv.bin[nd]->IntArea*gv.bin[nd]->cnv_H_pCM3;
559  Exp_i += exp(-E_i/gv.bin[nd]->tedust)*bin_density;
560  Exp_j += exp(-E_j/gv.bin[nd]->tedust)*bin_density;
561  dust_density += bin_density/(4*1e-10);
562  }
563 
564  ASSERT(fp_equal((realnum)dust_density,(realnum)(mole.grain_area/1e-10)));
565 
566  double total_sites = 4.*mole.grain_area*surface_density_of_sites;
567 
568  /* rates of migration on surface for each species */
569  double diff_i = vib_freq_i*Exp_i/total_sites;
570  double diff_j = vib_freq_j*Exp_j/total_sites;
571 
572  /* Exponential term models the likelyhood that two species, once they meet on the surface, will interact. Larger the barrier, the smaller
573  * the chance of a new molecule */
574  double scale = exp(-2*(quant_barrier/(HBAReV*EN1EV))*sqrt(2.0*rate->reduced_mass*0.3*BOLTZMANN*activ_barrier));
575 
576  /* Total Rate */
577  return scale*(diff_i + diff_j)/SDIV(dust_density);
578  }
579 
580  class mole_reaction_grn_photo : public mole_reaction
581  {
582  typedef mole_reaction_grn_photo T;
583  public:
584  virtual T* Create() const {return new T;}
585  virtual const char* name() {return "grn_photo";}
586  double rk() const
587  {
588  /* This function models the rate at which UV photons remove
589  * molecules adsorbed on the surface of grains, using the treatment given in:
590  * >>refer Bergin, E. A., Langer, W. D., & Goldsmith, P. F. 1995, ApJ, 441, 222
591  * The following treatment uses their equation 3 */
592 
593  DEBUG_ENTRY( "grn_photo()" );
594 
595  /* This is the number of molecules removed from the grain per
596  * incident photon use same value of 1e-4 as used in Bergin, include
597  * conversion to radiation field units to get the dimensions right
598  * (cf the d'Hendercourt reference in Bergin et al) */
599 
600  fixit("grainn photoionization");
601  // 2e-15 is mean adsorbed species cross section, from
602  // >>refer Greenberg, L. T., 1973, IAUS, 52, 413
603  // 1.232e7f * 1.71f is from DB96 referred to below
604  // will be multiplied by yield factor (~1e-4) to get overall photodesorption rate
605  return 2e-15 * hmi.UV_Cont_rel2_Draine_DB96_depth *(1.232e7f * 1.71f);
606  }
607  };
608 }
609 #include "rt_escprob.h"
610 namespace {
611  class mole_reaction_th85rate_co : public mole_reaction
612  {
613  typedef mole_reaction_th85rate_co T;
614  public:
615  virtual T* Create() const {return new T;}
616 
617  virtual const char* name() {return "th85rate_co";}
618 
619  double rk() const
620  {
621  double esc_co, column;
622  /******************************************************************************************
623  * First define the rate, which is of the form:
624  *
625  * R = (Ro)*(Go*exp(-3.2Av))*Beta(tau(CO))
626  *
627  * where:
628  *
629  * Ro = 1.67*e-10
630  * (Go*exp(-3.2Av)) = hmi.UV_Cont_rel2_Habing_TH85_depth
631  * tauCO = 4.4e-15 * findspecies("CO")->column / (DopplerWidth/1e5) /
632  * (1. + phycon.sqrte*0.6019);
633  * tauC = 1.6*e17*N(C)
634  * Beta(tau(CO)) = esca0k2(esc_co)
635  ********************************************************************************************/
636  /* eqn 12 of
637  * >>refer CO dissoc Hollenbach, D.J., Takahashi, T., & Tielens, A. 1991, ApJ, 377, 192
638  * based on
639  * >>refer CO dissoc Black, J.H., & van Dishoeck, E.F. 1988, ApJ, 334, 771 */
640 
641  if (this->reactants[0]->n_nuclei() != 0)
642  column = mole.species[ this->reactants[0]->index ].column;
643  else
644  column = mole.species[ this->reactants[1]->index ].column;
645 
646  esc_co = 4.4e-15 * column /
647  /* the line width in km/s */
649  /* this term accounts for populations within ground elec state */
650  (1. + phycon.sqrte*0.6019);
651  return esca0k2(esc_co)*th85rate(this);
652  }
653  };
654 
655  class mole_reaction_oh_c2h2_co_ch3 : public mole_reaction
656  {
657  typedef mole_reaction_oh_c2h2_co_ch3 T;
658  public:
659  virtual T* Create() const {return new T;}
660  virtual const char* name() {return "oh_c2h2_co_ch3";}
661  double rk() const
662  {
663  /* This rate will blow up if the temperature gets too low, therefore
664  * set this rate for T < 500 equal to the rate at 500 K */
665  if(phycon.te > 500)
666  {
667  return hmrate(this);
668  }
669  else
670  {
671  return 6.3E-18;
672  }
673  }
674  };
675 
676 
677  class mole_reaction_h_hnc_hcn_h : public mole_reaction
678  {
679  typedef mole_reaction_h_hnc_hcn_h T;
680  public:
681  virtual T* Create() const {return new T;}
682 
683  virtual const char* name() {return "h_hnc_hcn_h";}
684  double rk() const
685  {
686  if(phycon.te > 100)
687  {
688  return hmrate(this);
689  }
690  else
691  {
692  return 1e-15;
693  }
694  }
695  };
696 }
697 #include "iso.h"
698 #include "h2.h"
699 double frac_H2star_hminus(void)
700 {
701  /* >>chng 03 sep 09, get ratio of excited to ground state H2 */
703  {
704  return hmi.H2star_forms_hminus /
706 
707  /* option print statement for above */
708  /* printf( " H2s frac h- %.3e f(H2g) %.3e\n",frac_H2star_hminus ,
709  hmi.H2_forms_hminus/SDIV(hmi.H2star_forms_hminus+hmi.H2_forms_hminus));*/
710  }
711  else
712  {
713  /* the large H2 molecule was not evaluated, so we can't use exact
714  * branching ratios. These are the distribution fractions for around 500K */
715  /*These depend on temperature and distribution function and the definition of ENERGY_H2_STAR.
716  So reset the values properly*/
717  /* >>chng 05 jul 13, TE, with the new definition of H2s these are both 1 */
718  /* >>chng 05 jul 31, activate above print, rest for current 0.5 ev defn */
719  return 1. - 4.938e-6;
720  }
721 }
722 
723 namespace {
724  double frac_H2star_grains(void)
725  {
726  /* >>chng 03 sep 09, get ratio of excited to ground state H2 */
728  {
729  return hmi.H2star_forms_grains /
731 
732  /* option print statement for above */
733  /*printf( "DEBUG H2s frac grain %.3e f(H2g) %.3e ",frac_H2star_grains ,
734  hmi.H2_forms_grains/SDIV(hmi.H2star_forms_grains+hmi.H2_forms_grains) ); */
735  }
736  else
737  {
738  /* the large H2 molecule was not evaluated, so we can't use exact
739  * branching ratios. These are the distribution fractions for around 500K */
740  /*These depend on temperature and distribution function and the definition of ENERGY_H2_STAR.
741  So reset the values properly*/
742  /* >>chng 05 jul 13, TE, with the new definition of H2s these are both 1 */
743  /* >>chng 05 jul 31, activate above print, rest for current 0.5 ev defn */
744  return 0.9416;
745  }
746  }
747 
748  class mole_reaction_h2ph3p : public mole_reaction
749  {
750  typedef mole_reaction_h2ph3p T;
751  public:
752  virtual T* Create() const {return new T;}
753  virtual const char* name() {return "h2ph3p";}
754  double rk() const
755  {
756  /* H2 + H2+ => H + H3+ */
761  return 1.40e-9*(1. - sexp(9940./phycon.te));
762  else
763  return 2.08e-9;
764  }
765  };
766 }
767 
768 
769 namespace {
770  class mole_reaction_hopexch : public mole_reaction
771  {
772  typedef mole_reaction_hopexch T;
773  public:
774  virtual T* Create() const {return new T;}
775  virtual const char* name() {return "hopexch";}
776  double rk() const
777  {
779  }
780  };
781 
782  class mole_reaction_hpoexch : public mole_reaction
783  {
784  typedef mole_reaction_hpoexch T;
785  public:
786  virtual T* Create() const {return new T;}
787  virtual const char* name() {return "hpoexch";}
788  double rk() const
789  {
791  }
792  };
793 
794  class mole_reaction_hmattach : public mole_reaction
795  {
796  typedef mole_reaction_hmattach T;
797  public:
798  virtual T* Create() const {return new T;}
799  virtual const char* name() {return "hmattach";}
800  double rk() const
801  {
803  }
804  };
805 
806  class mole_reaction_hmihph2p : public mole_reaction
807  {
808  typedef mole_reaction_hmihph2p T;
809  public:
810  virtual T* Create() const {return new T;}
811  virtual const char* name() {return "hmihph2p";}
812  double rk() const
813  {
814  /* H- + H+ => H2+ + e
815  * equation (H6) from
816  * >>refer H2 chemistry Galli,D., & Palla, F. 1998, A&A, 335, 403-420
817  * hmihph2p = 6.9e-9f*(Tg)^(-0.35) for Tg<=8000
818  * hmihph2p = 6.9e-9f*(Tg)^(-0.9) for Tg>=8000 */
819  if(phycon.te <= 7891.)
820  {
821  /*hmihph2p = 6.9e-9*pow(phycon.te , -0.35);*/
822  return 6.9e-9 / (phycon.te30 * phycon.te05);
823  }
824  else
825  {
826  /* >>chng 02 nov 18, had typo for leading coefficient here */
827  /*hmihph2p = 9.6e-7*pow(phycon.te , -0.9);*/
828  return 9.6e-7 / phycon.te90;
829  }
830  }
831  };
832 
833  class mole_reaction_hmphoto : public mole_reaction
834  {
835  typedef mole_reaction_hmphoto T;
836  public:
837  virtual T* Create() const {return new T;}
838  virtual const char* name() {return "hmphoto";}
839  double rk() const
840  {
841  return hmi.HMinus_photo_rate;
842  }
843  };
844 
845  double cionhm(const mole_reaction *)
846  {
847  /* collisional ionization of H-, rate from Janev, Langer et al.
848  * added factor hmi.exphmi for Boltzmann factor at low T
849  * Janev+ figure ends at 1e3 K */
850  if( phycon.te < 3074. )
851  {
852  return 1.46e-32*(powi(phycon.te,6))*phycon.sqrte*hmi.exphmi;
853  }
854  else if( phycon.te >= 3074. && phycon.te < 30000. )
855  {
856 
857  /* >>chng 03 mar 07, from above to below */
858  /*cionhm = 5.9e-19*phycon.te*phycon.te*phycon.sqrte*phycon.te03*
859  phycon.te01*phycon.te01;*/
860  return 5.9e-19*phycon.tesqrd*phycon.sqrte*phycon.te05;
861  }
862  else
863  {
864  return 1.54e-7;
865  }
866 
867  }
868  class mole_reaction_cionhm : public mole_reaction
869  {
870  typedef mole_reaction_cionhm T;
871  public:
872  virtual T* Create() const {return new T;}
873  virtual const char* name() {return "cionhm";}
874  double rk() const
875  {
876  return cionhm(this);
877  }
878  };
879 
880  double assoc_detach(void)
881  {
882  /* form molecular hydrogen from H minus,
883  * associative detachment: H- + H => H2 + E */
884  /* make H2 from H-
885  * associative detachment; H- + H => H2:
886  * >>referold H2 rates Browne & Dalgarno J PHys B 2, 885 */
887  /* rate coefficient from
888  * >>refer H2 form Launay, J.R., Le Dourneuf, M., & Zeippen, C.J.,
889  * >>refercon 1991, A&A, 252, 842-852*/
890  /* >>chng 02 oct 17, temp dependent fit to rate, updated reference,
891  * about 40% larger than before */
892  double y , x;
893  x = MAX2(10., phycon.te );
894  x = MIN2(1e4, x );
895  y=545969508.1323510+x*71239.23653059864;
896  return 1./y;
897  }
898 
899  class mole_reaction_c3bod : public mole_reaction
900  {
901  typedef mole_reaction_c3bod T;
902  public:
903  virtual T* Create() const {return new T;}
904  virtual const char* name() {return "c3bod";}
905  double rk() const
906  {
907  return cionhm(this)*hmi.rel_pop_LTE_Hmin;
908  }
909  };
910 
911  class mole_reaction_asdfg : public mole_reaction
912  {
913  typedef mole_reaction_asdfg T;
914  public:
915  virtual T* Create() const {return new T;}
916  virtual const char* name() {return "asdfg";}
917  double rk() const
918  {
919  return assoc_detach()*(1-frac_H2star_hminus());
920  }
921  };
922 
923  class mole_reaction_asdfs : public mole_reaction
924  {
925  typedef mole_reaction_asdfs T;
926  public:
927  virtual T* Create() const {return new T;}
928  virtual const char* name() {return "asdfs";}
929  double rk() const
930  {
931  return assoc_detach()*frac_H2star_hminus();
932  }
933  };
934 
935  class mole_reaction_asdbg : public mole_reaction
936  {
937  typedef mole_reaction_asdbg T;
938  public:
939  virtual T* Create() const {return new T;}
940  virtual const char* name() {return "asdbg";}
941  double rk() const
942  {
943  double ratio = mole_get_equilibrium_condition( this->label.c_str() );
944  return assoc_detach() * ratio * (1.-frac_H2star_hminus());
945  }
946  };
947 
948  class mole_reaction_asdbs : public mole_reaction
949  {
950  typedef mole_reaction_asdbs T;
951  public:
952  virtual T* Create() const {return new T;}
953  virtual const char* name() {return "asdbs";}
954  double rk() const
955  {
956  double ratio = mole_get_equilibrium_condition(this);
957  return assoc_detach() * ratio * frac_H2star_hminus();
958  }
959  };
960 
961  class mole_reaction_bhneut : public mole_reaction
962  {
963  typedef mole_reaction_bhneut T;
964  public:
965  virtual T* Create() const {return new T;}
966  virtual const char* name() {return "bhneut";}
967  double rk() const
968  {
969  if( phycon.te > 1000. && dense.xIonDense[ipHYDROGEN][0] > 0.0 )
970  {
971  double ratio = mole_get_equilibrium_condition(this);
972  /* HBN(3,1) is defined; when <HydTempLimit then set to 1 */
973  /* mutual neut, mostly into n=3; rates from Janev et al
974  * H + H(n=3) => H- + H+ */
976  /* this is the back reaction, forming H- from Ho */
977  return (hneut(this)*ratio*
978  (iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH3s].Pop()+
979  iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH3p].Pop()+
980  iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH3d].Pop()) /
982  }
983  else
984  {
985  return 0.;
986  }
987  }
988  };
989 
990  double hneut(const mole_reaction *)
991  {
992  if( phycon.te < 14125. )
993  {
994  /* the fit in Lepp et al. explodes at high temperature,
995  * Te = 14,125 is the temp where the rates reaches its lowest value */
996  return 1.4e-7*pow(phycon.te/300,-0.487)*exp(phycon.te/29300);
997  }
998  else
999  {
1000  return 3.4738192887404660e-008;
1001  }
1002  }
1003  class mole_reaction_hneut : public mole_reaction
1004  {
1005  typedef mole_reaction_hneut T;
1006  public:
1007  virtual T* Create() const {return new T;}
1008  virtual const char* name() {return "hneut";}
1009 
1010  double rk() const
1011  {
1012  return hneut(this);
1013  }
1014  };
1015 
1016  class mole_reaction_h2_spon_diss : public mole_reaction
1017  {
1018  typedef mole_reaction_h2_spon_diss T;
1019  public:
1020  virtual T* Create() const {return new T;}
1021  virtual const char* name() {return "h2_spon_diss";}
1022  double rk() const
1023  {
1024  return h2.spon_diss_tot;
1025  }
1026  };
1027 
1028  class mole_reaction_h2_ind_rad_diss : public mole_reaction
1029  {
1030  typedef mole_reaction_h2_ind_rad_diss T;
1031  public:
1032  virtual T* Create() const {return new T;}
1033  virtual const char* name() {return "h2_ind_rad_diss";}
1034  double rk() const
1035  {
1036  return 0.;
1037  }
1038  };
1039 
1040  double grnh2tot(const mole_reaction *)
1041  {
1042  DEBUG_ENTRY( "grnh2tot()" );
1043  fixit("Remove factor of dense.gas_phase[ipHYDROGEN] factor from"
1044  "derivation of rate_h2_form_grains_used to avoid"
1045  "division here");
1048  else
1049  return 0.;
1050  }
1051  class mole_reaction_grnh2tot : public mole_reaction
1052  {
1053  public:
1054  virtual const char* name() {return "grnh2tot";}
1055  double rk() const
1056  {
1057  return grnh2tot(this);
1058  }
1059  };
1060 
1061  class mole_reaction_grnh2 : public mole_reaction
1062  {
1063  typedef mole_reaction_grnh2 T;
1064  public:
1065  virtual T* Create() const {return new T;}
1066  virtual const char* name() {return "grnh2";}
1067  double rk() const
1068  {
1069  return grnh2tot(this)*(1.-frac_H2star_grains());
1070  }
1071  };
1072 
1073  class mole_reaction_grnh2s : public mole_reaction
1074  {
1075  typedef mole_reaction_grnh2s T;
1076  public:
1077  virtual T* Create() const {return new T;}
1078  virtual const char* name() {return "grnh2s";}
1079  double rk() const
1080  {
1081  return grnh2tot(this)*frac_H2star_grains();
1082  }
1083  };
1084 
1085  class mole_reaction_radasc : public mole_reaction
1086  {
1087  typedef mole_reaction_radasc T;
1088  public:
1089  virtual T* Create() const {return new T;}
1090  virtual const char* name() {return "radasc";}
1091  double rk() const
1092  {
1093  // excited atom radiative association,
1094  // H(n=2) + H(n=1) => H2 + hnu
1095 
1096  if( dense.xIonDense[ipHYDROGEN][0] > 0. )
1097  {
1098  return hmrate(this) *
1100  (iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2p].Pop() + iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2s].Pop())/
1101  dense.xIonDense[ipHYDROGEN][0];
1102  }
1103  else
1104  return 0.;
1105  }
1106  };
1107 
1108  class mole_reaction_assoc_ion : public mole_reaction
1109  {
1110  typedef mole_reaction_assoc_ion T;
1111  public:
1112  virtual T* Create() const {return new T;}
1113  virtual const char* name() {return "assoc_ion";}
1114  double rk() const
1115  {
1116  // excited atom associative ionization,
1117  // H(n=2) + H(n=1) => H2+ + e-
1118  if( dense.xIonDense[ipHYDROGEN][0] > 0. )
1119  {
1120  return hmrate(this) *
1122  (iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2p].Pop() + iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH2s].Pop())/
1123  dense.xIonDense[ipHYDROGEN][0];
1124  }
1125  else
1126  return 0.;
1127  }
1128  };
1129 
1130 
1131  double rh2g_dis_h(const mole_reaction *)
1132  {
1134  {
1135  return h2.Average_collH_dissoc_g;
1136  }
1137  else
1138  {
1139  double corr = MIN2(6.,14.44-phycon.alogte*3.08);
1140 
1141  if(corr > 0.)
1142  corr = exp10(corr*findspecieslocal("H")->den/(findspecieslocal("H")->den+1.6e4));
1143  else
1144  corr = 1.;
1145  /* must kill H- when UMIST is in place since they do not consider it */
1146  return 1.55e-8/phycon.sqrte*sexp(65107./phycon.te)* corr;
1147  }
1148  }
1149  class mole_reaction_rh2g_dis_h : public mole_reaction
1150  {
1151  typedef mole_reaction_rh2g_dis_h T;
1152  public:
1153  virtual T* Create() const {return new T;}
1154  virtual const char* name() {return "rh2g_dis_h";}
1155  double rk() const
1156  {
1157  return rh2g_dis_h(this);
1158  }
1159  };
1160 
1161  double rh2s_dis_h(const mole_reaction *rate)
1162  {
1163  DEBUG_ENTRY( "rh2s_dis_h()" );
1165  {
1166  return h2.Average_collH_dissoc_s;
1167  }
1168  else
1169  {
1170  if( ! fp_equal( rate->a, 1. ) )
1171  {
1172  fprintf( ioQQQ, "invalid parameter for rh2s_dis_h\n" );
1174  }
1175  return hmrate4(4.67e-7,-1.,5.5e4,phycon.te);
1176  }
1177  }
1178  class mole_reaction_rh2s_dis_h : public mole_reaction
1179  {
1180  typedef mole_reaction_rh2s_dis_h T;
1181  public:
1182  virtual T* Create() const {return new T;}
1183  virtual const char* name() {return "rh2s_dis_h";}
1184  double rk() const
1185  {
1186  return rh2s_dis_h(this);
1187  }
1188  };
1189 
1190  double rh2g_dis_h2(const mole_reaction *rate)
1191  {
1192  DEBUG_ENTRY( "rh2g_dis_h2()" );
1194  {
1195  return h2.Average_collH2_dissoc_g;
1196  }
1197  else
1198  {
1199  /* >>refer H2 chemistry Palla, F., Salpeter, E.E., & Stahler, S.W., 1983, ApJ,271, 632-641 + detailed balance relation */
1200  if( ! fp_equal( rate->a, 1. ) )
1201  {
1202  fprintf( ioQQQ, "invalid parameter for rh2g_dis_h2\n" );
1204  }
1205  return hmrate4(5.5e-29*0.5/(SAHA*3.634e-5)*sqrt(300.),0.5,5.195e4,phycon.te);
1206  }
1207  }
1208  class mole_reaction_rh2g_dis_h2 : public mole_reaction
1209  {
1210  typedef mole_reaction_rh2g_dis_h2 T;
1211  public:
1212  virtual T* Create() const {return new T;}
1213  virtual const char* name() {return "rh2g_dis_h2";}
1214  double rk() const
1215  {
1216  return rh2g_dis_h2(this);
1217  }
1218  };
1219 
1220  double rh2s_dis_h2(const mole_reaction *rate)
1221  {
1222  DEBUG_ENTRY( "rh2s_dis_h2()" );
1224  {
1225  return h2.Average_collH2_dissoc_s;
1226  }
1227  else
1228  {
1229  if( ! fp_equal( rate->a, 1. ) )
1230  {
1231  fprintf( ioQQQ, "invalid parameter for rh2s_dis_h2\n" );
1233  }
1234  return hmrate4(1e-11,0.,0.,phycon.te);
1235  }
1236  }
1237  class mole_reaction_rh2s_dis_h2 : public mole_reaction
1238  {
1239  typedef mole_reaction_rh2s_dis_h2 T;
1240  public:
1241  virtual T* Create() const {return new T;}
1242  virtual const char* name() {return "rh2s_dis_h2";}
1243  double rk() const
1244  {
1245  return rh2s_dis_h2(this);
1246  }
1247  };
1248 
1249  double rh2s_dis_h2_nodeexcit(const mole_reaction *rate)
1250  {
1251  DEBUG_ENTRY( "rh2s_dis_h2_nodeexcit()" );
1253  {
1254  return h2.Average_collH2_dissoc_s;
1255  }
1256  else
1257  {
1258  if( ! fp_equal( rate->a, 1. ) )
1259  {
1260  fprintf( ioQQQ, "invalid parameter for rh2s_dis_h2_nodeexcit\n" );
1262  }
1263  return hmrate4(1e-11,0.,2.18e4,phycon.te);
1264  }
1265  }
1266  class mole_reaction_rh2s_dis_h2_nodeexcit : public mole_reaction
1267  {
1268  typedef mole_reaction_rh2s_dis_h2_nodeexcit T;
1269  public:
1270  virtual T* Create() const {return new T;}
1271  virtual const char* name() {return "rh2s_dis_h2_nodeexcit";}
1272  double rk() const
1273  {
1274  return rh2s_dis_h2_nodeexcit(this);
1275  }
1276  };
1277 
1278  double bh2g_dis_h(const mole_reaction *rate)
1279  {
1280  return rh2g_dis_h(rate)*hmi.rel_pop_LTE_H2g;
1281  }
1282  class mole_reaction_bh2g_dis_h : public mole_reaction
1283  {
1284  typedef mole_reaction_bh2g_dis_h T;
1285  public:
1286  virtual T* Create() const {return new T;}
1287  virtual const char* name() {return "bh2g_dis_h";}
1288  double rk() const
1289  {
1290  return bh2g_dis_h(this);
1291  }
1292  };
1293 
1294  double bh2s_dis_h(const mole_reaction *rate)
1295  {
1296  return rh2s_dis_h(rate)*hmi.rel_pop_LTE_H2s;
1297  }
1298  class mole_reaction_bh2s_dis_h : public mole_reaction
1299  {
1300  typedef mole_reaction_bh2s_dis_h T;
1301  public:
1302  virtual T* Create() const {return new T;}
1303  virtual const char* name() {return "bh2s_dis_h";}
1304  double rk() const
1305  {
1306  return bh2s_dis_h(this);
1307  }
1308  };
1309 
1310  double bh2g_dis_h2(const mole_reaction *rate)
1311  {
1312  return rh2g_dis_h2(rate)*hmi.rel_pop_LTE_H2g;
1313  }
1314  class mole_reaction_bh2g_dis_h2 : public mole_reaction
1315  {
1316  typedef mole_reaction_bh2g_dis_h2 T;
1317  public:
1318  virtual T* Create() const {return new T;}
1319  virtual const char* name() {return "bh2g_dis_h2";}
1320  double rk() const
1321  {
1322  return bh2g_dis_h2(this);
1323  }
1324  };
1325 
1326  class mole_reaction_bh2s_dis_h2 : public mole_reaction
1327  {
1328  typedef mole_reaction_bh2s_dis_h2 T;
1329  public:
1330  virtual T* Create() const {return new T;}
1331  virtual const char* name() {return "bh2s_dis_h2";}
1332  double rk() const
1333  {
1334  return rh2s_dis_h2(this)*hmi.rel_pop_LTE_H2s;
1335  }
1336  };
1337 
1338  class mole_reaction_h2photon : public mole_reaction
1339  {
1340  typedef mole_reaction_h2photon T;
1341  public:
1342  virtual T* Create() const {return new T;}
1343  virtual const char* name() {return "h2photon";}
1344  double rk() const
1345  {
1346  return h2.photoionize_rate;
1347  }
1348  };
1349 
1350  class mole_reaction_h2crphot : public mole_reaction
1351  {
1352  typedef mole_reaction_h2crphot T;
1353  public:
1354  virtual T* Create() const {return new T;}
1355  virtual const char* name() {return "h2crphot";}
1356  double rk() const
1357  {
1358  return secondaries.csupra[ipHYDROGEN][0]*2.02;
1359  }
1360  };
1361 
1362  class mole_reaction_h2crphh : public mole_reaction
1363  {
1364  typedef mole_reaction_h2crphh T;
1365  public:
1366  virtual T* Create() const {return new T;}
1367  virtual const char* name() {return "h2crphh";}
1368  double rk() const
1369  {
1371  {
1372  /* cosmic ray & secondary electron excitation to triplets
1373  * big molecule scale factor changed 3-> 10
1374  *>>chng 07 apr 08, from 3 to 10 to better capture results
1375  * of Dalgarno et al 99 */
1376  return secondaries.x12tot*10.;
1377  }
1378  else
1379  {
1380  /* the original TH85 approximation */
1381  return secondaries.x12tot*3.;
1382  }
1383  }
1384  };
1385 
1386  class mole_reaction_h2scrphh : public mole_reaction
1387  {
1388  typedef mole_reaction_h2scrphh T;
1389  public:
1390  virtual T* Create() const {return new T;}
1391  virtual const char* name() {return "h2scrphh";}
1392  double rk() const
1393  {
1395  {
1396  return secondaries.x12tot*10.;
1397  }
1398  else
1399  {
1400  return secondaries.x12tot*3.;
1401  }
1402  }
1403  };
1404 
1405  class mole_reaction_radath : public mole_reaction
1406  {
1407  typedef mole_reaction_radath T;
1408  public:
1409  virtual T* Create() const {return new T;}
1410  virtual const char* name() {return "radath";}
1411  double rk() const
1412  {
1413  return MAX2(0.,2.325*MIN2(5000.,phycon.te)-1375.)*1e-20;
1414  }
1415  };
1416 
1417  class mole_reaction_gamtwo : public mole_reaction
1418  {
1419  typedef mole_reaction_gamtwo T;
1420  public:
1421  virtual T* Create() const {return new T;}
1422  virtual const char* name() {return "gamtwo";}
1423  double rk() const
1424  {
1425  t_phoHeat dummyGrd, dummyExc;
1426  hmi.h2plus_exc_frac = dsexp( 10000./phycon.te );
1427  double fracGrd = MAX2( 0., 1. - hmi.h2plus_exc_frac );
1428  double coefGrd = GammaK(opac.ih2pnt[0],opac.ih2pnt[1],opac.ih2pof,1.,&dummyGrd);
1429  double coefExc = GammaK(opac.ih2pnt_ex[0],opac.ih2pnt_ex[1],opac.ih2pof_ex,1.,&dummyExc);
1430  hmi.h2plus_heatcoef = dummyGrd.HeatNet * fracGrd + dummyExc.HeatNet * hmi.h2plus_exc_frac;
1431  double coef = coefGrd * fracGrd + coefExc * hmi.h2plus_exc_frac;
1432  return coef;
1433  }
1434  };
1435 
1436  class mole_reaction_hlike_phot : public mole_reaction
1437  {
1438  typedef mole_reaction_hlike_phot T;
1439  public:
1440  virtual T* Create() const {return new T;}
1441  virtual const char* name() {return "hlike_phot";}
1442  double rk() const
1443  {
1444  /* photoionization by hard photons, crossection =2*HI (wild guess)
1445  * -- rjrw: where do they go???
1446  * -- H3+ + hv => H2+ + H+ + e, best guess (P. Stancil, priv comm) */
1447 
1448  // on first pass this has not been set, do it here, but only do it once.
1449  if( !conv.nTotalIoniz )
1451  return iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].gamnc;
1452  }
1453  };
1454 
1455  class mole_reaction_h2s_sp_decay : public mole_reaction
1456  {
1457  typedef mole_reaction_h2s_sp_decay T;
1458  public:
1459  virtual T* Create() const {return new T;}
1460  virtual const char* name() {return "h2s_sp_decay";}
1461  double rk() const
1462  {
1463  /* >>chng 05 jul 11, TE, rename to use in punch file*/
1464  /* >>chng 05 jul 9, GS, use average A calculated from Big H2 */
1466  {
1467  return h2.Average_A;
1468  }
1469  else
1470  {
1471  return 2e-7;
1472  }
1473  }
1474  };
1475 
1476  double h2_collh2_deexc(const mole_reaction *)
1477  {
1479  {
1480  return h2.Average_collH2_deexcit;
1481  }
1482  else
1483  {
1484  return ((1.4e-12*phycon.sqrte * sexp( 18100./(phycon.te + 1200.) ))/6.);
1485  }
1486  }
1487  class mole_reaction_h2_collh2_deexc : public mole_reaction
1488  {
1489  typedef mole_reaction_h2_collh2_deexc T;
1490  public:
1491  virtual T* Create() const {return new T;}
1492  virtual const char* name() {return "h2_collh2_deexc";}
1493  double rk() const
1494  {
1495  return h2_collh2_deexc(this);
1496  }
1497  };
1498 
1499  double h2_collh_deexc(const mole_reaction *)
1500  {
1502  {
1503  return h2.Average_collH_deexcit;
1504  }
1505  else
1506  {
1507  return ((1e-12*phycon.sqrte * sexp(1000./phycon.te ))/6.);
1508  }
1509  }
1510  class mole_reaction_h2_collh_deexc : public mole_reaction
1511  {
1512  typedef mole_reaction_h2_collh_deexc T;
1513  public:
1514  virtual T* Create() const {return new T;}
1515  virtual const char* name() {return "h2_collh_deexc";}
1516  double rk() const
1517  {
1518  return h2_collh_deexc(this);
1519  }
1520  };
1521 
1522  double h2_collh2_excit(const mole_reaction *rate)
1523  {
1524  /* >>chng 05 jul 10, GS, use average collisional rate calculated from Big H2 */
1526  {
1527  return h2.Average_collH2_excit;
1528  }
1529  else
1530  {
1531  return h2_collh2_deexc(rate)*sexp( 30172./phycon.te); /* deexc_htwo*Boltz_fac_H2_H2star */
1532  }
1533  }
1534  class mole_reaction_h2_collh2_excit : public mole_reaction
1535  {
1536  typedef mole_reaction_h2_collh2_excit T;
1537  public:
1538  virtual T* Create() const {return new T;}
1539  virtual const char* name() {return "h2_collh2_excit";}
1540  double rk() const
1541  {
1542  return h2_collh2_excit(this);
1543  }
1544  };
1545 
1546  double h2_collh_excit(const mole_reaction *rate)
1547  {
1548  /* >>chng 05 jul 10, GS, use average collisional rate calculated from Big H2 */
1550  {
1551  return h2.Average_collH_excit;
1552  }
1553  else
1554  {
1555  return h2_collh_deexc(rate)*sexp( 30172./phycon.te); /* deexc_hneut*Boltz_fac_H2_H2star */
1556  }
1557  }
1558  class mole_reaction_h2_collh_excit : public mole_reaction
1559  {
1560  typedef mole_reaction_h2_collh_excit T;
1561  public:
1562  virtual T* Create() const {return new T;}
1563  virtual const char* name() {return "h2_collh_excit";}
1564  double rk() const
1565  {
1566  return h2_collh_excit(this);
1567  }
1568  };
1569 
1570  class mole_reaction_h2gexcit : public mole_reaction
1571  {
1572  typedef mole_reaction_h2gexcit T;
1573  public:
1574  virtual T* Create() const {return new T;}
1575  virtual const char* name() {return "h2gexcit";}
1576  double rk() const
1577  {
1579  }
1580  };
1581 
1582  class mole_reaction_h2sdissoc : public mole_reaction
1583  {
1584  typedef mole_reaction_h2sdissoc T;
1585  public:
1586  virtual T* Create() const {return new T;}
1587  virtual const char* name() {return "h2sdissoc";};
1588  double rk() const
1589  {
1590  /* >>chng 03 sep 11, add this process */
1591  /* photo-destroy H2* by Solomon process at same rate as H2ground dissociation,
1592  see above eqn A12 in TH85 */
1593  /* >>chng 00 nov 25 factor of 0.1, assume pump is total, and 10% destroy H2 */
1594  /* >>chng 03 mar 07, had factor of 0.1 for branching ratio from H2** to H+H,
1595  * but branching is now already included */
1597  }
1598  };
1599 
1600  class mole_reaction_h2gdissoc : public mole_reaction
1601  {
1602  typedef mole_reaction_h2gdissoc T;
1603  public:
1604  virtual T* Create() const {return new T;}
1605  virtual const char* name() {return "h2gdissoc";}
1606  double rk() const
1607  {
1608  /* >>chng 03 sep 11, add this process */
1609  /* photo-destroy H2* by Solomon process at same rate as H2ground dissociation,
1610  see above eqn A12 in TH85 */
1611  /* >>chng 00 nov 25 factor of 0.1, assume pump is total, and 10% destroy H2 */
1612  /* >>chng 03 mar 07, had factor of 0.1 for branching ratio from H2** to H+H,
1613  * but branching is now already included */
1615  }
1616  };
1617 
1618  class mole_reaction_hd_photodissoc : public mole_reaction
1619  {
1620  typedef mole_reaction_hd_photodissoc T;
1621  public:
1622  virtual T* Create() const {return new T;}
1623  virtual const char* name() {return "hd_photodissoc";}
1624  double rk() const
1625  {
1627  }
1628  };
1629 }
1630 
1631 /*hmirat compute radiative association rate for H- */
1632 double hmirat(double te)
1633 {
1634  double hmirat_v;
1635 
1636  DEBUG_ENTRY( "hmirat()" );
1637 
1638  // Compare published literature:
1639  // >>refer H- form deJong 1972A+A....20..263D
1640  // >>refer H- form Dalgarno 1973ApJ...181...95D
1641  // >>refer H- form Rawlings 1988MNRAS.230..695R
1642 
1643  /* fits to radiative association rate coefficients */
1644  if( te < 31.62 )
1645  {
1646  hmirat_v = 8.934e-18*phycon.sqrte*phycon.te003*phycon.te001*
1647  phycon.te001;
1648  }
1649  else if( te < 90. )
1650  {
1651  hmirat_v = 5.159e-18*phycon.sqrte*phycon.te10*phycon.te03*
1653  }
1654  else if( te < 1200. )
1655  {
1656  hmirat_v = 2.042e-18*te/phycon.te10/phycon.te03;
1657  }
1658  else if( te < 3800. )
1659  {
1660  hmirat_v = 8.861e-18*phycon.te70/phycon.te03/phycon.te01*
1661  phycon.te003;
1662  }
1663  else if( te <= 1.4e4 )
1664  {
1665  /* following really only optimized up to 1e4 */
1666  hmirat_v = 8.204e-17*phycon.sqrte/phycon.te10/phycon.te01*
1667  phycon.te003;
1668  }
1669  else
1670  {
1671  /* >>chng 00 sep 28, add this branch */
1672  /* >>chng 14 mar 26, rate slightly discontinuous */
1673  hmirat_v = 5.70e-16*phycon.te20/phycon.te01;
1674  }
1675 
1676  return( hmirat_v );
1677 }
1678 STATIC void mole_h2_grain_form(void);
1679 
1681 STATIC void mole_h_reactions(void);
1682 
1683 
1684 namespace {
1685  class mole_reaction_gamheh : public mole_reaction
1686  {
1687  typedef mole_reaction_gamheh T;
1688  public:
1689  virtual T* Create() const {return new T;}
1690  virtual const char* name() {return "gamheh";}
1691  double rk() const
1692  {
1693  double retval = 0.;
1694  long int limit,
1695  i;
1696  /* photodissociation through 1.6->2.3 continuum */
1697 
1698  /* why is this in a look instead of GammaK?
1699  * to fix must set opacities into stack */
1700 
1701  limit = MIN2(hmi.iheh2-1 , rfield.nflux );
1702  for( i=hmi.iheh1-1; i < limit; i++ )
1703  {
1704  retval += rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i];
1705  }
1706  retval *= 4e-18;
1707 
1708  /* hard radiation */
1709  retval += 3.*iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].gamnc;
1710 
1711  return retval;
1712  }
1713  };
1714 
1715  enum {exclude, base, umisthack, federman, lithium, deuterium, ti, misc, in_code, generated};
1716  static int source;
1717 
1718 
1719  static bool lgReactInitialized = false;
1720 }
1721 
1722 void mole_create_react( void )
1723 {
1724  /* Should adaptively select reactions rather than list them explicitly here */
1725 
1726  /* prevent memory leaks */
1727  /* \todo this is a temporary fix for PR14. We should improve the overall design
1728  * of this code to prevent valid pointers being overwritten in a second call to mole_create_react */
1729  if( lgReactInitialized )
1730  return;
1731 
1732  lgReactInitialized = true;
1733 
1734  DEBUG_ENTRY( "mole_create_react()" );
1735 
1736  if (UDFA)
1737  read_data("rate05_feb17.csv",parse_udfa);
1738 
1739  /* Set up registry of rate functions -- could do something intelligent about
1740  * caching rate values by extending this API... */
1741  newfunc<mole_reaction_null>();
1742  {
1743  map<string,bool> canonical;
1744  for (map<string,bool>::iterator it=mole_global.offReactions.begin();
1745  it != mole_global.offReactions.end(); ++it)
1746  {
1747  canonical[canonicalize_reaction_label(it->first.c_str())] = true;
1748  }
1749  mole_global.offReactions = canonical;
1750  }
1751 
1752  newfunc<mole_reaction_hmrate>();
1753  newfunc<mole_reaction_hmrate_exo>();
1754  newfunc<mole_reaction_constrate>();
1755  newfunc<mole_reaction_th85rate>();
1756  newfunc<mole_reaction_crnurate>();
1757  newfunc<mole_reaction_crnurate_noalbedo>();
1758  newfunc<mole_reaction_co_lnu_c_o_lnu>();
1759  newfunc<mole_reaction_vib_evap>();
1760  newfunc<mole_reaction_th85rate_co>();
1761  newfunc<mole_reaction_grn_abs>();
1762  /* >chng 07 Dec 11, add grain surface chemical reactions */
1763  newfunc<mole_reaction_grn_react>();
1764  /* >>chng 07 Dec 10, add photodesorption of grain molecules */
1765  newfunc<mole_reaction_grn_photo>();
1766  newfunc<mole_reaction_oh_c2h2_co_ch3>();
1767  newfunc<mole_reaction_h_hnc_hcn_h>();
1768 
1769  newfunc<mole_reaction_gamheh>();
1770  newfunc<mole_reaction_hd_photodissoc>();
1771  newfunc<mole_reaction_h2gdissoc>();
1772  newfunc<mole_reaction_h2sdissoc>();
1773  newfunc<mole_reaction_h2gexcit>();
1774  newfunc<mole_reaction_h2_collh_excit>();
1775  newfunc<mole_reaction_h2_collh2_excit>();
1776  newfunc<mole_reaction_h2_collh_deexc>();
1777  newfunc<mole_reaction_h2_collh2_deexc>();
1778  newfunc<mole_reaction_h2s_sp_decay>();
1779  newfunc<mole_reaction_hlike_phot>();
1780  newfunc<mole_reaction_gamtwo>();
1781  newfunc<mole_reaction_h2ph3p>();
1782  newfunc<mole_reaction_radath>();
1783  newfunc<mole_reaction_cryden_ov_bg>();
1784  newfunc<mole_reaction_h2scrphh>();
1785  newfunc<mole_reaction_h2crphh>();
1786  newfunc<mole_reaction_h2photon>();
1787  newfunc<mole_reaction_h2crphot>();
1788  newfunc<mole_reaction_rh2g_dis_h>();
1789  newfunc<mole_reaction_rh2s_dis_h>();
1790  newfunc<mole_reaction_rh2g_dis_h2>();
1791  newfunc<mole_reaction_rh2s_dis_h2>();
1792  newfunc<mole_reaction_rh2s_dis_h2_nodeexcit>();
1793  newfunc<mole_reaction_bh2g_dis_h>();
1794  newfunc<mole_reaction_bh2s_dis_h>();
1795  newfunc<mole_reaction_bh2g_dis_h2>();
1796  newfunc<mole_reaction_bh2s_dis_h2>();
1797  newfunc<mole_reaction_radasc>();
1798  newfunc<mole_reaction_assoc_ion>();
1799  newfunc<mole_reaction_grnh2>();
1800  newfunc<mole_reaction_grnh2s>();
1801  newfunc<mole_reaction_h2_spon_diss>();
1802  newfunc<mole_reaction_h2_ind_rad_diss>();
1803  newfunc<mole_reaction_bhneut>();
1804  newfunc<mole_reaction_hneut>();
1805  newfunc<mole_reaction_asdbs>();
1806  newfunc<mole_reaction_asdbg>();
1807  newfunc<mole_reaction_asdfs>();
1808  newfunc<mole_reaction_asdfg>();
1809  newfunc<mole_reaction_c3bod>();
1810  newfunc<mole_reaction_cionhm>();
1811  newfunc<mole_reaction_hmphoto>();
1812  newfunc<mole_reaction_hmihph2p>();
1813  newfunc<mole_reaction_hmattach>();
1814  //newfunc<mole_reaction_hpoexch>();
1815  //newfunc<mole_reaction_hopexch>();
1816 
1817  source = base;
1818  read_data("mole_co_base.dat",parse_base);
1819  if (mole_global.lgFederman)
1820  {
1821  source = federman;
1822  read_data("mole_co_federman.dat",parse_base);
1823  }
1824  if (!mole_global.lgLeidenHack)
1825  {
1826  source = umisthack;
1827  read_data("mole_co_umisthack.dat",parse_base);
1828  }
1829 
1830  source = lithium;
1831  read_data("mole_lithium.dat",parse_base);
1832 
1833  source = deuterium;
1834  read_data("mole_deuterium.dat",parse_base);
1835 
1836 #if 0
1837  source = ti;
1838  read_data("mole_ti.dat",parse_base);
1839 #endif
1840 
1841  source = misc;
1842  read_data("mole_misc.dat",parse_base);
1843 
1844  /* Load null reaction to delete real rate from database */
1845  if (!mole_global.lgProtElim)
1846  {
1847  source = exclude;
1848  newreact("C+,OH=>CO,H+","hmrate",0.,0.,0.);
1849  }
1850 
1851  source = in_code;
1852 
1853  newreact("H,H,grn=>H2,grn","grnh2",1.,0.,0.);
1854  newreact("H,H,grn=>H2*,grn","grnh2s",1.,0.,0.);
1855  newreact("H-,PHOTON=>H,e-","hmphoto",1.,0.,0.);
1856 
1857  /* mutual neutralization with heavies, rate from Dalgarno and McCray
1858  * all charged ions contribute equally,
1859  * H- + A+ => H + A */
1860  fixit("this should be atom_list instead of unresolved_element_list, but we have not defined ionized species of all isotopes yet!!!");
1861  //for(vector<count_ptr<chem_atom> >::iterator atom=atom_list.begin(); atom != atom_list.end(); ++atom)
1862  for(ChemNuclideList::iterator atom=nuclide_list.begin(); atom != nuclide_list.end(); ++atom)
1863  {
1864  if( !(*atom)->lgHasLinkedIon() )
1865  continue;
1866  long nelem = (*atom)->el->Z-1;
1867  if( nelem >= ipHELIUM && dense.lgElmtOn[nelem] )
1868  {
1869  char react[32];
1870  sprintf(react,"H-,%s+=>H,%s", (*atom)->label().c_str(), (*atom)->label().c_str() );
1871  newreact(react,"hmrate",4e-6/sqrt(300.),-0.5,0.);
1872  }
1873  }
1874 
1875  newreact("H,e-=>H-,PHOTON","hmattach",1.,0.,0.);
1876  newreact("H-,H+=>H2+,e-","hmihph2p",1.,0.,0.);
1877  newreact("H-,e-=>H,e-,e-","cionhm",1.,0.,0.);
1878  newreact("H,e-,e-=>H-,e-","c3bod",1.,0.,0.);
1879  newreact("H,H-=>H2,e-","asdfg",1.,0.,0.);
1880  newreact("H,H-=>H2*,e-","asdfs",1.,0.,0.);
1881  newreact("H2,e-=>H,H-","asdbg",1.,0.,0.);
1882  newreact("H2*,e-=>H,H-","asdbs",1.,0.,0.);
1883  newreact("H-,H+=>H,H","hneut",1.,0.,0.);
1884  newreact("H,H=>H-,H+","bhneut",1.,0.,0.);
1885 
1887  {
1888  //newreact("H2*=>H,H,PHOTON","h2_spon_diss",1.,0.,0.);
1889  newreact("H2*,PHOTON=>H,H,PHOTON","h2_ind_rad_diss",1.,0.,0.);
1890  newreact("H,H2+=>H+,H2","hmrate",0.,0.,0.); // This process yields H2* plus, so if that species is tracked, the rate into H2 is zero.
1891  }
1892  else
1893  {
1894  //newreact("H2=>H,H,PHOTON","h2_spon_diss",1.,0.,0.);
1895  newreact("H2,PHOTON=>H,H,PHOTON","h2_ind_rad_diss",1.,0.,0.);
1896  newreact("H,H2+=>H+,H2","hmrate",6.4e-10f,0.,0.); /* this process populates v=4,no J information assume into J=0 -> H2s not H2g */
1897  }
1898 
1900  {
1901  newreact("H,H=>H2,PHOTON","radasc",3e-14,0.,0.);
1902  newreact("H,H=>H2+,e-","assoc_ion",3.27e-10,-0.35,17829.); /* >>refer H2 rates Rawlings J.M.C, Drew J.E, Barlow M. J., 1993, MNRAS 265, 968 */
1903  newreact("H2,H=>H,H,H","rh2g_dis_h",1.,0.,0.);
1904  newreact("H2,H2=>H,H,H2","rh2g_dis_h2",1.,0.,0.);
1905  newreact("H,H,H=>H2,H","bh2g_dis_h",1.,0.,0.); /* back rate, three body recombination, 2H + S => H_2 + S */
1906  newreact("H,H,H2=>H2,H2","bh2g_dis_h2",1.,0.,0.);
1907  //newreact("H,H,H2=>H2,H2","hmrate",5.5e-29/(8*300.),-1.,0.); /* >>refer H2 chemistry Palla, F., Salpeter, E.E., & Stahler, S.W., 1983, ApJ,271, 632-641 */
1908  newreact("H2,PHOTON=>H2+,e-","h2photon",1.,0.,0.);
1909  newreact("H2,CRPHOT=>H2+,e-","h2crphot",1.,0.,0.);
1910  newreact("H2*,PHOTON=>H2+,e-","h2photon",1.,0.,0.);
1911  newreact("H2*,CRPHOT=>H2+,e-","h2crphot",1.,0.,0.);
1912  newreact("H2,CRPHOT=>H,H","h2crphh",1.,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1913  newreact("H2,CRPHOT=>H+,H-","cryden_ov_bg",3.9e-21,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1914  newreact("H2*,CRPHOT=>H+,H-","cryden_ov_bg",3.9e-21,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1915  newreact("H2,CRPHOT=>H+,H,e-","cryden_ov_bg",2.2e-19,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1916  newreact("H2*,CRPHOT=>H+,H,e-","cryden_ov_bg",2.2e-19,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1917  newreact("H+,H=>H2+,PHOTON","radath",1.,0.,0.);
1918  newreact("H2+,PHOTON=>H,H+","gamtwo",1.,0.,0.);
1919  newreact("H2+,CRPHOT=>H,H+","hlike_phot",1.,0.,0.);
1920  /* >> chng 05 aug 05, NPA comment. This reaction is not in UMIST, for the case
1921  of hard photons. Turn if off for the comparison. */
1922  newreact("H3+,CRPHOT=>H2+,H+,e-","hlike_phot",2.,0.,0.);
1923  newreact("H,H+,e-=>H2+,e-","hmrate",2e-7 * SAHA * (4./(2.*1.)) * 3.634e-5 * pow(300.,-1.50),-1.50,0.);
1924  }
1925  else
1926  {
1927  newreact("H2,CRPHOT=>H2+,e-","hmrate",4.4e-17,0.,0.);
1928  newreact("H2,CRPHOT=>H,H+,e-","hmrate",1e-19,0.,0.);
1929  newreact("H2*,CRPHOT=>H,H+,e-","hmrate",1e-19,0.,0.);
1930  newreact("H2*,CRPHOT=>H2+,e-","hmrate",4.4e-17,0.,0.);
1931  newreact("H2,CRPHOT=>H,H","hmrate",5e-18,0.,0.);
1932  newreact("e-,H3+=>H2,H","hmrate",2.5e-8,-0.3,0.);
1933  newreact("e-,H3+=>H,H,H","hmrate",7.5e-8,-0.3,0.);
1934  newreact("H+,H=>H2+,PHOTON","hmrate",5.3e-19,1.85,0);
1935  /* H2+ + e=> H + H;
1936  * equation (6,table 4) from
1937  * >>refer H2 l Maloney et.al, 1996,ApJ, 466, 561 */
1938  newreact("H2+,e-=>H,H","hmrate",1.6e-8,-0.43,0.);
1939  newreact("H2+,PHOTON=>H,H+","th85rate",5.7e-10,0.,1.9);
1940  }
1941 
1942  newreact("H2*,CRPHOT=>H,H","h2scrphh",1.,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1943  newreact("H2,H2+=>H,H3+","h2ph3p",1.,0.,0.);
1944  newreact("H2*=>H2,PHOTON","h2s_sp_decay",1.,0.,0.);
1945  newreact("H2*,H2=>H2,H2","h2_collh2_deexc",1.,0.,0.);
1946  newreact("H2*,H=>H2,H","h2_collh_deexc",1.,0.,0.);
1947  newreact("H2,H2=>H2*,H2","h2_collh2_excit",1.,0.,0.);
1948  newreact("H2,H=>H2*,H","h2_collh_excit",1.,0.,0.);
1949 
1950  // collisional dissociation of H2*
1951  newreact("H2*,H=>H,H,H","rh2s_dis_h",1.,0.,0.);
1952  newreact("H2*,H2=>H2,H,H","rh2s_dis_h2",1.,0.,0.);
1953  newreact("H2*,H2*=>H2,H,H","rh2s_dis_h2",1.,0.,0.);
1954  newreact("H2*,H2*=>H2*,H,H","rh2s_dis_h2_nodeexcit",1.,0.,0.);
1955 
1956 #if 0
1957  // more collision dissociation of H2
1958  newreact("H2,He=>He,H,H","rh2g_dis_h",1.,0.,0.);
1959  newreact("H2,H+=>H+,H,H","rh2g_dis_h",1.,0.,0.);
1960  newreact("H2,H3+=>H3+,H,H","rh2g_dis_h",1.,0.,0.);
1961  newreact("H2,e-=>e-,H,H","rh2g_dis_h",1.,0.,0.);
1962  newreact("H2*,He=>He,H,H","rh2s_dis_h",1.,0.,0.);
1963  newreact("H2*,H+=>H+,H,H","rh2s_dis_h",1.,0.,0.);
1964  newreact("H2*,H3+=>H3+,H,H","rh2s_dis_h",1.,0.,0.);
1965  newreact("H2*,e-=>e-,H,H","rh2s_dis_h",1.,0.,0.);
1966 
1967  // back reactions
1968  newreact("He,H,H=>H2,He","bh2g_dis_h",1.,0.,0.);
1969  newreact("H+,H,H=>H2,H+","bh2g_dis_h",1.,0.,0.);
1970  newreact("H3+,H,H=>H2,H3+","bh2g_dis_h",1.,0.,0.);
1971  newreact("e-,H,H=>H2,e-","bh2g_dis_h",1.,0.,0.);
1972  newreact("H,H,H=>H2*,H","bh2s_dis_h",1.,0.,0.);
1973  newreact("H2,H,H=>H2*,H2","bh2s_dis_h2",1.,0.,0.);
1974  newreact("H2,H,H=>H2*,H2*","bh2s_dis_h2",1.,0.,0.);
1975  newreact("H2*,H,H=>H2*,H2*","bh2s_dis_h2",1.,0.,0.);
1976  newreact("He,H,H=>H2*,He","bh2s_dis_h",1.,0.,0.);
1977  newreact("H+,H,H=>H2*,H+","bh2s_dis_h",1.,0.,0.);
1978  newreact("H3+,H,H=>H2*,H3+","bh2s_dis_h",1.,0.,0.);
1979  newreact("e-,H,H=>H2*,e-","bh2s_dis_h",1.,0.,0.);
1980 #endif
1981 
1982  newreact("H2,PHOTON=>H2*","h2gexcit",1.,0.,0.);
1983  newreact("H2*,PHOTON=>H,H","h2sdissoc",1.,0.,0.);
1984  newreact("H2,PHOTON=>H,H","h2gdissoc",1.,0.,0.);
1985  newreact("HeH+,PHOTON=>H,He+","gamheh",1.,0.,0.);
1986 
1987  if(0)
1988  {
1989  // grain surface reactions
1990  newreact("OHgrn,Hgrn=>H2Ogrn","grn_react",1.,0.,0.);
1991  }
1992 
1993  if (UDFA)
1994  {
1995  fprintf(stderr,"Finished testing against UDFA database\n");
1997  }
1998 
1999  if (0)
2000  plot_sparsity();
2001 
2002  source = generated;
2003 
2005 
2006  if( deut.lgElmtOn )
2008 
2009  long index = 0;
2010  for( mole_reaction_i it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it, ++index )
2011  it->second->index = index;
2012 
2013  mole.reaction_rks.resize( index );
2014  mole.old_zone = -1;
2015  if( index > 0 )
2016  memset( &mole.reaction_rks[0], 0, (unsigned long)(index)*sizeof(double) );
2017 
2018  // label catalytic, intra-group, and excitition/deexcitation vectors for all reactions
2019  for( mole_reaction_i it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it )
2020  register_reaction_vectors( it->second );
2021 }
2022 
2023 STATIC void mole_generate_isotopologue_reactions( string atom_old, string atom_new )
2024 {
2025  DEBUG_ENTRY( "mole_generate_isotopologue_reactions()" );
2026 
2027  bool lgDebug = false;
2028 
2029  count_ptr<chem_nuclide> atomOld = findnuclide(atom_old.c_str());
2030  // store new reaction strings (and pointer to reaction derived from) and add all to reactab map after following iterator
2031  vector<string> newReactionStrings;
2032  vector<mole_reaction*> oldReactions;
2033  vector<realnum> branchingRatios;
2034 
2035  // iterate over all reactions and generate new strings by replacing atom_old with atom_new
2036  for( mole_reaction_ci it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it )
2037  {
2038  bool lgFound = false;
2039 
2040  // Find number of atom sites in products
2041  int numSites = 0;
2042  for( long j=0; j<it->second->nproducts; ++j )
2043  {
2044  // Note that we must search before accessing the map because attempting to access an undeclared key will write to the map.
2045  if( it->second->products[j]->nNuclide.find( atomOld ) != it->second->products[j]->nNuclide.end() )
2046  numSites += it->second->products[j]->nNuclide[ atomOld ];
2047  }
2048 
2049  for( long i=0; i<it->second->nreactants; ++i )
2050  {
2051  // search for atom_old among reactants
2052  for( nNucs_i atom=it->second->reactants[i]->nNuclide.begin(); atom != it->second->reactants[i]->nNuclide.end(); ++atom )
2053  {
2054  if( atom->first->label() == atom_old )
2055  {
2056  lgFound = true;
2057  continue;
2058  }
2059  }
2060  if( lgFound )
2061  continue;
2062  }
2063 
2064  if( !lgFound )
2065  continue;
2066 
2067  if( lgDebug )
2068  fprintf( ioQQQ, "DEBUGGG mole_generate_isotopologue_reactions %s ..........\n", it->first.c_str() );
2069 
2070  for( long i=0; i<it->second->nreactants; ++i )
2071  {
2072  // ignore reactants with no nucleons (e-, PHOTON, CRPHOT, ... )
2073  if( it->second->reactants[i]->mole_mass < 0.99 * ATOMIC_MASS_UNIT )
2074  continue;
2075 
2076  vector<string> react_iso_labels;
2077  ChemNuclideList atomsLeftToRight;
2078  vector< int > numAtoms;
2079  string embellishments;
2080  // parse reactant label
2081  bool lgParseOK = parse_species_label( it->second->reactants[i]->label.c_str(), atomsLeftToRight, numAtoms, embellishments );
2082  if( !lgParseOK )
2083  TotalInsanity();
2084  // generate isotopologue labels
2086  atomsLeftToRight,
2087  numAtoms,
2088  atom_old,
2089  atom_new,
2090  embellishments,
2091  react_iso_labels );
2092  for( unsigned j=0; j<react_iso_labels.size(); ++j )
2093  {
2094  int numAtomsTot = 0;
2095  for( long k=0; k<it->second->nproducts; ++k )
2096  {
2097  // ignore products with no nucleons (e-, PHOTON, CRPHOT, ... )
2098  if( it->second->products[k]->mole_mass < 0.99 * ATOMIC_MASS_UNIT )
2099  continue;
2100 
2101  atomsLeftToRight.clear();
2102  numAtoms.clear();
2103  embellishments.clear();
2104  // parse product label
2105  lgParseOK = parse_species_label( it->second->products[k]->label.c_str(), atomsLeftToRight, numAtoms, embellishments );
2106  ASSERT( lgParseOK == true );
2107  // Loop over all positions in this product
2108  for( unsigned position = 0; position < atomsLeftToRight.size(); ++position )
2109  {
2110  string prod_iso_label;
2111  // generate isotopologue labels
2113  position,
2114  atomsLeftToRight,
2115  numAtoms,
2116  atom_old,
2117  atom_new,
2118  embellishments,
2119  prod_iso_label );
2120 
2121  if( prod_iso_label.empty() )
2122  continue;
2123 
2124  // Generate new reaction string
2125  string react_string;
2126  // first write reactants
2127  for( long i1=0; i1<i; ++i1 )
2128  {
2129  react_string += it->second->reactants[i1]->label;
2130  if( i1 != it->second->nreactants-1 )
2131  react_string += ",";
2132  }
2133  react_string += react_iso_labels[j];
2134  if( i != it->second->nreactants-1 )
2135  react_string += ",";
2136  for( long i2=i+1; i2<it->second->nreactants; ++i2 )
2137  {
2138  react_string += it->second->reactants[i2]->label;
2139  if( i2 != it->second->nreactants-1 )
2140  react_string += ",";
2141  }
2142 
2143  react_string += "=>";
2144  // now write products
2145  for( long k1=0; k1<k; ++k1 )
2146  {
2147  react_string += it->second->products[k1]->label;
2148  if( k1 != it->second->nproducts-1 )
2149  react_string += ",";
2150  }
2151  react_string += prod_iso_label;
2152  if( k != it->second->nproducts-1 )
2153  react_string += ",";
2154  for( long k2=k+1; k2<it->second->nproducts; ++k2 )
2155  {
2156  react_string += it->second->products[k2]->label;
2157  if( k2 != it->second->nproducts-1 )
2158  react_string += ",";
2159  }
2160 
2161  string canon_react_string = canonicalize_reaction_label( react_string.c_str() );
2162  // store new reaction string and pointer to old
2163  newReactionStrings.push_back( canon_react_string );
2164  oldReactions.push_back( it->second.get_ptr() );
2165  // This is the number of unique product lists given a particular reactant list. Will divide rate below.
2166  branchingRatios.push_back( numAtoms[position]/numSites );
2167 
2168  if( lgDebug )
2169  fprintf( ioQQQ, "DEBUGGG mole_generate_isotopologue_reactions .................... %s\t\t(%2i/%2i).\n",
2170  canon_react_string.c_str(), numAtoms[position], numSites );
2171 
2172  numAtomsTot += numAtoms[position];
2173  }
2174  }
2175  ASSERT( numAtomsTot == numSites );
2176  }
2177  }
2178  }
2179 
2180  ASSERT( oldReactions.size() == newReactionStrings.size() );
2181 
2182  // now declare new reactions
2183  vector<mole_reaction*>::const_iterator it2 = oldReactions.begin();
2184  vector<realnum>::const_iterator it3 = branchingRatios.begin();
2185  for( vector<string>::const_iterator it1 = newReactionStrings.begin(); it1 != newReactionStrings.end(); ++it1, ++it2, ++it3 )
2186  {
2187  fixit("make adjustments to a for mass?");
2188 
2189  // don't overwrite existing reaction with these new auto-generated details
2190  if( mole_priv::reactab.find( it1->c_str() ) == mole_priv::reactab.end() )
2191  {
2192  ASSERT( *it3 <= 1. + FLT_EPSILON );
2193  fixit("multiply by *it3 here. ASSERT at mole_reactions.cpp:1190 will blow currently.");
2194  newreact( it1->c_str(), (*it2)->name(), (*it2)->a /* * (*it3) */, (*it2)->b, (*it2)->c );
2195  }
2196  }
2197 
2198  return;
2199 }
2200 
2202 {
2203  DEBUG_ENTRY( "mole_check_reverse_reactions()" );
2204 
2205  char chLabel[50], chLabelSave[50];
2206  int exists;
2207 
2208  for(mole_reaction_i p=mole_priv::reactab.begin();
2209  p != mole_priv::reactab.end(); ++p)
2210  {
2211  mole_reaction_i q = p;
2212  strcpy( chLabel, p->second->label.c_str() );
2213  strcpy( chLabelSave, p->second->label.c_str() );
2214  char *str = chLabel;
2215  const char *delim = "=>";
2216  char *chNewProducts = strtok( str, delim );
2217  char *chNewReactants = strtok( NULL, delim );
2218  char chNewReaction[50];
2219 
2220  strcpy( chNewReaction, chNewReactants );
2221  strcat( chNewReaction, "=>" );
2222  strcat( chNewReaction, chNewProducts );
2223 
2224 
2225  q = mole_priv::reactab.find(chNewReaction);
2226 
2227  exists = (q != mole_priv::reactab.end());
2228  if ( !exists )
2229  {
2230  if( trace.lgTraceMole )
2231  {
2232  fprintf(ioQQQ,"Warning! No reverse reaction for %30s. ", p->second->label.c_str() );
2233  fprintf( ioQQQ,"\n" );
2234  }
2235 
2236  fixit("NB reverse reactions should be generated here");
2237  }
2238  }
2239 
2240  return;
2241 }
2242 
2243 STATIC double mole_get_equilibrium_condition( const char buf[] )
2244 {
2245  DEBUG_ENTRY( "mole_get_equilibrium_condition()" );
2246 
2247  mole_reaction *rate = mole_findrate_s(buf);
2248  double result = mole_get_equilibrium_condition( rate );
2249  return result;
2250 }
2251 
2253 {
2254  DEBUG_ENTRY( "mole_get_equilibrium_condition()" );
2255 
2256  if( !rate )
2257  return 0.;
2258 
2259  // multiply by reactant partition functions, then divide by products'
2260  double ln_result = 0.;
2261  for( long i=0; i<rate->nproducts; ++i)
2262  {
2263  double fac = mole_partition_function(rate->products[i]);
2264  if( fac==0. )
2265  return 0.;
2266  ln_result += log(fac);
2267  }
2268  for( long i=0; i<rate->nreactants; ++i)
2269  {
2270  double fac = mole_partition_function(rate->reactants[i]);
2271  if( fac==0. )
2272  return (double) BIGFLOAT;
2273  ln_result -= log(fac);
2274  }
2275  // Prevent overflow
2276  double result = exp( MIN2( SEXP_LIMIT, ln_result ) );
2277 
2278  //fprintf( ioQQQ, "DEBUGGG equilibrium %20s\t%e\n", rate->label.c_str(), result );
2279  return result;
2280 }
2281 
2282 STATIC double mole_partition_function( const molecule* const sp)
2283 {
2284  DEBUG_ENTRY( "mole_partition_function()" );
2285 
2286  if( sp->label == "PHOTON" || sp->label == "CRPHOT" )
2287  {
2288  fixit("How can we adapt existing structures to have a photon energy or range available here?");
2289  fixit("include 2hnu^3/c^2. Understand HNU3C2 macro!");
2290  return 1.; //sexp( energy_ryd/phycon.te_ryd );
2291  }
2292  else if( sp->label == "CRP" || sp->label == "grn" )
2293  return 1.;
2294 
2295  fixit("need to figure out stat weight for any given particle");
2296  double q = 1.;
2297  // last factors convert kJ/mol to Kelvin/particle
2298  double deltaH = sp->form_enthalpy * (1e10/AVOGADRO/BOLTZMANN);
2299  ASSERT( sp->mole_mass > 0. );
2300  double part_fun = powpq(phycon.te*sp->mole_mass/(HION_LTE_POP*ELECTRON_MASS),3,2) * q * dsexp(deltaH/phycon.te);
2301  ASSERT( part_fun < BIGFLOAT );
2302  ASSERT( part_fun >= 0. );
2303 
2304  return part_fun;
2305 }
2306 
2308 {
2309  DEBUG_ENTRY( "mole_cmp_num_in_out_reactions()" );
2310 
2311  vector<long> numForm, numDest;
2312  numForm.resize( mole_global.num_total );
2313  numDest.resize( mole_global.num_total );
2314 
2315  for(mole_reaction_i p=mole_priv::reactab.begin(); p != mole_priv::reactab.end(); p++)
2316  {
2317  count_ptr<mole_reaction> rate = p->second;
2318  for( long i=0; i<rate->nreactants; ++i)
2319  {
2320  ++numDest[ rate->reactants[i]->index ];
2321  }
2322 
2323  for( long i=0; i<rate->nproducts; ++i)
2324  {
2325  ++numForm[ rate->products[i]->index ];
2326  }
2327  }
2328 
2329  for( unsigned i=0; i<numForm.size(); ++i )
2330  {
2331  if( numForm[i]==0 && numDest[i]==0 )
2332  continue;
2333  if( numForm[i]>1 && numDest[i]>1 )
2334  continue;
2335  if( mole_global.list[i]->isMonatomic() )
2336  continue;
2337  fprintf( ioQQQ, "DEBUGGG mole_cmp_num_in_out_reactions %*s: in %4li out %4li\n", CHARS_SPECIES, mole_global.list[i]->label.c_str(), numForm[i], numDest[i] );
2338  }
2339 
2340  return;
2341 }
2342 
2343 STATIC char *getcsvfield(char **s,char c);
2344 STATIC void parse_base(char *s)
2345 {
2346  char *label, *reactstr, *f;
2347  double a, b, c;
2348  label = getcsvfield(&s,':');
2349  reactstr = getcsvfield(&s,':');
2350  f = getcsvfield(&s,':');
2351  a = atof(f);
2352  f = getcsvfield(&s,':');
2353  b = atof(f);
2354  f = getcsvfield(&s,':');
2355  c = atof(f);
2356 
2357  newreact(label,reactstr,a,b,c);
2358 
2359 }
2360 
2361 STATIC void newreact(const char label[], const char fun[], double a, double b, double c)
2362 {
2363  DEBUG_ENTRY( "newreact()" );
2364 
2365  ratefunc rate = findfunc(fun);
2366  if (rate.get_ptr() == NULL)
2367  {
2368  fprintf(stderr,"Rate function %s not known for reaction %s. Aborting. Sorry.\n",fun,label);
2369  cdEXIT( EXIT_FAILURE );
2370  }
2371 
2372  if( a < 0. )
2373  {
2374  fprintf(ioQQQ,"\n PROBLEM Reaction %s has negative pre-coefficient. Aborting. Sorry.\n", label);
2375  cdEXIT( EXIT_FAILURE );
2376  }
2377 
2378  rate->label = label;
2379  rate->a = a;
2380  rate->b = b;
2381  rate->c = c;
2382  rate->source = source;
2383 
2384  rate->photon = 0;
2385 
2386  if( parse_reaction( rate, label ) == 0 )
2387  return;
2388 
2389  canonicalize_reaction( rate );
2390 
2391  if( lgReactionTrivial( rate ) )
2392  return;
2393 
2394  if (mole_global.offReactions.find(rate->label)
2395  != mole_global.offReactions.end())
2396  {
2397  fprintf(ioQQQ," W-reaction %s disabled\n",rate->label.c_str());
2398  phycon.lgPhysOK = false;
2399  return;
2400  }
2401 
2402  const char *rateLabelPtr = rate->label.c_str();
2403 
2404  ASSERT(lgReactBalance(rate)); /* Verify rate conserves particles and charge */
2405 
2406  rate->udfastate = ABSENT;
2407  if (UDFA)
2408  {
2409  compare_udfa(rate);
2410  if (rate->udfastate == ABSENT)
2411  {
2412  fprintf(stderr,"Reaction %s not in UDFA\n",rateLabelPtr);
2413  }
2414  }
2415 
2416  /* >> chng 06 Oct 10 rjrw: use 1/(1/m1+1/m2) for reduced mass to prevent underflow */
2417  if (rate->nreactants == 2 && rate->reactants[0]->mole_mass!=0.0 && rate->reactants[1]->mole_mass!=0.0 )
2418  {
2419  rate->reduced_mass = 1./(1./rate->reactants[0]->mole_mass+1./rate->reactants[1]->mole_mass);
2420  }
2421  else
2422  {
2423  rate->reduced_mass = 0.;
2424  }
2425 
2426  /* If everything is OK, can register the reaction */
2427  mole_reaction_i p = mole_priv::reactab.find(rateLabelPtr);
2428  int exists = (p != mole_priv::reactab.end());
2429  // do not comment in release version, or if NO TIMES entered
2430  if(exists && !t_version::Inst().lgReleaseBranch && !t_version::Inst().lgRelease &&
2431  prt.lgPrintTime )
2432  {
2433  /* Replace old rate */
2434  fprintf(ioQQQ,"Warning: duplicate reaction %s -- using new version\n",rateLabelPtr);
2435  }
2436  mole_priv::reactab[rateLabelPtr] = rate;
2437 }
2438 
2439 STATIC long parse_reaction( count_ptr<mole_reaction>& rate, const char label[] )
2440 {
2441  DEBUG_ENTRY( "parse_reaction()" );
2442 
2443  for (int i=0;i<MAXREACTANTS;i++)
2444  {
2445  rate->reactants[i] = NULL;
2446  }
2447  rate->nreactants = 0;
2448 
2449  for (int i=0;i<MAXPRODUCTS;i++)
2450  {
2451  rate->products[i] = NULL;
2452  }
2453  rate->nproducts = 0;
2454 
2455  bool lgProd = false;
2456  string buf = "";
2457  for(int i=0;!i || label[i-1]!='\0';i++)
2458  {
2459  if(label[i] == ',' || label[i] == '=' || label[i] == '\0')
2460  {
2461  molecule *sp = findspecies(buf.c_str());
2462  if( sp == null_mole || !sp->isEnabled )
2463  {
2464  if( trace.lgTraceMole )
2465  fprintf(ioQQQ,"Mole_reactions: ignoring reaction %s (species %s not active)\n",label,buf.c_str());
2466  return 0;
2467  }
2468  buf = "";
2469  if(! lgProd)
2470  {
2471  if (rate->nreactants >= MAXREACTANTS)
2472  {
2473  fprintf(stderr,"Mole_reactions: Too many reactants in %s, only %d allowed\n",label,MAXREACTANTS);
2475  }
2476  rate->reactants[rate->nreactants] = sp;
2477  rate->nreactants++;
2478  }
2479  else
2480  {
2481  if (rate->nproducts >= MAXPRODUCTS)
2482  {
2483  fprintf(stderr,"Mole_reactions: Too many products in %s, only %d allowed\n",label,MAXPRODUCTS);
2485  }
2486  rate->products[rate->nproducts] = sp;
2487  rate->nproducts++;
2488  }
2489  if(label[i] == '=')
2490  {
2491  i++; /* skip '>' as well */
2492  if (label[i] != '>')
2493  {
2494  fprintf(ioQQQ,"Format error in reaction %s\n",label);
2496  }
2497  lgProd = true;
2498  }
2499  }
2500  else
2501  {
2502  buf += label[i];
2503  }
2504  }
2505 
2506  for (int i=0;i<MAXREACTANTS;i++)
2507  if( rate->reactants[i] != NULL )
2508  ++rate->reactants[i]->n_react;
2509  for (int i=0;i<MAXPRODUCTS;i++)
2510  if( rate->products[i] != NULL )
2511  ++rate->products[i]->n_react;
2512 
2513  ASSERT( rate->nreactants );
2514  ASSERT( rate->nproducts );
2515 
2516  return 1;
2517 }
2518 
2519 STATIC string canonicalize_reaction_label( const char label[] )
2520 {
2521  DEBUG_ENTRY( "canonicalize_reaction_label()" );
2522 
2523  // set up a dummy reaction
2524  ratefunc rate = findfunc("null");
2525  rate->label = label;
2526  parse_reaction( rate, label );
2527  canonicalize_reaction( rate );
2528 
2529  //if( !conv.nTotalIoniz && strcmp( label, rate->label.c_str() ) != 0 )
2530  // fprintf( ioQQQ, "DEBUGGG reaction label %20s canonicalized to %20s\n", label, rate->label.c_str() );
2531 
2532  return rate->label;
2533 }
2534 
2536 {
2537  DEBUG_ENTRY( "canonicalize_reaction()" );
2538 
2539  /* Put species in canonical order to make sure reactions are unique.
2540  Can cause problems when a consistent ordering of species is
2541  required (look for references to "reactants[0]" for examples) */
2543  t_mole_global::sort(rate->products,rate->products+rate->nproducts);
2544 
2545  // now reorder label in same (new) order
2546  string newLabel;
2547  for( long i=0; i<rate->nreactants; ++i )
2548  {
2549  newLabel += rate->reactants[i]->label;
2550  if( i != rate->nreactants-1 )
2551  newLabel += ",";
2552  }
2553  newLabel += "=>";
2554  for( long i=0; i<rate->nproducts; ++i )
2555  {
2556  newLabel += rate->products[i]->label;
2557  if( i != rate->nproducts-1 )
2558  newLabel += ",";
2559  }
2560 
2561  // overwrite original label with canonical
2562  rate->label = newLabel;
2563 
2564  return;
2565 }
2566 
2567 // Returns true if reactant and product vectors are identical.
2569 {
2570  DEBUG_ENTRY( "lgReactionTrivial()" );
2571 
2572  bool lgTrivial = false;
2573  if( rate->nreactants == rate->nproducts )
2574  {
2575  lgTrivial = true;
2576  for( int k=0; k<rate->nreactants; ++k )
2577  {
2578  if( rate->reactants[k] != rate->products[k] )
2579  {
2580  lgTrivial = false;
2581  break;
2582  }
2583  }
2584  }
2585 
2586  return lgTrivial;
2587 }
2588 
2590 {
2591  DEBUG_ENTRY( "register_reaction_vectors()" );
2592 
2593  for (long k=0;k<rate->nreactants;k++)
2594  {
2595  rate->rvector[k] = NULL;
2596  rate->rvector_excit[k] = NULL;
2597  }
2598 
2599  for (long k=0;k<rate->nproducts;k++)
2600  {
2601  rate->pvector[k] = NULL;
2602  rate->pvector_excit[k] = NULL;
2603  }
2604 
2605  /* Label catalytic species */
2606  for (long i=0;i<rate->nproducts;i++)
2607  {
2608  if (rate->pvector[i] == NULL)
2609  {
2610  for (long k=0;k<rate->nreactants;k++)
2611  {
2612  if (rate->rvector[k] == NULL)
2613  {
2614  if (rate->products[i] == rate->reactants[k])
2615  {
2616  rate->rvector[k] = rate->products[i];
2617  rate->pvector[i] = rate->reactants[k];
2618  break;
2619  }
2620  }
2621  }
2622  }
2623  }
2624 
2625  /* Label other intra-group transfers */
2626  for (long i=0;i<rate->nproducts;i++)
2627  {
2628  if (rate->pvector[i] == NULL)
2629  {
2630  for (long k=0;k<rate->nreactants;k++)
2631  {
2632  if (rate->rvector[k] == NULL)
2633  {
2634  if (rate->products[i]->groupnum != -1 &&
2635  rate->products[i]->groupnum ==
2636  rate->reactants[k]->groupnum)
2637  {
2638  rate->rvector[k] = rate->products[i];
2639  rate->pvector[i] = rate->reactants[k];
2640  break;
2641  }
2642  }
2643  }
2644  }
2645  }
2646 
2647  /* Label excited/deexcited pairs */
2648  for (long i=0;i<rate->nproducts;i++)
2649  {
2650  if (rate->pvector[i] == NULL && rate->pvector_excit[i] == NULL)
2651  {
2652  for (long k=0;k<rate->nreactants;k++)
2653  {
2654  if (rate->rvector[k] == NULL && rate->rvector_excit[k] == NULL )
2655  {
2656  if ( lgDifferByExcitation( *rate->products[i], *rate->reactants[k] ) )
2657  {
2658  rate->rvector_excit[k] = rate->products[i];
2659  rate->pvector_excit[i] = rate->reactants[k];
2660  break;
2661  }
2662  }
2663  }
2664  }
2665  }
2666 
2667  return;
2668 }
2669 
2670 
2672 {
2673  FILE *sparsefp;
2674  int i, j, nb, ch;
2675  long int ratej;
2676  double **c;
2677 
2678  c = (double **)MALLOC((size_t)mole_global.num_total*sizeof(double *));
2679  c[0] = (double *)MALLOC((size_t)mole_global.num_total*
2680  mole_global.num_total*sizeof(double));
2681 
2682  for(i=1;i<mole_global.num_total;i++)
2683  {
2684  c[i] = c[i-1]+mole_global.num_total;
2685  }
2686 
2687  for ( j=0; j < mole_global.num_total; j++ )
2688  {
2689  for ( i=0; i < mole_global.num_total; i++ )
2690  {
2691  c[j][i] = 0.;
2692  }
2693  }
2694 
2695  for(mole_reaction_i p=mole_priv::reactab.begin();
2696  p != mole_priv::reactab.end(); ++p)
2697  {
2698  mole_reaction &rate = *p->second;
2699 
2700  for (j=0;j<rate.nreactants;j++)
2701  {
2702  ratej = rate.reactants[j]->index;
2703  for (i=0;i<rate.nreactants;i++)
2704  {
2705  if (rate.rvector[i] == NULL)
2706  c[ratej][rate.reactants[i]->index] = 1.0;
2707  }
2708  for (i=0;i<rate.nproducts;i++)
2709  {
2710  if (rate.pvector[i] == NULL)
2711  c[ratej][rate.products[i]->index] = 1.0;
2712  }
2713  }
2714  }
2715 
2716  sparsefp = open_data("sparse.pbm","w");
2717  fprintf(sparsefp,"P4\n%d %d\n",
2719 
2720  for ( j=0; j < mole_global.num_total; j++ )
2721  {
2722  nb = ch = 0;
2723  for ( i=0; i < mole_global.num_total; i++ )
2724  {
2725  ch = (ch << 1) | (c[i][j] != 0.0);
2726  nb++;
2727  if (nb == 8)
2728  {
2729  fputc(ch,sparsefp);
2730  nb = ch = 0;
2731  }
2732  }
2733  if (nb != 0)
2734  {
2735  ch <<= 8-nb;
2736  fputc(ch,sparsefp);
2737  }
2738  }
2739  fclose(sparsefp);
2740  free(c[0]);
2741  free(c);
2742 }
2743 
2744 #ifndef NDEBUG
2746 {
2747  molecule::nNucsMap nel;
2748  int dcharge, n, sign;
2749  bool lgOK = true;
2750 
2751  dcharge = 0;
2752  for (n=0;n<rate->nreactants;n++)
2753  {
2754  for( nNucs_i it = rate->reactants[n]->nNuclide.begin(); it != rate->reactants[n]->nNuclide.end(); ++it )
2755  nel[it->first] += it->second;
2756  dcharge += rate->reactants[n]->charge;
2757  }
2758  for (n=0;n<rate->nproducts;n++)
2759  {
2760  for( nNucs_i it = rate->products[n]->nNuclide.begin(); it != rate->products[n]->nNuclide.end(); ++it )
2761  nel[it->first] -= it->second;
2762  dcharge -= rate->products[n]->charge;
2763  }
2764  if (dcharge != 0)
2765  {
2766  fprintf(stderr,"Reaction %s charge out of balance by %d\n",
2767  rate->label.c_str(),dcharge);
2768  lgOK = false;
2769  }
2770 
2771  for( nNucs_i it = nel.begin(); it != nel.end(); ++it )
2772  {
2773  if(it->second != 0)
2774  {
2775  if(it->second > 0)
2776  sign = 1;
2777  else
2778  sign = -1;
2779  fprintf(stderr,"Error: reaction %s %s %d of element %s\n",
2780  rate->label.c_str(),sign==1?"destroys":"creates",
2781  sign*it->second,
2782  it->first->label().c_str() );
2783  lgOK = false;
2784  }
2785  }
2786  return lgOK;
2787 }
2788 #endif
2789 
2790 enum {BUFSIZE=256};
2791 
2792 namespace
2793 {
2794  class formula_species {
2795  public:
2796  molecule *reactants[MAXREACTANTS], *products[MAXPRODUCTS];
2797  };
2798 
2799  bool operator< (const formula_species &a, const formula_species &b)
2800  {
2801  int i;
2802  for (i=0;i<MAXREACTANTS;i++)
2803  {
2804  if (a.reactants[i]<b.reactants[i])
2805  return true;
2806  else if (a.reactants[i]>b.reactants[i])
2807  return false;
2808  }
2809  for (i=0;i<MAXPRODUCTS;i++)
2810  {
2811  if (a.products[i]<b.products[i])
2812  return true;
2813  else if (a.products[i]>b.products[i])
2814  return false;
2815  }
2816  return false;
2817  }
2818 
2819  class udfa_reaction {
2820  public:
2821  int index;
2822  formula_species l;
2823  char source; /* Calculated, Estimated, Literature compilation, Measured */
2824  double a, b, c, trange[2]; /* Overall scale and valid temperature range */
2825  };
2826 }
2827 
2828 static map <formula_species,count_ptr<udfa_reaction> > udfatab;
2829 
2830 STATIC void read_data(const char file[], void (*parse)(char *s))
2831 {
2832  DEBUG_ENTRY( "read_data()" );
2833  char buf[BUFSIZE];
2834 
2835  FILE *fp = open_data(file,"r");
2836  if (!fp)
2837  {
2838  fprintf(stderr,"Error, could not read %s\n",file);
2840  }
2841 
2842  fixit("this seg-faults if file ends in blank line!");
2843  while(fgets(buf,BUFSIZE,fp))
2844  {
2845  if( buf[0] == '#' )
2846  continue;
2847  parse(buf);
2848  }
2849  fclose(fp);
2850 }
2851 #define FLTEQ(a,b) (fabs((a)-(b)) <= 1e-6*fabs((a)+(b)))
2852 STATIC void parse_udfa(char *s)
2853 {
2854  char *f;
2855  unsigned int havespecies = 1, i, n;
2856  /* lgCRPHOT is true for CRPHOT reactions as we change the data
2857  * format for them */
2858  int lgCRPHOT=0;
2859 
2860  count_ptr<udfa_reaction>r(new udfa_reaction);
2861  f = getcsvfield(&s,',');
2862  r->index = atoi(f);
2863 
2864  /* Load reactants */
2865  for (n=0;n<MAXREACTANTS;n++)
2866  {
2867  r->l.reactants[n] = NULL;
2868  }
2869  i = 0;
2870  for (n=0;n<MAXREACTANTS;n++)
2871  {
2872  f = getcsvfield(&s,',');
2873  if (f[0] != '\0')
2874  {
2875  i++;
2876  r->l.reactants[n] = findspecies(f);
2877  if (r->l.reactants[n] == null_mole)
2878  havespecies = 0;
2879  if (!strncmp(f,"CRPHOT",6))
2880  lgCRPHOT = 1;
2881  }
2882  }
2883  t_mole_global::sort(r->l.reactants,r->l.reactants+i);
2884 
2885  /* Load products */
2886  for (n=0;n<MAXPRODUCTS;n++)
2887  {
2888  r->l.products[n] = NULL; /* Sentinel */
2889  }
2890  i = 0;
2891  for (n=0;n<MAXPRODUCTS;n++)
2892  {
2893  f = getcsvfield(&s,',');
2894  if (f[0] != '\0')
2895  {
2896  i++;
2897  r->l.products[n] = findspecies(f);
2898  if (r->l.products[n] == null_mole)
2899  havespecies = 0;
2900  }
2901  }
2902 
2903  t_mole_global::sort(r->l.products,r->l.products+i);
2904 
2905  /* Load rate parameters */
2906  f = getcsvfield(&s,',');
2907  r->a = atof(f);
2908  f = getcsvfield(&s,',');
2909  r->b = atof(f);
2910  f = getcsvfield(&s,',');
2911  r->c = atof(f);
2912 
2913  if (lgCRPHOT)
2914  {
2915  /* UDFA has a uniform value for the cosmic ray field independent of
2916  circumstances which we correct -- verify they haven't changed
2917  anything and move the multiplicative constant into our usual place
2918  for it. */
2919  ASSERT (FLTEQ(r->a,1.3e-17));
2920  r->a = r->c;
2921  r->c = 0.;
2922  }
2923 
2924  /* Load data confidence and range of temperature validity */
2925  f = getcsvfield(&s,',');
2926  r->source = f[0]?f[0]:'?';
2927  for (n=0;n<2;n++) {
2928  f = getcsvfield(&s,',');
2929  r->trange[n] = atof(f);
2930  }
2931 
2932  if (havespecies)
2933  {
2934  if (udfatab.find(r->l) != udfatab.end())
2935  {
2936  fprintf(stderr,"Duplicate reaction\n");
2937  }
2938  udfatab[r->l] = r;
2939  }
2940 }
2941 STATIC char *getcsvfield(char **s, char c)
2942 {
2943  char *sv, *f;
2944 
2945  sv = strchr(*s,c);
2946  if (sv) {
2947  *sv++ = '\0';
2948  }
2949  f = *s;
2950  *s = sv;
2951  return f;
2952 }
2954 {
2955  formula_species s;
2956 
2957  for (int n=0;n<MAXREACTANTS;n++)
2958  {
2959  s.reactants[n] = rate->reactants[n];
2960  }
2961  for (int n=0;n<MAXPRODUCTS;n++)
2962  {
2963  s.products[n] = rate->products[n];
2964  }
2965  map<formula_species, count_ptr<udfa_reaction> >::iterator p
2966  = udfatab.find(s);
2967  if (p == udfatab.end() )
2968  {
2969  /* fprintf(stdout,"Did not find reaction %s\n",rate->label); */
2970  return;
2971  }
2972  else
2973  {
2974  count_ptr<udfa_reaction>& u = p->second;
2975  if (FLTEQ(rate->a,u->a) && FLTEQ(rate->b,u->b) && FLTEQ(rate->c,u->c))
2976  {
2977  rate->udfastate = CORRECT;
2978  /* fprintf(stdout,"Reaction %s agrees\n",rate->label); */
2979  }
2980  else
2981  {
2982  rate->udfastate = CONFLICT;
2983  /* fprintf(stdout,"Reaction %18.18s clashes: a %9.2e %9.2e|b %9.2e %9.2e|c %9.2e %9.2e\n",
2984  rate->label,rate->a,u->a,rate->b,u->b,rate->c,u->c); */
2985  }
2986  }
2987 }
2988 
2989 namespace
2990 {
2991  ratefunc findfunc (const char name[])
2992  {
2993  return count_ptr<mole_reaction>(mole_priv::functab[name]->Create());
2994  }
2995 }
2996 
2998 {
2999  enum { DEBUG_MOLE = false };
3000 
3001  DEBUG_ENTRY( "mole_update_rks()" );
3002 
3004 
3005  mole_h_reactions();
3006 
3007  for (mole_reaction_i p
3008  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
3009  {
3010  mole_reaction &rate = *p->second;
3011  long index = rate.index;
3012  realnum newrk = rate.a*rate.rk();
3013  if (DEBUG_MOLE)
3014  {
3015  realnum oldrk = (realnum)mole.reaction_rks[index];
3016  if (fabs(newrk-oldrk) > 0.1*newrk)
3017  fprintf(ioQQQ,"%s: %15.8g => %15.8g\n",
3018  rate.label.c_str(),oldrk,newrk);
3019  }
3020  mole.reaction_rks[index] = newrk;
3021  }
3022 }
3024 {
3025  DEBUG_ENTRY( "mole_rk_bigchange()" );
3026  enum { DEBUG_MOLE = false };
3027 
3028  if ( mole.old_reaction_rks.size() == 0 )
3029  {
3030  mole.old_zone = -1;
3031  mole.old_reaction_rks.resize(mole.reaction_rks.size());
3032  }
3033 
3034  if (nzone > 1)
3035  {
3036  ASSERT(mole.old_zone == nzone - 1);
3037  double bigchange = 0.;
3038  unsigned long bigindex = ULONG_MAX;
3039  for (unsigned long index=0; index<mole.reaction_rks.size(); ++index)
3040  {
3041  double oldrk = mole.old_reaction_rks[index],
3042  newrk = mole.reaction_rks[index],
3043  sum = oldrk+newrk, diff = newrk-oldrk;
3044  if (sum > 0.)
3045  {
3046  double change = fabs(diff)/sum;
3047  if (change > bigchange)
3048  {
3049  bigchange = change;
3050  bigindex = index;
3051  }
3052  }
3053  }
3054 
3055  for (mole_reaction_i p
3056  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
3057  {
3058  mole_reaction &rate = *p->second;
3059  if (bigindex == (unsigned) rate.index)
3060  {
3061  double oldrk = mole.old_reaction_rks[bigindex],
3062  newrk = mole.reaction_rks[bigindex];
3063  double pct = 0.;
3064  if (oldrk > 0.)
3065  pct = 100.*(newrk-oldrk)/oldrk;
3066  fprintf(ioQQQ, "Zone %ld, big chemistry rate change %s:"
3067  " %15.8g => %15.8g (%6.2g%%)\n",
3068  nzone,rate.label.c_str(),oldrk,newrk,pct);
3069  break;
3070  }
3071  }
3072  }
3073 
3074  mole.old_zone = nzone;
3075  for (unsigned long index=0; index<mole.reaction_rks.size(); ++index)
3076  {
3077  mole.old_reaction_rks[index] = mole.reaction_rks[index];
3078  }
3079 }
3080 
3082 {
3083  DEBUG_ENTRY( "mole_h2_grain_form()" );
3084 
3085  double T_ortho_para_crit,xi_ELRD, beta_alpha_ELRD, recombination_efficiency_ELRD, Td;
3087  realnum AveVelH2 = GetAveVelocity( 2.f * dense.AtomicWeight[ipHYDROGEN] );
3088 
3089  /* H2 formation on grains;
3090  * rate from
3091  * >>refer H2 grain formation Hollenbach, D., & McKee, C.F., 1979, ApJS, 41, 555 eq 3.4 3.8 */
3092  if( gv.lgDustOn() )
3093  {
3094 
3096  {
3097  fixit("Is this still necessary?");
3098  /* hmole is called before grains, so assure that all the grain stuff is properly initialized */
3099  GrainDrive();
3100  }
3101 
3102  /* these are rates (s-1) H2 will be deactivated by collisions with grains
3103  * will be incremented below
3104  * H2 ortho - para conversion on grain surface */
3106  /* rate (s-1) v=0, J=1 level goes to 0 */
3107  h2.rate_grain_J1_to_J0 = 0.;
3108 
3109  /* loop over all grain species */
3110  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3111  {
3112  /* >>chng 02 feb 15, removed check tedust > 1.01, change in GrainsInit
3113  * guarantees that all relevant parameters are initialized, PvH */
3114 
3115  double sticking_probability_H = sticking_probability_H_func( phycon.te, gv.bin[nd]->tedust );
3116 
3117  bool lgUseQHeat = ENABLE_QUANTUM_HEATING &&
3118  gv.lgGrainPhysicsOn && gv.bin[nd]->lgQHeat;
3119  long k, qnbin=0;
3120  vector<double> qtemp, qprob;
3121  if ( lgUseQHeat )
3122  {
3123  /* >>chng 04 feb 21, included quantum heating in calculation of formation rate, PvH */
3124  qtemp.resize(NQGRID);
3125  qprob.resize(NQGRID);
3126 
3127  qheat(qtemp,qprob,&qnbin,nd);
3128 
3129  if( gv.bin[nd]->lgUseQHeat )
3130  {
3131  ASSERT( qnbin > 0 );
3132  }
3133  else
3134  {
3135  qnbin = 1;
3136  qprob[0] = 1.;
3137  qtemp[0] = gv.bin[nd]->tedust;
3138  }
3139 
3140  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.;
3141 
3142  for( k=0; k < qnbin; k++ )
3143  {
3144  /* fraction of impacts that produce H2 before evaporation from grain surface.
3145  * this is equation 3.4 of
3146  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555
3147  * 1e4 is ratio of total absorption sites to appropriate sites
3148  * 920 is D_H and chosen to get f_a = 0.5 at 100 K.
3149  * factor of 0.6252 needed to obtain std ism rate to be 3e-17 at 100 K,
3150  * the value deduced by
3151  * >>refer H2 grain physics Jura, M., 1974, ApJ, 197, 581 */
3152  double conversion_efficiency_HM79 = 1/(1. + 1e4*sexp(920./qtemp[k]));
3153  sticking_probability_H = sticking_probability_H_func( phycon.te, qtemp[k] );
3154 
3155  gv.bin[nd]->rate_h2_form_grains_HM79 += qprob[k] * sticking_probability_H *
3156  conversion_efficiency_HM79;
3157  }
3158 
3159  /* NB IntArea is total, not projected, area, must div by 4 */
3160  /* gv.bin[nd]->rate_h2_form_grains_HM79 has units s^-1 since gv.bin[nd]->cnv_H_pCM3 has units cm-3 */
3161  /* cnv_H_pCM3 converts <unit>/H (default depletion) -> <unit>/cm^3 (actual depletion), units are cm-3 */
3162  gv.bin[nd]->rate_h2_form_grains_HM79 *= 0.5 * AveVelH *
3163  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3164 
3165  ASSERT( gv.bin[nd]->rate_h2_form_grains_HM79 > 0. );
3166  }
3167  else
3168  {
3169  /* fraction of impacts that produce H2 before evaporation from grain surface.
3170  * this is equation 3.4 of
3171  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555
3172  * 1e4 is ratio of total absorption sites to appropriate sites
3173  * 920 is D_H and chosen to get f_a = 0.5 at 100 K.
3174  * factor of 0.6252 needed to obtain std ism rate to be 3e-17 at 100 K,
3175  * the value deduced by
3176  * >>refer H2 grain physics Jura, M., 1974, ApJ, 197, 581 */
3177  double conversion_efficiency_HM79 = 1/(1. + 1e4*sexp(920./gv.bin[nd]->tedust));
3178 
3179  /* NB IntArea is total area per H for default abundances, not projected area, must div by 4
3180  * units s^-1 since gv.bin[nd]->cnv_H_pCM3 has units H cm-3
3181  * final units are cm s-1*/
3182  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3183  /* cnv_H_pCM3 converts <unit>/H (default depletion) -> <unit>/cm^3 (actual depletion), units are cm-3 */
3184  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * conversion_efficiency_HM79;
3185  ASSERT( gv.bin[nd]->rate_h2_form_grains_HM79 > 0. );
3186  }
3187 
3188  if( lgUseQHeat )
3189  {
3190  /* H2 formation on grains from
3191  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29 */
3192  /* number of monolayers per second - only affects efficiency at very low or high temperatures */
3193  double f = 1e-10;
3194  /* equation 17
3195  double sqrt_term = POW2( 1. + sqrt( (10000.-200.)/(600.-200.) ) );*/
3196  double sqrt_term = 35.399494936611667;
3197 
3198  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.;
3199 
3200  for( k=0; k < qnbin; k++ )
3201  {
3202  double beta_alpha = 0.25 * sqrt_term *sexp(200./qtemp[k] );
3203  /* equation 16 */
3204  double xi = 1./ (1. + 1.3e13*sexp(1.5*1e4/qtemp[k])*sqrt_term/(2.*f) );
3205  /* expression for beta comes from just after equation 5 */
3206  double beta = 3e12 * sexp( 320. / qtemp[k] );
3207  /* recombination efficiency given by their equation 15, they call
3208  * this epsilon_H2 */
3209  double recombination_efficiency_CT02 = xi / (1. + 0.005*f/2./SDIV(beta) + beta_alpha );
3210  sticking_probability_H = sticking_probability_H_func( phycon.te, qtemp[k] );
3211 
3212  /* printf( " k %ld Td %.6e re*sp %.6e\n", k, qtemp[k], recombination_efficiency_CT02* */
3213  /* sticking_probability_H ); */
3214 
3215  gv.bin[nd]->rate_h2_form_grains_CT02 += qprob[k] * sticking_probability_H *
3216  recombination_efficiency_CT02;
3217  }
3218 
3219  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3220  * so x/4 is projected area of circle */
3221  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3222  /* gv.bin[nd]->rate_h2_form_grains_CT02 units s-1 */
3223  gv.bin[nd]->rate_h2_form_grains_CT02 *= 0.5 * AveVelH *
3224  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3225 
3226  ASSERT( gv.bin[nd]->rate_h2_form_grains_CT02 > 0. );
3227  }
3228  else
3229  {
3230  /* H2 formation on grains from
3231  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29 */
3232  /* number of monolayers per second - only affects efficiency at very low or high temperatures */
3233  double f = 1e-10;
3234  /* equation 17
3235  double sqrt_term = POW2( 1. + sqrt( (10000.-200.)/(600.-200.) ) );*/
3236  double sqrt_term = 35.399494936611667;
3237  double beta_alpha = 0.25 * sqrt_term * exp(-200./gv.bin[nd]->tedust);
3238  /* equation 16 */
3239  double xi = 1./ (1. + 1.3e13*exp(-1.5e4/gv.bin[nd]->tedust)*sqrt_term/(2.*f) );
3240  /* expression for beta comes from just after equation 5 */
3241  double beta = 3e12 * exp(-320./gv.bin[nd]->tedust);
3242  /* recombination efficiency given by their equation 15, they call
3243  * this epsilon_H2 */
3244  double recombination_efficiency_CT02 = beta*xi / (beta + 0.0025*f + beta*beta_alpha);
3245 
3246  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3247  * so x/4 is projected area of circle */
3248  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3249  /* units s-1 */
3250  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3251  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_CT02;
3252  ASSERT( gv.bin[nd]->rate_h2_form_grains_CT02 >= 0. );
3253  }
3254 
3255  if( lgUseQHeat )
3256  {
3257  /* H2 formation on grains from
3258  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3259  ** >>refer H2 form Cazaux, S.; Tielens, A. G. G. M. 2010, 2010ApJ...715..698C
3260  ** improved treatment modifying CT rate above to include Eley-Rideal effect
3261  ** data and formalism comes from Appendix C of above reference
3262  ** this branch does quantum heating assuming rates simply scale as grain temperature */
3263  /* new rate variable ending stands for "Eley Rideal" */
3264 
3265  gv.bin[nd]->rate_h2_form_grains_ELRD= 0.;
3266 
3267  if( gv.bin[nd]->matType == MAT_CAR || gv.bin[nd]->matType == MAT_CAR2 ||
3268  gv.bin[nd]->matType == MAT_SIC || gv.bin[nd]->matType == MAT_PAH ||
3269  gv.bin[nd]->matType == MAT_PAH2 )
3270  {
3271  for( k=0; k < qnbin; k++ )
3272  {
3273  Td = qtemp[k];
3274 
3275  beta_alpha_ELRD = exp(-800./Td) / (0.5389970511202651 * exp(-540./Td) + 5.6333909478365e-14*sqrt(Td) ) ;
3276  xi_ELRD= 1./(1. + 4.61e24*sexp(45000./Td));
3277  recombination_efficiency_ELRD= (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3278  sticking_probability_H = 1./(1. + 0.04*sqrt(Td+phycon.te) +
3279  0.002*phycon.te + 8e-6*phycon.te*phycon.te);
3280 
3281  gv.bin[nd]->rate_h2_form_grains_ELRD+= qprob[k] * sticking_probability_H *
3282  recombination_efficiency_ELRD;
3283  }
3284 
3285  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3286  ** so x/4 is projected area of circle */
3287  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3288  /* gv.bin[nd]->rate_h2_form_grains_ELRD units s-1 */
3289 
3290  gv.bin[nd]->rate_h2_form_grains_ELRD*= 0.5 * AveVelH *
3291  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3292 
3293  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD> 0. );
3294  }
3295 
3296  else if( gv.bin[nd]->matType == MAT_SIL || gv.bin[nd]->matType == MAT_SIL2 )
3297  {
3298  for( k=0; k < qnbin; k++ )
3299  {
3300  Td = qtemp[k];
3301 
3302  beta_alpha_ELRD = exp(-450./Td) / (0.4266153643741715*exp(-340./Td) + 2.5335919594255e-14*sqrt(Td) ) ;
3303  xi_ELRD= 1./(1. + 7.00e24*sexp(45000./Td));
3304  recombination_efficiency_ELRD= (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3305  sticking_probability_H = 1./(1. + 0.04*sqrt(Td+phycon.te) +
3306  0.002*phycon.te + 8e-6*phycon.te*phycon.te);
3307 
3308  gv.bin[nd]->rate_h2_form_grains_ELRD+= qprob[k] * sticking_probability_H *
3309  recombination_efficiency_ELRD;
3310  }
3311 
3312  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3313  ** so x/4 is projected area of circle */
3314  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3315  /* gv.bin[nd]->rate_h2_form_grains_ELRD units s-1 */
3316  gv.bin[nd]->rate_h2_form_grains_ELRD*= 0.5 * AveVelH *
3317  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3318 
3319  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD> 0. );
3320  }
3321  }
3322  else
3323  {
3324  /* H2 formation on grains from
3325  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3326  ** improved treatment modifying CT rate above to include Eley-Rideal effect
3327  ** data and formalism comes from Appendix C of above reference */
3328  /* new rate variable ending stands for "Eley Rideal" */
3329  gv.bin[nd]->rate_h2_form_grains_ELRD= 0.;
3330 
3331  if( gv.bin[nd]->matType == MAT_CAR || gv.bin[nd]->matType == MAT_CAR2 ||
3332  gv.bin[nd]->matType == MAT_SIC || gv.bin[nd]->matType == MAT_PAH ||
3333  gv.bin[nd]->matType == MAT_PAH2 )
3334  {
3335  Td = gv.bin[nd]->tedust;
3336 
3337  beta_alpha_ELRD = exp(-800./Td) / (0.5389970511202651 * exp(-540./Td) + 5.6333909478365e-14*sqrt(Td) ) ;
3338  xi_ELRD= 1./(1. + 4.61e24*sexp(45000./Td));
3339  recombination_efficiency_ELRD = (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3340 
3341  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3342  ** so x/4 is projected area of circle */
3343  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3344  /* units s-1 */
3345  gv.bin[nd]->rate_h2_form_grains_ELRD = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3346  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_ELRD;
3347 
3348  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD > 0. );
3349  }
3350 
3351  else if( gv.bin[nd]->matType == MAT_SIL || gv.bin[nd]->matType == MAT_SIL2 )
3352  {
3353  Td = gv.bin[nd]->tedust;
3354 
3355  beta_alpha_ELRD = exp(-450./Td) / (0.4266153643741715*exp(-340./Td) + 2.5335919594255e-14*sqrt(Td) ) ;
3356  xi_ELRD= 1./(1. + 7.00e24*sexp(45000./Td));
3357  recombination_efficiency_ELRD = (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3358 
3359  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3360  ** so x/4 is projected area of circle */
3361  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3362  /* units s-1 */
3363  gv.bin[nd]->rate_h2_form_grains_ELRD = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3364  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_ELRD;
3365 
3366  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD > 0. );
3367  }
3368  }
3369 
3371  {
3372  /* reset sticking probability for code below */
3373  sticking_probability_H = sticking_probability_H_func( phycon.te, gv.bin[nd]->tedust );
3374  }
3375 
3376  /* rate (s-1) all H2 v,J levels go to 0 or 1, preserving nuclear spin */
3377  /* ortho to para on grain surfaces, taken from
3378  *>refer H2 sticking Le Bourlot, J., 2000, A&A, 360, 656-662
3379  * >chng 05 apr 30, GS, hmi.H2_total/dense.gas_phase[ipHYDROGEN] is removed
3380  * This is used in h2.c.
3381  * NB IntArea is total are per H, not projected area, must div by 4
3382  * gv.bin[nd]->cnv_H_pCM3 has units H cm-3 to product with above
3383  * is cm2/H H/cm3 or cm-1 or an opacity
3384  * multiply by velocity of H2, cm s-1, so product
3385  * h2.rate_grain_op_conserve has units s^-1 */
3386  h2.rate_grain_op_conserve += AveVelH2 * gv.bin[nd]->IntArea/4. *
3387  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H;
3388 
3389  /* ortho to para on grain surfaces, taken from
3390  *>refer H2 sticking Le Bourlot, J., 2000, A&A, 360, 656-662
3391  * For all grain temperatures, this process corresponds to high J going to
3392  * either 0 or 1 preserving nuclear spin. All ortho go to 1 and para go to 0.
3393  * When the dust temperature is below Tcrit all 1 go to 0 and so all J go to 0.
3394 
3395  * this temperature depends on grain composition, discussion left column of page 657,
3396  * this is for a bare grain */
3405  /* AveVelH2 is average speed of H2 molecules
3406  * for now assume that sticking probability for H2 on the grain is equal to
3407  * that for H
3408  * efficiency factor efficiency_opr is vary fast function of t dust -
3409  * large at low Td and small at Td > T_ortho_para_crit
3410  * start evaluating just above the critical temperature
3411  * T_ortho_para_crit this is roughly 24.345 K,GS */
3412  T_ortho_para_crit = 2. * hmi.Tad / log( POW2(60. *1.1e11)*hmi.Tad);
3413  if( gv.bin[nd]->tedust < T_ortho_para_crit )
3414  {
3415  double efficiency_opr = sexp(60.*1.1e11*sqrt(hmi.Tad)*sexp(hmi.Tad/gv.bin[nd]->tedust));
3416  /* rate (s-1) all v,J levels go to 0, regardless of nuclear spin
3417  * see above discussion for how units work out */
3418  h2.rate_grain_J1_to_J0 += AveVelH2 * gv.bin[nd]->IntArea/4. *
3419  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * efficiency_opr;
3420  }
3421  }
3422  /*fprintf(ioQQQ," H2 grain form rate HM79 %.2e %.2e CT02 %.2e %.2e O-P grn %.2e %.2e\n",
3423  gv.bin[nd]->rate_h2_form_grains_HM79 ,
3424  gv.bin[nd]->rate_h2_form_grains_HM79 ,
3425  gv.bin[nd]->rate_h2_form_grains_CT02 ,
3426  gv.bin[nd]->rate_h2_form_grains_CT02 ,
3427  h2.rate_grain_J1_to_J0,
3428  hmi.rate_h2_allX_2_J1_grains
3429  );*/
3430  /* options to turn off grain collision with atom h2 collisions grains off command */
3433 
3434  }
3435  else
3436  {
3437  /* grains are not enabled, set these to zero */
3438  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3439  {
3440  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.;
3441  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.;
3442  }
3443  /* rate all H2 goes to either 0 or 1 depending on ortho/para */
3445  /* at low temp, rate all H2 goes to J=0 */
3446  h2.rate_grain_J1_to_J0 = 0.;
3447  }
3448 
3449  /* the H2 catalysis rate on grains that is actually used in calculations
3450  * hmi.ScaleJura is scale factor set with set Jura scale command
3451  * units are s-1
3452  * default is 'C' Cazaux & Tielens */
3454  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3455  {
3456  if( hmi.chJura == 'C' )
3457  {
3458  /* use the new rate by
3459  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29
3460  * units are s-1*/
3461  gv.bin[nd]->rate_h2_form_grains_used =
3462  gv.bin[nd]->rate_h2_form_grains_CT02*hmi.ScaleJura;
3463  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3464  }
3465 
3466  if( hmi.chJura == 'E' )
3467  {
3468  /* use the new revised CT02 rate from
3469  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3470  ** units are s-1 */
3471  gv.bin[nd]->rate_h2_form_grains_used =
3472  gv.bin[nd]->rate_h2_form_grains_ELRD*hmi.ScaleJura;
3473  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3474  }
3475 
3476  else if( hmi.chJura == 'T' )
3477  {
3478  /* rate from Hollenbach & McKee 1979 */
3479  gv.bin[nd]->rate_h2_form_grains_used =
3480  gv.bin[nd]->rate_h2_form_grains_HM79*hmi.ScaleJura;
3481  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3482  }
3483  else if( hmi.chJura == 'S' )
3484  {
3485  /* H2 formation rate from
3486  * >>refer H2 form Sternberg, A. & Neufeld, D.A. 1999, ApJ, 516, 371 */
3487  gv.bin[nd]->rate_h2_form_grains_used =
3488  3e-18 * phycon.sqrte / gv.bin.size() * dense.gas_phase[ipHYDROGEN]*hmi.ScaleJura;
3489  /* this is simple rate from Sternberg & Neufeld 99 */
3490  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3491  }
3492  /*>>chng 07 jan 10, this had been C for constant, and so could never have been triggered.
3493  * caught by robin Williams, fixed by nick Abel, error was in sense that any set jura rate
3494  * would use Cazaux & Tielens */
3495  else if( hmi.chJura == 'F' )
3496  {
3497  /* command "set H2 rate" - enters log of Jura rate - C for constant,
3498  * no dependence on grain properties */
3499  gv.bin[nd]->rate_h2_form_grains_used = hmi.rate_h2_form_grains_set*dense.gas_phase[ipHYDROGEN] / gv.bin.size();
3500  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3501  }
3502  }
3504 
3506  {
3507  fprintf(ioQQQ, " fnzone %.2f H2 rate %.4e\n", fnzone, gv.rate_h2_form_grains_used_total );
3508  }
3509 
3510  /* print rate coefficient */
3511  /*fprintf(ioQQQ," total grain h2 form rate %.3e\n",gv.rate_h2_form_grains_used_total);*/
3512 
3513 }
3514 /*mole_h_reactions update mole reactions for H */
3516 {
3517  static double teused=-1;
3518  double exph2,
3519  exph2s,
3520  exphp,
3521  ex3hp;
3522  long i;
3523  double h2esc,
3524  th2,
3525  cr_H2s ,
3526  cr_H2dis,
3527  cr_H2dis_ELWERT_H2g,
3528  cr_H2dis_ELWERT_H2s;
3529 
3530  DEBUG_ENTRY( "mole_h_reactions()" );
3531 
3532  /* everything here depends only on temperature - don't do anything if we don't
3533  * need to */
3534 
3535  bool need_update = ! fp_equal( phycon.te, teused );
3536 
3537  if( need_update )
3538  {
3539  teused = phycon.te;
3540 
3541  /* get LTE populations */
3542  /* related to population of H- in LTE
3543  * IP is 0.754 eV */
3544  hmi.exphmi = sexp(8.745e3/phycon.te);
3545  if( hmi.exphmi > 0. )
3546  {
3547  /* these are ratio n*(H-)/[ n*(ne) n*(Ho) ] */
3548  hmi.rel_pop_LTE_Hmin = SAHA/(phycon.te32*hmi.exphmi)*(1./(2.*2.));
3549  }
3550  else
3551  {
3552  hmi.rel_pop_LTE_Hmin = 0.;
3553  }
3554 
3555  /* population of H2+ in LTE, hmi.rel_pop_LTE_H2p is H_2+/H / H+
3556  * dissociation energy is 2.647 */
3557  exphp = sexp(3.072e4/phycon.te);
3558  if( exphp > 0. )
3559  {
3560  /* stat weight of H2+ is 4
3561  * last factor was put in ver 85.23, missing before */
3562  hmi.rel_pop_LTE_H2p = SAHA/(phycon.te32*exphp)*(4./(2.*1.))*3.634e-5;
3563  }
3564  else
3565  {
3566  hmi.rel_pop_LTE_H2p = 0.;
3567  }
3568 
3569  /* related to population of H3+ in LTE, hmi.rel_pop_LTE_H3p is H_3+/( H2+ H+ )
3570  * dissociation energy is 2.647 */
3571  ex3hp = sexp(1.882e4/phycon.te);
3572  if( ex3hp > 0. )
3573  {
3574  /* stat weight of H2+ is 4
3575  * last factor was put in ver 85.23, missing before */
3576  hmi.rel_pop_LTE_H3p = SAHA/(phycon.te32*ex3hp)*(4./(2.*1.))*3.634e-5;
3577  }
3578  else
3579  {
3580  hmi.rel_pop_LTE_H3p = 0.;
3581  }
3582  }
3583  /* end constant temperature - */
3584 
3585  // Big H2 rates are dependent on population as well as temperature
3586  /* population of H2 in LTE
3587  * dissociation energy of H2g is 4.477eV, for TH85 model */
3588  /* >>chng 05 oct 17, GS, averaged in big H2 in order to consider correct statistical weight*/
3590  {
3591  /* the terms on the right were computed in the large molecule */
3594  }
3595  else
3596  {
3597  if (need_update)
3598  {
3599  /* H2 ground */
3600  exph2 = sexp((5.195e4)/phycon.te);
3601  /* >>chng 05 oct 17, GS, note that statical weight of H2g is assumed to be 1 if big H2 is not turned on*/
3602 
3603  if( exph2 > 0. )
3604  {
3605  /* >>chng 05 oct 17, GS, note that statical weight of H2g is assumed to be 1 if big H2 is not turned on*/
3606  hmi.rel_pop_LTE_H2g = SAHA/(phycon.te32*exph2)*(1./(2.*2.))*3.634e-5;
3607  }
3608  else
3609  {
3610  hmi.rel_pop_LTE_H2g = 0.;
3611  }
3612 
3613  /* H2 star */
3614  /* population of H2s in LTE
3615  * dissociation energy is 1.877eV, if h2s = 2.6eV, assumed for TH85 model */
3616  /* >>chng 05 oct 17, GS, averaged in big H2 in order to consider correct statistical weight*/
3617  exph2s = sexp(2.178e4/phycon.te);
3618 
3619  if( exph2s > 0. )
3620  {
3621  /* >>chng 05 oct 17, GS, note that statical weight of H2s is assumed to be 1 if big H2 is not turned on*/
3622  hmi.rel_pop_LTE_H2s = SAHA/(phycon.te32*exph2s)*(1./(2.*2.))*3.634e-5;
3623  }
3624  else
3625  {
3626  hmi.rel_pop_LTE_H2s = 0.;
3627  }
3628  }
3629  }
3630  {
3631  /*@-redef@*/
3632  /* often the H- route is the most efficient formation mechanism for H2,
3633  * will be through rate called Hmolec_old[ipMH]*hmi.assoc_detach
3634  * this debug print statement is to trace h2 oscillations */
3635  enum {DEBUG_LOC=false};
3636  /*@+redef@*/
3637  if( DEBUG_LOC && nzone>187&& iteration > 1)
3638  {
3639  /* rapid increase in H2 density caused by rapid increase in hmi.rel_pop_LTE_H2g */
3640  fprintf(ioQQQ,"ph2lteee\t%.2e\t%.1e\t%.1e\n",
3642  sexp(2.178e4/phycon.te),
3643  phycon.te);
3644  }
3645  }
3646 
3647  /* cooling due to radiative attachment */
3648  hmi.hmicol = hmirat(phycon.te)*EN1RYD*phycon.te*1.15e-5;
3649 
3650  fixit("Wasted cycles if we don't use Stancil's rates below? Why not put this down there/if used?");
3651  for( diatom_iter diatom = diatoms.begin(); diatom != diatoms.end(); ++diatom )
3652  {
3653  if( (*diatom)->lgEnabled && mole_global.lgStancil )
3654  (*diatom)->Mol_Photo_Diss_Rates();
3655  }
3656 
3657  /*fprintf(ioQQQ,"%.2e %.2e %.2e %.2e\n", phycon.te, hmi.hminus_rad_attach , hmi.hmicol,
3658  hmi.hmicol/(hmi.hminus_rad_attach*EN1RYD*phycon.te*1.15e-5) );*/
3659 
3660  /* get per unit vol */
3661  hmi.hmicol *= dense.eden*findspecieslocal("H")->den; /* was dense.xIonDense[ipHYDROGEN][0]; */
3662 
3663  /* ================================================================= */
3664  /* evaluate H- photodissociation rate, induced rec and rec cooling rates */
3665  /* >>chng 00 dec 24, add test so that photo rate only reevaluated two times per zone.
3666  * in grain-free models this was sometimes dominated by Lya and so oscillated.
3667  * especially bad in primal.in - change 2 to 4 and primal.in will stop due to Lya oscil */
3670  /* >>chng 02 feb 16, add damper on H- photo rate, wild oscillations in Lya photo rate in
3671  * grain free models */
3672 
3673  t_phoHeat photoHeat;
3674 
3675  /*hmi.HMinus_photo_rate = GammaBn( hmi.iphmin, nhe1Com.nhe1[0] , opac.iphmop ,
3676  HMINUSIONPOT , &hmi.HMinus_induc_rec_rate , &hmi.HMinus_induc_rec_cooling );*/
3678  HMINUSIONPOT , &hmi.HMinus_induc_rec_rate , &hmi.HMinus_induc_rec_cooling, &photoHeat );
3679 
3680  /* save H- photodissociation heating */
3681  hmi.HMinus_photo_heat = photoHeat.HeatNet;
3682 
3683  {
3684  /* following should be set true to print populations */
3685  /*@-redef@*/
3686  enum {DEBUG_LOC=false};
3687  /*@+redef@*/
3688  if( DEBUG_LOC)
3689  {
3690  fprintf(ioQQQ,"hminphoto\t%li\t%li\t%.2e\n", nzone, conv.nPres2Ioniz , hmi.HMinus_photo_rate );
3691  }
3692  }
3693 
3694  /* induced recombination */
3696 
3697  /* induced recombination cooling per unit volume */
3699  hmi.HMinus_induc_rec_cooling *= hmi.rel_pop_LTE_Hmin*dense.eden*findspecieslocal("H")->den; /* dense.xIonDense[ipHYDROGEN][0]; */
3700 
3701  {
3702  /* following should be set true to debug H- photoionization rates */
3703  /*@-redef@*/
3704  enum {DEBUG_LOC=false};
3705  /*@+redef@*/
3706  if( DEBUG_LOC && nzone>400/*&& iteration > 1*/)
3707  {
3708  fprintf(ioQQQ,"hmoledebugg %.2f ",fnzone);
3709  GammaPrt(
3710  hmi.iphmin-1 , iso_sp[ipHE_LIKE][ipHELIUM].fb[0].ipIsoLevNIonCon , opac.iphmop ,
3711  /* io unit we will write to */
3712  ioQQQ,
3713  /* total photo rate from previous call to GammaK */
3715  /* we will print contributors that are more than this rate */
3716  hmi.HMinus_photo_rate*0.05);
3717  }
3718  }
3719  /* add on high energy ionization, assume hydrogen cross section
3720  * n.b.; HGAMNC with secondaries */
3721  /* >>chng 00 dec 24, above goes to HeI edge, no need for this, and was not important*/
3722  /*hmi.HMinus_photo_rate += iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH1s].gamnc;*/
3723 
3724  /* ================================================================= */
3725  /* photodissociation by Lyman band absorption: esc prob treatment,
3726  * treatment based on
3727  * >>refer HI abs Tielens & Hollenbach 1985 ApJ 291, 722. */
3728  /* do up to carbon photo edge if carbon is turned on */
3729  /* >>>chng 00 apr 07, add test for whether element is turned on */
3731  /* >>chng 00 apr 07 from explicit ipHeavy to ipLo */
3732  /* find total intensity over carbon-ionizing continuum */
3733  /* >>chng 03 jun 09, use exact bounds rather than CI photo threshold for lower bound */
3734  /*for( i=ipLo; i < iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH1s].ipIsoLevNIonCon; i++ )*/
3735  /* the integral is from 6eV to 13.6, or 2060 - 912 Ang */
3736  for( i=rfield.ipG0_TH85_lo; i < rfield.ipG0_TH85_hi; ++i )
3737  {
3739  (rfield.outlin[0][i-1])+ (rfield.outlin_noplot[i-1]))*rfield.anu(i-1);
3740  }
3741 
3742  /* now convert to Habing ISM units
3743  * UV_Cont_rel2_Habing_TH85_face is FUV continuum relative to Habing value
3744  * 1.6e-3 ergs em-2 s-1 is the Habing 1968 field, quoted on page 723, end of first
3745  * full paragraph on left */
3747  /* if start of calculation remember G0 at illuminated face */
3748  if( nzone<=1 )
3749  {
3751  }
3752 
3753 
3754  /* >>chng 05 jan 09, add special ver of G0 */
3756  for( i=rfield.ipG0_spec_lo; i < rfield.ipG0_spec_hi; ++i )
3757  {
3759  rfield.outlin[0][i-1]+ rfield.outlin_noplot[i-1])*rfield.anu(i-1);
3760  }
3762 
3763  /* the Draine & Bertoldi version of the same thing, defined over their energy range */
3764  /* >>chng 04 feb 07, only evaluate at the illuminated face */
3765  if( !conv.nTotalIoniz )
3766  {
3768  /* this is sum of photon number between 912A and 1110, as per BD96 */
3769  for( i=rfield.ipG0_DB96_lo; i < rfield.ipG0_DB96_hi; ++i )
3770  {
3772  rfield.outlin[0][i-1]+ rfield.outlin_noplot[i-1]);
3773  }
3774  /* Convert into scaled ISM background field, total number of photons over value for 1 ISM field,
3775  * the coefficient 1.232e7 is the number of photons over this wavelength range for 1H and is
3776  * given in BD96, page 225, 4th line from start of section 4, also page 272, table 1, 2nd line
3777  * from bottom */
3778  /* >>chng 04 mar 16, introduce the 1.71 */
3779  /* equation 20 of DB96 gives chi as flux over 1.21e7, to produce one Habing field.
3780  * to get the Draine field we need to further divide by 1.71 as stated on the first
3781  * line after equation 23 */
3783  }
3784 
3785  /* escape prob takes into account line shielding,
3786  * next is opacity then optical depth in H2 UV lines, using eqn A7 of TH85 */
3788  /* the typical Lyman -Werner H2 line optical depth eq A7 of TH85a */
3789  th2 = (findspecieslocal("H2")->column+ findspecieslocal("H2*")->column)*hmi.H2Opacity;
3790  /* the escape probability - chance that continuum photon will penetrate to
3791  * this depth to pump the Lyman Werner bands */
3792  h2esc = esc_PRD_1side(th2,1e-4);
3793 
3794  /* cross section is eqn A8 of
3795  * >>refer H2 dissoc Tielens, A.G.G.M., & Hollenbach, D., 1985, ApJ, 291, 722
3796  * branching ratio of 10% is already included, so 10x smaller than their number
3797  * 10% lead to dissociation through H_2 + h nu => 2H */
3798  /* >>chng 05 mar 10, by TE, break into 2g and 2s
3799  * note use of same shielding column in below - can do far better */
3803 
3804  /* these are Burton et al. 1990 rates */
3808 
3809  {
3810  /* the following implements Drain & Bertoldi 1996, equation 37 from
3811  * >>refer H2 destruction Draine, B.T., & Bertoldi, F., 1996, ApJ, 468, 269-289
3812  * but the constant 4.6e-11 comes from Bertoldi & Draine equation 23,
3813  * this is the normalized H2 column density */
3814  double x = (findspecieslocal("H2")->column+findspecieslocal("H2*")->column) / 5e14;
3815  double sqrtx = sqrt(1.+x);
3816  /* Doppler with of H2 in km/s */
3817  double b5 = GetDopplerWidth(2.f*dense.AtomicWeight[ipHYDROGEN])/1e5;
3818  /* the molecular hydrogen line self-shielding factor */
3819  double fshield = 0.965/POW2(1.+x/b5) + 0.035/sqrtx *
3820  sexp(8.5e-4*sqrtx);
3821 
3822  /*double fshield = pow( MAX2(1.,colden.colden[ipCOLH2]/1e14) , -0.75 );*/
3823  /* this is the Bertoldi & Draine version of the Habing field,
3824  * with dilution of radiation and extinction due to grains */
3825  /* >>chng 04 apr 18, moved fshield, the line shielding factor, from this defn to
3826  * the following defn of dissociation rate, since following should measure continuum */
3829 
3830  /* the following comes from Bertoldi & Draine 1996, equation 23,
3831  * hmi.UV_Cont_rel2_Draine_DB96_depth already includes a factor of 1.71 to correct back from TH85 */
3832  /* >>chng 05 mar 10, TE, break into 2s and 2s */
3833  if( !mole_global.lgLeidenHack )
3834  {
3835  /* this is default, when set Leiden hack UMIST rates not entered */
3838  }
3839  else
3840  {
3841  /* done when set Leiden hack UMIST rates command entered */
3843  *sexp(3.02*rfield.extin_mag_V_point)* fshield;
3845  *sexp(3.02*rfield.extin_mag_V_point)* fshield;
3846  }
3847 
3848  /* BD do not give an excitation rate, so used 9 times the dissociation
3849  * rate by analogy with 90% going back into X, as per TH85 */
3850  /*>>chng 04 feb 07, had used 90% relax into X from TH85,
3851  * BD say that 15% dissociate, so 85/15 = 5.67 is factor */
3853  }
3854 
3855  /* do Elwert approximation to the dissociation rate */
3857  {
3858  /* this evaluates the new H2 dissociation rate by Torsten Elwert */
3859  /* chng 05 jun 23, TE
3860  * >>chng 05 sep 13, update master source with now approximation */
3861 
3862  /* Doppler with of H2 in km/s */
3863  double b5 = GetDopplerWidth(2.f*dense.AtomicWeight[ipHYDROGEN])/1e5;
3864 
3865  /* split the Solomon rates in H2g and H2s */
3866  /* >>chng 05 oct 19,
3867  * >>chng 05 dec 05, TE, define new approximation for the heating due to the destruction of H2
3868  * use this approximation for the specified cloud parameters, otherwise
3869  * use limiting cases for 1 <= G0, G0 >= 1e7, n >= 1e7, n <= 1 */
3870 
3871  double x_H2g, x_H2s,
3872  fshield_H2g, fshield_H2s,
3873  f_H2s;
3874  static double a_H2g, a_H2s,
3875  e1_H2g, e1_H2s,
3876  e2_H2g,
3877  b_H2g,
3878  sl_H2g, sl_H2s,
3879  k_f_H2s,
3880  k_H2g_to_H2s,
3881  log_G0_face = -1;
3882 
3883  /* define parameter range for the new approximation
3884  * test for G0
3885  *BUGFIX - this tested on lg_G0_face < 0 for initialization needed so did not work
3886  * in grids - change to evaluate in zone 0 */
3887  /* >>chng 07 feb 24, BUGFIX crash when G0=0 at start and radiation
3888  * field builds up due to diffuse fields - soln is to always reevaluate */
3889  /*if( !nzone )*/
3890  {
3892  {
3893  log_G0_face = 0.;
3894  }
3895  else if(hmi.UV_Cont_rel2_Draine_DB96_face >= 1e7)
3896  {
3897  log_G0_face = 7.;
3898  }
3899  else
3900  {
3901  log_G0_face = log10(hmi.UV_Cont_rel2_Draine_DB96_face);
3902  }
3903 
3904  /* terms only dependent on G0_face */
3905 
3906  /* coefficients and exponents */
3907  a_H2g = 0.06 * log_G0_face + 1.32;
3908  a_H2s = 0.375 * log_G0_face + 2.125;
3909 
3910  e1_H2g = -0.05 * log_G0_face + 2.25;
3911  e1_H2s = -0.125 * log_G0_face + 2.625;
3912 
3913  e2_H2g = -0.005 * log_G0_face + 0.625;
3914 
3915  b_H2g = -4.0e-3 * log_G0_face + 3.2e-2;
3916 
3917  /* scalelength for H2g and H2s */
3918  sl_H2g = 4.0e14;
3919  sl_H2s = 9.0e15;
3920 
3921  /* coefficient for 2nd term of Solomon H2s */
3922  k_f_H2s = MAX2(0.1,2.375 * log_G0_face - 1.875 );
3923 
3924  /* coefficient for branching ratio */
3925  k_H2g_to_H2s = MAX2(1.,-1.75 * log_G0_face + 11.25);
3926 
3927  /*fprintf( ioQQQ, "e1_H2g%.2e, e1_H2s%.2e, e2_H2g%.2e, b_H2g%.2e, a_H2g%.2e, a_H2s%.2e,sl_H2g: %.2e,sl_H2s: %.2e\n",
3928  e1_H2g, e1_H2s, e2_H2g, b_H2g, a_H2g, a_H2s, sl_H2g, sl_H2s);
3929  */
3930  }
3931 
3932  /* Solomon H2s ~G0^0.2 at large depth*/
3933  f_H2s = k_f_H2s * pow((double)hmi.UV_Cont_rel2_Draine_DB96_depth, 0.2 );
3934 
3935  /* scale length for absorption of UV lines */
3936  x_H2g = (findspecieslocal("H2")->column) / sl_H2g;
3937  x_H2s = (findspecieslocal("H2*")->column) / sl_H2s;
3938 
3939  /* the molecular hydrogen line self-shielding factor */
3940  fshield_H2g = 0.965/pow(1.+x_H2g/b5,e1_H2g) + b_H2g/pow(1.+x_H2g/b5,e2_H2g);
3941  fshield_H2s = 0.965/pow(1.+x_H2s/b5,e1_H2s);
3942 
3943  /* the Elwert Solomon rates for H2g and H2s hmi.chH2_small_model_type == 'E' */
3944  hmi.H2_Solomon_dissoc_rate_ELWERT_H2g = a_H2g * 4.6e-11 * fshield_H2g * hmi.UV_Cont_rel2_Draine_DB96_depth;
3945  hmi.H2_Solomon_dissoc_rate_ELWERT_H2s = a_H2s * 4.6e-11 * fshield_H2s * (hmi.UV_Cont_rel2_Draine_DB96_depth + f_H2s);
3946 
3947  /* assume branching ratio dependent on G0*/
3949 
3950  /* use G0_BD96 as this definition declines faster with depth which is physical as
3951  * the longer wavelengths in the definition of G0_TH85 cannot dissociate
3952  * H2s directly */
3955  }
3956  else
3957  {
3962  }
3963 
3964  /* this is rate of photodissociation of H2*, A12 of TH85 */
3966 
3967  /* dissociation rate from Burton et al. 1990 */
3969 
3970  /* rates for cosmic ray excitation of singlet bound electronic bound excited states
3971  * only add this to small molecule since automatically included in large
3972  *>>refer H2 cr excit Dalgarno, A., Yan, Min, & Liu, Weihong 1999, ApJS, 125, 237
3973  * this is excitation of H2* */
3974  /* >>chng 05 sep 13, do not include this process when Leiden hacks are in place */
3975  cr_H2s = secondaries.x12tot*0.9 / 2. * hmi.lgLeidenCRHack;
3976  /* this is the fraction that dissociate */
3977  /* >>chng 05 sep 13, do not include this process when Leiden hacks are in place */
3978  cr_H2dis = secondaries.x12tot*0.1 / 2. * hmi.lgLeidenCRHack;
3979 
3980  /* >>chng 05 sep 13, TE, synchronize treatment of CR */
3981  /* cosmic ray rates for dissociation of ground and H2s
3982  * two factors done to agree with large H2 deep in the cloud where
3983  * cosmic rays are important */
3984  cr_H2dis_ELWERT_H2g = secondaries.x12tot*5e-8 * hmi.lgLeidenCRHack;
3985  cr_H2dis_ELWERT_H2s = secondaries.x12tot*4e-2 * hmi.lgLeidenCRHack;
3986 
3987  /* at this point there are two or three independent estimates of the H2 dissociation rate.
3988  * if the large H2 molecule is on, then H2 Solomon rates has been defined in the last
3989  * call to the large molecule. Just above we have defined hmi.H2_Solomon_dissoc_rate_TH85,
3990  * the dissociation rate from Tielens & Hollenbach 1985, and hmi.H2_Solomon_dissoc_rate_BD96,
3991  * the rate from Bertoldi & Draine 1996. We can use any defined rate. If the big H2
3992  * molecule is on, use its rate. If not, for now use the TH85 rate, since that is the
3993  * rate we always have used in the past.
3994  * The actual rate we will use is given by hmi.H2_Solomon_dissoc_rate_used
3995  */
3996  /* this is the Solomon process dissociation rate actually used */
3998  {
3999  /* only update after big H2 molecule has been evaluated,
4000  * when very little H2 and big molecule not used, leave at previous (probably TH85) value,
4001  * since that value is always known */
4002 
4003  /* Solomon process rate from X into the X continuum with units s-1
4004  * rates are total rate, and rates from H2g and H2s */
4007 
4010 
4011  /* photoexcitation from H2g to H2s */
4014 
4015  /* add up H2s + hnu (continuum) => 2H + KE, continuum photodissociation,
4016  * this is not the Solomon process, true continuum, units s-1 */
4017  /* only include rates from H2s since this is only open channel, this process is well
4018  * shielded against Lyman continuum destruction by atomic hydrogen */
4020  /* NPA - 07/24/09 - logic to use Stancil photodissociation rate for H2s */
4024 
4025  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4026  * for unfavorable wavelength range of G0*/
4028  /* NPA - 07/24/09 - logic to use Stancil photodissociation rate for H2g */
4032  }
4033  else if( hmi.chH2_small_model_type == 'T' )
4034  {
4035  /* the TH85 rate */
4036  /*>>chng 05 jun 23, add cosmic rays */
4038  /* >>chng 05 sep 13, cr_H2dis was not included */
4041 
4042  /* continuum photodissociation H2s + hnu => 2H, ,
4043  * this is not the Solomon process, true continuum, units s-1 */
4045  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4046  * for unfavorable wavelength range of G0*/
4048  }
4049 
4050  else if( hmi.chH2_small_model_type == 'H' )
4051  {
4052  /* the improved H2 formalism given by
4053  *>>refer H2 dissoc Burton, M.G., Hollenbach, D.J. & Tielens, A.G.G.M
4054  >>refcon 1990, ApJ, 365, 620 */
4056  /* >>chng 05 sep 13, cr_H2dis was not included */
4059 
4060  /* continuum photodissociation H2s + hnu => 2H, ,
4061  * this is not the Solomon process, true continuum, units s-1 */
4063  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4064  * for unfavorable wavelength range of G0*/
4066  }
4067 
4068  else if( hmi.chH2_small_model_type == 'B' )
4069  {
4070  /* the Bertoldi & Draine rate - this is the default */
4071  /*>>chng 05 jun 23, add cosmic rays */
4073  /* >>chng 05 sep 13, cr_H2dis was not included */
4075  /* they did not do the excitation or dissoc rate, so use TH85 */
4077 
4078 
4079  /* continuum photodissociation H2s + hnu => 2H, ,
4080  * this is not the Solomon process, true continuum, units s-1 */
4082  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4083  * for unfavorable wavelength range of G0*/
4085  }
4086  else if( hmi.chH2_small_model_type == 'E' )
4087  {
4088  /* the Elwert et al. rate
4089  *>>chng 05 jun 23, add cosmic rays */
4093 
4094 
4095  /* continuum photodissociation H2s + hnu => 2H, ,
4096  * this is not the Solomon process, true continuum, units s-1 */
4099  }
4100  else
4101  TotalInsanity();
4102 
4103  {
4104  /*@-redef@*/
4105  enum {DEBUG_LOC=false};
4106  /*@+redef@*/
4107  if( DEBUG_LOC && h2.lgEnabled )
4108  {
4109  fprintf(ioQQQ," Solomon H2 dest rates: TH85 %.2e BD96 %.2e Big %.2e excit rates: TH85 %.2e Big %.2e\n",
4114  h2.gs_rate() );
4115  }
4116  }
4117 
4118  if( !hd.lgEnabled )
4120 
4121  return;
4122 }
4123 mole_reaction *mole_findrate_s(const char buf[])
4124 {
4125  DEBUG_ENTRY( "mole_findrate_s()" );
4126 
4127  string newbuf = canonicalize_reaction_label(buf);
4128 
4129  mole_reaction_i p = mole_priv::reactab.find(newbuf);
4130 
4131  if(p != mole_priv::reactab.end())
4132  return &(*p->second);
4133  else
4134  return NULL;
4135 }
4136 
4137 double t_mole_local::findrk(const char buf[]) const
4138 {
4139  DEBUG_ENTRY( "t_mole_local::findrk()" );
4140 
4141  mole_reaction *rate = mole_findrate_s(buf);
4142 
4143  if(!rate)
4144  return 0.;
4145 
4146  /* check for NaN */
4147  ASSERT( !isnan( reaction_rks[ rate->index ] ) );
4148 
4149  return reaction_rks[ rate->index ];
4150 }
4151 double t_mole_local::findrate(const char buf[]) const
4152 {
4153  double ret;
4154  int i;
4155 
4156  DEBUG_ENTRY( "t_mole_local::findrate()" );
4157 
4158  mole_reaction *rate = mole_findrate_s(buf);
4159  if(!rate)
4160  {
4161  return 0.;
4162  }
4163 
4164  ret = reaction_rks[ rate->index ];
4165  for(i=0;i<rate->nreactants;i++)
4166  ret *= species[ rate->reactants[i]->index ].den;
4167 
4168  return ret;
4169 }
4170 /* Calculate rate at which molecular network abstracts species */
4171 
4172 /* Need to check reactants vs reactant behaviour */
4173 double t_mole_local::sink_rate_tot(const char chSpecies[]) const
4174 {
4175  DEBUG_ENTRY( "t_mole_local::sink_rate_tot()" );
4176 
4177  const molecule* const sp = findspecies(chSpecies);
4178  double ratev = sink_rate_tot(sp);
4179 
4180  return ratev;
4181 }
4182 double t_mole_local::sink_rate_tot(const molecule* const sp) const
4183 {
4184  DEBUG_ENTRY( "t_mole_local::sink_rate_tot()" );
4185  double ratev = 0;
4186 
4187  for(mole_reaction_i p=mole_priv::reactab.begin();
4188  p != mole_priv::reactab.end(); ++p)
4189  {
4190  mole_reaction &rate = *p->second;
4191  ratev += sink_rate( sp, rate );
4192  }
4193 
4194  return ratev;
4195 }
4196 
4197 double t_mole_local::sink_rate(const molecule* const sp, const char buf[]) const
4198 {
4199  const mole_reaction* const rate = mole_findrate_s(buf);
4200  return sink_rate( sp, *rate );
4201 }
4202 
4203 double t_mole_local::sink_rate(const molecule* const sp, const mole_reaction& rate) const
4204 {
4205  DEBUG_ENTRY( "t_mole_local::sink_rate()" );
4206 
4207  int ipthis = -1;
4208  for(int i=0;i<rate.nreactants && ipthis == -1;i++)
4209  {
4210  if(rate.reactants[i] == sp && rate.rvector[i]==NULL && rate.rvector_excit[i]==NULL )
4211  {
4212  ipthis = i;
4213  }
4214  }
4215  if(ipthis != -1)
4216  {
4217  double ratevi = rate.a * rate.rk();
4218  for(int i=0;i<rate.nreactants;i++)
4219  {
4220  if(i!=ipthis)
4221  {
4222  ratevi *= species[ rate.reactants[i]->index ].den;
4223  }
4224  }
4225  return ratevi;
4226  }
4227  else
4228  return 0.;
4229 }
4230 
4232 double t_mole_local::dissoc_rate(const char chSpecies[]) const
4233 {
4234  DEBUG_ENTRY( "t_mole_local::dissoc_rate()" );
4235 
4236  molecule *sp = findspecies(chSpecies);
4237  if (sp == null_mole)
4238  return 0.0;
4239  ASSERT(sp->isMonatomic());
4240  const chem_nuclide *tgt = sp->nNuclide.begin()->first.get_ptr();
4241  molecule *ph = findspecies("PHOTON");
4242  double ratev = 0.0;
4243 
4244  for (mole_reaction_i p
4245  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4246  {
4247  mole_reaction &rate = *p->second;
4248 
4249  // Must have a photon in to be a dissociation rate
4250  int ipph = 0;
4251  for (int i=0;i<rate.nreactants;i++)
4252  {
4253  if (rate.reactants[i] == ph)
4254  ipph++;
4255  }
4256  if (!ipph)
4257  continue;
4258 
4259  // ipsp is number of *specific* species of interest,
4260  // ipfree is number in same ionization ladder, including X-
4261  int ipspin = 0, ipfreein = 0;
4262  for (int i=0;i<rate.nreactants;i++)
4263  {
4264  if (rate.reactants[i] == sp)
4265  ++ipspin;
4266  if (rate.reactants[i]->isMonatomic() && tgt == sp->nNuclide.begin()->first.get_ptr())
4267  ++ipfreein;
4268  }
4269  int ipspout = 0, ipfreeout = 0;
4270  for (int i=0;i<rate.nproducts;i++)
4271  {
4272  if (rate.products[i] == sp)
4273  ++ipspout;
4274  if (rate.products[i]->isMonatomic() && tgt == sp->nNuclide.begin()->first.get_ptr())
4275  ++ipfreeout;
4276  }
4277 
4278  // Must produce the species requested
4279  int newsp = ipspout-ipspin;
4280  if (newsp <= 0)
4281  continue;
4282 
4283  // And must do so by breaking bonds
4284  int nbondsbroken = ipfreeout-ipfreein;
4285  if (nbondsbroken <= 0)
4286  continue;
4287  // Fraction of the generated monatomic species which were *originally* bound
4288  double fracbroken = nbondsbroken/((double)ipfreeout);
4289  ASSERT( fracbroken <= 1.0 );
4290 
4291  double ratevi = reaction_rks[ rate.index ];
4292  for (int i=0;i<rate.nreactants;i++)
4293  {
4294  ratevi *= species[ rate.reactants[i]->index ].den;
4295  }
4296 
4297  // Photoproduction rate is rate of production of the species
4298  // which has not come from an initially monatomic source
4299 
4300  double ratesp = ratevi*newsp; // This is the total production
4301  // rate of the specific species
4302  ratesp *= fracbroken; // Scale back for any initially unbound
4303  // monatoms
4304 
4305  ratev += ratesp;
4306  }
4307  return ratev;
4308 }
4309 double t_mole_local::source_rate_tot(const char chSpecies[]) const
4310 {
4311  DEBUG_ENTRY( "t_mole_local::source_rate_tot()" );
4312 
4313  molecule *sp = findspecies(chSpecies);
4314  double ratev = source_rate_tot(sp);
4315 
4316  return ratev;
4317 }
4318 double t_mole_local::source_rate_tot(const molecule* const sp) const
4319 {
4320  DEBUG_ENTRY( "t_mole_local::source_rate_tot()" );
4321  double ratev = 0;
4322 
4323  for (mole_reaction_i p =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4324  {
4325  mole_reaction &rate = *p->second;
4326  int ipthis = 0;
4327  for(int i=0;i<rate.nproducts;i++)
4328  {
4329  if( rate.products[i] == sp && rate.pvector[i]==NULL && rate.pvector_excit[i]==NULL )
4330  {
4331  ipthis++;
4332  }
4333  }
4334  if(ipthis)
4335  {
4336  double ratevi = rate.a * rate.rk();
4337  for(int i=0;i<rate.nreactants;i++)
4338  {
4339  ratevi *= species[ rate.reactants[i]->index ].den;
4340  }
4341  ratev += ipthis*ratevi;
4342  }
4343  }
4344 
4345  return ratev;
4346 }
4347 
4348 double t_mole_local::chem_heat(void) const
4349 {
4350  /* >>chng 07, Feb 11 NPA. Calculate the chemical heating rate. This is defined as the net energy of the
4351  * reaction, which is:
4352  *
4353  * Energy = SUM[formation energies of reactants] - SUM[formation energies of products]
4354  *
4355  * Now take the energy, and multiply by the densities of the reactants and the rate constant, finally
4356  * you have to multiply by 1.66e-14, which is the conversion factor to go from kJ/mol to erg/atom
4357  * this gives the units in the form of erg/atom*cm3/s*cm-3*cm-3 = erg/cm-3/s/atom, which is
4358  * a heating rate
4359  */
4360 
4361  DEBUG_ENTRY( "t_mole_local::chem_heat()" );
4362 
4363  double heating = 0.;
4364  map<double,string> heatMap;
4365  molecule *ph = findspecies("PHOTON");
4366  molecule *crph = findspecies("CRPHOT");
4367  molecule *grn = findspecies("grn");
4368 
4369  /* loop over all reactions */
4370  for (mole_reaction_i p
4371  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4372  {
4373  mole_reaction &rate = *p->second;
4374 
4375  // If PHOTON appears, assume it accounts for energy difference
4376  bool lgCanSkip = false;
4377  for (int i=0;i<rate.nproducts;i++)
4378  {
4379  if( rate.products[i] == ph || rate.products[i] == crph )
4380  lgCanSkip = true;
4381  }
4382  for (int i=0;i<rate.nreactants;i++)
4383  {
4384  if( rate.reactants[i] == ph || rate.reactants[i] == crph )
4385  lgCanSkip = true;
4386  }
4387  // grain catalyst reactions are handled in grain physics, don't double count here
4388  for (int i=0;i<rate.nreactants;i++)
4389  {
4390  if( rate.reactants[i] == grn && rate.rvector[i] != NULL )
4391  lgCanSkip = true;
4392  }
4393 
4394  if( lgCanSkip )
4395  continue;
4396 
4397  /* This loop calculates the product of the rate constant times the densities*/
4398  double rate_tot = reaction_rks[ rate.index ];
4399  for( long i=0; i < rate.nreactants; ++i )
4400  {
4401  rate_tot *= species[ rate.reactants[i]->index ].den;
4402  }
4403 
4404  realnum reaction_enthalpy = 0.;
4405 
4406  /* Calculate the sum of the formation energies for the reactants */
4407  for( long i=0; i < rate.nreactants; ++i )
4408  {
4409  reaction_enthalpy += rate.reactants[i]->form_enthalpy;
4410  }
4411 
4412  /* Subtract from that the sum of the formation energies of the products */
4413  for( long i=0; i < rate.nproducts; ++i )
4414  {
4415  reaction_enthalpy -= rate.products[i]->form_enthalpy;
4416  }
4417 
4418  /* this is the chemical heating rate. TODO. Once the H chem is merged with the C chem, then
4419  * we will have the chemical heating rate for all reactions. This is only a subset and, thusfar,
4420  * not actually used in getting the total heating. Tests with pdr_leiden_hack_f1.in show that this
4421  * heating rate can be up to 10% of the total heating */
4422 
4423  double heat = reaction_enthalpy*rate_tot*(1e10/AVOGADRO); /* 1.66e-14f; */
4424  heatMap[heat] = rate.label;
4425  heating += heat;
4426  }
4427 
4428  // use reverse iterator to print out biggest contributors
4429  long index = 0;
4430  // this should be a const_reverse_iterator, but pgCC 12.2-0 64-bit cannot handle this.
4431  // it appears there is no const version of heatMap.rend(); as a result the compiler
4432  // cannot find a suitable version of operator != in "it != heatMap.rend()"
4433  // The Solaris Studio compiler version 12.3 has the same problem
4434  for( map<double,string>::reverse_iterator it = heatMap.rbegin(); it != heatMap.rend(); ++it, ++index )
4435  {
4436  fprintf( ioQQQ, "DEBUGGG heat %li\t%li\t%.6e\t%s\n", index, nzone, it->first, it->second.c_str() );
4437  if( index==2 )
4438  break;
4439  }
4440  index = 0;
4441  for( map<double,string>::iterator it = heatMap.begin(); it != heatMap.end(); ++it, ++index )
4442  {
4443  if( it->first >= 0. )
4444  break;
4445  fprintf( ioQQQ, "DEBUGGG cool %li\t%li\t%.6e\t%s\n", index, nzone, it->first, it->second.c_str() );
4446  if( index==2 )
4447  break;
4448  }
4449 
4450  return heating;
4451 }
4452 
4453 STATIC double sticking_probability_H_func( double T_gas, double T_grain )
4454 {
4455  DEBUG_ENTRY( "sticking_probability_H_func()" );
4456  double S = sticking_probability_H_HM79( T_gas, T_grain );
4457  return S;
4458 }
4459 
4460 STATIC double sticking_probability_H_HM79( double T_gas, double T_grain )
4461 {
4462  DEBUG_ENTRY( "sticking_probability_H_HM79()" );
4463 
4464  /* sticking probability, 2H + grain equation 3.7 of
4465  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555,
4466  * fraction of H impacts on grain surface that stick */
4467  /* this sticking probability is used for both HM79 and CT02 */
4468  double T2 = T_gas / 100.;
4469  double Tg2 = T_grain / 100.;
4470  double S = 1./(1. + 0.4*sqrt(Tg2 + T2) + 0.2*T2 + 0.08*T2*T2);
4471  return S;
4472 }
4473 
long int iphmin
Definition: hmi.h:128
molecule * reactants[MAXREACTANTS]
Definition: mole_priv.h:53
realnum x12tot
Definition: secondaries.h:65
double sink_rate_tot(const char chSpecies[]) const
t_mole_global mole_global
Definition: mole.cpp:7
double hmicol
Definition: hmi.h:33
double hmirat(double te)
STATIC void register_reaction_vectors(count_ptr< mole_reaction > rate)
double grain_area
Definition: mole.h:457
bool lgStancil
Definition: mole.h:337
nNucsMap nNuclide
Definition: mole.h:157
double H2_Solomon_dissoc_rate_used_H2g
Definition: hmi.h:103
static void sort(MoleculeList::iterator start, MoleculeList::iterator end)
vector< double > reaction_rks
Definition: mole.h:470
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:751
t_atmdat atmdat
Definition: atmdat.cpp:6
double Average_A
Definition: h2_priv.h:303
double HMinus_photo_rate
Definition: hmi.h:53
double gs_rate(void)
STATIC double sticking_probability_H_func(double T_gas, double T_grain)
molecule::nNucsMap::iterator nNucs_i
Definition: mole.h:242
double rel_pop_LTE_s
Definition: h2_priv.h:290
double rel_pop_LTE_g
Definition: h2_priv.h:289
bool lgElmtOn
Definition: deuterium.h:21
molecule * null_mole
qList st
Definition: iso.h:482
long int ipG0_spec_hi
Definition: rfield.h:253
void mole_create_react(void)
double te03
Definition: phycon.h:58
long old_zone
Definition: mole.h:472
double exp10(double x)
Definition: cddefines.h:1383
long int iheh1
Definition: hmi.h:69
const int ipHE_LIKE
Definition: iso.h:65
int num_total
Definition: mole.h:362
long int ipG0_DB96_hi
Definition: rfield.h:250
double H2_photodissoc_ELWERT_H2s
Definition: hmi.h:122
double GammaK(long int ipLoEnr, long int ipHiEnr, long int ipOpac, double yield1, t_phoHeat *photoHeat)
NORETURN void TotalInsanity(void)
Definition: service.cpp:1067
t_opac opac
Definition: opacity.cpp:5
bool lgH2_Chemistry_BigH2
Definition: hmi.h:171
double Average_collH2_excit
Definition: h2_priv.h:307
STATIC void mole_check_reverse_reactions(void)
realnum ** flux
Definition: rfield.h:70
bool lgRelease
Definition: version.h:28
double H2_H2g_to_H2s_rate_used
Definition: hmi.h:100
realnum UV_Cont_rel2_Draine_DB96_face
Definition: hmi.h:84
double spon_diss_tot
Definition: h2_priv.h:269
const realnum SMALLFLOAT
Definition: cpu.h:246
virtual const char * name()=0
bool lgLeiden_Keep_ipMH2s
Definition: hmi.h:219
bool lgTraceMole
Definition: trace.h:55
realnum * outlin_noplot
Definition: rfield.h:191
double H2star_forms_grains
Definition: hmi.h:164
bool operator<(const count_ptr< T > &a, const count_ptr< T > &b)
Definition: count_ptr.h:88
double H2_H2g_to_H2s_rate_BHT90
Definition: hmi.h:91
double H2_forms_grains
Definition: hmi.h:164
double Cont_Dissoc_Rate_H2g
Definition: h2_priv.h:285
const int ipOXYGEN
Definition: cddefines.h:355
long int ipG0_spec_lo
Definition: rfield.h:253
double H2_photodissoc_used_H2s
Definition: hmi.h:120
t_conv conv
Definition: conv.cpp:5
T sign(T x, T y)
Definition: cddefines.h:846
double H2_Solomon_dissoc_rate_TH85_H2s
Definition: hmi.h:110
t_hextra hextra
Definition: hextra.cpp:5
int nreactants
Definition: mole_priv.h:52
double H2_photodissoc_BHT90
Definition: hmi.h:124
#define MAXREACTANTS
Definition: mole_priv.h:45
STATIC void mole_h2_grain_form(void)
double findrk(const char buf[]) const
long int ipG0_TH85_hi
Definition: rfield.h:246
bool lgEvaluated
Definition: h2_priv.h:317
t_phycon phycon
Definition: phycon.cpp:6
long int ih2pof
Definition: opacity.h:222
realnum TurbVel
Definition: doppvel.h:21
double H2_forms_hminus
Definition: hmi.h:164
map< string, count_ptr< mole_reaction > > reactab
double rate_grain_op_conserve
Definition: h2_priv.h:280
double H2_photodissoc_TH85
Definition: hmi.h:123
double H2_Solomon_dissoc_rate_BD96_H2g
Definition: hmi.h:106
sys_float sexp(sys_float x)
Definition: service.cpp:1095
realnum column
Definition: mole.h:422
double H2_Solomon_dissoc_rate_ELWERT_H2s
Definition: hmi.h:113
bool lgProtElim
Definition: mole.h:347
double H2_H2g_to_H2s_rate_ELWERT
Definition: hmi.h:97
double c
Definition: mole_priv.h:59
realnum ** outlin
Definition: rfield.h:191
FILE * ioQQQ
Definition: cddefines.cpp:7
long int ipG0_TH85_lo
Definition: rfield.h:246
molezone * findspecieslocal(const char buf[])
long int nzone
Definition: cddefines.cpp:14
double source_rate_tot(const char chSpecies[]) const
STATIC char * getcsvfield(char **s, char c)
double rate_h2_form_grains_set
Definition: hmi.h:192
void iso_photo(long ipISO, long nelem)
t_DoppVel DoppVel
Definition: doppvel.cpp:5
ChemNuclideList nuclide_list
double H2_Solomon_dissoc_rate_BD96_H2s
Definition: hmi.h:112
vector< freeBound > fb
Definition: iso.h:481
char chJura
Definition: hmi.h:185
Definition: mole.h:142
#define MIN2(a, b)
Definition: cddefines.h:807
bool parse_species_label(const char label[], ChemNuclideList &atomsLeftToRight, vector< int > &numAtoms, string &embellishments)
double anu(size_t i) const
Definition: mesh.h:111
double Average_collH2_dissoc_g
Definition: h2_priv.h:312
double dsexp(double x)
Definition: service.cpp:1134
realnum Tad
Definition: hmi.h:135
double Average_collH2_deexcit
Definition: h2_priv.h:305
char ** chSpecies
Definition: taulines.cpp:14
bool lgNonEquilChem
Definition: mole.h:342
long int ih2pof_ex
Definition: opacity.h:222
map< string, bool > offReactions
Definition: mole.h:367
double H2_Solomon_dissoc_rate_TH85_H2g
Definition: hmi.h:104
bool lgPhysOK
Definition: phycon.h:111
t_dense dense
Definition: global.cpp:15
STATIC void newreact(const char label[], const char fun[], double a, double b, double c)
realnum form_enthalpy
Definition: mole.h:189
static t_version & Inst()
Definition: cddefines.h:209
double Solomon_dissoc_rate_g
Definition: h2_priv.h:271
double HMinus_photo_heat
Definition: hmi.h:65
double te003
Definition: phycon.h:58
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:11
double H2_Solomon_dissoc_rate_BHT90_H2g
Definition: hmi.h:105
bool isEnabled
Definition: mole.h:153
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:135
double Average_collH2_dissoc_s
Definition: h2_priv.h:313
long int iteration
Definition: cddefines.cpp:16
double rel_pop_LTE_H2s
Definition: hmi.h:199
t_trace trace
Definition: trace.cpp:5
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:858
double H2_Solomon_dissoc_rate_used_H2s
Definition: hmi.h:109
#define MALLOC(exp)
Definition: cddefines.h:556
STATIC long parse_reaction(count_ptr< mole_reaction > &rate, const char label[])
molecule * products[MAXPRODUCTS]
Definition: mole_priv.h:56
void mole_cmp_num_in_out_reactions(void)
STATIC void mole_h_reactions(void)
t_ionbal ionbal
Definition: ionbal.cpp:8
double chem_heat(void) const
long int ipG0_DB96_lo
Definition: rfield.h:250
double te01
Definition: phycon.h:58
double H2_photodissoc_ELWERT_H2g
Definition: hmi.h:121
STATIC bool lgReactionTrivial(count_ptr< mole_reaction > &rate)
vector< double > old_reaction_rks
Definition: mole.h:471
string label
Definition: mole_priv.h:51
molecule * rvector[MAXREACTANTS]
Definition: mole_priv.h:54
bool lgLeidenHack
Definition: mole.h:334
const bool ENABLE_QUANTUM_HEATING
Definition: grainvar.h:13
void qheat(vector< double > &, vector< double > &, long *, size_t)
double photodissoc_BigH2_H2s
Definition: h2_priv.h:264
#define POW2
Definition: cddefines.h:983
const int ipH1s
Definition: iso.h:29
long int nPres2Ioniz
Definition: conv.h:145
#define STATIC
Definition: cddefines.h:118
double te001
Definition: phycon.h:58
bool lgEnabled
Definition: h2_priv.h:352
double h2plus_heatcoef
Definition: hmi.h:48
int groupnum
Definition: mole.h:194
double H2_H2g_to_H2s_rate_BD96
Definition: hmi.h:94
t_mole_local mole
Definition: mole.cpp:8
map< string, count_ptr< mole_reaction > >::iterator mole_reaction_i
Definition: mole_priv.h:38
molecule * findspecies(const char buf[])
t_rfield rfield
Definition: rfield.cpp:9
double Average_collH_deexcit
Definition: h2_priv.h:306
void create_isotopologues_one_position(unsigned position, ChemNuclideList &atoms, vector< int > &numAtoms, string atom_old, string atom_new, string embellishments, string &newLabel)
realnum * ConInterOut
Definition: rfield.h:156
float realnum
Definition: cddefines.h:124
valarray< class molezone > species
Definition: mole.h:468
#define EXIT_FAILURE
Definition: cddefines.h:168
double exphmi
Definition: hmi.h:199
virtual double rk() const =0
static realnum albedo
double sink_rate(const molecule *const sp, const mole_reaction &rate) const
double photodissoc_BigH2_H2g
Definition: h2_priv.h:265
const realnum BIGFLOAT
Definition: cpu.h:244
void mole_rk_bigchange(void)
count_ptr< chem_nuclide > findnuclide(const char buf[])
double rel_pop_LTE_Hmin
Definition: hmi.h:199
vector< diatomics * > diatoms
Definition: h2.cpp:8
#define cdEXIT(FAIL)
Definition: cddefines.h:484
int index
Definition: mole.h:194
double powi(double, long int)
Definition: service.cpp:690
STATIC bool lgReactBalance(const count_ptr< mole_reaction > &rate)
map< string, count_ptr< mole_reaction > > functab
realnum * TauAbsFace
Definition: opacity.h:99
double H2_Solomon_dissoc_rate_BHT90_H2s
Definition: hmi.h:111
bool lgGrainPhysicsOn
Definition: grainvar.h:481
diatomics h2("h2", 4100.,&hmi.H2_total, Yan_H2_CS)
realnum GetDopplerWidth(realnum massAMU)
bool lgPrintTime
Definition: prt.h:161
int n_react
Definition: mole.h:195
bool exists(const molecule *m)
Definition: mole.h:258
const int ipH3s
Definition: iso.h:32
double column(const genericState &gs)
map< const count_ptr< chem_nuclide >, int, element_pointer_value_less > nNucsMap
Definition: mole.h:145
realnum GetAveVelocity(realnum massAMU)
double te05
Definition: phycon.h:58
long int iphmop
Definition: opacity.h:222
realnum UV_Cont_rel2_Habing_TH85_face
Definition: hmi.h:74
realnum cryden_ov_background
Definition: hextra.h:35
const int ipH3d
Definition: iso.h:34
t_radius radius
Definition: radius.cpp:5
double H2_photodissoc_used_H2g
Definition: hmi.h:119
double a
Definition: mole_priv.h:59
double esc_PRD_1side(double tau, double a)
Definition: rt_escprob.cpp:116
t_prt prt
Definition: prt.cpp:14
long int nTotalIoniz
Definition: conv.h:159
double **** PhotoRate_Shell
Definition: ionbal.h:109
bool lgElmtOn[LIMELM]
Definition: dense.h:160
double rate_grain_J1_to_J0
Definition: h2_priv.h:281
double extin_mag_V_point
Definition: rfield.h:260
bool lgLeidenCRHack
Definition: hmi.h:220
realnum gas_phase[LIMELM]
Definition: dense.h:76
realnum UV_Cont_rel2_Draine_DB96_depth
Definition: hmi.h:84
vector< count_ptr< chem_nuclide > > ChemNuclideList
Definition: mole.h:124
const int ipH2p
Definition: iso.h:31
realnum AtomicWeight[LIMELM]
Definition: dense.h:80
STATIC void mole_generate_isotopologue_reactions(string atom_old, string atom_new)
double rel_pop_LTE_H2p
Definition: hmi.h:211
double frac_H2star_hminus()
#define ASSERT(exp)
Definition: cddefines.h:617
double reduced_mass
Definition: mole_priv.h:59
bool lgNeutrals
Definition: mole.h:352
double findrate(const char buf[]) const
molecule * pvector[MAXPRODUCTS]
Definition: mole_priv.h:57
const int ipH2s
Definition: iso.h:30
map< string, count_ptr< mole_reaction > >::const_iterator mole_reaction_ci
Definition: mole_priv.h:39
STATIC void compare_udfa(const count_ptr< mole_reaction > &rate)
bool lgH2_grain_deexcitation
Definition: h2_priv.h:373
char chH2_small_model_type
Definition: hmi.h:179
double rel_pop_LTE_H2g
Definition: hmi.h:211
const int ipH_LIKE
Definition: iso.h:64
bool isMonatomic(void) const
Definition: mole.h:182
int charge
Definition: mole.h:158
double den
Definition: mole.h:421
double Average_collH_excit
Definition: h2_priv.h:308
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:729
realnum UV_Cont_rel2_Habing_spec_depth
Definition: hmi.h:74
double powpq(double x, int p, int q)
Definition: service.cpp:726
double Solomon_dissoc_rate_s
Definition: h2_priv.h:272
double photoionize_rate
Definition: h2_priv.h:261
#define isnan
Definition: cddefines.h:663
const int ipHELIUM
Definition: cddefines.h:349
void GrainDrive()
Definition: grains.cpp:1597
STATIC double sticking_probability_H_HM79(double T_gas, double T_grain)
bool lgDifferByExcitation(const molecule &mol1, const molecule &mol2)
double te10
Definition: phycon.h:58
STATIC void plot_sparsity(void)
double Cont_Dissoc_Rate_H2s
Definition: h2_priv.h:284
double GammaBn(long int ipLoEnr, long int ipHiEnr, long int ipOpac, double thresh, double *ainduc, double *rcool, t_phoHeat *photoHeat)
Definition: cont_gammas.cpp:34
vector< GrainBin * > bin
Definition: grainvar.h:585
void mole_update_rks(void)
diatomics hd("hd", 4100.,&hmi.HD_total, Yan_H2_CS)
long int ip1000A
Definition: rfield.h:256
double te20
Definition: phycon.h:58
t_deuterium deut
Definition: deuterium.cpp:7
string label
Definition: mole.h:156
double eden
Definition: dense.h:201
double b
Definition: mole_priv.h:59
STATIC double mole_get_equilibrium_condition(const char buf[])
STATIC void read_data(const char file[], void(*parse)(char *s))
STATIC double mole_partition_function(const molecule *const sp)
#define MAX2(a, b)
Definition: cddefines.h:828
realnum mole_mass
Definition: mole.h:190
realnum UV_Cont_rel2_Habing_TH85_depth
Definition: hmi.h:74
const int NQGRID
Definition: grainvar.h:34
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1217
double te70
Definition: phycon.h:58
realnum ScaleJura
Definition: hmi.h:189
MoleculeList list
Definition: mole.h:365
double dissoc_rate(const char chSpecies[]) const
realnum ** csupra
Definition: secondaries.h:33
mole_reaction * mole_findrate_s(const char buf[])
double te90
Definition: phycon.h:58
sys_float SDIV(sys_float x)
Definition: cddefines.h:1006
double alogte
Definition: phycon.h:92
double pow(double x, int i)
Definition: cddefines.h:782
molecule * rvector_excit[MAXREACTANTS]
Definition: mole_priv.h:55
double H2_H2g_to_H2s_rate_TH85
Definition: hmi.h:88
const int ipCARBON
Definition: cddefines.h:353
#define S(I_, J_)
STATIC void parse_udfa(char *s)
double HeatNet
Definition: thermal.h:204
virtual mole_reaction * Create() const =0
double Average_collH_dissoc_g
Definition: h2_priv.h:310
double hmrate4(double a, double b, double c, double te)
Definition: mole.h:537
bool lgReleaseBranch
Definition: version.h:25
double esca0k2(double taume)
Definition: rt_escprob.cpp:376
void GammaPrt(long int ipLoEnr, long int ipHiEnr, long int ipOpac, FILE *ioFILE, double total, double threshold)
long int iheh2
Definition: hmi.h:69
STATIC void canonicalize_reaction(count_ptr< mole_reaction > &rate)
STATIC string canonicalize_reaction_label(const char label[])
bool lgFederman
Definition: mole.h:336
double Average_collH_dissoc_s
Definition: h2_priv.h:311
realnum H2Opacity
Definition: hmi.h:38
double sqrte
Definition: phycon.h:58
#define fixit(a)
Definition: cddefines.h:416
long int ih2pnt[2]
Definition: opacity.h:222
GrainVar gv
Definition: grainvar.cpp:5
t_secondaries secondaries
Definition: secondaries.cpp:5
t_hmi hmi
Definition: hmi.cpp:5
double r1r0sq
Definition: radius.h:31
double fnzone
Definition: cddefines.cpp:15
double CharExcIonOf[NCX][LIMELM][LIMELM+1]
Definition: atmdat.h:300
double te
Definition: phycon.h:21
double H2_Solomon_dissoc_rate_ELWERT_H2g
Definition: hmi.h:107
double HMinus_induc_rec_rate
Definition: hmi.h:65
const double SEXP_LIMIT
Definition: cddefines.h:1368
STATIC void parse_base(char *s)
bool lgDustOn() const
Definition: grainvar.h:477
const int ipHYDROGEN
Definition: cddefines.h:348
double rel_pop_LTE_H3p
Definition: hmi.h:211
double CharExcRecTo[NCX][LIMELM][LIMELM+1]
Definition: atmdat.h:300
long int nflux
Definition: rfield.h:48
#define FLTEQ(a, b)
long int ih2pnt_ex[2]
Definition: opacity.h:222
void create_isotopologues(ChemNuclideList &atoms, vector< int > &numAtoms, string atom_old, string atom_new, string embellishments, vector< string > &newLabels)
const int ipH3p
Definition: iso.h:33
double te30
Definition: phycon.h:58
double te32
Definition: phycon.h:58
vector< diatomics * >::iterator diatom_iter
Definition: h2.h:13
#define MAXPRODUCTS
Definition: mole_priv.h:46
double rate_h2_form_grains_used_total
Definition: grainvar.h:576
static map< formula_species, count_ptr< udfa_reaction > > udfatab
molecule * pvector_excit[MAXPRODUCTS]
Definition: mole_priv.h:58
double h2plus_exc_frac
Definition: hmi.h:50
double tesqrd
Definition: phycon.h:36
double HMinus_induc_rec_cooling
Definition: hmi.h:65
double H2star_forms_hminus
Definition: hmi.h:164