HepLib
Lib3_GK.h
Go to the documentation of this file.
1 // modified version from https://github.com/drjerry/quadpackpp
2 // Adpative GaussKronrod
3 #pragma once
4 #include "Lib3_GaussKronrod.h"
5 
6 namespace {
7 
8  class FtnBase {
9  public:
10  virtual int operator() (unsigned yn, Real *y, Real *e, Real_t x) =0;
11  const unsigned n;
12  FtnBase(unsigned yn) : n(yn) { }
13  };
14  class Function : public FtnBase {
15  public:
16  typedef std::function<int(unsigned yn, Real *y, Real *e, Real_t x, void *fdata)> f1Type;
17  virtual int operator() (unsigned yn, Real *y, Real *e, Real_t x) override { return function_(yn,y,e,x,fdata_); }
18  Function(unsigned yn, const f1Type & function, void *fdata) : FtnBase(yn), function_(function), fdata_(fdata) { }
19  ~Function() { }
20  void * fdata() { return fdata_; }
21  private:
22  f1Type function_;
23  void * fdata_;
24  };
25 
26  class GK : public GaussKronrod {
27  public:
28  typedef void (*PrintHookerType) (Real*, Real*, size_t *, void *);
29  GK(size_t n, size_t m) : GaussKronrod(m) , limit(n) { }
30  int QAG(FtnBase &f, Real_t a, Real_t b, Real_t epsabs, Real_t epsrel, Real *result, Real *abserr, PrintHookerType PrintHooker);
31  private:
32  size_t limit;
33  Real rescale_error(Real err, Real_t result_abs, Real_t result_asc);
34  int qag(FtnBase &f, Real_t a, Real_t b, Real *result, Real *abserr);
35  };
36 
37  Real GK::rescale_error (Real err, Real_t result_abs, Real_t result_asc) {
38  err = abs(err);
39  if (result_asc != Real(0) && err != Real(0)) {
40  // cast 1.5 as Real number
41  Real exponent = Real(3)/Real(2);
42  Real scale = pow((200 * err / result_asc), exponent);
43  if (scale < Real(1)) err = result_asc * scale;
44  else err = result_asc;
45  }
46  if (result_abs > mpfr::minval() / (50 * mpfr::machine_epsilon())) {
47  Real min_err = 50 * mpfr::machine_epsilon() * result_abs;
48  if (min_err > err) err = min_err;
49  }
50  return err;
51  }
52 
53  int GK::qag(FtnBase &f, Real_t a, Real_t b, Real *result, Real *abserr) {
54  const Real center = (a + b) / 2;
55  const Real half_length = (b - a) / 2;
56  const Real abs_half_length = abs(half_length);
57  unsigned yn = f.n;
58  Real f_center[yn], ef_center[yn];
59  if(f(yn, f_center, ef_center, center)) return FAILURE;
60 
61  Real result_gauss[yn], result_kronrod[yn], result_abs[yn], result_asc[yn], mean[yn], err[yn];
62  for(int j=0; j<yn; j++) {
63  result_gauss[j] = Real(0);
64  result_kronrod[j] = f_center[j] * wgk_[n_ - 1];
65  result_abs[j] = abs(result_kronrod[j]);
66  result_asc[j] = mean[j] = err[j] = Real(0);
67  if (n_ % 2 == 0) result_gauss[j] = f_center[j] * wg_[n_/2 - 1];
68  }
69 
70  Real fv1[yn*n_], e_fv1[yn*n_], fv2[yn*n_], e_fv2[yn*n_];
71  if(true) { // Parallel
72  int RC1[n_], RC2[n_];
73  for(int j=0; j<n_; j++) RC1[j] = RC2[j] = 0;
74  auto prec = mpfr::mpreal::get_default_prec();
75  auto rnd = mpfr::mpreal::get_default_rnd();
76  #pragma omp parallel for
77  for(int jj = 0; jj < 2*n_; jj++) {
78  int j = jj/2, j2 = jj % 2;
79  mpfr::mpreal::set_default_prec(prec);
80  mpfr::mpreal::set_default_rnd(rnd);
81  Real abscissa = half_length * xgk_[j];
82  if(j2==0) RC1[j] = f(yn, fv1+yn*j, e_fv1+yn*j, center - abscissa);
83  else RC2[j] = f(yn, fv2+yn*j, e_fv2+yn*j, center + abscissa);
84  mpfr_free_cache();
85  }
86  for(int j=0; j<n_; j++) if(RC1[j]!=0 || RC2[j]!=0) return FAILURE;
87 
88  for(int jj=0; jj<yn; jj++) { // jj for y index
89  for(int j = 0; j < (n_ - 1) / 2; j++) {
90  int jtw = j * 2 + 1;
91  Real fval1 = fv1[yn*jtw+jj];
92  Real fval2 = fv2[yn*jtw+jj];
93  Real fsum = fval1 + fval2;
94  result_gauss[jj] += wg_[j] * fsum;
95  result_kronrod[jj] += wgk_[jtw] * fsum;
96  result_abs[jj] += wgk_[jtw] * (abs(fval1) + abs(fval2));
97  }
98 
99  for (int j = 0; j < n_ / 2; j++) {
100  int jtwm1 = j * 2;
101  Real fval1 = fv1[yn*jtwm1+jj];
102  Real fval2 = fv2[yn*jtwm1+jj];
103  result_kronrod[jj] += wgk_[jtwm1] * (fval1 + fval2);
104  result_abs[jj] += wgk_[jtwm1] * (abs(fval1) + abs(fval2));
105  }
106  }
107  } else { // Non-Parallel
108  Real fsum, fval1, fval2;
109  for (int j = 0; j < (n_ - 1) / 2; j++) {
110  int jtw = j * 2 + 1; /* j=1,2,3 jtw=2,4,6 */
111  Real abscissa = half_length * xgk_[jtw];
112  f(yn, fv1+yn*jtw, e_fv1+yn*jtw, center - abscissa);
113  f(yn, fv2+yn*jtw, e_fv2+yn*jtw, center + abscissa);
114  for(int jj=0; jj<yn; jj++) { // jj for y index
115  Real_t fval1 = fv1[yn*jtw+jj];
116  Real_t fval2 = fv2[yn*jtw+jj];
117  fsum = fval1 + fval2;
118  result_gauss[jj] += wg_[j] * fsum;
119  result_kronrod[jj] += wgk_[jtw] * fsum;
120  result_abs[jj] += wgk_[jtw] * (abs(fval1) + abs(fval2));
121  }
122  }
123 
124  for (int j = 0; j < n_ / 2; j++) {
125  int jtwm1 = j * 2;
126  Real abscissa = half_length * xgk_[jtwm1];
127  f(yn, fv1+yn*jtwm1, e_fv1+yn*jtwm1, center - abscissa);
128  f(yn, fv2+yn*jtwm1, e_fv2+yn*jtwm1, center + abscissa);
129  for(int jj=0; jj<yn; jj++) { // jj for y index
130  Real_t fval1 = fv1[yn*jtwm1+jj];
131  Real_t fval2 = fv2[yn*jtwm1+jj];
132  result_kronrod[jj] += wgk_[jtwm1] * (fval1 + fval2);
133  result_abs[jj] += wgk_[jtwm1] * (abs(fval1) + abs(fval2));
134  }
135  }
136  }
137 
138  for(int jj=0; jj<yn; jj++) { // jj for y index
139  mean[jj] = result_kronrod[jj] / 2;
140  result_asc[jj] = wgk_[n_ - 1] * abs(f_center[jj] - mean[jj]);
141  for (int j = 0; j < n_ - 1; j++) {
142  result_asc[jj] += wgk_[j] * (abs(fv1[yn*j+jj] - mean[jj]) + abs(fv2[yn*j+jj] - mean[jj]));
143  }
144  /* scale by the width of the integration region */
145  err[jj] = (result_kronrod[jj] - result_gauss[jj]) * half_length;
146  result_kronrod[jj] *= half_length;
147  result_abs[jj] *= abs_half_length;
148  result_asc[jj] *= abs_half_length;
149  result[jj] = result_kronrod[jj];
150  abserr[jj] = rescale_error (err[jj], result_abs[jj], result_asc[jj]);
151  }
152 
153  return SUCCESS;
154  }
155 
156  inline Real max(unsigned yn, Real *x) {
157  Real max = x[0];
158  for(int j=1; j<yn; j++) if(max<x[j]) max = x[j];
159  return max;
160  }
161 
162  int GK::QAG(FtnBase &f, Real_t a, Real_t b, Real_t epsabs, Real_t epsrel, Real *result, Real *abserr, PrintHookerType PrintHooker) {
163  size_t size;
164  size_t nrmax;
165  size_t i_work;
166  size_t maximum_level;
167 
168  unsigned yn = f.n;
169  size_t n = limit;
170  Real alist[n], blist[n], rlist[n][yn], elist[n][yn];
171  size_t order[n], level[n];
172  size = 0;
173  maximum_level = 0;
174 
175  Real area[yn], errsum[yn], result0[yn], abserr0[yn], tolerance[yn];
176  size_t iteration = 0;
177 
178  {
179  size = 0;
180  nrmax = 0;
181  i_work = 0;
182  alist[0] = a;
183  blist[0] = b;
184  for(int j=0; j<yn; j++) rlist[0][j] = elist[0][j] = Real(0);
185  order[0] = 0;
186  level[0] = 0;
187  maximum_level = 0;
188  }
189  for(int j=0; j<yn; j++) result[j] = abserr[j] = Real(0);
190 
191  if(this->qag(f, a, b, result0, abserr0)) return FAILURE;
192  {
193  size = 1;
194  for(int j=0; j<yn; j++) {
195  rlist[0][j] = result0[j];
196  elist[0][j] = abserr0[j];
197  }
198  }
199 
200  /* Test on accuracy */
201  for(int j=0; j<yn; j++) tolerance[j] = max (epsabs, epsrel * abs(result0[j]));
202  bool ok = true;
203  for(int j=0; j<yn; j++) {
204  if(abserr0[j]>tolerance[j]) { ok = false; break; }
205  }
206 
207  if (ok) {
208  for(int j=0; j<yn; j++) {
209  result[j] = result0[j];
210  abserr[j] = abserr0[j];
211  }
212  size_t kk = 1;
213  auto fdata = ((Function&)f).fdata();
214  if(PrintHooker) PrintHooker(result, abserr, &kk, fdata);
215  return SUCCESS;
216  }
217 
218  for(int j=0; j<yn; j++) {
219  area[j] = result0[j];
220  errsum[j] = abserr0[j];
221  }
222  iteration = 1;
223 
224  do {
225  Real a1, b1, a2, b2;
226  Real a_i, b_i, r_i[yn], e_i[yn];
227  Real area1[yn], area2[yn], area12[yn];
228  Real error1[yn], error2[yn], error12[yn];
229 
230  for(int j=0; j<yn; j++) {
231  area1[j] = area2[j] = area12[j] = error1[j] = error2[j] = error12[j] = Real(0);
232  }
233 
234  /* Bisect the subinterval with the largest error estimate */
235 
236  {
237  a_i = alist[i_work];
238  b_i = blist[i_work];
239  for(int j=0; j<yn; j++) {
240  r_i[j] = rlist[i_work][j];
241  e_i[j] = elist[i_work][j];
242  }
243  }
244 
245  a1 = a_i;
246  b1 = (a_i + b_i) / Real(2);
247  a2 = b1;
248  b2 = b_i;
249 
250  if(this->qag(f, a1, b1, area1, error1)) return FAILURE;
251  if(this->qag(f, a2, b2, area2, error2)) return FAILURE;
252 
253  for(int j=0; j<yn; j++) {
254  area12[j] = area1[j] + area2[j];
255  error12[j] = error1[j] + error2[j];
256 
257  errsum[j] += (error12[j] - e_i[j]);
258  area[j] += area12[j] - r_i[j];
259 
260  tolerance[j] = max (epsabs, epsrel * abs(area[j]));
261  }
262 
263  {
264  const size_t i_max = i_work;
265  const size_t i_new = size;
266 
267  const size_t new_level = level[i_max] + 1;
268 
269  /* append the newly-created intervals to the list */
270 
271  if (max(yn,error2) > max(yn,error1)) {
272  alist[i_max] = a2; /* blist[maxerr] is already == b2 */
273  for(int j=0; j<yn; j++) {
274  rlist[i_max][j] = area2[j];
275  elist[i_max][j] = error2[j];
276  }
277  level[i_max] = new_level;
278 
279  alist[i_new] = a1;
280  blist[i_new] = b1;
281  for(int j=0; j<yn; j++) {
282  rlist[i_new][j] = area1[j];
283  elist[i_new][j] = error1[j];
284  }
285  level[i_new] = new_level;
286  } else {
287  blist[i_max] = b1; /* alist[maxerr] is already == a1 */
288  for(int j=0; j<yn; j++) {
289  rlist[i_max][j] = area1[j];
290  elist[i_max][j] = error1[j];
291  }
292  level[i_max] = new_level;
293 
294  alist[i_new] = a2;
295  blist[i_new] = b2;
296  for(int j=0; j<yn; j++) {
297  rlist[i_new][j] = area2[j];
298  elist[i_new][j] = error2[j];
299  }
300  level[i_new] = new_level;
301  }
302 
303  size++;
304 
305  if (new_level > maximum_level) maximum_level = new_level;
306 
307  {
308  const size_t last = size - 1;
309 
310  Real errmax, errmin;
311  int i, k, top;
312 
313  size_t i_nrmax = nrmax;
314  size_t i_maxerr = order[i_nrmax];
315 
316  /* Check whether the list contains more than two error estimates */
317  if (last < 2) {
318  order[0] = 0;
319  order[1] = 1;
320  i_work = i_maxerr;
321  } else {
322  errmax = max(yn,elist[i_maxerr]);
323  while (i_nrmax > 0 && errmax > max(yn,elist[order[i_nrmax - 1]])) {
324  order[i_nrmax] = order[i_nrmax - 1];
325  i_nrmax--;
326  }
327  if(last < (limit/2 + 2)) top = last;
328  else top = limit - last + 1;
329  i = i_nrmax + 1;
330  while (i < top && errmax < max(yn,elist[order[i]])) {
331  order[i-1] = order[i];
332  i++;
333  }
334  order[i-1] = i_maxerr;
335  errmin = max(yn,elist[last]);
336  k = top - 1;
337  while (k > i - 2 && errmin >= max(yn,elist[order[k]])) {
338  order[k+1] = order[k];
339  k--;
340  }
341  order[k+1] = last;
342  /* Set i_max and e_max */
343  i_maxerr = order[i_nrmax];
344  i_work = i_maxerr;
345  nrmax = i_nrmax;
346  }
347  }
348  }
349 
350  {
351  a_i = alist[i_work];
352  b_i = blist[i_work];
353  for(int j=0; j<yn; j++) {
354  r_i[j] = rlist[i_work][j];
355  e_i[j] = elist[i_work][j];
356  }
357  }
358 
359  if(PrintHooker) {
360  size_t kk = iteration;
361  auto fdata = ((Function&)f).fdata();
362  PrintHooker(area, errsum, &kk, fdata);
363  if(kk!=iteration) {
364  for(int j=0; j<yn; j++) {
365  result[j] = area[j];
366  abserr[j] = errsum[j];
367  }
368  return SUCCESS;
369  }
370  }
371  ok = true;
372  for(int j=0; j<yn; j++) {
373  if(errsum[j]>tolerance[j]) { ok = false; break; }
374  }
375  iteration++;
376  } while (iteration < limit && !ok);
377 
378  for(int j=0; j<yn; j++) {
379  result[j] = Real(0);
380  for (size_t k = 0; k < size; k++) result[j] += rlist[k][j];
381  abserr[j] = errsum[j];
382  }
383 
384  return SUCCESS;
385  }
386 
387 }
int * a
Definition: Functions.cpp:234
#define FAILURE
#define SUCCESS