PLUTO
math_root_finders.c File Reference

Collection of root-finder algorithms. More...

#include "pluto.h"
Include dependency graph for math_root_finders.c:

Go to the source code of this file.

Macros

#define MAX_ITER   60
 

Functions

int Brent (double(*Func)(double, void *), void *param, double x1, double x2, double abs_acc, double rel_acc, double *xroot)
 
int Ridder (double(*Func)(double, void *), void *param, double x1, double x2, double abs_acc, double rel_acc, double *xroot)
 
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 Broyden (double x[], int n, int *check, void(*vecfunc)(int, double[], double[]))
 

Detailed Description

Collection of root-finder algorithms.

Author
A. Mignone (migno.nosp@m.ne@p.nosp@m.h.uni.nosp@m.to.i.nosp@m.t)
Date
June 20, 2014

Definition in file math_root_finders.c.

Macro Definition Documentation

#define MAX_ITER   60

Definition at line 12 of file math_root_finders.c.

Function Documentation

int Brent ( double(*)(double, void *)  Func,
void *  param,
double  x1,
double  x2,
double  abs_acc,
double  rel_acc,
double *  xroot 
)

Use Brent's method to find the root of $ f(x) = 0$ known to lie between x1 and x2. Here the function must be in the form double Func(x,*p), where where x is the independent variable while *p is a (void) pointer to any data type containing the function parameters. Absolute accuracies can be specified to check for convergence

Parameters
[in]*funca pointer to a function func(x, *par)
[in]*parama void pointer containing the parameters
[in]x1the leftmost interval point
[in]x2the rightmost interval point
[in]abs_accthe desired absolute accuracy.(> 0 if you wish to use it).
[in]rel_accthe desired relative accuracy.(> 0 if you wish to use it).
[out]xrootthe zero of the function.
Returns
The return value is 0 on success, 1 if the root could not be found to the desired level of accurat and 2 if the the initial interval does not contain the root.

Definition at line 14 of file math_root_finders.c.

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 }
static double a
Definition: init.c:135
#define MAX(a, b)
Definition: macros.h:101
int g_maxRootIter
Maximum number of iterations for root finder.
Definition: globals.h:95
#define WARNING(a)
Definition: macros.h:217
#define DSIGN(x)
Definition: macros.h:110
long int g_stepNumber
Gives the current integration step number.
Definition: globals.h:97
#define MAX_ITER
void print(const char *fmt,...)
Definition: amrPluto.cpp:497
tuple c
Definition: menu.py:375
#define s
static Runtime q

Here is the call graph for this function:

Here is the caller graph for this function:

void Broyden ( double  x[],
int  n,
int *  check,
void(*)(int, double[], double[])  vecfunc 
)

Definition at line 335 of file math_root_finders.c.

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 }
#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
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 MAX_ROOT_EQNS
Definition: math_tools.h:37
#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
void RSolve(double **a, int n, double *d, double *b)
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
tuple c
Definition: menu.py:375
#define TOLF
Definition: math_tools.h:32
#define s
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
int i
Definition: analysis.c:2
#define ARRAY_2D(nx, ny, type)
Definition: prototypes.h:171
#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

Here is the call graph for this function:

void FDJacobian ( int  n,
double  x[],
double  fv[],
double **  df,
void(*)(int, double[], double[])  vecfunc 
)

Definition at line 239 of file math_root_finders.c.

240  {
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 }
static int n
Definition: analysis.c:3
#define EPS_FD_JAC
Definition: math_tools.h:31
int j
Definition: analysis.c:2
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
int i
Definition: analysis.c:2

Here is the caller graph for this function:

void LineSearch ( int  n,
double  xold[],
double  fold,
double  g[],
double  p[],
double  x[],
double  mf[],
double *  f,
double  stpmax,
int *  check,
void(*)(int, double[], double[])  vecfunc 
)

Definition at line 263 of file math_root_finders.c.

265  {
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 }
static double a
Definition: init.c:135
#define MAX(a, b)
Definition: macros.h:101
static int n
Definition: analysis.c:3
void print(const char *fmt,...)
Definition: amrPluto.cpp:497
#define ALF
Definition: math_tools.h:36
int i
Definition: analysis.c:2
#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

Here is the call graph for this function:

Here is the caller graph for this function:

int Ridder ( double(*)(double, void *)  Func,
void *  param,
double  x1,
double  x2,
double  abs_acc,
double  rel_acc,
double *  xroot 
)

Use Ridder's method to find the root of $ f(x) = 0$ known to lie between x1 and x2. Here the function must be in the form double Func(x,*p), where where x is the independent variable while *p is a (void) pointer to any data type containing the function parameters. Both relative and absolute accuracies can be specified and convergence is achieved by the condition that is realized first. To choose among the two accuracies, set the other one to a negative number.

Parameters
[in]*funca pointer to a function func(x, *par)
[in]*parama void pointer containing the parameters
[in]x1the leftmost interval point
[in]x2the rightmost interval point
[in]abs_accthe desired absolute accuracy (> 0 if you wish to use it).
[in]rel_accthe desired relative accuracy (> 0 if you wish to use it).
[out]xrootthe zero of the function.
Returns
The return value is 0 on success, 1 if the root could not be found to the desired level of accurat and 2 if the the initial interval does not contain the root.

Definition at line 120 of file math_root_finders.c.

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 }
#define MAX(a, b)
Definition: macros.h:101
int g_maxRootIter
Maximum number of iterations for root finder.
Definition: globals.h:95
#define WARNING(a)
Definition: macros.h:217
#define MAX_ITER
int j
Definition: analysis.c:2
void print(const char *fmt,...)
Definition: amrPluto.cpp:497
#define s
#define QUIT_PLUTO(e_code)
Definition: macros.h:125

Here is the call graph for this function: