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-2022 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 
1353 
1354  typedef mole_reaction_h2crphot T;
1355  public:
1356  virtual T* Create() const {return new T;}
1357  virtual const char* name() {return "h2crphot";}
1358  double rk() const
1359  {
1360  return secondaries.csupra[ipHYDROGEN][0]*2.02;
1361  }
1362  };
1363 
1364  class mole_reaction_h2crphh : public mole_reaction
1365  {
1366  typedef mole_reaction_h2crphh T;
1367  public:
1368  virtual T* Create() const {return new T;}
1369  virtual const char* name() {return "h2crphh";}
1370  double rk() const
1371  {
1373  {
1374  /* cosmic ray & secondary electron excitation to triplets
1375  * big molecule scale factor changed 3-> 10
1376  *>>chng 07 apr 08, from 3 to 10 to better capture results
1377  * of Dalgarno et al 99 */
1378  //return secondaries.x12tot*10.;
1379  /*>>chng 20 jul 04, from 10 to 1.4 as discussed in
1380  * https://ui.adsabs.harvard.edu/abs/2020RNAAS...4...78S/abstract
1381  */
1382  return secondaries.x12tot*1.4;
1383  }
1384  else
1385  {
1386  /* the original TH85 approximation */
1387  return secondaries.x12tot*3.;
1388  }
1389  }
1390  };
1391 
1392  class mole_reaction_h2scrphh : public mole_reaction
1393  {
1394  typedef mole_reaction_h2scrphh T;
1395  public:
1396  virtual T* Create() const {return new T;}
1397  virtual const char* name() {return "h2scrphh";}
1398  double rk() const
1399  {
1401  {
1402  //return secondaries.x12tot*10.;
1403  //return secondaries.x12tot*10.;
1404  /*>>chng 20 jul 04, from 10 to 1.4 as discussed in
1405  * https://ui.adsabs.harvard.edu/abs/2020RNAAS...4...78S/abstract
1406  */
1407  return secondaries.x12tot*1.4;
1408  }
1409  else
1410  {
1411  return secondaries.x12tot*3.;
1412  }
1413  }
1414  };
1415 
1416  class mole_reaction_radath : public mole_reaction
1417  {
1418  typedef mole_reaction_radath T;
1419  public:
1420  virtual T* Create() const {return new T;}
1421  virtual const char* name() {return "radath";}
1422  double rk() const
1423  {
1424  return MAX2(0.,2.325*MIN2(5000.,phycon.te)-1375.)*1e-20;
1425  }
1426  };
1427 
1428  class mole_reaction_gamtwo : public mole_reaction
1429  {
1430  typedef mole_reaction_gamtwo T;
1431  public:
1432  virtual T* Create() const {return new T;}
1433  virtual const char* name() {return "gamtwo";}
1434  double rk() const
1435  {
1436  t_phoHeat dummyGrd, dummyExc;
1437  hmi.h2plus_exc_frac = dsexp( 10000./phycon.te );
1438  double fracGrd = MAX2( 0., 1. - hmi.h2plus_exc_frac );
1439  double coefGrd = GammaK(opac.ih2pnt[0],opac.ih2pnt[1],opac.ih2pof,1.,&dummyGrd);
1440  double coefExc = GammaK(opac.ih2pnt_ex[0],opac.ih2pnt_ex[1],opac.ih2pof_ex,1.,&dummyExc);
1441  hmi.h2plus_heatcoef = dummyGrd.HeatNet * fracGrd + dummyExc.HeatNet * hmi.h2plus_exc_frac;
1442  double coef = coefGrd * fracGrd + coefExc * hmi.h2plus_exc_frac;
1443  return coef;
1444  }
1445  };
1446 
1447  class mole_reaction_hlike_phot : public mole_reaction
1448  {
1449  typedef mole_reaction_hlike_phot T;
1450  public:
1451  virtual T* Create() const {return new T;}
1452  virtual const char* name() {return "hlike_phot";}
1453  double rk() const
1454  {
1455  /* photoionization by hard photons, crossection =2*HI (wild guess)
1456  * -- rjrw: where do they go???
1457  * -- H3+ + hv => H2+ + H+ + e, best guess (P. Stancil, priv comm) */
1458 
1459  // on first pass this has not been set, do it here, but only do it once.
1460  if( !conv.nTotalIoniz )
1462  return iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].gamnc;
1463  }
1464  };
1465 
1466  class mole_reaction_h2s_sp_decay : public mole_reaction
1467  {
1468  typedef mole_reaction_h2s_sp_decay T;
1469  public:
1470  virtual T* Create() const {return new T;}
1471  virtual const char* name() {return "h2s_sp_decay";}
1472  double rk() const
1473  {
1474  /* >>chng 05 jul 11, TE, rename to use in punch file*/
1475  /* >>chng 05 jul 9, GS, use average A calculated from Big H2 */
1477  {
1478  return h2.Average_A;
1479  }
1480  else
1481  {
1482  return 2e-7;
1483  }
1484  }
1485  };
1486 
1487  double h2_collh2_deexc(const mole_reaction *)
1488  {
1490  {
1491  return h2.Average_collH2_deexcit;
1492  }
1493  else
1494  {
1495  return ((1.4e-12*phycon.sqrte * sexp( 18100./(phycon.te + 1200.) ))/6.);
1496  }
1497  }
1498  class mole_reaction_h2_collh2_deexc : public mole_reaction
1499  {
1500  typedef mole_reaction_h2_collh2_deexc T;
1501  public:
1502  virtual T* Create() const {return new T;}
1503  virtual const char* name() {return "h2_collh2_deexc";}
1504  double rk() const
1505  {
1506  return h2_collh2_deexc(this);
1507  }
1508  };
1509 
1510  double h2_collh_deexc(const mole_reaction *)
1511  {
1513  {
1514  return h2.Average_collH_deexcit;
1515  }
1516  else
1517  {
1518  return ((1e-12*phycon.sqrte * sexp(1000./phycon.te ))/6.);
1519  }
1520  }
1521  class mole_reaction_h2_collh_deexc : public mole_reaction
1522  {
1523  typedef mole_reaction_h2_collh_deexc T;
1524  public:
1525  virtual T* Create() const {return new T;}
1526  virtual const char* name() {return "h2_collh_deexc";}
1527  double rk() const
1528  {
1529  return h2_collh_deexc(this);
1530  }
1531  };
1532 
1533  double h2_collh2_excit(const mole_reaction *rate)
1534  {
1535  /* >>chng 05 jul 10, GS, use average collisional rate calculated from Big H2 */
1537  {
1538  return h2.Average_collH2_excit;
1539  }
1540  else
1541  {
1542  return h2_collh2_deexc(rate)*sexp( 30172./phycon.te); /* deexc_htwo*Boltz_fac_H2_H2star */
1543  }
1544  }
1545  class mole_reaction_h2_collh2_excit : public mole_reaction
1546  {
1547  typedef mole_reaction_h2_collh2_excit T;
1548  public:
1549  virtual T* Create() const {return new T;}
1550  virtual const char* name() {return "h2_collh2_excit";}
1551  double rk() const
1552  {
1553  return h2_collh2_excit(this);
1554  }
1555  };
1556 
1557  double h2_collh_excit(const mole_reaction *rate)
1558  {
1559  /* >>chng 05 jul 10, GS, use average collisional rate calculated from Big H2 */
1561  {
1562  return h2.Average_collH_excit;
1563  }
1564  else
1565  {
1566  return h2_collh_deexc(rate)*sexp( 30172./phycon.te); /* deexc_hneut*Boltz_fac_H2_H2star */
1567  }
1568  }
1569  class mole_reaction_h2_collh_excit : public mole_reaction
1570  {
1571  typedef mole_reaction_h2_collh_excit T;
1572  public:
1573  virtual T* Create() const {return new T;}
1574  virtual const char* name() {return "h2_collh_excit";}
1575  double rk() const
1576  {
1577  return h2_collh_excit(this);
1578  }
1579  };
1580 
1581  class mole_reaction_h2gexcit : public mole_reaction
1582  {
1583  typedef mole_reaction_h2gexcit T;
1584  public:
1585  virtual T* Create() const {return new T;}
1586  virtual const char* name() {return "h2gexcit";}
1587  double rk() const
1588  {
1590  }
1591  };
1592 
1593  class mole_reaction_h2sdissoc : public mole_reaction
1594  {
1595  typedef mole_reaction_h2sdissoc T;
1596  public:
1597  virtual T* Create() const {return new T;}
1598  virtual const char* name() {return "h2sdissoc";};
1599  double rk() const
1600  {
1601  /* >>chng 03 sep 11, add this process */
1602  /* photo-destroy H2* by Solomon process at same rate as H2ground dissociation,
1603  see above eqn A12 in TH85 */
1604  /* >>chng 00 nov 25 factor of 0.1, assume pump is total, and 10% destroy H2 */
1605  /* >>chng 03 mar 07, had factor of 0.1 for branching ratio from H2** to H+H,
1606  * but branching is now already included */
1608  }
1609  };
1610 
1611  class mole_reaction_h2gdissoc : public mole_reaction
1612  {
1613  typedef mole_reaction_h2gdissoc T;
1614  public:
1615  virtual T* Create() const {return new T;}
1616  virtual const char* name() {return "h2gdissoc";}
1617  double rk() const
1618  {
1619  /* >>chng 03 sep 11, add this process */
1620  /* photo-destroy H2* by Solomon process at same rate as H2ground dissociation,
1621  see above eqn A12 in TH85 */
1622  /* >>chng 00 nov 25 factor of 0.1, assume pump is total, and 10% destroy H2 */
1623  /* >>chng 03 mar 07, had factor of 0.1 for branching ratio from H2** to H+H,
1624  * but branching is now already included */
1626  }
1627  };
1628 
1629  class mole_reaction_hd_photodissoc : public mole_reaction
1630  {
1631  typedef mole_reaction_hd_photodissoc T;
1632  public:
1633  virtual T* Create() const {return new T;}
1634  virtual const char* name() {return "hd_photodissoc";}
1635  double rk() const
1636  {
1638  }
1639  };
1640 }
1641 
1642 /*hmirat compute radiative association rate for H- */
1643 double hmirat(double te)
1644 {
1645  double hmirat_v;
1646 
1647  DEBUG_ENTRY( "hmirat()" );
1648 
1649  // Compare published literature:
1650  // >>refer H- form deJong 1972A+A....20..263D
1651  // >>refer H- form Dalgarno 1973ApJ...181...95D
1652  // >>refer H- form Rawlings 1988MNRAS.230..695R
1653 
1654  /* fits to radiative association rate coefficients */
1655  if( te < 31.62 )
1656  {
1657  hmirat_v = 8.934e-18*phycon.sqrte*phycon.te003*phycon.te001*
1658  phycon.te001;
1659  }
1660  else if( te < 90. )
1661  {
1662  hmirat_v = 5.159e-18*phycon.sqrte*phycon.te10*phycon.te03*
1664  }
1665  else if( te < 1200. )
1666  {
1667  hmirat_v = 2.042e-18*te/phycon.te10/phycon.te03;
1668  }
1669  else if( te < 3800. )
1670  {
1671  hmirat_v = 8.861e-18*phycon.te70/phycon.te03/phycon.te01*
1672  phycon.te003;
1673  }
1674  else if( te <= 1.4e4 )
1675  {
1676  /* following really only optimized up to 1e4 */
1677  hmirat_v = 8.204e-17*phycon.sqrte/phycon.te10/phycon.te01*
1678  phycon.te003;
1679  }
1680  else
1681  {
1682  /* >>chng 00 sep 28, add this branch */
1683  /* >>chng 14 mar 26, rate slightly discontinuous */
1684  hmirat_v = 5.70e-16*phycon.te20/phycon.te01;
1685  }
1686 
1687  return( hmirat_v );
1688 }
1689 STATIC void mole_h2_grain_form(void);
1690 
1692 STATIC void mole_h_reactions(void);
1693 
1694 
1695 namespace {
1696  class mole_reaction_gamheh : public mole_reaction
1697  {
1698  typedef mole_reaction_gamheh T;
1699  public:
1700  virtual T* Create() const {return new T;}
1701  virtual const char* name() {return "gamheh";}
1702  double rk() const
1703  {
1704  double retval = 0.;
1705  long int limit,
1706  i;
1707  /* photodissociation through 1.6->2.3 continuum */
1708 
1709  /* why is this in a look instead of GammaK?
1710  * to fix must set opacities into stack */
1711 
1712  limit = MIN2(hmi.iheh2-1 , rfield.nflux );
1713  for( i=hmi.iheh1-1; i < limit; i++ )
1714  {
1715  retval += rfield.flux[0][i] + rfield.ConInterOut[i]+ rfield.outlin[0][i] + rfield.outlin_noplot[i];
1716  }
1717  retval *= 4e-18;
1718 
1719  /* hard radiation */
1720  retval += 3.*iso_sp[ipH_LIKE][ipHYDROGEN].fb[ipH1s].gamnc;
1721 
1722  return retval;
1723  }
1724  };
1725 
1726  enum {exclude, base, umisthack, federman, lithium, deuterium, ti, misc, in_code, generated};
1727  static int source;
1728 
1729 
1730  static bool lgReactInitialized = false;
1731 }
1732 
1733 void mole_create_react( void )
1734 {
1735  /* Should adaptively select reactions rather than list them explicitly here */
1736 
1737  /* prevent memory leaks */
1738  /* \todo this is a temporary fix for PR14. We should improve the overall design
1739  * of this code to prevent valid pointers being overwritten in a second call to mole_create_react */
1740  if( lgReactInitialized )
1741  return;
1742 
1743  lgReactInitialized = true;
1744 
1745  DEBUG_ENTRY( "mole_create_react()" );
1746 
1747  /* UDFA set 0 (false) above, UDFA = 1 (true) to make UDFA comparison and stop */
1748  if( UDFA )
1749  read_data("rate05_feb17.csv",parse_udfa);
1750 
1751  /* Set up registry of rate functions -- could do something intelligent about
1752  * caching rate values by extending this API... */
1753  newfunc<mole_reaction_null>();
1754  {
1755  map<string,bool> canonical;
1756  for (map<string,bool>::iterator it=mole_global.offReactions.begin();
1757  it != mole_global.offReactions.end(); ++it)
1758  {
1759  canonical[canonicalize_reaction_label(it->first.c_str())] = true;
1760  }
1761  mole_global.offReactions = canonical;
1762  }
1763 
1764  newfunc<mole_reaction_hmrate>();
1765  newfunc<mole_reaction_hmrate_exo>();
1766  newfunc<mole_reaction_constrate>();
1767  newfunc<mole_reaction_th85rate>();
1768  newfunc<mole_reaction_crnurate>();
1769  newfunc<mole_reaction_crnurate_noalbedo>();
1770  newfunc<mole_reaction_co_lnu_c_o_lnu>();
1771  newfunc<mole_reaction_vib_evap>();
1772  newfunc<mole_reaction_th85rate_co>();
1773  newfunc<mole_reaction_grn_abs>();
1774  /* >chng 07 Dec 11, add grain surface chemical reactions */
1775  newfunc<mole_reaction_grn_react>();
1776  /* >>chng 07 Dec 10, add photodesorption of grain molecules */
1777  newfunc<mole_reaction_grn_photo>();
1778  newfunc<mole_reaction_oh_c2h2_co_ch3>();
1779  newfunc<mole_reaction_h_hnc_hcn_h>();
1780 
1781  newfunc<mole_reaction_gamheh>();
1782  newfunc<mole_reaction_hd_photodissoc>();
1783  newfunc<mole_reaction_h2gdissoc>();
1784  newfunc<mole_reaction_h2sdissoc>();
1785  newfunc<mole_reaction_h2gexcit>();
1786  newfunc<mole_reaction_h2_collh_excit>();
1787  newfunc<mole_reaction_h2_collh2_excit>();
1788  newfunc<mole_reaction_h2_collh_deexc>();
1789  newfunc<mole_reaction_h2_collh2_deexc>();
1790  newfunc<mole_reaction_h2s_sp_decay>();
1791  newfunc<mole_reaction_hlike_phot>();
1792  newfunc<mole_reaction_gamtwo>();
1793  newfunc<mole_reaction_h2ph3p>();
1794  newfunc<mole_reaction_radath>();
1795  newfunc<mole_reaction_cryden_ov_bg>();
1796  newfunc<mole_reaction_h2scrphh>();
1797  newfunc<mole_reaction_h2crphh>();
1798  newfunc<mole_reaction_h2photon>();
1799  newfunc<mole_reaction_h2crphot>();
1800  newfunc<mole_reaction_rh2g_dis_h>();
1801  newfunc<mole_reaction_rh2s_dis_h>();
1802  newfunc<mole_reaction_rh2g_dis_h2>();
1803  newfunc<mole_reaction_rh2s_dis_h2>();
1804  newfunc<mole_reaction_rh2s_dis_h2_nodeexcit>();
1805  newfunc<mole_reaction_bh2g_dis_h>();
1806  newfunc<mole_reaction_bh2s_dis_h>();
1807  newfunc<mole_reaction_bh2g_dis_h2>();
1808  newfunc<mole_reaction_bh2s_dis_h2>();
1809  newfunc<mole_reaction_radasc>();
1810  newfunc<mole_reaction_assoc_ion>();
1811  newfunc<mole_reaction_grnh2>();
1812  newfunc<mole_reaction_grnh2s>();
1813  newfunc<mole_reaction_h2_spon_diss>();
1814  newfunc<mole_reaction_h2_ind_rad_diss>();
1815  newfunc<mole_reaction_bhneut>();
1816  newfunc<mole_reaction_hneut>();
1817  newfunc<mole_reaction_asdbs>();
1818  newfunc<mole_reaction_asdbg>();
1819  newfunc<mole_reaction_asdfs>();
1820  newfunc<mole_reaction_asdfg>();
1821  newfunc<mole_reaction_c3bod>();
1822  newfunc<mole_reaction_cionhm>();
1823  newfunc<mole_reaction_hmphoto>();
1824  newfunc<mole_reaction_hmihph2p>();
1825  newfunc<mole_reaction_hmattach>();
1826  //newfunc<mole_reaction_hpoexch>();
1827  //newfunc<mole_reaction_hopexch>();
1828 
1829  source = base;
1830  read_data("mole_co_base.dat",parse_base);
1831  if (mole_global.lgFederman)
1832  {
1833  source = federman;
1834  read_data("mole_co_federman.dat",parse_base);
1835  }
1836  if (!mole_global.lgLeidenHack)
1837  {
1838  source = umisthack;
1839  read_data("mole_co_umisthack.dat",parse_base);
1840  }
1841 
1842  source = lithium;
1843  read_data("mole_lithium.dat",parse_base);
1844 
1845  source = deuterium;
1846  read_data("mole_deuterium.dat",parse_base);
1847 
1848 #if 0
1849  source = ti;
1850  read_data("mole_ti.dat",parse_base);
1851 #endif
1852 
1853  source = misc;
1854  read_data("mole_misc.dat",parse_base);
1855 
1856  /* Load null reaction to delete real rate from database */
1857  if (!mole_global.lgProtElim)
1858  {
1859  source = exclude;
1860  newreact("C+,OH=>CO,H+","hmrate",0.,0.,0.);
1861  }
1862 
1863  source = in_code;
1864 
1865  newreact("H,H,grn=>H2,grn","grnh2",1.,0.,0.);
1866  newreact("H,H,grn=>H2*,grn","grnh2s",1.,0.,0.);
1867  newreact("H-,PHOTON=>H,e-","hmphoto",1.,0.,0.);
1868 
1869  /* mutual neutralization with heavies, rate from Dalgarno and McCray
1870  * all charged ions contribute equally,
1871  * H- + A+ => H + A */
1872  fixit("this should be atom_list instead of unresolved_element_list, but we have not defined ionized species of all isotopes yet!!!");
1873  //for(vector<count_ptr<chem_atom> >::iterator atom=atom_list.begin(); atom != atom_list.end(); ++atom)
1874  for(ChemNuclideList::iterator atom=nuclide_list.begin(); atom != nuclide_list.end(); ++atom)
1875  {
1876  if( !(*atom)->lgHasLinkedIon() )
1877  continue;
1878  long nelem = (*atom)->el->Z-1;
1879  if( nelem >= ipHELIUM && dense.lgElmtOn[nelem] )
1880  {
1881  char react[32];
1882  sprintf(react,"H-,%s+=>H,%s", (*atom)->label().c_str(), (*atom)->label().c_str() );
1883  newreact(react,"hmrate",4e-6/sqrt(300.),-0.5,0.);
1884  }
1885  }
1886 
1887  newreact("H,e-=>H-,PHOTON","hmattach",1.,0.,0.);
1888  newreact("H-,H+=>H2+,e-","hmihph2p",1.,0.,0.);
1889  newreact("H-,e-=>H,e-,e-","cionhm",1.,0.,0.);
1890  newreact("H,e-,e-=>H-,e-","c3bod",1.,0.,0.);
1891  newreact("H,H-=>H2,e-","asdfg",1.,0.,0.);
1892  newreact("H,H-=>H2*,e-","asdfs",1.,0.,0.);
1893  newreact("H2,e-=>H,H-","asdbg",1.,0.,0.);
1894  newreact("H2*,e-=>H,H-","asdbs",1.,0.,0.);
1895  newreact("H-,H+=>H,H","hneut",1.,0.,0.);
1896  newreact("H,H=>H-,H+","bhneut",1.,0.,0.);
1897 
1899  {
1900  //newreact("H2*=>H,H,PHOTON","h2_spon_diss",1.,0.,0.);
1901  newreact("H2*,PHOTON=>H,H,PHOTON","h2_ind_rad_diss",1.,0.,0.);
1902  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.
1903  }
1904  else
1905  {
1906  //newreact("H2=>H,H,PHOTON","h2_spon_diss",1.,0.,0.);
1907  newreact("H2,PHOTON=>H,H,PHOTON","h2_ind_rad_diss",1.,0.,0.);
1908  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 */
1909  }
1910 
1912  {
1913  newreact("H,H=>H2,PHOTON","radasc",3e-14,0.,0.);
1914  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 */
1915  newreact("H2,H=>H,H,H","rh2g_dis_h",1.,0.,0.);
1916  newreact("H2,H2=>H,H,H2","rh2g_dis_h2",1.,0.,0.);
1917  newreact("H,H,H=>H2,H","bh2g_dis_h",1.,0.,0.); /* back rate, three body recombination, 2H + S => H_2 + S */
1918  newreact("H,H,H2=>H2,H2","bh2g_dis_h2",1.,0.,0.);
1919  //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 */
1920  newreact("H2,PHOTON=>H2+,e-","h2photon",1.,0.,0.);
1921  newreact("H2,CRPHOT=>H2+,e-","h2crphot",1.,0.,0.);
1922  newreact("H2*,PHOTON=>H2+,e-","h2photon",1.,0.,0.);
1923  newreact("H2*,CRPHOT=>H2+,e-","h2crphot",1.,0.,0.);
1924  newreact("H2,CRPHOT=>H,H","h2crphh",1.,0.,0.); /* >>refer H2 k Shaw+20 2020RNAAS...4...78S */
1925  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 */
1926  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 */
1927  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 */
1928  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 */
1929  newreact("H+,H=>H2+,PHOTON","radath",1.,0.,0.);
1930  newreact("H2+,PHOTON=>H,H+","gamtwo",1.,0.,0.);
1931  newreact("H2+,CRPHOT=>H,H+","hlike_phot",1.,0.,0.);
1932  /* >> chng 05 aug 05, NPA comment. This reaction is not in UMIST, for the case
1933  of hard photons. Turn if off for the comparison. */
1934  newreact("H3+,CRPHOT=>H2+,H+,e-","hlike_phot",2.,0.,0.);
1935  newreact("H,H+,e-=>H2+,e-","hmrate",2e-7 * SAHA * (4./(2.*1.)) * 3.634e-5 * pow(300.,-1.50),-1.50,0.);
1936  }
1937  else
1938  {
1939  newreact("H2,CRPHOT=>H2+,e-","hmrate",4.4e-17,0.,0.);
1940  newreact("H2,CRPHOT=>H,H+,e-","hmrate",1e-19,0.,0.);
1941  newreact("H2*,CRPHOT=>H,H+,e-","hmrate",1e-19,0.,0.);
1942  newreact("H2*,CRPHOT=>H2+,e-","hmrate",4.4e-17,0.,0.);
1943  newreact("H2,CRPHOT=>H,H","hmrate",5e-18,0.,0.);
1944  newreact("e-,H3+=>H2,H","hmrate",2.5e-8,-0.3,0.);
1945  newreact("e-,H3+=>H,H,H","hmrate",7.5e-8,-0.3,0.);
1946  newreact("H+,H=>H2+,PHOTON","hmrate",5.3e-19,1.85,0);
1947  /* H2+ + e=> H + H;
1948  * equation (6,table 4) from
1949  * >>refer H2 l Maloney et.al, 1996,ApJ, 466, 561 */
1950  newreact("H2+,e-=>H,H","hmrate",1.6e-8,-0.43,0.);
1951  newreact("H2+,PHOTON=>H,H+","th85rate",5.7e-10,0.,1.9);
1952  }
1953 
1954  newreact("H2*,CRPHOT=>H,H","h2scrphh",1.,0.,0.); /* >>refer H2 k Millar, T.J., et.al, 1997,A&AS, 121, 139 */
1955  newreact("H2,H2+=>H,H3+","h2ph3p",1.,0.,0.);
1956  newreact("H2*=>H2,PHOTON","h2s_sp_decay",1.,0.,0.);
1957  newreact("H2*,H2=>H2,H2","h2_collh2_deexc",1.,0.,0.);
1958  newreact("H2*,H=>H2,H","h2_collh_deexc",1.,0.,0.);
1959  newreact("H2,H2=>H2*,H2","h2_collh2_excit",1.,0.,0.);
1960  newreact("H2,H=>H2*,H","h2_collh_excit",1.,0.,0.);
1961 
1962  // collisional dissociation of H2*
1963  newreact("H2*,H=>H,H,H","rh2s_dis_h",1.,0.,0.);
1964  newreact("H2*,H2=>H2,H,H","rh2s_dis_h2",1.,0.,0.);
1965  newreact("H2*,H2*=>H2,H,H","rh2s_dis_h2",1.,0.,0.);
1966  newreact("H2*,H2*=>H2*,H,H","rh2s_dis_h2_nodeexcit",1.,0.,0.);
1967 
1968 #if 0
1969  // more collision dissociation of H2
1970  newreact("H2,He=>He,H,H","rh2g_dis_h",1.,0.,0.);
1971  newreact("H2,H+=>H+,H,H","rh2g_dis_h",1.,0.,0.);
1972  newreact("H2,H3+=>H3+,H,H","rh2g_dis_h",1.,0.,0.);
1973  newreact("H2,e-=>e-,H,H","rh2g_dis_h",1.,0.,0.);
1974  newreact("H2*,He=>He,H,H","rh2s_dis_h",1.,0.,0.);
1975  newreact("H2*,H+=>H+,H,H","rh2s_dis_h",1.,0.,0.);
1976  newreact("H2*,H3+=>H3+,H,H","rh2s_dis_h",1.,0.,0.);
1977  newreact("H2*,e-=>e-,H,H","rh2s_dis_h",1.,0.,0.);
1978 
1979  // back reactions
1980  newreact("He,H,H=>H2,He","bh2g_dis_h",1.,0.,0.);
1981  newreact("H+,H,H=>H2,H+","bh2g_dis_h",1.,0.,0.);
1982  newreact("H3+,H,H=>H2,H3+","bh2g_dis_h",1.,0.,0.);
1983  newreact("e-,H,H=>H2,e-","bh2g_dis_h",1.,0.,0.);
1984  newreact("H,H,H=>H2*,H","bh2s_dis_h",1.,0.,0.);
1985  newreact("H2,H,H=>H2*,H2","bh2s_dis_h2",1.,0.,0.);
1986  newreact("H2,H,H=>H2*,H2*","bh2s_dis_h2",1.,0.,0.);
1987  newreact("H2*,H,H=>H2*,H2*","bh2s_dis_h2",1.,0.,0.);
1988  newreact("He,H,H=>H2*,He","bh2s_dis_h",1.,0.,0.);
1989  newreact("H+,H,H=>H2*,H+","bh2s_dis_h",1.,0.,0.);
1990  newreact("H3+,H,H=>H2*,H3+","bh2s_dis_h",1.,0.,0.);
1991  newreact("e-,H,H=>H2*,e-","bh2s_dis_h",1.,0.,0.);
1992 #endif
1993 
1994  newreact("H2,PHOTON=>H2*","h2gexcit",1.,0.,0.);
1995  newreact("H2*,PHOTON=>H,H","h2sdissoc",1.,0.,0.);
1996  newreact("H2,PHOTON=>H,H","h2gdissoc",1.,0.,0.);
1997  newreact("HeH+,PHOTON=>H,He+","gamheh",1.,0.,0.);
1998 
1999  if(0)
2000  {
2001  // grain surface reactions
2002  newreact("OHgrn,Hgrn=>H2Ogrn","grn_react",1.,0.,0.);
2003  }
2004 
2005  if(UDFA)
2006  {
2007  fprintf(stderr,"Finished testing against UDFA database\n");
2009  }
2010 
2011  if (0)
2012  plot_sparsity();
2013 
2014  source = generated;
2015 
2017 
2018  if( deut.lgElmtOn )
2020 
2021  long index = 0;
2022  for( mole_reaction_i it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it, ++index )
2023  it->second->index = index;
2024 
2025  mole.reaction_rks.resize( index );
2026  mole.old_zone = -1;
2027  if( index > 0 )
2028  memset( &mole.reaction_rks[0], 0, (unsigned long)(index)*sizeof(double) );
2029 
2030  // label catalytic, intra-group, and excitition/deexcitation vectors for all reactions
2031  for( mole_reaction_i it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it )
2032  register_reaction_vectors( it->second );
2033 }
2034 
2035 STATIC void mole_generate_isotopologue_reactions( string atom_old, string atom_new )
2036 {
2037  DEBUG_ENTRY( "mole_generate_isotopologue_reactions()" );
2038 
2039  bool lgDebug = false;
2040 
2041  count_ptr<chem_nuclide> atomOld = findnuclide(atom_old.c_str());
2042  // store new reaction strings (and pointer to reaction derived from) and add all to reactab map after following iterator
2043  vector<string> newReactionStrings;
2044  vector<mole_reaction*> oldReactions;
2045  vector<realnum> branchingRatios;
2046 
2047  // iterate over all reactions and generate new strings by replacing atom_old with atom_new
2048  for( mole_reaction_ci it = mole_priv::reactab.begin(); it != mole_priv::reactab.end(); ++it )
2049  {
2050  bool lgFound = false;
2051 
2052  // Find number of atom sites in products
2053  int numSites = 0;
2054  for( long j=0; j<it->second->nproducts; ++j )
2055  {
2056  // Note that we must search before accessing the map because attempting to access an undeclared key will write to the map.
2057  if( it->second->products[j]->nNuclide.find( atomOld ) != it->second->products[j]->nNuclide.end() )
2058  numSites += it->second->products[j]->nNuclide[ atomOld ];
2059  }
2060 
2061  for( long i=0; i<it->second->nreactants; ++i )
2062  {
2063  // search for atom_old among reactants
2064  for( nNucs_i atom=it->second->reactants[i]->nNuclide.begin(); atom != it->second->reactants[i]->nNuclide.end(); ++atom )
2065  {
2066  if( atom->first->label() == atom_old )
2067  {
2068  lgFound = true;
2069  continue;
2070  }
2071  }
2072  if( lgFound )
2073  continue;
2074  }
2075 
2076  if( !lgFound )
2077  continue;
2078 
2079  if( lgDebug )
2080  fprintf( ioQQQ, "DEBUGGG mole_generate_isotopologue_reactions %s ..........\n", it->first.c_str() );
2081 
2082  for( long i=0; i<it->second->nreactants; ++i )
2083  {
2084  // ignore reactants with no nucleons (e-, PHOTON, CRPHOT, ... )
2085  if( it->second->reactants[i]->mole_mass < 0.99 * ATOMIC_MASS_UNIT )
2086  continue;
2087 
2088  vector<string> react_iso_labels;
2089  ChemNuclideList atomsLeftToRight;
2090  vector< int > numAtoms;
2091  string embellishments;
2092  // parse reactant label
2093  bool lgParseOK = parse_species_label( it->second->reactants[i]->label.c_str(), atomsLeftToRight, numAtoms, embellishments );
2094  if( !lgParseOK )
2095  TotalInsanity();
2096  // generate isotopologue labels
2098  atomsLeftToRight,
2099  numAtoms,
2100  atom_old,
2101  atom_new,
2102  embellishments,
2103  react_iso_labels );
2104  for( unsigned j=0; j<react_iso_labels.size(); ++j )
2105  {
2106  int numAtomsTot = 0;
2107  for( long k=0; k<it->second->nproducts; ++k )
2108  {
2109  // ignore products with no nucleons (e-, PHOTON, CRPHOT, ... )
2110  if( it->second->products[k]->mole_mass < 0.99 * ATOMIC_MASS_UNIT )
2111  continue;
2112 
2113  atomsLeftToRight.clear();
2114  numAtoms.clear();
2115  embellishments.clear();
2116  // parse product label
2117  lgParseOK = parse_species_label( it->second->products[k]->label.c_str(), atomsLeftToRight, numAtoms, embellishments );
2118  ASSERT( lgParseOK == true );
2119  // Loop over all positions in this product
2120  for( unsigned position = 0; position < atomsLeftToRight.size(); ++position )
2121  {
2122  string prod_iso_label;
2123  // generate isotopologue labels
2125  position,
2126  atomsLeftToRight,
2127  numAtoms,
2128  atom_old,
2129  atom_new,
2130  embellishments,
2131  prod_iso_label );
2132 
2133  if( prod_iso_label.empty() )
2134  continue;
2135 
2136  // Generate new reaction string
2137  string react_string;
2138  // first write reactants
2139  for( long i1=0; i1<i; ++i1 )
2140  {
2141  react_string += it->second->reactants[i1]->label;
2142  if( i1 != it->second->nreactants-1 )
2143  react_string += ",";
2144  }
2145  react_string += react_iso_labels[j];
2146  if( i != it->second->nreactants-1 )
2147  react_string += ",";
2148  for( long i2=i+1; i2<it->second->nreactants; ++i2 )
2149  {
2150  react_string += it->second->reactants[i2]->label;
2151  if( i2 != it->second->nreactants-1 )
2152  react_string += ",";
2153  }
2154 
2155  react_string += "=>";
2156  // now write products
2157  for( long k1=0; k1<k; ++k1 )
2158  {
2159  react_string += it->second->products[k1]->label;
2160  if( k1 != it->second->nproducts-1 )
2161  react_string += ",";
2162  }
2163  react_string += prod_iso_label;
2164  if( k != it->second->nproducts-1 )
2165  react_string += ",";
2166  for( long k2=k+1; k2<it->second->nproducts; ++k2 )
2167  {
2168  react_string += it->second->products[k2]->label;
2169  if( k2 != it->second->nproducts-1 )
2170  react_string += ",";
2171  }
2172 
2173  string canon_react_string = canonicalize_reaction_label( react_string.c_str() );
2174  // store new reaction string and pointer to old
2175  newReactionStrings.push_back( canon_react_string );
2176  oldReactions.push_back( it->second.get_ptr() );
2177  // This is the number of unique product lists given a particular reactant list. Will divide rate below.
2178  branchingRatios.push_back( numAtoms[position]/numSites );
2179 
2180  if( lgDebug )
2181  fprintf( ioQQQ, "DEBUGGG mole_generate_isotopologue_reactions .................... %s\t\t(%2i/%2i).\n",
2182  canon_react_string.c_str(), numAtoms[position], numSites );
2183 
2184  numAtomsTot += numAtoms[position];
2185  }
2186  }
2187  ASSERT( numAtomsTot == numSites );
2188  }
2189  }
2190  }
2191 
2192  ASSERT( oldReactions.size() == newReactionStrings.size() );
2193 
2194  // now declare new reactions
2195  vector<mole_reaction*>::const_iterator it2 = oldReactions.begin();
2196  vector<realnum>::const_iterator it3 = branchingRatios.begin();
2197  for( vector<string>::const_iterator it1 = newReactionStrings.begin(); it1 != newReactionStrings.end(); ++it1, ++it2, ++it3 )
2198  {
2199  fixit("make adjustments to a for mass?");
2200 
2201  // don't overwrite existing reaction with these new auto-generated details
2202  if( mole_priv::reactab.find( it1->c_str() ) == mole_priv::reactab.end() )
2203  {
2204  ASSERT( *it3 <= 1. + FLT_EPSILON );
2205  fixit("multiply by *it3 here. ASSERT at mole_reactions.cpp:1190 will blow currently.");
2206  newreact( it1->c_str(), (*it2)->name(), (*it2)->a /* * (*it3) */, (*it2)->b, (*it2)->c );
2207  }
2208  }
2209 
2210  return;
2211 }
2212 
2214 {
2215  DEBUG_ENTRY( "mole_check_reverse_reactions()" );
2216 
2217  char chLabel[50], chLabelSave[50];
2218  int exists;
2219 
2220  for(mole_reaction_i p=mole_priv::reactab.begin();
2221  p != mole_priv::reactab.end(); ++p)
2222  {
2223  mole_reaction_i q = p;
2224  strcpy( chLabel, p->second->label.c_str() );
2225  strcpy( chLabelSave, p->second->label.c_str() );
2226  char *str = chLabel;
2227  const char *delim = "=>";
2228  char *chNewProducts = strtok( str, delim );
2229  char *chNewReactants = strtok( NULL, delim );
2230  char chNewReaction[50];
2231 
2232  strcpy( chNewReaction, chNewReactants );
2233  strcat( chNewReaction, "=>" );
2234  strcat( chNewReaction, chNewProducts );
2235 
2236 
2237  q = mole_priv::reactab.find(chNewReaction);
2238 
2239  exists = (q != mole_priv::reactab.end());
2240  if ( !exists )
2241  {
2242  if( trace.lgTraceMole )
2243  {
2244  fprintf(ioQQQ,"Warning! No reverse reaction for %30s. ", p->second->label.c_str() );
2245  fprintf( ioQQQ,"\n" );
2246  }
2247 
2248  fixit("NB reverse reactions should be generated here");
2249  }
2250  }
2251 
2252  return;
2253 }
2254 
2255 STATIC double mole_get_equilibrium_condition( const char buf[] )
2256 {
2257  DEBUG_ENTRY( "mole_get_equilibrium_condition()" );
2258 
2259  mole_reaction *rate = mole_findrate_s(buf);
2260  double result = mole_get_equilibrium_condition( rate );
2261  return result;
2262 }
2263 
2265 {
2266  DEBUG_ENTRY( "mole_get_equilibrium_condition()" );
2267 
2268  if( !rate )
2269  return 0.;
2270 
2271  // multiply by reactant partition functions, then divide by products'
2272  double ln_result = 0.;
2273  for( long i=0; i<rate->nproducts; ++i)
2274  {
2275  double fac = mole_partition_function(rate->products[i]);
2276  if( fac==0. )
2277  return 0.;
2278  ln_result += log(fac);
2279  }
2280  for( long i=0; i<rate->nreactants; ++i)
2281  {
2282  double fac = mole_partition_function(rate->reactants[i]);
2283  if( fac==0. )
2284  return (double) BIGFLOAT;
2285  ln_result -= log(fac);
2286  }
2287  // Prevent overflow
2288  double result = exp( MIN2( SEXP_LIMIT, ln_result ) );
2289 
2290  //fprintf( ioQQQ, "DEBUGGG equilibrium %20s\t%e\n", rate->label.c_str(), result );
2291  return result;
2292 }
2293 
2294 STATIC double mole_partition_function( const molecule* const sp)
2295 {
2296  DEBUG_ENTRY( "mole_partition_function()" );
2297 
2298  if( sp->label == "PHOTON" || sp->label == "CRPHOT" )
2299  {
2300  fixit("How can we adapt existing structures to have a photon energy or range available here?");
2301  fixit("include 2hnu^3/c^2. Understand HNU3C2 macro!");
2302  return 1.; //sexp( energy_ryd/phycon.te_ryd );
2303  }
2304  else if( sp->label == "CRP" || sp->label == "grn" )
2305  return 1.;
2306 
2307  fixit("need to figure out stat weight for any given particle");
2308  double q = 1.;
2309  // last factors convert kJ/mol to Kelvin/particle
2310  double deltaH = sp->form_enthalpy * (1e10/AVOGADRO/BOLTZMANN);
2311  ASSERT( sp->mole_mass > 0. );
2312  double part_fun = powpq(phycon.te*sp->mole_mass/(HION_LTE_POP*ELECTRON_MASS),3,2) * q * dsexp(deltaH/phycon.te);
2313  ASSERT( part_fun < BIGFLOAT );
2314  ASSERT( part_fun >= 0. );
2315 
2316  return part_fun;
2317 }
2318 
2320 {
2321  DEBUG_ENTRY( "mole_cmp_num_in_out_reactions()" );
2322 
2323  vector<long> numForm, numDest;
2324  numForm.resize( mole_global.num_total );
2325  numDest.resize( mole_global.num_total );
2326 
2327  for(mole_reaction_i p=mole_priv::reactab.begin(); p != mole_priv::reactab.end(); p++)
2328  {
2329  count_ptr<mole_reaction> rate = p->second;
2330  for( long i=0; i<rate->nreactants; ++i)
2331  {
2332  ++numDest[ rate->reactants[i]->index ];
2333  }
2334 
2335  for( long i=0; i<rate->nproducts; ++i)
2336  {
2337  ++numForm[ rate->products[i]->index ];
2338  }
2339  }
2340 
2341  for( unsigned i=0; i<numForm.size(); ++i )
2342  {
2343  if( numForm[i]==0 && numDest[i]==0 )
2344  continue;
2345  if( numForm[i]>1 && numDest[i]>1 )
2346  continue;
2347  if( mole_global.list[i]->isMonatomic() )
2348  continue;
2349  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] );
2350  }
2351 
2352  return;
2353 }
2354 
2355 STATIC char *getcsvfield(char **s,char c);
2356 STATIC void parse_base(char *s)
2357 {
2358  char *label, *reactstr, *f;
2359  double a, b, c;
2360  label = getcsvfield(&s,':');
2361  reactstr = getcsvfield(&s,':');
2362  f = getcsvfield(&s,':');
2363  a = atof(f);
2364  f = getcsvfield(&s,':');
2365  b = atof(f);
2366  f = getcsvfield(&s,':');
2367  c = atof(f);
2368 
2369  newreact(label,reactstr,a,b,c);
2370 
2371 }
2372 
2373 STATIC void newreact(const char label[], const char fun[], double a, double b, double c)
2374 {
2375  DEBUG_ENTRY( "newreact()" );
2376 
2377  ratefunc rate = findfunc(fun);
2378  if (rate.get_ptr() == NULL)
2379  {
2380  fprintf(stderr,"Rate function %s not known for reaction %s. Aborting. Sorry.\n",fun,label);
2381  cdEXIT( EXIT_FAILURE );
2382  }
2383 
2384  if( a < 0. )
2385  {
2386  fprintf(ioQQQ,"\n PROBLEM Reaction %s has negative pre-coefficient. Aborting. Sorry.\n", label);
2387  cdEXIT( EXIT_FAILURE );
2388  }
2389 
2390  rate->label = label;
2391  rate->a = a;
2392  rate->b = b;
2393  rate->c = c;
2394  rate->source = source;
2395 
2396  rate->photon = 0;
2397 
2398  if( parse_reaction( rate, label ) == 0 )
2399  return;
2400 
2401  canonicalize_reaction( rate );
2402 
2403  if( lgReactionTrivial( rate ) )
2404  return;
2405 
2406  if (mole_global.offReactions.find(rate->label)
2407  != mole_global.offReactions.end())
2408  {
2409  fprintf(ioQQQ," W-reaction %s disabled\n",rate->label.c_str());
2410  phycon.lgPhysOK = false;
2411  return;
2412  }
2413 
2414  const char *rateLabelPtr = rate->label.c_str();
2415 
2416  ASSERT(lgReactBalance(rate)); /* Verify rate conserves particles and charge */
2417 
2418  rate->udfastate = ABSENT;
2419  if( UDFA)
2420  {
2421  compare_udfa(rate);
2422  if (rate->udfastate == ABSENT)
2423  {
2424  fprintf(stderr,"Reaction %s not in UDFA\n",rateLabelPtr);
2425  }
2426  }
2427 
2428  /* >> chng 06 Oct 10 rjrw: use 1/(1/m1+1/m2) for reduced mass to prevent underflow */
2429  if (rate->nreactants == 2 && rate->reactants[0]->mole_mass!=0.0 && rate->reactants[1]->mole_mass!=0.0 )
2430  {
2431  rate->reduced_mass = 1./(1./rate->reactants[0]->mole_mass+1./rate->reactants[1]->mole_mass);
2432  }
2433  else
2434  {
2435  rate->reduced_mass = 0.;
2436  }
2437 
2438  /* If everything is OK, can register the reaction */
2439  mole_reaction_i p = mole_priv::reactab.find(rateLabelPtr);
2440  int exists = (p != mole_priv::reactab.end());
2441  // do not comment in release or beta version, or if NO TIMES entered
2443  {
2444  /* Replace old rate */
2445  fprintf(ioQQQ,"Attention: duplicate reaction %s -- using new version\n",rateLabelPtr);
2446  }
2447  mole_priv::reactab[rateLabelPtr] = rate;
2448 }
2449 
2450 STATIC long parse_reaction( count_ptr<mole_reaction>& rate, const char label[] )
2451 {
2452  DEBUG_ENTRY( "parse_reaction()" );
2453 
2454  for (int i=0;i<MAXREACTANTS;i++)
2455  {
2456  rate->reactants[i] = NULL;
2457  }
2458  rate->nreactants = 0;
2459 
2460  for (int i=0;i<MAXPRODUCTS;i++)
2461  {
2462  rate->products[i] = NULL;
2463  }
2464  rate->nproducts = 0;
2465 
2466  bool lgProd = false;
2467  string buf = "";
2468  for(int i=0;!i || label[i-1]!='\0';i++)
2469  {
2470  if(label[i] == ',' || label[i] == '=' || label[i] == '\0')
2471  {
2472  molecule *sp = findspecies(buf.c_str());
2473  if( sp == null_mole || !sp->isEnabled )
2474  {
2475  if( trace.lgTraceMole )
2476  fprintf(ioQQQ,"Mole_reactions: ignoring reaction %s (species %s not active)\n",label,buf.c_str());
2477  return 0;
2478  }
2479  buf = "";
2480  if(! lgProd)
2481  {
2482  if (rate->nreactants >= MAXREACTANTS)
2483  {
2484  fprintf(stderr,"Mole_reactions: Too many reactants in %s, only %d allowed\n",label,MAXREACTANTS);
2486  }
2487  rate->reactants[rate->nreactants] = sp;
2488  rate->nreactants++;
2489  }
2490  else
2491  {
2492  if (rate->nproducts >= MAXPRODUCTS)
2493  {
2494  fprintf(stderr,"Mole_reactions: Too many products in %s, only %d allowed\n",label,MAXPRODUCTS);
2496  }
2497  rate->products[rate->nproducts] = sp;
2498  rate->nproducts++;
2499  }
2500  if(label[i] == '=')
2501  {
2502  i++; /* skip '>' as well */
2503  if (label[i] != '>')
2504  {
2505  fprintf(ioQQQ,"Format error in reaction %s\n",label);
2507  }
2508  lgProd = true;
2509  }
2510  }
2511  else
2512  {
2513  buf += label[i];
2514  }
2515  }
2516 
2517  for (int i=0;i<MAXREACTANTS;i++)
2518  if( rate->reactants[i] != NULL )
2519  ++rate->reactants[i]->n_react;
2520  for (int i=0;i<MAXPRODUCTS;i++)
2521  if( rate->products[i] != NULL )
2522  ++rate->products[i]->n_react;
2523 
2524  ASSERT( rate->nreactants );
2525  ASSERT( rate->nproducts );
2526 
2527  return 1;
2528 }
2529 
2530 STATIC string canonicalize_reaction_label( const char label[] )
2531 {
2532  DEBUG_ENTRY( "canonicalize_reaction_label()" );
2533 
2534  // set up a dummy reaction
2535  ratefunc rate = findfunc("null");
2536  rate->label = label;
2537  parse_reaction( rate, label );
2538  canonicalize_reaction( rate );
2539 
2540  //if( !conv.nTotalIoniz && strcmp( label, rate->label.c_str() ) != 0 )
2541  // fprintf( ioQQQ, "DEBUGGG reaction label %20s canonicalized to %20s\n", label, rate->label.c_str() );
2542 
2543  return rate->label;
2544 }
2545 
2547 {
2548  DEBUG_ENTRY( "canonicalize_reaction()" );
2549 
2550  /* Put species in canonical order to make sure reactions are unique.
2551  Can cause problems when a consistent ordering of species is
2552  required (look for references to "reactants[0]" for examples) */
2554  t_mole_global::sort(rate->products,rate->products+rate->nproducts);
2555 
2556  // now reorder label in same (new) order
2557  string newLabel;
2558  for( long i=0; i<rate->nreactants; ++i )
2559  {
2560  newLabel += rate->reactants[i]->label;
2561  if( i != rate->nreactants-1 )
2562  newLabel += ",";
2563  }
2564  newLabel += "=>";
2565  for( long i=0; i<rate->nproducts; ++i )
2566  {
2567  newLabel += rate->products[i]->label;
2568  if( i != rate->nproducts-1 )
2569  newLabel += ",";
2570  }
2571 
2572  // overwrite original label with canonical
2573  rate->label = newLabel;
2574 
2575  return;
2576 }
2577 
2578 // Returns true if reactant and product vectors are identical.
2580 {
2581  DEBUG_ENTRY( "lgReactionTrivial()" );
2582 
2583  bool lgTrivial = false;
2584  if( rate->nreactants == rate->nproducts )
2585  {
2586  lgTrivial = true;
2587  for( int k=0; k<rate->nreactants; ++k )
2588  {
2589  if( rate->reactants[k] != rate->products[k] )
2590  {
2591  lgTrivial = false;
2592  break;
2593  }
2594  }
2595  }
2596 
2597  return lgTrivial;
2598 }
2599 
2601 {
2602  DEBUG_ENTRY( "register_reaction_vectors()" );
2603 
2604  for (long k=0;k<rate->nreactants;k++)
2605  {
2606  rate->rvector[k] = NULL;
2607  rate->rvector_excit[k] = NULL;
2608  }
2609 
2610  for (long k=0;k<rate->nproducts;k++)
2611  {
2612  rate->pvector[k] = NULL;
2613  rate->pvector_excit[k] = NULL;
2614  }
2615 
2616  /* Label catalytic species */
2617  for (long i=0;i<rate->nproducts;i++)
2618  {
2619  if (rate->pvector[i] == NULL)
2620  {
2621  for (long k=0;k<rate->nreactants;k++)
2622  {
2623  if (rate->rvector[k] == NULL)
2624  {
2625  if (rate->products[i] == rate->reactants[k])
2626  {
2627  rate->rvector[k] = rate->products[i];
2628  rate->pvector[i] = rate->reactants[k];
2629  break;
2630  }
2631  }
2632  }
2633  }
2634  }
2635 
2636  /* Label other intra-group transfers */
2637  for (long i=0;i<rate->nproducts;i++)
2638  {
2639  if (rate->pvector[i] == NULL)
2640  {
2641  for (long k=0;k<rate->nreactants;k++)
2642  {
2643  if (rate->rvector[k] == NULL)
2644  {
2645  if (rate->products[i]->groupnum != -1 &&
2646  rate->products[i]->groupnum ==
2647  rate->reactants[k]->groupnum)
2648  {
2649  rate->rvector[k] = rate->products[i];
2650  rate->pvector[i] = rate->reactants[k];
2651  break;
2652  }
2653  }
2654  }
2655  }
2656  }
2657 
2658  /* Label excited/deexcited pairs */
2659  for (long i=0;i<rate->nproducts;i++)
2660  {
2661  if (rate->pvector[i] == NULL && rate->pvector_excit[i] == NULL)
2662  {
2663  for (long k=0;k<rate->nreactants;k++)
2664  {
2665  if (rate->rvector[k] == NULL && rate->rvector_excit[k] == NULL )
2666  {
2667  if ( lgDifferByExcitation( *rate->products[i], *rate->reactants[k] ) )
2668  {
2669  rate->rvector_excit[k] = rate->products[i];
2670  rate->pvector_excit[i] = rate->reactants[k];
2671  break;
2672  }
2673  }
2674  }
2675  }
2676  }
2677 
2678  return;
2679 }
2680 
2681 
2683 {
2684  FILE *sparsefp;
2685  int i, j, nb, ch;
2686  long int ratej;
2687  double **c;
2688 
2689  c = (double **)MALLOC((size_t)mole_global.num_total*sizeof(double *));
2690  c[0] = (double *)MALLOC((size_t)mole_global.num_total*
2691  mole_global.num_total*sizeof(double));
2692 
2693  for(i=1;i<mole_global.num_total;i++)
2694  {
2695  c[i] = c[i-1]+mole_global.num_total;
2696  }
2697 
2698  for ( j=0; j < mole_global.num_total; j++ )
2699  {
2700  for ( i=0; i < mole_global.num_total; i++ )
2701  {
2702  c[j][i] = 0.;
2703  }
2704  }
2705 
2706  for(mole_reaction_i p=mole_priv::reactab.begin();
2707  p != mole_priv::reactab.end(); ++p)
2708  {
2709  mole_reaction &rate = *p->second;
2710 
2711  for (j=0;j<rate.nreactants;j++)
2712  {
2713  ratej = rate.reactants[j]->index;
2714  for (i=0;i<rate.nreactants;i++)
2715  {
2716  if (rate.rvector[i] == NULL)
2717  c[ratej][rate.reactants[i]->index] = 1.0;
2718  }
2719  for (i=0;i<rate.nproducts;i++)
2720  {
2721  if (rate.pvector[i] == NULL)
2722  c[ratej][rate.products[i]->index] = 1.0;
2723  }
2724  }
2725  }
2726 
2727  sparsefp = open_data("sparse.pbm","w");
2728  fprintf(sparsefp,"P4\n%d %d\n",
2730 
2731  for ( j=0; j < mole_global.num_total; j++ )
2732  {
2733  nb = ch = 0;
2734  for ( i=0; i < mole_global.num_total; i++ )
2735  {
2736  ch = (ch << 1) | (c[i][j] != 0.0);
2737  nb++;
2738  if (nb == 8)
2739  {
2740  fputc(ch,sparsefp);
2741  nb = ch = 0;
2742  }
2743  }
2744  if (nb != 0)
2745  {
2746  ch <<= 8-nb;
2747  fputc(ch,sparsefp);
2748  }
2749  }
2750  fclose(sparsefp);
2751  free(c[0]);
2752  free(c);
2753 }
2754 
2755 #ifndef NDEBUG
2757 {
2758  molecule::nNucsMap nel;
2759  int dcharge, n, sign;
2760  bool lgOK = true;
2761 
2762  dcharge = 0;
2763  for (n=0;n<rate->nreactants;n++)
2764  {
2765  for( nNucs_i it = rate->reactants[n]->nNuclide.begin(); it != rate->reactants[n]->nNuclide.end(); ++it )
2766  nel[it->first] += it->second;
2767  dcharge += rate->reactants[n]->charge;
2768  }
2769  for (n=0;n<rate->nproducts;n++)
2770  {
2771  for( nNucs_i it = rate->products[n]->nNuclide.begin(); it != rate->products[n]->nNuclide.end(); ++it )
2772  nel[it->first] -= it->second;
2773  dcharge -= rate->products[n]->charge;
2774  }
2775  if (dcharge != 0)
2776  {
2777  fprintf(stderr,"Reaction %s charge out of balance by %d\n",
2778  rate->label.c_str(),dcharge);
2779  lgOK = false;
2780  }
2781 
2782  for( nNucs_i it = nel.begin(); it != nel.end(); ++it )
2783  {
2784  if(it->second != 0)
2785  {
2786  if(it->second > 0)
2787  sign = 1;
2788  else
2789  sign = -1;
2790  fprintf(stderr,"Error: reaction %s %s %d of element %s\n",
2791  rate->label.c_str(),sign==1?"destroys":"creates",
2792  sign*it->second,
2793  it->first->label().c_str() );
2794  lgOK = false;
2795  }
2796  }
2797  return lgOK;
2798 }
2799 #endif
2800 
2801 enum {BUFSIZE=256};
2802 
2803 namespace
2804 {
2805  class formula_species {
2806  public:
2807  molecule *reactants[MAXREACTANTS], *products[MAXPRODUCTS];
2808  };
2809 
2810  bool operator< (const formula_species &a, const formula_species &b)
2811  {
2812  int i;
2813  for (i=0;i<MAXREACTANTS;i++)
2814  {
2815  if (a.reactants[i]<b.reactants[i])
2816  return true;
2817  else if (a.reactants[i]>b.reactants[i])
2818  return false;
2819  }
2820  for (i=0;i<MAXPRODUCTS;i++)
2821  {
2822  if (a.products[i]<b.products[i])
2823  return true;
2824  else if (a.products[i]>b.products[i])
2825  return false;
2826  }
2827  return false;
2828  }
2829 
2830  class udfa_reaction {
2831  public:
2832  int index;
2833  formula_species l;
2834  char source; /* Calculated, Estimated, Literature compilation, Measured */
2835  double a, b, c, trange[2]; /* Overall scale and valid temperature range */
2836  };
2837 }
2838 
2839 static map <formula_species,count_ptr<udfa_reaction> > udfatab;
2840 
2841 STATIC void read_data(const char file[], void (*parse)(char *s))
2842 {
2843  DEBUG_ENTRY( "read_data()" );
2844  char buf[BUFSIZE];
2845 
2846  FILE *fp = open_data(file,"r");
2847  if (!fp)
2848  {
2849  fprintf(stderr,"Error, could not read %s\n",file);
2851  }
2852 
2853  fixit("this seg-faults if file ends in blank line!");
2854  while(fgets(buf,BUFSIZE,fp))
2855  {
2856  if( buf[0] == '#' )
2857  continue;
2858  parse(buf);
2859  }
2860  fclose(fp);
2861 }
2862 #define FLTEQ(a,b) (fabs((a)-(b)) <= 1e-6*fabs((a)+(b)))
2863 STATIC void parse_udfa(char *s)
2864 {
2865  char *f;
2866  unsigned int havespecies = 1, i, n;
2867  /* lgCRPHOT is true for CRPHOT reactions as we change the data
2868  * format for them */
2869  int lgCRPHOT=0;
2870 
2871  count_ptr<udfa_reaction>r(new udfa_reaction);
2872  f = getcsvfield(&s,',');
2873  r->index = atoi(f);
2874 
2875  /* Load reactants */
2876  for (n=0;n<MAXREACTANTS;n++)
2877  {
2878  r->l.reactants[n] = NULL;
2879  }
2880  i = 0;
2881  for (n=0;n<MAXREACTANTS;n++)
2882  {
2883  f = getcsvfield(&s,',');
2884  if (f[0] != '\0')
2885  {
2886  i++;
2887  r->l.reactants[n] = findspecies(f);
2888  if (r->l.reactants[n] == null_mole)
2889  havespecies = 0;
2890  if (!strncmp(f,"CRPHOT",6))
2891  lgCRPHOT = 1;
2892  }
2893  }
2894  t_mole_global::sort(r->l.reactants,r->l.reactants+i);
2895 
2896  /* Load products */
2897  for (n=0;n<MAXPRODUCTS;n++)
2898  {
2899  r->l.products[n] = NULL; /* Sentinel */
2900  }
2901  i = 0;
2902  for (n=0;n<MAXPRODUCTS;n++)
2903  {
2904  f = getcsvfield(&s,',');
2905  if (f[0] != '\0')
2906  {
2907  i++;
2908  r->l.products[n] = findspecies(f);
2909  if (r->l.products[n] == null_mole)
2910  havespecies = 0;
2911  }
2912  }
2913 
2914  t_mole_global::sort(r->l.products,r->l.products+i);
2915 
2916  /* Load rate parameters */
2917  f = getcsvfield(&s,',');
2918  r->a = atof(f);
2919  f = getcsvfield(&s,',');
2920  r->b = atof(f);
2921  f = getcsvfield(&s,',');
2922  r->c = atof(f);
2923 
2924  if( lgCRPHOT)
2925  {
2926  /* UDFA has a uniform value for the cosmic ray field independent of
2927  circumstances which we correct -- verify they haven't changed
2928  anything and move the multiplicative constant into our usual place
2929  for it. */
2930  ASSERT (FLTEQ(r->a,1.3e-17));
2931  r->a = r->c;
2932  r->c = 0.;
2933  }
2934 
2935  /* Load data confidence and range of temperature validity */
2936  f = getcsvfield(&s,',');
2937  r->source = f[0]?f[0]:'?';
2938  for (n=0;n<2;n++) {
2939  f = getcsvfield(&s,',');
2940  r->trange[n] = atof(f);
2941  }
2942 
2943  if (havespecies)
2944  {
2945  if (udfatab.find(r->l) != udfatab.end())
2946  {
2947  fprintf(stderr,"Duplicate reaction\n");
2948  }
2949  udfatab[r->l] = r;
2950  }
2951 }
2952 STATIC char *getcsvfield(char **s, char c)
2953 {
2954  char *sv, *f;
2955 
2956  sv = strchr(*s,c);
2957  if (sv) {
2958  *sv++ = '\0';
2959  }
2960  f = *s;
2961  *s = sv;
2962  return f;
2963 }
2965 {
2966  formula_species s;
2967 
2968  for (int n=0;n<MAXREACTANTS;n++)
2969  {
2970  s.reactants[n] = rate->reactants[n];
2971  }
2972  for (int n=0;n<MAXPRODUCTS;n++)
2973  {
2974  s.products[n] = rate->products[n];
2975  }
2976  map<formula_species, count_ptr<udfa_reaction> >::iterator p
2977  = udfatab.find(s);
2978  if (p == udfatab.end() )
2979  {
2980  /* fprintf(stdout,"Did not find reaction %s\n",rate->label); */
2981  return;
2982  }
2983  else
2984  {
2985  count_ptr<udfa_reaction>& u = p->second;
2986  if (FLTEQ(rate->a,u->a) && FLTEQ(rate->b,u->b) && FLTEQ(rate->c,u->c))
2987  {
2988  rate->udfastate = CORRECT;
2989  /* fprintf(stdout,"Reaction %s agrees\n",rate->label); */
2990  }
2991  else
2992  {
2993  rate->udfastate = CONFLICT;
2994  /* fprintf(stdout,"Reaction %18.18s clashes: a %9.2e %9.2e|b %9.2e %9.2e|c %9.2e %9.2e\n",
2995  rate->label,rate->a,u->a,rate->b,u->b,rate->c,u->c); */
2996  }
2997  }
2998 }
2999 
3000 namespace
3001 {
3002  ratefunc findfunc (const char name[])
3003  {
3004  return count_ptr<mole_reaction>(mole_priv::functab[name]->Create());
3005  }
3006 }
3007 
3009 {
3010  enum { DEBUG_MOLE = false };
3011 
3012  DEBUG_ENTRY( "mole_update_rks()" );
3013 
3015 
3016  mole_h_reactions();
3017 
3018  for (mole_reaction_i p
3019  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
3020  {
3021  mole_reaction &rate = *p->second;
3022  long index = rate.index;
3023  realnum newrk = rate.a*rate.rk();
3024  if (DEBUG_MOLE)
3025  {
3026  realnum oldrk = (realnum)mole.reaction_rks[index];
3027  if (fabs(newrk-oldrk) > 0.1*newrk)
3028  fprintf(ioQQQ,"%s: %15.8g => %15.8g\n",
3029  rate.label.c_str(),oldrk,newrk);
3030  }
3031  mole.reaction_rks[index] = newrk;
3032  }
3033 }
3035 {
3036  DEBUG_ENTRY( "mole_rk_bigchange()" );
3037  enum { DEBUG_MOLE = false };
3038 
3039  if ( mole.old_reaction_rks.size() == 0 )
3040  {
3041  mole.old_zone = -1;
3042  mole.old_reaction_rks.resize(mole.reaction_rks.size());
3043  }
3044 
3045  if (nzone > 1)
3046  {
3047  ASSERT(mole.old_zone == nzone - 1);
3048  double bigchange = 0.;
3049  unsigned long bigindex = ULONG_MAX;
3050  for (unsigned long index=0; index<mole.reaction_rks.size(); ++index)
3051  {
3052  double oldrk = mole.old_reaction_rks[index],
3053  newrk = mole.reaction_rks[index],
3054  sum = oldrk+newrk, diff = newrk-oldrk;
3055  if (sum > 0.)
3056  {
3057  double change = fabs(diff)/sum;
3058  if (change > bigchange)
3059  {
3060  bigchange = change;
3061  bigindex = index;
3062  }
3063  }
3064  }
3065 
3066  for (mole_reaction_i p
3067  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
3068  {
3069  mole_reaction &rate = *p->second;
3070  if (bigindex == (unsigned) rate.index)
3071  {
3072  double oldrk = mole.old_reaction_rks[bigindex],
3073  newrk = mole.reaction_rks[bigindex];
3074  double pct = 0.;
3075  if (oldrk > 0.)
3076  pct = 100.*(newrk-oldrk)/oldrk;
3077  fprintf(ioQQQ, "Zone %ld, big chemistry rate change %s:"
3078  " %15.8g => %15.8g (%6.2g%%)\n",
3079  nzone,rate.label.c_str(),oldrk,newrk,pct);
3080  break;
3081  }
3082  }
3083  }
3084 
3085  mole.old_zone = nzone;
3086  for (unsigned long index=0; index<mole.reaction_rks.size(); ++index)
3087  {
3088  mole.old_reaction_rks[index] = mole.reaction_rks[index];
3089  }
3090 }
3091 
3093 {
3094  DEBUG_ENTRY( "mole_h2_grain_form()" );
3095 
3096  double T_ortho_para_crit,xi_ELRD, beta_alpha_ELRD, recombination_efficiency_ELRD, Td;
3098  realnum AveVelH2 = GetAveVelocity( 2.f * dense.AtomicWeight[ipHYDROGEN] );
3099 
3100  /* H2 formation on grains;
3101  * rate from
3102  * >>refer H2 grain formation Hollenbach, D., & McKee, C.F., 1979, ApJS, 41, 555 eq 3.4 3.8 */
3103  if( gv.lgDustOn() )
3104  {
3105 
3107  {
3108  fixit("Is this still necessary?");
3109  /* hmole is called before grains, so assure that all the grain stuff is properly initialized */
3110  GrainDrive();
3111  }
3112 
3113  /* these are rates (s-1) H2 will be deactivated by collisions with grains
3114  * will be incremented below
3115  * H2 ortho - para conversion on grain surface */
3117  /* rate (s-1) v=0, J=1 level goes to 0 */
3118  h2.rate_grain_J1_to_J0 = 0.;
3119 
3120  /* loop over all grain species */
3121  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3122  {
3123  /* >>chng 02 feb 15, removed check tedust > 1.01, change in GrainsInit
3124  * guarantees that all relevant parameters are initialized, PvH */
3125 
3126  double sticking_probability_H = sticking_probability_H_func( phycon.te, gv.bin[nd]->tedust );
3127 
3128  bool lgUseQHeat = ENABLE_QUANTUM_HEATING &&
3129  gv.lgGrainPhysicsOn && gv.bin[nd]->lgQHeat;
3130  long k, qnbin=0;
3131  vector<double> qtemp, qprob;
3132  if ( lgUseQHeat )
3133  {
3134  /* >>chng 04 feb 21, included quantum heating in calculation of formation rate, PvH */
3135  qtemp.resize(NQGRID);
3136  qprob.resize(NQGRID);
3137 
3138  qheat(qtemp,qprob,&qnbin,nd);
3139 
3140  if( gv.bin[nd]->lgUseQHeat )
3141  {
3142  ASSERT( qnbin > 0 );
3143  }
3144  else
3145  {
3146  qnbin = 1;
3147  qprob[0] = 1.;
3148  qtemp[0] = gv.bin[nd]->tedust;
3149  }
3150 
3151  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.;
3152 
3153  for( k=0; k < qnbin; k++ )
3154  {
3155  /* fraction of impacts that produce H2 before evaporation from grain surface.
3156  * this is equation 3.4 of
3157  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555
3158  * 1e4 is ratio of total absorption sites to appropriate sites
3159  * 920 is D_H and chosen to get f_a = 0.5 at 100 K.
3160  * factor of 0.6252 needed to obtain std ism rate to be 3e-17 at 100 K,
3161  * the value deduced by
3162  * >>refer H2 grain physics Jura, M., 1974, ApJ, 197, 581 */
3163  double conversion_efficiency_HM79 = 1/(1. + 1e4*sexp(920./qtemp[k]));
3164  sticking_probability_H = sticking_probability_H_func( phycon.te, qtemp[k] );
3165 
3166  gv.bin[nd]->rate_h2_form_grains_HM79 += qprob[k] * sticking_probability_H *
3167  conversion_efficiency_HM79;
3168  }
3169 
3170  /* NB IntArea is total, not projected, area, must div by 4 */
3171  /* gv.bin[nd]->rate_h2_form_grains_HM79 has units s^-1 since gv.bin[nd]->cnv_H_pCM3 has units cm-3 */
3172  /* cnv_H_pCM3 converts <unit>/H (default depletion) -> <unit>/cm^3 (actual depletion), units are cm-3 */
3173  gv.bin[nd]->rate_h2_form_grains_HM79 *= 0.5 * AveVelH *
3174  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3175 
3176  ASSERT( gv.bin[nd]->rate_h2_form_grains_HM79 > 0. );
3177  }
3178  else
3179  {
3180  /* fraction of impacts that produce H2 before evaporation from grain surface.
3181  * this is equation 3.4 of
3182  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555
3183  * 1e4 is ratio of total absorption sites to appropriate sites
3184  * 920 is D_H and chosen to get f_a = 0.5 at 100 K.
3185  * factor of 0.6252 needed to obtain std ism rate to be 3e-17 at 100 K,
3186  * the value deduced by
3187  * >>refer H2 grain physics Jura, M., 1974, ApJ, 197, 581 */
3188  double conversion_efficiency_HM79 = 1/(1. + 1e4*sexp(920./gv.bin[nd]->tedust));
3189 
3190  /* NB IntArea is total area per H for default abundances, not projected area, must div by 4
3191  * units s^-1 since gv.bin[nd]->cnv_H_pCM3 has units H cm-3
3192  * final units are cm s-1*/
3193  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3194  /* cnv_H_pCM3 converts <unit>/H (default depletion) -> <unit>/cm^3 (actual depletion), units are cm-3 */
3195  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * conversion_efficiency_HM79;
3196  ASSERT( gv.bin[nd]->rate_h2_form_grains_HM79 > 0. );
3197  }
3198 
3199  if( lgUseQHeat )
3200  {
3201  /* H2 formation on grains from
3202  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29 */
3203  /* number of monolayers per second - only affects efficiency at very low or high temperatures */
3204  double f = 1e-10;
3205  /* equation 17
3206  double sqrt_term = POW2( 1. + sqrt( (10000.-200.)/(600.-200.) ) );*/
3207  double sqrt_term = 35.399494936611667;
3208 
3209  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.;
3210 
3211  for( k=0; k < qnbin; k++ )
3212  {
3213  double beta_alpha = 0.25 * sqrt_term *sexp(200./qtemp[k] );
3214  /* equation 16 */
3215  double xi = 1./ (1. + 1.3e13*sexp(1.5*1e4/qtemp[k])*sqrt_term/(2.*f) );
3216  /* expression for beta comes from just after equation 5 */
3217  double beta = 3e12 * sexp( 320. / qtemp[k] );
3218  /* recombination efficiency given by their equation 15, they call
3219  * this epsilon_H2 */
3220  double recombination_efficiency_CT02 = xi / (1. + 0.005*f/2./SDIV(beta) + beta_alpha );
3221  sticking_probability_H = sticking_probability_H_func( phycon.te, qtemp[k] );
3222 
3223  /* printf( " k %ld Td %.6e re*sp %.6e\n", k, qtemp[k], recombination_efficiency_CT02* */
3224  /* sticking_probability_H ); */
3225 
3226  gv.bin[nd]->rate_h2_form_grains_CT02 += qprob[k] * sticking_probability_H *
3227  recombination_efficiency_CT02;
3228  }
3229 
3230  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3231  * so x/4 is projected area of circle */
3232  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3233  /* gv.bin[nd]->rate_h2_form_grains_CT02 units s-1 */
3234  gv.bin[nd]->rate_h2_form_grains_CT02 *= 0.5 * AveVelH *
3235  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3236 
3237  ASSERT( gv.bin[nd]->rate_h2_form_grains_CT02 > 0. );
3238  }
3239  else
3240  {
3241  /* H2 formation on grains from
3242  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29 */
3243  /* number of monolayers per second - only affects efficiency at very low or high temperatures */
3244  double f = 1e-10;
3245  /* equation 17
3246  double sqrt_term = POW2( 1. + sqrt( (10000.-200.)/(600.-200.) ) );*/
3247  double sqrt_term = 35.399494936611667;
3248  double beta_alpha = 0.25 * sqrt_term * exp(-200./gv.bin[nd]->tedust);
3249  /* equation 16 */
3250  double xi = 1./ (1. + 1.3e13*exp(-1.5e4/gv.bin[nd]->tedust)*sqrt_term/(2.*f) );
3251  /* expression for beta comes from just after equation 5 */
3252  double beta = 3e12 * exp(-320./gv.bin[nd]->tedust);
3253  /* recombination efficiency given by their equation 15, they call
3254  * this epsilon_H2 */
3255  double recombination_efficiency_CT02 = beta*xi / (beta + 0.0025*f + beta*beta_alpha);
3256 
3257  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3258  * so x/4 is projected area of circle */
3259  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3260  /* units s-1 */
3261  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3262  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_CT02;
3263  ASSERT( gv.bin[nd]->rate_h2_form_grains_CT02 >= 0. );
3264  }
3265 
3266  if( lgUseQHeat )
3267  {
3268  /* H2 formation on grains from
3269  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3270  ** >>refer H2 form Cazaux, S.; Tielens, A. G. G. M. 2010, 2010ApJ...715..698C
3271  ** improved treatment modifying CT rate above to include Eley-Rideal effect
3272  ** data and formalism comes from Appendix C of above reference
3273  ** this branch does quantum heating assuming rates simply scale as grain temperature */
3274  /* new rate variable ending stands for "Eley Rideal" */
3275 
3276  gv.bin[nd]->rate_h2_form_grains_ELRD= 0.;
3277 
3278  if( gv.bin[nd]->matType == MAT_CAR || gv.bin[nd]->matType == MAT_CAR2 ||
3279  gv.bin[nd]->matType == MAT_SIC || gv.bin[nd]->matType == MAT_PAH ||
3280  gv.bin[nd]->matType == MAT_PAH2 )
3281  {
3282  for( k=0; k < qnbin; k++ )
3283  {
3284  Td = qtemp[k];
3285 
3286  beta_alpha_ELRD = exp(-800./Td) / (0.5389970511202651 * exp(-540./Td) + 5.6333909478365e-14*sqrt(Td) ) ;
3287  xi_ELRD= 1./(1. + 4.61e24*sexp(45000./Td));
3288  recombination_efficiency_ELRD= (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3289  sticking_probability_H = 1./(1. + 0.04*sqrt(Td+phycon.te) +
3290  0.002*phycon.te + 8e-6*phycon.te*phycon.te);
3291 
3292  gv.bin[nd]->rate_h2_form_grains_ELRD+= qprob[k] * sticking_probability_H *
3293  recombination_efficiency_ELRD;
3294  }
3295 
3296  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3297  ** so x/4 is projected area of circle */
3298  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3299  /* gv.bin[nd]->rate_h2_form_grains_ELRD units s-1 */
3300 
3301  gv.bin[nd]->rate_h2_form_grains_ELRD*= 0.5 * AveVelH *
3302  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3303 
3304  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD> 0. );
3305  }
3306 
3307  else if( gv.bin[nd]->matType == MAT_SIL || gv.bin[nd]->matType == MAT_SIL2 )
3308  {
3309  for( k=0; k < qnbin; k++ )
3310  {
3311  Td = qtemp[k];
3312 
3313  beta_alpha_ELRD = exp(-450./Td) / (0.4266153643741715*exp(-340./Td) + 2.5335919594255e-14*sqrt(Td) ) ;
3314  xi_ELRD= 1./(1. + 7.00e24*sexp(45000./Td));
3315  recombination_efficiency_ELRD= (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3316  sticking_probability_H = 1./(1. + 0.04*sqrt(Td+phycon.te) +
3317  0.002*phycon.te + 8e-6*phycon.te*phycon.te);
3318 
3319  gv.bin[nd]->rate_h2_form_grains_ELRD+= qprob[k] * sticking_probability_H *
3320  recombination_efficiency_ELRD;
3321  }
3322 
3323  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3324  ** so x/4 is projected area of circle */
3325  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3326  /* gv.bin[nd]->rate_h2_form_grains_ELRD units s-1 */
3327  gv.bin[nd]->rate_h2_form_grains_ELRD*= 0.5 * AveVelH *
3328  gv.bin[nd]->IntArea/4. * gv.bin[nd]->cnv_H_pCM3;
3329 
3330  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD> 0. );
3331  }
3332  }
3333  else
3334  {
3335  /* H2 formation on grains from
3336  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3337  ** improved treatment modifying CT rate above to include Eley-Rideal effect
3338  ** data and formalism comes from Appendix C of above reference */
3339  /* new rate variable ending stands for "Eley Rideal" */
3340  gv.bin[nd]->rate_h2_form_grains_ELRD= 0.;
3341 
3342  if( gv.bin[nd]->matType == MAT_CAR || gv.bin[nd]->matType == MAT_CAR2 ||
3343  gv.bin[nd]->matType == MAT_SIC || gv.bin[nd]->matType == MAT_PAH ||
3344  gv.bin[nd]->matType == MAT_PAH2 )
3345  {
3346  Td = gv.bin[nd]->tedust;
3347 
3348  beta_alpha_ELRD = exp(-800./Td) / (0.5389970511202651 * exp(-540./Td) + 5.6333909478365e-14*sqrt(Td) ) ;
3349  xi_ELRD= 1./(1. + 4.61e24*sexp(45000./Td));
3350  recombination_efficiency_ELRD = (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3351 
3352  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3353  ** so x/4 is projected area of circle */
3354  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3355  /* units s-1 */
3356  gv.bin[nd]->rate_h2_form_grains_ELRD = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3357  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_ELRD;
3358 
3359  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD > 0. );
3360  }
3361 
3362  else if( gv.bin[nd]->matType == MAT_SIL || gv.bin[nd]->matType == MAT_SIL2 )
3363  {
3364  Td = gv.bin[nd]->tedust;
3365 
3366  beta_alpha_ELRD = exp(-450./Td) / (0.4266153643741715*exp(-340./Td) + 2.5335919594255e-14*sqrt(Td) ) ;
3367  xi_ELRD= 1./(1. + 7.00e24*sexp(45000./Td));
3368  recombination_efficiency_ELRD = (1. / (1. + beta_alpha_ELRD))*xi_ELRD;
3369 
3370  /* gv.bin[nd]->IntArea integrated grain surface area Int(4pi*a^2), normalized per H, in cm^2/H,
3371  ** so x/4 is projected area of circle */
3372  /* gv.bin[nd]->cnv_H_pCM3 is H density [cm-3] times grain depletion factor */
3373  /* units s-1 */
3374  gv.bin[nd]->rate_h2_form_grains_ELRD = 0.5 * AveVelH * gv.bin[nd]->IntArea/4. *
3375  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * recombination_efficiency_ELRD;
3376 
3377  ASSERT( gv.bin[nd]->rate_h2_form_grains_ELRD > 0. );
3378  }
3379  }
3380 
3382  {
3383  /* reset sticking probability for code below */
3384  sticking_probability_H = sticking_probability_H_func( phycon.te, gv.bin[nd]->tedust );
3385  }
3386 
3387  /* rate (s-1) all H2 v,J levels go to 0 or 1, preserving nuclear spin */
3388  /* ortho to para on grain surfaces, taken from
3389  *>refer H2 sticking Le Bourlot, J., 2000, A&A, 360, 656-662
3390  * >chng 05 apr 30, GS, hmi.H2_total/dense.gas_phase[ipHYDROGEN] is removed
3391  * This is used in h2.c.
3392  * NB IntArea is total are per H, not projected area, must div by 4
3393  * gv.bin[nd]->cnv_H_pCM3 has units H cm-3 to product with above
3394  * is cm2/H H/cm3 or cm-1 or an opacity
3395  * multiply by velocity of H2, cm s-1, so product
3396  * h2.rate_grain_op_conserve has units s^-1 */
3397  h2.rate_grain_op_conserve += AveVelH2 * gv.bin[nd]->IntArea/4. *
3398  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H;
3399 
3400  /* ortho to para on grain surfaces, taken from
3401  *>refer H2 sticking Le Bourlot, J., 2000, A&A, 360, 656-662
3402  * For all grain temperatures, this process corresponds to high J going to
3403  * either 0 or 1 preserving nuclear spin. All ortho go to 1 and para go to 0.
3404  * When the dust temperature is below Tcrit all 1 go to 0 and so all J go to 0.
3405 
3406  * this temperature depends on grain composition, discussion left column of page 657,
3407  * this is for a bare grain */
3416  /* AveVelH2 is average speed of H2 molecules
3417  * for now assume that sticking probability for H2 on the grain is equal to
3418  * that for H
3419  * efficiency factor efficiency_opr is vary fast function of t dust -
3420  * large at low Td and small at Td > T_ortho_para_crit
3421  * start evaluating just above the critical temperature
3422  * T_ortho_para_crit this is roughly 24.345 K,GS */
3423  T_ortho_para_crit = 2. * hmi.Tad / log( POW2(60. *1.1e11)*hmi.Tad);
3424  if( gv.bin[nd]->tedust < T_ortho_para_crit )
3425  {
3426  double efficiency_opr = sexp(60.*1.1e11*sqrt(hmi.Tad)*sexp(hmi.Tad/gv.bin[nd]->tedust));
3427  /* rate (s-1) all v,J levels go to 0, regardless of nuclear spin
3428  * see above discussion for how units work out */
3429  h2.rate_grain_J1_to_J0 += AveVelH2 * gv.bin[nd]->IntArea/4. *
3430  gv.bin[nd]->cnv_H_pCM3 * sticking_probability_H * efficiency_opr;
3431  }
3432  }
3433  /*fprintf(ioQQQ," H2 grain form rate HM79 %.2e %.2e CT02 %.2e %.2e O-P grn %.2e %.2e\n",
3434  gv.bin[nd]->rate_h2_form_grains_HM79 ,
3435  gv.bin[nd]->rate_h2_form_grains_HM79 ,
3436  gv.bin[nd]->rate_h2_form_grains_CT02 ,
3437  gv.bin[nd]->rate_h2_form_grains_CT02 ,
3438  h2.rate_grain_J1_to_J0,
3439  hmi.rate_h2_allX_2_J1_grains
3440  );*/
3441  /* options to turn off grain collision with atom h2 collisions grains off command */
3444 
3445  }
3446  else
3447  {
3448  /* grains are not enabled, set these to zero */
3449  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3450  {
3451  gv.bin[nd]->rate_h2_form_grains_CT02 = 0.;
3452  gv.bin[nd]->rate_h2_form_grains_HM79 = 0.;
3453  }
3454  /* rate all H2 goes to either 0 or 1 depending on ortho/para */
3456  /* at low temp, rate all H2 goes to J=0 */
3457  h2.rate_grain_J1_to_J0 = 0.;
3458  }
3459 
3460  /* the H2 catalysis rate on grains that is actually used in calculations
3461  * hmi.ScaleJura is scale factor set with set Jura scale command
3462  * units are s-1
3463  * default is 'C' Cazaux & Tielens */
3465  for( size_t nd=0; nd < gv.bin.size(); nd++ )
3466  {
3467  if( hmi.chJura == 'C' )
3468  {
3469  /* use the new rate by
3470  * >>refer H2 form Cazaux, S., & Tielens, A.G.G.M., 2002, ApJ, 575, L29
3471  * units are s-1*/
3472  gv.bin[nd]->rate_h2_form_grains_used =
3473  gv.bin[nd]->rate_h2_form_grains_CT02*hmi.ScaleJura;
3474  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3475  }
3476 
3477  if( hmi.chJura == 'E' )
3478  {
3479  /* use the new revised CT02 rate from
3480  ** >>refer H2 form Rollig, M. et al., 2013, A&A, 549, A85
3481  ** units are s-1 */
3482  gv.bin[nd]->rate_h2_form_grains_used =
3483  gv.bin[nd]->rate_h2_form_grains_ELRD*hmi.ScaleJura;
3484  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3485  }
3486 
3487  else if( hmi.chJura == 'T' )
3488  {
3489  /* rate from Hollenbach & McKee 1979 */
3490  gv.bin[nd]->rate_h2_form_grains_used =
3491  gv.bin[nd]->rate_h2_form_grains_HM79*hmi.ScaleJura;
3492  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3493  }
3494  else if( hmi.chJura == 'S' )
3495  {
3496  /* H2 formation rate from
3497  * >>refer H2 form Sternberg, A. & Neufeld, D.A. 1999, ApJ, 516, 371 */
3498  gv.bin[nd]->rate_h2_form_grains_used =
3499  3e-18 * phycon.sqrte / gv.bin.size() * dense.gas_phase[ipHYDROGEN]*hmi.ScaleJura;
3500  /* this is simple rate from Sternberg & Neufeld 99 */
3501  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3502  }
3503  /*>>chng 07 jan 10, this had been C for constant, and so could never have been triggered.
3504  * caught by robin Williams, fixed by nick Abel, error was in sense that any set jura rate
3505  * would use Cazaux & Tielens */
3506  else if( hmi.chJura == 'F' )
3507  {
3508  /* command "set H2 rate" - enters log of Jura rate - C for constant,
3509  * no dependence on grain properties */
3510  gv.bin[nd]->rate_h2_form_grains_used = hmi.rate_h2_form_grains_set*dense.gas_phase[ipHYDROGEN] / gv.bin.size();
3511  gv.rate_h2_form_grains_used_total += gv.bin[nd]->rate_h2_form_grains_used;
3512  }
3513  }
3515 
3517  {
3518  fprintf(ioQQQ, " fnzone %.2f H2 rate %.4e\n", fnzone, gv.rate_h2_form_grains_used_total );
3519  }
3520 
3521  /* print rate coefficient */
3522  /*fprintf(ioQQQ," total grain h2 form rate %.3e\n",gv.rate_h2_form_grains_used_total);*/
3523 
3524 }
3525 /*mole_h_reactions update mole reactions for H */
3527 {
3528  static double teused=-1;
3529  double exph2,
3530  exph2s,
3531  exphp,
3532  ex3hp;
3533  long i;
3534  double h2esc,
3535  th2,
3536  cr_H2s ,
3537  cr_H2dis,
3538  cr_H2dis_ELWERT_H2g,
3539  cr_H2dis_ELWERT_H2s;
3540 
3541  DEBUG_ENTRY( "mole_h_reactions()" );
3542 
3543  /* everything here depends only on temperature - don't do anything if we don't
3544  * need to */
3545 
3546  bool need_update = ! fp_equal( phycon.te, teused );
3547 
3548  if( need_update )
3549  {
3550  teused = phycon.te;
3551 
3552  /* get LTE populations */
3553  /* related to population of H- in LTE
3554  * IP is 0.754 eV */
3555  hmi.exphmi = sexp(8.745e3/phycon.te);
3556  if( hmi.exphmi > 0. )
3557  {
3558  /* these are ratio n*(H-)/[ n*(ne) n*(Ho) ] */
3559  hmi.rel_pop_LTE_Hmin = SAHA/(phycon.te32*hmi.exphmi)*(1./(2.*2.));
3560  }
3561  else
3562  {
3563  hmi.rel_pop_LTE_Hmin = 0.;
3564  }
3565 
3566  /* population of H2+ in LTE, hmi.rel_pop_LTE_H2p is H_2+/H / H+
3567  * dissociation energy is 2.647 */
3568  exphp = sexp(3.072e4/phycon.te);
3569  if( exphp > 0. )
3570  {
3571  /* stat weight of H2+ is 4
3572  * last factor was put in ver 85.23, missing before */
3573  hmi.rel_pop_LTE_H2p = SAHA/(phycon.te32*exphp)*(4./(2.*1.))*3.634e-5;
3574  }
3575  else
3576  {
3577  hmi.rel_pop_LTE_H2p = 0.;
3578  }
3579 
3580  /* related to population of H3+ in LTE, hmi.rel_pop_LTE_H3p is H_3+/( H2+ H+ )
3581  * dissociation energy is 2.647 */
3582  ex3hp = sexp(1.882e4/phycon.te);
3583  if( ex3hp > 0. )
3584  {
3585  /* stat weight of H2+ is 4
3586  * last factor was put in ver 85.23, missing before */
3587  hmi.rel_pop_LTE_H3p = SAHA/(phycon.te32*ex3hp)*(4./(2.*1.))*3.634e-5;
3588  }
3589  else
3590  {
3591  hmi.rel_pop_LTE_H3p = 0.;
3592  }
3593  }
3594  /* end constant temperature - */
3595 
3596  // Big H2 rates are dependent on population as well as temperature
3597  /* population of H2 in LTE
3598  * dissociation energy of H2g is 4.477eV, for TH85 model */
3599  /* >>chng 05 oct 17, GS, averaged in big H2 in order to consider correct statistical weight*/
3601  {
3602  /* the terms on the right were computed in the large molecule */
3605  }
3606  else
3607  {
3608  if (need_update)
3609  {
3610  /* H2 ground */
3611  exph2 = sexp((5.195e4)/phycon.te);
3612  /* >>chng 05 oct 17, GS, note that statical weight of H2g is assumed to be 1 if big H2 is not turned on*/
3613 
3614  if( exph2 > 0. )
3615  {
3616  /* >>chng 05 oct 17, GS, note that statical weight of H2g is assumed to be 1 if big H2 is not turned on*/
3617  hmi.rel_pop_LTE_H2g = SAHA/(phycon.te32*exph2)*(1./(2.*2.))*3.634e-5;
3618  }
3619  else
3620  {
3621  hmi.rel_pop_LTE_H2g = 0.;
3622  }
3623 
3624  /* H2 star */
3625  /* population of H2s in LTE
3626  * dissociation energy is 1.877eV, if h2s = 2.6eV, assumed for TH85 model */
3627  /* >>chng 05 oct 17, GS, averaged in big H2 in order to consider correct statistical weight*/
3628  exph2s = sexp(2.178e4/phycon.te);
3629 
3630  if( exph2s > 0. )
3631  {
3632  /* >>chng 05 oct 17, GS, note that statical weight of H2s is assumed to be 1 if big H2 is not turned on*/
3633  hmi.rel_pop_LTE_H2s = SAHA/(phycon.te32*exph2s)*(1./(2.*2.))*3.634e-5;
3634  }
3635  else
3636  {
3637  hmi.rel_pop_LTE_H2s = 0.;
3638  }
3639  }
3640  }
3641  {
3642  /*@-redef@*/
3643  /* often the H- route is the most efficient formation mechanism for H2,
3644  * will be through rate called Hmolec_old[ipMH]*hmi.assoc_detach
3645  * this debug print statement is to trace h2 oscillations */
3646  enum {DEBUG_LOC=false};
3647  /*@+redef@*/
3648  if( DEBUG_LOC && nzone>187&& iteration > 1)
3649  {
3650  /* rapid increase in H2 density caused by rapid increase in hmi.rel_pop_LTE_H2g */
3651  fprintf(ioQQQ,"ph2lteee\t%.2e\t%.1e\t%.1e\n",
3653  sexp(2.178e4/phycon.te),
3654  phycon.te);
3655  }
3656  }
3657 
3658  /* cooling due to radiative attachment */
3659  hmi.hmicol = hmirat(phycon.te)*EN1RYD*phycon.te*1.15e-5;
3660 
3661  fixit("Wasted cycles if we don't use Stancil's rates below? Why not put this down there/if used?");
3662  for( diatom_iter diatom = diatoms.begin(); diatom != diatoms.end(); ++diatom )
3663  {
3664  if( (*diatom)->lgEnabled && mole_global.lgStancil )
3665  (*diatom)->Mol_Photo_Diss_Rates();
3666  }
3667 
3668  /*fprintf(ioQQQ,"%.2e %.2e %.2e %.2e\n", phycon.te, hmi.hminus_rad_attach , hmi.hmicol,
3669  hmi.hmicol/(hmi.hminus_rad_attach*EN1RYD*phycon.te*1.15e-5) );*/
3670 
3671  /* get per unit vol */
3672  hmi.hmicol *= dense.eden*findspecieslocal("H")->den; /* was dense.xIonDense[ipHYDROGEN][0]; */
3673 
3674  /* ================================================================= */
3675  /* evaluate H- photodissociation rate, induced rec and rec cooling rates */
3676  /* >>chng 00 dec 24, add test so that photo rate only reevaluated two times per zone.
3677  * in grain-free models this was sometimes dominated by Lya and so oscillated.
3678  * especially bad in primal.in - change 2 to 4 and primal.in will stop due to Lya oscil */
3681  /* >>chng 02 feb 16, add damper on H- photo rate, wild oscillations in Lya photo rate in
3682  * grain free models */
3683 
3684  t_phoHeat photoHeat;
3685 
3686  /*hmi.HMinus_photo_rate = GammaBn( hmi.iphmin, nhe1Com.nhe1[0] , opac.iphmop ,
3687  HMINUSIONPOT , &hmi.HMinus_induc_rec_rate , &hmi.HMinus_induc_rec_cooling );*/
3689  HMINUSIONPOT , &hmi.HMinus_induc_rec_rate , &hmi.HMinus_induc_rec_cooling, &photoHeat );
3690 
3691  /* save H- photodissociation heating */
3692  hmi.HMinus_photo_heat = photoHeat.HeatNet;
3693 
3694  {
3695  /* following should be set true to print populations */
3696  /*@-redef@*/
3697  enum {DEBUG_LOC=false};
3698  /*@+redef@*/
3699  if( DEBUG_LOC)
3700  {
3701  fprintf(ioQQQ,"hminphoto\t%li\t%li\t%.2e\n", nzone, conv.nPres2Ioniz , hmi.HMinus_photo_rate );
3702  }
3703  }
3704 
3705  /* induced recombination */
3707 
3708  /* induced recombination cooling per unit volume */
3710  hmi.HMinus_induc_rec_cooling *= hmi.rel_pop_LTE_Hmin*dense.eden*findspecieslocal("H")->den; /* dense.xIonDense[ipHYDROGEN][0]; */
3711 
3712  {
3713  /* following should be set true to debug H- photoionization rates */
3714  /*@-redef@*/
3715  enum {DEBUG_LOC=false};
3716  /*@+redef@*/
3717  if( DEBUG_LOC && nzone>400/*&& iteration > 1*/)
3718  {
3719  fprintf(ioQQQ,"hmoledebugg %.2f ",fnzone);
3720  GammaPrt(
3721  hmi.iphmin-1 , iso_sp[ipHE_LIKE][ipHELIUM].fb[0].ipIsoLevNIonCon , opac.iphmop ,
3722  /* io unit we will write to */
3723  ioQQQ,
3724  /* total photo rate from previous call to GammaK */
3726  /* we will print contributors that are more than this rate */
3727  hmi.HMinus_photo_rate*0.05);
3728  }
3729  }
3730  /* add on high energy ionization, assume hydrogen cross section
3731  * n.b.; HGAMNC with secondaries */
3732  /* >>chng 00 dec 24, above goes to HeI edge, no need for this, and was not important*/
3733  /*hmi.HMinus_photo_rate += iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH1s].gamnc;*/
3734 
3735  /* ================================================================= */
3736  /* photodissociation by Lyman band absorption: esc prob treatment,
3737  * treatment based on
3738  * >>refer HI abs Tielens & Hollenbach 1985 ApJ 291, 722. */
3739  /* do up to carbon photo edge if carbon is turned on */
3740  /* >>>chng 00 apr 07, add test for whether element is turned on */
3742  /* >>chng 00 apr 07 from explicit ipHeavy to ipLo */
3743  /* find total intensity over carbon-ionizing continuum */
3744  /* >>chng 03 jun 09, use exact bounds rather than CI photo threshold for lower bound */
3745  /*for( i=ipLo; i < iso_sp[ipH_LIKE][ipHYDROGEN].st[ipH1s].ipIsoLevNIonCon; i++ )*/
3746  /* the integral is from 6eV to 13.6, or 2060 - 912 Ang */
3747  for( i=rfield.ipG0_TH85_lo; i < rfield.ipG0_TH85_hi; ++i )
3748  {
3750  (rfield.outlin[0][i-1])+ (rfield.outlin_noplot[i-1]))*rfield.anu(i-1);
3751  }
3752 
3753  /* now convert to Habing ISM units
3754  * UV_Cont_rel2_Habing_TH85_face is FUV continuum relative to Habing value
3755  * 1.6e-3 ergs em-2 s-1 is the Habing 1968 field, quoted on page 723, end of first
3756  * full paragraph on left */
3758  /* if start of calculation remember G0 at illuminated face */
3759  if( nzone<=1 )
3760  {
3762  }
3763 
3764 
3765  /* >>chng 05 jan 09, add special ver of G0 */
3767  for( i=rfield.ipG0_spec_lo; i < rfield.ipG0_spec_hi; ++i )
3768  {
3770  rfield.outlin[0][i-1]+ rfield.outlin_noplot[i-1])*rfield.anu(i-1);
3771  }
3773 
3774  /* the Draine & Bertoldi version of the same thing, defined over their energy range */
3775  /* >>chng 04 feb 07, only evaluate at the illuminated face */
3776  if( !conv.nTotalIoniz )
3777  {
3779  /* this is sum of photon number between 912A and 1110, as per BD96 */
3780  for( i=rfield.ipG0_DB96_lo; i < rfield.ipG0_DB96_hi; ++i )
3781  {
3783  rfield.outlin[0][i-1]+ rfield.outlin_noplot[i-1]);
3784  }
3785  /* Convert into scaled ISM background field, total number of photons over value for 1 ISM field,
3786  * the coefficient 1.232e7 is the number of photons over this wavelength range for 1H and is
3787  * given in BD96, page 225, 4th line from start of section 4, also page 272, table 1, 2nd line
3788  * from bottom */
3789  /* >>chng 04 mar 16, introduce the 1.71 */
3790  /* equation 20 of DB96 gives chi as flux over 1.21e7, to produce one Habing field.
3791  * to get the Draine field we need to further divide by 1.71 as stated on the first
3792  * line after equation 23 */
3794  }
3795 
3796  /* escape prob takes into account line shielding,
3797  * next is opacity then optical depth in H2 UV lines, using eqn A7 of TH85 */
3799  /* the typical Lyman -Werner H2 line optical depth eq A7 of TH85a */
3800  th2 = (findspecieslocal("H2")->column+ findspecieslocal("H2*")->column)*hmi.H2Opacity;
3801  /* the escape probability - chance that continuum photon will penetrate to
3802  * this depth to pump the Lyman Werner bands */
3803  h2esc = esc_PRD_1side(th2,1e-4);
3804 
3805  /* cross section is eqn A8 of
3806  * >>refer H2 dissoc Tielens, A.G.G.M., & Hollenbach, D., 1985, ApJ, 291, 722
3807  * branching ratio of 10% is already included, so 10x smaller than their number
3808  * 10% lead to dissociation through H_2 + h nu => 2H */
3809  /* >>chng 05 mar 10, by TE, break into 2g and 2s
3810  * note use of same shielding column in below - can do far better */
3814 
3815  /* these are Burton et al. 1990 rates */
3819 
3820  {
3821  /* the following implements Drain & Bertoldi 1996, equation 37 from
3822  * >>refer H2 destruction Draine, B.T., & Bertoldi, F., 1996, ApJ, 468, 269-289
3823  * but the constant 4.6e-11 comes from Bertoldi & Draine equation 23,
3824  * this is the normalized H2 column density */
3825  double x = (findspecieslocal("H2")->column+findspecieslocal("H2*")->column) / 5e14;
3826  double sqrtx = sqrt(1.+x);
3827  /* Doppler with of H2 in km/s */
3828  double b5 = GetDopplerWidth(2.f*dense.AtomicWeight[ipHYDROGEN])/1e5;
3829  /* the molecular hydrogen line self-shielding factor */
3830  double fshield = 0.965/POW2(1.+x/b5) + 0.035/sqrtx *
3831  sexp(8.5e-4*sqrtx);
3832 
3833  /*double fshield = pow( MAX2(1.,colden.colden[ipCOLH2]/1e14) , -0.75 );*/
3834  /* this is the Bertoldi & Draine version of the Habing field,
3835  * with dilution of radiation and extinction due to grains */
3836  /* >>chng 04 apr 18, moved fshield, the line shielding factor, from this defn to
3837  * the following defn of dissociation rate, since following should measure continuum */
3840 
3841  /* the following comes from Bertoldi & Draine 1996, equation 23,
3842  * hmi.UV_Cont_rel2_Draine_DB96_depth already includes a factor of 1.71 to correct back from TH85 */
3843  /* >>chng 05 mar 10, TE, break into 2s and 2s */
3844  if( !mole_global.lgLeidenHack )
3845  {
3846  /* this is default, when set Leiden hack UMIST rates not entered */
3849  }
3850  else
3851  {
3852  /* done when set Leiden hack UMIST rates command entered */
3854  *sexp(3.02*rfield.extin_mag_V_point)* fshield;
3856  *sexp(3.02*rfield.extin_mag_V_point)* fshield;
3857  }
3858 
3859  /* BD do not give an excitation rate, so used 9 times the dissociation
3860  * rate by analogy with 90% going back into X, as per TH85 */
3861  /*>>chng 04 feb 07, had used 90% relax into X from TH85,
3862  * BD say that 15% dissociate, so 85/15 = 5.67 is factor */
3864  }
3865 
3866  /* do Elwert approximation to the dissociation rate */
3868  {
3869  /* this evaluates the new H2 dissociation rate by Torsten Elwert */
3870  /* chng 05 jun 23, TE
3871  * >>chng 05 sep 13, update master source with now approximation */
3872 
3873  /* Doppler with of H2 in km/s */
3874  double b5 = GetDopplerWidth(2.f*dense.AtomicWeight[ipHYDROGEN])/1e5;
3875 
3876  /* split the Solomon rates in H2g and H2s */
3877  /* >>chng 05 oct 19,
3878  * >>chng 05 dec 05, TE, define new approximation for the heating due to the destruction of H2
3879  * use this approximation for the specified cloud parameters, otherwise
3880  * use limiting cases for 1 <= G0, G0 >= 1e7, n >= 1e7, n <= 1 */
3881 
3882  double x_H2g, x_H2s,
3883  fshield_H2g, fshield_H2s,
3884  f_H2s;
3885  static double a_H2g, a_H2s,
3886  e1_H2g, e1_H2s,
3887  e2_H2g,
3888  b_H2g,
3889  sl_H2g, sl_H2s,
3890  k_f_H2s,
3891  k_H2g_to_H2s,
3892  log_G0_face = -1;
3893 
3894  /* define parameter range for the new approximation
3895  * test for G0
3896  *BUGFIX - this tested on lg_G0_face < 0 for initialization needed so did not work
3897  * in grids - change to evaluate in zone 0 */
3898  /* >>chng 07 feb 24, BUGFIX crash when G0=0 at start and radiation
3899  * field builds up due to diffuse fields - soln is to always reevaluate */
3900  /*if( !nzone )*/
3901  {
3903  {
3904  log_G0_face = 0.;
3905  }
3906  else if(hmi.UV_Cont_rel2_Draine_DB96_face >= 1e7)
3907  {
3908  log_G0_face = 7.;
3909  }
3910  else
3911  {
3912  log_G0_face = log10(hmi.UV_Cont_rel2_Draine_DB96_face);
3913  }
3914 
3915  /* terms only dependent on G0_face */
3916 
3917  /* coefficients and exponents */
3918  a_H2g = 0.06 * log_G0_face + 1.32;
3919  a_H2s = 0.375 * log_G0_face + 2.125;
3920 
3921  e1_H2g = -0.05 * log_G0_face + 2.25;
3922  e1_H2s = -0.125 * log_G0_face + 2.625;
3923 
3924  e2_H2g = -0.005 * log_G0_face + 0.625;
3925 
3926  b_H2g = -4.0e-3 * log_G0_face + 3.2e-2;
3927 
3928  /* scalelength for H2g and H2s */
3929  sl_H2g = 4.0e14;
3930  sl_H2s = 9.0e15;
3931 
3932  /* coefficient for 2nd term of Solomon H2s */
3933  k_f_H2s = MAX2(0.1,2.375 * log_G0_face - 1.875 );
3934 
3935  /* coefficient for branching ratio */
3936  k_H2g_to_H2s = MAX2(1.,-1.75 * log_G0_face + 11.25);
3937 
3938  /*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",
3939  e1_H2g, e1_H2s, e2_H2g, b_H2g, a_H2g, a_H2s, sl_H2g, sl_H2s);
3940  */
3941  }
3942 
3943  /* Solomon H2s ~G0^0.2 at large depth*/
3944  f_H2s = k_f_H2s * pow((double)hmi.UV_Cont_rel2_Draine_DB96_depth, 0.2 );
3945 
3946  /* scale length for absorption of UV lines */
3947  x_H2g = (findspecieslocal("H2")->column) / sl_H2g;
3948  x_H2s = (findspecieslocal("H2*")->column) / sl_H2s;
3949 
3950  /* the molecular hydrogen line self-shielding factor */
3951  fshield_H2g = 0.965/pow(1.+x_H2g/b5,e1_H2g) + b_H2g/pow(1.+x_H2g/b5,e2_H2g);
3952  fshield_H2s = 0.965/pow(1.+x_H2s/b5,e1_H2s);
3953 
3954  /* the Elwert Solomon rates for H2g and H2s hmi.chH2_small_model_type == 'E' */
3955  hmi.H2_Solomon_dissoc_rate_ELWERT_H2g = a_H2g * 4.6e-11 * fshield_H2g * hmi.UV_Cont_rel2_Draine_DB96_depth;
3956  hmi.H2_Solomon_dissoc_rate_ELWERT_H2s = a_H2s * 4.6e-11 * fshield_H2s * (hmi.UV_Cont_rel2_Draine_DB96_depth + f_H2s);
3957 
3958  /* assume branching ratio dependent on G0*/
3960 
3961  /* use G0_BD96 as this definition declines faster with depth which is physical as
3962  * the longer wavelengths in the definition of G0_TH85 cannot dissociate
3963  * H2s directly */
3966  }
3967  else
3968  {
3973  }
3974 
3975  /* this is rate of photodissociation of H2*, A12 of TH85 */
3977 
3978  /* dissociation rate from Burton et al. 1990 */
3980 
3981  /* rates for cosmic ray excitation of singlet bound electronic bound excited states
3982  * only add this to small molecule since automatically included in large
3983  *>>refer H2 cr excit Dalgarno, A., Yan, Min, & Liu, Weihong 1999, ApJS, 125, 237
3984  * this is excitation of H2* */
3985  /* >>chng 05 sep 13, do not include this process when Leiden hacks are in place */
3986  cr_H2s = secondaries.x12tot*0.9 / 2. * hmi.lgLeidenCRHack;
3987  /* this is the fraction that dissociate */
3988  /* >>chng 05 sep 13, do not include this process when Leiden hacks are in place */
3989  cr_H2dis = secondaries.x12tot*0.1 / 2. * hmi.lgLeidenCRHack;
3990 
3991  /* >>chng 05 sep 13, TE, synchronize treatment of CR */
3992  /* cosmic ray rates for dissociation of ground and H2s
3993  * two factors done to agree with large H2 deep in the cloud where
3994  * cosmic rays are important */
3995  cr_H2dis_ELWERT_H2g = secondaries.x12tot*5e-8 * hmi.lgLeidenCRHack;
3996  cr_H2dis_ELWERT_H2s = secondaries.x12tot*4e-2 * hmi.lgLeidenCRHack;
3997 
3998  /* at this point there are two or three independent estimates of the H2 dissociation rate.
3999  * if the large H2 molecule is on, then H2 Solomon rates has been defined in the last
4000  * call to the large molecule. Just above we have defined hmi.H2_Solomon_dissoc_rate_TH85,
4001  * the dissociation rate from Tielens & Hollenbach 1985, and hmi.H2_Solomon_dissoc_rate_BD96,
4002  * the rate from Bertoldi & Draine 1996. We can use any defined rate. If the big H2
4003  * molecule is on, use its rate. If not, for now use the TH85 rate, since that is the
4004  * rate we always have used in the past.
4005  * The actual rate we will use is given by hmi.H2_Solomon_dissoc_rate_used
4006  */
4007  /* this is the Solomon process dissociation rate actually used */
4009  {
4010  /* only update after big H2 molecule has been evaluated,
4011  * when very little H2 and big molecule not used, leave at previous (probably TH85) value,
4012  * since that value is always known */
4013 
4014  /* Solomon process rate from X into the X continuum with units s-1
4015  * rates are total rate, and rates from H2g and H2s */
4018 
4021 
4022  /* photoexcitation from H2g to H2s */
4025 
4026  /* add up H2s + hnu (continuum) => 2H + KE, continuum photodissociation,
4027  * this is not the Solomon process, true continuum, units s-1 */
4028  /* only include rates from H2s since this is only open channel, this process is well
4029  * shielded against Lyman continuum destruction by atomic hydrogen */
4031  /* NPA - 07/24/09 - logic to use Stancil photodissociation rate for H2s */
4035 
4036  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4037  * for unfavorable wavelength range of G0*/
4039  /* NPA - 07/24/09 - logic to use Stancil photodissociation rate for H2g */
4043  }
4044  else if( hmi.chH2_small_model_type == 'T' )
4045  {
4046  /* the TH85 rate */
4047  /*>>chng 05 jun 23, add cosmic rays */
4049  /* >>chng 05 sep 13, cr_H2dis was not included */
4052 
4053  /* continuum photodissociation H2s + hnu => 2H, ,
4054  * this is not the Solomon process, true continuum, units s-1 */
4056  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4057  * for unfavorable wavelength range of G0*/
4059  }
4060 
4061  else if( hmi.chH2_small_model_type == 'H' )
4062  {
4063  /* the improved H2 formalism given by
4064  *>>refer H2 dissoc Burton, M.G., Hollenbach, D.J. & Tielens, A.G.G.M
4065  >>refcon 1990, ApJ, 365, 620 */
4067  /* >>chng 05 sep 13, cr_H2dis was not included */
4070 
4071  /* continuum photodissociation H2s + hnu => 2H, ,
4072  * this is not the Solomon process, true continuum, units s-1 */
4074  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4075  * for unfavorable wavelength range of G0*/
4077  }
4078 
4079  else if( hmi.chH2_small_model_type == 'B' )
4080  {
4081  /* the Bertoldi & Draine rate - this is the default */
4082  /*>>chng 05 jun 23, add cosmic rays */
4084  /* >>chng 05 sep 13, cr_H2dis was not included */
4086  /* they did not do the excitation or dissoc rate, so use TH85 */
4088 
4089 
4090  /* continuum photodissociation H2s + hnu => 2H, ,
4091  * this is not the Solomon process, true continuum, units s-1 */
4093  /* >>chng 05 mar 24, TE, continuum photodissociation rate of H2g, small correction factor accounts
4094  * for unfavorable wavelength range of G0*/
4096  }
4097  else if( hmi.chH2_small_model_type == 'E' )
4098  {
4099  /* the Elwert et al. rate
4100  *>>chng 05 jun 23, add cosmic rays */
4104 
4105 
4106  /* continuum photodissociation H2s + hnu => 2H, ,
4107  * this is not the Solomon process, true continuum, units s-1 */
4110  }
4111  else
4112  TotalInsanity();
4113 
4114  {
4115  /*@-redef@*/
4116  enum {DEBUG_LOC=false};
4117  /*@+redef@*/
4118  if( DEBUG_LOC && h2.lgEnabled )
4119  {
4120  fprintf(ioQQQ," Solomon H2 dest rates: TH85 %.2e BD96 %.2e Big %.2e excit rates: TH85 %.2e Big %.2e\n",
4125  h2.gs_rate() );
4126  }
4127  }
4128 
4129  if( !hd.lgEnabled )
4131 
4132  return;
4133 }
4134 mole_reaction *mole_findrate_s(const char buf[])
4135 {
4136  DEBUG_ENTRY( "mole_findrate_s()" );
4137 
4138  string newbuf = canonicalize_reaction_label(buf);
4139 
4140  mole_reaction_i p = mole_priv::reactab.find(newbuf);
4141 
4142  if(p != mole_priv::reactab.end())
4143  return &(*p->second);
4144  else
4145  return NULL;
4146 }
4147 
4148 double t_mole_local::findrk(const char buf[]) const
4149 {
4150  DEBUG_ENTRY( "t_mole_local::findrk()" );
4151 
4152  mole_reaction *rate = mole_findrate_s(buf);
4153 
4154  if(!rate)
4155  return 0.;
4156 
4157  /* check for NaN */
4158  ASSERT( !isnan( reaction_rks[ rate->index ] ) );
4159 
4160  return reaction_rks[ rate->index ];
4161 }
4162 double t_mole_local::findrate(const char buf[]) const
4163 {
4164  double ret;
4165  int i;
4166 
4167  DEBUG_ENTRY( "t_mole_local::findrate()" );
4168 
4169  mole_reaction *rate = mole_findrate_s(buf);
4170  if(!rate)
4171  {
4172  return 0.;
4173  }
4174 
4175  ret = reaction_rks[ rate->index ];
4176  for(i=0;i<rate->nreactants;i++)
4177  ret *= species[ rate->reactants[i]->index ].den;
4178 
4179  return ret;
4180 }
4181 /* Calculate rate at which molecular network abstracts species */
4182 
4183 /* Need to check reactants vs reactant behaviour */
4184 double t_mole_local::sink_rate_tot(const char chSpecies[]) const
4185 {
4186  DEBUG_ENTRY( "t_mole_local::sink_rate_tot()" );
4187 
4188  const molecule* const sp = findspecies(chSpecies);
4189  double ratev = sink_rate_tot(sp);
4190 
4191  return ratev;
4192 }
4193 double t_mole_local::sink_rate_tot(const molecule* const sp) const
4194 {
4195  DEBUG_ENTRY( "t_mole_local::sink_rate_tot()" );
4196  double ratev = 0;
4197 
4198  for(mole_reaction_i p=mole_priv::reactab.begin();
4199  p != mole_priv::reactab.end(); ++p)
4200  {
4201  mole_reaction &rate = *p->second;
4202  ratev += sink_rate( sp, rate );
4203  }
4204 
4205  return ratev;
4206 }
4207 
4208 double t_mole_local::sink_rate(const molecule* const sp, const char buf[]) const
4209 {
4210  const mole_reaction* const rate = mole_findrate_s(buf);
4211  return sink_rate( sp, *rate );
4212 }
4213 
4214 double t_mole_local::sink_rate(const molecule* const sp, const mole_reaction& rate) const
4215 {
4216  DEBUG_ENTRY( "t_mole_local::sink_rate()" );
4217 
4218  int ipthis = -1;
4219  for(int i=0;i<rate.nreactants && ipthis == -1;i++)
4220  {
4221  if(rate.reactants[i] == sp && rate.rvector[i]==NULL && rate.rvector_excit[i]==NULL )
4222  {
4223  ipthis = i;
4224  }
4225  }
4226  if(ipthis != -1)
4227  {
4228  double ratevi = rate.a * rate.rk();
4229  for(int i=0;i<rate.nreactants;i++)
4230  {
4231  if(i!=ipthis)
4232  {
4233  ratevi *= species[ rate.reactants[i]->index ].den;
4234  }
4235  }
4236  return ratevi;
4237  }
4238  else
4239  return 0.;
4240 }
4241 
4243 double t_mole_local::dissoc_rate(const char chSpecies[]) const
4244 {
4245  DEBUG_ENTRY( "t_mole_local::dissoc_rate()" );
4246 
4247  molecule *sp = findspecies(chSpecies);
4248  if (sp == null_mole)
4249  return 0.0;
4250  ASSERT(sp->isMonatomic());
4251  const chem_nuclide *tgt = sp->nNuclide.begin()->first.get_ptr();
4252  molecule *ph = findspecies("PHOTON");
4253  double ratev = 0.0;
4254 
4255  for (mole_reaction_i p
4256  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4257  {
4258  mole_reaction &rate = *p->second;
4259 
4260  // Must have a photon in to be a dissociation rate
4261  int ipph = 0;
4262  for (int i=0;i<rate.nreactants;i++)
4263  {
4264  if (rate.reactants[i] == ph)
4265  ipph++;
4266  }
4267  if (!ipph)
4268  continue;
4269 
4270  // ipsp is number of *specific* species of interest,
4271  // ipfree is number in same ionization ladder, including X-
4272  int ipspin = 0, ipfreein = 0;
4273  for (int i=0;i<rate.nreactants;i++)
4274  {
4275  if (rate.reactants[i] == sp)
4276  ++ipspin;
4277  if (rate.reactants[i]->isMonatomic() && tgt == sp->nNuclide.begin()->first.get_ptr())
4278  ++ipfreein;
4279  }
4280  int ipspout = 0, ipfreeout = 0;
4281  for (int i=0;i<rate.nproducts;i++)
4282  {
4283  if (rate.products[i] == sp)
4284  ++ipspout;
4285  if (rate.products[i]->isMonatomic() && tgt == sp->nNuclide.begin()->first.get_ptr())
4286  ++ipfreeout;
4287  }
4288 
4289  // Must produce the species requested
4290  int newsp = ipspout-ipspin;
4291  if (newsp <= 0)
4292  continue;
4293 
4294  // And must do so by breaking bonds
4295  int nbondsbroken = ipfreeout-ipfreein;
4296  if (nbondsbroken <= 0)
4297  continue;
4298  // Fraction of the generated monatomic species which were *originally* bound
4299  double fracbroken = nbondsbroken/((double)ipfreeout);
4300  ASSERT( fracbroken <= 1.0 );
4301 
4302  double ratevi = reaction_rks[ rate.index ];
4303  for (int i=0;i<rate.nreactants;i++)
4304  {
4305  ratevi *= species[ rate.reactants[i]->index ].den;
4306  }
4307 
4308  // Photoproduction rate is rate of production of the species
4309  // which has not come from an initially monatomic source
4310 
4311  double ratesp = ratevi*newsp; // This is the total production
4312  // rate of the specific species
4313  ratesp *= fracbroken; // Scale back for any initially unbound
4314  // monatoms
4315 
4316  ratev += ratesp;
4317  }
4318  return ratev;
4319 }
4320 double t_mole_local::source_rate_tot(const char chSpecies[]) const
4321 {
4322  DEBUG_ENTRY( "t_mole_local::source_rate_tot()" );
4323 
4324  molecule *sp = findspecies(chSpecies);
4325  double ratev = source_rate_tot(sp);
4326 
4327  return ratev;
4328 }
4329 double t_mole_local::source_rate_tot(const molecule* const sp) const
4330 {
4331  DEBUG_ENTRY( "t_mole_local::source_rate_tot()" );
4332  double ratev = 0;
4333 
4334  for (mole_reaction_i p =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4335  {
4336  mole_reaction &rate = *p->second;
4337  int ipthis = 0;
4338  for(int i=0;i<rate.nproducts;i++)
4339  {
4340  if( rate.products[i] == sp && rate.pvector[i]==NULL && rate.pvector_excit[i]==NULL )
4341  {
4342  ipthis++;
4343  }
4344  }
4345  if(ipthis)
4346  {
4347  double ratevi = rate.a * rate.rk();
4348  for(int i=0;i<rate.nreactants;i++)
4349  {
4350  ratevi *= species[ rate.reactants[i]->index ].den;
4351  }
4352  ratev += ipthis*ratevi;
4353  }
4354  }
4355 
4356  return ratev;
4357 }
4358 
4359 double t_mole_local::chem_heat(void) const
4360 {
4361  /* >>chng 07, Feb 11 NPA. Calculate the chemical heating rate. This is defined as the net energy of the
4362  * reaction, which is:
4363  *
4364  * Energy = SUM[formation energies of reactants] - SUM[formation energies of products]
4365  *
4366  * Now take the energy, and multiply by the densities of the reactants and the rate constant, finally
4367  * you have to multiply by 1.66e-14, which is the conversion factor to go from kJ/mol to erg/atom
4368  * this gives the units in the form of erg/atom*cm3/s*cm-3*cm-3 = erg/cm-3/s/atom, which is
4369  * a heating rate
4370  */
4371 
4372  DEBUG_ENTRY( "t_mole_local::chem_heat()" );
4373 
4374  double heating = 0.;
4375  map<double,string> heatMap;
4376  molecule *ph = findspecies("PHOTON");
4377  molecule *crph = findspecies("CRPHOT");
4378  molecule *grn = findspecies("grn");
4379 
4380  /* loop over all reactions */
4381  for (mole_reaction_i p
4382  =mole_priv::reactab.begin(); p != mole_priv::reactab.end(); ++p)
4383  {
4384  mole_reaction &rate = *p->second;
4385 
4386  // If PHOTON appears, assume it accounts for energy difference
4387  bool lgCanSkip = false;
4388  for (int i=0;i<rate.nproducts;i++)
4389  {
4390  if( rate.products[i] == ph || rate.products[i] == crph )
4391  lgCanSkip = true;
4392  }
4393  for (int i=0;i<rate.nreactants;i++)
4394  {
4395  if( rate.reactants[i] == ph || rate.reactants[i] == crph )
4396  lgCanSkip = true;
4397  }
4398  // grain catalyst reactions are handled in grain physics, don't double count here
4399  for (int i=0;i<rate.nreactants;i++)
4400  {
4401  if( rate.reactants[i] == grn && rate.rvector[i] != NULL )
4402  lgCanSkip = true;
4403  }
4404 
4405  if( lgCanSkip )
4406  continue;
4407 
4408  /* This loop calculates the product of the rate constant times the densities*/
4409  double rate_tot = reaction_rks[ rate.index ];
4410  for( long i=0; i < rate.nreactants; ++i )
4411  {
4412  rate_tot *= species[ rate.reactants[i]->index ].den;
4413  }
4414 
4415  realnum reaction_enthalpy = 0.;
4416 
4417  /* Calculate the sum of the formation energies for the reactants */
4418  for( long i=0; i < rate.nreactants; ++i )
4419  {
4420  reaction_enthalpy += rate.reactants[i]->form_enthalpy;
4421  }
4422 
4423  /* Subtract from that the sum of the formation energies of the products */
4424  for( long i=0; i < rate.nproducts; ++i )
4425  {
4426  reaction_enthalpy -= rate.products[i]->form_enthalpy;
4427  }
4428 
4429  /* this is the chemical heating rate. TODO Once the H chem is merged with the C chem, then
4430  * we will have the chemical heating rate for all reactions. This is only a subset and, thusfar,
4431  * not actually used in getting the total heating. Tests with pdr_leiden_hack_f1.in show that this
4432  * heating rate can be up to 10% of the total heating */
4433 
4434  double heat = reaction_enthalpy*rate_tot*(1e10/AVOGADRO); /* 1.66e-14f; */
4435  heatMap[heat] = rate.label;
4436  heating += heat;
4437  }
4438 
4439  // use reverse iterator to print out biggest contributors
4440  long index = 0;
4441  // this should be a const_reverse_iterator, but pgCC 12.2-0 64-bit cannot handle this.
4442  // it appears there is no const version of heatMap.rend(); as a result the compiler
4443  // cannot find a suitable version of operator != in "it != heatMap.rend()"
4444  // The Solaris Studio compiler version 12.3 has the same problem
4445  for( map<double,string>::reverse_iterator it = heatMap.rbegin(); it != heatMap.rend(); ++it, ++index )
4446  {
4447  fprintf( ioQQQ, "DEBUGGG heat %li\t%li\t%.6e\t%s\n", index, nzone, it->first, it->second.c_str() );
4448  if( index==2 )
4449  break;
4450  }
4451  index = 0;
4452  for( map<double,string>::iterator it = heatMap.begin(); it != heatMap.end(); ++it, ++index )
4453  {
4454  if( it->first >= 0. )
4455  break;
4456  fprintf( ioQQQ, "DEBUGGG cool %li\t%li\t%.6e\t%s\n", index, nzone, it->first, it->second.c_str() );
4457  if( index==2 )
4458  break;
4459  }
4460 
4461  return heating;
4462 }
4463 
4464 STATIC double sticking_probability_H_func( double T_gas, double T_grain )
4465 {
4466  DEBUG_ENTRY( "sticking_probability_H_func()" );
4467  double S = sticking_probability_H_HM79( T_gas, T_grain );
4468  return S;
4469 }
4470 
4471 STATIC double sticking_probability_H_HM79( double T_gas, double T_grain )
4472 {
4473  DEBUG_ENTRY( "sticking_probability_H_HM79()" );
4474 
4475  /* sticking probability, 2H + grain equation 3.7 of
4476  * >>refer grain phys Hollenbach, D.J., & McKee, C.F., 1979, ApJS, 41, 555,
4477  * fraction of H impacts on grain surface that stick */
4478  /* this sticking probability is used for both HM79 and CT02 */
4479  double T2 = T_gas / 100.;
4480  double Tg2 = T_grain / 100.;
4481  double S = 1./(1. + 0.4*sqrt(Tg2 + T2) + 0.2*T2 + 0.08*T2*T2);
4482  return S;
4483 }
4484 
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:765
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:251
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:1368
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:248
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:971
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:68
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:189
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:356
long int ipG0_spec_lo
Definition: rfield.h:251
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:842
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:244
bool lgEvaluated
Definition: h2_priv.h:317
t_phycon phycon
Definition: phycon.cpp:6
long int ih2pof
Definition: opacity.h:223
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:999
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:189
FILE * ioQQQ
Definition: cddefines.cpp:7
long int ipG0_TH85_lo
Definition: rfield.h:244
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:803
bool parse_species_label(const char label[], ChemNuclideList &atomsLeftToRight, vector< int > &numAtoms, string &embellishments)
double anu(size_t i) const
Definition: mesh.h:120
double Average_collH2_dissoc_g
Definition: h2_priv.h:312
double dsexp(double x)
Definition: service.cpp:1038
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:223
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:854
double H2_Solomon_dissoc_rate_used_H2s
Definition: hmi.h:109
#define MALLOC(exp)
Definition: cddefines.h:554
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:248
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:979
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:154
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:482
int index
Definition: mole.h:194
double powi(double, long int)
Definition: service.cpp:594
STATIC bool lgReactBalance(const count_ptr< mole_reaction > &rate)
map< string, count_ptr< mole_reaction > > functab
realnum * TauAbsFace
Definition: opacity.h:100
double H2_Solomon_dissoc_rate_BHT90_H2s
Definition: hmi.h:111
bool lgGrainPhysicsOn
Definition: grainvar.h:479
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:223
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:112
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:258
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:613
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:723
realnum UV_Cont_rel2_Habing_spec_depth
Definition: hmi.h:74
double powpq(double x, int p, int q)
Definition: service.cpp:630
double Solomon_dissoc_rate_s
Definition: h2_priv.h:272
double photoionize_rate
Definition: h2_priv.h:261
#define isnan
Definition: cddefines.h:659
const int ipHELIUM
Definition: cddefines.h:350
void GrainDrive()
Definition: grains.cpp:1586
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:583
void mole_update_rks(void)
diatomics hd("hd", 4100.,&hmi.HD_total, Yan_H2_CS)
long int ip1000A
Definition: rfield.h:254
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:824
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:1121
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:1002
double alogte
Definition: phycon.h:92
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:354
#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:424
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:417
long int ih2pnt[2]
Definition: opacity.h:223
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:1353
STATIC void parse_base(char *s)
bool lgDustOn() const
Definition: grainvar.h:475
const int ipHYDROGEN
Definition: cddefines.h:349
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:46
#define FLTEQ(a, b)
long int ih2pnt_ex[2]
Definition: opacity.h:223
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:574
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