Commit 9c6b092ed7d700dc1e8672fa81d7fa9aeb1fb042

Authored by knodlseder
1 parent 784e9fe5

make trapzd() public

include/GIntegral.hpp
@@ -4,10 +4,18 @@ @@ -4,10 +4,18 @@
4 * copyright (C) 2010-2011 by Jurgen Knodlseder * 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,6 +72,7 @@ public:
64 void integrand(GIntegrand* integrand) { m_integrand=integrand; } 72 void integrand(GIntegrand* integrand) { m_integrand=integrand; }
65 const GIntegrand* integrand(void) const { return m_integrand; } 73 const GIntegrand* integrand(void) const { return m_integrand; }
66 double romb(double a, double b, int k = 5); 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 std::string print(void) const; 76 std::string print(void) const;
68 77
69 protected: 78 protected:
@@ -72,7 +81,6 @@ protected: @@ -72,7 +81,6 @@ protected:
72 void copy_members(const GIntegral& integral); 81 void copy_members(const GIntegral& integral);
73 void free_members(void); 82 void free_members(void);
74 double polint(double* xa, double* ya, int n, double x, double *dy); 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 // Protected data area 85 // Protected data area
78 GIntegrand* m_integrand; //!< Pointer to integrand 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,63 +196,157 @@ double GIntegral::romb(double a, double b, int k)
196 double result = 0.0; 196 double result = 0.0;
197 double ss = 0.0; 197 double ss = 0.0;
198 double dss = 0.0; 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 // Return result 351 // Return result
258 return result; 352 return result;
@@ -411,94 +505,6 @@ double GIntegral::polint(double* xa, double* ya, int n, double x, double *dy) @@ -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 = Friends = 510 = Friends =