cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
conv_base.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 /*ConvBase main routine to drive ionization solution for all species, find total opacity
4  * called by ConvIoniz */
5 /*lgConverg check whether ionization of element nelem has converged */
6 #include "cddefines.h"
7 #include "dynamics.h"
8 #include "trace.h"
9 #include "elementnames.h"
10 #include "save.h"
11 #include "phycon.h"
12 #include "secondaries.h"
13 #include "stopcalc.h"
14 #include "grainvar.h"
15 #include "highen.h"
16 #include "dense.h"
17 #include "hmi.h"
18 #include "rfield.h"
19 #include "pressure.h"
20 #include "taulines.h"
21 #include "rt.h"
22 #include "grains.h"
23 #include "atmdat.h"
24 #include "ionbal.h"
25 #include "opacity.h"
26 #include "cooling.h"
27 #include "thermal.h"
28 #include "mole.h"
29 #include "iso.h"
30 #include "conv.h"
31 #include "h2.h"
32 #include "deuterium.h"
33 
34 STATIC bool lgNetEdenSrcSmall( void );
35 
36 void UpdateUTAs( void );
37 
38 /*lgIonizConverg check whether ionization of element nelem has converged, called by ionize,
39  * returns true if element is converged, false if not */
40 namespace
41 {
42  class IonizConverg
43  {
44  /* this is fractions [ion stage][nelem], ion stage = 0 for atom, nelem=0 for H*/
45  double OldFracs[LIMELM+1][LIMELM+1];
46  public:
47  IonizConverg()
48  {
49  for (long nelem = ipHYDROGEN; nelem < LIMELM; ++nelem)
50  {
51  for (long ion = 0; ion <= nelem+1; ++ion)
52  {
53  OldFracs[nelem][ion] = dense.xIonDense[nelem][ion];
54  }
55  }
56  }
57  void operator()(
58  /* atomic number on the C scale, 0 for H, 25 for Fe */
59  long loop_ion ,
60  /* this is allowed error as a fractional change. Most are 0.15 */
61  double delta ,
62  /* option to print abundances */
63  bool lgPrint )
64  {
65  bool lgConverg_v = false;
66  double Abund,
67  bigchange ,
68  change ,
69  one;
70 
71  DEBUG_ENTRY( "IonizConverg::operator()" );
72 
73  for (long nelem =ipHYDROGEN; nelem<LIMELM; ++nelem )
74  {
75  if( !dense.lgElmtOn[nelem] )
76  continue;
77 
78  double abundold=0. , abundnew=0.;
79  long ionchg=-1;
80 
81  /* arguments are atomic number, ionization stage
82  * OldFracs[nelem][0] is abundance of nelem (cm^-3) */
83 
84  /* this function returns true if ionization of element
85  * with atomic number nelem has not changed by more than delta,*/
86 
87  /* check whether abundances exist yet, only do this for after first zone */
88  /*if( nzone > 0 )*/
89  /* >>chng 03 sep 02, check on changed ionization after first call through,
90  * to insure converged constant eden / temperature models */
91  if( conv.nPres2Ioniz )
92  {
93  /* >>chng 04 aug 31, this had been static, caused last hits on large changes
94  * in ionization */
95  bigchange = 0.;
96  change = 0.;
97  Abund = dense.gas_phase[nelem];
98 
99  /* loop over all ionization stages, loop over all ions, not just active ones,
100  * since this also sets old values, and so will zero out non-existant ones */
101  for( long ion=0; ion <= (nelem+1); ++ion )
102  {
103  /*lint -e727 OlsdFracs not initialized */
104  if( OldFracs[nelem][ion]/Abund > 1e-4 &&
105  dense.xIonDense[nelem][ion]/Abund > 1e-4 )
106  /*lint +e727 OlsdFracs not initialized */
107  {
108  /* check change in old to new value */
109  one = fabs(dense.xIonDense[nelem][ion]-OldFracs[nelem][ion])/
110  OldFracs[nelem][ion];
111  change = MAX2(change, one );
112  /* remember abundances for largest change */
113  if( change>bigchange )
114  {
115  bigchange = change;
116  abundold = OldFracs[nelem][ion]/Abund;
117  abundnew = dense.xIonDense[nelem][ion]/Abund;
118  ionchg = ion;
119  }
120  }
121  /* now set new value */
122  OldFracs[nelem][ion] = dense.xIonDense[nelem][ion];
123  }
124 
125  if( change >= delta )
126  {
127  char chConvIoniz[INPUT_LINE_LENGTH];
128  sprintf( chConvIoniz , "%2s ion" , elementnames.chElementSym[nelem] );
129  conv.setConvIonizFail(chConvIoniz,abundold,abundnew);
130  ASSERT( abundold>0. && abundnew>0. );
131  }
132  else
133  lgConverg_v = true;
134  }
135  else
136  {
137  for( long ion=0; ion <= (nelem+1); ++ion )
138  {
139  OldFracs[nelem][ion] = dense.xIonDense[nelem][ion];
140  }
141 
142  }
143 
144  /* option to print abundances */
145  if( lgPrint )
146  {
147  fprintf(ioQQQ," nz %ld loop %ld element %li converged? %c worst %ld change %g\n",
148  nzone, loop_ion, nelem, TorF(lgConverg_v),ionchg,bigchange);
149  for( long ion=0; ion<(nelem+1); ++ion )
150  {
151  fprintf(ioQQQ,"\t%.5e", dense.xIonDense[nelem][ion]/dense.gas_phase[nelem]);
152  }
153  fprintf(ioQQQ,"\n");
154  }
155  }
156  }
157  };
158 }
159 
160 /*ConvBase main routine to drive ionization solution for all species, find total opacity
161  * called by ConvIoniz
162  * return 0 if ok, 1 if abort */
163 int ConvBase(
164  /* this is zero the first time ConvBase is called by convIoniz,
165  * counts number of call thereafter */
166  long loopi )
167 {
168  double HeatOld,
169  EdenTrue_old,
170  EdenFromMolecOld,
171  EdenFromGrainsOld,
172  HeatingOld ,
173  CoolingOld;
174  static double SecondOld;
175  static long int nzoneOTS=-1;
176 # define LOOP_ION_LIMIT 10
177  long int loop_ion;
178  static double SumOTS=0. , OldSumOTS[2]={0.,0.};
179  double save_iso_grnd[NISO][LIMELM];
180  valarray<realnum> mole_save(mole_global.num_calc);
181  IonizConverg lgIonizConverg;
182 
183  DEBUG_ENTRY( "ConvBase()" );
184 
185  /* this is set to phycon.te in tfidle, is used to insure that all temp
186  * vars are properly updated when conv_ionizeopacitydo is called
187  * NB must be same type as phycon.te */
189 
190  /* this allows zone number to be printed with slight increment as zone converged
191  * conv.nPres2Ioniz is incremented at the bottom of this routine */
192  fnzone = (double)nzone + (double)conv.nPres2Ioniz/100.;
193 
194  /* reevaluate pressure */
195  /* this sets values of pressure.PresTotlCurr, also calls tfidle,
196  * and sets the total energy content of gas, which may be important for acvection */
197  PresTotCurrent();
198 
199  /* >>chng 04 sep 15, move EdenTrue_old up here, and will redo at bottom
200  * to find change
201  * find and save current true electron density - if this changes by more than the
202  * tolerance then ionization solution is not converged */
203  /* >>chng 04 jul 27, move eden_sum here from after this loop, so that change in EdenTrue
204  * can be monitored */
205  /* update EdenTrue, eden itself is actually changed in ConvEdenIoniz */
206  /* must not call eden_sum on very first time since for classic PDR total
207  * ionization may still be zero on first call */
208  if( conv.nTotalIoniz )
209  {
210  if( eden_sum() )
211  {
212  /* non-zero return indicates abort condition */
213  ++conv.nTotalIoniz;
214  return 1;
215  }
216  }
217 
218  /* the following two were evaluated in eden_sum
219  * will confirm that these are converged */
220  EdenTrue_old = dense.EdenTrue;
221  EdenFromMolecOld = mole.elec;
222  EdenFromGrainsOld = gv.TotalEden;
223  HeatingOld = thermal.htot;
224  CoolingOld = thermal.ctot;
225 
226  /* remember current ground state population - will check if converged */
227  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
228  {
229  for( long nelem=ipISO; nelem<LIMELM;++nelem )
230  {
231  if( dense.lgElmtOn[nelem] )
232  {
233  /* save the ground state population */
234  save_iso_grnd[ipISO][nelem] = iso_sp[ipISO][nelem].st[0].Pop();
235  }
236  }
237  }
238 
239  for( long i=0; i < mole_global.num_calc; i++ )
240  {
241  mole_save[i] = (realnum) mole.species[i].den;
242  }
243 
244  if( loopi==0 )
245  {
246  /* these will be used to look for oscillating ots rates */
247  OldSumOTS[0] = 0.;
248  OldSumOTS[1] = 0.;
249  conv.lgOscilOTS = false;
250  }
251 
252  if( trace.lgTrace )
253  {
254  fprintf( ioQQQ,
255  " ConvBase called. %.2f Te:%.3e HI:%.3e HII:%.3e H2:%.3e Ne:%.3e htot:%.3e CSUP:%.2e Conv?%c\n",
256  fnzone,
257  phycon.te,
260  hmi.H2_total,
261  dense.eden,
262  thermal.htot,
264  TorF(conv.lgConvIoniz()) );
265  }
266  /* want this flag to be true when we exit, various problems will set falst */
268 
269  /* this routine is in heatsum.c, and zeros out the heating array */
270  HeatZero();
271 
272  /* if this is very first call, say not converged, since no meaningful way to
273  * check on changes in quantities. this counter is false only on very first
274  * call, when equal to zero */
275  if( !conv.nTotalIoniz )
276  {
277  conv.setConvIonizFail( "first call", 0.0, 0.0 );
278  }
279 
280  /* this will be flag to check whether any ionization stages
281  * were trimmed down */
282  conv.lgIonStageTrimed = false;
283 
284  /* must redo photoionization rates for all species on second and later tries */
285  /* always reevaluate the rates when . . . */
286  /* this flag says not to redo opac and photo rates, and following test will set
287  * true if one of several tests not done*/
288  opac.lgRedoStatic = false;
289  if(
290  /* opac.lgOpacStatic (usually true), is set false with no static opacity command */
291  !opac.lgOpacStatic ||
292  /* we are in search mode */
293  conv.lgSearch ||
294  /* this is the first call to this zone */
295  conv.nPres2Ioniz == 0 )
296  {
297  /* we need to redo ALL photoionization rates */
298  opac.lgRedoStatic = true;
299  }
300 
301  /* calculate radiative and dielectronic recombination rate coefficients */
303 
304  /* this adjusts the lowest and highest stages of ionization we will consider,
305  * only safe to call when lgRedoStatic is true since this could lower the
306  * lowest stage of ionization, which needs all its photo rates */
307 
308  /* conv.nTotalIoniz is only 0 (false) on the very first call to here,
309  * when the ionization distribution is not yet done */
310  if( conv.nTotalIoniz )
311  {
312  bool lgIonizTrimCalled = false;
313  static long int nZoneCalled = 0;
314 
315  fixit(); // nZoneCalled should be reinitialized for each grid point?
316 
317  /* ionization trimming only used for He and heavier, not H */
318  /* only do this one time per zone since up and down cycle can occur */
319  /* >>chng 05 jan 15, increasing temperature above default first conditions, also
320  * no trim during search - this fixed major logical error when sim is
321  * totally mechanically heated to coronal temperatures -
322  * problem discovered by Ronnie Hoogerwerf */
323  /* do not keep changing the trim after the first call within
324  * this zone once we are deep into layer - doing so introduced very
325  * small level of noise as some stages
326  * went up and down - O+2 - O+3 was good example, when small H+3 after He+ i-front
327  * limit to one increase per element per zone */
328  if( conv.nTotalIoniz>2 &&
329  /* only call one time per zone except during search phase,
330  * when only call after 20 times only if temperature has changed */
331  ( conv.lgSearch || nZoneCalled!=nzone) )
332  {
333  lgIonizTrimCalled = true;
334  for( long nelem=ipHELIUM; nelem<LIMELM; ++nelem )
335  {
336  if( dense.lgElmtOn[nelem] )
337  {
338  /* ion_trim will set conv.lgIonStageTrimed true is any ion has its
339  * lowest stage of ionization dropped or trimmed */
340  ion_trim(nelem);
341  }
342  }
343  nZoneCalled = nzone;
344  }
345 
346  /* following block only set of asserts */
347 # if !defined(NDEBUG)
348  /* check that proper abundances are either positive or zero */
349  for( long nelem=ipHELIUM; nelem<LIMELM; ++nelem)
350  {
351  if( dense.lgElmtOn[nelem] )
352  {
353  for( long ion=0; ion<dense.IonLow[nelem]; ++ion )
354  {
355  ASSERT( dense.xIonDense[nelem][ion] == 0. );
356  }
357  /*if( nelem==5 ) fprintf(ioQQQ,"carbbb\t%li\n", dense.IonHigh[nelem]);*/
358  for( long ion=dense.IonLow[nelem]; ion<=dense.IonHigh[nelem]; ++ion )
359  {
360  /* >>chng 02 feb 06, had been > o., chng to > SMALLFLOAT to
361  * trip over VERY small floats that failed on alphas, but not 386
362  *
363  * in case where lower ionization stage was just lowered or
364  * trimmed down the abundance
365  * was set to SMALLFLOAT so test must be < SMALLFLOAT */
366  /* >>chng 02 feb 19, add check for search phase. During this search
367  * models with extreme ionization (all neutral or all ionized) can
368  * have extreme but non-zero abundances far from the ionization peak for
369  * element with lots of electrons. These will go away once the model
370  * becomes stable */
371  /* >>chng 03 dec 01, add check on whether ion trim was called
372  * conserve.in threw assert when iontrim not called and abund grew small */
373  ASSERT( conv.lgSearch || !lgIonizTrimCalled ||
374  /* this can happen if all C is in the form of CO */
375  (ion==0 && dense.IonHigh[nelem]==0 ) ||
376  dense.xIonDense[nelem][ion] >= SMALLFLOAT ||
377  dense.xIonDense[nelem][ion]/dense.gas_phase[nelem] >= SMALLFLOAT );
378  }
379  for( long ion=dense.IonHigh[nelem]+1; ion<nelem+1; ++ion )
380  {
381  ASSERT( ion >= 0 );
382  ASSERT( dense.xIonDense[nelem][ion] == 0. );
383  }
384  }
385  }
386 # endif
387  }
388 
389  /* now check if anything trimmed down */
390  if( conv.lgIonStageTrimed )
391  {
392  /* something was trimmed down, so say that ionization not yet stable */
393  /* say that ionization has not converged, secondaries changed by too much */
394  conv.setConvIonizFail( "IonTrimmed", 0.0, 0.0 );
395  }
396 
397  /* reevaluate advective terms if turned on */
398  if( dynamics.lgAdvection )
399  DynaIonize();
400 
401  /* evaluate Compton heating, bound E Compton, cosmic rays */
402  highen();
403 
404  // Depends on dense.eden, phycon.te and trimming level of H, He
406 
407  iso_update_rates( );
408 
409  long ionLowCache[LIMELM], ionHighCache[LIMELM];
410  for( long nelem=ipHYDROGEN; nelem<LIMELM; nelem++ )
411  {
412  if( dense.lgSetIoniz[nelem] )
413  {
414  dense.IonLow[nelem] = 0;
415  dense.IonHigh[nelem] = nelem + 1;
416  while( dense.SetIoniz[nelem][dense.IonLow[nelem]] == 0. )
417  ++dense.IonLow[nelem];
418  while( dense.SetIoniz[nelem][dense.IonHigh[nelem]] == 0. )
419  --dense.IonHigh[nelem];
420  }
421  ionLowCache[nelem] = dense.IonLow[nelem];
422  ionHighCache[nelem] = dense.IonHigh[nelem];
423  }
424 
425  /* >>chng 04 feb 15, add loop over ionization until converged. Non-convergence
426  * in this case means ionization ladder pop changed, probably because of way
427  * that Auger ejection is treated - loop exits when conditions tested at end are met */
429  loop_ion = 0;
430  do
431  {
434 
435  /* set the convergence flag to true,
436  * if anything changes in ConvBase, it will be set false */
437  if( loop_ion )
439 
440  /* charge transfer evaluation needs to be here so that same rate
441  * coefficient used for H ion and other recombination */
442  /* fill in master charge transfer array, and zero out some arrays that track effects */
443 
444  ChargTranEval();
445 
446  /* find grain temperature, charge, and gas heating rate */
447  /* >>chng 04 apr 15, moved here from after call to HeLike(), PvH */
448  GrainDrive();
449 
450  /* evaluate Compton heating, bound E Compton, cosmic rays */
451  highen();
452 
453  /* find corrections for three-body rec - collisional ionization */
454  atmdat_3body();
455 
456  /* update UTA inner-shell ionization rates */
457  UpdateUTAs();
458 
460 
461  /* evaluate molecular hydrogen level populations */
462  for( diatom_iter diatom = diatoms.begin(); diatom != diatoms.end(); ++diatom )
463  {
464  bool lgPopsConverged = true;
465  double old_val, new_val;
466  (*diatom)->H2_LevelPops( lgPopsConverged, old_val, new_val );
467  if( !lgPopsConverged )
468  {
469  conv.setConvIonizFail( "H2 pops", old_val, new_val);
470  }
471  }
472 
474 
475  long ion_loop = 0;
476  const int nconv = 3;
477  double xIonDense0[nconv][LIMELM][LIMELM+1];
478  bool lgShortCircuit = false;
479  for( ion_loop=0; ion_loop<nconv && !lgShortCircuit; ++ion_loop)
480  {
482  for (long nelem = ipHYDROGEN; nelem < LIMELM; ++nelem)
483  {
484  for (long ion = 0; ion <= nelem+1; ++ion)
485  {
486  xIonDense0[ion_loop][nelem][ion] = dense.xIonDense[nelem][ion];
487  }
488  }
489 
490  double netion = 0.0;
491  for( long nelem=ipHYDROGEN; nelem<LIMELM; nelem++ )
492  {
493  if (!dense.lgElmtOn[nelem])
494  continue;
495 
496  ASSERT(dense.IonLow[nelem] >= ionLowCache[nelem]);
497  ASSERT(dense.IonHigh[nelem] <= ionHighCache[nelem]);
498  ion_wrapper( nelem );
499  if (nelem == ipHYDROGEN || nelem == ipOXYGEN)
500  {
501  double hion =
503  iso_sp[ipH_LIKE][ipHYDROGEN].st[0].Pop()*
508  if (nelem == ipHYDROGEN)
509  netion += hion;
510  else
511  netion -= hion;
512  }
513 
514  if ( conv.lgUpdateCouplings )
516  }
517  if (dense.lgElmtOn[ipHYDROGEN] && dense.lgElmtOn[ipOXYGEN] && ion_loop == 1)
518  {
519  // Comparison rate is whether error is either a small fraction of the minimum ionization rate,
520  // or a tighter check on whether the fluxes are balanced as well as is feasible numerically
521  double ion_cmp = MAX2(0.01*MIN2(ionbal.RateIonizTot(ipHYDROGEN,0), ionbal.RateIonizTot(ipOXYGEN,0)),
524 
525  if (fabs(netion) > ion_cmp &&
527  1e-8*iso_sp[ipH_LIKE][ipHYDROGEN].st[0].Pop()*dense.xIonDense[ipOXYGEN][0] )
528  {
529  conv.setConvIonizFail( "OH CX inconsistency" , ion_cmp, netion);
530  }
531  }
532 
533  // If not going to end anyhow, check whether changes were small
534  bool lgCanShortCircuit = (ion_loop+1 < nconv);
535  for( long nelem=ipHYDROGEN; nelem<LIMELM && lgCanShortCircuit; ++nelem )
536  {
537  if (!dense.lgElmtOn[nelem])
538  continue;
539  for (long ion = dense.IonLow[nelem];
540  ion <= dense.IonHigh[nelem]; ++ion)
541  {
542  double x0 = xIonDense0[ion_loop][nelem][ion];
543  double x1 = dense.xIonDense[nelem][ion];
544  if (fabs(x0-x1) > 1e-6*(x0+x1))
545  {
546  lgCanShortCircuit = false;
547  break;
548  }
549  }
550  }
551  lgShortCircuit = lgCanShortCircuit;
552  }
553 
554  if (!lgShortCircuit)
555  {
556  // Apply convergence acceleration
557  for (long nelem = ipHYDROGEN; nelem < LIMELM; ++nelem)
558  {
559  if (!dense.lgElmtOn[nelem])
560  continue;
561  double tot0 = 0., tot1 = 0.;
562  double xIonNew[LIMELM+1];
563  for (long ion = 0; ion <= nelem+1; ++ion)
564  {
565  double x0 = xIonDense0[nconv-2][nelem][ion];
566  double x1 = xIonDense0[nconv-1][nelem][ion];
567  double x2 = dense.xIonDense[nelem][ion];
568  xIonNew[ion] = x2;
569  tot0 += x2;
570  // Richardson extrapolation formula to accelerate convergence
571  // Assumes convergence to x^ is geometric, i.e.
572  // x_i = x^ + a d^i
573 
574  double extstep = 0.,predict=x2,
575  step0 = x1-x0, step1 = x2-x1, abs1 = fabs(step1);
576  // Protect against roundoff/noise in inner solver
577  if ( abs1 > 1000.0*((double)DBL_EPSILON)*x2 )
578  {
579  double denom = fabs(step1-step0);
580  double sgn = (step1*step0 > 0)? 1.0 : -1.0;
581  // Greatest acceleration allowed is MAXACC*latest step length
582  // Can we do better than static tuning this parameter?
583  const double MAXACC=100.0;
584  double extfac = 1.0/(denom/abs1 + 1.0/MAXACC);
585  extstep = sgn*extfac*step1;
586  //extstep = sgn*MIN2(extfac*step1,0.01*x2);
587  predict = x2+extstep;
588  if (predict > 0.0)
589  xIonNew[ion] = predict;
590  }
591  if ( 0 )
592  //if ( nelem == ipHYDROGEN || (nelem == ipIRON && ion <=2 ) )
593  if ( (nelem == ipNICKEL && ion <=2 ) )
594  fprintf(ioQQQ,"Extrap %3ld %3ld %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g\n",
595  nelem,ion,
596  x0,x0-xIonDense0[nconv-3][nelem][ion],x1-x0,x2-x1,extstep,predict);
597  tot1 += xIonNew[ion];
598  }
599  if ( tot1 > SMALLFLOAT )
600  {
601  double scal = tot0/tot1;
602  for (long ion = 0; ion <= nelem+1; ++ion)
603  {
604  dense.xIonDense[nelem][ion] = scal*xIonNew[ion];
605  }
606  for ( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
607  {
608  double renorm;
609  iso_renorm(nelem, ipISO, renorm);
610  }
611  }
612  }
613 
614  bool lgPostExtrapSolve = true;
615  if (lgPostExtrapSolve)
616  {
617  for (long nelem = ipHYDROGEN; nelem < LIMELM; ++nelem)
618  {
619  if (!dense.lgElmtOn[nelem])
620  continue;
621  ion_wrapper( nelem );
622  }
623  }
624  }
626 
627  /*>>chng 04 may 09, add option to abort here, inspired by H2 pop failures
628  * which cascaded downstream if we did not abort */
629  /* return if one of above solvers has declared abort condition */
630  if( lgAbort )
631  {
632  ++conv.nTotalIoniz;
633  return 1;
634  }
635 
637 
638  /* drive chemistry network*/
639  mole_drive();
640 
642 
643  /* all elements have now had ionization reevaluated - in some cases we may have upset
644  * the ionization that was forced with an "element ionization" command - here we will
645  * re-impose that set ionization */
646  /* >>chng 04 oct 13, add this logic */
647  for( long nelem=ipHYDROGEN; nelem < LIMELM; nelem++ )
648  {
649  if( dense.lgSetIoniz[nelem] )
650  {
651  dense.IonLow[nelem] = 0;
652  dense.IonHigh[nelem] = nelem + 1;
653  while( dense.SetIoniz[nelem][dense.IonLow[nelem]] == 0. )
654  ++dense.IonLow[nelem];
655  while( dense.SetIoniz[nelem][dense.IonHigh[nelem]] == 0. )
656  --dense.IonHigh[nelem];
657  }
658  }
659 
660  /* redo ct ion rate for reasons now unclear */
661  ChargTranEval();
662 
663  /* lgIonizConverg is a function to check whether ionization has converged
664  * check whether ionization changed by more than relative error
665  * given by second number */
666  /* >>chng 04 feb 14, loop over all elements rather than just a few */
667  lgIonizConverg(loop_ion, conv.IonizErrorAllowed , false );
668 
669  if( deut.lgElmtOn )
670  {
671  static double OldDeut[2] = {0., 0.};
672  for( long ion=0; ion<2; ++ion )
673  {
674  if( fabs(deut.xIonDense[ion] - OldDeut[ion] ) > 0.2*conv.IonizErrorAllowed*fabs(OldDeut[ion]) )
675  {
676  conv.setConvIonizFail( "D ion" , OldDeut[ion], deut.xIonDense[ion]);
677  }
678  OldDeut[ion] = deut.xIonDense[ion];
679  }
680  }
681 
682  if( fabs(EdenTrue_old - dense.EdenTrue) > conv.EdenErrorAllowed/2.*fabs(dense.EdenTrue) )
683  {
684  conv.setConvIonizFail( "EdTr cng" , EdenTrue_old, dense.EdenTrue);
685  }
686 
687  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
688  {
689  for( long nelem=ipISO; nelem<LIMELM; ++nelem )
690  {
691  lgStatesConserved( nelem, nelem-ipISO, iso_sp[ipISO][nelem].st, iso_sp[ipISO][nelem].numLevels_local, 1e-3f, loop_ion );
692  }
693  }
694 
695  if( trace.nTrConvg>=4 )
696  {
697  /* trace ionization */
698  fprintf( ioQQQ,
699  " ConvBase4 ionization driver loop_ion %li converged? %c reason not converged %s\n" ,
700  loop_ion ,
701  TorF( conv.lgConvIoniz()) ,
702  conv.chConvIoniz() );
703  }
704 
705  ++loop_ion;
706  }
707  /* loop is not converged, less than loop limit, and we are reevaluating */
708  while( !conv.lgConvIoniz() && loop_ion < LOOP_ION_LIMIT && rfield.lgIonizReevaluate);
709 
710  if( conv.lgConvIoniz() )
712 
713  /* >>chng 05 oct 29, move CT heating here from heat_sum since this sometimes contributes
714  * cooling rather than heat and so needs to be sorted out before either heating or cooling
715  * are derived first find net heating - */
717  /* net is cooling if negative */
720 
721  /* get total cooling, thermal.ctot = does not occur since passes as pointer. This can add heat.
722  * it calls coolSum at end to sum up the total cooling */
724 
725  /* get total heating rate - first save old quantities to check how much it changes */
726  HeatOld = thermal.htot;
727 
728  /* HeatSum will update ElecFrac,
729  * secondary electron ionization and excitation efficiencies,
730  * and sum up current secondary rates - remember old values before we enter */
731  SecondOld = secondaries.csupra[ipHYDROGEN][0];
732 
733  /* update the total heating - it was all set to zero in HeatZero at top of this routine,
734  * occurs before secondaries bit below, since this updates electron fracs */
735  HeatSum();
736 
737  /* test whether we can just set the rate to the new one, or whether we should
738  * take average and do it again. secondaries.sec2total was set in hydrogenic, and
739  * is ratio of secondary to total hydrogen destruction rates */
740  /* >>chng 02 nov 20, add test on size of csupra - primal had very close to underflow */
742  fabs( 1. - SecondOld/SDIV(secondaries.csupra[ipHYDROGEN][0]) ) > 0.1 &&
743  SecondOld > 0. && secondaries.csupra[ipHYDROGEN][0] > 0.)
744  {
745  /* say that ionization has not converged, secondaries changed by too much */
746  conv.setConvIonizFail( "SecIonRate", SecondOld,
748  }
749 
750 # if 0
751  static realnum hminus_old=0.;
752  /* >>chng 04 apr 15, add this convergence test */
753  if( conv.nTotalIoniz )
754  {
755  realnum hminus_den = findspecieslocal("H-")->den;
756  if( fabs( hminus_old-hminus_den ) > fabs( hminus_den * conv.EdenErrorAllowed ) )
757  {
758  conv.setConvIonizFail( "Big H- chn", hminus_old, hminus_den );
759  }
760  hminus_old = hminus_den;
761  }
762 # endif
763 
764  if( HeatOld > 0. && !thermal.lgTemperatureConstant )
765  {
766  /* check if heating has converged - tolerance is final match */
767  if( fabs(1.-thermal.htot/HeatOld) > conv.HeatCoolRelErrorAllowed*.5 )
768  {
769  conv.setConvIonizFail( "Big d Heat", HeatOld, thermal.htot);
770  }
771  }
772 
773  /* abort flag may have already been set - if so bail */
774  if( lgAbort )
775  {
776 
777  return 1;
778  }
779 
780  /* evaluate current opacities
781  * rfield.lgOpacityReevaluate normally true,
782  * set false with no opacity reevaluate command, an option to only
783  * evaluate opacity one time per zone */
785  OpacityAddTotal();
786 
787  /* >>chng 02 jun 11, call even first time that this routine is called -
788  * this seemed to help convergence */
789 
790  /* do OTS rates for all lines and all continua since
791  * we now have ionization balance of all species. Note that this is not
792  * entirely self-consistent, since destruction probabilities here are not the same as
793  * the ones used in the model atoms. Problems?? if near convergence
794  * then should be nearly identical */
796  conv.lgIonStageTrimed || conv.lgSearch || nzone!=nzoneOTS )
797  {
798  RT_OTS();
799  nzoneOTS = nzone;
800 
801  /* remember old ots rates */
802  OldSumOTS[0] = OldSumOTS[1];
803  OldSumOTS[1] = SumOTS;
804  /*fprintf(ioQQQ," calling RT_OTS zone %.2f SumOTS is %.2e\n",fnzone,SumOTS);*/
805 
806  /* now update several components of the continuum, this only happens after
807  * we have gone through entire solution for this zone at least one time.
808  * there can be wild ots oscillation on first call */
809  /* the rel change of 0.2 was chosen by running hizqso - smaller increased
810  * itrzn but larger did not further decrease it. */
811  RT_OTS_Update(&SumOTS);
812  /*fprintf(ioQQQ,"RT_OTS_Updateee\t%.3f\t%.2e\t%.2e\n", fnzone,SumOTS , OldSumOTS[1] );*/
813  }
814  else
815  SumOTS = 0.;
816 
817  /* now check whether the ots rates changed */
818  if( SumOTS> 0. )
819  {
820  /* the ots rate must be converged to the error in the electron density */
821  /* how fine should this be converged?? originally had above, 10%, but take
822  * smaller ratio?? */
823  if( fabs(1.-OldSumOTS[1]/SumOTS) > conv.EdenErrorAllowed )
824  {
825  /* this branch, ionization not converged due to large change in ots rates.
826  * check whether ots rates are oscillating, if loopi > 1 so we have enough info*/
827  if( loopi > 1 )
828  {
829  /* here we have three values, are they changing sign? */
830  if( (OldSumOTS[0]-OldSumOTS[1]) * ( OldSumOTS[1] - SumOTS ) < 0. )
831  {
832  /* ots rates are oscillating */
833  conv.lgOscilOTS = true;
834  }
835  }
836 
837  conv.setConvIonizFail( "OTSRatChng" , OldSumOTS[1], SumOTS);
838  }
839 
840  /* produce info on the ots fields if either "trace ots" or
841  * "trace convergence xxx ots " was entered */
842  if( ( trace.lgTrace && trace.lgOTSBug ) ||
843  ( trace.nTrConvg && trace.lgOTSBug ) )
844  {
845  RT_OTS_PrtRate(SumOTS*0.05 , 'b' );
846  }
847  /*fprintf(ioQQQ,"DEBUG opac\t%.2f\t%.3e\t%.3e\n",fnzone,
848  dense.xIonDense[ipNICKEL][0] ,
849  dense.xIonDense[ipZINC][0] );*/
850  {
851  /* DEBUG OTS rates - turn this on to debug line, continuum or both rates */
852  enum {DEBUG_LOC=false};
853  if( DEBUG_LOC && (nzone>110) )
854  {
855 # if 0
856 # include "lines_service.h"
857  DumpLine( &iso_sp[ipH_LIKE][ipHYDROGEN].trans(2,0) );
858 # endif
859  /* last par 'l' for line, 'c' for continua, 'b' for both,
860  * the numbers printed are:
861  * cell i, [i], so 1 less than ipoint
862  * anu[i],
863  * otslin[i],
864  * opacity_abs[i],
865  * otslin[i]*opacity_abs[i],
866  * rfield.chLineLabel[i] ,
867  * rfield.line_count[i] */
868  }
869  }
870  }
871  {
872  /* DEBUG OTS rates - turn this on to debug line, continuum or both rates */
873  enum {DEBUG_LOC=false};
874  if( DEBUG_LOC && (nzone>200) )
875  {
876  fprintf(ioQQQ,"debug otsss\t%li\t%.3e\t%.3e\t%.3e\n",
877  nzone,
878  iso_sp[0][1].trans(15,3).Emis().ots(),
879  TauLines[26].Emis().ots(),
880  opac.opacity_abs[2069]);
881  }
882  }
883 
884  /* option to print OTS continuum with TRACE OTS */
885  if( trace.lgTrace && trace.lgOTSBug )
886  {
887  /* find ots rates here, so we only print fraction of it,
888  * SumOTS is both line and continuum contributing to ots, and is multiplied by opacity */
889  /* number is weakest rate to print */
890  RT_OTS_PrtRate(SumOTS*0.05 , 'b' );
891  }
892 
893  // all RT routines called
894  RT_line_all( );
895 
896  /* >>chng 01 mar 16, evaluate pressure here since changing and other values needed */
897  /* reevaluate pressure */
898  /* this sets values of pressure.PresTotlCurr, also calls tfidle */
899  PresTotCurrent();
900 
902 
903  /* update some counters that keep track of how many times this routine
904  * has been called */
905 
906  if( trace.lgTrace )
907  {
908  fprintf( ioQQQ,
909  " ConvBase return. fnzone %.2f nPres2Ioniz %li Te:%.3e HI:%.3e HII:%.3e H2:%.3e Ne:%.3e htot:%.3e CSUP:%.2e Conv?%c reason:%s\n",
910  fnzone,
912  phycon.te,
915  hmi.H2_total,
916  dense.eden,
917  thermal.htot,
919  TorF(conv.lgConvIoniz()) ,
920  conv.chConvIoniz());
921  }
922 
923  /* this counts number of times we are called by ConvPresTempEdenIoniz,
924  * number of calls in this zone so first call is zero
925  * reset to zero each time ConvPresTempEdenIoniz is called */
926  ++conv.nPres2Ioniz;
927 
928  /* this is abort option set with SET PRESIONIZ command,
929  * test on nzone since init can take many iterations
930  * this is seldom used except in special cases */
931  if( conv.nPres2Ioniz > conv.limPres2Ioniz && nzone > 0)
932  {
933  fprintf(ioQQQ,"PROBLEM ConvBase sets lgAbort since nPres2Ioniz exceeds limPres2Ioniz. ");
934  fprintf(ioQQQ,"Their values are %li and %li.\n",conv.nPres2Ioniz , conv.limPres2Ioniz);
935  lgAbort = true;
936  return 1;
937  }
938 
939  /* various checks on the convergence of the current solution */
940  if( eden_sum() )
941  {
942  /* non-zero return indicates abort condition */
943  return 1;
944  }
945 
946  /* is electron density converged? */
948  if( fabs(EdenTrue_old - dense.EdenTrue) > fabs(dense.EdenTrue * conv.EdenErrorAllowed/2.) )
949  {
950  conv.setConvIonizFail( "eden chng", EdenTrue_old, dense.EdenTrue);
951  }
952 
953  /* check on molecular electron den */
954  if( fabs(EdenFromMolecOld - mole.elec) > fabs(dense.EdenTrue * conv.EdenErrorAllowed/2.) )
955  {
956  conv.setConvIonizFail( "edn chnCO", EdenFromMolecOld, dense.EdenTrue);
957  }
958 
959  if( gv.lgGrainElectrons )
960  {
961  /* check on grain electron den */
962  if( fabs(EdenFromGrainsOld - gv.TotalEden) > fabs(dense.EdenTrue * conv.EdenErrorAllowed/2.) )
963  {
964  conv.setConvIonizFail( "edn grn e", EdenFromGrainsOld, gv.TotalEden);
965  }
966 
967  /* check on sum of grain and molecular electron den - often two large numbers that cancel */
968  if( fabs( (EdenFromMolecOld-EdenFromGrainsOld) - (mole.elec-gv.TotalEden) ) >
969  fabs(dense.EdenTrue * conv.EdenErrorAllowed/4.) )
970  {
971  conv.setConvIonizFail( "edn mole-grn",
972  (EdenFromMolecOld-EdenFromGrainsOld),
973  (mole.elec-gv.TotalEden));
974  }
975  }
976 
977  /* check on heating and cooling if vary temp model
978  * >>chng 08 jul 01, over the code's entire history it had tested whether
979  * this is a constant temperature simulation and did not do this test if
980  * the thermal solution was not done. There are some cases where we do
981  * want to specify the temperature and then find the heating or cooling -
982  * this is done in calculations of cooling curves for instance. With this
983  * change the heating/cooling are converged even in a constant temperature
984  * sim. this does make CT sims run more slowly but with greater accuracy
985  * if heating or cooling is reported */
987  {
988  if( fabs(HeatingOld - thermal.htot)/thermal.htot > conv.HeatCoolRelErrorAllowed/2. )
989  {
990  conv.setConvIonizFail( "heat chg", HeatingOld, thermal.htot);
991  }
992 
993  if( fabs(CoolingOld - thermal.ctot)/thermal.ctot > conv.HeatCoolRelErrorAllowed/2. )
994  {
995  conv.setConvIonizFail( "cool chg", CoolingOld, thermal.ctot);
996  }
997  }
998 
999  /* check whether molecular abundances are stable */
1000  for( long i=0; i < mole_global.num_calc; ++i )
1001  {
1002  // done relative to total nuclei density so that we can do pure metal plasmas.
1003  if( fabs(mole.species[i].den-mole_save[i])/dense.xNucleiTotal-1. >
1005  {
1006  char chConvIoniz[INPUT_LINE_LENGTH];
1007  sprintf( chConvIoniz, "ch %-4.4s",mole_global.list[i]->label.c_str() );
1008  conv.setConvIonizFail( chConvIoniz,
1009  mole_save[i]/dense.xNucleiTotal,
1010  mole.species[i].den/dense.xNucleiTotal);
1011  }
1012  }
1013 
1014  /* >>chng 05 mar 26, add this convergence test - important for molecular or advective
1015  * sims since iso ion solver must sync up with chemistry */
1016  /* remember current ground state population - will check if converged */
1017  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
1018  {
1019  for( long nelem=ipISO; nelem<LIMELM;++nelem )
1020  {
1021  if( dense.lgElmtOn[nelem] )
1022  {
1023  /* only do this check for "significant" levels of ionization */
1024  /*lint -e644 var possibly not init */
1025  if( dense.xIonDense[nelem][nelem-ipISO]/dense.gas_phase[nelem] > 1e-5 )
1026  {
1027  if( fabs(iso_sp[ipISO][nelem].st[0].Pop()-save_iso_grnd[ipISO][nelem])/SDIV(iso_sp[ipISO][nelem].st[0].Pop())-1. >
1029  {
1030  char chConvIoniz[INPUT_LINE_LENGTH];
1031  sprintf( chConvIoniz,"iso %2li %2li",ipISO, nelem );
1032  conv.setConvIonizFail(chConvIoniz,
1033  save_iso_grnd[ipISO][nelem],
1034  iso_sp[ipISO][nelem].st[0].Pop());
1035  }
1036  }
1037  /*lint +e644 var possibly not init */
1038  }
1039  }
1040  }
1041 
1042  /* this counts how many times ConvBase has been called in this iteration,
1043  * located here at bottom of routine so that number is false on first
1044  * call, set to 0 in when iteration starts - used to create itr/zn
1045  * number in printout often used to tell whether this is the very
1046  * first attempt at solution in this iteration */
1047  ++conv.nTotalIoniz;
1048 
1049  /* first sweep is over if this is not search phase */
1050  if( !conv.lgSearch )
1051  conv.lgFirstSweepThisZone = false;
1052 
1053  /* this was set with STOP NTOTALIONIZ command - only a debugging aid
1054  * by default is zero so false */
1056  {
1057  /* non-zero return indicates abort condition */
1058  fprintf(ioQQQ , "ABORT flag set since STOP nTotalIoniz was set and reached.\n");
1059  return 1;
1060  }
1061 
1063  {
1065  {
1066  static int iter_punch=-1;
1067  if( iteration !=iter_punch )
1068  fprintf( save.ipTraceConvergeBase, "%s\n",save.chHashString );
1069  iter_punch = iteration;
1070  }
1071 
1072  fprintf( save.ipTraceConvergeBase,
1073  "%li\t%.4e\t%.4e\t%.4e\n",
1075  }
1076 
1077  return 0;
1078 }
1079 
1080 void UpdateUTAs( void )
1081 {
1082  DEBUG_ENTRY( "UpdateUTAs()" );
1083 
1084  /* only reevaluate this on first pass through on this zone */
1086  {
1087  /* inner shell ionization */
1088  for( long nelem=0; nelem< LIMELM; ++nelem )
1089  {
1090  for( long ion=0; ion<nelem+1; ++ion )
1091  {
1092  ionbal.UTA_ionize_rate[nelem][ion] = 0.;
1093  ionbal.UTA_heat_rate[nelem][ion] = 0.;
1094  }
1095  }
1096  /* inner shell ionization by UTA lines */
1097  /* this flag turned off with no UTA command */
1099  {
1100  for( long i=0; i < nUTA; ++i )
1101  {
1102  /* rateone is inverse lifetime of level against autoionization */
1103  double rateone = UTALines[i].Emis().pump() * UTALines[i].Emis().AutoIonizFrac();
1104  ionbal.UTA_ionize_rate[(*UTALines[i].Hi()).nelem()-1][(*UTALines[i].Hi()).IonStg()-1] += rateone;
1105  /* heating rate in erg atom-1 s-1 */
1106  ionbal.UTA_heat_rate[(*UTALines[i].Hi()).nelem()-1][(*UTALines[i].Hi()).IonStg()-1] += rateone*UTALines[i].Coll().heat();
1107  {
1108  /* DEBUG OTS rates - turn this on to debug line, continuum or both rates */
1109  /*@-redef@*/
1110  enum {DEBUG_LOC=false};
1111  /*@+redef@*/
1112  if( DEBUG_LOC /*&& UTALines[i].nelem==ipIRON+1 && (UTALines[i].IonStg==15||UTALines[i].IonStg==14)*/ )
1113  {
1114  fprintf(ioQQQ,"DEBUG UTA %3i %3i %.3f %.2e %.2e %.2e\n",
1115  (*UTALines[i].Hi()).nelem() , (*UTALines[i].Hi()).IonStg() , UTALines[i].WLAng() ,
1116  rateone, UTALines[i].Coll().heat(),
1117  UTALines[i].Coll().heat()*dense.xIonDense[(*UTALines[i].Hi()).nelem()-1][(*UTALines[i].Hi()).IonStg()-1] );
1118  }
1119  }
1120  }
1121  }
1122  }
1123 
1124  return;
1125 }
1126 
1128 {
1129  fixit(); // this routine needs to be enabled
1130  return true;
1131  DEBUG_ENTRY( "lgNetEdenSrcSmall()" );
1132 
1133  if( conv.lgSearch )
1134  return true;
1135  fixit(); // grain rates not well tested below
1136  if( gv.lgDustOn() )
1137  return true;
1138 
1139  // Check for consistency of explicit source and sink rates for
1140  // electrons with population derived from neutrality
1141  double ionsrc = 0., ionsnk = 0.;
1142  for( long nelem=0; nelem < LIMELM; ++nelem )
1143  {
1144  if( !dense.lgElmtOn[nelem] )
1145  continue;
1146  ionsrc += ionbal.elecsrc[nelem];
1147  ionsnk += ionbal.elecsnk[nelem];
1148  for( long ion_from = 0; ion_from <= nelem + 1; ++ion_from )
1149  {
1150  for( long ion_to = 0; ion_to <= nelem + 1; ++ion_to )
1151  {
1152  if( ion_to-ion_from > 0 )
1153  {
1154  ionsrc += gv.GrainChTrRate[nelem][ion_from][ion_to] *
1155  dense.xIonDense[nelem][ion_from] * (ion_to-ion_from);
1156  }
1157  else if( ion_to-ion_from < 0 )
1158  {
1159  ionsnk += gv.GrainChTrRate[nelem][ion_from][ion_to] *
1160  dense.xIonDense[nelem][ion_from] * (ion_from-ion_to);
1161  }
1162  }
1163  }
1164  }
1165  long ipMElec = findspecies("e-")->index;
1166  const double totsrc = ionsrc + mole.species[ipMElec].src;
1167  const double totsnk = ionsnk + mole.species[ipMElec].snk*dense.EdenTrue;
1168  const double diff = (totsrc - totsnk);
1169  const double ave = ( fabs(totsrc) + fabs(totsnk) )/2.;
1170  fixit(); // Need to tighten up e- population convergence criterion
1171  const double error_allowed = 0.05 * ave; //conv.EdenErrorAllowed * ave;
1172  if( fabs(diff) > error_allowed )
1173  {
1174  enum {DEBUG_LOC=false};
1175  if( DEBUG_LOC )
1176  {
1177  fprintf(ioQQQ,"PROBLEM large NetEdenSrc nzone %li\t%e\t%e\t%e\t%e\n",
1178  nzone,
1179  totsrc/SDIV(totsnk),
1180  dense.EdenTrue,
1181  ionsrc + mole.species[ipMElec].src,
1182  ionsnk + mole.species[ipMElec].snk*dense.EdenTrue);
1183  }
1184  conv.setConvIonizFail( "NetEdenSrc", diff, error_allowed);
1185  return false;
1186  }
1187  else
1188  return true;
1189 }
#define MIN2
Definition: cddefines.h:765
void ion_trim(long int nelem)
Definition: ion_trim.cpp:21
double RateIonizTot(long nelem, long ion)
Definition: ionbal.h:254
t_mole_global mole_global
Definition: mole.cpp:6
void RT_OTS_Update(double *SumOTS)
Definition: rt_ots.cpp:488
void GrainDrive(void)
Definition: grains.cpp:1591
void DumpLine(const TransitionProxy &t)
Definition: transition.cpp:100
t_atmdat atmdat
Definition: atmdat.cpp:6
t_thermal thermal
Definition: thermal.cpp:5
static double x2[63]
bool lgElmtOn
Definition: deuterium.h:19
double * opacity_abs
Definition: opacity.h:95
qList st
Definition: iso.h:453
double EdenErrorAllowed
Definition: conv.h:267
TransitionList UTALines("UTALines",&AnonStates)
double ** UTA_heat_rate
Definition: ionbal.h:172
bool lgGrainElectrons
Definition: grainvar.h:494
t_opac opac
Definition: opacity.cpp:5
int num_calc
Definition: mole.h:314
static double x1[83]
void mole_drive(void)
Definition: mole_drive.cpp:41
int ConvBase(long loopi)
Definition: conv_base.cpp:163
const realnum SMALLFLOAT
Definition: cpu.h:178
bool lgFirstSweepThisZone
Definition: conv.h:155
const int NISO
Definition: cddefines.h:265
void RT_line_all(void)
Definition: rt_line_all.cpp:26
char TorF(bool l)
Definition: cddefines.h:714
void RT_OTS_PrtRate(double weak, int chFlag)
Definition: rt_ots.cpp:712
const int ipOXYGEN
Definition: cddefines.h:316
#define MAX2
Definition: cddefines.h:786
int eden_sum(void)
Definition: eden_sum.cpp:18
double ctot
Definition: thermal.h:110
bool lgAdvection
Definition: dynamics.h:60
t_StopCalc StopCalc
Definition: stopcalc.cpp:5
t_conv conv
Definition: conv.cpp:5
STATIC bool lgNetEdenSrcSmall(void)
Definition: conv_base.cpp:1127
double elecsrc[LIMELM]
Definition: ionbal.h:251
double ChargTranSumHeat(void)
double char_tran_cool
Definition: thermal.h:146
#define LOOP_ION_LIMIT
long int limPres2Ioniz
Definition: conv.h:161
t_phycon phycon
Definition: phycon.cpp:6
void CoolEvaluate(double *tot)
Definition: cool_eval.cpp:45
void resetConvIoniz()
Definition: conv.h:100
char chHashString[INPUT_LINE_LENGTH]
Definition: save.h:295
t_dense dense
Definition: dense.cpp:24
double char_tran_heat
Definition: thermal.h:146
bool lgIonizReevaluate
Definition: rfield.h:128
FILE * ioQQQ
Definition: cddefines.cpp:7
molezone * findspecieslocal(const char buf[])
long int nzone
Definition: cddefines.cpp:14
bool lgConvIoniz() const
Definition: conv.h:115
void incrementCounter(const counter_type type)
Definition: conv.h:308
t_dynamics dynamics
Definition: dynamics.cpp:44
const int ipNICKEL
Definition: cddefines.h:336
void lgStatesConserved(long nelem, long ionStage, qList states, long numStates, realnum err_tol, long loop_ion)
Definition: dense.cpp:160
bool lgOscilOTS
Definition: conv.h:193
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:125
t_elementnames elementnames
Definition: elementnames.cpp:5
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:8
void PresTotCurrent(void)
bool lgIonStageTrimed
Definition: conv.h:189
void UpdateUTAs(void)
Definition: conv_base.cpp:1080
bool lgTemperatureConstant
Definition: thermal.h:32
long int iteration
Definition: cddefines.cpp:16
bool lgSearch
Definition: conv.h:175
t_trace trace
Definition: trace.cpp:5
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:816
void iso_collapsed_update(void)
Definition: iso_solve.cpp:27
const char * chConvIoniz() const
Definition: conv.h:119
realnum SetIoniz[LIMELM][LIMELM+1]
Definition: dense.h:154
t_ionbal ionbal
Definition: ionbal.cpp:5
double TotalEden
Definition: grainvar.h:528
FILE * ipTraceConvergeBase
Definition: save.h:342
double te_update
Definition: thermal.h:128
long int nPres2Ioniz
Definition: conv.h:152
realnum sec2total
Definition: secondaries.h:27
#define STATIC
Definition: cddefines.h:101
bool lgTrace
Definition: trace.h:12
t_mole_local mole
Definition: mole.cpp:7
molecule * findspecies(const char buf[])
t_rfield rfield
Definition: rfield.cpp:8
void DynaIonize(void)
Definition: dynamics.cpp:186
double ** UTA_ionize_rate
Definition: ionbal.h:170
long int IonHigh[LIMELM+1]
Definition: dense.h:120
bool lgInnerShellLine_on
Definition: ionbal.h:175
void OpacityAddTotal(void)
static double x0[83]
float realnum
Definition: cddefines.h:107
valarray< class molezone > species
Definition: mole.h:355
realnum IonizErrorAllowed
Definition: conv.h:280
realnum xNucleiTotal
Definition: dense.h:104
const int INPUT_LINE_LENGTH
Definition: cddefines.h:258
vector< diatomics * > diatoms
Definition: h2.cpp:8
void ion_recom_calculate(void)
bool lgElmtOn[LIMELM]
Definition: dense.h:146
int index
Definition: mole.h:169
int nTrConvg
Definition: trace.h:27
realnum HeatCoolRelErrorAllowed
Definition: conv.h:278
long int nTotalIonizStop
Definition: stopcalc.h:127
void iso_update_rates(void)
Definition: iso_solve.cpp:51
double xIonDense[2]
Definition: deuterium.h:21
long int nTotalIoniz
Definition: conv.h:166
char chElementSym[LIMELM][CHARS_ELEMENT_SYM]
Definition: elementnames.h:25
bool lgOpacStatic
Definition: opacity.h:140
realnum gas_phase[LIMELM]
Definition: dense.h:71
void mole_update_sources(void)
Definition: mole_drive.cpp:106
void SetDeuteriumIonization(const double &xNeutral, const double &xIonized)
Definition: deuterium.cpp:26
long int IonLow[LIMELM+1]
Definition: dense.h:119
#define ASSERT(exp)
Definition: cddefines.h:582
bool lgOpacityReevaluate
Definition: rfield.h:121
double htot
Definition: thermal.h:149
TransitionList TauLines("TauLines",&AnonStates)
const int ipH_LIKE
Definition: iso.h:62
const int LIMELM
Definition: cddefines.h:262
double elecsnk[LIMELM]
Definition: ionbal.h:251
double den
Definition: mole.h:396
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
const int ipHELIUM
Definition: cddefines.h:310
bool lgTraceConvergeBase
Definition: save.h:340
bool lgRedoStatic
Definition: opacity.h:147
double H2_total
Definition: hmi.h:16
bool lgUpdateCouplings
Definition: conv.h:259
t_deuterium deut
Definition: deuterium.cpp:8
double eden
Definition: dense.h:190
double EdenTrue
Definition: dense.h:221
void iso_renorm(long nelem, long ipISO, double &renorm)
Definition: iso_solve.cpp:272
double elec
Definition: mole.h:347
MoleculeList list
Definition: mole.h:317
void ion_wrapper(long nelem)
realnum ** csupra
Definition: secondaries.h:21
bool lgOTSBug
Definition: trace.h:103
sys_float SDIV(sys_float x)
Definition: cddefines.h:956
void setConvIonizFail(const char *reason, double oldval, double newval)
Definition: conv.h:107
void HeatZero(void)
Definition: heat_sum.cpp:928
long int nUTA
Definition: taulines.cpp:26
bool lgElemsConserved(void)
Definition: dense.cpp:99
GrainVar gv
Definition: grainvar.cpp:5
t_secondaries secondaries
Definition: secondaries.cpp:5
t_hmi hmi
Definition: hmi.cpp:5
bool lgTraceConvergeBaseHash
Definition: save.h:340
double fnzone
Definition: cddefines.cpp:15
void ChargTranEval(void)
double CharExcIonOf[NCX][LIMELM][LIMELM+1]
Definition: atmdat.h:152
t_save save
Definition: save.cpp:5
double te
Definition: phycon.h:11
void highen(void)
Definition: highen.cpp:21
void atmdat_3body(void)
bool lgDustOn() const
Definition: grainvar.h:471
const int ipHYDROGEN
Definition: cddefines.h:309
void fixit(void)
Definition: service.cpp:991
realnum GrainChTrRate[LIMELM][LIMELM+1][LIMELM+1]
Definition: grainvar.h:541
double CharExcRecTo[NCX][LIMELM][LIMELM+1]
Definition: atmdat.h:152
void RT_OTS(void)
Definition: rt_ots.cpp:39
bool lgSetIoniz[LIMELM]
Definition: dense.h:149
void HeatSum(void)
Definition: heat_sum.cpp:33
EmissionList & Emis()
Definition: transition.h:329
vector< diatomics * >::iterator diatom_iter
Definition: h2.h:13
bool lgAbort
Definition: cddefines.cpp:10