cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mole_species.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2013 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*CO_Init called from cdInit to initialize co routines */
4 /*CO_update_chem_rates update rate coefficients, only temp part - in mole_co_etc.c */
5 #include "cdstd.h"
6 #include <cctype>
7 #include <string.h>
8 #include <algorithm>
9 #include <stdlib.h>
10 #include "cddefines.h"
11 #include "co.h"
12 #include "colden.h"
13 #include "conv.h"
14 #include "deuterium.h"
15 #include "doppvel.h"
16 #include "elementnames.h"
17 #include "h2.h"
18 #include "iso.h"
19 #include "phycon.h"
20 #include "physconst.h"
21 #include "mole.h"
22 #include "mole_priv.h"
23 #include "hmi.h"
24 #include "radius.h"
25 #include "rfield.h"
26 #include "rt.h"
27 #include "secondaries.h"
28 #include "dense.h"
29 #include "ionbal.h"
30 #include "grainvar.h"
31 #include "timesc.h"
32 #include "taulines.h"
33 #include "trace.h"
34 /*lint -e778 constant expression evaluates to 0 in operation '-' */
35 
36 /* CO_update_chem_rates update rate coefficients, only temp part - in
37  * mole_co_etc.c called in conv_base before any chemistry or
38  * ionization is done */
39 
41 
42 STATIC void read_species_file( string filename, bool lgCreateIsotopologues = true );
43 STATIC void newelement(const char label[], int ipion);
44 STATIC void newisotope( const count_ptr<chem_element> &el, int massNumberA,
45  realnum mass_amu, double frac );
47 // newspecies is overloaded. The first one just calls the second with the additional lgCreateIsotopologues set true
48 STATIC molecule *newspecies(const char label[], enum spectype type,
49  enum mole_state state, realnum form_enthalpy);
50 STATIC molecule *newspecies(const char label[], enum spectype type,
51  enum mole_state state, realnum form_enthalpy, bool lgCreateIsotopologues);
52 STATIC count_ptr<chem_atom> findatom(const char buf[]);
53 STATIC bool isactive(const molecule &mol);
54 STATIC bool ispassive(const molecule &mol);
55 STATIC void ReadIsotopeFractions( const vector<bool>& lgResolveNelem );
56 //STATIC void create_isotopologues(count_ptr<molecule> mol, ChemAtomList& atoms, vector<int>& numAtoms);
57 
58 namespace mole_priv {
59  map <string,count_ptr<molecule> > spectab;
60  map <string,count_ptr<mole_reaction> > reactab;
61  map <string,count_ptr<chem_element> > elemtab;
62  map <string,count_ptr<chem_atom> > atomtab;
63  map <string,count_ptr<mole_reaction> > functab;
64 };
69 vector< count_ptr <chem_element> > element_list;
73 
74 #include <functional>
75 
76 namespace
77 {
78  class MoleCmp : public binary_function<const count_ptr<molecule>,
79  const count_ptr<molecule>,bool>
80  {
81  public:
82  bool operator()(const count_ptr<molecule> &mol1,
83  const count_ptr<molecule> &mol2) const
84  {
85  return mol1->compare(*mol2) < 0;
86  }
87  bool operator()(const molecule *mol1, const molecule *mol2) const
88  {
89  return mol1->compare(*mol2) < 0;
90  }
91  };
92 }
93 
94 void t_mole_global::sort(t_mole_global::MoleculeList::iterator start,
95  t_mole_global::MoleculeList::iterator end)
96 {
97  std::sort(start,end,MoleCmp());
98 }
100 {
101  std::sort(start,end,MoleCmp());
102 }
103 
104 STATIC void ReadIsotopeFractions( const vector<bool>& lgResolveNelem )
105 {
106  DEBUG_ENTRY( "ReadIsotopeFractions()" );
107 
108  char chLine[INPUT_LINE_LENGTH];
109  long i;
110  bool lgEOL;
111 
112  static const char chFile[] = "isotope_fractions.dat";
113  FILE *ioDATA = open_data( chFile, "r" );
114  ASSERT( ioDATA != NULL );
115 
116  while( read_whole_line( chLine, (int)sizeof(chLine), ioDATA ) != NULL )
117  {
118  if( chLine[0] == '#' )
119  continue;
120 
121  i = 1;
122  long Z = (long)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
123  long A = (long)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
124  // file has fractionation as percent; the 0.01 converts to fraction
125  double frac = 0.01 * (double)FFmtRead(chLine,&i,INPUT_LINE_LENGTH,&lgEOL);
126 
127  fixit(); // need real masses here instead of just A (protons + neutrons)
128  if( (unsigned)Z <= lgResolveNelem.size() && lgResolveNelem[Z-1] )
129  newisotope( element_list[Z-1], A, (realnum)A, frac );
130  // always do this to continue history of predicting 13CO
131  else if( Z-1==ipCARBON )
132  newisotope( element_list[Z-1], A, (realnum)A, frac );
133  }
134 
135  fclose( ioDATA );
136 
137  return;
138 }
139 
141 {
142  DEBUG_ENTRY( "mole_global::make_species()" );
143 
144  long int i;
145  molecule *sp;
146 
147  null_element = new chem_element(0,"") ;
148  null_atom = new( chem_atom );
149  null_molezone = new( molezone );
150  null_molezone->den = 0.;
151 
152  /* set up concordance of elemental species to external Cloudy indices */
153  for (i=0;i<LIMELM;i++)
154  {
156  }
157 
158  // flip this to treat deuterium
159  if( deut.lgElmtOn )
160  lgTreatIsotopes[ipHYDROGEN] = true;
161 
162  // read and define isotopes, set default fractionations
164 
165  // special code to maintain effect of "set 12C13C" command
166  {
167  count_ptr<chem_atom> atom12C = findatom("^12C");
168  count_ptr<chem_atom> atom13C = findatom("^13C");
169 
170  if( co.C12_C13_isotope_ratio >= 0. )
171  {
172  double ratio = co.C12_C13_isotope_ratio;
173  atom12C->frac = ratio / (ratio + 1.);
174  atom13C->frac = 1. / (ratio + 1.);
175  }
176  else
177  {
178  double ratio = atom12C->frac / SDIV( atom13C->frac );
179  co.C12_C13_isotope_ratio = ratio;
180  }
181  // Make sure only two isotopes are defined: 12C, 13C.
182  // The mean-abundance isotope is defined below.
183  ASSERT( element_list[ipCARBON]->isotopes.size() == 2 );
184  }
185 
186 
188  {
189  SetDeuteriumFractionation( element_list[ipHYDROGEN]->isotopes[2]->frac );
190  SetGasPhaseDeuterium( dense.gas_phase[ipHYDROGEN] );
192  }
193 
194  for( long nelem=0; nelem<LIMELM; ++nelem )
195  {
196  realnum mass_amu = MeanMassOfElement( element_list[nelem] );
197  //define generic mean-abundance isotopes
198  newisotope( element_list[nelem], -1, mass_amu, 1.0 );
199  }
200 
201  ASSERT( (long) unresolved_atom_list.size() == LIMELM );
202 
203  /* set up properties of molecular species -- chemical formulae,
204  array indices, elementary components (parsed from formula),
205  status within CO network, location of stored value external
206  to CO network (must be floating point). */
207 
208  /* Sizes of different parts of network are calculated by increments in newspecies */
210  /* Enthalpies of formation taken from
211  * >>refer mol Le Teuff, Y. E., Millar, T. J., & Markwick, A. J.,2000, A&AS, 146, 157
212  */
213 
214  /* Zero density pseudo-species to return when molecule is switched off */
215  null_mole = newspecies(" ",OTHER,MOLE_NULL, 0.);
216  null_mole->index = -1;
217 
218  read_species_file( "chem_species.dat" );
219 
221  {
222  /* What are formation enthalpies of COgrn, H2Ogrn, OHgrn? For
223  present, take grn as standard state, and neglect adsorption enthalpy.
224 
225  -- check e.g. http://www.arxiv.org/abs/astro-ph/0702322 for CO adsorption energy.
226  */
227  if (0)
228  {
229  read_species_file( "chem_species_grn.dat" );
230  }
231  else
232  {
233  sp = newspecies("COgrn ",MOLECULE,MOLE_ACTIVE, -113.8f);
234  sp = newspecies("H2Ogrn",MOLECULE,MOLE_ACTIVE, -238.9f);
235  sp = newspecies("OHgrn ",MOLECULE,MOLE_ACTIVE, 38.4f);
236  //sp = newspecies("Hgrn ",MOLECULE,MOLE_ACTIVE, 216.f);
237  }
238  }
239 
240  /* Add passive species to complete network */
241  sp = newspecies("e- ",OTHER,MOLE_PASSIVE, 0.0f);
242  sp->charge = -1; sp->mole_mass = (realnum)ELECTRON_MASS; /* Augment properties for this non-molecular species */
243  sp = newspecies("grn ",OTHER,MOLE_PASSIVE, 0.0f);
244  sp = newspecies("PHOTON",OTHER,MOLE_PASSIVE, 0.0f);
245  sp = newspecies("CRPHOT",OTHER,MOLE_PASSIVE, 0.0f);
246  sp = newspecies("CRP ",OTHER,MOLE_PASSIVE, 0.0f);
247 
249  sp = newspecies("H- ",MOLECULE,MOLE_ACTIVE, 143.2f);
251  {
252  sp = newspecies("H2* ",MOLECULE,MOLE_ACTIVE,
254  }
255 
256  if( deut.lgElmtOn )
257  {
258  read_species_file( "chem_species_deuterium.dat", false );
259  }
260 
261  /* Add species for all other elements and their first ions -- couple to network at least via H- */
262  for( ChemAtomList::iterator atom = unresolved_atom_list.begin();
263  atom != unresolved_atom_list.end(); ++atom)
264  {
265  long int nelem = (*atom)->el->Z-1;
266 
267  for( long ion=0; ion<=nelem+1; ion++ )
268  {
270  char temp[CHARS_ION_STAGE+1];
271  if( ion==0 )
272  temp[0] = '\0';
273  else if( ion==1 )
274  sprintf( temp, "+" );
275  else
276  sprintf( temp, "+%ld", ion );
277  sprintf( str, "%s%s", (*atom)->label().c_str(), temp );
278  if (findspecies(str) == null_mole)
279  {
280  sp = newspecies(str,MOLECULE,MOLE_ACTIVE, 0.f);
281  fixit(); // populate these in a local update
282 #if 0
283  if( sp != NULL )
284  {
285  sp->levels = NULL;
286  sp->numLevels = 0;
287  }
288 #endif
289  }
290  }
291  }
292 
293  return;
294 }
295 
297 {
298  DEBUG_ENTRY( "mole_make_list()" );
299 
300  /* Create linear list of species and populate it... */
302 
303  /* ...first active species */
304  long int i = 0;
305  for (molecule_i p = mole_priv::spectab.begin(); p != mole_priv::spectab.end(); ++p)
306  {
307  if (isactive(*(p->second)))
308  mole_global.list[i++] = p->second;
309  }
310  ASSERT (i == mole_global.num_calc);
311 
312  /* Sort list into a standard ordering */
314 
315  for (molecule_i p = mole_priv::spectab.begin(); p != mole_priv::spectab.end(); ++p)
316  {
317  if (ispassive(*(p->second)))
318  mole_global.list[i++] = p->second;
319  }
320  ASSERT (i == mole_global.num_total);
321 
322  /* Set molecule indices to order of list just created */
323  for(i=0;i<mole_global.num_total;i++)
324  {
325  mole_global.list[i]->index = i;
326  }
327 
328  for(i=0;i<mole_global.num_total;i++)
329  {
330  if( !mole_global.list[i]->parentLabel.empty() )
331  {
332  long parentIndex = findspecies( mole_global.list[i]->parentLabel.c_str() )->index;
333  mole_global.list[i]->parentIndex = parentIndex;
334  }
335  else
336  mole_global.list[i]->parentIndex = -1;
337  }
338 
339  /* Register the atomic ladders */
340  for(i=0;i<mole_global.num_total;i++)
341  {
342  molecule *sp = &(*mole_global.list[i]);
343  if (sp->isMonatomic())
344  {
345  ASSERT( (int)sp->nAtom.size() == 1 );
346  count_ptr<chem_atom> atom = sp->nAtom.begin()->first;
347  ASSERT(sp->charge <= atom->el->Z);
348  if(sp->charge >= 0 && sp->lgGas_Phase)
349  {
350  atom->ipMl[sp->charge] = i;
351  }
352  }
353  }
354 
355  return;
356 
357 }
358 
359 STATIC void read_species_file( string filename, bool lgCreateIsotopologues )
360 {
361  DEBUG_ENTRY( "read_sepcies_file()" );
362 
363  fstream ioDATA;
364  open_data( ioDATA, filename.c_str(), mode_r );
365  string line;
366 
367  while( getline( ioDATA,line ) )
368  {
369  if( line.empty() )
370  break;
371  if( line[0] == '#' )
372  continue;
373  istringstream iss( line );
374  string species;
375  double formation_enthalpy;
376  iss >> species;
377  iss >> formation_enthalpy;
378  ASSERT( iss.eof() );
379  newspecies( species.c_str(), MOLECULE,MOLE_ACTIVE, formation_enthalpy, lgCreateIsotopologues );
380  //fprintf( ioQQQ, "DEBUGGG read_species_file %s\t%f\n", species.c_str(), formation_enthalpy );
381  }
382 
383  return;
384 }
385 /*lint +e778 constant expression evaluates to 0 in operation '-' */
386 
389  vector< int >& numAtoms,
390  string atom_old,
391  string atom_new,
392  string embellishments,
393  vector<string>& newLabels )
394 {
395  fixit(); // make sure atom_new and atom_old are isotopes
396  fixit(); // make sure atom_new is not already present
397 
398  //for( ChemAtomList::iterator it = atoms.begin(); it != atoms.end(); ++it )
399  for( unsigned position = 0; position < atoms.size(); ++position )
400  {
401  stringstream str;
402  if( atoms[position]->label() == atom_old )
403  {
404  for( unsigned i=0; i<position; ++i )
405  {
406  str << atoms[i]->label();
407  if( numAtoms[i]>1 )
408  str << numAtoms[i];
409  }
410 
411  if( numAtoms[position] > 1 )
412  {
413  str << atom_old;
414  if( numAtoms[position] > 2 )
415  str << numAtoms[position]-1;
416  }
417 
418 
419  if( position+1 == atoms.size() )
420  str << atom_new;
421 
422  for( unsigned i=position+1; i<atoms.size(); ++i )
423  {
424  if( i==position+1 )
425  {
426  // remove adjacent duplicates
427  if( atom_new == atoms[i]->label() )
428  {
429  str << atoms[i]->label();
430  ASSERT( numAtoms[i] + 1 > 1 );
431  str << numAtoms[i] + 1;
432  }
433  else
434  {
435  str << atom_new;
436  str << atoms[i]->label();
437  if( numAtoms[i] > 1 )
438  str << numAtoms[i];
439  }
440  }
441  else
442  {
443  str << atoms[i]->label();
444  if( numAtoms[i] > 1 )
445  str << numAtoms[i];
446  }
447  }
448 
449  // add on charge, grn, and excitation embellishments
450  str << embellishments;
451 
452  newLabels.push_back( str.str() );
453  //fprintf( ioQQQ, "DEBUGGG create_isotopologues_one %s\n", newLabels.back().c_str() );
454  }
455  }
456 
457  return;
458 }
459 
460 /* Fill element linking structure */
461 STATIC void newelement(const char label[], int ipion)
462 {
463  char *s;
464 
465  DEBUG_ENTRY("newelement()");
466 
467  /* Create private workspace for label; copy and strip trailing whitespace */
468  int len = strlen(label)+1;
469  auto_vec<char> mylab_v(new char[len]);
470  char *mylab = mylab_v.data();
471  strncpy(mylab,label,len);
472  s = strchr(mylab,' ');
473  if (s)
474  *s = '\0';
475 
476  int exists = (mole_priv::elemtab.find(mylab) != mole_priv::elemtab.end());
477  if (!exists)
478  {
479  count_ptr<chem_element> element(new chem_element(ipion+1,mylab));
480  mole_priv::elemtab[element->label] = element;
481  element_list.push_back(element);
482  }
483  return;
484 }
485 
486 /* Fill isotope lists */
487 STATIC void newisotope( const count_ptr<chem_element>& el, int massNumberA,
488  realnum mass_amu, double frac )
489 {
490 
491  DEBUG_ENTRY("newisotope()");
492 
493  ASSERT( massNumberA < 3 * LIMELM && ( massNumberA > 0 || massNumberA == -1 ) );
494  ASSERT( mass_amu < 3. * LIMELM && mass_amu > 0. );
495  ASSERT( frac <= 1. + FLT_EPSILON && frac >= 0. );
496 
497  count_ptr<chem_atom> isotope(new chem_atom);
498  isotope->A = massNumberA;
499  isotope->mass_amu = mass_amu;
500  isotope->frac = frac;
501  isotope->ipMl.resize(el->Z+1);
502  isotope->el = el.get_ptr();
503  for (long int ion = 0; ion < el->Z+1; ion++)
504  isotope->ipMl[ion] = -1; /* Chemical network species indices not yet defined */
505 
506  //int exists = (mole_priv::atomtab.find( isotope->label() ) != mole_priv::atomtab.end());
507  mole_priv::atomtab[ isotope->label() ] = isotope;
508  atom_list.push_back(isotope);
509  if( isotope->lgMeanAbundance() )
510  unresolved_atom_list.push_back(isotope);
511  // register with 'parent' element
512  el->isotopes[massNumberA] = isotope;
513 }
514 
516 {
517  DEBUG_ENTRY("MeanMassOfElement()");
518 
519  // if no isotopes have been defined, just use the mean mass stored elsewhere
520  if( el->isotopes.size()==0 )
521  return dense.AtomicWeight[el->Z-1];
522 
523  realnum averageMass = 0., fracsum = 0.;
524  for( isotopes_i it = el->isotopes.begin(); it != el->isotopes.end(); ++it )
525  {
526  fracsum += it->second->frac;
527  averageMass += it->second->mass_amu * it->second->frac;
528  }
529  ASSERT( fp_equal( fracsum, 1.f ) );
530 
531  return averageMass;
532 }
533 
535  const char label[],
536  enum spectype type,
537  enum mole_state state,
538  realnum form_enthalpy)
539 {
540  return newspecies( label, type, state, form_enthalpy, true);
541 }
542 
543 /* Parse species string to find constituent atoms, charge etc. */
545  const char label[],
546  enum spectype type,
547  enum mole_state state,
548  realnum form_enthalpy,
549  bool lgCreateIsotopologues )/* formation enthalpy at 0K */
550 {
551  DEBUG_ENTRY("newspecies()");
552 
553  int exists;
554  ChemAtomList atomsLeftToRight;
555  vector< int > numAtoms;
556  string embellishments;
557  char *s;
558  count_ptr<molecule> mol(new molecule);
559 
560  mol->parentLabel.clear();
561  mol->isEnabled = true;
562  mol->charge = 0;
563  mol->lgExcit = false;
564  mol->mole_mass = 0.0;
565  mol->state = state;
566  mol->lgGas_Phase = true;
567  mol->form_enthalpy = form_enthalpy;
568  mol->groupnum = -1;
569 
570  /* Create private workspace for label; copy and strip trailing whitespace */
571  int len = strlen(label)+1;
572  auto_vec<char> mylab_v(new char[len]);
573  char *mylab = mylab_v.data();
574  strncpy(mylab,label,len);
575  s = strchr(mylab,' ');
576  if (s)
577  *s = '\0';
578  mol->label = mylab;
579 
580  if(type == MOLECULE)
581  {
582  if( parse_species_label( mylab, atomsLeftToRight, numAtoms, embellishments, mol->lgExcit, mol->charge, mol->lgGas_Phase ) == false )
583  return NULL;
584 
585  for( unsigned i = 0; i < atomsLeftToRight.size(); ++i )
586  {
587  mol->nAtom[ atomsLeftToRight[i] ] += numAtoms[i];
588  mol->mole_mass += numAtoms[i] * atomsLeftToRight[i]->mass_amu * (realnum)ATOMIC_MASS_UNIT;
589  }
590  }
591 
592  // we also kill H- if molecules are disabled. This is less than ideal,
593  // but physically motivated by the fact that one of the strongest H- sinks
594  // involves formation of H2 (disabled by "no molecules"), while one the
595  // fastest sources is e- recombination (which would still be allowed).
596  if ( (mol->n_nuclei() > 1 || (mol->isMonatomic() && mol->charge==-1) ) && mole_global.lgNoMole)
597  {
598  if( trace.lgTraceMole )
599  fprintf(ioQQQ,"No species %s as molecules off\n",label);
600  return NULL;
601  }
602 
603  if (mol->n_nuclei() > 1 && mole_global.lgNoHeavyMole)
604  {
605  for( nAtoms_ri it=mol->nAtom.rbegin(); it != mol->nAtom.rend(); --it )
606  {
607  if( it->first->el->Z-1 != ipHYDROGEN )
608  {
609  ASSERT( it->second > 0 );
610  if( trace.lgTraceMole )
611  fprintf(ioQQQ,"No species %s as heavy molecules off\n",label);
612  return NULL;
613  }
614  }
615  }
616 
617  /* Insert species into hash table */
618  exists = (mole_priv::spectab.find(mol->label) != mole_priv::spectab.end());
619  if( exists )
620  {
621  fprintf( ioQQQ,"Warning: duplicate species %s - using first one\n",
622  mol->label.c_str() );
623  return NULL;
624  }
625  else
626  mole_priv::spectab[mol->label] = mol;
627 
628  // all map entries should have strictly positive number of nuclei
629  for( nAtoms_i it=mol->nAtom.begin(); it != mol->nAtom.end(); ++it )
630  ASSERT( it->second > 0 );
631 
632  if (state != MOLE_NULL)
634  if (state == MOLE_ACTIVE)
636 
637  // this is a special case to always treat 13CO (as has long been done)
638  if( lgCreateIsotopologues && type==MOLECULE && mol->label.compare("CO")==0 )
639  {
640  molecule *sp = newspecies( "^13CO", MOLECULE, mol->state, mol->form_enthalpy, false );
641  sp->parentLabel = mol->label;
642  }
643 
644  // create singly-substituted isotopologues
645  if( lgCreateIsotopologues && type==MOLECULE && !mol->isMonatomic() )
646  {
647  for( nAtoms_i it1 = mol->nAtom.begin(); it1 != mol->nAtom.end(); ++it1 )
648  {
649  for( map<int, count_ptr<chem_atom> >::iterator it2 = it1->first->el->isotopes.begin();
650  it2 != it1->first->el->isotopes.end(); ++it2 )
651  {
652  // we don't want to create ^1H isotopologues (only substitute D for H)
653  if( it1->first->el->Z-1 == ipHYDROGEN && it2->second->A != 2 )
654  continue;
655  if( !mole_global.lgTreatIsotopes[it1->first->el->Z-1] )
656  continue;
657  if( it2->second->lgMeanAbundance() )
658  continue;
659  vector<string> isoLabs;
660  create_isotopologues_one( atomsLeftToRight, numAtoms, it1->first->label(), it2->second->label(), embellishments, isoLabs );
661  //fprintf( ioQQQ, " DEBUGGG %10s isotopologues of %10s:", it1->first->label().c_str(), mol->label.c_str() );
662  //for( vector<string>::iterator lab = isoLabs.begin(); lab != isoLabs.end(); ++ lab )
663  // fprintf( ioQQQ, " %10s", lab->c_str() );
664  //fprintf( ioQQQ, "\n" );
665  for( vector<string>::iterator newLabel = isoLabs.begin(); newLabel != isoLabs.end(); ++newLabel )
666  {
667  molecule *sp = newspecies( newLabel->c_str(), MOLECULE, mol->state, mol->form_enthalpy, false );
668  // D is special -- don't set parentLabel
669  if( sp!=NULL && it2->second->A != 2 )
670  sp->parentLabel = mol->label;
671  }
672  }
673  }
674  }
675 
676  return &(*mol);
677 }
678 bool parse_species_label( const char label[], ChemAtomList &atomsLeftToRight, vector<int> &numAtoms, string &embellishments )
679 {
680  bool lgExcit, lgGas_Phase;
681  int charge;
682  bool lgOK = parse_species_label( label, atomsLeftToRight, numAtoms, embellishments, lgExcit, charge, lgGas_Phase );
683  return lgOK;
684 }
685 bool parse_species_label( const char label[], ChemAtomList &atomsLeftToRight, vector<int> &numAtoms, string &embellishments,
686  bool &lgExcit, int &charge, bool &lgGas_Phase )
687 {
688  long int i, n, ipAtom;
689  char thisAtom[CHARS_ISOTOPE_SYM];
691  char mylab[CHARS_SPECIES];
692  char *s;
693 
694  strncpy( mylab, label, CHARS_SPECIES );
695 
696  /* Excitation... */
697  s = strpbrk(mylab,"*");
698  if(s)
699  {
700  lgExcit = true;
701  embellishments = s;
702  *s = '\0';
703  }
704 
705  /* ...Charge */
706  s = strpbrk(mylab,"+-");
707  if(s)
708  {
709  if(isdigit(*(s+1)))
710  n = atoi(s+1);
711  else
712  n = 1;
713  if(*s == '+')
714  charge = n;
715  else
716  charge = -n;
717  embellishments = s + embellishments;
718  *s = '\0';
719  }
720  /* ...Grain */
721  s = strstr(mylab,"grn");
722  if(s)
723  {
724  lgGas_Phase = false;
725  embellishments = s + embellishments;
726  *s = '\0';
727  }
728  else
729  {
730  lgGas_Phase = true;
731  }
732  //fprintf( ioQQQ, "DEBUGGG parse_species_label %s\t%s\t%s\n", label, mylab, embellishments.c_str() );
733 
734  /* Now analyse chemical formula */
735  i = 0;
736  while (mylab[i] != '\0' && mylab[i] != ' ' && mylab[i] != '*')
737  {
738  /* Select next element in species, matches regexp [A-Z][a-z]? */
739  ipAtom = 0;
740  /* look for isotope prefix */
741  if(mylab[i]=='^')
742  {
743  thisAtom[ipAtom++] = mylab[i++];
744  ASSERT( isdigit(mylab[i]) );
745  thisAtom[ipAtom++] = mylab[i++];
746  if(isdigit(mylab[i]))
747  {
748  thisAtom[ipAtom++] = mylab[i++];
749  }
750  }
751  // should be first character of an element symbol
752  thisAtom[ipAtom++] = mylab[i++];
753  if(islower(mylab[i]))
754  {
755  thisAtom[ipAtom++] = mylab[i++];
756  }
757  thisAtom[ipAtom] = '\0';
758  ASSERT(ipAtom <= CHARS_ISOTOPE_SYM);
759 
760  atom = findatom(thisAtom);
761  if(atom.get_ptr() == NULL)
762  {
763  fprintf(stderr,"Did not recognize atom at %s in \"%s \"[%ld]\n",thisAtom,mylab,i);
764  exit(-1);
765  }
766  if(!dense.lgElmtOn[atom->el->Z-1])
767  {
768  if( trace.lgTraceMole )
769  fprintf(ioQQQ,"No species %s as element %s off\n",mylab,atom->el->label.c_str() );
770  return false;
771  }
772 
773  if(isdigit(mylab[i])) /* If there is >1 of this atom */
774  {
775  n = 0;
776  do {
777  n = 10*n+(long int)(mylab[i]-'0');
778  i++;
779  } while (isdigit(mylab[i]));
780  }
781  else
782  {
783  n = 1;
784  }
785  atomsLeftToRight.push_back( atom );
786  numAtoms.push_back( n );
787  }
788 
789  return true;
790 }
791 STATIC bool isactive(const molecule &mol)
792 {
793  DEBUG_ENTRY("isactive()");
794  return mol.state == MOLE_ACTIVE;
795 }
796 STATIC bool ispassive(const molecule &mol)
797 {
798 
799  DEBUG_ENTRY("ispassive()");
800  return mol.state == MOLE_PASSIVE;
801 }
802 
803 bool lgDifferByExcitation( const molecule &mol1, const molecule &mol2 )
804 {
805  if( mol1.label == mol2.label + "*" )
806  return true;
807  else if( mol2.label == mol1.label + "*" )
808  return true;
809  else
810  return false;
811 }
812 
813 molecule *findspecies(const char buf[])
814 {
815  DEBUG_ENTRY("findspecies()");
816 
817  // strip string of the first space and anything after it
818  string s;
819  for (const char *pb = buf; *pb && *pb != ' '; ++pb)
820  {
821  s += *pb;
822  }
823 
824  const molecule_i p = mole_priv::spectab.find(s);
825 
826  if(p != mole_priv::spectab.end())
827  return &(*p->second);
828  else
829  return null_mole;
830 }
831 
832 molezone *findspecieslocal(const char buf[])
833 {
834  DEBUG_ENTRY("findspecieslocal()");
835 
836  // strip string of the first space and anything after it
837  string s;
838  for (const char *pb = buf; *pb && *pb != ' '; ++pb)
839  {
840  s += *pb;
841  }
842 
843  const molecule_i p = mole_priv::spectab.find(s);
844 
845  if(p != mole_priv::spectab.end())
846  return &mole.species[ p->second->index ];
847  else
848  return null_molezone;
849 }
850 
852 {
853  chem_atom_i p;
854 
855  DEBUG_ENTRY("findatom()");
856 
857  p = mole_priv::atomtab.find(buf);
858 
859  if(p != mole_priv::atomtab.end())
860  return p->second;
861  else
862  return count_ptr<chem_atom>(NULL);
863 }
864 
866 {
867  int i;
868  double den_times_area, den_grains, adsorbed_density;
869 
870  DEBUG_ENTRY("mole_update_species_cache()");
871 
872  enum { DEBUG_MOLE = false };
873 
874  for (i=0;i<mole_global.num_total;i++)
875  {
876  if(mole.species[i].location != NULL)
877  {
878  ASSERT( mole_global.list[i]->parentLabel.empty() );
879  mole.species[i].den = *(mole.species[i].location);
880  if (DEBUG_MOLE)
881  fprintf(ioQQQ,"%s: %f\n",mole_global.list[i]->label.c_str(),mole.species[i].den);
882  }
883  }
884 
886 
887  /* For rates that are dependent on grain physics. This includes grain density,
888  cross sectional area, and dust temperature of each constituent. Note that
889 
890  gv.bin[nd]->IntArea/4.*gv.bin[nd]->cnv_H_pCM3
891 
892  is the integrated projected grain surface area per cm^3 of gas for each grain size bin */
893 
894  /* >>chng 06 feb 28, turn off this rate when no grain molecules */
895  /* >>chng 06 dec 05 rjrw: do this in newreact rather than rate */
896  if( gv.lgDustOn() )
897  {
898  den_times_area = den_grains = 0.0;
899  for( size_t nd=0; nd < gv.bin.size(); nd++ )
900  {
901  /* >>chng 06 mar 04, update expression for projected grain surface area, PvH */
902  den_times_area += gv.bin[nd]->IntArea/4.*gv.bin[nd]->cnv_H_pCM3;
903  den_grains += gv.bin[nd]->cnv_GR_pCM3;
904  }
905 
906  adsorbed_density = 0.0;
907  for (i=0;i<mole_global.num_total;i++)
908  {
909  if( !mole_global.list[i]->lgGas_Phase && mole_global.list[i]->parentLabel.empty() )
910  adsorbed_density += mole.species[i].den;
911  }
912 
913  mole.grain_area = (realnum) den_times_area;
914  mole.grain_density = (realnum) den_grains;
915 
916  double mole_cs = 1e-15;
917  if (4*den_times_area <= mole_cs*adsorbed_density)
918  mole.grain_saturation = 1.0;
919  else
920  mole.grain_saturation = (realnum)((mole_cs*adsorbed_density)/(4.*den_times_area));
921  }
922  else
923  {
924  mole.grain_area = 0.0;
925  mole.grain_density = 0.0;
926  mole.grain_saturation = 1.0;
927  }
928  if (DEBUG_MOLE)
929  fprintf(ioQQQ,"Dust: %f %f %f\n",
931 
932 }
933 
935 // Finding the total atom density from MoleMap.molElems w
936 {
937  int i;
938 
939  /* These two updates should together maintain the abundance invariant */
940 
941  // Assert invariant
943 
944  // Update total of non-ladder species
947 
948  /* charge on molecules */
949  mole.elec = 0.;
950  for(i=0;i<mole_global.num_calc;i++)
951  {
952  if (mole.species[i].location == NULL && mole_global.list[i]->parentLabel.empty())
953  mole.elec += mole.species[i].den*mole_global.list[i]->charge;
954  }
955 
956  // Update ionization ladder species
957  realnum delta = 0.0;
958  long ncpt = 0;
959 
960  for (i=0;i<mole_global.num_total;i++)
961  {
962  if(mole.species[i].location && mole_global.list[i]->state == MOLE_ACTIVE)
963  {
964  realnum new_pop = mole.species[i].den;
965 
966  if( mole_global.list[i]->isMonatomic() )
967  {
968  realnum old_pop = *(mole.species[i].location);
969  long nelem = mole_global.list[i]->nAtom.begin()->first->el->Z-1;
970  realnum frac = (new_pop-old_pop)/SDIV(new_pop+old_pop+1e-8*
971  dense.gas_phase[nelem]);
972  delta += frac*frac;
973  ++ncpt;
974  }
975 
976  //if( iteration >= 3 && nzone >= 100 )
977  // fprintf( ioQQQ, "DEBUGGG mole_return_ %i\t%s\t%.12e\t%.12e\t%.12e\t%.12e\t%li\n",
978  // i, mole_global.list[i]->label.c_str(), new_pop, old_pop, frac, delta, ncpt );
979  *(mole.species[i].location) = new_pop;
980  }
981  }
982 
983  // Assert invariant
985  return ncpt>0 ? sqrt(delta/ncpt) : 0.f;
986 }
987 
989 {
990  DEBUG_ENTRY("t_mole_local::set_isotope_abundances()");
991 
992  // loop over unresolved elements
993  for(ChemAtomList::iterator atom = unresolved_atom_list.begin(); atom != unresolved_atom_list.end(); ++atom)
994  {
995  // loop over all isotopes of each element
996  for( isotopes_i it = (*atom)->el->isotopes.begin(); it != (*atom)->el->isotopes.end(); ++it )
997  {
998  // skip mean-abundance "isotopes"
999  if( it->second->lgMeanAbundance() )
1000  continue;
1001 
1002  // loop over all ions of the isotope
1003  for( unsigned long ion=0; ion<it->second->ipMl.size(); ++ion )
1004  {
1005  if( it->second->ipMl[ion] != -1 &&
1006  (species[ it->second->ipMl[ion] ].location == NULL ) && (*atom)->ipMl[ion] != -1 )
1007  {
1008  species[ it->second->ipMl[ion] ].den = species[ (*atom)->ipMl[ion] ].den * it->second->frac;
1009  }
1010  }
1011  }
1012  }
1013 
1014  return;
1015 }
1016 
1017 void t_mole_local::set_location( long nelem, long ion, double *density )
1018 {
1019  DEBUG_ENTRY( "t_mole_local::set_location()" );
1020 
1021  ASSERT( nelem < LIMELM );
1022  ASSERT( ion < nelem + 2 );
1023  long mole_index = unresolved_atom_list[nelem]->ipMl[ion];
1024  // element not enabled if index is -1
1025  if( mole_index == -1 )
1026  return;
1027  ASSERT( mole_index < mole_global.num_total );
1028  species[mole_index].location = density;
1029 
1030  return;
1031 }
1032 
1034 {
1035  DEBUG_ENTRY( "total_molecule_deut()" );
1036 
1037  double total = 0.;
1038 
1039  if( !deut.lgElmtOn )
1040  return;
1041 
1042  for (long int i=0;i<mole_global.num_calc;++i)
1043  {
1044  if (mole.species[i].location == NULL && mole_global.list[i]->parentLabel.empty() )
1045  {
1046  for( molecule::nAtomsMap::iterator atom=mole_global.list[i]->nAtom.begin();
1047  atom != mole_global.list[i]->nAtom.end(); ++atom)
1048  {
1049  long int nelem = atom->first->el->Z-1;
1050  if( nelem==0 && atom->first->A==2 )
1051  {
1052  total += mole.species[i].den*atom->second;
1053  }
1054  }
1055  }
1056  }
1057 
1058  total_f = (realnum)total;
1059 
1060  return;
1061 }
1063 {
1064  DEBUG_ENTRY( "total_molecule_elems()" );
1065 
1066  /* now set total density of each element locked in molecular species */
1067  for ( long int nelem=ipHYDROGEN;nelem<LIMELM; ++nelem )
1068  {
1069  total[nelem] = 0.;
1070  }
1071  for (long int i=0;i<mole_global.num_calc;++i)
1072  {
1073  if (mole.species[i].location == NULL && mole_global.list[i]->parentLabel.empty() )
1074  {
1075  for( molecule::nAtomsMap::iterator atom=mole_global.list[i]->nAtom.begin();
1076  atom != mole_global.list[i]->nAtom.end(); ++atom)
1077  {
1078  ASSERT( atom->second > 0 );
1079  long int nelem = atom->first->el->Z-1;
1080  if( atom->first->lgMeanAbundance() )
1081  total[nelem] += (realnum) mole.species[i].den*atom->second;
1082  }
1083  }
1084  }
1085 }
1086 void total_network_elems(double total[LIMELM])
1087 {
1088  DEBUG_ENTRY( "total_network_elems()" );
1089 
1090  /* now set total density of each element locked in molecular species */
1091  for ( long int nelem=ipHYDROGEN;nelem<LIMELM; ++nelem )
1092  {
1093  total[nelem] = 0.;
1094  }
1095  for (long int i=0;i<mole_global.num_calc;++i)
1096  {
1097  if (mole_global.list[i]->parentLabel.empty())
1098  {
1099  for( molecule::nAtomsMap::iterator atom=mole_global.list[i]->nAtom.begin();
1100  atom != mole_global.list[i]->nAtom.end(); ++atom)
1101  {
1102  long int nelem = atom->first->el->Z-1;
1103  total[nelem] += (realnum) mole.species[i].den*atom->second;
1104  }
1105  }
1106  }
1107 }
1109 {
1110  long int i;
1111  realnum total;
1112 
1113  DEBUG_ENTRY( "total_molecules()" );
1114 
1115  total = 0.;
1116  for (i=0;i<mole_global.num_calc;++i)
1117  {
1118  if (mole.species[i].location == NULL && mole_global.list[i]->parentLabel.empty())
1119  total += (realnum) mole.species[i].den;
1120  }
1121  return total;
1122 }
1124 {
1125  long int i;
1126  realnum total;
1127 
1128  DEBUG_ENTRY( "total_molecules_gasphase()" );
1129 
1130  total = 0.;
1131  for (i=0;i<mole_global.num_calc;++i)
1132  {
1133  if (mole_global.list[i]->lgGas_Phase && mole.species[i].location == NULL && mole_global.list[i]->parentLabel.empty())
1134  total += (realnum) mole.species[i].den;
1135  }
1136  return total;
1137 }
1138 /*lint +e778 const express eval to 0 */
1139 /*lint +e725 expect positive indentation */
1140 
1142 {
1143  long int i, j;
1144  /* Neutrals and positive ions will be treated as single species inside
1145  molecular equilibrium solver, to facilitate coupling with ionization
1146  solvers */
1147  DEBUG_ENTRY ("mole_make_groups()");
1148  if (mole_global.num_calc == 0)
1149  {
1150  groupspecies = NULL;
1152  return;
1153  }
1154  groupspecies = (molecule **) MALLOC(mole_global.num_calc*sizeof(molecule *));
1155  for (i=0,j=0;i<mole_global.num_calc;i++)
1156  {
1157  if( mole_global.list[i]->parentLabel.empty() && ( !mole_global.list[i]->isMonatomic() || mole_global.list[i]->charge <= 0 || ! mole_global.list[i]->lgGas_Phase ) )
1158  {
1159  /* Compound molecules and negative ions are represented individually */
1160  mole_global.list[i]->groupnum = j;
1161  groupspecies[j++] = &(*mole_global.list[i]);
1162  }
1163  else
1164  {
1165  /* All positive ions are collapsed into single macrostate (i.e. H+ -> H) */
1166  /* Need to increase constant if higher ions are included */
1167  ASSERT (mole_global.list[i]->charge < LIMELM+1);
1168  ASSERT (mole_global.list[i]->groupnum == -1);
1169  }
1170  }
1172  groupspecies = (molecule **) REALLOC((void *)groupspecies,
1173  mole_global.num_compacted*sizeof(molecule *));
1174 
1175  for (i=0;i<mole_global.num_calc;i++)
1176  {
1177  if (mole_global.list[i]->groupnum == -1)
1178  {
1179  if( mole_global.list[i]->isMonatomic() && mole_global.list[i]->parentLabel.empty() )
1180  {
1181  for( nAtoms_i it = mole_global.list[i]->nAtom.begin(); it != mole_global.list[i]->nAtom.end(); ++it )
1182  {
1183  ASSERT( it->second > 0 );
1184  mole_global.list[i]->groupnum = mole_global.list[it->first->ipMl[0]]->groupnum;
1185  break;
1186  }
1187  }
1188  else
1189  {
1190  ASSERT( !mole_global.list[i]->parentLabel.empty() );
1191  mole_global.list[i]->groupnum = mole_global.list[ mole_global.list[i]->parentIndex ]->groupnum;
1192  }
1193  }
1194 
1195  ASSERT( mole_global.list[i]->groupnum != -1);
1196  }
1197 
1198  return;
1199 }
1200 
t_mole_global mole_global
Definition: mole.cpp:6
map< int, count_ptr< chem_atom > > isotopes
Definition: mole.h:29
double grain_area
Definition: mole.h:344
static void sort(MoleculeList::iterator start, MoleculeList::iterator end)
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:616
const double ENERGY_H2_STAR
Definition: h2_priv.h:582
t_co co
Definition: co.cpp:5
struct t_species species
Definition: cddefines.h:1228
bool lgElmtOn
Definition: deuterium.h:19
molecule * null_mole
int n_nuclei(void) const
Definition: mole.h:147
vector< bool > lgTreatIsotopes
Definition: mole.h:311
int num_total
Definition: mole.h:314
ChemAtomList atom_list
mole_state
Definition: mole.h:15
realnum total_molecules(void)
int num_calc
Definition: mole.h:314
void make_species(void)
void total_molecule_deut(realnum &total)
STATIC count_ptr< chem_atom > findatom(const char buf[])
map< string, count_ptr< molecule > >::iterator molecule_i
Definition: mole_priv.h:39
bool lgLeiden_Keep_ipMH2s
Definition: hmi.h:208
bool lgTraceMole
Definition: trace.h:55
const double KJMOL1CM
Definition: physconst.h:170
int A
Definition: mole.h:44
const string label
Definition: mole.h:28
void mole_make_list(void)
t_dense dense
Definition: dense.cpp:24
map< string, count_ptr< mole_reaction > > reactab
map< int, count_ptr< chem_atom > >::iterator isotopes_i
Definition: mole.h:35
STATIC molecule * newspecies(const char label[], enum spectype type, enum mole_state state, realnum form_enthalpy)
double frac
Definition: mole.h:47
FILE * ioQQQ
Definition: cddefines.cpp:7
molezone * findspecieslocal(const char buf[])
Definition: mole.h:364
bool lgGas_Phase
Definition: mole.h:146
void InitDeuteriumIonization()
Definition: deuterium.cpp:19
Definition: mole.h:132
int num_compacted
Definition: mole.h:314
realnum form_enthalpy
Definition: mole.h:164
realnum mass_amu
Definition: mole.h:46
double grain_density
Definition: mole.h:344
t_elementnames elementnames
Definition: elementnames.cpp:5
Definition: mole.h:15
bool isEnabled
Definition: mole.h:139
element_type * data() const
Definition: cddefines.h:1179
t_trace trace
Definition: trace.cpp:5
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:816
#define MALLOC(exp)
Definition: cddefines.h:505
chem_element * el
Definition: mole.h:43
STATIC realnum MeanMassOfElement(const count_ptr< chem_element > &el)
bool lgLeidenHack
Definition: mole.h:286
const ios_base::openmode mode_r
Definition: cpu.h:199
STATIC bool isactive(const molecule &mol)
molecule ** groupspecies
#define STATIC
Definition: cddefines.h:101
map< string, count_ptr< chem_element > > elemtab
string parentLabel
Definition: mole.h:137
STATIC void read_species_file(string filename, bool lgCreateIsotopologues=true)
int groupnum
Definition: mole.h:169
chem_atom * null_atom
t_mole_local mole
Definition: mole.cpp:7
molecule * findspecies(const char buf[])
molecule::nAtomsMap::reverse_iterator nAtoms_ri
Definition: mole.h:215
bool parse_species_label(const char label[], ChemAtomList &atomsLeftToRight, vector< int > &numAtoms, string &embellishments)
t_atoms atoms
Definition: atoms.cpp:5
float realnum
Definition: cddefines.h:107
valarray< class molezone > species
Definition: mole.h:355
enum mole_state state
Definition: mole.h:168
const int INPUT_LINE_LENGTH
Definition: cddefines.h:258
void create_isotopologues_one(ChemAtomList &atoms, vector< int > &numAtoms, string atom_old, string atom_new, string embellishments, vector< string > &newLabels)
realnum AtomicWeight[LIMELM]
Definition: dense.h:75
bool lgElmtOn[LIMELM]
Definition: dense.h:146
map< string, count_ptr< chem_atom > >::iterator chem_atom_i
Definition: mole_priv.h:41
int index
Definition: mole.h:169
realnum total_molecules_gasphase(void)
map< string, count_ptr< mole_reaction > > functab
const int Z
Definition: mole.h:27
STATIC void newelement(const char label[], int ipion)
realnum mole_return_cached_species(const GroupMap &MoleMap)
bool lgExcit
Definition: mole.h:145
diatomics h2("h2", 4100.,&hmi.H2_total, Yan_H2_CS)
void SetDeuteriumFractionation(const realnum &frac)
Definition: deuterium.cpp:61
void SetGasPhaseDeuterium(const realnum &Hdensity)
Definition: deuterium.cpp:69
t_state state
Definition: state.cpp:19
Definition: mole.h:37
char chElementSym[LIMELM][CHARS_ELEMENT_SYM]
Definition: elementnames.h:25
vector< int > ipMl
Definition: mole.h:45
string label(void) const
Definition: mole.h:55
int compare(const molecule &mol2) const
Definition: mole.h:183
map< string, count_ptr< chem_atom > > atomtab
realnum gas_phase[LIMELM]
Definition: dense.h:71
bool lgMeanAbundance(void) const
Definition: mole.h:49
#define ASSERT(exp)
Definition: cddefines.h:582
T * get_ptr() const
Definition: count_ptr.h:49
void set_isotope_abundances(void)
STATIC void start(long, realnum[], realnum[], long, long[], realnum *, int *)
void total_network_elems(double total[LIMELM])
vector< count_ptr< chem_element > > element_list
void set_location(long nelem, long ion, double *dense)
const int LIMELM
Definition: cddefines.h:262
bool isMonatomic(void) const
Definition: mole.h:157
int charge
Definition: mole.h:144
double den
Definition: mole.h:396
STATIC void ReadIsotopeFractions(const vector< bool > &lgResolveNelem)
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
const double ELECTRON_MASS
Definition: physconst.h:91
realnum C12_C13_isotope_ratio
Definition: co.h:20
STATIC void newisotope(const count_ptr< chem_element > &el, int massNumberA, realnum mass_amu, double frac)
bool lgGrain_mole_deplete
Definition: mole.h:308
bool lgDifferByExcitation(const molecule &mol1, const molecule &mol2)
vector< GrainBin * > bin
Definition: grainvar.h:583
void mole_update_species_cache(void)
STATIC bool ispassive(const molecule &mol)
ChemAtomList unresolved_atom_list
t_deuterium deut
Definition: deuterium.cpp:8
string label
Definition: mole.h:142
#define REALLOC
Definition: cddefines.h:523
double elec
Definition: mole.h:347
realnum mole_mass
Definition: mole.h:165
MoleculeList list
Definition: mole.h:317
spectype
sys_float SDIV(sys_float x)
Definition: cddefines.h:956
const int ipCARBON
Definition: cddefines.h:314
nAtomsMap nAtom
Definition: mole.h:143
char * read_whole_line(char *chLine, int nChar, FILE *ioIN)
Definition: service.cpp:70
realnum xMolecules
Definition: deuterium.h:22
bool lgNoHeavyMole
Definition: mole.h:280
bool lgElemsConserved(void)
Definition: dense.cpp:99
GrainVar gv
Definition: grainvar.cpp:5
void updateXMolecules()
Definition: dense.cpp:26
t_hmi hmi
Definition: hmi.cpp:5
bool lgNoMole
Definition: mole.h:277
bool lgDustOn() const
Definition: grainvar.h:471
const int ipHYDROGEN
Definition: cddefines.h:309
void mole_make_groups(void)
void fixit(void)
Definition: service.cpp:991
map< string, count_ptr< molecule > > spectab
chem_element * null_element
void total_molecule_elems(realnum total[LIMELM])
molezone * null_molezone
const double ATOMIC_MASS_UNIT
Definition: physconst.h:88
vector< count_ptr< chem_atom > > ChemAtomList
Definition: mole.h:115
double grain_saturation
Definition: mole.h:344
double FFmtRead(const char *chCard, long int *ipnt, long int last, bool *lgEOL)
Definition: service.cpp:381
molecule::nAtomsMap::iterator nAtoms_i
Definition: mole.h:214