cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TestIterTrack.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 #include <UnitTest++.h>
4 #include "cddefines.h"
5 #include "iter_track.h"
6 
7 namespace {
8  // test a function that would have gone into a limit cycle
9  TEST(IterTrackBasicFloat)
10  {
12  sys_float x = 1.f;
13  sys_float xnew = 2.f;
14  while( abs(x-xnew) > 2.f*FLT_EPSILON*abs(x) )
15  {
16  x = xnew;
17  // derivative at root is -1
18  xnew = track.next_val( x, 2.f/x );
19  }
20  CHECK( fp_equal( xnew, (sys_float)sqrt(2.) ) );
21  // now clear the tracker and try again
22  track.clear();
23  x = 1.f;
24  xnew = 2.f;
25  while( abs(x-xnew) > 2.f*FLT_EPSILON*abs(x) )
26  {
27  x = xnew;
28  // derivative at root is -1
29  xnew = track.next_val( x, 3.f/x );
30  }
31  CHECK( fp_equal( xnew, (sys_float)sqrt(3.) ) );
32  }
33 
34  // now test the same for doubles
35  TEST(IterTrackBasicDouble)
36  {
38  double x = 1.;
39  double xnew = 2.;
40  while( abs(x-xnew) > 2.*DBL_EPSILON*abs(x) )
41  {
42  x = xnew;
43  // derivative at root is -1
44  xnew = track.next_val( x, 2./x );
45  }
46  CHECK( fp_equal( xnew, sqrt(2.) ) );
47  }
48 
49  // test a function that would have diverged
50  TEST(IterTrackBasicUnstable)
51  {
53  double x = 1.;
54  double xnew = 2.;
55  while( abs(x-xnew) > 2.*DBL_EPSILON*abs(x) )
56  {
57  x = xnew;
58  // derivative at root is -5
59  xnew = track.next_val( x, 1./x - 2.*x );
60  }
61  // possible solutions are +/-sqrt(1/3), either one may be found
62  CHECK( fp_equal( abs(xnew), 1./sqrt(3.) ) );
63  }
64 
65  // test a function that would have converged anyway
66  TEST(IterTrackBasicStableNeg)
67  {
69  double x = 1.;
70  double xnew = 2.;
71  // this would have diverged without iter_tracking
72  while( abs(x-xnew) > 2.*DBL_EPSILON*abs(x) )
73  {
74  x = xnew;
75  // derivative at root is -1/3
76  xnew = track.next_val( x, 1./x + x/3. );
77  }
78  CHECK( fp_equal( xnew, sqrt(1.5) ) );
79  }
80 
81  TEST(IterTrackBasicStablePos)
82  {
84  double x = 1.;
85  double xnew = 2.;
86  // this would have diverged without iter_tracking
87  while( abs(x-xnew) > 2.*DBL_EPSILON*abs(x) )
88  {
89  x = xnew;
90  // derivative at root is 1/3
91  xnew = track.next_val( x, 1./x + 2.*x/3. );
92  }
93  CHECK( fp_equal( xnew, sqrt(3.) ) );
94  }
95 
96  double testfun(double x)
97  {
98  return sin(x)-0.5;
99  }
100 
101  TEST(IterTrack)
102  {
103  double x1, fx1, x2, fx2, x3, fx3;
104  iter_track track;
105  x1 = 0.;
106  fx1 = testfun(x1);
107  x3 = 1.5;
108  fx3 = testfun(x3);
109  double tol = 1.e-12;
110  track.set_tol(tol);
111  CHECK_EQUAL( 0, track.init_bracket(x1,fx1,x3,fx3) );
112  CHECK( fp_equal( track.bracket_width(), abs(x3-x1) ) );
113  CHECK( !track.lgConverged() );
114  x2 = 0.5*(x1+x3);
115  fx2 = testfun(x2);
116  track.add( x2, fx2 );
117  double xnew = track.next_val(0.01);
118  CHECK( fp_equal_tol( abs(xnew/x2-1.), 0.01, 1.e-12 ) );
119  const int navg = 5;
120  vector<double> xvals( navg ); // keep track of the last navg x-values
121  for( int i=0; i < 100 && !track.lgConverged(); ++i )
122  {
123  x2 = track.next_val();
124  fx2 = testfun(x2);
125  track.add( x2, fx2 );
126  // use xvals as circular buffer
127  xvals[i%navg] = x2;
128  }
129  CHECK( track.lgConverged() );
130  double exact_root = asin(0.5);
131  CHECK( fp_equal_tol( track.root(), exact_root, tol ) );
132  double sigma;
133  double val = track.deriv( navg, sigma );
134  double delta_lo = *min_element( xvals.begin(), xvals.end() ) - exact_root;
135  double delta_hi = *max_element( xvals.begin(), xvals.end() ) - exact_root;
136  CHECK( delta_lo < 0. );
137  CHECK( delta_hi > 0. );
138  // the exact derivative at the root is sqrt(3)/2 = 0.8660254...
139  // the exact 2nd derivative at the root is -1/2
140  double err_lo = -0.5*delta_lo;
141  double err_hi = -0.5*delta_hi;
142  CHECK( fp_bound( sqrt(3.)/2.+err_hi, val, sqrt(3.)/2.+err_lo ) );
143  // the tangent at the exact root is given by asin(0.5) + sqrt(3)/2*(x-x0)
144  // if we subtract that from the Taylor expansion of testfun we get:
145  // residual = -1/4*(x-x0)^2 + O((x-x0)^3), hence sigma should be less
146  // than the maximum absolute value of -1/4*(x-x0)^2 (the actual fit
147  // should run slightly closer to the maximum deviant value than the tangent).
148  CHECK( sigma < max( pow2(err_lo), pow2(err_hi) ) );
149  // ask for more points than are available to see if that is handled correctly
150  val = track.deriv( 200 );
151  double val2 = track.deriv();
152  CHECK( fp_equal( val, val2 ) );
153  val = track.deriv( 200, sigma );
154  double sigma2;
155  val = track.deriv( sigma2 );
156  CHECK( fp_equal( sigma, sigma2 ) );
157 
158  // now do the same thing for the zero_fit() methods...
159  val = track.zero_fit( navg, sigma );
160  // the exact root is asin(0.5) = 0.52359877...
161  CHECK( fp_equal_tol( exact_root, val, 2.*sigma ) );
162  val = track.zero_fit( 200 );
163  val2 = track.zero_fit();
164  CHECK( fp_equal( val, val2 ) );
165  val = track.zero_fit( 200, sigma );
166  val = track.zero_fit( sigma2 );
167  CHECK( fp_equal( sigma, sigma2 ) );
168  }
169 
170  // this is the short version of the above...
171  TEST(AmsterdamMethod)
172  {
173  double x1, fx1, x2, fx2;
174  x1 = 0.;
175  fx1 = testfun(x1);
176  x2 = 1.5;
177  fx2 = testfun(x2);
178  double tol = 1.e-12;
179  int err = -1;
180  double x = Amsterdam_Method( testfun, x1, fx1, x2, fx2, tol, 1000, err );
181  CHECK_EQUAL( 0, err );
182  CHECK( fp_equal_tol( x, asin(0.5), tol ) );
183  }
184 
185  // now test some unstable functions
186  double testfun2(double x)
187  {
188  return exp(x)-3.;
189  }
190 
191  // the derivative at the root is 3
192  TEST(AmsterdamMethod2)
193  {
194  double x1, fx1, x2, fx2;
195  x1 = 0.;
196  fx1 = testfun2(x1);
197  x2 = 3.;
198  fx2 = testfun2(x2);
199  double tol = 1.e-12;
200  int err = -1;
201  double x = Amsterdam_Method( testfun2, x1, fx1, x2, fx2, tol, 1000, err );
202  CHECK_EQUAL( 0, err );
203  CHECK( fp_equal_tol( x, log(3.), tol ) );
204  }
205 
206  double testfun3(double x)
207  {
208  return 1./x - 2.*x;
209  }
210 
211  // the derivative at the root is -4
212  TEST(AmsterdamMethod3)
213  {
214  double x1, fx1, x2, fx2;
215  x1 = 0.1;
216  fx1 = testfun3(x1);
217  x2 = 3.;
218  fx2 = testfun3(x2);
219  double tol = 1.e-12;
220  int err = -1;
221  double x = Amsterdam_Method( testfun3, x1, fx1, x2, fx2, tol, 1000, err );
222  CHECK_EQUAL( 0, err );
223  CHECK( fp_equal_tol( x, sqrt(0.5), tol ) );
224  }
225 }
static double x2[63]
double bracket_width() const
Definition: iter_track.h:85
static double x1[83]
double next_val()
Definition: iter_track.cpp:18
void add(double x, double fx)
Definition: iter_track.h:120
bool fp_equal_tol(sys_float x, sys_float y, sys_float tol)
Definition: cddefines.h:858
double Amsterdam_Method(double(*f)(double), double a, double fa, double c, double fc, double tol, int max_iter, int &err)
Definition: iter_track.cpp:238
T next_val(T current, T next_est)
Definition: iter_track.h:241
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:816
int init_bracket(double x1, double fx1, double x2, double fx2)
Definition: iter_track.h:104
bool lgConverged()
Definition: iter_track.h:89
float sys_float
Definition: cddefines.h:110
long max(int a, long b)
Definition: cddefines.h:779
bool fp_bound(sys_float lo, sys_float x, sys_float hi, int n=3)
Definition: cddefines.h:881
T pow2(T a)
Definition: cddefines.h:935
double zero_fit(int n, double &sigma) const
Definition: iter_track.cpp:164
double deriv(int n, double &sigma) const
Definition: iter_track.cpp:145
void set_tol(double tol)
Definition: iter_track.h:81
double root() const
Definition: iter_track.h:100