cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dynamics.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 /* DynaIterEnd called at end of iteration when advection is turned on */
4 /* DynaStartZone called at start of zone calculation when advection is turned on */
5 /* DynaEndZone called at end of zone calculation when advection is turned on */
6 /* DynaIonize, called from ionize to evaluate advective terms for current conditions */
7 /* DynaPresChngFactor, called from PressureChange to evaluate new density needed for
8  * current conditions and wind solution, returns ratio of new to old density */
9 /* timestep_next - find next time step in time dependent case */
10 /* DynaZero zero some dynamics variables, called from zero.c */
11 /* DynaCreateArrays allocate some space needed to save the dynamics structure variables,
12  * called from DynaCreateArrays */
13 /* DynaPrtZone - called to print zone results */
14 /* DynaSave save info related to advection */
15 /* DynaSave, save output for dynamics solutions */
16 /* ParseDynaTime parse the time command, called from ParseCommands */
17 /* ParseDynaWind parse the wind command, called from ParseCommands */
18 #include "cddefines.h"
19 #include "cddrive.h"
20 #include "struc.h"
21 #include "input.h"
22 #include "colden.h"
23 #include "radius.h"
24 #include "thirdparty.h"
25 #include "stopcalc.h"
26 #include "hextra.h"
27 #include "rfield.h"
28 #include "iterations.h"
29 #include "trace.h"
30 #include "conv.h"
31 #include "timesc.h"
32 #include "dense.h"
33 #include "mole.h"
34 #include "thermal.h"
35 #include "pressure.h"
36 #include "phycon.h"
37 #include "wind.h"
38 #include "hmi.h"
39 #include "iso.h"
40 #include "dynamics.h"
41 #include "cosmology.h"
42 #include "taulines.h"
43 #include "parser.h"
45 static int ipUpstream=-1,iphUpstream=-1,ipyUpstream=-1;
46 
47 /*
48  * >>chng 01 mar 16, incorporate advection within dynamical solutions
49  * this file contains the routines that incorporate effects of dynamics and advection upon the
50  * thermal and ionization solutions.
51  *
52  * This code was originally developed in March 2001 during
53  * a visit to UNAM Morelia, in collaboration with Robin Williams, Jane Arthur, and Will Henney.
54  * Development was continued by email, and in a meeting in July/Aug 2001 at U Cardiff
55  * Further development June 2002, UNAM Morelia (Cloudy and the Duendes Verdes)
56  */
57 
58 /* the interpolated upstream densities of all ionization stages,
59  * [element][ion] */
60 static double **UpstreamIon;
61 static double ***UpstreamStatesElem;
62 /* total abundance of each element per hydrogen */
63 static double *UpstreamElem;
64 
65 /* hydrogen molecules */
66 static double *Upstream_molecules;
67 
68 /* space to save continuum when time command is used
69 static realnum *dyna_flux_save;*/
70 
71 /* array of times and continuum values we will interpolate upon */
72 static double *time_elapsed_time ,
74  *time_dt,
78 #define NTIME 200
79 
80 /* number of time steps actually read in */
81 static long int nTime_flux=0;
82 
83 /* routine called at end of iteration to determine new step sizes */
84 STATIC void DynaNewStep(void);
85 
86 /* routine called at end of iteration to save values in previous iteration */
87 STATIC void DynaSaveLast(void);
88 
89 /* routine called to determine mass flux at given distance */
90 /* static realnum DynaFlux(double depth); */
91 
92 /* lookahead distance, as derived in DynaIterEnd */
93 static double Dyn_dr;
94 
95 /* advected work */
96 static double AdvecSpecificEnthalpy;
97 
98 /* HI ionization structure from previous iteration */
99 static realnum *Old_histr/*[NZLIM]*/ ,
100  /* Lyman continuum optical depth from previous iteration */
101  *Old_xLyman_depth/*[NZLIM]*/,
102  /* depth of position in previous iteration */
103  *Old_depth/*[NZLIM]*/,
104  /* old n_p density from previous iteration */
105  *Old_hiistr/*[NZLIM]*/,
106  /* old pressure from previous iteration */
107  *Old_pressure/*[NZLIM]*/,
108  /* H density - particles per unit vol */
109  *Old_density/*[NZLIM]*/ ,
110  /* density - total grams per unit vol */
111  *Old_DenMass/*[NZLIM]*/ ,
112  /* sum of enthalpy and kinetic energy per gram */
113  *EnthalpyDensity/*[NZLIM]*/,
114  /* old electron density from previous iteration */
115  *Old_ednstr/*[NZLIM]*/,
116  /* sum of enthalpy and kinetic energy per gram */
117  *Old_EnthalpyDensity/*[NZLIM]*/;
118 
120 
121 /* the ionization fractions from the previous iteration */
123 
124 /* the gas phase abundances from the previous iteration */
126 
127 /* the iso levels from the previous iteration */
129 
130 /* the number of zones that were saved in the previous iteration */
131 static long int nOld_zone;
132 
133 /*timestep_next - find next time step in time dependent case */
134 STATIC double timestep_next( void )
135 {
136  static double te_old=-1;
137  double timestep_Hp_temp , timestep_return;
138 
139  DEBUG_ENTRY( "timestep_next()" );
140 
141  timestep_return = dynamics.timestep;
142 
143  if( dynamics.lgRecom )
144  {
145  double te_new;
146  if( cdTemp(
147  /* four char string, null terminzed, giving the element name */
148  "hydr",
149  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number */
150  2 ,
151  /* will be temperature */
152  &te_new,
153  /* how to weight the average, must be "VOLUME" or "RADIUS" */
154  "VOLUME" ) )
155  TotalInsanity();
156 
157  if( te_old>0 )
158  {
159  double dTdStep = fabs(te_new-te_old)/te_new;
160  /* this is the change factor to get 0.1 frac change in mean temp */
161  double dT_factor = 0.04/SDIV(dTdStep);
162  dT_factor = MIN2( 2.0 , dT_factor );
163  dT_factor = MAX2( 0.01 , dT_factor );
164  timestep_Hp_temp = dynamics.timestep * dT_factor;
165  }
166  else
167  {
168  timestep_Hp_temp = -1.;
169  }
170  te_old = te_new;
171  if( timestep_Hp_temp > 0. )
172  timestep_return = timestep_Hp_temp;
173  }
174  else
175  {
176  timestep_return = dynamics.timestep_init;
177  }
178  fprintf(ioQQQ,"DEBUG timestep_next returns %.3e, old temp %.2e\n" , timestep_return, te_old );
179 
180  return( timestep_return );
181 }
182 
183 /* ============================================================================== */
184 /* DynaIonize, called from ConvBase to evaluate advective terms for current conditions,
185  * calculates terms to add to ionization balance equation */
186 void DynaIonize(void)
187 {
188  DEBUG_ENTRY( "DynaIonize()" );
189 
190  /* the time (s) needed for gas to move dynamics.Dyn_dr */
191  /* >>chng 02 dec 11 rjrw increase dynamics.dynamics.timestep when beyond end of previous zone, to allow -> eqm */
192  if( !dynamics.lgTimeDependentStatic )
193  {
194  /* in time dependent model dynamics.timestep only changes once at end of iteration
195  * and is constant across a model */
196  /* usual case - full dynamics */
197  dynamics.timestep = -Dyn_dr/wind.windv;
198  }
199  /* printf("%d %g %g %g %g\n",nzone,radius.depth,Dyn_dr,radius.depth-Old_depth[nOld_zone-1],dynamics.timestep); */
200 
202  if( nzone > 0 )
204 
205  /* do nothing on first iteration or when looking beyond previous iteration */
206  /* >>chng 05 jan 27, from hardwired "iteration < 2" to more general case,
207  * this is set with SET DYNAMICS RELAX command with the default of 2 */
208  //For advection cases, switch to local equilibrium when depth is outside
209  //the region of previous iteration.
210  //Possibly should limit range of dynamical sources further by adding Dyn_dr???
211  double depth = radius.depth;
212  if( iteration < dynamics.n_initial_relax+1 ||
213  ( ! dynamics.lgTimeDependentStatic &&
214  ( depth < 0 || depth > dynamics.oldFullDepth ) ) )
215  {
216  /* first iteration, return zero */
217  dynamics.Cool_r = 0.;
218  dynamics.Heat_v = 0.;
219  dynamics.dHeatdT = 0.;
220 
221  dynamics.Rate = 0.;
222 
223  for( long nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
224  {
225  for( long ion=0; ion<nelem+2; ++ion )
226  {
227  dynamics.Source[nelem][ion] = 0.;
228  }
229  }
230  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
231  {
232  for( long nelem=ipISO; nelem<LIMELM; ++nelem)
233  {
234  if( dense.lgElmtOn[nelem] )
235  {
236  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_local; ++level )
237  {
238  dynamics.StatesElem[nelem][nelem-ipISO][level] = 0.;
239  }
240  }
241  }
242  }
243  for( long mol=0;mol<mole_global.num_calc;mol++)
244  {
245  dynamics.molecules[mol] = 0.;
246  }
247  return;
248  }
249 
250  if( dynamics.lgTracePrint )
251  {
252  fprintf(ioQQQ,"workwork\t%li\t%.3e\t%.3e\t%.3e\n",
253  nzone,
256  5./2.*pressure.PresGasCurr
257  );
258  }
259 
260  /* net cooling due to advection */
261  /* >>chng 01 aug 01, removed hden from dilution, put back into here */
262  /* >>chng 01 sep 15, do not update this variable the very first time this routine
263  * is called at the new zone. */
264  dynamics.Cool_r = 1./dynamics.timestep*dynamics.lgCoolHeat;
265  dynamics.Heat_v = AdvecSpecificEnthalpy/dynamics.timestep*dynamics.lgCoolHeat;
266  dynamics.dHeatdT = 0.*dynamics.lgCoolHeat;
267 
268 # if 0
269  if( dynamics.lgTracePrint || nzone>17 && iteration == 10)
270  {
271  fprintf(ioQQQ,
272  "dynamics cool-heat\t%li\t%.3e\t%i\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\n",
273  nzone,
274  phycon.te,
275  dynamics.lgCoolHeat,
276  thermal.htot,
281  scalingDensity(),
282  dynamics.timestep);
283  }
284 # endif
285 
286  /* second or greater iteration, have advective terms */
287  /* this will evaluate advective terms for current physical conditions */
288 
289  /* the rate (s^-1) atoms drift in from upstream, a source term for the ground */
290 
291  /* dynamics.Hatom/dynamics.timestep is the source (cm^-3 s^-1) of neutrals,
292  normalized to (s^-1) by the next higher ionization state as for all
293  other recombination terms */
294 
295  /* dynamics.xIonDense[ipHYDROGEN][1]/dynamics.timestep is the sink (cm^-3 s^-1) of
296  ions, normalized to (s^-1) by the ionization state as for all other
297  ionization terms */
298 
299  dynamics.Rate = 1./dynamics.timestep;
300 
301  for( long mol=0;mol<mole_global.num_calc;mol++)
302  {
303  dynamics.molecules[mol] = Upstream_molecules[mol]*scalingDensity();
304  }
305 
306  for( long nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
307  {
308  if( dense.lgElmtOn[nelem] )
309  {
310  /* check that the total number of each element is conserved along the flow */
311  if(fabs(UpstreamElem[nelem]*scalingDensity() -dense.gas_phase[nelem])/dense.gas_phase[nelem]>=1e-3)
312  {
313  fprintf(ioQQQ,
314  "PROBLEM conservation error: zn %li elem %li upstream %.8e abund %.8e (up-ab)/up %.2e\n",
315  nzone ,
316  nelem,
317  UpstreamElem[nelem]*scalingDensity(),
318  dense.gas_phase[nelem] ,
319  (UpstreamElem[nelem]*scalingDensity()-dense.gas_phase[nelem]) /
320  (UpstreamElem[nelem]*scalingDensity()) );
321  }
322  /* ASSERT( fabs(UpstreamElem[nelem]*scalingDensity() -dense.gas_phase[nelem])/dense.gas_phase[nelem]<1e-3); */
323  for( long ion=0; ion<dense.IonLow[nelem]; ++ion )
324  {
325  dynamics.Source[nelem][ion] = 0.;
326  }
327  for( long ion=dense.IonLow[nelem]; ion<=dense.IonHigh[nelem]; ++ion )
328  {
329  /* Normalize to next higher state in current zone, except at first iteration
330  where upstream version may be a better estimate (required for
331  convergence in the small dynamics.timestep limit) */
332 
333  dynamics.Source[nelem][ion] =
334  /* UpstreamIon is ion number per unit hydrogen because dilution is 1/hden
335  * this forms the ratio of upstream atom over current ion, per dynamics.timestep,
336  * so Source has units cm-3 s-1 */
337  UpstreamIon[nelem][ion] * scalingDensity() / dynamics.timestep;
338 
339  }
340  for( long ion=dense.IonHigh[nelem]+1;ion<nelem+2; ++ion )
341  {
342  dynamics.Source[nelem][ion] = 0.;
343  dynamics.Source[nelem][dense.IonHigh[nelem]] +=
344  UpstreamIon[nelem][ion] * scalingDensity() / dynamics.timestep;
345  }
346  }
347  }
348 
349  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
350  {
351  for( long nelem=ipISO; nelem<LIMELM; ++nelem)
352  {
353  if( dense.lgElmtOn[nelem] )
354  {
355  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_local; ++level )
356  {
357  dynamics.StatesElem[nelem][nelem-ipISO][level] =
358  UpstreamStatesElem[nelem][nelem-ipISO][level] * scalingDensity() / dynamics.timestep;
359  }
360  }
361  }
362  }
363 
364 # if 0
365  fprintf(ioQQQ,"dynamiccc\t%li\t%.2e\t%.2e\t%.2e\t%.2e\n",
366  nzone,
367  dynamics.Rate,
368  dynamics.Source[ipHYDROGEN][0],
369  dynamics.Rate,
370  dynamics.Source[ipCARBON][3]);
371 # endif
372 #if 0
373  long nelem = ipCARBON;
374  long ion = 3;
375  /*if( nzone > 160 && iteration > 1 )*/
376  fprintf(ioQQQ,"dynaionizeeee\t%li\t%i\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\n",
377  nzone,
378  ipUpstream,
379  radius.depth ,
381  dense.xIonDense[nelem][ion],
382  UpstreamIon[nelem][ion]* scalingDensity(),
383  Old_xIonDense[ipUpstream][nelem][ion] ,
384  dense.xIonDense[nelem][ion+1],
385  UpstreamIon[nelem][ion+1]* scalingDensity(),
386  Old_xIonDense[ipUpstream][nelem][ion+1] ,
387  dynamics.timestep,
388  dynamics.Source[nelem][ion]
389  );
390 #endif
391  if( dynamics.lgTracePrint )
392  {
393  fprintf(ioQQQ," DynaIonize, %4li photo=%.2e , H recom= %.2e \n",
394  nzone,dynamics.Rate , dynamics.Source[0][0] );
395  }
396  return;
397 }
398 
399 /* ============================================================================== */
400 /* DynaStartZone called at start of zone calculation when advection is turned on */
401 void DynaStartZone(void)
402 {
403  /* this routine is called at the start of a zone calculation, by ZoneStart:
404  *
405  * it sets deduced variables to zero if first iteration,
406  *
407  * if upstream depth is is outside the computed structure on previous iteration,
408  * return value at shielded face
409  *
410  * Also calculates discretization_error, an estimate of the accuracy of the source terms.
411  *
412  * */
413 
414  /* this is index of upstream cell in structure stored from previous iteration */
415  double upstream, dilution, dilutionleft, dilutionright, frac_next;
416 
417  /* Properties for cell half as far upstream, used to converge dynamics.timestep */
418  double hupstream, hnextfrac=-BIGFLOAT, hion, hmol, hiso;
419 
420  /* Properties for cell at present depth, used to converge dynamics.timestep */
421  double ynextfrac=-BIGFLOAT, yion, ymol, yiso;
422 
423  long int nelem , ion, mol;
424 
425  DEBUG_ENTRY( "DynaStartZone()" );
426 
427  /* do nothing on first iteration */
428  if( iteration < 2 )
429  {
430  dynamics.Upstream_density = 0.;
432  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
433  {
434  for( ion=0; ion<nelem+2; ++ion )
435  {
436  UpstreamIon[nelem][ion] = 0.;
437  }
438  }
439  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
440  {
441  for( nelem=ipISO; nelem<LIMELM; ++nelem)
442  {
443  if( dense.lgElmtOn[nelem] )
444  {
445  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
446  {
447  UpstreamStatesElem[nelem][nelem-ipISO][level] = 0.;
448  }
449  }
450  }
451  }
452  /* hydrogen molecules */
453  for(mol=0; mol<mole_global.num_calc;mol++)
454  {
455  Upstream_molecules[mol] = 0;
456  }
457 
458  ipUpstream = -1;
459  iphUpstream = -1;
460  ipyUpstream = -1;
461  return;
462  }
463 
464  /* radius.depth is distance from illuminated face of cloud to outer edge of
465  * current zone, which has thickness radius.drad */
466 
467  /* find where the down stream point is, in previous iteration: we
468  * are looking for point where gas in current cell was in previous
469  * iteration */
470 
471  /* true, both advection and wind solution */
472  /* don't interpolate to the illuminated side of the first cell */
473  upstream = MAX2(Old_depth[0] , radius.depth + Dyn_dr);
474  hupstream = 0.5*(radius.depth + upstream);
475 
476  /* now locate upstream point in previous stored structure,
477  * will be at the same point or higher than we found previously */
478  while( (Old_depth[ipUpstream+1] < upstream ) &&
479  ( ipUpstream < nOld_zone-1 ) )
480  {
481  ++ipUpstream;
482  }
483  ASSERT( ipUpstream <= nOld_zone-1 );
484 
485  /* above loop will give ipUpstream == nOld_zone-1 if computed structure has been overrun */
486 
488  {
489  /* we have not overrun radius scale of previous iteration */
490  frac_next = ( upstream - Old_depth[ipUpstream])/
491  (Old_depth[ipUpstream+1] - Old_depth[ipUpstream]);
492  dynamics.Upstream_density = (realnum)(Old_density[ipUpstream] +
493  (Old_density[ipUpstream+1] - Old_density[ipUpstream])*
494  frac_next);
495  dilutionleft = 1./Old_density[ipUpstream];
496  dilutionright = 1./Old_density[ipUpstream+1];
497 
498  /* fractional changes in density from passive advection */
499  /* >>chng 01 May 02 rjrw: use hden for dilution */
500  /* >>chng 01 aug 01, remove hden here, put back into vars when used in DynaIonize */
501  dilution = 1./dynamics.Upstream_density;
502 
503  /* the advected enthalphy */
505  (Old_EnthalpyDensity[ipUpstream+1]*dilutionright - Old_EnthalpyDensity[ipUpstream]*dilutionleft)*
506  frac_next);
507 
508  ASSERT( Old_depth[ipUpstream] <= upstream && upstream <= Old_depth[ipUpstream+1] );
509 
510  // we have a mix of realnum and double here, so make sure realnum is used for the test...
511  realnum lo = (realnum)(Old_EnthalpyDensity[ipUpstream]*dilutionleft);
513  realnum hi = (realnum)(Old_EnthalpyDensity[ipUpstream+1]*dilutionright);
514  if( ! fp_bound(lo,x,hi) )
515  {
516  fprintf(ioQQQ,"PROBLEM interpolated enthalpy density is not within range %.16e\t%.16e\t%.16e\t%e\t%e\n",
517  lo, x, hi, (hi-x)/(hi-lo), (x-lo)/(hi-lo));
518  }
519 
520  ASSERT( fp_bound(lo,x,hi) );
521 
522  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
523  {
524  UpstreamElem[nelem] = 0.;
525  for( ion=0; ion<nelem+2; ++ion )
526  {
527  /* Easier to bring out the division by the old hydrogen
528  * density rather than putting in dilution and then
529  * looking for how dilution is defined. The code is
530  * essentially equivalent, but slower */
531  /* UpstreamIon is ion number per unit material (measured
532  * as defined in scalingdensity()), at the upstream
533  * position */
534  UpstreamIon[nelem][ion] =
536  (Old_xIonDense[ipUpstream+1][nelem][ion]/Old_density[ipUpstream+1] -
538  frac_next;
539 
540  UpstreamElem[nelem] += UpstreamIon[nelem][ion];
541  }
542  }
543 
544  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
545  {
546  for( nelem=ipISO; nelem<LIMELM; ++nelem)
547  {
548  if( dense.lgElmtOn[nelem] )
549  {
550  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
551  {
552  UpstreamStatesElem[nelem][nelem-ipISO][level] =
553  Old_StatesElem[ipUpstream][nelem][nelem-ipISO][level]/Old_density[ipUpstream] +
554  (Old_StatesElem[ipUpstream+1][nelem][nelem-ipISO][level]/Old_density[ipUpstream+1] -
555  Old_StatesElem[ipUpstream][nelem][nelem-ipISO][level]/Old_density[ipUpstream])*
556  frac_next;
557  /* check for NaN */
558  ASSERT( !isnan( UpstreamStatesElem[nelem][nelem-ipISO][level] ) );
559  }
560  }
561  }
562  }
563 
564  for(mol=0;mol<mole_global.num_calc;mol++)
565  {
567  (Old_molecules[ipUpstream+1][mol]/Old_density[ipUpstream+1] -
569  frac_next;
570  /* Externally represented species are already counted in UpstreamElem */
571  if(mole.species[mol].location == NULL && mole_global.list[mol]->parentLabel.empty())
572  {
573  for(molecule::nAtomsMap::iterator atom= mole_global.list[mol]->nAtom.begin();
574  atom != mole_global.list[mol]->nAtom.end(); ++atom)
575  {
576  UpstreamElem[atom->first->el->Z-1] +=
577  Upstream_molecules[mol]*atom->second;
578  }
579  }
580  }
581  }
582  else
583  {
584  /* SPECIAL CASE - we have overrun the previous iteration's radius */
585  long ipBound = ipUpstream;
586  if (ipBound == -1)
587  ipBound = 0;
588  dynamics.Upstream_density = Old_density[ipBound];
589  /* fractional changes in density from passive advection */
590  dilution = 1./dynamics.Upstream_density;
591  /* AdvecSpecificEnthalpy enters as heat term */
593  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
594  {
595  UpstreamElem[nelem] = 0.;
596  for( ion=0; ion<nelem+2; ++ion )
597  {
598  /* UpstreamIon is ion number per unit hydrogen */
599  UpstreamIon[nelem][ion] =
600  Old_xIonDense[ipBound][nelem][ion]/Old_density[ipBound];
601  UpstreamElem[nelem] += UpstreamIon[nelem][ion];
602  }
603  }
604 
605  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
606  {
607  for( nelem=ipISO; nelem<LIMELM; ++nelem)
608  {
609  if( dense.lgElmtOn[nelem] )
610  {
611  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
612  {
613  UpstreamStatesElem[nelem][nelem-ipISO][level] =
614  Old_StatesElem[ipBound][nelem][nelem-ipISO][level]/Old_density[ipBound];
615  /* check for NaN */
616  ASSERT( !isnan( UpstreamStatesElem[nelem][nelem-ipISO][level] ) );
617  }
618  }
619  }
620  }
621 
622  for(mol=0;mol<mole_global.num_calc;mol++)
623  {
624  Upstream_molecules[mol] = Old_molecules[ipBound][mol]/Old_density[ipBound];
625  if(mole.species[mol].location == NULL && mole_global.list[mol]->parentLabel.empty())
626  {
627  for(molecule::nAtomsMap::iterator atom=mole_global.list[mol]->nAtom.begin();
628  atom != mole_global.list[mol]->nAtom.end(); ++atom)
629  {
630  UpstreamElem[atom->first->el->Z-1] +=
631  Upstream_molecules[mol]*atom->second;
632  }
633  }
634  }
635  }
636 
637  /* Repeat enough of the above for half-step and no-step to judge convergence:
638  * the result of this code is the increment of discretization_error */
639 
640  while( (Old_depth[iphUpstream+1] < hupstream ) &&
641  ( iphUpstream < nOld_zone-1 ) )
642  {
643  ++iphUpstream;
644  }
645  ASSERT( iphUpstream <= nOld_zone-1 );
646 
647  while( (Old_depth[ipyUpstream+1] < radius.depth ) &&
648  ( ipyUpstream < nOld_zone-1 ) )
649  {
650  ++ipyUpstream;
651  }
652  ASSERT( ipyUpstream <= nOld_zone-1 );
653 
654  dynamics.dRad = BIGFLOAT;
655 
657  hnextfrac = ( hupstream - Old_depth[iphUpstream])/
659  else
660  hnextfrac = 0.;
661 
663  ynextfrac = ( radius.depth - Old_depth[ipyUpstream])/
664  (Old_depth[ipyUpstream+1] - Old_depth[ipyUpstream]);
665  else
666  ynextfrac = 0.;
667 
668  // Shouldn't be jumping over large numbers of upstream cells
669  if(ipUpstream != -1 && ipUpstream < nOld_zone-1)
670  dynamics.dRad = MIN2(dynamics.dRad,
671  5*(Old_depth[ipUpstream+1] - Old_depth[ipUpstream]));
672 
673 
674  // Value for scaling zonal changes to set zone width
675  const double STEP_FACTOR=0.05;
676 
677  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
678  {
679  for( ion=0; ion<nelem+2; ++ion )
680  {
681  double f1;
682  if(ipyUpstream != -1 && ipyUpstream != nOld_zone-1 && (Old_depth[ipyUpstream+1] - Old_depth[ipyUpstream]>SMALLFLOAT))
683  {
684  yion =
686  (Old_xIonDense[ipyUpstream+1][nelem][ion]/Old_density[ipyUpstream+1] -
688  ynextfrac;
689  }
690  else
691  {
692  long ipBound = ipyUpstream;
693  if (-1 == ipBound)
694  ipBound = 0;
695  yion = Old_xIonDense[ipBound][nelem][ion]/Old_density[ipBound];
696  }
697  if(iphUpstream != -1 && iphUpstream != nOld_zone-1 && (Old_depth[iphUpstream+1] - Old_depth[iphUpstream]>SMALLFLOAT))
698  {
699  hion =
701  (Old_xIonDense[iphUpstream+1][nelem][ion]/Old_density[iphUpstream+1] -
703  hnextfrac;
704  }
705  else
706  {
707  long ipBound = iphUpstream;
708  if (-1 == ipBound)
709  ipBound = 0;
710  hion = Old_xIonDense[ipBound][nelem][ion]/Old_density[ipBound];
711  }
712 
713  /* the proposed thickness of the next zone */
714  f1 = fabs(yion - UpstreamIon[nelem][ion] );
715  if( f1 > SMALLFLOAT )
716  {
717  dynamics.dRad = MIN2(dynamics.dRad,STEP_FACTOR*fabs(Dyn_dr) *
718  /* don't pay attention to species with abundance relative to H less than 1e-6 */
719  MAX2(yion + UpstreamIon[nelem][ion],1e-6 ) / f1);
720  }
721 
722  /* Must be consistent with convergence_error below */
723  /* this error is error due to the advection length not being zero - a finite
724  * advection length. no need to bring convergence error to below
725  * discretization error. when convergece error is lower than a fraction of this
726  * errror we reduce the advection length. */
727  dynamics.discretization_error += POW2(yion-2.*hion+UpstreamIon[nelem][ion]);
728  dynamics.error_scale2 += POW2(UpstreamIon[nelem][ion]-yion);
729  }
730  }
731 
732  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
733  {
734  for( nelem=ipISO; nelem<LIMELM; ++nelem)
735  {
736  if( dense.lgElmtOn[nelem] )
737  {
738  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
739  {
740  double f1;
741  if(ipyUpstream != -1 && ipyUpstream != nOld_zone-1 &&
742  (Old_depth[ipyUpstream+1] - Old_depth[ipyUpstream]>SMALLFLOAT))
743  {
744  yiso =
745  Old_StatesElem[ipyUpstream][nelem][nelem-ipISO][level]/Old_density[ipyUpstream] +
746  (Old_StatesElem[ipyUpstream+1][nelem][nelem-ipISO][level]/Old_density[ipyUpstream+1] -
747  Old_StatesElem[ipyUpstream][nelem][nelem-ipISO][level]/Old_density[ipyUpstream])*
748  ynextfrac;
749  }
750  else
751  {
752  long ipBound = ipyUpstream;
753  if (-1 == ipBound)
754  ipBound = 0;
755  yiso = Old_StatesElem[ipBound][nelem][nelem-ipISO][level]/Old_density[ipBound];
756  }
757  if(iphUpstream != -1 && iphUpstream != nOld_zone-1 &&
758  (Old_depth[iphUpstream+1] - Old_depth[iphUpstream]>SMALLFLOAT))
759  {
760  hiso =
761  Old_StatesElem[iphUpstream][nelem][nelem-ipISO][level]/Old_density[iphUpstream] +
762  (Old_StatesElem[iphUpstream+1][nelem][nelem-ipISO][level]/Old_density[iphUpstream+1] -
763  Old_StatesElem[iphUpstream][nelem][nelem-ipISO][level]/Old_density[iphUpstream])*
764  hnextfrac;
765  }
766  else
767  {
768  long ipBound = iphUpstream;
769  if (-1 == ipBound)
770  ipBound = 0;
771  hiso = Old_StatesElem[ipBound][nelem][nelem-ipISO][level]/Old_density[ipBound];
772  }
773 
774  /* the proposed thickness of the next zone */
775  f1 = fabs(yiso - UpstreamStatesElem[nelem][nelem-ipISO][level] );
776  if( f1 > SMALLFLOAT )
777  {
778  dynamics.dRad = MIN2(dynamics.dRad,fabs(Dyn_dr*STEP_FACTOR) *
779  /* don't pay attention to species with abundance relative to H less tghan 1e-6 */
780  MAX2(yiso + UpstreamStatesElem[nelem][nelem-ipISO][level],1e-6 ) / f1);
781  }
782  /* Must be consistent with convergence_error below */
783  /* this error is error due to the advection length not being zero - a finite
784  * advection length. no need to bring convergence error to below
785  * discretization error. when convergece error is lower than a fraction of this
786  * error we reduce the advection length. */
787  dynamics.discretization_error += POW2(yiso-2.*hiso+UpstreamStatesElem[nelem][nelem-ipISO][level]);
788  dynamics.error_scale2 += POW2(UpstreamStatesElem[nelem][nelem-ipISO][level]);
789  }
790  }
791  }
792  }
793 
794  for(mol=0; mol < mole_global.num_calc; mol++)
795  {
796  double f1;
797  if(ipyUpstream != -1 && ipyUpstream != nOld_zone-1 && (Old_depth[ipyUpstream+1] - Old_depth[ipyUpstream]>SMALLFLOAT))
798  {
799  ymol =
801  (Old_molecules[ipyUpstream+1][mol]/Old_density[ipyUpstream+1] -
803  ynextfrac;
804  }
805  else
806  {
807  long ipBound = ipyUpstream;
808  if (-1 == ipBound)
809  ipBound = 0;
810  ymol = Old_molecules[ipBound][mol]/Old_density[ipBound];
811  }
812  if(iphUpstream != -1 && iphUpstream != nOld_zone-1 && (Old_depth[iphUpstream+1] - Old_depth[iphUpstream]>SMALLFLOAT))
813  {
814  hmol =
816  (Old_molecules[iphUpstream+1][mol]/Old_density[iphUpstream+1] -
818  hnextfrac;
819  }
820  else
821  {
822  long ipBound = iphUpstream;
823  if (-1 == ipBound)
824  ipBound = 0;
825  hmol = Old_molecules[ipBound][mol]/Old_density[ipBound];
826  }
827 
828  /* the proposed thickness of the next zone */
829  f1 = fabs(ymol - Upstream_molecules[mol] );
830  if( f1 > SMALLFLOAT )
831  {
832  dynamics.dRad = MIN2(dynamics.dRad,fabs(Dyn_dr*STEP_FACTOR) *
833  /* don't pay attention to species with abundance relative to H less than 1e-6 */
834  MAX2(ymol + Upstream_molecules[mol],1e-6 ) / f1 );
835  }
836 
837  /* Must be consistent with convergence_error below */
838  /* >>chngf 01 aug 01, remove scalingDensity() from HAtom */
839  /* >>chngf 02 aug 01, multiply by cell width */
840  dynamics.discretization_error += POW2(ymol-2.*hmol+Upstream_molecules[mol]);
841  dynamics.error_scale2 += POW2(Upstream_molecules[mol]-ymol);
842  }
843 
844  if( dynamics.lgTracePrint )
845  {
846  fprintf(ioQQQ," DynaStartZone, %4li photo=%.2e , H recom= %.2e dil %.2e \n",
847  nzone,dynamics.Rate , dynamics.Source[0][0] , dilution*scalingDensity() );
848  }
849  return;
850 }
851 
852 /* DynaEndZone called at end of zone calculation when advection is turned on */
853 void DynaEndZone(void)
854 {
855  DEBUG_ENTRY( "DynaEndZone()" );
856 
857  /* this routine is called at the end of a zone calculation, by ZoneEnd */
858 
860 
861  if(dynamics.lgTracePrint)
862  fprintf(ioQQQ,"Check dp: %g %g mom %g %g mas %g\n",
867  DynaFlux(radius.depth)*(1e16-radius.depth)*(1e16-radius.depth));
868  return;
869 }
870 
871 
872 /* ============================================================================== */
873 /* DynaIterEnd called at end of iteration when advection is turned on */
874 void DynaIterEnd(void)
875 {
876  /* this routine is called by IterRestart at the end of an iteration
877  * when advection is turned on. currently it only derives a
878  * dynamics.timestep by looking at the spatial derivative of
879  * some stored quantities */
880  long int i;
881  static long int nTime_dt_array_element = 0;
882 
883  DEBUG_ENTRY( "DynaIterEnd()" );
884 
885  /* set stopping outer radius to current outer radius once we have let
886  * solution relax dynamics.n_initial_relax times
887  * note the off by one confusion - relax is 2 by default,
888  * want to do two static iterations then start dynamics
889  * iteration was incremented before this call so iteration == 2 at
890  * end of first iteration */
891  if( iteration == dynamics.n_initial_relax+1)
892  {
893  fprintf(ioQQQ,"DYNAMICS DynaIterEnd sets stop radius to %.2e after "
894  "dynamics.n_initial_relax=%li iterations.\n",
895  radius.depth,
896  dynamics.n_initial_relax);
897  for( i=iteration-1; i<iterations.iter_malloc; ++i )
898  /* set stopping radius to current radius, this stops
899  * dynamical solutions from overrunning the upstream scale
900  * and extending to very large radius due to unphysical heat
901  * appearing to advect into region */
903  }
904 
905  dynamics.DivergePresInteg = 0.;
906 
907  /* This routine is only called if advection is turned on at the end of
908  * each iteration. The test
909  * is to check whether wind velocity is also set by dynamics code */
910 
911  /* !dynamics.lgStatic true - a true dynamical model */
912  if( !dynamics.lgTimeDependentStatic )
913  {
914  if(iteration == dynamics.n_initial_relax+1 )
915  {
916  /* let model settle down for n_initial_relax iterations before we begin
917  * dynamics.n_initial_relax set with "set dynamics relax"
918  * command - it gives the first iteration where we do dynamics
919  * note the off by one confusion - relax is 2 by default,
920  * want to do two static iterations then start dynamics
921  * iteration was incremented before this call so iteration == 2
922  * at end of first iteration */
923  if( dynamics.AdvecLengthInit> 0. )
924  {
925  Dyn_dr = dynamics.AdvecLengthInit;
926  }
927  else
928  {
929  /* -ve dynamics.adveclengthlimit sets length as fraction of first iter total depth */
930  Dyn_dr = -dynamics.AdvecLengthInit*radius.depth;
931  }
932 
933  if (wind.windv0 > 0)
934  Dyn_dr = -Dyn_dr;
935 
936  if( dynamics.lgTracePrint )
937  {
938  fprintf(ioQQQ," DynaIterEnd, dr=%.2e \n",
939  Dyn_dr );
940  }
941  }
942  else if(iteration > dynamics.n_initial_relax+1 )
943  {
944  /* evaluate errors and update Dyn_dr */
945  DynaNewStep();
946  }
947  }
948  else
949  {
950  /* this is time-dependent static model */
951  static double HeatInitial=-1. , HeatRadiated=-1. ,
952  DensityInitial=-1;
953  /* n_initial_relax is number of time-steady models before we start
954  * to evolve, set with "set dynamics relax" command */
955  Dyn_dr = 0.;
956  fprintf(ioQQQ,
957  "DEBUG times enter dynamics.timestep %.2e elapsed_time %.2e iteration %li relax %li \n",
958  dynamics.timestep ,
959  dynamics.time_elapsed,
960  iteration , dynamics.n_initial_relax);
961  if( iteration > dynamics.n_initial_relax )
962  {
963  /* evaluate errors */
964  DynaNewStep();
965 
966  /* this is set true on CORONAL XXX TIME INIT command, says to use constant
967  * temperature for first n_initial_relax iterations, then let run free */
968  if( dynamics.lg_coronal_time_init )
969  {
971  thermal.ConstTemp = 0.;
972  }
973 
974  /* time variable branch, now without dynamics */
975  /* elapsed time - don't increase dynamics.time_elapsed during first two
976  * two iterations since this sets static model */
977  dynamics.time_elapsed += dynamics.timestep;
978  /* dynamics.timestep_stop is -1 if not set with explicit stop time */
979  if( dynamics.timestep_stop > 0 && dynamics.time_elapsed > dynamics.timestep_stop )
980  {
981  dynamics.lgStatic_completed = true;
982  }
983 
984  /* stop lowest temperature time command */
987  dynamics.lgStatic_completed = true;
988 
989  /* this is heat radiated, after correction for change of H density in constant
990  * pressure cloud */
991  HeatRadiated += (thermal.ctot-dynamics.Cool()) * dynamics.timestep *
992  (DensityInitial / scalingDensity());
993  }
994  else
995  {
996  /* this branch, during initial relaxation of solution */
997  HeatInitial = 1.5 * pressure.PresGasCurr;
998  HeatRadiated = 0.;
999  DensityInitial = scalingDensity();
1000  fprintf(ioQQQ,"DEBUG relaxing times requested %li this is step %li\n",
1001  dynamics.n_initial_relax , iteration);
1002  }
1003  fprintf(ioQQQ,"DEBUG heat conser HeatInitial=%.2e HeatRadiated=%.2e\n",
1004  HeatInitial , HeatRadiated );
1005 
1006  /* at this point dynamics.time_elapsed is the time at the end of the
1007  * previous iteration. We need dt for the next iteration */
1008  if( dynamics.time_elapsed > time_elapsed_time[nTime_dt_array_element] )
1009  {
1010  /* time has advanced to next table point,
1011  * set dynamics.timestep to specified value */
1012  ++nTime_dt_array_element;
1013  /* this is an assert since we already qualified the array
1014  * element above */
1015  ASSERT( nTime_dt_array_element < nTime_flux );
1016 
1017  /* option to set flag for recombination logic */
1018  if( lgtime_Recom[nTime_dt_array_element] )
1019  {
1020  fprintf(ioQQQ,"DEBUG dynamics turn on recombination logic\n");
1021  dynamics.lgRecom = true;
1022  /* set largest possible zone thickness to value on previous
1023  * iteration when light was on - during recombination conditions
1024  * become much more homogeneous and dr can get too large,
1025  * crashing into H i-front */
1027  radius.lgSdrmaxRel = false;
1028  }
1029 
1030  if( lgtime_dt_specified )
1031  {
1032  /* this is the new dynamics.timestep */
1033  fprintf(ioQQQ,"DEBUG lgtimes increment Time to %li %.2e\n" ,nTime_dt_array_element,
1034  dynamics.timestep);
1035  dynamics.timestep = time_dt[nTime_dt_array_element];
1036  /* option to change time step factor - default is 1.2 set in DynaZero */
1037  if( time_dt_scale_factor[nTime_dt_array_element] > 0. )
1038  dynamics.timestep_factor = time_dt_scale_factor[nTime_dt_array_element];
1039  }
1040  }
1041  else if( lgtime_dt_specified )
1042  {
1043  /* we are between two points in the table, increase dynamics.timestep */
1044  dynamics.timestep *= dynamics.timestep_factor;
1045  fprintf(ioQQQ,"DEBUG lgtimes increment Timeby dynamics.timestep_factor to %li %.2e\n" ,
1046  nTime_dt_array_element,
1047  dynamics.timestep );
1048  if(dynamics.time_elapsed+dynamics.timestep > time_elapsed_time[nTime_dt_array_element] )
1049  {
1050  fprintf(ioQQQ,"DEBUG lgtimes but reset to %.2e\n" ,dynamics.timestep );
1051  dynamics.timestep = 1.0001*(time_elapsed_time[nTime_dt_array_element]-dynamics.time_elapsed);
1052  }
1053  }
1054  else
1055  {
1056  /* time not specified in third column, so use initial */
1057  dynamics.timestep = timestep_next();
1058  }
1059 
1060  if( cosmology.lgDo )
1061  {
1065  }
1066 
1067  fprintf(ioQQQ,"DEBUG times exit dynamics.timestep %.2e elapsed_time %.2e scale %.2e ",
1068  dynamics.timestep ,
1069  dynamics.time_elapsed,
1071 
1072  if( cosmology.lgDo )
1073  {
1074  fprintf(ioQQQ,"redshift %.3e ", cosmology.redshift_current );
1075  }
1076 
1077  fprintf(ioQQQ,"\n" );
1078  }
1079 
1080  /* Dyn_dr == 0 is for static time dependent cloud */
1081  ASSERT( (iteration < dynamics.n_initial_relax+1) ||
1082  Dyn_dr != 0. || (Dyn_dr == 0. && wind.lgStatic()) );
1083 
1084  /* reset the upstream counters */
1086  dynamics.discretization_error = 0.;
1087  dynamics.error_scale2 = 0.;
1088 
1089  /* save results from previous iteration */
1090  DynaSaveLast();
1091  return;
1092 }
1093 
1094 /*DynaNewStep work out convergence errors */
1096 {
1097  long int ilast = 0,
1098  i,
1099  nelem,
1100  ion,
1101  mol;
1102 
1103  double frac_next=-BIGFLOAT,
1104  Oldi_density,
1105  Oldi_ion,
1106  Oldi_iso,
1107  Oldi_mol;
1108 
1109  DEBUG_ENTRY( "DynaNewStep()" );
1110 
1111  /*n = MIN2(nzone, NZLIM-1);*/
1112  dynamics.convergence_error = 0;
1113  dynamics.error_scale1 = 0.;
1114 
1115  ASSERT( nzone < struc.nzlim);
1116  for(i=0;i<nzone;++i)
1117  {
1118  /* Interpolate for present position in previous solution */
1119  while( (Old_depth[ilast] < struc.depth[i] ) &&
1120  ( ilast < nOld_zone-1 ) )
1121  {
1122  ++ilast;
1123  }
1124  ASSERT( ilast <= nOld_zone-1 );
1125 
1126  if(ilast != nOld_zone-1 && ((Old_depth[ilast+1] - Old_depth[ilast])> SMALLFLOAT) )
1127  {
1128  frac_next = ( struc.depth[i] - Old_depth[ilast])/
1129  (Old_depth[ilast+1] - Old_depth[ilast]);
1130  Oldi_density = Old_density[ilast] +
1131  (Old_density[ilast+1] - Old_density[ilast])*
1132  frac_next;
1133  }
1134  else
1135  {
1136  Oldi_density = Old_density[ilast];
1137  }
1138  /* Must be consistent with discretization_error above */
1139  /* >>chngf 02 aug 01, multiply by cell width */
1140  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
1141  {
1142  for( ion=0; ion<nelem+2; ++ion )
1143  {
1144  if(ilast != nOld_zone-1 && ((Old_depth[ilast+1] - Old_depth[ilast])> SMALLFLOAT) )
1145  {
1146  Oldi_ion = (Old_xIonDense[ilast][nelem][ion] +
1147  (Old_xIonDense[ilast+1][nelem][ion]-Old_xIonDense[ilast][nelem][ion])*
1148  frac_next);
1149  }
1150  else
1151  {
1152  Oldi_ion = Old_xIonDense[ilast][nelem][ion];
1153  }
1154  dynamics.convergence_error += POW2((double)Oldi_ion/Oldi_density-struc.xIonDense[nelem][ion][i]/scalingZoneDensity(i)) /* *struc.dr[i] */;
1155 
1156  /* >>chng 02 nov 11, add first error scale estimate from Robin */
1157  //fprintf(ioQQQ,"%g %g %g\n",dynamics.error_scale1,
1158  // struc.xIonDense[nelem][ion][i],scalingZoneDensity(i));
1159  dynamics.error_scale1 += POW2((double)struc.xIonDense[nelem][ion][i]/scalingZoneDensity(i));
1160  }
1161  }
1162  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
1163  {
1164  for( nelem=ipISO; nelem<LIMELM; ++nelem)
1165  {
1166  if( dense.lgElmtOn[nelem] )
1167  {
1168  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_local; ++level )
1169  {
1170  if(ilast != nOld_zone-1 && ((Old_depth[ilast+1] - Old_depth[ilast])> SMALLFLOAT) )
1171  {
1172  Oldi_iso = (Old_StatesElem[ilast][nelem][nelem-ipISO][level] +
1173  (Old_StatesElem[ilast+1][nelem][nelem-ipISO][level]-Old_StatesElem[ilast][nelem][nelem-ipISO][level])*
1174  frac_next);
1175  }
1176  else
1177  {
1178  Oldi_iso = Old_StatesElem[ilast][nelem][nelem-ipISO][level];
1179  }
1180  dynamics.convergence_error += POW2(Oldi_iso/Oldi_density-struc.StatesElem[nelem][nelem-ipISO][level][i]/struc.hden[i]) /* *struc.dr[i] */;
1181 
1182  /* >>chng 02 nov 11, add first error scale estimate from Robin */
1183  dynamics.error_scale1 += POW2(struc.StatesElem[nelem][nelem-ipISO][level][i]/struc.hden[i]);
1184  }
1185  }
1186  }
1187  }
1188 
1189  for( mol=0; mol < mole_global.num_calc; mol++)
1190  {
1191  if(ilast != nOld_zone-1 && ((Old_depth[ilast+1] - Old_depth[ilast])> SMALLFLOAT) )
1192  {
1193  Oldi_mol = (Old_molecules[ilast][mol] +
1194  (Old_molecules[ilast+1][mol]-Old_molecules[ilast][mol])*
1195  frac_next);
1196  }
1197  else
1198  {
1199  Oldi_mol = Old_molecules[ilast][mol];
1200  }
1201  dynamics.convergence_error += POW2((double)Oldi_mol/Oldi_density-struc.molecules[mol][i]/scalingZoneDensity(i)) /* *struc.dr[i] */;
1202 
1203  /* >>chng 02 nov 11, add first error scale estimate from Robin
1204  * used to normalize the above convergence_error */
1205  dynamics.error_scale1 += POW2((double)struc.molecules[mol][i]/scalingZoneDensity(i));
1206  }
1207  }
1208 
1209  /* convergence_error is an estimate of the convergence of the solution from its change during the last iteration,
1210  discretization_error is an estimate of the accuracy of the advective terms, calculated in DynaStartZone above:
1211  if dominant error is from the advective terms, need to make them more accurate.
1212  */
1213 
1214  /* report properties of previous iteration */
1215  fprintf(ioQQQ,"DYNAMICS DynaNewStep: Dyn_dr %.2e convergence_error %.2e discretization_error %.2e error_scale1 %.2e error_scale2 %.2e\n",
1216  Dyn_dr, dynamics.convergence_error , dynamics.discretization_error ,
1217  dynamics.error_scale1 , dynamics.error_scale2
1218  );
1219 
1220  /* >>chng 02 nov 29, dynamics.convergence_tolerance is now set to 0.1 in init routine */
1221  if( dynamics.convergence_error < dynamics.convergence_tolerance*dynamics.discretization_error )
1222  Dyn_dr /= 1.5;
1223  return;
1224 }
1225 
1226 /*DynaSaveLast save results from previous iteration */
1228 {
1229  long int i,
1230  ion,
1231  nelem,
1232  mol;
1233 
1234  DEBUG_ENTRY( "DynaSaveLast()" );
1235 
1236  /* Save results from previous iteration */
1237  nOld_zone = nzone;
1238  dynamics.oldFullDepth = struc.depth[nzone-1];
1239  ASSERT( nzone < struc.nzlim );
1240  for( i=0; i<nzone; ++i )
1241  {
1242  Old_histr[i] = struc.histr[i];
1243  Old_depth[i] = struc.depth[i];
1245  /* old n_p density from previous iteration */
1246  Old_hiistr[i] = struc.hiistr[i];
1247  /* old pressure from previous iteration */
1248  Old_pressure[i] = struc.pressure[i];
1249  /* old electron density from previous iteration */
1250  Old_ednstr[i] = struc.ednstr[i];
1251  /* energy term */
1254  Old_DenMass[i] = struc.DenMass[i];
1255 
1256  for(mol=0;mol<mole_global.num_calc;mol++)
1257  {
1258  Old_molecules[i][mol] = struc.molecules[mol][i];
1259  }
1260 
1261  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
1262  {
1263  Old_gas_phase[i][nelem] = dense.gas_phase[nelem];
1264  for( ion=0; ion<nelem+2; ++ion )
1265  {
1266  Old_xIonDense[i][nelem][ion] = struc.xIonDense[nelem][ion][i];
1267  }
1268  }
1269  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
1270  {
1271  for( nelem=ipISO; nelem<LIMELM; ++nelem)
1272  {
1273  if( dense.lgElmtOn[nelem] )
1274  {
1275  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
1276  {
1277  Old_StatesElem[i][nelem][nelem-ipISO][level] = struc.StatesElem[nelem][nelem-ipISO][level][i];
1278  ASSERT( !isnan( Old_StatesElem[i][nelem][nelem-ipISO][level] ) );
1279  }
1280  }
1281  }
1282  }
1283  }
1284  return;
1285 }
1286 
1287 realnum DynaFlux(double depth)
1288 
1289 {
1290  realnum flux;
1291 
1292  DEBUG_ENTRY( "DynaFlux()" );
1293 
1294  if(dynamics.FluxIndex == 0)
1295  {
1296  flux = (realnum)dynamics.FluxScale;
1297  }
1298  else
1299  {
1300  flux = (realnum)(dynamics.FluxScale*pow(fabs(depth-dynamics.FluxCenter),dynamics.FluxIndex));
1301  if(depth < dynamics.FluxCenter)
1302  flux = -flux;
1303  }
1304  if(dynamics.lgFluxDScale)
1305  {
1306  /*flux *= struc.DenMass[0]; */
1307  /* WJH 21 may 04, changed to use dense.xMassDensity0, which should be strictly constant */
1308  flux *= dense.xMassDensity0;
1309  }
1310  return flux;
1311 }
1312 
1313 /* ============================================================================== */
1314 /*DynaZero zero some dynamics variables, called from zero.c,
1315  * before parsing commands */
1316 void DynaZero( void )
1317 {
1318  int ipISO;
1319 
1320  DEBUG_ENTRY( "DynaZero()" );
1321 
1322  /* the number of zones in the previous iteration */
1323  nOld_zone = 0;
1324 
1325  /* by default advection is turned off */
1326  dynamics.lgAdvection = false;
1327  /*dynamics.Velocity = 0.;*/
1328  AdvecSpecificEnthalpy = 0.;
1329  dynamics.Cool_r = 0.;
1330  dynamics.Heat_v = 0.;
1331  dynamics.dHeatdT = 0.;
1332  dynamics.HeatMax = 0.;
1333  dynamics.CoolMax = 0.;
1334  dynamics.Rate = 0.;
1335 
1336  /* sets recombination logic, keyword RECOMBINATION on a time step line */
1337  dynamics.lgRecom = false;
1338 
1339  /* don't force populations to equilibrium levels */
1340  dynamics.lgEquilibrium = false;
1341 
1342  /* set true if time dependent calculation is finished */
1343  dynamics.lgStatic_completed = false;
1344 
1345  /* vars that determine whether time dependent soln only - set with time command */
1346  dynamics.lgTimeDependentStatic = false;
1347  dynamics.timestep_init = -1.;
1348  /* this factor multiplies the time step */
1349  dynamics.timestep_factor = 1.2;
1350  dynamics.time_elapsed = 0.;
1351 
1352  /* set the first iteration to include dynamics rather than constant pressure */
1353  /* iteration number, initial iteration is 1, default is 2 - changed with SET DYNAMICS FIRST command */
1354  dynamics.n_initial_relax = 2;
1355 
1356  /* set initial value of the advection length,
1357  * neg => fraction of depth of init model, + length cm */
1358  dynamics.AdvecLengthInit = -0.1;
1359 
1360  /* this is a tolerance for determining whether dynamics has converged */
1361  dynamics.convergence_tolerance = 0.1;
1362 
1363  /* this says that set dynamics pressure mode was set */
1364  dynamics.lgSetPresMode = false;
1365 
1366  /* set default values for uniform mass flux */
1367  dynamics.FluxScale = 0.;
1368  dynamics.lgFluxDScale = false;
1369  dynamics.FluxCenter = 0.;
1370  dynamics.FluxIndex = 0.;
1371  dynamics.dRad = BIGFLOAT;
1372 
1373  for( ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
1374  {
1375  /* factor to allow turning off advection for one of the iso seq,
1376  * this is done with command "no advection h-like" or "he-like"
1377  * only for testing */
1378  dynamics.lgISO[ipISO] = true;
1379  }
1380  /* turn off advection for rest of ions, command "no advection metals" */
1381  dynamics.lgMETALS = true;
1382  /* turn off thermal effects of advection, command "no advection cooling" */
1383  dynamics.lgCoolHeat = true;
1384  dynamics.DivergePresInteg = 0.;
1385 
1386  dynamics.discretization_error = 0.;
1387  dynamics.error_scale2 = 0.;
1388  return;
1389 }
1390 
1391 
1392 /* ============================================================================== */
1393 /* DynaCreateArrays allocate some space needed to save the dynamics structure variables,
1394  * called from DynaCreateArrays */
1395 void DynaCreateArrays( void )
1396 {
1397  long int nelem,
1398  ns,
1399  i,
1400  ion,
1401  mol;
1402 
1403  DEBUG_ENTRY( "DynaCreateArrays()" );
1404 
1405  if (mole_global.num_calc != 0)
1406  {
1407  Upstream_molecules = (double*)MALLOC((size_t)mole_global.num_calc*sizeof(double) );
1408 
1409  dynamics.molecules = (double*)MALLOC((size_t)mole_global.num_calc*sizeof(double) );
1410  }
1411  else
1412  {
1413  Upstream_molecules = dynamics.molecules = NULL;
1414  }
1415  UpstreamElem = (double*)MALLOC((size_t)LIMELM*sizeof(double) );
1416 
1417  dynamics.Source = ((double**)MALLOC( (size_t)LIMELM*sizeof(double *) ));
1418  UpstreamIon = ((double**)MALLOC( (size_t)LIMELM*sizeof(double *) ));
1419  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem )
1420  {
1421  dynamics.Source[nelem] = ((double*)MALLOC( (size_t)(nelem+2)*sizeof(double) ));
1422  UpstreamIon[nelem] = ((double*)MALLOC( (size_t)(nelem+2)*sizeof(double) ));
1423  for( ion=0; ion<nelem+2; ++ion )
1424  {
1425  dynamics.Source[nelem][ion] = 0.;
1426  }
1427  }
1428 
1429  UpstreamStatesElem = ((double***)MALLOC( (size_t)LIMELM*sizeof(double **) ));
1430  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
1431  {
1432  if( dense.lgElmtOn[nelem] )
1433  {
1434  UpstreamStatesElem[nelem] = (double**)MALLOC(sizeof(double*)*(unsigned)(nelem+1) );
1435  for( long ion=0; ion<nelem+1; ion++ )
1436  {
1437  long ipISO = nelem-ion;
1438  if( ipISO < NISO )
1439  {
1440  UpstreamStatesElem[nelem][nelem-ipISO] = (double*)MALLOC(sizeof(double)*(unsigned)iso_sp[ipISO][nelem].numLevels_max);
1441  }
1442  else
1443  {
1444  fixit(); // for now, point non-iso ions to NULL
1445  UpstreamStatesElem[nelem][nelem-ipISO] = NULL;
1446  }
1447  }
1448  }
1449  }
1450 
1451 
1452  dynamics.StatesElem = ((double***)MALLOC( (size_t)LIMELM*sizeof(double **) ));
1453  for( nelem=ipHYDROGEN; nelem<LIMELM; ++nelem)
1454  {
1455  if( dense.lgElmtOn[nelem] )
1456  {
1457  dynamics.StatesElem[nelem] = (double**)MALLOC(sizeof(double*)*(unsigned)(nelem+1) );
1458  for( long ion=0; ion<nelem+1; ion++ )
1459  {
1460  long ipISO = nelem-ion;
1461  if( ipISO < NISO )
1462  {
1463  dynamics.StatesElem[nelem][nelem-ipISO] = (double*)MALLOC(sizeof(double)*(unsigned)iso_sp[ipISO][nelem].numLevels_max);
1464  }
1465  else
1466  {
1467  fixit(); // for now, point non-iso ions to NULL
1468  dynamics.StatesElem[nelem][nelem-ipISO] = NULL;
1469  }
1470  }
1471  }
1472  }
1473 
1474  dynamics.Rate = 0.;
1475 
1476  Old_EnthalpyDensity = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1477 
1478  Old_ednstr = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1479 
1480  EnthalpyDensity = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1481 
1482  Old_DenMass = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1483 
1484  Old_density = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1485 
1486  Old_pressure = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1487 
1488  Old_histr = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1489 
1490  Old_hiistr = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1491 
1492  Old_depth = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1493 
1494  Old_xLyman_depth = ((realnum*)MALLOC( (size_t)(struc.nzlim)*sizeof(realnum )));
1495 
1496  Old_xIonDense = (realnum ***)MALLOC(sizeof(realnum **)*(unsigned)(struc.nzlim) );
1497 
1498  Old_StatesElem = (realnum ****)MALLOC(sizeof(realnum ***)*(unsigned)(struc.nzlim) );
1499 
1500  Old_gas_phase = (realnum **)MALLOC(sizeof(realnum *)*(unsigned)(struc.nzlim) );
1501 
1502  Old_molecules = (realnum **)MALLOC(sizeof(realnum *)*(unsigned)(struc.nzlim) );
1503 
1504  /* now create diagonal of space for ionization arrays */
1505  for( ns=0; ns < struc.nzlim; ++ns )
1506  {
1507  Old_xIonDense[ns] =
1508  (realnum**)MALLOC(sizeof(realnum*)*(unsigned)(LIMELM) );
1509 
1510  Old_StatesElem[ns] =
1511  (realnum***)MALLOC(sizeof(realnum**)*(unsigned)(LIMELM) );
1512 
1513  Old_gas_phase[ns] =
1514  (realnum*)MALLOC(sizeof(realnum)*(unsigned)(LIMELM) );
1515 
1516  if (mole_global.num_calc != 0)
1517  {
1518  Old_molecules[ns] =
1519  (realnum*)MALLOC(sizeof(realnum)*(unsigned)(mole_global.num_calc) );
1520  }
1521  else
1522  {
1523  Old_molecules[ns] = NULL;
1524  }
1525 
1526  for( nelem=0; nelem<LIMELM; ++nelem )
1527  {
1528  Old_xIonDense[ns][nelem] =
1529  (realnum*)MALLOC(sizeof(realnum)*(unsigned)(LIMELM+1) );
1530  }
1531 
1532  for( nelem=0; nelem< LIMELM; ++nelem )
1533  {
1534  if( dense.lgElmtOn[nelem] )
1535  {
1536  Old_StatesElem[ns][nelem] =
1537  (realnum**)MALLOC(sizeof(realnum*)*(unsigned)(nelem+1) );
1538  for( ion=0; ion<nelem+1; ion++ )
1539  {
1540  long ipISO = nelem-ion;
1541  if( ipISO < NISO )
1542  {
1543  Old_StatesElem[ns][nelem][ion] =
1544  (realnum*)MALLOC(sizeof(realnum)*(unsigned)iso_sp[ipISO][nelem].numLevels_max);
1545  }
1546  else
1547  {
1548  fixit(); // for now, point non-iso ions to NULL
1549  Old_StatesElem[ns][nelem][ion] = NULL;
1550  }
1551  }
1552  }
1553  }
1554  }
1555 
1556  for( i=0; i < struc.nzlim; i++ )
1557  {
1558  /* these are values if H0 and tau_912 from previous iteration */
1559  Old_histr[i] = 0.;
1560  Old_xLyman_depth[i] = 0.;
1561  Old_depth[i] = 0.;
1562  dynamics.oldFullDepth = 0.;
1563  /* old n_p density from previous iteration */
1564  Old_hiistr[i] = 0.;
1565  /* old pressure from previous iteration */
1566  Old_pressure[i] = 0.;
1567  /* old electron density from previous iteration */
1568  Old_ednstr[i] = 0.;
1569  Old_density[i] = 0.;
1570  Old_DenMass[i] = 0.;
1571  Old_EnthalpyDensity[i] = 0.;
1572  for( nelem=0; nelem<LIMELM; ++nelem )
1573  {
1574  for( ion=0; ion<LIMELM+1; ++ion )
1575  {
1576  Old_xIonDense[i][nelem][ion] = 0.;
1577  }
1578  }
1579  for( long ipISO=ipH_LIKE; ipISO<NISO; ++ipISO )
1580  {
1581  for( nelem=ipISO; nelem<LIMELM; ++nelem)
1582  {
1583  if( dense.lgElmtOn[nelem] )
1584  {
1585  for( long level=0; level < iso_sp[ipISO][nelem].numLevels_max; ++level )
1586  {
1587  Old_StatesElem[i][nelem][nelem-ipISO][level] = 0.;
1588  }
1589  }
1590  }
1591  }
1592 
1593  for(mol=0;mol<mole_global.num_calc;mol++)
1594  {
1595  Old_molecules[i][mol] = 0.;
1596  }
1597  }
1598  return;
1599 }
1600 
1601 /*advection_set_default - called to set default conditions
1602  * when time and wind commands are parsed,
1603  * lgWind is true if dynamics, false if time dependent */
1604 STATIC void advection_set_default( bool lgWind )
1605 {
1606 
1607  DEBUG_ENTRY( "advection_set_default()" );
1608 
1609  /* turn on advection */
1610  dynamics.lgAdvection = true;
1611 
1612  /* turn off prediction of next zone's temperature, as guessed in ZoneStart,
1613  * also set with no tepredictor */
1614  thermal.lgPredNextTe = false;
1615 
1616  /* use the new temperature solver
1617  strcpy( conv.chSolverEden , "new" ); */
1618 
1619  /* constant total pressure, gas+rad+incident continuum
1620  * turn on radiation pressure */
1623  pressure.lgPres_ram_ON = true;
1624 
1625  /* we need to make the solvers much more exact when advection is in place */
1626  if( lgWind )
1627  {
1628  /* increase precision of solution */
1629  conv.EdenErrorAllowed = 1e-3;
1630  /* the actual relative error is relative to the total heating and cooling,
1631  * which include the dynamics.heat() and .cool(), which are the advected heating/cooling.
1632  * the two terms can be large and nearly cancel, what is written to the .heat() and cool files
1633  * by save files has had the smaller of the two subtracted, leaving only the net advected
1634  * heating and cooling */
1635  conv.HeatCoolRelErrorAllowed = 3e-4f;
1636  conv.PressureErrorAllowed = 1e-3f;
1637 
1638  if( cosmology.lgDo )
1639  {
1640  conv.EdenErrorAllowed = 1e-5;
1641  conv.PressureErrorAllowed = 1e-5f;
1642  }
1643  }
1644  return;
1645 }
1646 
1647 /* ============================================================================== */
1648 /* ParseDynaTime parse the time command, called from ParseCommands */
1650 {
1651  DEBUG_ENTRY( "ParseDynaTime()" );
1652 
1653  /*flag set true when time dependent only */
1654  dynamics.lgTimeDependentStatic = true;
1655 
1656  dynamics.timestep_init = p.getNumberCheckAlwaysLogLim("dynamics.timestep",30.);
1657 
1658  dynamics.timestep = dynamics.timestep_init;
1659  if( p.nMatch( "TRAC" ) )
1660  dynamics.lgTracePrint = true;
1661 
1662  /* this is the stop time and is optional */
1663  dynamics.timestep_stop = p.getNumberDefaultAlwaysLog("stop time", -1.);
1664 
1665  /* set default flags - false says that time dependent, not dynamical solution */
1666  advection_set_default(false);
1667 
1668  wind.windv0 = 0.;
1669  wind.setStatic();
1670  wind.windv = wind.windv0;
1671 
1672  /* create time step and flux arrays */
1673  time_elapsed_time = (double*)MALLOC((size_t)NTIME*sizeof(double));
1674  time_flux_ratio = (double*)MALLOC((size_t)NTIME*sizeof(double));
1675  time_dt = (double*)MALLOC((size_t)NTIME*sizeof(double));
1676  time_dt_scale_factor = (double*)MALLOC((size_t)NTIME*sizeof(double));
1677  lgtime_Recom = (int*)MALLOC((size_t)NTIME*sizeof(int));
1678 
1679  /* number of lines we will save */
1680  nTime_flux = 0;
1681 
1682  /* get the next line, and check for eof */
1683  p.getline();
1684  if( p.m_lgEOF )
1685  {
1686  fprintf( ioQQQ,
1687  " Hit EOF while reading time-continuum list; use END to end list.\n" );
1689  }
1690 
1691  /* third column might set dt - if any third column is missing then
1692  * this is set false and only time on command line is used */
1693  lgtime_dt_specified = true;
1694 
1695  while( p.strcmp("END") != 0 )
1696  {
1697  if( nTime_flux >= NTIME )
1698  {
1699  fprintf( ioQQQ,
1700  " Too many time points have been entered; the limit is %d. Increase variable NTIME in dynamics.c.\n",
1701  NTIME );
1703  }
1704 
1705  if( p.nMatch("CYCLE") )
1706  {
1707  double period = p.getNumberCheckAlwaysLog("log time");
1708  ASSERT( period > time_elapsed_time[nTime_flux-1] );
1709  long pointsPerPeriod = nTime_flux;
1710  while( nTime_flux < NTIME - 1 )
1711  {
1712  time_elapsed_time[nTime_flux] = period + time_elapsed_time[nTime_flux-pointsPerPeriod];
1714  time_dt[nTime_flux] = time_dt[nTime_flux-pointsPerPeriod];
1716  nTime_flux++;
1717  }
1718  //Tell the code to continue cyclically by equating two named time points
1719  fprintf( ioQQQ, " Adding cycles with period = %e s.\n", period );
1720 
1721  /* get next line and check for eof */
1722  p.getline();
1723  if( p.m_lgEOF )
1724  {
1725  fprintf( ioQQQ, " Hit EOF while reading line list; use END to end list.\n" );
1727  }
1728  continue;
1729  }
1730 
1732  if( nTime_flux >= 1 )
1734  time_flux_ratio[nTime_flux] = p.getNumberCheckAlwaysLog("log flux ratio");
1735 
1736  /* this is optional dt to set time step - if not given then initial
1737  * time step is always used */
1738  time_dt[nTime_flux] = p.getNumberDefaultAlwaysLog("log time step",-1.);
1739 
1740  /* if any of these are not specified then do not use times array */
1741  if( time_dt[nTime_flux] < 0.0 )
1742  lgtime_dt_specified = false;
1743 
1744  /* this is optional scale factor to increase time */
1746  "scale factor to increase time",-1.);
1747 
1748  /* turn on recombination front logic */
1749  if( p.nMatch("RECOMBIN") )
1750  {
1751  /* this sets flag dynamics.lgRecom true so that all of code knows recombination
1752  * is taking place */
1753  lgtime_Recom[nTime_flux] = true;
1754  }
1755  else
1756  {
1757  lgtime_Recom[nTime_flux] = false;
1758  }
1759 
1760  /* this is total number stored so far */
1761  ++nTime_flux;
1762 
1763  /* get next line and check for eof */
1764  p.getline();
1765  if( p.m_lgEOF )
1766  {
1767  fprintf( ioQQQ, " Hit EOF while reading line list; use END to end list.\n" );
1769  }
1770 
1771  }
1772 
1773  if( nTime_flux < 2 )
1774  {
1775  fprintf( ioQQQ, " At least two instances of time must be specified. There is an implicit instance at t=0.\n" \
1776  " The user must specify at least one additional time. Sorry.\n" );
1778  }
1779 
1780  for( long i=0; i < nTime_flux; i++ )
1781  {
1782  fprintf( ioQQQ, "DEBUG time dep %.2e %.2e %.2e %.2e\n",
1783  time_elapsed_time[i],
1784  time_flux_ratio[i] ,
1785  time_dt[i],
1787  }
1788  fprintf( ioQQQ, "\n" );
1789  return;
1790 }
1791 /* ============================================================================== */
1792 /* ParseDynaWind parse the wind command, called from ParseCommands */
1794 {
1795  int iVelocity_Type;
1796  bool lgModeSet=false;
1797  /* compiler flagged possible paths where dfdr used but not set -
1798  * this is for safety/keep it happy */
1799  double dfdr=-BIGDOUBLE;
1800 
1801  DEBUG_ENTRY( "ParseDynaWind()" );
1802 
1803  if( p.nMatch( "TRAC" ) )
1804  dynamics.lgTracePrint = true;
1805 
1806  /* Flag for type of velocity law:
1807  * 1 is original, give initial velocity at illuminated face
1808  * 2 is face flux gradient (useful if face velocity is zero),
1809  * set to zero, but will be reset if velocity specified */
1810  iVelocity_Type = 0;
1811  /* wind structure, parameters are initial velocity and optional mass
1812  * v read in in km s-1 and convert to cm s-1, mass in solar masses */
1813  if( p.nMatch( "VELO" ) )
1814  {
1815  wind.windv0 = (realnum)(p.getNumberPlain("velocity")*1e5);
1816  wind.windv = wind.windv0;
1817  wind.setDefault();
1818  iVelocity_Type = 1;
1819  }
1820 
1821  if( p.nMatch( "BALL" ) )
1822  {
1823  wind.setBallistic();
1824  lgModeSet = true;
1825  }
1826 
1827  if( p.nMatch( "STAT" ) )
1828  {
1829  wind.windv0 = 0.;
1830  wind.setStatic();
1831  lgModeSet = true;
1832  iVelocity_Type = 1;
1833  }
1834 
1835  if ( 1 == iVelocity_Type && !lgModeSet)
1836  {
1837  if (wind.windv0 > 0.)
1838  {
1839  fprintf(ioQQQ,"Warning, BALListic option needed to switch off pressure gradient terms\n");
1840  }
1841  else if (wind.windv0 == 0.)
1842  {
1843  fprintf(ioQQQ,"Warning, STATic option needed for zero speed solutions\n");
1844  }
1845  }
1846 
1847  if( p.nMatch("DFDR") )
1848  {
1849  /* velocity not specified, rather mass flux gradient */
1850  dfdr = p.getNumberPlain("flux gradient");
1851  iVelocity_Type = 2;
1852  }
1853 
1854  /* center option, gives xxx */
1855  if( p.nMatch("CENT") )
1856  {
1857  /* physical length in cm, can be either sign */
1858  dynamics.FluxCenter = p.getNumberPlain(
1859  "centre of mass flux distribution");
1860  }
1861 
1862  /* flux index */
1863  if( p.nMatch("INDE") )
1864  {
1865  /* power law index */
1866  dynamics.FluxIndex = p.getNumberPlain(
1867  "power law index of mass flux distribution");
1868  }
1869 
1870  /* the case where velocity was set */
1871  if(iVelocity_Type == 1)
1872  {
1873  /* was flux index also set? */
1874  if(dynamics.FluxIndex == 0)
1875  {
1876  dynamics.FluxScale = wind.windv0;
1877  dynamics.lgFluxDScale = true;
1878  /* Center doesn't mean much in this case -- make sure it's
1879  * in front of grid so DynaFlux doesn't swap signs where
1880  * it shouldn't */
1881  dynamics.FluxCenter = -1.;
1882  }
1883  else
1884  {
1887  /* velocity was set but flux index was not set - estimate it */
1888  dynamics.FluxScale = wind.windv0*
1889  pow(fabs(dynamics.FluxCenter),-dynamics.FluxIndex);
1890 
1891  dynamics.lgFluxDScale = true;
1892  if(dynamics.FluxCenter > 0)
1893  {
1894  dynamics.FluxScale = -dynamics.FluxScale;
1895  }
1896  }
1897  }
1898  /* the case where flux gradient is set */
1899  else if(iVelocity_Type == 2)
1900  {
1901  if(dynamics.FluxIndex == 0)
1902  {
1903  fprintf(ioQQQ,"Can't specify gradient when flux is constant!\n");
1904  /* use this exit handler, which closes out MPI when multiprocessing */
1906  }
1909  /* Can't specify FluxScale from dvdr rather than dfdr, as
1910  * d(rho)/dr != 0 */
1911  dynamics.FluxScale = dfdr/dynamics.FluxIndex*
1912  pow(fabs(dynamics.FluxCenter),1.-dynamics.FluxIndex);
1913  if(dynamics.FluxCenter > 0)
1914  {
1915  dynamics.FluxScale = -dynamics.FluxScale;
1916  }
1917  dynamics.lgFluxDScale = false;
1918 
1919  /* put in bogus value simply as flag -- assume that surface velocity
1920  * is small or we wouldn't be using this to specify. */
1921  wind.windv0 = -0.01f;
1922  wind.setDefault();
1923  }
1924  else
1925  {
1926  /* assume old-style velocity-only specification */
1927  /* wind structure, parameters are initial velocity and optional mass
1928  * v in km/sec, mass in solar masses */
1929  wind.windv0 = (realnum)(p.getNumberCheck("wind velocity")*1e5);
1930  if (wind.windv0 < 0.)
1931  {
1932  wind.setDefault();
1933  }
1934  else if (wind.windv0 > 0.)
1935  {
1936  wind.setBallistic();
1937  }
1938  else
1939  {
1940  wind.setStatic();
1941  }
1942 
1943  dynamics.FluxScale = wind.windv0;
1944  dynamics.FluxIndex = 0.;
1945  dynamics.lgFluxDScale = true;
1946  /* Center doesn't mean much in this case -- make sure it's
1947  * in front of grid so DynaFlux doesn't swap signs where
1948  * it shouldn't */
1949  dynamics.FluxCenter = -1.;
1950  }
1951 
1952  wind.windv = wind.windv0;
1953 
1954 # ifdef FOO
1955  fprintf(ioQQQ,"Scale %g (*%c) Index %g Center %g\n",
1956  dynamics.FluxScale,(dynamics.lgFluxDScale)?'D':'1',
1957  dynamics.FluxIndex,dynamics.FluxCenter);
1958 # endif
1959 
1960  /* option to include advection */
1961  if( p.nMatch( "ADVE" ) )
1962  {
1963  /* set default flags - true says dynamical solution */
1964  advection_set_default(true);
1965  strcpy( dense.chDenseLaw, "DYNA" );
1966  }
1967 
1968  else
1969  {
1970  /* this is usual hypersonic outflow */
1971  if( wind.windv0 <= 1.e6 )
1972  {
1973  /* speed of sound roughly 10 km/s */
1974  fprintf( ioQQQ, " >>>>Initial wind velocity should be greater than speed of sound; calculation only valid above sonic point.\n" );
1975  wind.lgWindOK = false;
1976  }
1977 
1978  /* set the central object mass, in solar masses */
1979  wind.comass = (realnum)p.getNumberDefault("central object mass",1.);
1980  /* default is one solar mass */
1981 
1982  /* option for rotating disk, keyword is disk */
1983  wind.lgDisk = false;
1984  if( p.nMatch( "DISK") )
1985  wind.lgDisk = true;
1986 
1987  strcpy( dense.chDenseLaw, "WIND" );
1988  }
1989 
1990 
1991  /* option to turn off continuum radiative acceleration */
1992  if( p.nMatch("NO CO") )
1993  {
1994  pressure.lgContRadPresOn = false;
1995  }
1996  else
1997  {
1998  pressure.lgContRadPresOn = true;
1999  }
2000  return;
2001 }
2002 
2003 /*DynaPrtZone called to print zone results */
2004 void DynaPrtZone( void )
2005 {
2006 
2007  DEBUG_ENTRY( "DynaPrtZone()" );
2008 
2009  ASSERT( nzone>0 && nzone<struc.nzlim );
2010 
2011  if( nzone > 0 )
2012  {
2013  fprintf(ioQQQ," DYNAMICS Advection: Uad %.2f Uwd%.2e FRCcool: %4.2f Heat %4.2f\n",
2015  wind.windv/1e5 ,
2016  dynamics.Cool()/thermal.ctot,
2017  dynamics.Heat()/thermal.ctot);
2018  }
2019 
2020  ASSERT( EnthalpyDensity[nzone-1] > 0. );
2021 
2022  fprintf(ioQQQ," DYNAMICS Eexcit:%.4e Eion:%.4e Ebin:%.4e Ekin:%.4e ET+pdv %.4e EnthalpyDensity/rho%.4e AdvSpWork%.4e\n",
2027  5./2.*pressure.PresGasCurr ,
2029  );
2030  return;
2031 }
2032 
2033 /*DynaPunchTimeDep - save info about time dependent solution */
2034 void DynaPunchTimeDep( FILE* ipPnunit , const char *chJob )
2035 {
2036 
2037  DEBUG_ENTRY( "DynaPunchTimeDep()" );
2038 
2039  if( strcmp( chJob , "END" ) == 0 )
2040  {
2041  double te_mean,
2042  H2_mean,
2043  H0_mean,
2044  Hp_mean,
2045  Hep_mean;
2046  /* save info at end */
2047  if( cdTemp(
2048  /* four char string, null terminated, giving the element name */
2049  "HYDR",
2050  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
2051  * 0 means that chLabel is a special case */
2052  2,
2053  /* will be temperature */
2054  &te_mean,
2055  /* how to weight the average, must be "VOLUME" or "RADIUS" */
2056  "RADIUS" ) )
2057  {
2058  TotalInsanity();
2059  }
2060  if( cdIonFrac(
2061  /* four char string, null terminated, giving the element name */
2062  "HYDR",
2063  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
2064  * 0 says special case */
2065  2,
2066  /* will be fractional ionization */
2067  &Hp_mean,
2068  /* how to weight the average, must be "VOLUME" or "RADIUS" */
2069  "RADIUS" ,
2070  /* if true then weighting also has electron density, if false then only volume or radius */
2071  false ) )
2072  {
2073  TotalInsanity();
2074  }
2075  if( cdIonFrac(
2076  /* four char string, null terminated, giving the element name */
2077  "HYDR",
2078  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
2079  * 0 says special case */
2080  1,
2081  /* will be fractional ionization */
2082  &H0_mean,
2083  /* how to weight the average, must be "VOLUME" or "RADIUS" */
2084  "RADIUS" ,
2085  /* if true then weighting also has electron density, if false then only volume or radius */
2086  false ) )
2087  {
2088  TotalInsanity();
2089  }
2090  if( cdIonFrac(
2091  /* four char string, null terminated, giving the element name */
2092  "H2 ",
2093  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
2094  * 0 says special case */
2095  0,
2096  /* will be fractional ionization */
2097  &H2_mean,
2098  /* how to weight the average, must be "VOLUME" or "RADIUS" */
2099  "RADIUS" ,
2100  /* if true then weighting also has electron density, if false then only volume or radius */
2101  false ) )
2102  {
2103  TotalInsanity();
2104  }
2105  if( cdIonFrac(
2106  /* four char string, null terminated, giving the element name */
2107  "HELI",
2108  /* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
2109  * 0 says special case */
2110  2,
2111  /* will be fractional ionization */
2112  &Hep_mean,
2113  /* how to weight the average, must be "VOLUME" or "RADIUS" */
2114  "RADIUS" ,
2115  /* if true then weighting also has electron density, if false then only volume or radius */
2116  false ) )
2117  {
2118  TotalInsanity();
2119  }
2120  fprintf( ipPnunit ,
2121  "%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\t%.5e\n" ,
2122  dynamics.time_elapsed ,
2123  dynamics.timestep ,
2125  scalingDensity(),
2126  te_mean ,
2127  Hp_mean ,
2128  H0_mean ,
2129  H2_mean ,
2130  Hep_mean ,
2131  /* ratio of CO to total H column densities */
2132  findspecieslocal("CO")->column / SDIV( colden.colden[ipCOL_HTOT] ),
2135  );
2136  }
2137  else
2138  TotalInsanity();
2139  return;
2140 }
2141 
2142 /*DynaSave save dynamics - info related to advection */
2143 void DynaSave(FILE* ipPnunit , char chJob )
2144 {
2145  DEBUG_ENTRY( "DynaSave()" );
2146 
2147  if( chJob=='a' )
2148  {
2149  /* this is save dynamics advection, the only save dynamics */
2150  fprintf( ipPnunit , "%.5e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\t%.3e\n",
2152  thermal.htot ,
2153  dynamics.Cool() ,
2154  dynamics.Heat() ,
2155  dynamics.dCooldT() ,
2156  dynamics.Source[ipHYDROGEN][ipHYDROGEN],
2157  dynamics.Rate,
2160  );
2161  }
2162  else
2163  TotalInsanity();
2164  return;
2165 }
2166 
2167 #define MERGE 0
2169 {
2170  double heat = Heat_v*scalingDensity();
2171  if (MERGE)
2172  {
2173  double cool = Cool_r*phycon.EnthalpyDensity;
2174  if (heat > cool)
2175  return heat-cool;
2176  else
2177  return 0.;
2178  }
2179  return heat;
2180 }
2181 
2183 {
2184  double cool = Cool_r*phycon.EnthalpyDensity;
2185  if (MERGE)
2186  {
2187  double heat = Heat_v*scalingDensity();
2188  if (heat < cool)
2189  return cool-heat;
2190  else
2191  return 0.;
2192  }
2193  return cool;
2194 }
2195 #undef MERGE
2196 
2198 {
2199  return Cool_r*5./2.*pressure.PresGasCurr/phycon.te;
2200 }
2201 
2202 void DynaIterStart(void)
2203 {
2204  DEBUG_ENTRY( "DynaIterStart()" );
2205 
2206  if( 0 == nTime_flux )
2207  {
2209  return;
2210  }
2211  else if( dynamics.time_elapsed <= time_elapsed_time[0] )
2212  {
2213  /* if very early times not specified assume no flux variation yet */
2215  }
2216  else if( dynamics.time_elapsed > time_elapsed_time[nTime_flux-1] )
2217  {
2218  fprintf( ioQQQ,
2219  " PROBLEM - DynaIterStart - I need the continuum at time %.2e but the table ends at %.2e.\n" ,
2220  dynamics.time_elapsed ,
2223  }
2224  else
2225  {
2227  /* the times in seconds */
2229  /* the rfield.time_continuum_scale factors */
2230  time_flux_ratio,
2231  /* the number of rfield.time_continuum_scale factors */
2232  nTime_flux,
2233  /* the desired time */
2234  dynamics.time_elapsed);
2235  }
2236 
2237  fprintf(ioQQQ,"DEBUG time dep reset continuum iter %ld dynamics.timestep %.2e elapsed time %.2e scale %.2e",
2238  iteration,
2239  dynamics.timestep ,
2240  dynamics.time_elapsed,
2242  if( dynamics.lgRecom )
2243  {
2244  fprintf(ioQQQ," recom");
2245  }
2246  fprintf(ioQQQ,"\n");
2247 
2248  /* make sure that at least one continuum source is variable */
2249  long int nTimeVary = 0;
2250  for( long int i=0; i < rfield.nShape; i++ )
2251  {
2252  /* this is set true if particular continuum source can vary with time
2253  * set true if TIME appears on intensity / luminosity command line */
2254  if( rfield.lgTimeVary[i] )
2255  ++nTimeVary;
2256  }
2257 
2259  {
2260  /* vary extra heating */
2262  fprintf(ioQQQ,"DEBUG TurbHeat vary new heat %.2e\n",
2263  hextra.TurbHeat);
2264  }
2265  else if( !nTimeVary )
2266  {
2267  fprintf(ioQQQ," DISASTER - there were no variable continua "
2268  "or heat sources - put TIME option on at least one "
2269  "luminosity or hextra command.\n");
2271  }
2272 }
2273 
2274 
realnum * hden
Definition: struc.h:25
#define MIN2
Definition: cddefines.h:765
bool nMatch(const char *chKey) const
Definition: parser.h:135
bool lgContRadPresOn
Definition: pressure.h:105
void DynaPrtZone(void)
Definition: dynamics.cpp:2004
t_mole_global mole_global
Definition: mole.cpp:6
long int iter_malloc
Definition: iterations.h:29
double depth
Definition: radius.h:22
static realnum * EnthalpyDensity
Definition: dynamics.cpp:99
void setDefault(void)
Definition: wind.h:82
static double * Upstream_molecules
Definition: dynamics.cpp:66
static realnum *** Old_xIonDense
Definition: dynamics.cpp:122
t_thermal thermal
Definition: thermal.cpp:5
STATIC void advection_set_default(bool lgWind)
Definition: dynamics.cpp:1604
t_colden colden
Definition: colden.cpp:5
static realnum * Old_pressure
Definition: dynamics.cpp:99
double FluxCenter
Definition: dynamics.h:111
double Cool()
Definition: dynamics.cpp:2182
double EdenErrorAllowed
Definition: conv.h:267
void ParseDynaWind(Parser &p)
Definition: dynamics.cpp:1793
double convergence_tolerance
Definition: dynamics.h:156
void DynaIterEnd(void)
Definition: dynamics.cpp:874
NORETURN void TotalInsanity(void)
Definition: service.cpp:886
const double BIGDOUBLE
Definition: cpu.h:181
bool lgWindOK
Definition: wind.h:42
static double *** UpstreamStatesElem
Definition: dynamics.cpp:61
int num_calc
Definition: mole.h:314
t_struc struc
Definition: struc.cpp:6
void DynaCreateArrays(void)
Definition: dynamics.cpp:1395
static realnum ** Old_molecules
Definition: dynamics.cpp:119
bool lgDisk
Definition: wind.h:74
const realnum SMALLFLOAT
Definition: cpu.h:178
const int NISO
Definition: cddefines.h:265
double EnergyIonization
Definition: phycon.h:31
bool lgFluxDScale
Definition: dynamics.h:132
realnum windv0
Definition: wind.h:11
void DynaIterStart(void)
Definition: dynamics.cpp:2202
realnum redshift_step
Definition: cosmology.h:26
void DynaSave(FILE *ipPnunit, char chJob)
Definition: dynamics.cpp:2143
#define MAX2
Definition: cddefines.h:786
double ctot
Definition: thermal.h:110
bool lgMETALS
Definition: dynamics.h:86
bool lgAdvection
Definition: dynamics.h:60
bool lgTimeDependentStatic
Definition: dynamics.h:96
bool lgTracePrint
Definition: dynamics.h:177
int cdIonFrac(const char *chLabel, long int IonStage, double *fracin, const char *chWeight, bool lgDensity)
Definition: cddrive.cpp:1072
t_StopCalc StopCalc
Definition: stopcalc.cpp:5
void DynaStartZone(void)
Definition: dynamics.cpp:401
t_conv conv
Definition: conv.cpp:5
realnum * ednstr
Definition: struc.h:25
t_hextra hextra
Definition: hextra.cpp:5
static double ** UpstreamIon
Definition: dynamics.cpp:60
realnum ** molecules
Definition: struc.h:71
t_phycon phycon
Definition: phycon.cpp:6
double EnthalpyDensity
Definition: phycon.h:40
t_dense dense
Definition: dense.cpp:24
realnum TurbHeatSave
Definition: hextra.h:32
double getNumberDefaultAlwaysLog(const char *chDesc, double fdef)
Definition: parser.cpp:327
int cdTemp(const char *chLabel, long int IonStage, double *TeMean, const char *chWeight)
Definition: cddrive.cpp:1602
double sdrmax
Definition: radius.h:153
FILE * ioQQQ
Definition: cddefines.cpp:7
molezone * findspecieslocal(const char buf[])
long int nzone
Definition: cddefines.cpp:14
static realnum * Old_hiistr
Definition: dynamics.cpp:99
static int ipUpstream
Definition: dynamics.cpp:45
#define NTIME
Definition: dynamics.cpp:78
t_dynamics dynamics
Definition: dynamics.cpp:44
realnum time_continuum_scale
Definition: rfield.h:213
static double * time_dt_scale_factor
Definition: dynamics.cpp:72
bool lgDo
Definition: cosmology.h:44
Definition: parser.h:31
bool lgISO[NISO]
Definition: dynamics.h:83
realnum PressureErrorAllowed
Definition: conv.h:272
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:125
double FluxScale
Definition: dynamics.h:129
bool lgStatic_completed
Definition: dynamics.h:105
double getNumberPlain(const char *chDesc)
Definition: parser.cpp:269
double error_scale2
Definition: dynamics.h:162
double Heat_v
Definition: dynamics.h:63
bool lgTimeVary[LIMSPC]
Definition: rfield.h:306
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:8
realnum * DenMass
Definition: struc.h:25
void DynaEndZone(void)
Definition: dynamics.cpp:853
double Heat()
Definition: dynamics.cpp:2168
static long int nOld_zone
Definition: dynamics.cpp:131
STATIC void DynaNewStep(void)
Definition: dynamics.cpp:1095
Wind wind
Definition: wind.cpp:5
bool lgTemperatureConstant
Definition: thermal.h:32
long int iteration
Definition: cddefines.cpp:16
STATIC double timestep_next(void)
Definition: dynamics.cpp:134
#define MALLOC(exp)
Definition: cddefines.h:505
double * molecules
Definition: dynamics.h:80
double drad
Definition: radius.h:22
static realnum * Old_density
Definition: dynamics.cpp:99
static realnum * Old_ednstr
Definition: dynamics.cpp:99
#define ipCOL_HTOT
Definition: colden.h:12
realnum * depth
Definition: struc.h:25
realnum redshift_current
Definition: cosmology.h:26
double timestep_stop
Definition: dynamics.h:181
static realnum * Old_EnthalpyDensity
Definition: dynamics.cpp:99
#define POW2
Definition: cddefines.h:933
void DynaZero(void)
Definition: dynamics.cpp:1316
#define STATIC
Definition: cddefines.h:101
static double Dyn_dr
Definition: dynamics.cpp:93
void setStatic(void)
Definition: wind.h:88
realnum DynaFlux(double depth)
Definition: dynamics.cpp:1287
realnum TurbHeat
Definition: hextra.h:32
t_mole_local mole
Definition: mole.cpp:7
realnum ConstTemp
Definition: thermal.h:44
t_pressure pressure
Definition: pressure.cpp:5
t_rfield rfield
Definition: rfield.cpp:8
void DynaIonize(void)
Definition: dynamics.cpp:186
long int IonHigh[LIMELM+1]
Definition: dense.h:120
static double * time_elapsed_time
Definition: dynamics.cpp:72
double timestep
Definition: dynamics.h:181
float realnum
Definition: cddefines.h:107
valarray< class molezone > species
Definition: mole.h:355
double dHeatdT
Definition: dynamics.h:63
#define EXIT_FAILURE
Definition: cddefines.h:144
realnum **** StatesElem
Definition: struc.h:67
const realnum BIGFLOAT
Definition: cpu.h:176
bool lgPres_magnetic_ON
Definition: pressure.h:131
bool lgSdrmaxRel
Definition: radius.h:161
bool lgEquilibrium
Definition: dynamics.h:174
double dr_max_last_iter
Definition: radius.h:177
double discretization_error
Definition: dynamics.h:159
bool lgElmtOn[LIMELM]
Definition: dense.h:146
bool lgTurbHeatVaryTime
Definition: hextra.h:66
#define cdEXIT(FAIL)
Definition: cddefines.h:438
STATIC void DynaSaveLast(void)
Definition: dynamics.cpp:1227
bool fp_bound(sys_float lo, sys_float x, sys_float hi, int n=3)
Definition: cddefines.h:881
static realnum * Old_histr
Definition: dynamics.cpp:99
double depth_mid_zone
Definition: radius.h:22
t_iterations iterations
Definition: iterations.cpp:5
void ParseDynaTime(Parser &p)
Definition: dynamics.cpp:1649
double PresGasCurr
Definition: pressure.h:86
realnum HeatCoolRelErrorAllowed
Definition: conv.h:278
static realnum * Old_DenMass
Definition: dynamics.cpp:99
realnum scalingZoneDensity(long i)
Definition: dense.cpp:385
t_radius radius
Definition: radius.cpp:5
t_timesc timesc
Definition: timesc.cpp:5
double dRad
Definition: dynamics.h:138
void setBallistic(void)
Definition: wind.h:94
int strcmp(const char *s2)
Definition: parser.h:177
static realnum * Old_xLyman_depth
Definition: dynamics.cpp:99
static long int nTime_flux
Definition: dynamics.cpp:81
double CoolMax
Definition: dynamics.h:68
double Cool_r
Definition: dynamics.h:63
long int nzlim
Definition: struc.h:19
realnum TempLoStopIteration
Definition: stopcalc.h:45
realnum gas_phase[LIMELM]
Definition: dense.h:71
bool getline(void)
Definition: parser.cpp:164
double timestep_init
Definition: dynamics.h:181
double getNumberCheckAlwaysLogLim(const char *chDesc, double flim)
Definition: parser.cpp:314
long int IonLow[LIMELM+1]
Definition: dense.h:119
#define ASSERT(exp)
Definition: cddefines.h:582
double sound_speed_adiabatic
Definition: timesc.h:45
static realnum ** Old_gas_phase
Definition: dynamics.cpp:125
bool lgSetPresMode
Definition: dynamics.h:166
double error_scale1
Definition: dynamics.h:162
double EnergyBinding
Definition: phycon.h:44
double Rate
Definition: dynamics.h:71
double htot
Definition: thermal.h:149
const int ipH_LIKE
Definition: iso.h:62
const int LIMELM
Definition: cddefines.h:262
char chDenseLaw[5]
Definition: dense.h:158
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
#define isnan
Definition: cddefines.h:624
t_cosmology cosmology
Definition: cosmology.cpp:11
double AdvecLengthInit
Definition: dynamics.h:108
realnum scalingDensity(void)
Definition: dense.cpp:378
double linint(const double x[], const double y[], long n, double xval)
double getNumberCheckAlwaysLog(const char *chDesc)
Definition: parser.cpp:308
double dCooldT()
Definition: dynamics.cpp:2197
double getNumberDefault(const char *chDesc, double fdef)
Definition: parser.cpp:282
double *** StatesElem
Definition: dynamics.h:77
realnum * histr
Definition: struc.h:25
double eden
Definition: dense.h:190
bool lgPredNextTe
Definition: thermal.h:28
bool lgCoolHeat
Definition: dynamics.h:89
double EnergyExcitation
Definition: phycon.h:37
realnum * xLyman_depth
Definition: struc.h:25
realnum xMassDensity0
Definition: dense.h:95
static int iphUpstream
Definition: dynamics.cpp:45
MoleculeList list
Definition: mole.h:317
bool lgRecom
Definition: dynamics.h:102
double ** Source
Definition: dynamics.h:74
realnum GetHubbleFactor(realnum z)
Definition: cosmology.cpp:13
sys_float SDIV(sys_float x)
Definition: cddefines.h:956
double time_elapsed
Definition: dynamics.h:99
long int n_initial_relax
Definition: dynamics.h:126
const int ipCARBON
Definition: cddefines.h:314
bool lgPres_ram_ON
Definition: pressure.h:132
long int nShape
Definition: rfield.h:322
void DynaPunchTimeDep(FILE *ipPnunit, const char *chJob)
Definition: dynamics.cpp:2034
long int numLevels_max
Definition: iso.h:493
bool lgStatic(void) const
Definition: wind.h:24
realnum Upstream_density
Definition: dynamics.h:169
static realnum **** Old_StatesElem
Definition: dynamics.cpp:128
#define MERGE
Definition: dynamics.cpp:2167
double timestep_factor
Definition: dynamics.h:181
static double * time_flux_ratio
Definition: dynamics.cpp:72
bool m_lgEOF
Definition: parser.h:42
double convergence_error
Definition: dynamics.h:153
realnum xMassDensity
Definition: dense.h:91
double te
Definition: phycon.h:11
const int ipHYDROGEN
Definition: cddefines.h:309
void fixit(void)
Definition: service.cpp:991
realnum * hiistr
Definition: struc.h:25
static double AdvecSpecificEnthalpy
Definition: dynamics.cpp:96
realnum colden[NCOLD]
Definition: colden.h:38
double HeatMax
Definition: dynamics.h:68
double oldFullDepth
Definition: dynamics.h:141
static realnum * Old_depth
Definition: dynamics.cpp:99
realnum *** xIonDense
Definition: struc.h:64
bool lg_coronal_time_init
Definition: dynamics.h:93
bool lgPres_radiation_ON
Definition: pressure.h:130
long int numLevels_local
Definition: iso.h:498
int * lgtime_Recom
Definition: dynamics.cpp:77
realnum windv
Definition: wind.h:18
realnum comass
Definition: wind.h:14
double FluxIndex
Definition: dynamics.h:135
static int ipyUpstream
Definition: dynamics.cpp:45
bool lgtime_dt_specified
Definition: dynamics.cpp:76
realnum DivergePresInteg
Definition: dynamics.h:171
static double * time_dt
Definition: dynamics.cpp:72
static double * UpstreamElem
Definition: dynamics.cpp:63
realnum TempHiStopIteration
Definition: stopcalc.h:38
realnum * pressure
Definition: struc.h:25
double * StopThickness
Definition: radius.h:22
double getNumberCheck(const char *chDesc)
Definition: parser.cpp:273