cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
conv_eden_ioniz.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 /*ConvEdenIoniz called by ConvTempIonz, calls ConvIoniz solving for eden */
4 /*lgConvEden returns true if electron density is converged */
5 /*EdenError evaluate ConvIoniz() until ionization has converged and return error on eden */
6 #include "cddefines.h"
7 #include "dense.h"
8 #include "trace.h"
9 #include "thermal.h"
10 #include "thirdparty.h"
11 #include "phycon.h"
12 #include "conv.h"
13 
14 /*lgConvEden returns true if electron density is converged */
15 STATIC bool lgConvEden(void);
16 /*EdenError evaluate ConvIoniz() until ionization has converged and return error on eden */
17 STATIC double EdenError(double eden);
18 
19 /*ConvEdenIoniz called by ConvTempEdenIoniz, calls ConvIoniz solving for eden
20  * returns 0 if ok, 1 if abort */
21 int ConvEdenIoniz(void)
22 {
23  DEBUG_ENTRY( "ConvEdenIoniz()" );
24 
25  /* this routine is called by ConvTempEdenIoniz, it calls ConvIoniz
26  * and changes the electron density until it converges */
27 
28  if( trace.lgTrace )
29  {
30  fprintf( ioQQQ, "\n" );
31  fprintf( ioQQQ, " ConvEdenIoniz entered\n" );
32  }
33  if( trace.nTrConvg>=3 )
34  {
35  fprintf( ioQQQ,
36  " ConvEdenIoniz called, entering eden loop using solver %s.\n",
38  }
39 
40  /* save entry value of eden */
41  double EdenEntry = dense.eden;
42 
43  // this branch uses the van Wijngaarden-Dekker-Brent method
44  if( strcmp( conv.chSolverEden , "vWDB" )== 0 )
45  {
46  conv.lgConvEden = false;
47 
48  iter_track NeTrack;
49  double n1, error1, n2, error2;
50 
51  for( int n=0; n < 3; ++n )
52  {
53  const int DEF_ITER = 10;
54  // this is the maximum relative step in eden
55  const double factor = 0.02;
56 
57  NeTrack.clear();
58 
59  // when dense.EdenTrue becomes negative, error1 > n1 (since n1 > 0.)
60  // a straight copy EdenTrue -> eden would then imply a step > 100% down
61  // all of the code below will cap that to n1*(1.-factor), and eden stays > 0.
62  // this is also asserted in EdenError, the ONLY place where dense.eden is set
63 
64  n1 = dense.eden;
65  error1 = EdenError( n1 );
66  NeTrack.add( n1, error1 );
67 
69  n2 = sqrt(dense.eden*dense.EdenTrue);
70  else if( abs(safe_div( error1, n1 )) < factor )
71  n2 = dense.EdenTrue;
72  else
73  n2 = ( error1 > 0. ) ? n1*(1.-factor) : n1*(1.+factor);
74 
75  // n1 == n2 will occur if SET EDEN command was given
76  if( !fp_equal( n1, n2 ) )
77  error2 = EdenError( n2 );
78  else
79  error2 = error1;
80  NeTrack.add( n2, error2 );
81 
82  int j = 0;
83 
84  // now hunt until we have bracketed the solution
85  while( error1*error2 > 0. && j++ < DEF_ITER )
86  {
87  n1 = n2;
88  error1 = error2;
89  double deriv = NeTrack.deriv(5);
90  // the factor 1.2 creates 20% safety margin
91  double step = safe_div( -1.2*error1, deriv, 0. );
92  step = sign( min( abs(step), factor*n1 ), step );
93  n2 = n1 + step;
94  error2 = EdenError( n2 );
95  NeTrack.add( n2, error2 );
96  }
97 
98  if( error1*error2 > 0. && trace.nTrConvg >= 3 )
99  {
100  fprintf( ioQQQ, " ConvEdenIoniz: bracket failure 1 n1: %e %e n2: %e %e\n",
101  n1, error1, n2, error2 );
102  NeTrack.print_history();
103  }
104 
105  // using the derivative failed, so simply start hunting up or downwards
106  // we may need to take a big step, so max_iter should be big
107  while( error1*error2 > 0. && j++ < 20*DEF_ITER )
108  {
109  n1 = n2;
110  error1 = error2;
111  n2 = ( error1 > 0. ) ? n1*(1.-factor) : n1*(1.+factor);
112  error2 = EdenError( n2 );
113  NeTrack.add( n2, error2 );
114  }
115 
116  if( error1*error2 > 0. && trace.nTrConvg >= 3 )
117  {
118  fprintf( ioQQQ, " ConvEdenIoniz: bracket failure 2 n1: %e %e n2: %e %e\n",
119  n1, error1, n2, error2 );
120  NeTrack.print_history();
121  }
122 
123  NeTrack.clear();
124 
125  // the bracket should have been found, now set up the Brent solver
126  if( NeTrack.init_bracket( n1, error1, n2, error2 ) == 0 )
127  {
128  // set tolerance to 2 ulp; if bracket gets narrower than 3 ulp we declare
129  // a convergence failure to avoid changes getting lost in machine precision
130  NeTrack.set_tol(2.*DBL_EPSILON*n2);
131 
132  double NeNew = 0.5*(n1+n2);
133  for( int i = 0; i < (1<<(n/2))*DEF_ITER; i++ )
134  {
135  // check for convergence, as well as a pathologically narrow bracket
136  if( lgConvEden() || NeTrack.bracket_width() < 3.*DBL_EPSILON*n2 )
137  break;
138 
139  NeTrack.add( NeNew, EdenError( NeNew ) );
140  NeNew = NeTrack.next_val(factor);
141  }
142  }
143 
144  if( conv.lgConvEden )
145  break;
146 
147  if( trace.nTrConvg >= 3 )
148  {
149  fprintf( ioQQQ, " ConvEdenIoniz: brent fails\n" );
150  NeTrack.print_history();
151  }
152  }
153 
154  if( trace.lgTrace || trace.nTrConvg >= 3 )
155  {
156  fprintf( ioQQQ, " ConvEdenIoniz: entry eden %.4e -> %.4e rel chng %.2f%% accuracy %.2f%%\n",
157  EdenEntry, dense.eden, (safe_div(dense.eden,EdenEntry,1.)-1.)*100.,
158  (safe_div(dense.eden,dense.EdenTrue,1.)-1.)*100. );
159  fprintf( ioQQQ, " ConvEdenIoniz returns converged=%c reason %s\n",
161  }
162  }
163  else
164  {
165  fprintf( ioQQQ, "ConvEdenIoniz finds insane solver %s\n", conv.chSolverEden );
166  ShowMe();
167  }
168 
169  return 0;
170 }
171 
172 /* returns true if electron density is converged */
173 STATIC bool lgConvEden(void)
174 {
176  if( !conv.lgConvEden )
177  {
178  conv.setConvIonizFail( "Ne big chg" , dense.EdenTrue, dense.eden);
179  }
180  return conv.lgConvEden;
181 }
182 
183 /* evaluate ConvIoniz() until ionization has converged and return error on eden */
184 STATIC double EdenError(double eden)
185 {
186  // don't let electron density be zero - logs are taken
187  ASSERT( eden > 0. );
188 
189  // this is the only place where the new electron density is set
191  EdenChange( eden );
192 
193  for( int i=0; i < 5; ++i )
194  {
195  if( ConvIoniz() )
196  lgAbort = true;
197 
198  if( conv.lgConvIoniz() )
199  break;
200  }
201 
202  double error = dense.eden - dense.EdenTrue;
203 
204  if( trace.nTrConvg >= 3 )
205  fprintf( ioQQQ, " EdenError: eden %.4e EdenTrue %.4e rel. err. %.4e\n",
207 
208  return error;
209 }
210 
bool lgConvEden
Definition: conv.h:202
double EdenErrorAllowed
Definition: conv.h:267
double bracket_width() const
Definition: iter_track.h:85
double next_val()
Definition: iter_track.cpp:18
void add(double x, double fx)
Definition: iter_track.h:120
const realnum SMALLFLOAT
Definition: cpu.h:178
void print_history() const
Definition: iter_track.h:177
char TorF(bool l)
Definition: cddefines.h:714
t_conv conv
Definition: conv.cpp:5
T sign(T x, T y)
Definition: cddefines.h:804
t_dense dense
Definition: dense.cpp:24
FILE * ioQQQ
Definition: cddefines.cpp:7
bool lgConvIoniz() const
Definition: conv.h:115
void incrementCounter(const counter_type type)
Definition: conv.h:308
STATIC double EdenError(double eden)
bool lgSearch
Definition: conv.h:175
t_trace trace
Definition: trace.cpp:5
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:816
const char * chConvIoniz() const
Definition: conv.h:119
int init_bracket(double x1, double fx1, double x2, double fx2)
Definition: iter_track.h:104
#define STATIC
Definition: cddefines.h:101
bool lgTrace
Definition: trace.h:12
long min(int a, long b)
Definition: cddefines.h:727
STATIC bool lgConvEden(void)
sys_float safe_div(sys_float x, sys_float y, sys_float res_0by0)
Definition: cddefines.h:965
int nTrConvg
Definition: trace.h:27
#define ASSERT(exp)
Definition: cddefines.h:582
void clear()
Definition: iter_track.h:76
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:688
double eden
Definition: dense.h:190
double EdenTrue
Definition: dense.h:221
int ConvIoniz(void)
Definition: conv_ioniz.cpp:11
double deriv(int n, double &sigma) const
Definition: iter_track.cpp:145
void setConvIonizFail(const char *reason, double oldval, double newval)
Definition: conv.h:107
void EdenChange(double EdenNew)
Definition: eden_change.cpp:12
void ShowMe(void)
Definition: service.cpp:181
char chSolverEden[20]
Definition: conv.h:245
void set_tol(double tol)
Definition: iter_track.h:81
int ConvEdenIoniz(void)
bool lgAbort
Definition: cddefines.cpp:10