RSTT  3.1.0
Regional Seismic Travel Time
IntegrateFunction.h
Go to the documentation of this file.
1 //- ****************************************************************************
2 //-
3 //- Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
4 //- (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
5 //- Government retains certain rights in this software.
6 //-
7 //- BSD Open Source License
8 //- All rights reserved.
9 //-
10 //- Redistribution and use in source and binary forms, with or without
11 //- modification, are permitted provided that the following conditions are met:
12 //-
13 //- 1. Redistributions of source code must retain the above copyright notice,
14 //- this list of conditions and the following disclaimer.
15 //-
16 //- 2. Redistributions in binary form must reproduce the above copyright
17 //- notice, this list of conditions and the following disclaimer in the
18 //- documentation and/or other materials provided with the distribution.
19 //-
20 //- 3. Neither the name of the copyright holder nor the names of its
21 //- contributors may be used to endorse or promote products derived from
22 //- this software without specific prior written permission.
23 //-
24 //- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 //- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 //- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 //- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
28 //- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 //- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 //- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 //- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 //- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 //- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 //- POSSIBILITY OF SUCH DAMAGE.
35 //-
36 //- ****************************************************************************
37 
38 #ifndef INTEGRATEFUNCTION_H
39 #define INTEGRATEFUNCTION_H
40 
41 // **** _SYSTEM INCLUDES_ ******************************************************
42 
43 #include <float.h>
44 #include <vector>
45 #include <iostream>
46 #include <limits>
47 
48 using namespace std;
49 // use standard library objects
50 
51 // **** _LOCAL INCLUDES_ *******************************************************
52 
53 #include "UtilGlobals.h"
54 
55 // **** _BEGIN UTIL NAMESPACE_ *************************************************
56 
57 namespace util {
58 
59 // **** _CLASS CONSTANTS_ ******************************************************
60 // **** _FORWARD REFERENCES_ ***************************************************
61 
62 // **** _CLASS DEFINITION_ *****************************************************
63 //
69 //
110 // *****************************************************************************
111 template<class F>
113 {
114  public:
115 
116  // **** _PUBLIC LIFCYCLES_ *************************************************
117 
122  IntegrateFunction(F& f, double tol);
123 
126 
129 
130  // **** _PUBLIC OPERATORS_ *************************************************
131 
134 
135  // **** _PUBLIC METHODS_ ***************************************************
136 
141  double integrateClosed(double a, double b);
142 
148  double integrateAOpenS(double a, double b);
149 
151  F& getF();
152 
154  const F& getF() const;
155 
157  void setTolerance(double tol);
158 
160  double getTolerance() const;
161 
163  //static double getTest(int f, double ftrn, double tol);
164 
165  private:
166 
167  // **** _PRIVATE METHODS_ **************************************************
168 
173  //
177  double integrateClosedRcrsv(double a, double b, double* fr);
178 
180  //
201  double simpson(double a, double b, double* fa, double& s);
202 
203  // **** _PRIVATE DATA_ *****************************************************
204 
206  double ifTol;
207 
209  F& ifF;
210 };
211 
212 // **** _INLINE FUNCTION IMPLEMENTATIONS_ **************************************
213 
214 // Returns a reference to the integrated function.
215 template<class F>
217 {
218  return ifF;
219 }
220 
221 // Returns a const reference to the integrated function.
222 template<class F>
223 inline const F& IntegrateFunction<F>::getF() const
224 {
225  return ifF;
226 }
227 
228 // Sets the integration tolerance value.
229 template<class F>
230 inline void IntegrateFunction<F>::setTolerance(double tol)
231 {
232  ifTol = tol;
233 }
234 
235 // Returns the integration tolerance value.
236 template<class F>
238 {
239  return ifTol;
240 }
241 
242 // Adaptive closed form numerical integration of the input function
243 // over the closed interval a to b. The function is assumed to be
244 // defined over the entire interval [a, b]. The function uses the 3 point
245 // Simpsons rule to evaluate all sub-intervals.
246 template<class F>
247 inline double IntegrateFunction<F>::integrateClosed(double a, double b)
248 {
249  double fr[3];
250 
251  // evaluate the function at a, b, and the midpoint and save into fr.
252 
253  fr[0] = ifF(a);
254  fr[1] = ifF(0.5 * (a + b));
255  fr[2] = ifF(b);
256 
257  // integrate and return result
258 
259  return integrateClosedRcrsv(a, b, fr);
260 }
261 
262 template<class F>
263 inline double IntegrateFunction<F>::integrateAOpenS(double a, double b)
264 {
265  double fs, fa, ae, be, senew;
266 
267  // set the integration result to 0.0 and calculate a small value near a
268  // but slightly larger (e). Set the smallest legal value for e (minstep)
269  // and account for precision loss in the step size due to significant
270  // digits in front of the decimal place (of a).
271 
272  double s = 0.0;
273  double e = (b - a) * ifTol;
274  fa = fabs(a);
275  double minstep = 10.0 * DBL_EPSILON;
276  if (fa > 1.0) minstep *= fa;
277 
278  // calculate integral from just shy of the asymptote to b and
279  // loop over successive steps getting closer to a each step
280  // (e to e/10 each loop). Loop while the stepsize is decremented by
281  // an order of magnitude at each step.
282 
283  ae = a + e;
284  s = integrateClosed(ae, b);
285  be = ae; ae = a + 0.1 * e;
286  do
287  {
288  // get contribution from a+e/10 to a+e ... sum contribution to s
289 
290  senew = integrateClosed(ae, be);
291  s += senew;
292 
293  // see if error criteria has been met ... if so return s, otherwise
294  // decrement e by 10 and try again
295 
296  fs = fabs(s);
297  if ((fabs(senew) < ifTol * fs) || (fs < ifTol))
298  return s;
299  else
300  e /= 10.0;
301 
302  // continue while e is larger than minimum step size
303 
304  be = ae; ae = a + 0.1 * e;
305  } while ((e > minstep) && (be > ae) && (ae > a));
306 
307  // output error tolerance condtion and return best estimate
308 
309  if (fabs(senew) > ifTol)
310  {
311  // should throw here ... need to resume after the fact
312  // should output a, b, e, ae, be, s, senew, iftol
313  cout << " Error:: Function Error Tolerance Exceeded ... " << endl
314  << " Tolerance Condition Was Not Met." << endl;
315  }
316  return s;
317 }
318 
319 // Adaptive closed form numerical integration of the input function
320 // over the closed interval a to b. The function is assumed to be
321 // defined over the entire interval [a, b]. The function uses the 3 point
322 // Simpsons rule to evaluate all sub-intervals.
323 //
324 // The array fr contains previous function evaluations at ifF(a),
325 // ifF((a + b)/2), and ifF(b). This private function is only called by the
326 // public cover function integrateClosed(a, b).
327 template<class F>
328 inline double IntegrateFunction<F>::integrateClosedRcrsv(double a, double b,
329  double* fr)
330 {
331  // set the integration result to 0.0 and save the input previously
332  // calculated function evalutions in fr into fa. fa[1] and fa[3] are
333  // calculated in function simpson(...) below.
334 
335  double s = 0.0;
336  double fa[5];
337  fa[0] = fr[0];
338  fa[2] = fr[1];
339  fa[4] = fr[2];
340 
341  // evaluate Simpsons rule and return result if tolerance is met.
342 
343  double se = simpson(a, b, fa, s);
344  double fs = fabs(s);
345  if ((se < ifTol * fs) || (fs < ifTol))
346  return s;
347  else
348  {
349  // not accurate enough yet ... calculate interval mid-point and verify
350  // machine precison will allow evaluation.
351 
352  double m = 0.5 * (a + b);
353  if ((m <= a) | (b <= m))
354  {
355  if (se > ifTol)
356  {
357  // write out warning
358  // should throw error here ... write out a, b, m, s, se, iftol
359  cout << " Error:: Function Error Tolerance Exceeded ... " << endl
360  << " Tolerance Condition Was Not Met." << endl;
361  }
362  return s;
363  }
364 
365  // integrate over left and right sub-intervals ... return the summed
366  // result
367 
368  return integrateClosedRcrsv(a, m, &fa[0]) +
369  integrateClosedRcrsv(m, b, &fa[2]);
370  }
371 }
372 
373 // A 3 point 4th order Simpsons integration rule.
374 //
375 // (h/3)(f0 + 4*f1 + f2)
376 //
377 // where h is half the interval width, f0 is the function to be integrated
378 // defined at the left most range, f2 is defined at the right most range,
379 // and f1 is defined at the mid-point of the range.
380 //
381 // The rule evaluates the integral across a sub-interval range using the
382 // rule 3 times, once across the sub-interval, once across the 1st half of
383 // the sub-interval and once across the second half of the sub-interval.
384 // The split halves are summed to form one result while the entire
385 // interval evaluation forms the other. The former has an accuracy that is
386 // about 4 times greater than the entire interval evaluation. Convergence
387 // is attained when the difference between the two is less than the input
388 // tolerance.
389 //
390 // Five function evaluations are required for the closed form solution.
391 // However, 3 evaluations are passed from the previous call so only 2 new
392 // function evalutions are required per call to this function. The 3
393 // previous functions evaluations are provided in the array fa at
394 // locations fa[0], fa[2], and fa[4]. Evaltions for fa[1] and fa[3] are
395 // performed in this function and saved into the array.
396 template<class F>
397 inline double IntegrateFunction<F>::simpson(double a, double b,
398  double* fa, double& s)
399 {
400  // calculate interval width and the two remaining function evalutions
401 
402  double h = b - a;
403  fa[1] = ifF(a + 0.25 * h);
404  fa[3] = ifF(a + 0.75 * h);
405  h *= 0.5;
406 
407  // calculate results over entire interval (s1) and the interval split in
408  // half (s). Return s and the difference between both evaluations.
409 
410  double dh = h / 6.0;
411  double s1 = 2.0 * dh * (fa[0] + 4.0 * fa[2] + fa[4]);
412  s = dh * (fa[0] + 4.0 * (fa[1] + fa[3]) + 2.0 * fa[2] + fa[4]);
413  return fabs(s - s1);
414 }
415 
416 // **** _TEST FUNCTION IMPLEMENTATIONS_ **************************************
417 
420 //
425 
426 // f = velocity function
427 // ftrn = is fractional radius where rtrn = ftrn * (rtop - rbot) + rbot
428 // fa = is fractional radius where ra = fa * (rtop - rtrn) + rtrn above the turn radius
429 // fb = is fractional radius where rb = fb * (rtop - rtrn) + rtrn above the turn radius
430 // (Note: fb > fa, fb == 1 gives rb == rtop)
431 // tif.setF(f);
432 // tif.setRTurn(ftrn);
433 // double a = tif.getA(fa);
434 // double b = tif.getB(fb);
435 //class TestIntegrateFunction
436 //{
437 // public:
438 //
439 // //! Default Constructor.
440 // TestIntegrateFunction() {f=1;};
441 //
442 // //! Copy Constructor.
443 // TestIntegrateFunction(const TestIntegrateFunction& tif) {f=1;};
444 //
445 // //! Destructor.
446 // ~TestIntegrateFunction() {f=1;};
447 //
448 // //! Assignment Operator.
449 // TestIntegrateFunction& operator=(const TestIntegrateFunction& tif)
450 // {return *this;};
451 //
452 // //! \brief Function parentheses operator(). Returns a double given a
453 // //! single double argument. This function is the integrand.
454 // double operator()(double r)
455 // {
456 // ++fccnt;
457 // double vr = v(r);
458 // double pv = p * vr;
459 //
460 // //return sqrt((r - pv) * (r + pv)) / r / vr; // Tau Function
461 // return 1.0 / sqrt((r - pv) * (r + pv)); // Turning Asymptote
462 // //return pv / sqrt((r - pv) * (r + pv)) / r; // Distance
463 // //return r / sqrt((r - pv) * (r + pv)) / vr; // Time
464 // }
465 //
466 // //! Zeros the function call count.
467 // void resetFCCount() {fccnt = 0;};
468 //
469 // //! Returns the function call count.
470 // int getFCCount() const {return fccnt;};
471 //
472 // //! Set velocity model
473 // void setF(int fin) {f = fin;};
474 //
475 // //! Set turning radius
476 // void setRTurn(double ftrn)
477 // {
478 // rturn = ftrn * (rbot() - rtop()) + rtop();
479 // p = rturn / v(rturn);
480 // };
481 //
482 // //! Get a limit.
483 // double getLimit(double fin) const
484 // {
485 // return fin * (rtop() - rturn) + rturn;
486 // };
487 //
488 // // mantle1 p vel from r = 6336 to 6251
489 // double v1(double r) const
490 // {
491 // double rn = r / 6371.0;
492 // return 8.78541 - 0.74953 * rn;
493 // };
494 //
495 // // mantle2 p vel from r = 6251 to 6161
496 // double v2(double r) const
497 // {
498 // double rn = r / 6371.0;
499 // return 25.41389 - 17.69722 * rn;
500 // };
501 //
502 // // mantle3 p vel from r = 6161 to 5961
503 // double v3(double r) const
504 // {
505 // double rn = r / 6371.0;
506 // return 30.78765 - 23.25415 * rn;
507 // };
508 //
509 // // mantle4 p vel from r = 5961 to 5711
510 // double v4(double r) const
511 // {
512 // double rn = r / 6371.0;
513 // return 29.38896 - 21.40656 * rn;
514 // };
515 //
516 // // mantle5 p vel from r = 5711 to 5611
517 // double v5(double r) const
518 // {
519 // double rn = r / 6371.0;
520 // return 25.96984 - 16.93412 * rn;
521 // };
522 //
523 // // mantle p vel from r = 5611 to 3631
524 // double v6(double r) const
525 // {
526 // double rn = r / 6371.0;
527 // return 25.1486 + rn * (-41.1538 + rn * (51.9932 + rn * -26.6083));
528 // };
529 //
530 // // c-m trns p vel from r = 3631 to 3482
531 // double v7(double r) const
532 // {
533 // double rn = r / 6371.0;
534 // return 14.49470 - 1.47089 * rn;
535 // };
536 //
537 // // outer core p vel from r = 3482 to 1217.1
538 // double v8(double r) const
539 // {
540 // double rn = r / 6371.0;
541 // return 10.03904 + rn * (3.75665 + rn * -13.67046);
542 // };
543 //
544 // // inner core p vel from r = 1217.1 to 0
545 // double v9(double r) const
546 // {
547 // double rn = r / 6371.0;
548 // return 11.24094 + rn * rn * -4.09689;
549 // };
550 //
551 // double rtop() const
552 // {
553 // if (f < 5)
554 // {
555 // if (f < 3)
556 // {
557 // if (f == 1)
558 // return 6336.0;
559 // else
560 // return 6251.0;
561 // }
562 // else if (f == 3)
563 // return 6161.0;
564 // else
565 // return 5961.0;
566 // }
567 // else if (f < 7)
568 // {
569 // if (f == 5)
570 // return 5711.0;
571 // else
572 // return 5611.0;
573 // }
574 // else if (f < 9)
575 // {
576 // if (f == 7)
577 // return 3631.0;
578 // else
579 // return 3482.0;
580 // }
581 // else
582 // return 1217.1;
583 //
584 // return 0.0;
585 // };
586 //
587 // double rbot() const
588 // {
589 // if (f < 5)
590 // {
591 // if (f < 3)
592 // {
593 // if (f == 1)
594 // return 6251.0;
595 // else
596 // return 6161.0;
597 // }
598 // else if (f == 3)
599 // return 5961.0;
600 // else
601 // return 5711.0;
602 // }
603 // else if (f < 7)
604 // {
605 // if (f == 5)
606 // return 5611.0;
607 // else
608 // return 3631.0;
609 // }
610 // else if (f < 9)
611 // {
612 // if (f == 7)
613 // return 3482.0;
614 // else
615 // return 1217.1;
616 // }
617 // else
618 // return 0.0;
619 //
620 // return 0.0;
621 // };
622 //
623 // double v(double r) const
624 // {
625 // if (f < 5)
626 // {
627 // if (f < 3)
628 // {
629 // if (f == 1)
630 // return v1(r);
631 // else
632 // return v2(r);
633 // }
634 // else if (f == 3)
635 // return v3(r);
636 // else
637 // return v4(r);
638 // }
639 // else if (f < 7)
640 // {
641 // if (f == 5)
642 // return v5(r);
643 // else
644 // return v6(r);
645 // }
646 // else if (f < 9)
647 // {
648 // if (f == 7)
649 // return v7(r);
650 // else
651 // return v8(r);
652 // }
653 // else
654 // return v9(r);
655 //
656 // return 0.0;
657 // };
658 //
659 // private:
660 //
661 // //! \brief The integrand function call count. Used to examine the
662 // //! number of times the operator()(double x) function is called.
663 // int fccnt;
664 //
665 // int f;
666 // double p;
667 //
668 // double rturn;
669 //};
670 
671 } // end namespace util
672 
673 #endif // INTEGRATEFUNCTION_H
util::IntegrateFunction::integrateAOpenS
double integrateAOpenS(double a, double b)
Adaptive closed form numerical integration of the input function over the open interval a to b,...
Definition: IntegrateFunction.h:263
util::IntegrateFunction
Class supports numerical integration of an arbitrary function using a fourth order Simpsons rule for ...
Definition: IntegrateFunction.h:113
util::IntegrateFunction::getF
const F & getF() const
Returns a const reference to the integrated function.
Definition: IntegrateFunction.h:223
UTIL_EXP
#define UTIL_EXP
Definition: UtilGlobals.h:66
util::IntegrateFunction::getF
F & getF()
Returns a reference to the integrated function.
Definition: IntegrateFunction.h:216
util::IntegrateFunction::setTolerance
void setTolerance(double tol)
Sets the integration tolerance value.
Definition: IntegrateFunction.h:230
util::IntegrateFunction::IntegrateFunction
IntegrateFunction(F &f, double tol)
Standard Constructor.
util::IntegrateFunction::IntegrateFunction
IntegrateFunction(const IntegrateFunction< F > &ifctn)
Copy Constructor.
util::IntegrateFunction::integrateClosed
double integrateClosed(double a, double b)
Adaptive closed form numerical integration of the input function over the closed interval a to b....
Definition: IntegrateFunction.h:247
util::IntegrateFunction::getTolerance
double getTolerance() const
Returns the integration tolerance value.
Definition: IntegrateFunction.h:237
UtilGlobals.h
util::IntegrateFunction::~IntegrateFunction
virtual ~IntegrateFunction()
Destructor.
util::IntegrateFunction::operator=
IntegrateFunction< F > & operator=(const IntegrateFunction< F > &ifctn)
Assignment Operator.
util
Definition: Brents.h:54