cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
conv_pres_temp_eden_ioniz.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2022 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*ConvPresTempEdenIoniz solve for current pressure, calls PressureChange, ConvTempEdenIonize,
4  * called by cloudy */
5 /*ConvFail handle convergence failure */
6 #include "cddefines.h"
7 
8 #include "phycon.h"
9 #include "rt.h"
10 #include "dense.h"
11 #include "pressure.h"
12 #include "trace.h"
13 #include "conv.h"
14 #include "pressure_change.h"
15 #include "thermal.h"
16 #include "geometry.h"
17 #include "grainvar.h"
18 #include "grains.h"
19 
20 /*ConvPresTempEdenIoniz solve for current pressure, calls PressureChange, ConvTempEdenIoniz,
21  * called by cloudy
22  * returns 0 if ok, 1 if disaster */
24 {
25  DEBUG_ENTRY( "ConvPresTempEdenIoniz()" );
26 
27  /* this will count number of times we call ConvBase in this zone,
28  * counter is incremented there
29  * zero indicates first pass through solvers on this zone */
30  conv.nPres2Ioniz = 0;
32  conv.lgLastSweepThisZone = false;
33  /* this will save the history of density - pressure relationship
34  * for the current zone */
35  if( nzone != conv.hist_pres_nzone )
36  {
37  /* first time in this zone - reset history */
39  conv.hist_pres_density.clear();
40  conv.hist_pres_current.clear();
41  conv.hist_pres_error.clear();
42  }
43 
44  /* should still be true at end */
45  conv.lgConvPops = true;
46 
47  /*rel_slope = 0.;*/
48 
49  if( trace.nTrConvg>=1 )
50  {
51  fprintf( ioQQQ,
52  " ConvPresTempEdenIoniz1 entered, will call ConvIoniz to initialize\n");
53  }
54 
55  /* converge the ionization first, so that we know where we are, and have
56  * a valid foundation to begin the search */
57  /* the true electron density dense.EdenTrue is set in eden_sum called by ConvBase */
58 
59  /* this evaluates current pressure, and returns whether or not
60  * it is within tolerance of correct pressure */
61  conv.lgConvPres = false;
62 
63  /* convergence trace at this level */
64  if( trace.nTrConvg>=1 )
65  {
66  fprintf( ioQQQ,
67  " ConvPresTempEdenIoniz1 ConvIoniz found following converged: Pres:%c, Temp:%c, Eden:%c, Ion:%c, Pops:%c\n",
73  }
74 
75  /* trace convergence print at this level */
76  if( trace.nTrConvg>=1 )
77  {
78  fprintf( ioQQQ,
79  "\n ConvPresTempEdenIoniz1 entering main pressure loop.\n");
80  }
81 
82  AbundChange();
83 
84  if ( strcmp(dense.chDenseLaw,"CPRE") == 0 ||
85  strcmp(dense.chDenseLaw,"DYNA") == 0 )
86  {
87  /* set the initial temperature to the current value, so we will know
88  * if we are trying to jump over a thermal front */
89  double TemperatureInitial = phycon.te;
90 
91  /* chng 02 dec 11 rjrw -- ConvIoniz => ConvTempEdenIoniz() here for consistency with inside loop */
92  /* ConvIoniz; */
93  if( ConvTempEdenIoniz() )
94  {
95  return 1;
96  }
97 
98  PresMode presmode;
99  presmode.set();
100  solverState st;
101  st.press = pressureZone(presmode);
102 
103  /* this will be flag to check for pressure oscillations */
104  bool lgPresOscil = false;
105  bool lgStable = true;
106  /* this is loop where it happened */
107  long nloop_pres_oscil = 0;
108  /* we will use these to check whether hden oscillating - would need to decrease step size */
109  double hden_chng = 0.;
110  /* this is dP_chng_factor, cut in half when pressure error changes sign */
111  double dP_chng_factor = 1.;
112 
113  /* the limit to the number of loops */
114  const int LOOPMAX = 100;
115  /* this will be the limit, which we will increase if no oscillations occur */
116  long LoopMax = LOOPMAX;
117  long loop = 0;
118 
119  /* if start of calculation and we are solving for set pressure,
120  * allow a lot more iterations */
122  LoopMax = 10*LOOPMAX;
123 
124  while( (loop < LoopMax) && !conv.lgConvPres && !lgAbort )
125  {
126  /* there can be a pressure or density oscillation early in the search - if not persistent
127  * ok to clear flag */
128  /* >>chng 01 aug 24, if large change in temperature allow lots more loops */
129  if( fabs( TemperatureInitial - phycon.te )/phycon.te > 0.3 )
130  LoopMax = 2*LOOPMAX;
131 
132  /* change current densities of all constituents if necessary,
133  * PressureChange evaluates lgPresOK, true if pressure is now ok
134  * sets CurrentPressure and CorrectPressure */
135  double hden_old = dense.gas_phase[ipHYDROGEN];
136  /*pres_old = pressure.PresTotlCurr;*/
137 
138  /* this will evaluate current pressure, update the densities,
139  * determine the wind velocity, and set conv.lgConvPres,
140  * return value is true if density was changed, false if no changes were necessary
141  * if density changes then we must redo the temperature and ionization
142  * PressureChange contains the logic that determines how to change the density to get
143  * the right pressure */
144 
145  static ConvergenceCounter cctr=conv.register_("PRES_CHANGES");
146  ++cctr;
147  bool lgAbortPressure;
148  PressureChange(dP_chng_factor, presmode, st, lgAbortPressure, lgStable);
149  if( lgAbortPressure )
150  {
151  return 1;
152  }
153 
154  /* if product of these two is negative then hden is oscillating */
155  double hden_chng_old = hden_chng;
156  hden_chng = dense.gas_phase[ipHYDROGEN] - hden_old;
157  if( fabs(hden_chng) < SMALLFLOAT )
158  hden_chng = sign( (double)SMALLFLOAT, hden_chng );
159 
160  {
161  /*@-redef@*/
162  enum{DEBUG_LOC=false};
163  /*@+redef@*/
164  if( DEBUG_LOC && nzone > 150 && iteration > 1 )
165  {
166  fprintf(ioQQQ,"%li\t%.2e\t%.2e\n",
167  nzone,
170  );
171  }
172  }
173 
174  /* check whether pressure is oscillating */
175  if( ( ( hden_chng*hden_chng_old < 0. ) ) && loop > 1 )
176  {
177  /*fprintf(ioQQQ,"DEBUG\t%.2f\t%.2e\t%.2e\t%.2e\t%.2e\n",
178  fnzone,pres_chng,pres_chng_old ,hden_chng,hden_chng_old);*/
179  lgPresOscil = true;
180  nloop_pres_oscil = loop;
181  /* >>chng 04 dec 09, go to this factor becoming smaller every time oscillation occurs */
182  dP_chng_factor = MAX2( 0.125, dP_chng_factor * 0.5 );
183  /* dP_chng_factor is how pressure changes with density - pass this to
184  * changing routine if it is stable */
185 
186  /*fprintf(ioQQQ,"oscilll %li %.2e %.2e %.2e %.2e dP_chng_factor %.2e\n",
187  loop ,
188  pres_chng,
189  pres_chng_old,
190  hden_chng ,
191  hden_chng_old ,
192  rel_slope);*/
193  }
194 
195  /* convergence trace at this level */
196  if( trace.nTrConvg>=1 )
197  {
198  fprintf( ioQQQ,
199  " ConvPresTempEdenIoniz1 %ld l:%3li nH:%.4e ne:%.4e PCurnt:%.4e err:%6.3f%% dPf:%.2e Te:%.4e Osc:%c Stb:%c\n",
200  nzone,
201  loop,
203  dense.eden,
205  /* this is percentage error */
206  100.*pressure.PresTotlError,
207  dP_chng_factor ,
208  phycon.te,
209  TorF(lgPresOscil),
210  TorF(lgStable)
211  );
212  }
213 
214  /* increment loop counter */
215  ++loop;
216 
217  /* there can be a pressure or density oscillation early in the search - if not persistent
218  * ok to clear flag */
219  if( loop - nloop_pres_oscil > 4 )
220  lgPresOscil = false;
221 
222  /* if we hit limit of loop, but no oscillations have happened, then we are
223  * making progress, and can keep going */
224  if( loop == LoopMax && !lgPresOscil )
225  {
226  LoopMax = MIN2( LOOPMAX, LoopMax*2 );
227  }
228  }
229  }
230  else
231  {
232  double targetDensity = zoneDensity();
233  double startingDensity = scalingDensity();
235 
236  double logRatio = log(targetDensity/startingDensity);
237  long nstep = (long) ceil(fabs(logRatio)/pdelta);
238  // Ensure at least one update per zone
239  if (nstep == 0)
240  nstep = 1;
241  double density_change_factor = exp(logRatio/nstep);
242 
243  for (long i=0; i<nstep; i++)
244  {
245  if (i == nstep - 1)
246  {
247  // Try to ensure exact answer at last iteration
248  density_change_factor = targetDensity/scalingDensity();
249  }
250 
251  /* this will evaluate current pressure, update the densities,
252  * determine the wind velocity, and set conv.lgConvPres,
253  * return value is true if density was changed, false if no changes were necessary
254  * if density changes then we must redo the temperature and ionization */
255 
256  /* >>chng 04 feb 11, add option to remember current density and pressure */
260 
261  if( trace.lgTrace )
262  {
263  fprintf( ioQQQ,
264  " DensityUpdate called, changing HDEN from %10.3e to %10.3e Set fill fac to %10.3e\n",
265  dense.gas_phase[ipHYDROGEN], density_change_factor*dense.gas_phase[ipHYDROGEN],
266  geometry.FillFac );
267  }
268 
269  ScaleAllDensities((realnum) density_change_factor);
270 
271  /* must call TempChange since ionization has changed, there are some
272  * terms that affect collision rates (H0 term in electron collision) */
273  TempChange(phycon.te , false);
274 
275  /* heating cooling balance while doing ionization, this is
276  * where the heavy lifting is done, this calls
277  * PresTotCurrent, which sets pressure.PresTotlCurr */
278  if( ConvTempEdenIoniz() )
279  {
280  return 1;
281  }
282 
283  /* convergence trace at this level */
284  if( trace.nTrConvg>=1 )
285  {
286  fprintf( ioQQQ,
287  " ConvPresTempEdenIoniz1 %.2f l:%3li nH:%.4e ne:%.4e PCurnt:%.4e err:%6.3f%% Te:%.4e Osc:%c\n",
288  fnzone,
289  i,
291  dense.eden,
293  /* this is percentage error */
294  100.*pressure.PresTotlError,
295  phycon.te,
296  TorF(false) );
297  }
298  }
299 
300  PresTotCurrent();
301 
302  conv.lgConvPres = true;
303  }
304  /* keep track of minimum and maximum temperature */
307 
308  /* >>chng 04 jan 31, now that all of the physics is converged, determine grain drift velocity */
309  if( gv.lgDustOn() && gv.lgGrainPhysicsOn )
310  GrainDrift();
311 
312  /* >>chng 01 mar 14, all ConvFail one more time, no matter how
313  * many failures occurred below. Had been series of if, so multiple
314  * calls per failure possible. */
315  /* >>chng 04 au 07, only announce pres fail here,
316  * we did not converge the pressure */
317  if( !conv.lgConvIoniz() )
318  ConvFail("ioni","");
319  else if( !conv.lgConvEden )
320  ConvFail("eden","");
321  else if( !conv.lgConvTemp )
322  ConvFail("temp","");
323  else if( !conv.lgConvPres )
324  ConvFail("pres","");
325 
326  /* this is only a sanity check that the summed continua accurately
327  * reflect all of the individual components. Only include this
328  * when NDEBUG is not set, we are in not debug compile */
329 # if !defined(NDEBUG)
330  RT_OTS_ChkSum(0);
331 # endif
332 
333  return 0;
334 }
void RT_OTS_ChkSum(long int ipPnt)
Definition: rt_ots.cpp:606
bool lgConvEden
Definition: conv.h:195
vector< double > hist_pres_density
Definition: conv.h:291
t_thermal thermal
Definition: thermal.cpp:6
double MaxFractionalDensityStepPerIteration
Definition: conv.h:270
double pressureZone(const PresMode &presmode)
vector< double > hist_pres_error
Definition: conv.h:291
void PressureChange(double dP_chng_factor, const PresMode &presmode, solverState &st, bool &lgAbort, bool &lgStable)
const realnum SMALLFLOAT
Definition: cpu.h:246
bool lgFirstSweepThisZone
Definition: conv.h:148
ConvergenceCounter register_(const string name)
Definition: conv.cpp:87
char TorF(bool l)
Definition: cddefines.h:749
bool lgConvPres
Definition: conv.h:192
t_conv conv
Definition: conv.cpp:5
T sign(T x, T y)
Definition: cddefines.h:842
t_phycon phycon
Definition: phycon.cpp:6
bool lgConvPops
Definition: conv.h:136
FILE * ioQQQ
Definition: cddefines.cpp:7
realnum FillFac
Definition: geometry.h:29
long int nzone
Definition: cddefines.cpp:14
bool lgConvIoniz() const
Definition: conv.h:108
#define MIN2(a, b)
Definition: cddefines.h:803
double PresTotlCurr
Definition: pressure.h:46
double zoneDensity()
void TempChange(double TempNew, bool lgForceUpdate)
Definition: temp_change.cpp:32
int ConvTempEdenIoniz(void)
void GrainDrift()
Definition: grains.cpp:4968
t_dense dense
Definition: global.cpp:15
void PresTotCurrent(void)
long int iteration
Definition: cddefines.cpp:16
t_trace trace
Definition: trace.cpp:5
t_geometry geometry
Definition: geometry.cpp:5
void ScaleAllDensities(realnum factor)
Definition: dense.cpp:56
long int nPres2Ioniz
Definition: conv.h:145
bool lgTrace
Definition: trace.h:12
realnum tlowst
Definition: thermal.h:68
vector< double > hist_pres_current
Definition: conv.h:291
t_pressure pressure
Definition: pressure.cpp:9
float realnum
Definition: cddefines.h:124
long max(int a, long b)
Definition: cddefines.h:817
realnum thist
Definition: thermal.h:68
long min(int a, long b)
Definition: cddefines.h:762
bool lgGrainPhysicsOn
Definition: grainvar.h:479
double PresTotlError
Definition: pressure.h:46
bool AbundChange()
Definition: dense.cpp:300
int nTrConvg
Definition: trace.h:27
long int hist_pres_nzone
Definition: conv.h:292
void ConvFail(const char chMode[], const char chDetail[])
Definition: conv_fail.cpp:16
realnum gas_phase[LIMELM]
Definition: dense.h:76
char chDenseLaw[5]
Definition: dense.h:176
bool lgConvTemp
Definition: conv.h:189
bool lgPressureInitialSpecified
Definition: pressure.h:56
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
realnum scalingDensity(void)
Definition: dense.cpp:409
int ConvPresTempEdenIoniz(void)
double eden
Definition: dense.h:201
#define MAX2(a, b)
Definition: cddefines.h:824
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
bool lgLastSweepThisZone
Definition: conv.h:150
GrainVar gv
Definition: grainvar.cpp:5
double fnzone
Definition: cddefines.cpp:15
double te
Definition: phycon.h:21
bool lgDustOn() const
Definition: grainvar.h:475
const int ipHYDROGEN
Definition: cddefines.h:349
bool lgAbort
Definition: cddefines.cpp:10