RootFinders.hpp
Go to the documentation of this file.
1 //===========================================================================
2 //
3 // File: RootFinders.hpp
4 //
5 // Created: Thu May 6 19:59:42 2010
6 //
7 // Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
8 // Jostein R Natvig <jostein.r.natvig@sintef.no>
9 //
10 // $Date$
11 //
12 // $Revision$
13 //
14 //===========================================================================
15 
16 /*
17  Copyright 2010 SINTEF ICT, Applied Mathematics.
18  Copyright 2010 Statoil ASA.
19 
20  This file is part of the Open Porous Media project (OPM).
21 
22  OPM is free software: you can redistribute it and/or modify
23  it under the terms of the GNU General Public License as published by
24  the Free Software Foundation, either version 3 of the License, or
25  (at your option) any later version.
26 
27  OPM is distributed in the hope that it will be useful,
28  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  GNU General Public License for more details.
31 
32  You should have received a copy of the GNU General Public License
33  along with OPM. If not, see <http://www.gnu.org/licenses/>.
34 */
35 
36 #ifndef OPM_ROOTFINDERS_HEADER
37 #define OPM_ROOTFINDERS_HEADER
38 
39 #include <opm/common/ErrorMacros.hpp>
40 
41 #include <algorithm>
42 #include <limits>
43 #include <cmath>
44 #include <iostream>
45 
46 namespace Opm
47 {
48 
49  struct ThrowOnError
50  {
51  static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
52  {
53  OPM_THROW(std::runtime_error, "Error in parameters, zero not bracketed: [a, b] = ["
54  << x0 << ", " << x1 << "] f(a) = " << f0 << " f(b) = " << f1);
55  return -1e100; // Never reached.
56  }
57  static double handleTooManyIterations(const double x0, const double x1, const int maxiter)
58  {
59  OPM_THROW(std::runtime_error, "Maximum number of iterations exceeded: " << maxiter << "\n"
60  << "Current interval is [" << std::min(x0, x1) << ", "
61  << std::max(x0, x1) << "]");
62  return -1e100; // Never reached.
63  }
64  };
65 
66 
68  {
69  static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
70  {
71  OPM_REPORT;
72  std::cerr << "Error in parameters, zero not bracketed: [a, b] = ["
73  << x0 << ", " << x1 << "] f(a) = " << f0 << " f(b) = " << f1
74  << "";
75  return std::fabs(f0) < std::fabs(f1) ? x0 : x1;
76  }
77  static double handleTooManyIterations(const double x0, const double x1, const int maxiter)
78  {
79  OPM_REPORT;
80  std::cerr << "Maximum number of iterations exceeded: " << maxiter
81  << ", current interval is [" << std::min(x0, x1) << ", "
82  << std::max(x0, x1) << "]";
83  return 0.5*(x0 + x1);
84  }
85  };
86 
87 
89  {
90  static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
91  {
92  return std::fabs(f0) < std::fabs(f1) ? x0 : x1;
93  }
94  static double handleTooManyIterations(const double x0, const double x1, const int /*maxiter*/)
95  {
96  return 0.5*(x0 + x1);
97  }
98  };
99 
100 
101 
102  template <class ErrorPolicy = ThrowOnError>
104  {
105  public:
106 
107 
113  template <class Functor>
114  inline static double solve(const Functor& f,
115  const double a,
116  const double b,
117  const int max_iter,
118  const double tolerance,
119  int& iterations_used)
120  {
121  using namespace std;
122  const double macheps = numeric_limits<double>::epsilon();
123  const double eps = tolerance + macheps*max(max(fabs(a), fabs(b)), 1.0);
124 
125  double x0 = a;
126  double x1 = b;
127  double f0 = f(x0);
128  const double epsF = tolerance + macheps*max(fabs(f0), 1.0);
129  if (fabs(f0) < epsF) {
130  return x0;
131  }
132  double f1 = f(x1);
133  if (fabs(f1) < epsF) {
134  return x1;
135  }
136  if (f0*f1 > 0.0) {
137  return ErrorPolicy::handleBracketingFailure(a, b, f0, f1);
138  }
139  iterations_used = 0;
140  // In every iteraton, x1 is the last point computed,
141  // and x0 is the last point computed that makes it a bracket.
142  while (fabs(x1 - x0) >= 1e-9*eps) {
143  double xnew = regulaFalsiStep(x0, x1, f0, f1);
144  double fnew = f(xnew);
145 // cout << "xnew = " << xnew << " fnew = " << fnew << endl;
146  ++iterations_used;
147  if (iterations_used > max_iter) {
148  return ErrorPolicy::handleTooManyIterations(x0, x1, max_iter);
149  }
150  if (fabs(fnew) < epsF) {
151  return xnew;
152  }
153  // Now we must check which point we must replace.
154  if ((fnew > 0.0) == (f0 > 0.0)) {
155  // We must replace x0.
156  x0 = x1;
157  f0 = f1;
158  } else {
159  // We must replace x1, this is the case where
160  // the modification to regula falsi kicks in,
161  // by modifying f0.
162  // 1. The classic Illinois method
163 // const double gamma = 0.5;
164  // @afr: The next two methods do not work??!!?
165  // 2. The method called 'Method 3' in the paper.
166 // const double phi0 = f1/f0;
167 // const double phi1 = fnew/f1;
168 // const double gamma = 1.0 - phi1/(1.0 - phi0);
169  // 3. The method called 'Method 4' in the paper.
170 // const double phi0 = f1/f0;
171 // const double phi1 = fnew/f1;
172 // const double gamma = 1.0 - phi0 - phi1;
173 // cout << "phi0 = " << phi0 <<" phi1 = " << phi1 <<
174 // " gamma = " << gamma << endl;
175  // 4. The 'Pegasus' method
176  const double gamma = f1/(f1 + fnew);
177  f0 *= gamma;
178  }
179  x1 = xnew;
180  f1 = fnew;
181  }
182  return 0.5*(x0 + x1);
183  }
184 
185 
192  template <class Functor>
193  inline static double solve(const Functor& f,
194  const double initial_guess,
195  const double a,
196  const double b,
197  const int max_iter,
198  const double tolerance,
199  int& iterations_used)
200  {
201  using namespace std;
202  const double macheps = numeric_limits<double>::epsilon();
203  const double eps = tolerance + macheps*max(max(fabs(a), fabs(b)), 1.0);
204 
205  double f_initial = f(initial_guess);
206  const double epsF = tolerance + macheps*max(fabs(f_initial), 1.0);
207  if (fabs(f_initial) < epsF) {
208  return initial_guess;
209  }
210  double x0 = a;
211  double x1 = b;
212  double f0 = f_initial;
213  double f1 = f_initial;
214  if (x0 != initial_guess) {
215  f0 = f(x0);
216  if (fabs(f0) < epsF) {
217  return x0;
218  }
219  }
220  if (x1 != initial_guess) {
221  f1 = f(x1);
222  if (fabs(f1) < epsF) {
223  return x1;
224  }
225  }
226  if (f0*f_initial < 0.0) {
227  x1 = initial_guess;
228  f1 = f_initial;
229  } else {
230  x0 = initial_guess;
231  f0 = f_initial;
232  }
233  if (f0*f1 > 0.0) {
234  return ErrorPolicy::handleBracketingFailure(a, b, f0, f1);
235  }
236  iterations_used = 0;
237  // In every iteraton, x1 is the last point computed,
238  // and x0 is the last point computed that makes it a bracket.
239  while (fabs(x1 - x0) >= 1e-9*eps) {
240  double xnew = regulaFalsiStep(x0, x1, f0, f1);
241  double fnew = f(xnew);
242 // cout << "xnew = " << xnew << " fnew = " << fnew << endl;
243  ++iterations_used;
244  if (iterations_used > max_iter) {
245  return ErrorPolicy::handleTooManyIterations(x0, x1, max_iter);
246  }
247  if (fabs(fnew) < epsF) {
248  return xnew;
249  }
250  // Now we must check which point we must replace.
251  if ((fnew > 0.0) == (f0 > 0.0)) {
252  // We must replace x0.
253  x0 = x1;
254  f0 = f1;
255  } else {
256  // We must replace x1, this is the case where
257  // the modification to regula falsi kicks in,
258  // by modifying f0.
259  // 1. The classic Illinois method
260 // const double gamma = 0.5;
261  // @afr: The next two methods do not work??!!?
262  // 2. The method called 'Method 3' in the paper.
263 // const double phi0 = f1/f0;
264 // const double phi1 = fnew/f1;
265 // const double gamma = 1.0 - phi1/(1.0 - phi0);
266  // 3. The method called 'Method 4' in the paper.
267 // const double phi0 = f1/f0;
268 // const double phi1 = fnew/f1;
269 // const double gamma = 1.0 - phi0 - phi1;
270 // cout << "phi0 = " << phi0 <<" phi1 = " << phi1 <<
271 // " gamma = " << gamma << endl;
272  // 4. The 'Pegasus' method
273  const double gamma = f1/(f1 + fnew);
274  f0 *= gamma;
275  }
276  x1 = xnew;
277  f1 = fnew;
278  }
279  return 0.5*(x0 + x1);
280  }
281 
282 
283  private:
284  inline static double regulaFalsiStep(const double a,
285  const double b,
286  const double fa,
287  const double fb)
288  {
289  assert(fa*fb < 0.0);
290  return (b*fa - a*fb)/(fa - fb);
291  }
292 
293 
294  };
295 
296 
297 
300  template <class Functor>
301  inline void bracketZero(const Functor& f,
302  const double x0,
303  const double dx,
304  double& a,
305  double& b)
306  {
307  const int max_iters = 100;
308  double f0 = f(x0);
309  double cur_dx = dx;
310  int i = 0;
311  for (; i < max_iters; ++i) {
312  double x = x0 + cur_dx;
313  double f_new = f(x);
314  if (f0*f_new <= 0.0) {
315  break;
316  }
317  cur_dx = -2.0*cur_dx;
318  }
319  if (i == max_iters) {
320  OPM_THROW(std::runtime_error, "Could not bracket zero in " << max_iters << "iterations.");
321  }
322  if (cur_dx < 0.0) {
323  a = x0 + cur_dx;
324  b = i < 2 ? x0 : x0 + 0.25*cur_dx;
325  } else {
326  a = i < 2 ? x0 : x0 + 0.25*cur_dx;
327  b = x0 + cur_dx;
328  }
329  }
330 
331 
332 
333 
334 
335 } // namespace Opm
336 
337 
338 
339 
340 #endif // OPM_ROOTFINDERS_HEADER
Definition: AnisotropicEikonal.hpp:43
static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
Definition: RootFinders.hpp:51
Definition: RootFinders.hpp:103
static double solve(const Functor &f, const double initial_guess, const double a, const double b, const int max_iter, const double tolerance, int &iterations_used)
Definition: RootFinders.hpp:193
Definition: RootFinders.hpp:49
static double handleTooManyIterations(const double x0, const double x1, const int maxiter)
Definition: RootFinders.hpp:77
static double solve(const Functor &f, const double a, const double b, const int max_iter, const double tolerance, int &iterations_used)
Definition: RootFinders.hpp:114
STL namespace.
Definition: RootFinders.hpp:67
void bracketZero(const Functor &f, const double x0, const double dx, double &a, double &b)
Definition: RootFinders.hpp:301
static double handleTooManyIterations(const double x0, const double x1, const int)
Definition: RootFinders.hpp:94
static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
Definition: RootFinders.hpp:90
Definition: RootFinders.hpp:88
static double handleTooManyIterations(const double x0, const double x1, const int maxiter)
Definition: RootFinders.hpp:57
static double handleBracketingFailure(const double x0, const double x1, const double f0, const double f1)
Definition: RootFinders.hpp:69