Cantera  2.3.0
RootFind.h
Go to the documentation of this file.
1 /**
2  * @file RootFind.h Header file for implicit nonlinear solver of a one
3  * dimensional function (see \ref numerics and class \link
4  * Cantera::RootFind RootFind\endlink).
5  */
6 
7 // This file is part of Cantera. See License.txt in the top-level directory or
8 // at http://www.cantera.org/license.txt for license and copyright information.
9 
10 #ifndef CT_ROOTFIND_H
11 #define CT_ROOTFIND_H
12 /**
13  * @defgroup solverGroup Solvers for Equation Systems
14  */
15 
16 #include "ResidEval.h"
17 
18 namespace Cantera
19 {
20 
21 //@{
22 /// @name Constant which determines the return integer from the routine
23 
24 //! This means that the root solver was a success
25 #define ROOTFIND_SUCCESS 0
26 //! This return value means that the root finder resolved a solution in the x
27 //! coordinate, however, convergence in F was not achieved.
28 /*!
29  * A common situation for this to happen is that f(x) is discontinuous about
30  * f(x) = f_0, where we seek the x where the function is equal to f_0. f(x)
31  * spans the f_0 while not being equal to f_0 anywhere.
32  */
33 #define ROOTFIND_SUCCESS_XCONVERGENCEONLY 1
34 //! This means that the root solver failed to achieve convergence
35 #define ROOTFIND_FAILEDCONVERGENCE -1
36 //! This means that the input to the root solver was defective
37 #define ROOTFIND_BADINPUT -2
38 //! This means that the rootfinder believes the solution is lower than xmin
39 #define ROOTFIND_SOLNLOWERTHANXMIN -3
40 //! This means that the rootfinder believes the solution is higher than xmax
41 #define ROOTFIND_SOLNHIGHERTHANXMAX -4
42 //@}
43 
44 //! Root finder for 1D problems
45 /*!
46  * @deprecated Unused. To be removed after Cantera 2.3. See
47  * boost::math::tools::toms748_solve for an alternative.
48  *
49  * The root finder solves a single nonlinear equation described below.
50  *
51  * \f[
52  * f(x) = f_0
53  * \f]
54  *
55  * \f$ f(x) \f$ is assumed to be single valued as a function of x.\f$ f(x) \f$
56  * is not assumed to be continuous nor is its derivative assumed to be well
57  * formed.
58  *
59  * Root finders are significantly different in the sense that do not have to
60  * rely solely on Newton's method to find the answer to the problem. Instead
61  * they use a method to bound the solution between high and low values and then
62  * use a method to refine that bound. The eventual solution to the problem is
63  * presented as x_best and as a bound, delta_X, on the solution component.
64  * Because of this, they are far more stable for functions and Jacobians that
65  * have discontinuities or noise associated with them.
66  *
67  * The algorithm is a convolution of a local Secant method with an approach of
68  * finding a straddle in x. The Jacobian is never required.
69  *
70  * There is a general breakdown of the algorithm into stages. The first stage
71  * seeks to find a straddle of the function. The second stage seeks to reduce
72  * the bounds in x and f in order to satisfy the specification of the stopping
73  * criteria. In the last stage the algorithm seeks to find the base value of x
74  * that satisfies the original equation given what it current knows about the
75  * function.
76  *
77  * Globalization strategy
78  *
79  * Specifying the General Changes in x
80  *
81  * Supplying Hints with General Function Behavior Flags
82  *
83  * Stopping Criteria
84  *
85  * Specification of the Stopping Criteria
86  *
87  * Additional constraints
88  *
89  * Bounds Criteria For the Routine
90  *
91  * Example
92  *
93  * @code
94  * // Define a residual. The definition of a residual involves a lot more work than is shown here.
95  * ResidEval * ec;
96  * // Instantiate the root finder with the residual to be solved, ec.
97  * RootFind rf(&ec);
98  * // Set the relative and absolute tolerances for f and x.
99  * rf.setTol(1.0E-5, 1.0E-10, 1.0E-5, 1.0E-11);
100  * // Give a hint about the function's dependence on x. This is needed, for example, if the function has
101  * // flat regions.
102  * rf.setFuncIsGenerallyIncreasing(true);
103  * rf.setDeltaX(0.01);
104  * // Supply an initial guess for the solution
105  * double xbest = phiM;
106  * double oldP = printLvl_;
107  * // Set the print level for the solver. Zero produces no output. Two produces a summary table of each iteration.
108  * rf.setPrintLvl(2);
109  * // Define a minimum and maximum for the independent variable.
110  * double phimin = 1.3;
111  * double phimax = 2.2;
112  * // Define a maximum iteration number
113  * int itmax = 100;
114  * // Define the f_0 value, and on return will contain the actual value of f(x) obtained
115  * double currentObtained;
116  * // Call the solver
117  * status = rf.solve(phimin, phimax, 100, currentObtained, &xbest);
118  * if (status == 0) {
119  * if (printLvl_ > 1) {
120  * printf("Electrode::integrateConstantCurrent(): Volts (%g amps) = %g\n", currentObtained, xbest);
121  * }
122  * } else {
123  * if (printLvl_) {
124  * printf("Electrode::integrateConstantCurrent(): bad status = %d Volts (%g amps) = %g\n",
125  * status, currentObtained, xbest);
126  * }
127  * }
128  * @endcode
129  *
130  * @todo Noise
131  * @todo General Search to be done when all else fails
132  */
133 class RootFind
134 {
135 public:
136  //! Constructor for the object
137  /*!
138  * @param resid Pointer to the residual function to be used to calculate f(x)
139  */
140  RootFind(ResidEval* resid);
141 
142  //! @deprecated To be removed after Cantera 2.3.
143  RootFind(const RootFind& r);
144  ~RootFind() {}
145  //! @deprecated To be removed after Cantera 2.3.
146  RootFind& operator=(const RootFind& right);
147 
148 private:
149  //! Calculate a deltaX from an input value of x
150  /*!
151  * This routine ensure that the deltaX will be greater or equal to
152  * DeltaXNorm_ or 1.0E-14 x
153  *
154  * @param x1 input value of x
155  */
156  doublereal delXNonzero(doublereal x1) const;
157 
158  //! Calculate a deltaX from an input value of x
159  /*!
160  * This routine ensure that the deltaX will be greater or equal to
161  * DeltaXNorm_ or 1.0E-14 x or deltaXConverged_.
162  *
163  * @param x1 input value of x
164  */
165  doublereal delXMeaningful(doublereal x1) const;
166 
167  //! Calculate a controlled, nonzero delta between two numbers
168  /*!
169  * The delta is designed to be greater than or equal to delXMeaningful(x)
170  * defined above with the same sign as the original delta. Therefore if you
171  * subtract it from either of the two original numbers, you get a different
172  * number.
173  *
174  * @param x2 first number
175  * @param x1 second number
176  */
177  doublereal deltaXControlled(doublereal x2, doublereal x1) const;
178 
179  //! Function to decide whether two real numbers are the same or not
180  /*!
181  * A comparison is made between the two numbers to decide whether they are
182  * close to one another. This is defined as being within factor *
183  * delXMeaningful() of each other.
184  *
185  * The basic premise here is that if the two numbers are too close, the
186  * noise will prevent an accurate calculation of the function and its slope.
187  *
188  * @param x1 First number
189  * @param x2 second number
190  * @param factor Multiplicative factor to multiple deltaX with
191  * @returns a boolean indicating whether the two numbers are the same or not.
192  */
193  bool theSame(doublereal x2, doublereal x1, doublereal factor = 1.0) const;
194 
195 public:
196  //! Using a line search method, find the root of a 1D function
197  /*!
198  * This routine solves the following equation.
199  *
200  * \f[
201  * R(x) = f(x) - f_o = 0
202  * \f]
203  *
204  * @param xmin Minimum value of x to be used.
205  * @param xmax Maximum value of x to be used
206  * @param itmax maximum number of iterations. Usually, it can be less than 50.
207  * @param funcTargetValue Value of \f$ f_o \f$ in the equation. On return,
208  * it contains the value of the function actually obtained.
209  * @param xbest Returns the x that satisfies the function On input, xbest
210  * should contain the best estimate of the solution. An
211  * attempt to find the solution near xbest is made.
212  * @return:
213  * 0 = ROOTFIND_SUCCESS Found function
214  * -1 = ROOTFIND_FAILEDCONVERGENCE Failed to find the answer
215  * -2 = ROOTFIND_BADINPUT Bad input was detected
216  */
217  int solve(doublereal xmin, doublereal xmax, int itmax, doublereal& funcTargetValue, doublereal* xbest);
218 
219  //! Return the function value
220  /*!
221  * This routine evaluates the following equation.
222  *
223  * \f[
224  * R(x) = f(x) - f_o = 0
225  * \f]
226  *
227  * @param x Value of the independent variable
228  *
229  * @return The routine returns the value of \f$ R(x) \f$
230  */
231  doublereal func(doublereal x);
232 
233  //! Set the tolerance parameters for the rootfinder
234  /*!
235  * These tolerance parameters are used on the function value and the
236  * independent value to determine convergence
237  *
238  * @param rtolf Relative tolerance. The default is 10^-5
239  * @param atolf absolute tolerance. The default is 10^-11
240  * @param rtolx Relative tolerance. The default is 10^-5. Default parameter
241  * is 0.0, in which case rtolx is set equal to rtolf
242  * @param atolx absolute tolerance. The default is 10^-11. Default
243  * parameter is 0.0, in which case atolx is set equal to
244  * atolf
245  */
246  void setTol(doublereal rtolf, doublereal atolf, doublereal rtolx = 0.0, doublereal atolx = 0.0);
247 
248  //! Set the print level from the rootfinder
249  /*!
250  * - 0: No printing of any kind
251  * - 1: Single print line indicating success or failure of the routine.
252  * - 2: Summary table printed at the end of the routine, with a convergence
253  * history
254  * - 3: Printouts during the iteration are added. Summary table is printed
255  * out at the end. if writeLogAllowed_ is turned on, a file is written
256  * out with the convergence history.
257  *
258  * @param printLvl integer value
259  */
260  void setPrintLvl(int printLvl);
261 
262  //! Set the function behavior flag
263  /*!
264  * If this is true, the function is generally an increasing function of x.
265  * In particular, if the algorithm is seeking a higher value of f, it will
266  * look in the positive x direction.
267  *
268  * This type of function is needed because this algorithm must deal with
269  * regions of f(x) where f is not changing with x.
270  *
271  * @param value boolean value
272  */
273  void setFuncIsGenerallyIncreasing(bool value);
274 
275  //! Set the function behavior flag
276  /*!
277  * If this is true, the function is generally a decreasing function of x. In
278  * particular, if the algorithm is seeking a higher value of f, it will look
279  * in the negative x direction.
280  *
281  * This type of function is needed because this algorithm must deal with
282  * regions of f(x) where f is not changing with x.
283  *
284  * @param value boolean value
285  */
286  void setFuncIsGenerallyDecreasing(bool value);
287 
288  //! Set the minimum value of deltaX
289  /*!
290  * @param deltaXNorm
291  */
292  void setDeltaX(doublereal deltaXNorm);
293 
294  //! Set the maximum value of deltaX
295  /*!
296  * @param deltaX
297  */
298  void setDeltaXMax(doublereal deltaX);
299 
300  //! Print the iteration history table
301  void printTable();
302 
303 public:
304  //! Pointer to the residual function evaluator
306 
307  //! Target value for the function. We seek the value of f that is equal to
308  //! this value
309  doublereal m_funcTargetValue;
310 
311  //! Absolute tolerance for the value of f
312  doublereal m_atolf;
313 
314  //! Absolute tolerance for the value of x
315  doublereal m_atolx;
316 
317  //! Relative tolerance for the value of f and x
318  doublereal m_rtolf;
319 
320  //! Relative tolerance for the value of x
321  doublereal m_rtolx;
322 
323  //! Maximum number of step sizes
324  doublereal m_maxstep;
325 
326 protected:
327  //! Print level. @see setPrintLvl
328  int printLvl;
329 
330 public:
331  //! Boolean to turn on the possibility of writing a log file.
333 
334 protected:
335  //! Delta X norm. This is the nominal value of deltaX that will be used by
336  //! the program
337  doublereal DeltaXnorm_;
338 
339  //! Boolean indicating whether DeltaXnorm_ has been specified by the user or
340  //! not
342 
343  //! Delta X Max.
344  /*!
345  * This is the maximum value of deltaX that will be used by the program.
346  * Sometimes a large change in x causes problems.
347  */
348  doublereal DeltaXMax_;
349 
350  //! Boolean indicating whether DeltaXMax_ has been specified by the user or
351  //! not
353 
354  //! Boolean indicating whether the function is an increasing with x
356 
357  //! Boolean indicating whether the function is decreasing with x
359 
360  //! Value of delta X that is needed for convergence
361  /*!
362  * X will be considered as converged if we are within deltaXConverged_ of
363  * the solution The default is zero.
364  */
365  doublereal deltaXConverged_;
366 
367  //! Internal variable tracking largest x tried.
368  doublereal x_maxTried_;
369 
370  //! Internal variable tracking f(x) of largest x tried.
371  doublereal fx_maxTried_;
372 
373  //! Internal variable tracking smallest x tried.
374  doublereal x_minTried_;
375 
376  //! Internal variable tracking f(x) of smallest x tried.
377  doublereal fx_minTried_;
378 
379  //! Structure containing the iteration history
380  struct rfTable {
381  //@{
382  int its;
383  int TP_its;
384  double slope;
385  double xval;
386  double fval;
387  int foundPos;
388  int foundNeg;
389  double deltaXConverged;
390  double deltaFConverged;
391  double delX;
392 
393  std::string reasoning;
394 
395  void clear() {
396  its = 0;
397  TP_its = 0;
398  slope = -1.0E300;
399  xval = -1.0E300;
400  fval = -1.0E300;
401  reasoning = "";
402  };
403 
404  rfTable() :
405  its(-2),
406  TP_its(0),
407  slope(-1.0E300),
408  xval(-1.0E300),
409  fval(-1.0E300),
410  foundPos(0),
411  foundNeg(0),
412  deltaXConverged(-1.0E300),
413  deltaFConverged(-1.0E300),
414  delX(-1.0E300) {
415  };
416  //@}
417  };
418 
419  //! Vector of iteration histories
420  std::vector<struct rfTable> rfHistory_;
421 };
422 }
423 #endif
void setDeltaX(doublereal deltaXNorm)
Set the minimum value of deltaX.
Definition: RootFind.cpp:1045
doublereal DeltaXnorm_
Delta X norm.
Definition: RootFind.h:337
doublereal fx_minTried_
Internal variable tracking f(x) of smallest x tried.
Definition: RootFind.h:377
bool FuncIsGenerallyDecreasing_
Boolean indicating whether the function is decreasing with x.
Definition: RootFind.h:358
doublereal x_maxTried_
Internal variable tracking largest x tried.
Definition: RootFind.h:368
std::vector< struct rfTable > rfHistory_
Vector of iteration histories.
Definition: RootFind.h:420
void setFuncIsGenerallyDecreasing(bool value)
Set the function behavior flag.
Definition: RootFind.cpp:1037
Structure containing the iteration history.
Definition: RootFind.h:380
int specifiedDeltaXnorm_
Boolean indicating whether DeltaXnorm_ has been specified by the user or not.
Definition: RootFind.h:341
RootFind & operator=(const RootFind &right)
Definition: RootFind.cpp:86
void printTable()
Print the iteration history table.
Definition: RootFind.cpp:1057
doublereal delXNonzero(doublereal x1) const
Calculate a deltaX from an input value of x.
Definition: RootFind.cpp:117
int printLvl
Print level.
Definition: RootFind.h:328
doublereal m_atolx
Absolute tolerance for the value of x.
Definition: RootFind.h:315
doublereal m_rtolx
Relative tolerance for the value of x.
Definition: RootFind.h:321
bool writeLogAllowed_
Boolean to turn on the possibility of writing a log file.
Definition: RootFind.h:332
doublereal m_rtolf
Relative tolerance for the value of f and x.
Definition: RootFind.h:318
doublereal DeltaXMax_
Delta X Max.
Definition: RootFind.h:348
doublereal x_minTried_
Internal variable tracking smallest x tried.
Definition: RootFind.h:374
void setTol(doublereal rtolf, doublereal atolf, doublereal rtolx=0.0, doublereal atolx=0.0)
Set the tolerance parameters for the rootfinder.
Definition: RootFind.cpp:1008
Root finder for 1D problems.
Definition: RootFind.h:133
void setFuncIsGenerallyIncreasing(bool value)
Set the function behavior flag.
Definition: RootFind.cpp:1029
Virtual base class for DAE residual function evaluators.
Definition: ResidEval.h:33
doublereal m_funcTargetValue
Target value for the function.
Definition: RootFind.h:309
bool FuncIsGenerallyIncreasing_
Boolean indicating whether the function is an increasing with x.
Definition: RootFind.h:355
bool theSame(doublereal x2, doublereal x1, doublereal factor=1.0) const
Function to decide whether two real numbers are the same or not.
Definition: RootFind.cpp:151
doublereal fx_maxTried_
Internal variable tracking f(x) of largest x tried.
Definition: RootFind.h:371
doublereal delXMeaningful(doublereal x1) const
Calculate a deltaX from an input value of x.
Definition: RootFind.cpp:127
doublereal deltaXControlled(doublereal x2, doublereal x1) const
Calculate a controlled, nonzero delta between two numbers.
Definition: RootFind.cpp:136
ResidEval * m_residFunc
Pointer to the residual function evaluator.
Definition: RootFind.h:305
int solve(doublereal xmin, doublereal xmax, int itmax, doublereal &funcTargetValue, doublereal *xbest)
Using a line search method, find the root of a 1D function.
Definition: RootFind.cpp:163
void setDeltaXMax(doublereal deltaX)
Set the maximum value of deltaX.
Definition: RootFind.cpp:1051
doublereal m_maxstep
Maximum number of step sizes.
Definition: RootFind.h:324
doublereal deltaXConverged_
Value of delta X that is needed for convergence.
Definition: RootFind.h:365
RootFind(ResidEval *resid)
Constructor for the object.
Definition: RootFind.cpp:33
void setPrintLvl(int printLvl)
Set the print level from the rootfinder.
Definition: RootFind.cpp:1024
Namespace for the Cantera kernel.
Definition: application.cpp:29
doublereal m_atolf
Absolute tolerance for the value of f.
Definition: RootFind.h:312
int specifiedDeltaXMax_
Boolean indicating whether DeltaXMax_ has been specified by the user or not.
Definition: RootFind.h:352
doublereal func(doublereal x)
Return the function value.
Definition: RootFind.cpp:990