Commit 9c6b092ed7d700dc1e8672fa81d7fa9aeb1fb042

Authored by knodlseder
1 parent 784e9fe5

make trapzd() public

include/GIntegral.hpp
... ... @@ -4,10 +4,18 @@
4 4 * copyright (C) 2010-2011 by Jurgen Knodlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7   - * This program is free software; you can redistribute it and/or modify *
8   - * it under the terms of the GNU General Public License as published by *
9   - * the Free Software Foundation; either version 2 of the License, or *
10   - * (at your option) any later version. *
  7 + * This program is free software: you can redistribute it and/or modify *
  8 + * it under the terms of the GNU General Public License as published by *
  9 + * the Free Software Foundation, either version 3 of the License, or *
  10 + * (at your option) any later version. *
  11 + * *
  12 + * This program is distributed in the hope that it will be useful, *
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  15 + * GNU General Public License for more details. *
  16 + * *
  17 + * You should have received a copy of the GNU General Public License *
  18 + * along with this program. If not, see <http://www.gnu.org/licenses/>. *
11 19 * *
12 20 ***************************************************************************/
13 21 /**
... ... @@ -64,6 +72,7 @@ public:
64 72 void integrand(GIntegrand* integrand) { m_integrand=integrand; }
65 73 const GIntegrand* integrand(void) const { return m_integrand; }
66 74 double romb(double a, double b, int k = 5);
  75 + double trapzd(double a, double b, int n = 1, double result = 0.0);
67 76 std::string print(void) const;
68 77  
69 78 protected:
... ... @@ -72,7 +81,6 @@ protected:
72 81 void copy_members(const GIntegral& integral);
73 82 void free_members(void);
74 83 double polint(double* xa, double* ya, int n, double x, double *dy);
75   - double trapzd(double a, double b, int n, double result);
76 84  
77 85 // Protected data area
78 86 GIntegrand* m_integrand; //!< Pointer to integrand
... ...
src/numerics/GIntegral.cpp
... ... @@ -196,63 +196,157 @@ double GIntegral::romb(double a, double b, int k)
196 196 double result = 0.0;
197 197 double ss = 0.0;
198 198 double dss = 0.0;
  199 +
  200 + // Continue only if integration range is valid
  201 + if (b > a) {
  202 +
  203 + // Allocate temporal storage
  204 + double* s = new double[m_max_iter+2];
  205 + double* h = new double[m_max_iter+2];
  206 +
  207 + // Initialise step size
  208 + h[1] = 1.0;
  209 + s[0] = 0.0;
  210 +
  211 + // Iterative loop
  212 + for (m_iter = 1; m_iter <= m_max_iter; ++m_iter) {
  213 +
  214 + // Integration using Trapezoid rule
  215 + s[m_iter] = trapzd(a, b, m_iter, s[m_iter-1]);
  216 +
  217 + // Compile option: Check for NaN/Inf
  218 + #if defined(G_NAN_CHECK)
  219 + if (isnotanumber(s[m_iter]) || isinfinite(s[m_iter])) {
  220 + std::cout << "*** ERROR: GIntegral::romb";
  221 + std::cout << "(a=" << a << ", b=" << b << ", k=" << k << "):";
  222 + std::cout << " NaN/Inf encountered";
  223 + std::cout << " (s[" << m_iter << "]=" << s[m_iter] << ")";
  224 + std::cout << std::endl;
  225 + }
  226 + #endif
  227 +
  228 + // Starting from iteration k on, use polynomial interpolation
  229 + if (m_iter >= k) {
  230 + ss = polint(&h[m_iter-k], &s[m_iter-k], k, 0.0, &dss);
  231 + if (std::abs(dss) <= m_eps * std::abs(ss)) {
  232 + converged = true;
  233 + result = ss;
  234 + break;
  235 + }
  236 + }
199 237  
200   - // Allocate temporal storage
201   - double* s = new double[m_max_iter+2];
202   - double* h = new double[m_max_iter+2];
203   -
204   - // Initialise step size
205   - h[1] = 1.0;
206   - s[0] = 0.0;
  238 + // Reduce step size
  239 + h[m_iter+1]= 0.25 * h[m_iter];
207 240  
208   - // Loop
209   - for (m_iter = 1; m_iter <= m_max_iter; ++m_iter) {
  241 + } // endfor: iterative loop
210 242  
211   - // Integration using Trapezoid rule
212   - s[m_iter] = trapzd(a, b, m_iter, s[m_iter-1]);
  243 + // Free temporal storage
  244 + delete [] s;
  245 + delete [] h;
213 246  
214   - // Compile option: Check for NaN/Inf
215   - #if defined(G_NAN_CHECK)
216   - if (std::isnan(s[m_iter]) || std::isinf(s[m_iter])) {
217   - std::cout << "*** ERROR: GIntegral::romb";
218   - std::cout << "(a=" << a << ", b=" << b << ", k=" << k << "):";
219   - std::cout << " NaN/Inf encountered";
220   - std::cout << " (s[" << m_iter << "]=" << s[m_iter] << ")";
221   - std::cout << std::endl;
222   - }
223   - #endif
224   -
225   - // Starting from iteration k on, use polynomial interpolation
226   - if (m_iter >= k) {
227   - ss = polint(&h[m_iter-k], &s[m_iter-k], k, 0.0, &dss);
228   - if (std::abs(dss) <= m_eps * std::abs(ss)) {
229   - converged = true;
230   - result = ss;
231   - break;
  247 + // Dump warning
  248 + if (!m_silent) {
  249 + if (!converged) {
  250 + std::cout << "*** WARNING: GIntegral::romb: ";
  251 + std::cout << "Integration did not converge ";
  252 + std::cout << "(iter=" << m_iter;
  253 + std::cout << ", result=" << ss;
  254 + std::cout << ", d=" << std::abs(dss);
  255 + std::cout << " > " << m_eps * std::abs(ss) << ")";
  256 + std::cout << std::endl;
  257 + throw;
232 258 }
233 259 }
  260 +
  261 + } // endif: integration range was valid
  262 +
  263 + // Return result
  264 + return result;
  265 +}
234 266  
235   - // Reduce step size
236   - h[m_iter+1]= 0.25 * h[m_iter];
237 267  
  268 +/***********************************************************************//**
  269 + * @brief Perform Trapezoidal integration
  270 + *
  271 + * @param[in] a Left integration boundary.
  272 + * @param[in] b Right integration boundary.
  273 + * @param[in] n Number of steps.
  274 + * @param[in] result Result from a previous trapezoidal integration step.
  275 + *
  276 + * The original Numerical Recipes function had result declared as a static
  277 + * variable, yet this led to some untrackable integration problems. For this
  278 + * reason, previous results are now passed using an argument.
  279 + * Result initialisation is done if n=1.
  280 + ***************************************************************************/
  281 +double GIntegral::trapzd(double a, double b, int n, double result)
  282 +{
  283 + // Handle case of identical boundaries
  284 + if (a == b) {
  285 + result = 0.0;
238 286 }
  287 +
  288 + // ... otherwise use trapeziodal rule
  289 + else {
  290 +
  291 + // Case A: Only a single step is requested
  292 + if (n == 1) {
  293 +
  294 + // Evaluate integrand at boundaries
  295 + double y_a = m_integrand->eval(a);
  296 + double y_b = m_integrand->eval(b);
  297 +
  298 + // Compute result
  299 + result = 0.5*(b-a)*(m_integrand->eval(a) + m_integrand->eval(b));
  300 +
  301 + } // endif: only a single step was requested
239 302  
240   - // Free temporal storage
241   - delete [] s;
242   - delete [] h;
243   -
244   - // Dump warning
245   - if (!m_silent) {
246   - if (!converged) {
247   - std::cout << "*** WARNING: GIntegral::romb: ";
248   - std::cout << "Integration did not converge ";
249   - std::cout << "(iter=" << m_iter;
250   - std::cout << ", result=" << ss;
251   - std::cout << ", d=" << std::abs(dss);
252   - std::cout << " > " << m_eps * std::abs(ss) << ")";
253   - std::cout << std::endl;
  303 + // Case B: More than a single step is requested
  304 + else {
  305 + // Compute step level 2^(n-1)
  306 + int it = 1;
  307 + for (int j = 1; j < n-1; ++j)
  308 + it <<= 1;
  309 +
  310 + // Verify that step level is valid
  311 + if (it == 0) {
  312 + std::cout << "*** ERROR: GIntegral::trapzd(";
  313 + std::cout << "a=" << a << ", b=" << b << ", n=" << n;
  314 + std::cout << ", result=" << result << "): it=" << it << ". ";
  315 + std::cout << "Looks like an overflow?";
  316 + std::cout << std::endl;
  317 + }
  318 +
  319 + // Set step size
  320 + double tnm = double(it);
  321 + double del = (b-a)/tnm;
  322 +
  323 + // Verify that step is >0
  324 + if (del == 0) {
  325 + std::cout << "*** ERROR: GIntegral::trapzd(";
  326 + std::cout << "a=" << a << ", b=" << b << ", n=" << n;
  327 + std::cout << ", result=" << result << "): del=" << del << ". ";
  328 + std::cout << "Step is too small to make sense.";
  329 + std::cout << std::endl;
  330 + }
  331 +
  332 + // Sum up values
  333 + double x = a + 0.5*del;
  334 + double sum = 0.0;
  335 + for (int j = 0; j < it; ++j, x+=del) {
  336 +
  337 + // Evaluate integrand
  338 + double y = m_integrand->eval(x);
  339 +
  340 + // Add integrand
  341 + sum += y;
  342 +
  343 + } // endfor: looped over steps
  344 +
  345 + // Set result
  346 + result = 0.5*(result + (b-a)*sum/tnm);
254 347 }
255   - }
  348 +
  349 + } // endelse: trapeziodal rule was applied
256 350  
257 351 // Return result
258 352 return result;
... ... @@ -411,94 +505,6 @@ double GIntegral::polint(double* xa, double* ya, int n, double x, double *dy)
411 505 }
412 506  
413 507  
414   -/***********************************************************************//**
415   - * @brief Perform Trapezoidal integration
416   - *
417   - * @param[in] a Left integration boundary.
418   - * @param[in] b Right integration boundary.
419   - * @param[in] n Number of steps.
420   - * @param[in] result Result from a previous trapezoidal integration step.
421   - *
422   - * The original Numerical Recipes function had result declared as a static
423   - * variable, yet this led to some untrackable integration problems. For this
424   - * reason, previous results are now passed using an argument.
425   - * Result initialisation is done if n=1.
426   - ***************************************************************************/
427   -double GIntegral::trapzd(double a, double b, int n, double result)
428   -{
429   - // Handle case of identical boundaries
430   - if (a == b) {
431   - result = 0.0;
432   - }
433   -
434   - // ... otherwise use trapeziodal rule
435   - else {
436   -
437   - // Case A: Only a single step is requested
438   - if (n == 1) {
439   -
440   - // Evaluate integrand at boundaries
441   - double y_a = m_integrand->eval(a);
442   - double y_b = m_integrand->eval(b);
443   -
444   - // Compute result
445   - result = 0.5*(b-a)*(m_integrand->eval(a) + m_integrand->eval(b));
446   -
447   - } // endif: only a single step was requested
448   -
449   - // Case B: More than a single step is requested
450   - else {
451   - // Compute step level 2^(n-1)
452   - int it = 1;
453   - for (int j = 1; j < n-1; ++j)
454   - it <<= 1;
455   -
456   - // Verify that step level is valid
457   - if (it == 0) {
458   - std::cout << "*** ERROR: GIntegral::trapzd(";
459   - std::cout << "a=" << a << ", b=" << b << ", n=" << n;
460   - std::cout << ", result=" << result << "): it=" << it << ". ";
461   - std::cout << "Looks like an overflow?";
462   - std::cout << std::endl;
463   - }
464   -
465   - // Set step size
466   - double tnm = double(it);
467   - double del = (b-a)/tnm;
468   -
469   - // Verify that step is >0
470   - if (it == 0) {
471   - std::cout << "*** ERROR: GIntegral::trapzd(";
472   - std::cout << "a=" << a << ", b=" << b << ", n=" << n;
473   - std::cout << ", result=" << result << "): del=" << del << ". ";
474   - std::cout << "Step is too small to make sense.";
475   - std::cout << std::endl;
476   - }
477   -
478   - // Sum up values
479   - double x = a + 0.5*del;
480   - double sum = 0.0;
481   - for (int j = 0; j < it; ++j, x+=del) {
482   -
483   - // Evaluate integrand
484   - double y = m_integrand->eval(x);
485   -
486   - // Add integrand
487   - sum += y;
488   -
489   - } // endfor: looped over steps
490   -
491   - // Set result
492   - result = 0.5*(result + (b-a)*sum/tnm);
493   - }
494   -
495   - } // endelse: trapeziodal rule was applied
496   -
497   - // Return result
498   - return result;
499   -}
500   -
501   -
502 508 /*==========================================================================
503 509 = =
504 510 = Friends =
... ...