PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
cubature.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005 Steven G. Johnson
3  *
4  * Portions (see comments) based on HIntLib (also distributed under
5  * the GNU GPL), copyright (c) 2002-2005 Rudolf Schuerer.
6  *
7  * Portions (see comments) based on GNU GSL (also distributed under
8  * the GNU GPL), copyright (c) 1996-2000 Brian Gough.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  */
25 
26 /* CHANGELOG:
27 
28 15jan09 E. Bueler: initialization values for esterr struct; stops warnings
29  from -Wall
30 
31 16Sep10 C. Khroulev: very minor changes to get rid of *very* pedantic warnings
32 
33 23Jan15 C. Khroulev: avoid calling realloc(ptr, 0) (see heap_free())
34 */
35 
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40 #include <limits.h>
41 #include <float.h>
42 
43 #include "cubature.h"
44 
45 /* Basic datatypes */
46 
47 typedef struct {
48  double val, err;
49 } esterr;
50 
51 static double relError(esterr ee)
52 {
53  return (ee.val == 0.0 ? HUGE_VAL : fabs(ee.err / ee.val));
54 }
55 
56 typedef struct {
57  unsigned dim;
58  double *data; /* length 2*dim = center followed by half-width */
59  double vol; /* cache volume = product of widths */
60 } hypercube;
61 
62 static double compute_vol(const hypercube *h)
63 {
64  unsigned i;
65  double vol = 1;
66  for (i = 0; i < h->dim; ++i)
67  vol *= 2 * h->data[i + h->dim];
68  return vol;
69 }
70 
71 static hypercube make_hypercube(unsigned dim, const double *center, const double *width)
72 {
73  unsigned i;
74  hypercube h;
75  h.dim = dim;
76  h.data = (double *) malloc(sizeof(double) * dim * 2);
77  for (i = 0; i < dim; ++i) {
78  h.data[i] = center[i];
79  h.data[i + dim] = width[i];
80  }
81  h.vol = compute_vol(&h);
82  return h;
83 }
84 
85 static hypercube make_hypercube_range(unsigned dim, const double *xmin, const double *xmax)
86 {
87  hypercube h = make_hypercube(dim, xmin, xmax);
88  unsigned i;
89  for (i = 0; i < dim; ++i) {
90  h.data[i] = 0.5 * (xmin[i] + xmax[i]);
91  h.data[i + dim] = 0.5 * (xmax[i] - xmin[i]);
92  }
93  h.vol = compute_vol(&h);
94  return h;
95 }
96 
98 {
99  free(h->data);
100  h->dim = 0;
101 }
102 
103 typedef struct {
106  unsigned splitDim;
107 } region;
108 
109 static region make_region(const hypercube *h)
110 {
111  region R;
112  /* initialization values by E. Bueler 1/15/09 */
113  R.ee.err = 1.0e30; R.ee.val = 1.0e30;
114  R.h = make_hypercube(h->dim, h->data, h->data + h->dim);
115  R.splitDim = 0;
116  return R;
117 }
118 
119 static void destroy_region(region *R)
120 {
121  destroy_hypercube(&R->h);
122 }
123 
124 static void cut_region(region *R, region *R2)
125 {
126  unsigned d = R->splitDim, dim = R->h.dim;
127  *R2 = *R;
128  R->h.data[d + dim] *= 0.5;
129  R->h.vol *= 0.5;
130  R2->h = make_hypercube(dim, R->h.data, R->h.data + dim);
131  R->h.data[d] -= R->h.data[d + dim];
132  R2->h.data[d] += R->h.data[d + dim];
133 }
134 
135 typedef struct rule_s {
136  unsigned dim; /* the dimensionality */
137  unsigned num_points; /* number of evaluation points */
138  unsigned (*evalError)(struct rule_s *r, integrand f, void *fdata,
139  const hypercube *h, esterr *ee);
140  void (*destroy)(struct rule_s *r);
142 
143 static void destroy_rule(rule *r)
144 {
145  if (r->destroy) r->destroy(r);
146  free(r);
147 }
148 
149 static region eval_region(region R, integrand f, void *fdata, rule *r)
150 {
151  R.splitDim = r->evalError(r, f, fdata, &R.h, &R.ee);
152  return R;
153 }
154 
155 /***************************************************************************/
156 /* Functions to loop over points in a hypercube. */
157 
158 /* Based on orbitrule.cpp in HIntLib-0.0.10 */
159 
160 /* ls0 returns the least-significant 0 bit of n (e.g. it returns
161  0 if the LSB is 0, it returns 1 if the 2 LSBs are 01, etcetera). */
162 
163 #if (defined(__GNUC__) || defined(__ICC)) && (defined(__i386__) || defined (__x86_64__))
164 /* use x86 bit-scan instruction, based on count_trailing_zeros()
165  macro in GNU GMP's longlong.h. */
166 static unsigned ls0(unsigned n)
167 {
168  unsigned count;
169  n = ~n;
170  __asm__("bsfl %1,%0": "=r"(count):"rm"(n));
171  return count;
172 }
173 #else
174 static unsigned ls0(unsigned n)
175 {
176  const unsigned bits[] = {
177  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
178  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
179  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
180  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,
181  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
182  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
183  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
184  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7,
185  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
186  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
187  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
188  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6,
189  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
190  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,
191  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,
192  0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 8,
193  };
194  unsigned bit;
195  bit = 0;
196  while ((n & 0xff) == 0xff) {
197  n >>= 8;
198  bit += 8;
199  }
200  return bit + bits[n & 0xff];
201 }
202 #endif
203 
204 /**
205  * Evaluate the integral on all 2^n points (+/-r,...+/-r)
206  *
207  * A Gray-code ordering is used to minimize the number of coordinate updates
208  * in p.
209  */
210 static double evalR_Rfs(integrand f, void *fdata, unsigned dim, double *p, const double *c, const
211 double *r)
212 {
213  double sum = 0;
214  unsigned i;
215  unsigned signs = 0; /* 0/1 bit = +/- for corresponding element of r[] */
216 
217  /* We start with the point where r is ADDed in every coordinate (This implies signs=0) */
218  for (i = 0; i < dim; ++i)
219  p[i] = c[i] + r[i];
220 
221  /* Loop through the points in gray-code ordering */
222  for (i = 0;; ++i) {
223  unsigned mask, d;
224 
225  sum += f(dim, p, fdata);
226 
227  d = ls0(i); /* which coordinate to flip */
228  if (d >= dim)
229  break;
230 
231  /* flip the d-th bit and add/subtract r[d] */
232  mask = 1U << d;
233  signs ^= mask;
234  p[d] = (signs & mask) ? c[d] - r[d] : c[d] + r[d];
235  }
236  return sum;
237 }
238 
239 static double evalRR0_0fs(integrand f, void *fdata, unsigned dim, double *p, const double *c,
240 const double *r)
241 {
242  unsigned i, j;
243  double sum = 0;
244 
245  for (i = 0; i < dim - 1; ++i) {
246  p[i] = c[i] - r[i];
247  for (j = i + 1; j < dim; ++j) {
248  p[j] = c[j] - r[j];
249  sum += f(dim, p, fdata);
250  p[i] = c[i] + r[i];
251  sum += f(dim, p, fdata);
252  p[j] = c[j] + r[j];
253  sum += f(dim, p, fdata);
254  p[i] = c[i] - r[i];
255  sum += f(dim, p, fdata);
256 
257  p[j] = c[j]; /* Done with j -> Restore p[j] */
258  }
259  p[i] = c[i]; /* Done with i -> Restore p[i] */
260  }
261  return sum;
262 }
263 
264 /* static double evalR0_0fs4d(integrand f, void *fdata, unsigned dim, double *p, const double *c,
265 double *sum0_, const double *r1, double *sum1_, const double *r2, double *sum2_) */
266 static unsigned evalR0_0fs4d(integrand f, void *fdata, unsigned dim, double *p, const double *c,
267 double *sum0_, const double *r1, double *sum1_, const double *r2, double *sum2_)
268 {
269  double maxdiff = 0;
270  unsigned i, dimDiffMax = 0;
271  double sum0, sum1 = 0, sum2 = 0; /* copies for aliasing, performance */
272 
273  double ratio = r1[0] / r2[0];
274 
275  ratio *= ratio;
276  sum0 = f(dim, p, fdata);
277 
278  for (i = 0; i < dim; i++) {
279  double f1a, f1b, f2a, f2b, diff;
280 
281  p[i] = c[i] - r1[i];
282  sum1 += (f1a = f(dim, p, fdata));
283  p[i] = c[i] + r1[i];
284  sum1 += (f1b = f(dim, p, fdata));
285  p[i] = c[i] - r2[i];
286  sum2 += (f2a = f(dim, p, fdata));
287  p[i] = c[i] + r2[i];
288  sum2 += (f2b = f(dim, p, fdata));
289  p[i] = c[i];
290 
291  diff = fabs(f1a + f1b - 2 * sum0 - ratio * (f2a + f2b - 2 * sum0));
292 
293  if (diff > maxdiff) {
294  maxdiff = diff;
295  dimDiffMax = i;
296  }
297  }
298 
299  *sum0_ += sum0;
300  *sum1_ += sum1;
301  *sum2_ += sum2;
302 
303  return dimDiffMax;
304 }
305 
306 #define num0_0(dim) (1U)
307 #define numR0_0fs(dim) (2 * (dim))
308 #define numRR0_0fs(dim) (2 * (dim) * (dim-1))
309 #define numR_Rfs(dim) (1U << (dim))
310 
311 /***************************************************************************/
312 /* Based on rule75genzmalik.cpp in HIntLib-0.0.10: An embedded
313  cubature rule of degree 7 (embedded rule degree 5) due to A. C. Genz
314  and A. A. Malik. See:
315 
316  A. C. Genz and A. A. Malik, "An imbedded [sic] family of fully
317  symmetric numerical integration rules," SIAM
318  J. Numer. Anal. 20 (3), 580-588 (1983).
319 */
320 
321 typedef struct {
323 
324  /* temporary arrays of length dim */
325  double *widthLambda, *widthLambda2, *p;
326 
327  /* dimension-dependent constants */
328  double weight1, weight3, weight5;
329  double weightE1, weightE3;
331 
332 #define real(x) ((double)(x))
333 #define to_int(n) ((int)(n))
334 
335 static int isqr(int x)
336 {
337  return x * x;
338 }
339 
341 {
342  rule75genzmalik *r = (rule75genzmalik *) r_;
343  free(r->p);
344 }
345 
346 static unsigned rule75genzmalik_evalError(rule *r_, integrand f, void *fdata, const hypercube *h,
347 esterr *ee)
348 {
349  /* lambda2 = sqrt(9/70), lambda4 = sqrt(9/10), lambda5 = sqrt(9/19) */
350  const double lambda2 = 0.3585685828003180919906451539079374954541;
351  const double lambda4 = 0.9486832980505137995996680633298155601160;
352  const double lambda5 = 0.6882472016116852977216287342936235251269;
353  const double weight2 = 980. / 6561.;
354  const double weight4 = 200. / 19683.;
355  const double weightE2 = 245. / 486.;
356  const double weightE4 = 25. / 729.;
357 
358  rule75genzmalik *r = (rule75genzmalik *) r_;
359  unsigned i, dimDiffMax, dim = r_->dim;
360  double sum1 = 0.0, sum2 = 0.0, sum3 = 0.0, sum4, sum5, result, res5th;
361  const double *center = h->data;
362  const double *width = h->data + dim;
363 
364  for (i = 0; i < dim; ++i)
365  r->p[i] = center[i];
366 
367  for (i = 0; i < dim; ++i)
368  r->widthLambda2[i] = width[i] * lambda2;
369  for (i = 0; i < dim; ++i)
370  r->widthLambda[i] = width[i] * lambda4;
371 
372  /* Evaluate function in the center, in f(lambda2,0,...,0) and
373  f(lambda3=lambda4, 0,...,0). Estimate dimension with largest error */
374  dimDiffMax = evalR0_0fs4d(f, fdata, dim, r->p, center, &sum1, r->widthLambda2, &sum2,
375 r->widthLambda, &sum3);
376 
377  /* Calculate sum4 for f(lambda4, lambda4, 0, ...,0) */
378  sum4 = evalRR0_0fs(f, fdata, dim, r->p, center, r->widthLambda);
379 
380  /* Calculate sum5 for f(lambda5, lambda5, ..., lambda5) */
381  for (i = 0; i < dim; ++i)
382  r->widthLambda[i] = width[i] * lambda5;
383  sum5 = evalR_Rfs(f, fdata, dim, r->p, center, r->widthLambda);
384 
385  /* Calculate fifth and seventh order results */
386 
387  result = h->vol * (r->weight1 * sum1 + weight2 * sum2 + r->weight3 * sum3 + weight4 * sum4 +
388 r->weight5 * sum5);
389  res5th = h->vol * (r->weightE1 * sum1 + weightE2 * sum2 + r->weightE3 * sum3 + weightE4 *
390 sum4);
391 
392  ee->val = result;
393  ee->err = fabs(res5th - result);
394 
395  return dimDiffMax;
396 }
397 
398 static rule *make_rule75genzmalik(unsigned dim)
399 {
400  rule75genzmalik *r;
401 
402  if (dim < 2) return 0; /* this rule does not support 1d integrals */
403 
404  r = (rule75genzmalik *) malloc(sizeof(rule75genzmalik));
405  r->parent.dim = dim;
406 
407  r->weight1 = (real(12824 - 9120 * to_int(dim) + 400 * isqr(to_int(dim)))
408  / real(19683));
409  r->weight3 = real(1820 - 400 * to_int(dim)) / real(19683);
410  r->weight5 = real(6859) / real(19683) / real(1U << dim);
411  r->weightE1 = (real(729 - 950 * to_int(dim) + 50 * isqr(to_int(dim)))
412  / real(729));
413  r->weightE3 = real(265 - 100 * to_int(dim)) / real(1458);
414 
415  r->p = (double *) malloc(sizeof(double) * dim * 3);
416  r->widthLambda = r->p + dim;
417  r->widthLambda2 = r->p + 2 * dim;
418 
419  r->parent.num_points = num0_0(dim) + 2 * numR0_0fs(dim)
420  + numRR0_0fs(dim) + numR_Rfs(dim);
421 
424 
425  return (rule *) r;
426 }
427 
428 /***************************************************************************/
429 /* 1d 15-point Gaussian quadrature rule, based on qk15.c and qk.c in
430  GNU GSL (which in turn is based on QUADPACK). */
431 
432 static unsigned rule15gauss_evalError(rule *r, integrand f, void *fdata,
433  const hypercube *h, esterr *ee)
434 {
435  /* Gauss quadrature weights and kronrod quadrature abscissae and
436  weights as evaluated with 80 decimal digit arithmetic by
437  L. W. Fullerton, Bell Labs, Nov. 1981. */
438  const unsigned n = 8;
439  const double xgk[8] = { /* abscissae of the 15-point kronrod rule */
440  0.991455371120812639206854697526329,
441  0.949107912342758524526189684047851,
442  0.864864423359769072789712788640926,
443  0.741531185599394439863864773280788,
444  0.586087235467691130294144838258730,
445  0.405845151377397166906606412076961,
446  0.207784955007898467600689403773245,
447  0.000000000000000000000000000000000
448  /* xgk[1], xgk[3], ... abscissae of the 7-point gauss rule.
449  xgk[0], xgk[2], ... to optimally extend the 7-point gauss rule */
450  };
451  static const double wg[4] = { /* weights of the 7-point gauss rule */
452  0.129484966168869693270611432679082,
453  0.279705391489276667901467771423780,
454  0.381830050505118944950369775488975,
455  0.417959183673469387755102040816327
456  };
457  static const double wgk[8] = { /* weights of the 15-point kronrod rule */
458  0.022935322010529224963732008058970,
459  0.063092092629978553290700663189204,
460  0.104790010322250183839876322541518,
461  0.140653259715525918745189590510238,
462  0.169004726639267902826583426598550,
463  0.190350578064785409913256402421014,
464  0.204432940075298892414161999234649,
465  0.209482141084727828012999174891714
466  };
467 
468  const double center = h->data[0];
469  const double width = h->data[1];
470  double fv1[7], fv2[7]; /* C. Khroulev, 16Sep10: hard-wired 7 = n - 1 */
471  const double f_center = f(1, &center, fdata);
472  double result_gauss = f_center * wg[n/2 - 1];
473  double result_kronrod = f_center * wgk[n - 1];
474  double result_abs = fabs(result_kronrod);
475  double result_asc, mean, err;
476  unsigned j;
477 
478  if (r == NULL) {} /* should quash unused parameter pedantic msg */
479 
480  for (j = 0; j < (n - 1) / 2; ++j) {
481  unsigned int j2 = 2*j + 1;
482  double x, f1, f2, fsum, w = width * xgk[j2];
483  x = center - w; fv1[j2] = f1 = f(1, &x, fdata);
484  x = center + w; fv2[j2] = f2 = f(1, &x, fdata);
485  fsum = f1 + f2;
486  result_gauss += wg[j] * fsum;
487  result_kronrod += wgk[j2] * fsum;
488  result_abs += wgk[j2] * (fabs(f1) + fabs(f2));
489  }
490 
491  for (j = 0; j < n/2; ++j) {
492  unsigned int j2 = 2*j;
493  double x, f1, f2, w = width * xgk[j2];
494  x = center - w; fv1[j2] = f1 = f(1, &x, fdata);
495  x = center + w; fv2[j2] = f2 = f(1, &x, fdata);
496  result_kronrod += wgk[j2] * (f1 + f2);
497  result_abs += wgk[j2] * (fabs(f1) + fabs(f2));
498 
499  }
500 
501  ee->val = result_kronrod * width;
502 
503  /* compute error estimate: */
504  mean = result_kronrod * 0.5;
505  result_asc = wgk[n - 1] * fabs(f_center - mean);
506  for (j = 0; j < n - 1; ++j)
507  result_asc += wgk[j] * (fabs(fv1[j]-mean) + fabs(fv2[j]-mean));
508  err = (result_kronrod - result_gauss) * width;
509  result_abs *= width;
510  result_asc *= width;
511  if (result_asc != 0 && err != 0) {
512  double scale = pow((200 * err / result_asc), 1.5);
513  if (scale < 1)
514  err = result_asc * scale;
515  else
516  err = result_asc;
517  }
518  if (result_abs > DBL_MIN / (50 * DBL_EPSILON)) {
519  double min_err = 50 * DBL_EPSILON * result_abs;
520  if (min_err > err)
521  err = min_err;
522  }
523  ee->err = err;
524 
525  return 0; /* no choice but to divide 0th dimension */
526 }
527 
528 static rule *make_rule15gauss(unsigned dim)
529 {
530  rule *r;
531  if (dim != 1) return 0; /* this rule is only for 1d integrals */
532  r = (rule *) malloc(sizeof(rule));
533  r->dim = dim;
534  r->num_points = 15;
536  r->destroy = 0;
537  return r;
538 }
539 
540 /***************************************************************************/
541 /* binary heap implementation (ala _Introduction to Algorithms_ by
542  Cormen, Leiserson, and Rivest), for use as a priority queue of
543  regions to integrate. */
544 
546 #define KEY(hi) ((hi).ee.err)
547 
548 typedef struct {
549  unsigned n, nalloc;
552 } heap;
553 
554 static void heap_resize(heap *h, unsigned nalloc)
555 {
556  if (nalloc != 0) {
557  h->nalloc = nalloc;
558  h->items = (heap_item *) realloc(h->items, sizeof(heap_item) * nalloc);
559  } else {
560  h->nalloc = 0;
561  free(h->items);
562  h->items = NULL;
563  }
564 }
565 
566 static heap heap_alloc(unsigned nalloc)
567 {
568  heap h;
569  h.n = 0;
570  h.nalloc = 0;
571  h.items = 0;
572  h.ee.val = h.ee.err = 0;
573  heap_resize(&h, nalloc);
574  return h;
575 }
576 
577 /* note that heap_free does not deallocate anything referenced by the items */
578 static void heap_free(heap *h)
579 {
580  h->n = 0;
581  heap_resize(h, 0);
582 }
583 
584 static void heap_push(heap *h, heap_item hi)
585 {
586  int insert;
587 
588  h->ee.val += hi.ee.val;
589  h->ee.err += hi.ee.err;
590  insert = h->n;
591  if (++(h->n) > h->nalloc)
592  heap_resize(h, h->n * 2);
593 
594  while (insert) {
595  int parent = (insert - 1) / 2;
596  if (KEY(hi) <= KEY(h->items[parent]))
597  break;
598  h->items[insert] = h->items[parent];
599  insert = parent;
600  }
601  h->items[insert] = hi;
602 }
603 
605 {
606  heap_item ret;
607  int i, n, child;
608 
609  if (!(h->n)) {
610  fprintf(stderr, "attempted to pop an empty heap\n");
611  exit(EXIT_FAILURE);
612  }
613 
614  ret = h->items[0];
615  h->items[i = 0] = h->items[n = --(h->n)];
616  while ((child = i * 2 + 1) < n) {
617  int largest;
618  heap_item swap;
619 
620  if (KEY(h->items[child]) <= KEY(h->items[i]))
621  largest = i;
622  else
623  largest = child;
624  if (++child < n && KEY(h->items[largest]) < KEY(h->items[child]))
625  largest = child;
626  if (largest == i)
627  break;
628  swap = h->items[i];
629  h->items[i] = h->items[largest];
630  h->items[i = largest] = swap;
631  }
632 
633  h->ee.val -= ret.ee.val;
634  h->ee.err -= ret.ee.err;
635  return ret;
636 }
637 
638 /***************************************************************************/
639 
640 /* adaptive integration, analogous to adaptintegrator.cpp in HIntLib */
641 
642 static int ruleadapt_integrate(rule *r, integrand f, void *fdata, const hypercube *h, unsigned
643 maxEval, double reqAbsError, double reqRelError, esterr *ee)
644 {
645  unsigned initialRegions; /* number of initial regions (non-adaptive) */
646  unsigned minIter; /* minimum number of adaptive subdivisions */
647  unsigned maxIter; /* maximum number of adaptive subdivisions */
648  unsigned initialPoints;
649  heap regions;
650  unsigned i;
651  int status = -1; /* = ERROR */
652 
653  initialRegions = 1; /* or: use some percentage of maxEval/r->num_points */
654  initialPoints = initialRegions * r->num_points;
655  minIter = 0;
656  if (maxEval) {
657  if (initialPoints > maxEval) {
658  initialRegions = maxEval / r->num_points;
659  initialPoints = initialRegions * r->num_points;
660  }
661  maxEval -= initialPoints;
662  maxIter = maxEval / (2 * r->num_points);
663  } else
664  maxIter = UINT_MAX;
665 
666  if (initialRegions == 0)
667  return status; /* ERROR */
668 
669  regions = heap_alloc(initialRegions);
670 
671  heap_push(&regions, eval_region(make_region(h), f, fdata, r));
672  /* or:
673  if (initialRegions != 1)
674  partition(h, initialRegions, EQUIDISTANT, &regions, f,fdata, r); */
675 
676  for (i = 0; i < maxIter; ++i) {
677  region R, R2;
678  if (i >= minIter && (regions.ee.err <= reqAbsError
679  || relError(regions.ee) <= reqRelError)) {
680  status = 0; /* converged! */
681  break;
682  }
683  R = heap_pop(&regions); /* get worst region */
684  cut_region(&R, &R2);
685  heap_push(&regions, eval_region(R, f, fdata, r));
686  heap_push(&regions, eval_region(R2, f, fdata, r));
687  }
688 
689  ee->val = ee->err = 0; /* re-sum integral and errors */
690  for (i = 0; i < regions.n; ++i) {
691  ee->val += regions.items[i].ee.val;
692  ee->err += regions.items[i].ee.err;
693  destroy_region(&regions.items[i]);
694  }
695  /* printf("regions.nalloc = %d\n", regions.nalloc); */
696  heap_free(&regions);
697 
698  return status;
699 }
700 
701 int adapt_integrate(integrand f, void *fdata,
702  unsigned dim, const double *xmin, const double *xmax,
703  unsigned maxEval, double reqAbsError, double reqRelError,
704  double *val, double *estimated_error)
705 {
706  rule *r;
707  hypercube h;
708  esterr ee;
709  int status;
710  /* initialization values by E. Bueler 1/15/09 */
711  ee.err = 1.0e30; ee.val = 1.0e30;
712 
713  if (dim == 0) { /* trivial integration */
714  ee.val = f(0, xmin, fdata);
715  ee.err = 0;
716  return 0;
717  }
718  r = dim == 1 ? make_rule15gauss(dim) : make_rule75genzmalik(dim);
719  h = make_hypercube_range(dim, xmin, xmax);
720  status = ruleadapt_integrate(r, f, fdata, &h,
721  maxEval, reqAbsError, reqRelError,
722  &ee);
723  *val = ee.val;
724  *estimated_error = ee.err;
725  destroy_hypercube(&h);
726  destroy_rule(r);
727  return status;
728 }
729 
static void destroy_region(region *R)
Definition: cubature.c:119
static void cut_region(region *R, region *R2)
Definition: cubature.c:124
static hypercube make_hypercube(unsigned dim, const double *center, const double *width)
Definition: cubature.c:71
#define num0_0(dim)
Definition: cubature.c:306
region heap_item
Definition: cubature.c:545
static hypercube make_hypercube_range(unsigned dim, const double *xmin, const double *xmax)
Definition: cubature.c:85
static void destroy_rule(rule *r)
Definition: cubature.c:143
static heap heap_alloc(unsigned nalloc)
Definition: cubature.c:566
static double evalRR0_0fs(integrand f, void *fdata, unsigned dim, double *p, const double *c, const double *r)
Definition: cubature.c:239
static double relError(esterr ee)
Definition: cubature.c:51
static heap_item heap_pop(heap *h)
Definition: cubature.c:604
int adapt_integrate(integrand f, void *fdata, unsigned dim, const double *xmin, const double *xmax, unsigned maxEval, double reqAbsError, double reqRelError, double *val, double *estimated_error)
Definition: cubature.c:701
static void heap_push(heap *h, heap_item hi)
Definition: cubature.c:584
static unsigned evalR0_0fs4d(integrand f, void *fdata, unsigned dim, double *p, const double *c, double *sum0_, const double *r1, double *sum1_, const double *r2, double *sum2_)
Definition: cubature.c:266
static void heap_free(heap *h)
Definition: cubature.c:578
static double compute_vol(const hypercube *h)
Definition: cubature.c:62
static rule * make_rule75genzmalik(unsigned dim)
Definition: cubature.c:398
#define numR0_0fs(dim)
Definition: cubature.c:307
static int ruleadapt_integrate(rule *r, integrand f, void *fdata, const hypercube *h, unsigned maxEval, double reqAbsError, double reqRelError, esterr *ee)
Definition: cubature.c:642
static unsigned rule15gauss_evalError(rule *r, integrand f, void *fdata, const hypercube *h, esterr *ee)
Definition: cubature.c:432
static void destroy_hypercube(hypercube *h)
Definition: cubature.c:97
#define numRR0_0fs(dim)
Definition: cubature.c:308
static unsigned rule75genzmalik_evalError(rule *r_, integrand f, void *fdata, const hypercube *h, esterr *ee)
Definition: cubature.c:346
static void destroy_rule75genzmalik(rule *r_)
Definition: cubature.c:340
#define numR_Rfs(dim)
Definition: cubature.c:309
#define real(x)
Definition: cubature.c:332
static region eval_region(region R, integrand f, void *fdata, rule *r)
Definition: cubature.c:149
#define to_int(n)
Definition: cubature.c:333
static unsigned ls0(unsigned n)
Definition: cubature.c:174
static region make_region(const hypercube *h)
Definition: cubature.c:109
static double evalR_Rfs(integrand f, void *fdata, unsigned dim, double *p, const double *c, const double *r)
Definition: cubature.c:210
static void heap_resize(heap *h, unsigned nalloc)
Definition: cubature.c:554
#define KEY(hi)
Definition: cubature.c:546
struct rule_s rule
static rule * make_rule15gauss(unsigned dim)
Definition: cubature.c:528
static int isqr(int x)
Definition: cubature.c:335
double(* integrand)(unsigned ndim, const double *x, void *)
Definition: cubature.h:60
#define n
Definition: exactTestM.c:37
double sum(const array::Scalar &input)
Sums up all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:150
double val
Definition: cubature.c:48
double err
Definition: cubature.c:48
unsigned nalloc
Definition: cubature.c:549
heap_item * items
Definition: cubature.c:550
esterr ee
Definition: cubature.c:551
unsigned n
Definition: cubature.c:549
Definition: cubature.c:548
double * data
Definition: cubature.c:58
double vol
Definition: cubature.c:59
unsigned dim
Definition: cubature.c:57
unsigned splitDim
Definition: cubature.c:106
esterr ee
Definition: cubature.c:105
hypercube h
Definition: cubature.c:104
double weight5
Definition: cubature.c:328
double * widthLambda2
Definition: cubature.c:325
double weightE1
Definition: cubature.c:329
double weight1
Definition: cubature.c:328
double weightE3
Definition: cubature.c:329
double weight3
Definition: cubature.c:328
double * widthLambda
Definition: cubature.c:325
double * p
Definition: cubature.c:325
unsigned(* evalError)(struct rule_s *r, integrand f, void *fdata, const hypercube *h, esterr *ee)
Definition: cubature.c:138
unsigned num_points
Definition: cubature.c:137
void(* destroy)(struct rule_s *r)
Definition: cubature.c:140
unsigned dim
Definition: cubature.c:136
int count
Definition: test_cube.c:16