All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
inte_qag_gsl.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2014, Jerry Gagelman
5  and Andrew W. Steiner
6 
7  This file is part of O2scl.
8 
9  O2scl is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 3 of the License, or
12  (at your option) any later version.
13 
14  O2scl is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
21 
22  -------------------------------------------------------------------
23 */
24 /*
25  * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
26  *
27  * This program is free software; you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License as published by
29  * the Free Software Foundation; either version 3 of the License, or (at
30  * your option) any later version.
31  *
32  * This program is distributed in the hope that it will be useful, but
33  * WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35  * General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License
38  * along with this program; if not, write to the Free Software
39  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
40  * 02110-1301, USA.
41  */
42 #ifndef O2SCL_GSL_INTE_QAG_H
43 #define O2SCL_GSL_INTE_QAG_H
44 
45 /** \file inte_qag_gsl.h
46  \brief File defining \ref o2scl::inte_qag_gsl
47 */
48 #include <o2scl/inte.h>
49 #include <o2scl/inte_kronrod_gsl.h>
50 #include <o2scl/funct.h>
51 #include <o2scl/string_conv.h>
52 
53 #ifndef DOXYGEN_NO_O2NS
54 namespace o2scl {
55 #endif
56 
57  /** \brief Adaptive numerical integration of a function (without
58  singularities) on a bounded interval (GSL)
59 
60  Adaptive integration of a univariate function requires two main
61  procedures: approximating the integral on a bounded interval,
62  and estimating the approximation error. The algorithm
63  recursively refines the interval, computing the integral and its
64  error estimate on each subinterval, until the total error
65  estimate over \b all subintervals falls within the
66  user-specified tolerance. The value returned is the sum of the
67  (approximated) integrals over all subintervals.
68 
69  See \ref gslinte_subsect in the User's guide for general
70  information about the GSL integration classes.
71 
72  \future There are a few fine-tuned parameters which should
73  be re-expressed as data members in the convergence tests.
74  \future Should QUADPACK parameters in round-off tests be subject
75  to adjustments by the end user?
76  \future Add functions to examine the contents of the workspace
77  to detect regions where the integrand may be problematic;
78  possibly call these functions automatically depending on
79  verbosity settings.
80  */
81  template<class func_t=funct11> class inte_qag_gsl :
82  public inte_kronrod_gsl<func_t> {
83 
84  public:
85 
86  /// Create an integrator with the specified rule
88  }
89 
90  virtual ~inte_qag_gsl() {}
91 
92  /** \brief Integrate function \c func from \c a to \c b and place
93  the result in \c res and the error in \c err
94 
95  */
96  virtual int integ_err(func_t &func, double a, double b,
97  double &res, double &err) {
98  return qag(func,a,b,this->tol_abs,this->tol_rel,&res,&err);
99  }
100 
101 #ifndef DOXYGEN_INTERNAL
102 
103  protected:
104 
105  /** \brief Perform an adaptive integration given the coefficients,
106  and returning \c result
107 
108  \future Just move this function to integ_err().
109  */
110  int qag(func_t &func, const double a, const double b,
111  const double l_epsabs, const double l_epsrel,
112  double *result, double *abserr) {
113 
114  double area, errsum;
115  double result0, abserr0, resabs0, resasc0;
116  double tolerance;
117  size_t iteration = 0;
118  int roundoff_type1 = 0, roundoff_type2 = 0, error_type = 0;
119 
120  double round_off;
121 
122  /* Initialize results */
123 
124  this->w->initialise(a,b);
125 
126  *result = 0;
127  *abserr = 0;
128 
129  double dbl_eps=std::numeric_limits<double>::epsilon();
130 
131  if (l_epsabs <= 0 &&
132  (l_epsrel < 50 * dbl_eps || l_epsrel < 0.5e-28)) {
133  this->last_iter=0;
134  std::string estr="Tolerance cannot be achieved with given ";
135  estr+="value of tol_abs, "+dtos(l_epsabs)+", and tol_rel, "+
136  dtos(l_epsrel)+", in inte_qag_gsl::qag().";
137  O2SCL_ERR(estr.c_str(),exc_ebadtol);
138  }
139 
140  /* perform the first integration */
141 
142  this->gauss_kronrod(func,a,b,&result0,&abserr0,&resabs0,&resasc0);
143 
144  this->w->set_initial_result(result0,abserr0);
145 
146  /* Test on accuracy */
147 
148  tolerance = GSL_MAX_DBL(l_epsabs, l_epsrel * fabs (result0));
149 
150  /* need IEEE rounding here to match original quadpack behavior */
151 
152  round_off=gsl_coerce_double(50 * dbl_eps * resabs0);
153 
154  if (abserr0 <= round_off && abserr0 > tolerance) {
155 
156  *result = result0;
157  *abserr = abserr0;
158 
159  // We start with 1 here, because an integration
160  // was already performed above
161  this->last_iter=1;
162 
163  std::string estr="Cannot reach tolerance because of roundoff ";
164  estr+="error on first attempt in inte_qag_gsl::qag().";
165  O2SCL_CONV_RET(estr.c_str(),exc_eround,this->err_nonconv);
166 
167  } else if ((abserr0 <= tolerance &&
168  abserr0 != resasc0) || abserr0 == 0.0) {
169  *result = result0;
170  *abserr = abserr0;
171 
172  // We start with 1 here, because an integration
173  // was already performed above
174  this->last_iter=1;
175 
176  return success;
177 
178  } else if (this->w->limit == 1) {
179 
180  *result = result0;
181  *abserr = abserr0;
182 
183  // We start with 1 here, because an integration
184  // was already performed above
185  this->last_iter=1;
186 
187  O2SCL_CONV2_RET("A maximum of 1 iteration was insufficient ",
188  "in inte_qag_gsl::qag().",
189  exc_emaxiter,this->err_nonconv);
190  }
191 
192  area = result0;
193  errsum = abserr0;
194 
195  iteration = 1;
196  do {
197  double a1, b1, a2, b2;
198  double a_i, b_i, r_i, e_i;
199  double area1 = 0, area2 = 0, area12 = 0;
200  double error1 = 0, error2 = 0, error12 = 0;
201  double resasc1, resasc2;
202  double resabs1, resabs2;
203 
204  /* Bisect the subinterval with the largest error estimate */
205 
206  this->w->retrieve (&a_i, &b_i, &r_i, &e_i);
207 
208  a1 = a_i;
209  b1 = 0.5 * (a_i + b_i);
210  a2 = b1;
211  b2 = b_i;
212 
213  this->gauss_kronrod(func,a1,b1,&area1,&error1,&resabs1,&resasc1);
214  this->gauss_kronrod(func,a2,b2,&area2,&error2,&resabs2,&resasc2);
215 
216  area12 = area1 + area2;
217  error12 = error1 + error2;
218 
219  errsum += (error12 - e_i);
220  area += area12 - r_i;
221 
222  if (resasc1 != error1 && resasc2 != error2) {
223  double delta = r_i - area12;
224 
225  if (fabs (delta) <= 1.0e-5 * fabs (area12) &&
226  error12 >= 0.99 * e_i) {
227  roundoff_type1++;
228  }
229  if (iteration >= 10 && error12 > e_i) {
230  roundoff_type2++;
231  }
232  }
233 
234  tolerance = GSL_MAX_DBL (l_epsabs, l_epsrel * fabs (area));
235 
236  if (errsum > tolerance) {
237  if (roundoff_type1 >= 6 || roundoff_type2 >= 20) {
238  // round off error
239  error_type = 2;
240  }
241  /* set error flag in the case of bad integrand behaviour at
242  a point of the integration range */
243 
244  if (this->w->subinterval_too_small (a1, a2, b2)) {
245  error_type = 3;
246  }
247  }
248 
249  this->w->update (a1, b1, area1, error1, a2, b2, area2, error2);
250 
251  this->w->retrieve (&a_i, &b_i, &r_i, &e_i);
252 
253  if (this->verbose>0) {
254  std::cout << "inte_qag_gsl Iter: " << iteration;
255  std::cout.setf(std::ios::showpos);
256  std::cout << " Res: " << area;
257  std::cout.unsetf(std::ios::showpos);
258  std::cout << " Err: " << errsum
259  << " Tol: " << tolerance << std::endl;
260  if (this->verbose>1) {
261  char ch;
262  std::cout << "Press a key and type enter to continue. " ;
263  std::cin >> ch;
264  }
265  }
266 
267  iteration++;
268 
269  } while (iteration < this->w->limit && !error_type &&
270  errsum > tolerance);
271 
272  *result = this->w->sum_results();
273  *abserr = errsum;
274 
275  this->last_iter=iteration;
276 
277  if (errsum <= tolerance) {
278  return success;
279  } else if (error_type == 2) {
280  std::string estr="Roundoff error prevents tolerance ";
281  estr+="from being achieved in inte_qag_gsl::qag().";
282  O2SCL_CONV_RET(estr.c_str(),exc_eround,this->err_nonconv);
283  } else if (error_type == 3) {
284  std::string estr="Bad integrand behavior ";
285  estr+=" in inte_qag_gsl::qag().";
286  O2SCL_CONV_RET(estr.c_str(),exc_esing,this->err_nonconv);
287  } else if (iteration == this->w->limit) {
288  std::string estr="Maximum number of subdivisions ("+itos(iteration);
289  estr+=") reached in inte_qag_gsl::qag().";
290  O2SCL_CONV_RET(estr.c_str(),exc_emaxiter,this->err_nonconv);
291  } else {
292  std::string estr="Could not integrate function in inte_qag_gsl::";
293  estr+="qag() (it may have returned a non-finite result).";
294  O2SCL_ERR(estr.c_str(),exc_efailed);
295  }
296 
297  // No return statement needed since the above if statement
298  // always forces a return
299  }
300 
301 #endif
302 
303  public:
304 
305  /// Return string denoting type ("inte_qag_gsl")
306  const char *type() { return "inte_qag_gsl"; }
307 
308  };
309 
310 #ifndef DOXYGEN_NO_O2NS
311 }
312 #endif
313 
314 #endif
#define O2SCL_CONV_RET(d, n, b)
Set a "convergence" error and return the error value.
Definition: err_hnd.h:292
apparent singularity detected
Definition: err_hnd.h:93
exceeded max number of iterations
Definition: err_hnd.h:73
#define O2SCL_CONV2_RET(d, d2, n, b)
Set an error and return the error value, two-string version.
Definition: err_hnd.h:298
size_t last_iter
The most recent number of iterations taken.
Definition: inte.h:63
bool err_nonconv
If true, call the error handler if the routine does not converge or reach the desired tolerance (defa...
Definition: inte.h:81
int update(double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
Determine which new subinterval to add to the workspace stack and perform update. ...
virtual void gauss_kronrod(func_t &func, double a, double b, double *result, double *abserr, double *resabs, double *resasc)
Integration wrapper for user-specified function type.
generic failure
Definition: err_hnd.h:61
inte_qag_gsl()
Create an integrator with the specified rule.
Definition: inte_qag_gsl.h:87
int subinterval_too_small(double a1, double a2, double b2)
Test whether the proposed subdivision falls before floating-point precision.
double tol_abs
The maximum absolute uncertainty in the value of the integral (default )
Definition: inte.h:73
int initialise(double a, double b)
Initialize the workspace for an integration with limits a and b.
const char * type()
Return string denoting type ("inte_qag_gsl")
Definition: inte_qag_gsl.h:306
int qag(func_t &func, const double a, const double b, const double l_epsabs, const double l_epsrel, double *result, double *abserr)
Perform an adaptive integration given the coefficients, and returning result.
Definition: inte_qag_gsl.h:110
int set_initial_result(double result, double error)
Update the workspace with the result and error from the first integration.
std::string dtos(double x, int prec=6, bool auto_prec=false)
Convert a double to a string.
#define O2SCL_ERR(d, n)
Set an error with message d and code n.
Definition: err_hnd.h:273
int retrieve(double *a, double *b, double *r, double *e) const
Retrieve the ith result from the workspace stack.
Basic Gauss-Kronrod integration class (GSL)
inte_workspace_gsl * w
The integration workspace.
double sum_results()
Add up all of the contributions to construct the final result.
double tol_rel
The maximum relative uncertainty in the value of the integral (default )
Definition: inte.h:68
virtual int integ_err(func_t &func, double a, double b, double &res, double &err)
Integrate function func from a to b and place the result in res and the error in err.
Definition: inte_qag_gsl.h:96
Adaptive numerical integration of a function (without singularities) on a bounded interval (GSL) ...
Definition: inte_qag_gsl.h:81
size_t limit
Maximum number of subintervals allocated.
std::string itos(int x)
Convert an integer to a string.
user specified an invalid tolerance
Definition: err_hnd.h:77
Success.
Definition: err_hnd.h:47
int verbose
Verbosity.
Definition: inte.h:60
failed because of roundoff error
Definition: err_hnd.h:87

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..