cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mole_eval_balance.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_step fills in matrix for heavy elements molecular routines */
4 #include "cddefines.h"
5 #include "mole.h"
6 #include "mole_priv.h"
7 #include "save.h"
8 #include "dense.h"
9 #include "atmdat.h"
10 /* Nick Abel between July and October of 2003 assisted Dr. Ferland in improving the heavy element
11  * molecular network in Cloudy. Before this routine would predict negative abundances if
12  * the fraction of carbon in the form of molecules came close to 100%. A reorganizing of
13  * the reaction network detected several bugs. Treatment of "coupled reactions",
14  * in which both densities in the reaction rate were being predicted by Cloudy, were also
15  * added. Due to these improvements, Cloudy can now perform calculations
16  * where 100% of the carbon is in the form of CO without predicting negative abundances
17  *
18  * Additional changes were made in November of 2003 so that our reaction
19  * network would include all reactions from the TH85 paper. This involved
20  * adding silicon to the chemical network. Also the reaction rates were
21  * labeled to make identification with the reaction easier and the matrix
22  * elements of atomic C, O, and Si are now done in a loop, which makes
23  * the addition of future chemical species (like N or S) easy.
24  * */
25 /* Robin Williams in August 2006 onwards reorganized the coding to cut down repetitions.
26  * This isolated several further bugs, and allows a sigificant number of lines of
27  * code to be eliminated. The balance of S2/S2+ amd ClO/ClO+ seems highly sensitive
28  * (with small log scale results varying significantly if the order of arithmetic
29  * operations is changed) -- I suspect this may imply a bug somewhere.
30  * */
31 /*lint -e778 constant expression evaluatess to 0 in operation '-' */
32 /*=================================================================*/
33 
35 
36 void mole_eval_balance(long int num_total, double *b, bool lgJac, multi_arr<double,2> &c)
37 {
38  long int i, j;
39  mole_reaction *rate;
40  double rate_tot, rate_deriv[MAXREACTANTS], rk;
41  molecule *sp;
42 
43  DEBUG_ENTRY("mole_eval_balance()");
44  /* zero out array used for formation rates */
45  for( i=0; i < num_total; i++ )
46  {
47  b[i] = 0.;
48  }
49  if (lgJac)
50  c.zero();
51 
52  for(mole_reaction_i p=mole_priv::reactab.begin();
53  p != mole_priv::reactab.end(); ++p)
54  {
55  rate = &(*p->second);
56  rk = mole.reaction_rks[ rate->index ];
57 
58  rate_tot = rk;
59  for(i=0;i<rate->nreactants;i++)
60  {
61  rate_tot *= mole.species[ rate->reactants[i]->index ].den;
62  }
63 
64  for(i=0;i<rate->nreactants;i++)
65  {
66  sp = rate->reactants[i];
67  if (rate->rvector[i] == NULL)
68  {
69  b[sp->index] -= rate_tot;
70  }
71  }
72 
73  for(i=0;i<rate->nproducts;i++)
74  {
75  sp = rate->products[i];
76  if (rate->pvector[i] == NULL)
77  {
78  b[sp->index] += rate_tot;
79  }
80  }
81 
82  if (lgJac)
83  {
84  for(i=0;i<rate->nreactants;i++)
85  {
86  rate_deriv[i] = rk;
87  for(j=0;j<rate->nreactants;j++)
88  {
89  if(i!=j)
90  {
91  rate_deriv[i] *= mole.species[ rate->reactants[j]->index ].den;
92  }
93  }
94  }
95  for(j=0;j<rate->nreactants;j++)
96  {
97  sp = rate->reactants[j];
98  const double rated = rate_deriv[j];
99  for(i=0;i<rate->nreactants;i++)
100  {
101  if (rate->rvector[i] == NULL)
102  c[sp->index][rate->reactants[i]->index] -= rated;
103  }
104  for(i=0;i<rate->nproducts;i++)
105  {
106  if (rate->pvector[i] == NULL)
107  c[sp->index][rate->products[i]->index] += rated;
108  }
109  }
110  }
111  }
112 
113  if (lgJac)
114  {
116  }
117 
118  //mole_dominant_rates(findspecies("H+"),ioQQQ);
119  return;
120 }
121 
122 void mole_eval_sources(long int num_total)
123 {
124  long int i, j, nelem, ion, ion2;
125  mole_reaction *rate;
126  double rate_tot, rate_deriv[MAXREACTANTS], rk;
127  molecule *sp;
128 
129  DEBUG_ENTRY("mole_eval_sources()");
130  /* zero out array used for formation rates */
131  for( i=0; i < num_total; i++ )
132  {
133  mole.species[i].src = mole.species[i].snk = 0.;
134  }
135 
136  for( nelem=0; nelem< LIMELM; ++nelem )
137  {
138  /* these have one more ion than above */
139  for( ion=0; ion<nelem+2; ++ion )
140  {
141  /* zero out the transfer array */
142  for( ion2=0; ion2<nelem+2; ++ion2 )
143  {
144  mole.xMoleChTrRate[nelem][ion][ion2] = 0.;
145  }
146  }
147  }
148 
149  for(mole_reaction_i p=mole_priv::reactab.begin();
150  p != mole_priv::reactab.end(); ++p)
151  {
152  rate = &(*p->second);
153  rk = mole.reaction_rks[ rate->index ];
154 
155  for(i=0;i<rate->nreactants;i++)
156  {
157  rate_deriv[i] = rk;
158  for(j=0;j<rate->nreactants;j++)
159  {
160  if(i!=j)
161  {
162  rate_deriv[i] *= mole.species[ rate->reactants[j]->index ].den;
163  }
164  }
165  }
166 
167  rate_tot = rate_deriv[0] * mole.species[ rate->reactants[0]->index ].den;
168 
169  for(i=0;i<rate->nreactants;i++)
170  {
171  sp = rate->reactants[i];
172  if (rate->rvector[i] == NULL)
173  {
174  mole.species[sp->index].snk += rate_deriv[i];
175  }
176  else
177  {
178  // exclude charge exchange with isotopes of same element
179  if( rate->nreactants==2 )
180  {
181  long otherIndex = 1-i;
182  molecule *sp2 = rate->reactants[otherIndex];
183  if( sp->isMonatomic() && sp2->isMonatomic() && sp->nAtom.begin()->first->el == sp2->nAtom.begin()->first->el )
184  continue;
185  }
186 
187  if ( atmdat.lgCTOn )
188  {
189  for( ChemAtomList::iterator atom = unresolved_atom_list.begin(); atom != unresolved_atom_list.end(); ++atom)
190  {
191  nelem = (*atom)->el->Z-1;
192  if (sp->nAtom.find(*atom) != sp->nAtom.end() && sp->nAtom[*atom] != 0 && rate->rvector[i]->charge != sp->charge)
193  {
194  mole.xMoleChTrRate[nelem][sp->charge][rate->rvector[i]->charge] +=
195  (realnum) rate_deriv[i];
196  break;
197  }
198  }
199  }
200  }
201  }
202 
203  for(i=0;i<rate->nproducts;i++)
204  {
205  sp = rate->products[i];
206  if (rate->pvector[i] == NULL)
207  {
208  mole.species[sp->index].src += rate_tot;
209  }
210  }
211  }
212 
213  for (ChemAtomList::iterator atom = unresolved_atom_list.begin();
214  atom != unresolved_atom_list.end(); ++atom)
215  {
216  const long int nelem=(*atom)->el->Z-1;
217  if( !dense.lgElmtOn[nelem] )
218  continue;
219 
220  for (long int ion=0;ion<nelem+2;ion++)
221  {
222  if ((*atom)->ipMl[ion] != -1)
223  {
224  mole.source[nelem][ion] = mole.species[(*atom)->ipMl[ion]].src;
225  mole.sink[nelem][ion] = mole.species[(*atom)->ipMl[ion]].snk;
226  }
227  else
228  {
229  mole.source[nelem][ion] = 0.0;
230  mole.sink[nelem][ion] = 0.0;
231  }
232  }
233  }
234 
235  //mole_dominant_rates(findspecies("H+"),ioQQQ);
236  return;
237 }
238 
240 {
241  DEBUG_ENTRY ("lgNucleiConserved()");
242  bool checkAllOK = true;
244  tot(atom_list.size(),mole_global.num_calc);
245  vector<double> ccache(mole_global.num_calc);
246  vector<long> ncache(mole_global.num_calc);
247  test.zero();
248  tot.zero();
249 
250  map<chem_atom*, long> atom_to_index;
251  for (unsigned long j=0; j<atom_list.size(); ++j )
252  {
253  atom_to_index[atom_list[j].get_ptr()] = j;
254  }
255  for (long j=0;j<mole_global.num_calc;j++)
256  {
257  long nc = 0;
258  for (long i=0;i<mole_global.num_calc;i++)
259  {
260  if (c[i][j] != 0.)
261  {
262  ccache[nc] = c[i][j];
263  ncache[nc] = i;
264  ++nc;
265  }
266  }
267  if (nc > 0)
268  {
269  for (molecule::nAtomsMap::const_iterator el = mole_global.list[j]->nAtom.begin();
270  el != mole_global.list[j]->nAtom.end(); ++el)
271  {
272  long natom = atom_to_index[el->first.get_ptr()];
273  const int nAtomj = el->second;
274  for (long i=0;i<nc;i++)
275  {
276  const double term = ccache[i] * nAtomj;
277  test[natom][ncache[i]] += term;
278  tot[natom][ncache[i]] += fabs(term);
279  }
280  }
281  }
282  }
283 
284  for( unsigned long natom=0; natom < atom_list.size(); ++natom)
285  {
286  for (long i=0;i<mole_global.num_calc;i++)
287  {
288  const bool checkOK =
289  ( fabs(test[natom][i]) <= MAX2(1e-10*tot[natom][i], 1e10*DBL_MIN) );
290  if ( UNLIKELY(!checkOK) )
291  {
292  chem_atom *atom = atom_list[natom].get_ptr();
293  fprintf(stdout,"Network conservation error %s %s %g %g %g %g\n",
294  atom->label().c_str(),
295  mole_global.list[i]->label.c_str(),
296  test[natom][i],
297  test[natom][i]/tot[natom][i],
298  mole.species[atom->ipMl[0]].den,
299  mole.species[atom->ipMl[1]].den);
300  //fprintf(stdout,"Problem at %s\n",rate->label);
301  checkAllOK = false;
302  }
303  }
304  }
305  return checkAllOK;
306 }
307 
308 void mole_dominant_rates( const molecule *debug_species, FILE *ioOut )
309 {
310  long int i, j;
311  mole_reaction *rate, *ratesnk=NULL, *ratesrc=NULL;
312  double rate_tot, rate_deriv[MAXREACTANTS], rk;
313  molecule *sp;
314  double snkx=0.,srcx=0.;
315 
316  for(mole_reaction_i p=mole_priv::reactab.begin();
317  p != mole_priv::reactab.end(); ++p)
318  {
319  rate = &(*p->second);
320  rk = mole.reaction_rks[ rate->index ];
321 
322  for(i=0;i<rate->nreactants;i++)
323  {
324  rate_deriv[i] = rk;
325  for(j=0;j<rate->nreactants;j++)
326  {
327  if(i!=j)
328  {
329  rate_deriv[i] *= mole.species[ rate->reactants[j]->index ].den;
330  }
331  }
332  }
333 
334  rate_tot = rate_deriv[0] * mole.species[ rate->reactants[0]->index ].den;
335 
336  if (debug_species != null_mole)
337  {
338  for(i=0;i<rate->nproducts;++i)
339  {
340  sp = rate->products[i];
341  if (sp == debug_species && rate->pvector[i] == NULL)
342  {
343  if (fabs(rate_tot) > srcx)
344  {
345  srcx = rate_tot;
346  ratesrc = rate;
347  }
348  }
349  }
350  for(i=0;i<rate->nreactants;++i)
351  {
352  sp = rate->reactants[i];
353  if (sp == debug_species && rate->rvector[i] == NULL)
354  {
355  if (fabs(rate_deriv[i]) > snkx)
356  {
357  snkx = rate_deriv[i];
358  ratesnk = rate;
359  }
360  }
361  }
362  }
363  }
364 
365 
366  if (debug_species != null_mole)
367  {
368  if (ratesrc)
369  {
370  fprintf( ioOut, "%20.20s src %13.7g of %13.7g [",
371  ratesrc->label.c_str(),srcx,mole.species[debug_species->index].src);
372  for (j=0;j<ratesrc->nreactants;j++)
373  {
374  if (j)
375  {
376  fprintf( ioOut, "," );
377  }
378  fprintf( ioOut, "%-6.6s %13.7g",
379  ratesrc->reactants[j]->label.c_str(),
380  mole.species[ ratesrc->reactants[j]->index ].den);
381  }
382  fprintf( ioOut, "]" );
383  }
384  if (ratesnk)
385  {
386  fprintf( ioOut, "%20.20s snk %13.7g of %13.7g [",
387  ratesnk->label.c_str(), snkx * mole.species[debug_species->index].den,
388  mole.species[debug_species->index].snk * mole.species[debug_species->index].den);
389  for (j=0;j<ratesnk->nreactants;j++)
390  {
391  if (j)
392  {
393  fprintf( ioOut, "," );
394  }
395  fprintf( ioOut, "%-6.6s %13.7g",
396  ratesnk->reactants[j]->label.c_str(),
397  mole.species[ ratesnk->reactants[j]->index ].den);
398  }
399  fprintf( ioOut, "]" );
400  }
401  }
402  fprintf( ioOut, "\n" );
403 
404  return;
405 }
molecule * reactants[MAXREACTANTS]
Definition: mole_priv.h:53
t_mole_global mole_global
Definition: mole.cpp:6
vector< double > reaction_rks
Definition: mole.h:357
t_atmdat atmdat
Definition: atmdat.cpp:6
molecule * null_mole
ChemAtomList atom_list
void mole_dominant_rates(const molecule *debug_species, FILE *ioOut)
int num_calc
Definition: mole.h:314
#define MAX2
Definition: cddefines.h:786
int nreactants
Definition: mole_priv.h:52
#define MAXREACTANTS
Definition: mole_priv.h:45
STATIC bool lgNucleiConserved(const multi_arr< double, 2 > &c)
t_dense dense
Definition: dense.cpp:24
map< string, count_ptr< mole_reaction > > reactab
Definition: mole.h:132
double ** sink
Definition: mole.h:351
molecule * products[MAXPRODUCTS]
Definition: mole_priv.h:56
string label
Definition: mole_priv.h:51
molecule * rvector[MAXREACTANTS]
Definition: mole_priv.h:54
#define STATIC
Definition: cddefines.h:101
double ** source
Definition: mole.h:351
t_mole_local mole
Definition: mole.cpp:7
map< string, count_ptr< mole_reaction > >::iterator mole_reaction_i
Definition: mole_priv.h:37
realnum *** xMoleChTrRate
Definition: mole.h:353
float realnum
Definition: cddefines.h:107
valarray< class molezone > species
Definition: mole.h:355
bool lgElmtOn[LIMELM]
Definition: dense.h:146
void mole_eval_sources(long int num_total)
int index
Definition: mole.h:169
Definition: mole.h:37
vector< int > ipMl
Definition: mole.h:45
string label(void) const
Definition: mole.h:55
#define ASSERT(exp)
Definition: cddefines.h:582
molecule * pvector[MAXPRODUCTS]
Definition: mole_priv.h:57
void mole_eval_balance(long int num_total, double *b, bool lgJac, multi_arr< double, 2 > &c)
const int LIMELM
Definition: cddefines.h:262
bool isMonatomic(void) const
Definition: mole.h:157
int charge
Definition: mole.h:144
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
#define UNLIKELY(x)
Definition: cpu.h:374
ChemAtomList unresolved_atom_list
string label
Definition: mole.h:142
MoleculeList list
Definition: mole.h:317
bool lgCTOn
Definition: atmdat.h:177
nAtomsMap nAtom
Definition: mole.h:143