CoolProp  4.2.5
An open-source fluid property and humid air property database
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Solvers.cpp
Go to the documentation of this file.
1 #include <vector>
2 #include "Solvers.h"
3 #include "math.h"
4 #include "MatrixMath.h"
5 #include <iostream>
6 #include "CoolPropTools.h"
7 
8 std::vector<std::vector<double> > FuncWrapperND::Jacobian(std::vector<double> x)
9 {
10  double epsilon;
11  std::size_t N = x.size();
12  std::vector<double> r, xp;
13  std::vector<std::vector<double> > J(N, std::vector<double>(N, 0));
14  std::vector<double> r0 = call(x);
15  // Build the Jacobian by column
16  for (std::size_t i = 0; i < N; ++i)
17  {
18  xp = x;
19  epsilon = 0.001*x[i];
20  xp[i] += epsilon;
21  r = call(xp);
22 
23  for(std::size_t j = 0; j < N; ++j)
24  {
25  J[j][i] = (r[j]-r0[j])/epsilon;
26  }
27  }
28  return J;
29 }
30 
47 std::vector<double> NDNewtonRaphson_Jacobian(FuncWrapperND *f, std::vector<double> x0, double tol, int maxiter, std::string *errstring)
48 {
49  int iter=0;
50  *errstring=std::string("");
51  std::vector<double> f0,v,negative_f0;
52  std::vector<std::vector<double> > J;
53  double error = 999;
54  while (iter==0 || fabs(error)>tol){
55  f0 = f->call(x0);
56  J = f->Jacobian(x0);
57 
58  // Negate f0
59  negative_f0 = f0;
60  for (unsigned int i = 0; i<f0.size(); i++){ negative_f0[i] *= -1;}
61  // find v from J*v = -f
62  v = linsolve(J, negative_f0);
63  // Update the guess
64  for (unsigned int i = 0; i<v.size(); i++){ x0[i] += v[i];}
65  error = root_sum_square(f0);
66  if (iter>maxiter){
67  *errstring=std::string("reached maximum number of iterations");
68  x0[0]=_HUGE;
69  }
70  iter++;
71  }
72  return x0;
73 }
74 
85 double Newton(FuncWrapper1D *f, double x0, double ftol, int maxiter, std::string *errstring)
86 {
87  double x, dx, fval=999;
88  int iter=1;
89  (*errstring).empty();
90  x = x0;
91  while ((iter < 2 || fabs(fval) > ftol) && iter < maxiter)
92  {
93  fval = f->call(x);
94  dx = -fval/f->deriv(x);
95  x += dx;
96 
97  if (fabs(dx/x) < 10*DBL_EPSILON)
98  {
99  return x;
100  }
101 
102  if (iter>maxiter)
103  {
104  *errstring=std::string("reached maximum number of iterations");
105  throw SolutionError(format("Newton reached maximum number of iterations"));
106  }
107  iter=iter+1;
108  }
109  return x;
110 }
111 
123 double Secant(FuncWrapper1D *f, double x0, double dx, double tol, int maxiter, std::string *errstring)
124 {
125  double x1=0,x2=0,x3=0,y1=0,y2=0,x,fval=999;
126  int iter=1;
127  *errstring=std::string("");
128 
129  if (fabs(dx)==0){ *errstring=std::string("dx cannot be zero"); return _HUGE;}
130  while ((iter<=2 || fabs(fval)>tol) && iter<maxiter)
131  {
132  if (iter==1){x1=x0; x=x1;}
133  if (iter==2){x2=x0+dx; x=x2;}
134  if (iter>2) {x=x2;}
135  fval=f->call(x);
136  if (iter==1){y1=fval;}
137  if (iter>1)
138  {
139  double deltax = x2-x1;
140  if (fabs(deltax)<1e-14)
141  {
142  if (fabs(fval) < tol*10)
143  {
144  return x;
145  }
146  else
147  {
148  throw ValueError("Step is small but not solved to tolerance");
149  }
150  }
151  y2=fval;
152  x3=x2-y2/(y2-y1)*(x2-x1);
153  y1=y2; x1=x2; x2=x3;
154 
155  }
156  if (iter>maxiter)
157  {
158  *errstring=std::string("reached maximum number of iterations");
159  throw SolutionError(format("Secant reached maximum number of iterations"));
160  }
161  iter=iter+1;
162  }
163  return x3;
164 }
165 
179 double BoundedSecant(FuncWrapper1D *f, double x0, double xmin, double xmax, double dx, double tol, int maxiter, std::string *errstring)
180 {
181  double x1=0,x2=0,x3=0,y1=0,y2=0,x,fval=999;
182  int iter=1;
183  *errstring=std::string("");
184 
185  if (fabs(dx)==0){ *errstring=std::string("dx cannot be zero"); return _HUGE;}
186  while ((iter<=3 || fabs(fval)>tol) && iter<100)
187  {
188  if (iter==1){x1=x0; x=x1;}
189  if (iter==2){x2=x0+dx; x=x2;}
190  if (iter>2) {x=x2;}
191  fval=f->call(x);
192  if (iter==1){y1=fval;}
193  if (iter>1)
194  {
195  y2=fval;
196  x3=x2-y2/(y2-y1)*(x2-x1);
197  // Check bounds, go half the way to the limit if limit is exceeded
198  if (x3 < xmin)
199  {
200  x3 = (xmin + x2)/2;
201  }
202  if (x3 > xmax)
203  {
204  x3 = (xmax + x2)/2;
205  }
206  y1=y2; x1=x2; x2=x3;
207 
208  }
209  if (iter>maxiter)
210  {
211  *errstring=std::string("reached maximum number of iterations");
212  throw SolutionError(format("BoundedSecant reached maximum number of iterations"));
213  }
214  iter=iter+1;
215  }
216  return x3;
217 }
218 
235 double Brent(FuncWrapper1D *f, double a, double b, double macheps, double t, int maxiter, std::string *errstr)
236 {
237  int iter;
238  *errstr=std::string("");
239  double fa,fb,c,fc,m,tol,d,e,p,q,s,r;
240  fa = f->call(a);
241  fb = f->call(b);
242 
243  // If one of the boundaries is to within tolerance, just stop
244  if (fabs(fb) < t) { return b;}
245  if (!ValidNumber(fb)){
246  throw ValueError(format("Brent's method f(b) is NAN for b = %g",b).c_str());
247  }
248  if (fabs(fa) < t) { return a;}
249  if (!ValidNumber(fa)){
250  throw ValueError(format("Brent's method f(a) is NAN for a = %g",a).c_str());
251  }
252  if (fa*fb>0){
253  throw ValueError(format("Inputs in Brent [%f,%f] do not bracket the root. Function values are [%f,%f]",a,b,fa,fb));
254  }
255 
256  c=a;
257  fc=fa;
258  iter=1;
259  if (fabs(fc)<fabs(fb)){
260  // Goto ext: from Brent ALGOL code
261  a=b;
262  b=c;
263  c=a;
264  fa=fb;
265  fb=fc;
266  fc=fa;
267  }
268  d=b-a;
269  e=b-a;
270  m=0.5*(c-b);
271  tol=2*macheps*fabs(b)+t;
272  while (fabs(m)>tol && fb!=0){
273  // See if a bisection is forced
274  if (fabs(e)<tol || fabs(fa) <= fabs(fb)){
275  m=0.5*(c-b);
276  d=e=m;
277  }
278  else{
279  s=fb/fa;
280  if (a==c){
281  //Linear interpolation
282  p=2*m*s;
283  q=1-s;
284  }
285  else{
286  //Inverse quadratic interpolation
287  q=fa/fc;
288  r=fb/fc;
289  m=0.5*(c-b);
290  p=s*(2*m*q*(q-r)-(b-a)*(r-1));
291  q=(q-1)*(r-1)*(s-1);
292  }
293  if (p>0){
294  q=-q;
295  }
296  else{
297  p=-p;
298  }
299  s=e;
300  e=d;
301  m=0.5*(c-b);
302  if (2*p<3*m*q-fabs(tol*q) || p<fabs(0.5*s*q)){
303  d=p/q;
304  }
305  else{
306  m=0.5*(c-b);
307  d=e=m;
308  }
309  }
310  a=b;
311  fa=fb;
312  if (fabs(d)>tol){
313  b+=d;
314  }
315  else if (m>0){
316  b+=tol;
317  }
318  else{
319  b+=-tol;
320  }
321  fb=f->call(b);
322  if (!ValidNumber(fb)){
323  throw ValueError(format("Brent's method f(t) is NAN for t = %g",b).c_str());
324  }
325  if (fb*fc>0){
326  // Goto int: from Brent ALGOL code
327  c=a;
328  fc=fa;
329  d=e=b-a;
330  }
331  if (fabs(fc)<fabs(fb)){
332  // Goto ext: from Brent ALGOL code
333  a=b;
334  b=c;
335  c=a;
336  fa=fb;
337  fb=fc;
338  fc=fa;
339  }
340  m=0.5*(c-b);
341  tol=2*macheps*fabs(b)+t;
342  iter+=1;
343  if (!ValidNumber(a)){
344  throw ValueError(format("Brent's method a is NAN").c_str());}
345  if (!ValidNumber(b)){
346  throw ValueError(format("Brent's method b is NAN").c_str());}
347  if (!ValidNumber(c)){
348  throw ValueError(format("Brent's method c is NAN").c_str());}
349  if (iter>maxiter){
350  throw SolutionError(std::string("Brent's method reached maximum number of steps of %d ", maxiter));}
351  }
352  return b;
353 }
double BoundedSecant(FuncWrapper1D *f, double x0, double xmin, double xmax, double dx, double tol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:179
double root_sum_square(std::vector< double > x)
#define DBL_EPSILON
Definition: Helmholtz.cpp:10
std::string format(const char *fmt,...)
virtual double call(double)=0
std::vector< double > x(ncmax, 0)
std::vector< std::vector< double > > linsolve(std::vector< std::vector< double > > const &A, std::vector< std::vector< double > > const &B)
Definition: MatrixMath.cpp:185
double Newton(FuncWrapper1D *f, double x0, double ftol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:85
double Brent(FuncWrapper1D *f, double a, double b, double macheps, double t, int maxiter, std::string *errstr)
Definition: Solvers.cpp:235
virtual double deriv(double)
Definition: Solvers.h:16
std::vector< double > NDNewtonRaphson_Jacobian(FuncWrapperND *f, std::vector< double > x0, double tol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:47
double Secant(FuncWrapper1D *f, double x0, double dx, double tol, int maxiter, std::string *errstring)
Definition: Solvers.cpp:123
virtual std::vector< double > call(std::vector< double >)=0
virtual std::vector< std::vector< double > > Jacobian(std::vector< double >)
Definition: Solvers.cpp:8
bool ValidNumber(double x)