PLUTO
math_root_finders.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Collection of root-finder algorithms.
5 
6  \author A. Mignone (mignone@ph.unito.it)
7  \date June 20, 2014
8 */
9 /* ///////////////////////////////////////////////////////////////////// */
10 #include "pluto.h"
11 
12 #define MAX_ITER 60
13 /* ************************************************************ */
14 int Brent(double (*Func)(double, void *), void *param, double x1,
15  double x2, double abs_acc, double rel_acc, double *xroot)
16 /*!
17  * Use Brent's method to find the root of \f$ f(x) = 0\f$ known
18  * to lie between x1 and x2.
19  * Here the function must be in the form \c double \c Func(x,*p), where
20  * where \c x is the independent variable while \c *p is a (void) pointer
21  * to any data type containing the function parameters.
22  * Absolute accuracies can be specified to check for convergence
23  *
24  * \param [in] *func a pointer to a function func(x, *par)
25  * \param [in] *param a void pointer containing the parameters
26  * \param [in] x1 the leftmost interval point
27  * \param [in] x2 the rightmost interval point
28  * \param [in] abs_acc the desired absolute accuracy.(> 0 if you wish to
29  * use it).
30  * \param [in] rel_acc the desired relative accuracy.(> 0 if you wish to
31  * use it).
32  * \param [out] xroot the zero of the function.
33  *
34  * \return The return value is 0 on success, 1 if the root could
35  * not be found to the desired level of accurat and 2 if the
36  * the initial interval does not contain the root.
37  *************************************************************** */
38 {
39  int iter;
40  double a=x1,b=x2,c=x2,d,e,min1,min2;
41  double fa,fb,fc,p,q,r,s,tol1,xm;
42 
43  fa = (*Func)(a, param);
44  fb = (*Func)(b, param);
45 
46  if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0)){
47  WARNING(
48  if(g_stepNumber > 0) print ("! Brent: initial interval does not contain root.\n");
49  )
50  return 2; /* Error: initial interval does not contain root */
51  }
52  fc = fb;
53  for (iter=1; iter<=MAX_ITER; iter++) {
54  if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0)) {
55  c = a;
56  fc = fa;
57  e = d = b-a;
58  }
59  if (fabs(fc) < fabs(fb)) {
60  a = b;
61  b = c;
62  c = a;
63  fa = fb;
64  fb = fc;
65  fc = fa;
66  }
67  if (abs_acc < 0){
68  tol1 = 2.0*2.0e-16*fabs(b);
69  }else{
70  tol1 = 2.0*2.0e-16*fabs(b) + 0.5*abs_acc; /* EPS = 2.0e-16 machine
71  epsilon for double. */
72  }
73  xm = 0.5*(c - b);
74 /* if (fabs(xm) <= tol1 || fb == 0.0){ */
75  if (fabs(xm) <= 0.5*abs_acc || fabs(xm) <= 0.5*rel_acc*fabs(b) ||
76  fb == 0.0) {
77  *xroot = b;
79  return 0;
80  }
81  if (fabs(e) >= tol1 && fabs(fa) > fabs(fb)) {
82  s = fb/fa; /*Attempt inverse quadratic interpolation.*/
83  if (a == c) {
84  p = 2.0*xm*s;
85  q = 1.0 - s;
86  } else {
87  q = fa/fc;
88  r = fb/fc;
89  p = s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
90  q = (q-1.0)*(r-1.0)*(s-1.0);
91  }
92  if (p > 0.0) q = -q; /*Check whether in bounds. */
93  p = fabs(p);
94  min1 = 3.0*xm*q-fabs(tol1*q);
95  min2 = fabs(e*q);
96  if (2.0*p < (min1 < min2 ? min1 : min2)) {
97  e = d;
98  d = p/q;
99  } else {
100  d = xm;
101  e = d;
102  }
103  } else {
104  d = xm;
105  e = d;
106  }
107  a = b; /* Move last best guess to a.*/
108  fa = fb;
109  if (fabs(d) > tol1) b += d; /*Evaluate new trial root.*/
110  else b += DSIGN(xm)*fabs(tol1); /* SIGN(tol1,xm); */
111  fb=(*Func)(b, param);
112  }
113  WARNING(
114  print ("! Brent: exceed maximum iterations.\n");
115  )
116  return 1;
117 }
118 
119 /* ********************************************************************* */
120 int Ridder(double (*Func)(double, void *), void *param,
121  double x1, double x2, double abs_acc, double rel_acc,
122  double *xroot)
123 /*!
124  * Use Ridder's method to find the root of \f$ f(x) = 0\f$ known
125  * to lie between x1 and x2.
126  * Here the function must be in the form \c double \c Func(x,*p), where
127  * where \c x is the independent variable while \c *p is a (void) pointer
128  * to any data type containing the function parameters.
129  * Both relative and absolute accuracies can be specified and convergence
130  * is achieved by the condition that is realized first.
131  * To choose among the two accuracies, set the other one to a negative
132  * number.
133  *
134  * \param [in] *func a pointer to a function func(x, *par)
135  * \param [in] *param a void pointer containing the parameters
136  * \param [in] x1 the leftmost interval point
137  * \param [in] x2 the rightmost interval point
138  * \param [in] abs_acc the desired absolute accuracy (> 0 if you wish to
139  * use it).
140  * \param [in] rel_acc the desired relative accuracy (> 0 if you wish to
141  * use it).
142  * \param [out] xroot the zero of the function.
143  *
144  * \return The return value is 0 on success, 1 if the root could
145  * not be found to the desired level of accurat and 2 if the
146  * the initial interval does not contain the root.
147  ************************************************************************ */
148 {
149  int j;
150  double ans,fh,fl,fm,fnew,s,xh,xl,xm,xnew;
151  double delta;
152 
153  fl = (*Func)(x1, param);
154  fh = (*Func)(x2, param);
155 
156  if ((fl > 0.0 && fh < 0.0) || (fl < 0.0 && fh > 0.0)) {
157  xl = x1;
158  xh = x2;
159  ans = -1.11e30;
160 
161  for (j = 1; j <= MAX_ITER; j++) {
162  xm = 0.5*(xl + xh);
163  fm = (*Func)(xm, param);
164  s = sqrt(fm*fm - fl*fh);
165  if (s == 0.0) {
166  *xroot = ans;
168  return 0;
169  }
170  xnew = xm + (xm-xl)*((fl >= fh ? 1.0 : -1.0)*fm/s); /* update */
171  delta = fabs(xnew-ans);
172  if (delta <= abs_acc || delta <= rel_acc*fabs(xnew)) {
173  *xroot = ans;
175  return 0;
176  }
177  ans = xnew;
178  fnew = (*Func)(ans, param);
179  if (fnew == 0.0) {
180  *xroot = ans;
182  return 0;
183  }
184  if (fm*fnew < 0.0) {
185  xl = xm;
186  fl = fm;
187  xh = ans;
188  fh = fnew;
189  } else if (fl*fnew < 0.0) {
190  xh = ans;
191  fh = fnew;
192  } else if (fh*fnew < 0.0) {
193  xl = ans;
194  fl = fnew;
195  } else {
196  print ("! Ridder: never get here.\n");
197  print ("! xl = %12.6e, fl = %12.6e\n",xl,fl);
198  print ("! xh = %12.6e, fh = %12.6e\n",xh,fh);
199  print ("! xm = %12.6e, fm = %12.6e\n",xm,fm);
200  print ("! xnew = %12.6e, fnew = %12.6e\n",xnew,fnew);
201  print ("! sqrt^2 = %12.6e\n",fm*fm - fl*fh);
202  QUIT_PLUTO(1);
203  }
204 
205  delta = fabs(xh-xl);
206  if (delta <= abs_acc || delta <= rel_acc*fabs(xh)) {
207  *xroot = ans;
209  return 0;
210  }
211  }
212  WARNING(
213  print ("! Ridder: exceed maximum iterations.\n");
214  )
215  return 1; /* Error: max number of iteration exceeded */
216 
217  } else {
218 
219  if (fl == 0.0) {
220  *xroot = x1;
222  return 0;
223  }
224  if (fh == 0.0) {
225  *xroot = x2;
227  return 0;
228  }
229  /*
230  WARNING(
231  print ("! Ridder: initial interval does not contain root.\n");
232  )*/
233  return 2; /* Error: initial interval does not contain root */
234  }
235 }
236 #undef MAX_ITER
237 
238 /* ********************************************************************* */
239 void FDJacobian(int n, double x[], double fv[], double **df,
240  void (*vecfunc)(int , double [] , double [])){
241 /*
242  * Estimate forward difference of the Jacobian.
243  *
244  *********************************************************************** */
245 
246  int i, j;
247  double h, temp, *f;
248  f = ARRAY_1D(n, double);
249 
250  for(j=0;j<n;j++){
251  temp=x[j];
252  h = EPS_FD_JAC*fabs(temp);
253  if (h == 0.0) h = EPS_FD_JAC;
254  x[j] = temp + h;
255  h = x[j] - temp;
256  (*vecfunc)(n,x,f);
257  x[j] = temp;
258  for(i=0;i<n;i++) df[i][j] = (f[i]-fv[i])/h;
259  }
260 }
261 
262 /* ********************************************************************* */
263 void LineSearch (int n, double xold[], double fold, double g[],
264  double p[], double x[], double mf[], double *f, double stpmax,
265  int *check, void (*vecfunc)(int , double [] , double [])){
266 /*
267  * Line search algorithm to minimize functions.
268  *
269  *********************************************************************** */
270  int i;
271  double a, alam, alam2, alamin, b, disc, f2, rhs1;
272  double rhs2, slope, sum, temp, test, tmplam;
273 
274  *check = 0;
275  sum = 0.0;
276  for(i=0;i<n;i++) sum += p[i]*p[i];
277  sum = sqrt(sum);
278  if (sum > stpmax){
279  for(i=0;i<n;i++) p[i] *= stpmax/sum;
280  }
281  slope = 0.0;
282  for(i=0;i<n;i++) slope += g[i]*p[i];
283 
284  if(slope > 0.0){
285  print("! LineSearch: Roundoff problem in lnscrh\n");
286  QUIT_PLUTO(1);
287  }
288 
289  test = 0.0;
290  for(i=0;i<n;i++){
291  temp = fabs(p[i])/MAX(fabs(xold[i]), 1.0);
292  if (temp > test) test = temp;
293  }
294 
295  alamin = TOLX/test;
296  alam = 1.0;
297  for(;;){
298  for(i=0;i<n;i++) x[i] = xold[i] + alam*p[i];
299  (*vecfunc)(n, x, mf);
300  sum = 0.0;
301  for (i=0;i< n;i++){
302  sum += mf[i] * mf[i];
303  }
304  *f = 0.5*sum;
305  if (alam < alamin){
306  for(i=0;i<n;i++) x[i] = xold[i];
307  *check = 1;
308  return;
309  }else if(*f < fold + ALF*alam*slope) return;
310  else {
311  if (alam == 1.0){
312  tmplam = -slope/(2.0*(*f-fold-slope));
313  }else{
314  rhs1 = *f - fold - alam*slope;
315  rhs2 = f2 - fold - alam2*slope;
316  a = (rhs1/(alam*alam) - rhs2/(alam2*alam2))/(alam - alam2);
317  b = (-alam2*rhs1/(alam*alam) + alam*rhs2/(alam2*alam2))/(alam - alam2);
318  if (a == 0.0) tmplam = -slope/(2.0*b);
319  else {
320  disc = b*b - 3.0*a*slope;
321  if (disc < 0.0) tmplam = 0.5*alam;
322  else if (b <= 0.0) tmplam = (-b + sqrt(disc))/(3.0*a);
323  else tmplam = -slope/(b + sqrt(disc));
324  }
325  if (tmplam > 0.5*alam) tmplam = 0.5*alam;
326  }
327  }
328  alam2 = alam;
329  f2 = *f;
330  alam = MAX(tmplam, 0.1*alam);
331  }
332 }
333 
334 /* ********************************************************************* */
335 void Broyden(double x[], int n, int *check,
336  void (*vecfunc)(int, double [], double []))
337 /*
338  * Broyden multidimensional root finder.
339  *
340  *********************************************************************** */
341 {
342  int i, its, j, k, restrt, sing, skip;
343  double den, f, fold, stpmax, sum, temp, test;
344  static double *c, *d, *fvcold, *g, *p, **qt, **r, *s, *t, *w, *xold, *fguess;
345 
346  if (g == NULL){
347 
348  if(n > MAX_ROOT_EQNS)
349  print1 ("! Broyden : Number of equations exceed the maximum limit\n");
350 
351  c = ARRAY_1D(MAX_ROOT_EQNS, double);
352  d = ARRAY_1D(MAX_ROOT_EQNS, double);
353  fvcold = ARRAY_1D(MAX_ROOT_EQNS, double);
354  g = ARRAY_1D(MAX_ROOT_EQNS, double);
355  p = ARRAY_1D(MAX_ROOT_EQNS, double);
356  qt = ARRAY_2D(MAX_ROOT_EQNS,MAX_ROOT_EQNS, double);
358  s = ARRAY_1D(MAX_ROOT_EQNS, double);
359  t = ARRAY_1D(MAX_ROOT_EQNS, double);
360  w = ARRAY_1D(MAX_ROOT_EQNS, double);
361  xold = ARRAY_1D(MAX_ROOT_EQNS, double);
362  fguess = ARRAY_1D(MAX_ROOT_EQNS, double);
363  }
364 
365  /* Use fmin EXPLICTLY routine from math_minimization.c to create fvec. */
366 
367  (*vecfunc)(n, x, fguess);
368  sum = 0.0;
369  for (i=0;i< n;i++){
370  sum += fguess[i] * fguess[i];
371  }
372  f = 0.5*sum;
373 
374  test = 0.0;
375 
376  /* Is initial guess the root ? */
377  for (i=0; i<n; i++)
378  if (fabs(fguess[i]) > test) test = fabs(fguess[i]);
379  if (test < 0.01*TOLF) {
380  *check = 0;
381  return;
382  }
383 
384  /* Calculate stpmax for line searches */
385  sum = 0.0;
386  for (i=0;i<n;i++) sum += x[i] * x[i];
387  stpmax = STPMX*MAX(sqrt(sum), (double)n);
388  restrt = 1; /* To ensure initial computation of Jacobian. */
389 
390  /* Start the Iteration Loop */
391  for(its = 1; its <= MAXITS; its++){
392 
393  if (restrt){
394  FDJacobian(n,x,fguess,r,vecfunc); /* Compute Initial Jacobian in r */
395  QRDecompose (r, n, c, d, &sing); /* QR Decomposition of r. */
396  if (sing){
397  print ("! Broyden: singular Jacobian... Hard Luck !\n");
398  QUIT_PLUTO(1);
399  }
400 
401  /* Initialize transpose(Q) to Identity matrix. */
402  for(i=0;i<n;i++){
403  for(j=0;j<n;j++) qt[i][j] = 0.0;
404  qt[i][i] = 1.0;
405  }
406 
407  /* Compute transpose(Q) explicityly */
408  for(k=0; k < n-1; k++) {
409  if (c[k]) {
410  for (j=0; j<n; j++) {
411  sum = 0.0;
412  for(i=k; i<n; i++) {
413  sum += r[i][k]*qt[i][j];
414  }
415  sum /= c[k];
416  for(i=k; i<n; i++) {
417  qt[i][j] -= sum*r[i][k];
418  }
419  }
420  }
421  }
422 
423  /* Create R */
424  for(i=0;i<n;i++) {
425  r[i][i] = d[i]; /* Diagonal are in 'd' : QRDecompose */
426  for (j=0;j<i;j++) r[i][j] = 0.0;
427  }
428 
429  } else { /* End of restart and now doing the Broyden Update */
430 
431  for(i=0; i<n; i++) s[i] = x[i] - xold[i]; /* s = delta(x) */
432  for(i=0; i<n; i++) { /* t = R.s */
433  sum = 0.0;
434  for(j=i; j<n; j++) sum += r[i][j] * s[j];
435  t[i] = sum;
436  }
437  skip = 1;
438  for (i=0; i<n; i++){ /* w = delta(F) - B.s */
439  sum = 0.0;
440  for(j=0; j<n; j++) sum += qt[j][i] * t[j];
441  w[i] = fguess[i] - fvcold[i] - sum;
442  if (fabs(w[i]) >= EPS_FD_JAC*(fabs(fguess[i]) + fabs(fvcold[i]))) skip = 0;
443  /* No update with noisy components of w */
444  else w[i] = 0.0;
445  }
446 
447  if(!skip) {
448  for(i=0;i<n;i++) { /* t = transpose(Q).w */
449  sum = 0.0;
450  for(j=0;j<n;j++) sum += qt[i][j]*w[j];
451  t[i] = sum;
452  }
453 
454  den = 0.0;
455  for(i=0; i<n;i++) den += s[i] * s[i];
456  for(i=0; i<n;i++) s[i] /= den; /* Store s/(s.s) in s */
457 
458  QRUpdate(r,qt,n,t,s); /* Update R and transpose(Q) */
459 
460  for(i=0; i<n; i++) {
461  if (r[i][i] == 0.0){
462  print ("! Broyden: R is singular .. Hard Luck ! \n");
463  QUIT_PLUTO(1);
464  }
465  d[i] = r[i][i]; /* Diagonal of R in d */
466  }
467  } /* End if(!skip) */
468  } /* End of Broyden Update */
469 
470  /* Compute gradient(f) \approx transpose(Q.R) .F */
471  for(i=0;i<n;i++){
472  sum = 0.0;
473  for(j=0; j<n; j++) sum += qt[i][j] * fguess[j];
474  g[i] = sum;
475  }
476 
477  for(i=n-1;i>=0;i--){
478  sum = 0.0;
479  for(j=0; j<=i; j++) sum += r[j][i] * g[j];
480  g[i] = sum;
481  }
482 
483  /* Store x and F */
484  for(i=0;i<n;i++){
485  xold[i] = x[i];
486  fvcold[i] = fguess[i];
487  }
488  fold = f; /* Store Min. Least Sqrs from fmin */
489 
490  for(i=0;i<n;i++){ /* Compute RHS = -tranpose(Q).F */
491  sum = 0.0;
492  for(j=0; j<n; j++) sum += qt[i][j] * fguess[j];
493  p[i] = -sum;
494  }
495 
496  /* Solve Linear Equation */
497  RSolve(r, n , d, p);
498 
499  /* Do Line Search to get xnew, f and fvec[xnew] */
500  /*LineSearch (n, xold, fold, g, p, x, &f, stpmax, check, FMin); */
501  LineSearch (n, xold, fold, g, p, x, fguess, &f, stpmax, check, vecfunc);
502 
503  /* Test for convergenvce on function values. */
504  test = 0.0;
505  for(i=0;i<n;i++){
506  if (fabs(fguess[i]) > test) test = fabs(fguess[i]);
507  }
508  if (test < TOLF) { /* Function values converged */
509  *check = 0;
510  return;
511  }
512 
513  if(*check) { /* Line Search Failed */
514  if (restrt) {
515  print("! Broyden: Already tried reinitializing \n");
516  return;
517  } else {
518  test = 0.0;
519  den = MAX(f, 0.5*n);
520  for(i=0; i<n; i++){
521  temp = fabs(g[i]) * MAX(fabs(x[i]), 1.0)/den;
522  if (temp > test) test = temp;
523  }
524  if (test < TOLMIN) return;
525  else restrt = 1;
526  }
527  } else { /* Sucess Step */
528  restrt = 0;
529  test = 0.0;
530  for(i=0; i<n; i++){ /* Test convergence on x */
531  temp = (fabs(x[i] - xold[i])) / MAX(fabs(x[i]), 1.0);
532  if (temp > test) test = temp;
533  }
534  if (test < TOLX){
535  print("! Brodyen: All is Well !! \n");
536  return;
537  }
538  }
539  }
540  print("! Brodyen: MAXITS exceeded in Broyden\n");
541  return;
542 }
543 
static double a
Definition: init.c:135
#define MAX(a, b)
Definition: macros.h:101
void QRDecompose(double **a, int n, double *c, double *d, int *sing)
static int n
Definition: analysis.c:3
int g_maxRootIter
Maximum number of iterations for root finder.
Definition: globals.h:95
void FDJacobian(int n, double x[], double fv[], double **df, void(*vecfunc)(int, double[], double[]))
void LineSearch(int n, double xold[], double fold, double g[], double p[], double x[], double mf[], double *f, double stpmax, int *check, void(*vecfunc)(int, double[], double[]))
void print1(const char *fmt,...)
Definition: amrPluto.cpp:511
#define WARNING(a)
Definition: macros.h:217
#define MAX_ROOT_EQNS
Definition: math_tools.h:37
#define DSIGN(x)
Definition: macros.h:110
#define TOLMIN
Definition: math_tools.h:35
void QRUpdate(double **r, double **qt, int n, double *u, double *v)
#define EPS_FD_JAC
Definition: math_tools.h:31
#define STPMX
Definition: math_tools.h:34
int Brent(double(*Func)(double, void *), void *param, double x1, double x2, double abs_acc, double rel_acc, double *xroot)
long int g_stepNumber
Gives the current integration step number.
Definition: globals.h:97
void RSolve(double **a, int n, double *d, double *b)
#define MAX_ITER
int j
Definition: analysis.c:2
#define MAXITS
Definition: math_tools.h:30
int k
Definition: analysis.c:2
void print(const char *fmt,...)
Definition: amrPluto.cpp:497
#define ALF
Definition: math_tools.h:36
void Broyden(double x[], int n, int *check, void(*vecfunc)(int, double[], double[]))
tuple c
Definition: menu.py:375
#define TOLF
Definition: math_tools.h:32
#define s
PLUTO main header file.
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
int i
Definition: analysis.c:2
int Ridder(double(*Func)(double, void *), void *param, double x1, double x2, double abs_acc, double rel_acc, double *xroot)
#define ARRAY_2D(nx, ny, type)
Definition: prototypes.h:171
static Runtime q
#define QUIT_PLUTO(e_code)
Definition: macros.h:125
def check(pluto_dir, get_arch)
Definition: configure.py:6
#define TOLX
Definition: math_tools.h:33