Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
quadr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22/*
23This file is part of Vlasiator.
24*/
25
26#include <math.h>
27#include <stdlib.h>
28
29#include "quadr.hpp"
30
31/*
32 1D,2D,3D Romberg non-singular integration a'la Numerical Recipes.
33 Integration bounds must be constants.
34 Header file is quadr.H.
35 Test program is tstquadr.C
36 Same in Mathematica is tstquadr.ma
37*/
38
39static void trapez(const T1DFunction& func, double a, double b, double& S, int& it, int n)
40/* Compute the nth stage of refinement of extended trapezoidal rule.
41 When called with n=1, it returns S as the crudest estimate of the integral.
42 Subsequent calls with n=2,3,... (in that sequential order) will improve
43 the accuracy of S by adding 2^(n-2) additional interior points.
44 The argument it need not be assigned a value before, but:
45 *** S and it must not be modified between sequential calls! ***/
46{
47 int j;
48 if (n == 1) {
49 S = 0.5*(b-a)*(func(a) + func(b));
50 it = 1;
51 //recflops(4);
52 } else {
53 const double delta = (b-a)/it; // the spacing of points to be added
54 double x = a + 0.5*delta;
55 double sum = 0;
56 for (j=0; j<it; j++) {
57 sum+= func(x);
58 x+= delta;
59 }
60 S = 0.5*(S + (b-a)*sum/it); // replacement of S by its refined value
61 it*= 2;
62 //recflops(6+2*flops_div+it*2);
63 }
64}
65
66static void polint(const double xa[], const double ya[], int n, double x, double& y, double& dy)
67/* Given arrays xa and ya, each of length n, and given a value x,
68 return y and error estimate dy. If P(x) is the polynomial of degree n-1 such
69 that P(xa[i]) == ya[i], i=0..n-1, then the returned value y is P(x).*/
70{
71 int i,m,ns;
72 const int nmax = 20;
73 double C[nmax],D[nmax];
74 ns = 0;
75 double dif = fabs(x-xa[0]);
76 for (i=0; i<n; i++) {
77 double dift = fabs(x-xa[i]);
78 if (dift < dif) {
79 ns = i;
80 dif = dift;
81 }
82 C[i] = D[i] = ya[i];
83 }
84 //recflops(n*2);
85 y = ya[ns];
86 ns--;
87 for (m=0; m<n-1; m++) {
88 for (i=0; i<n-m-1; i++) {
89 const double h0 = xa[i] - x;
90 const double hp = xa[i+m+1] - x;
91 const double W = C[i+1] - D[i];
92 double den = h0 - hp;
93 den = W/den;
94 D[i] = hp*den;
95 C[i] = h0*den;
96 }
97 if (2*(ns+1) < n-m-1)
98 dy = C[ns+1];
99 else {
100 dy = D[ns];
101 ns--;
102 }
103 y+= dy;
104 }
105 //recflops((n-1)*((6+flops_div)*(n-m-1)+1));
106}
107
108static void ratint(const double xa[], const double ya[], int n, double x, double& y, double& dy)
109/* Given arrays xa and ya, each of length n, and given a value x,
110 return y and error estimate dy. The value returned is that of the diagonal rational
111 function, evaluated at x, which passed through the n points (xa[i],ya[i]), i=0..n-1. */
112{
113 int i,ns=0;
114 double w,t,hh,h,dd;
115 const int nmax = 20;
116 const double tiny = 1e-30; // a small number, smaller than anything...
117 double C[nmax],D[nmax];
118 hh = fabs(x-xa[0]);
119 for (i=0; i<n; i++) {
120 h = fabs(x-xa[i]);
121 if (h == 0) {
122 y = ya[i];
123 dy = 0;
124 return;
125 } else if (h < hh) {
126 ns = i;
127 hh = h;
128 }
129 C[i] = ya[i];
130 D[i] = ya[i] + tiny; // avoid 0/0 situation
131 }
132 //recflops(2+n*3);
133 y = ya[ns--];
134 int m1;
135 for (m1=1; m1<n; m1++) {
136 for (i=0; i<n-m1; i++) {
137 w = C[i+1] - D[i];
138 h = xa[i+m1] - x;
139 t = (xa[i] - x)*D[i]/h; // h will never be zero since this was tested above
140 dd = t - C[i+1];
141 if (dd == 0) {
142 cerr << "*** Error in ratint\n";
143 exit(111);
144 }
145 // this error occurs if the interpolating function has a pole at the requested value of x
146 dd = w/dd;
147 D[i] = C[i+1]*dd;
148 C[i] = t*dd;
149 }
150 //recflops((n-m1)*(7+2*flops_div));
151 y+= (dy = (2*(ns+1) < (n-m1) ? C[ns+1] : D[ns--]));
152 }
153}
154
155double Romberg_simple(const T1DFunction& func, double a, double b, double absacc)
156{
157 int j,k1, it = 0;
158 const int jmax = 8/*10*//*20*/; // maximum number of steps
159 const int k = 3/*4*//*5*/; // (maximum) number of points used in the extrapolation
160 double S[jmax+1]; // successive trapezoidal approximations
161 double H[jmax+1]; // and their step sizes
162 H[0] = 1;
163 double result = 0, dresult = 0;
164 for (j=1; j<=jmax; j++) {
165 trapez(func,a,b,S[j-1],it,j);
166 result = S[j-1];
167 if (j >= 1/*k*/) {
168 k1 = (j < k) ? j : k;
169 polint(&H[j-k1],&S[j-k1],k1,0.,result,dresult);
170 if (fabs(dresult) < absacc) {/*cout << "dresult=" << dresult << ", absacc=" << absacc << "\n";*/ break;}
171 }
172 S[j] = S[j-1];
173 H[j] = 0.25*H[j-1];
174 }
175// if (j > jmax) clog << "warning: romberg had " << j << " steps, result=" << result << ", dresult=" << dresult << "\n";
176 return result;
177}
178
179double Romberg(const T1DFunction& func, double a, double b, double absacc)
180{
181 int j, k1, it = 0;
182 const int jmax = 8/*20*/; // maximum number of steps
183 const int k = 5/*3*//*4*//*5*/; // Maximum number of points used in the extrapolation
184 const int min_k = 2/*k*/; // Minimum number of points used in the interpolation
185 double S[jmax+1]; // successive trapezoidal approximations
186 double H[jmax+1]; // and their step sizes
187 H[0] = 1;
188 double result=0, result_pol=0, result_rat=0;
189 double dresult, dresult_pol = 0, dresult_rat, dresult_polrat;
190 for (j=1; j<=jmax; j++) {
191 trapez(func,a,b,S[j-1],it,j);
192 result = S[j-1];
193 if (j >= min_k) {
194 k1 = (j < k) ? j : k;
195 // Try both rational and polynomial extrapolation.
196 // The error estimate is max(dresult_pol, dresult_rat, fabs(result_pol - result_rat));
197 polint(&H[j-k1],&S[j-k1],k1,0.,result_pol,dresult_pol);
198 ratint(&H[j-k1],&S[j-k1],k1,0.,result_rat,dresult_rat);
199 dresult_pol = fabs(dresult_pol);
200 dresult_rat = fabs(dresult_rat);
201 dresult = (dresult_pol > dresult_rat ? dresult_pol : dresult_rat);
202 dresult_polrat = fabs(result_pol - result_rat);
203 if (dresult_polrat > dresult) dresult = dresult_polrat;
204 if (dresult < absacc) {
205 //cout << "dresult=" << dresult << ", absacc=" << absacc << "\n";
206 result = 0.5*(result_pol + result_rat);
207 break;
208 }
209 }
210 S[j] = S[j-1];
211 H[j] = 0.25*H[j-1];
212 }
213// if (j > jmax) cout << "warning: romberg had " << j << " steps, result=" << result << ", dresult=" << dresult << "\n";
214 return result;
215}
216
217// 2D
218double Romberg(const T2DFunction& func, double a, double b, double c, double d, double absacc) {
219// cout << "2d romberg a=" << a << ", b=" << b << ", c=" << c << ", d=" << d << ", absacc=" << absacc << "\n";
220
221 T1DFunction Tinty = [=](double x)->double {
222 return Romberg( std::bind(func, x, std::placeholders::_1), c, d,absacc/(b-a));
223 };
224 return Romberg(Tinty,a,b,absacc);
225}
226
227// 3D
228double Romberg(const T3DFunction& func, double a, double b, double c, double d, double e, double f, double absacc) {
229 T1DFunction Tintxy = [=](double z)->double {
230 return Romberg(std::bind(func, std::placeholders::_1, std::placeholders::_2, z), a,b,c,d,absacc/(f-e));
231 };
232 return Romberg(Tintxy,e,f,absacc);
233}
for i
Definition Dispersion.m:24
Constants c
Definition Dispersion.m:45
std::function< double(double, double)> T2DFunction
Definition functions.hpp:31
std::function< double(double, double, double)> T3DFunction
Definition functions.hpp:32
std::function< double(double)> T1DFunction
Definition functions.hpp:30
const int j
const int k
static void ratint(const double xa[], const double ya[], int n, double x, double &y, double &dy)
Definition quadr.cpp:108
double Romberg(const T1DFunction &func, double a, double b, double absacc)
Definition quadr.cpp:179
double Romberg_simple(const T1DFunction &func, double a, double b, double absacc)
Definition quadr.cpp:155
static void trapez(const T1DFunction &func, double a, double b, double &S, int &it, int n)
Definition quadr.cpp:39
static void polint(const double xa[], const double ya[], int n, double x, double &y, double &dy)
Definition quadr.cpp:66