1 #include "NumericalApproximation.h" 16 NumericalApproximation::FunctorList NumericalApproximation::p_interpFunctors;
39 p_dataValidated =
false;
43 "NumericalApproximation() - Unable to construct NumericalApproximation object",
81 NumericalApproximation::NumericalApproximation(
unsigned int n,
double *x,
double *y,
90 "NumericalApproximation() - Unable to construct object using the given arrays, size and interpolation type",
125 NumericalApproximation::NumericalApproximation(
const vector <double> &x,
const vector <double> &y,
134 "NumericalApproximation() - Unable to construct an object using the given vectors and interpolation type",
185 "NumericalApproximation() - Unable to copy the given object",
216 if(&oldObject !=
this) {
217 if(GslInterpType(p_itype)) GslDeallocation();
218 SetInterpType(oldObject.
p_itype);
234 "operator=() - Unable to copy the given object",
250 NumericalApproximation::~NumericalApproximation() {
251 if(GslInterpType(p_itype)) GslDeallocation();
276 string NumericalApproximation::Name()
const {
277 if(p_itype == NumericalApproximation::CubicNeighborhood) {
278 return "cspline-neighborhood";
280 else if(p_itype == NumericalApproximation::CubicClamped) {
281 return "cspline-clamped";
283 else if(p_itype == NumericalApproximation::PolynomialNeville) {
284 return "polynomial-Neville's";
286 else if(p_itype == NumericalApproximation::CubicHermite) {
287 return "cspline-Hermite";
290 string name = (string(GslFunctor(p_itype)->name));
291 if(p_itype == NumericalApproximation::CubicNatural) {
292 return name +
"-natural";
299 "Name() - GSL interpolation type not found",
327 int NumericalApproximation::MinPoints() {
328 if(p_itype == NumericalApproximation::CubicNeighborhood) {
331 else if(p_itype == NumericalApproximation::CubicClamped) {
334 else if(p_itype == NumericalApproximation::PolynomialNeville) {
337 else if(p_itype == NumericalApproximation::CubicHermite) {
341 return (GslFunctor(p_itype)->min_size);
346 "MinPoints() - GSL interpolation not found",
380 if(GslInterpType(itype)) {
389 "MinPoints() - GSL interpolation type not found",
393 else if(itype == NumericalApproximation::CubicNeighborhood) {
396 else if(itype == NumericalApproximation::CubicClamped) {
399 else if(itype == NumericalApproximation::PolynomialNeville) {
402 else if(itype == NumericalApproximation::CubicHermite) {
406 "MinPoints() - Invalid argument. Unknown interpolation type: " 434 void NumericalApproximation::AddData(
const double x,
const double y) {
437 p_clampedComputed =
false;
438 p_clampedEndptsSet =
false;
439 p_dataValidated =
false;
440 p_clampedSecondDerivs.clear();
441 p_clampedDerivFirstPt = 0;
442 p_clampedDerivLastPt = 0;
443 p_polyNevError.clear();
467 void NumericalApproximation::AddData(
unsigned int n,
double *x,
double *y) {
468 for(
unsigned int i = 0; i < n; i++) {
472 p_clampedComputed =
false;
473 p_clampedEndptsSet =
false;
474 p_dataValidated =
false;
475 p_clampedSecondDerivs.clear();
476 p_clampedDerivFirstPt = 0;
477 p_clampedDerivLastPt = 0;
478 p_polyNevError.clear();
506 void NumericalApproximation::AddData(
const vector <double> &x,
507 const vector <double> &y)
512 ReportException(IException::Programmer,
"AddData()",
513 "Invalid arguments. The sizes of the input vectors do " 520 if(!p_x.empty() || !p_y.empty()) {
521 for(
int i = 0; i < n; i++) {
531 p_clampedComputed =
false;
532 p_clampedEndptsSet =
false;
533 p_dataValidated =
false;
534 p_clampedSecondDerivs.clear();
535 p_clampedDerivFirstPt = 0;
536 p_clampedDerivLastPt = 0;
537 p_polyNevError.clear();
559 void NumericalApproximation::SetCubicClampedEndptDeriv(
double yp1,
double ypn) {
560 if(p_itype != NumericalApproximation::CubicClamped) {
561 ReportException(IException::Programmer,
"SetCubicClampedEndptDeriv()",
562 "This method is only valid for cspline-clamped interpolation, may not be used for " 563 + Name() +
" interpolation",
566 p_clampedDerivFirstPt = yp1;
567 p_clampedDerivLastPt = ypn;
568 p_clampedEndptsSet =
true;
586 void NumericalApproximation::AddCubicHermiteDeriv(
unsigned int n,
double *fprimeOfx) {
587 if(p_itype != NumericalApproximation::CubicHermite) {
588 ReportException(IException::Programmer,
"SetCubicHermiteDeriv()",
589 "This method is only valid for cspline-Hermite interpolation, may not be used for " 590 + Name() +
" interpolation",
593 for(
unsigned int i = 0; i < n; i++) {
594 p_fprimeOfx.push_back(fprimeOfx[i]);
611 void NumericalApproximation::AddCubicHermiteDeriv(
612 const vector <double> &fprimeOfx) {
613 if(p_itype != NumericalApproximation::CubicHermite) {
614 ReportException(IException::Programmer,
"SetCubicHermiteDeriv()",
615 "This method is only valid for cspline-Hermite interpolation, may not be used for " 616 + Name() +
" interpolation",
621 if(!p_fprimeOfx.empty()) {
622 for(
unsigned int i = 0; i < fprimeOfx.size(); i++) {
623 p_fprimeOfx.push_back(fprimeOfx[i]);
627 p_fprimeOfx = fprimeOfx;
645 void NumericalApproximation::AddCubicHermiteDeriv(
647 if(p_itype != NumericalApproximation::CubicHermite) {
648 ReportException(IException::Programmer,
"SetCubicHermiteDeriv()",
649 "This method is only valid for cspline-Hermite interpolation, may not be used for " 650 + Name() +
" interpolation",
653 p_fprimeOfx.push_back(fprimeOfx);
681 vector <double> NumericalApproximation::CubicClampedSecondDerivatives() {
683 if(p_itype != NumericalApproximation::CubicClamped)
684 ReportException(IException::Programmer,
"CubicClampedSecondDerivatives()",
685 "This method is only valid for cspline-clamped interpolation type may not be used for " 686 + Name() +
" interpolation",
688 if(!p_clampedComputed) ComputeCubicClamped();
689 return p_clampedSecondDerivs;
694 "CubicClampedSecondDerivatives() - Unable to compute clamped cubic spline interpolation",
717 double NumericalApproximation::DomainMinimum() {
719 if(GslInterpType(p_itype)) {
721 if(!GslComputed()) ComputeGsl();
722 return (p_interp->interp->xmin);
725 if(!p_dataValidated) ValidateDataSet();
726 return *min_element(p_x.begin(), p_x.end());
732 "DomainMinimum() - Unable to calculate the domain minimum for the data set",
754 double NumericalApproximation::DomainMaximum() {
756 if(GslInterpType(p_itype)) {
758 if(!GslComputed()) ComputeGsl();
759 return (p_interp->interp->xmax);
762 if(!p_dataValidated) ValidateDataSet();
763 return *max_element(p_x.begin(), p_x.end());
769 "DomainMaximum() - Unable to calculate the domain maximum for the data set",
787 bool NumericalApproximation::Contains(
double x) {
788 return binary_search(p_x.begin(), p_x.end(), x);
830 double NumericalApproximation::Evaluate(
const double a,
const ExtrapType &etype) {
836 else a0 = ValueToExtrapolate(a, etype);
838 if(p_itype == NumericalApproximation::CubicNeighborhood) {
839 return EvaluateCubicNeighborhood(a0);
841 else if(p_itype == NumericalApproximation::PolynomialNeville) {
842 p_polyNevError.clear();
843 return EvaluatePolynomialNeville(a0);
845 else if(p_itype == NumericalApproximation::CubicClamped) {
847 if(!p_clampedComputed) ComputeCubicClamped();
848 return EvaluateCubicClamped(a0);
850 else if(p_itype == NumericalApproximation::CubicHermite) {
851 return EvaluateCubicHermite(a0);
854 if(!GslComputed()) ComputeGsl();
856 GslIntegrityCheck(gsl_spline_eval_e(p_interp, a0, p_acc, &result),
_FILEINFO_);
862 "Evaluate() - Unable to evaluate the function at the point a = " 906 vector <double> NumericalApproximation::Evaluate(
const vector <double> &a,
const ExtrapType &etype) {
908 if(p_itype == NumericalApproximation::CubicNeighborhood) {
912 return EvaluateCubicNeighborhood(a, etype);
914 vector <double> result(a.size());
915 if(p_itype == NumericalApproximation::PolynomialNeville) {
918 p_polyNevError.clear();
919 for(
unsigned int i = 0; i < result.size(); i++) {
921 if(InsideDomain(a[i]))
923 else a0 = ValueToExtrapolate(a[i], etype);
924 result[i] = EvaluatePolynomialNeville(a0);
930 for(
unsigned int i = 0; i < result.size(); i++) {
931 result[i] = Evaluate(a[i], etype);
938 "Evaluate() - Unable to evaluate the function at the given vector of points",
964 vector <double> NumericalApproximation::PolynomialNevilleErrorEstimate() {
965 if(p_itype != NumericalApproximation::PolynomialNeville) {
966 ReportException(IException::Programmer,
"PolynomialNevilleErrorEstimate()",
967 "This method is only valid for polynomial-Neville's, may not be used for " 968 + Name() +
" interpolation",
971 if(p_polyNevError.empty()) {
972 ReportException(IException::Programmer,
"PolynomialNevilleErrorEstimate()",
973 "Error not calculated. This method only valid after Evaluate() has been called",
976 return p_polyNevError;
1014 double NumericalApproximation::GslFirstDerivative(
const double a) {
1016 if(!GslComputed()) ComputeGsl();
1021 "GslFirstDerivative() - Unable to compute the first derivative at a = " 1022 +
IString(a) +
" using the GSL interpolation",
1025 if(!InsideDomain(a)) {
1026 ReportException(IException::Programmer,
"GslFirstDerivative()",
1027 "Invalid argument. Value entered, a = " 1028 +
IString(a) +
", is outside of domain = [" 1029 +
IString(DomainMinimum()) +
", " 1030 +
IString(DomainMaximum()) +
"]",
1033 if(!GslInterpType(p_itype)) {
1034 ReportException(IException::Programmer,
"GslFirstDerivative()",
1035 "Method only valid for GSL interpolation types, may not be used for " 1036 + Name() +
" interpolation",
1041 GslIntegrityCheck(gsl_spline_eval_deriv_e(p_interp, a, p_acc, &value),
_FILEINFO_);
1047 "GslFirstDerivative() - Unable to compute the first derivative at a = " 1048 +
IString(a) +
". GSL integrity check failed",
1065 double NumericalApproximation::EvaluateCubicHermiteFirstDeriv(
const double a) {
1066 if(p_itype != NumericalApproximation::CubicHermite) {
1067 ReportException(IException::User,
"EvaluateCubicHermiteFirstDeriv()",
1068 "This method is only valid for cspline-Hermite interpolation, may not be used for " 1069 + Name() +
" interpolation",
1072 if(p_fprimeOfx.size() != Size()) {
1073 ReportException(IException::User,
"EvaluateCubicHermiteFirstDeriv()",
1074 "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.",
1078 int lowerIndex = FindIntervalLowerIndex(a);
1082 if(a == p_x[lowerIndex]) {
1083 return p_fprimeOfx[lowerIndex];
1085 if(a == p_x[lowerIndex+1]) {
1086 return p_fprimeOfx[lowerIndex+1];
1089 double x0, x1, y0, y1, m0, m1;
1091 x0 = p_x[lowerIndex];
1092 x1 = p_x[lowerIndex+1];
1094 y0 = p_y[lowerIndex];
1095 y1 = p_y[lowerIndex+1];
1097 m0 = p_fprimeOfx[lowerIndex];
1098 m1 = p_fprimeOfx[lowerIndex+1];
1104 return ((6 * t * t - 6 * t) * y0 + (3 * t * t - 4 * t + 1) * h * m0 + (-6 * t * t + 6 * t) * y1 + (3 * t * t - 2 * t) * h * m1) / h;
1153 double NumericalApproximation::BackwardFirstDifference(
const double a,
const unsigned int n,
const double h) {
1154 if(!InsideDomain(a)) {
1155 ReportException(IException::Programmer,
"BackwardFirstDifference()",
1156 "Invalid argument. Value entered, a = " 1157 +
IString(a) +
", is outside of domain = [" 1158 +
IString(DomainMinimum()) +
", " 1159 +
IString(DomainMaximum()) +
"]",
1162 if(!InsideDomain(a - (n - 1)*h)) {
1163 ReportException(IException::Programmer,
"BackwardFirstDifference()",
1164 "Formula steps outside of domain. For " 1165 +
IString((
int) n) +
"-point backward difference, a-(n-1)h = " 1166 +
IString(a - (n - 1)*h) +
" is smaller than domain min = " 1168 +
". Try forward difference or use smaller value for h or n",
1171 if(!p_dataValidated) ValidateDataSet();
1175 for(
double i = 0; i < n; i++) {
1176 xi = a + h * (i - (n - 1));
1177 f.push_back(Evaluate(xi));
1183 "BackwardFirstDifference() - Unable to calculate backward first difference for (a, n, h) = (" 1189 return (-f[0] + f[1]) / h;
1191 return (3 * f[2] - 4 * f[1] + f[0]) / (2 * h);
1194 "BackwardFirstDifference() - Invalid argument. There is no " 1195 +
IString((
int) n) +
"-point backward difference formula in use",
1242 double NumericalApproximation::ForwardFirstDifference(
const double a,
const unsigned int n,
const double h) {
1243 if(!InsideDomain(a)) {
1244 ReportException(IException::Programmer,
"ForwardFirstDifference()",
1245 "Invalid argument. Value entered, a = " 1246 +
IString(a) +
", is outside of domain = [" 1247 +
IString(DomainMinimum()) +
", " 1248 +
IString(DomainMaximum()) +
"]",
1251 if(!InsideDomain(a + (n - 1)*h)) {
1252 ReportException(IException::Programmer,
"ForwardFirstDifference()",
1253 "Formula steps outside of domain. For " 1254 +
IString((
int) n) +
"-point forward difference, a+(n-1)h = " 1255 +
IString(a + (n - 1)*h) +
" is greater than domain max = " 1257 +
". Try backward difference or use smaller value for h or n",
1260 if(!p_dataValidated) ValidateDataSet();
1264 for(
double i = 0; i < n; i++) {
1266 f.push_back(Evaluate(xi));
1272 "ForwardFirstDifference() - Unable to calculate forward first difference for (a, n, h) = (" 1278 return (-f[0] + f[1]) / h;
1280 return (-3 * f[0] + 4 * f[1] - f[2]) / (2 * h);
1283 "ForwardFirstDifference() - Invalid argument. There is no " 1284 +
IString((
int) n) +
"-point forward difference formula in use",
1332 double NumericalApproximation::CenterFirstDifference(
const double a,
const unsigned int n,
const double h) {
1333 if(!InsideDomain(a)) {
1334 ReportException(IException::Programmer,
"CenterFirstDifference()",
1335 "Invalid argument. Value entered, a = " 1336 +
IString(a) +
", is outside of domain = [" 1337 +
IString(DomainMinimum()) +
", " 1338 +
IString(DomainMaximum()) +
"]",
1341 if(!InsideDomain(a + (n - 1)*h) || !InsideDomain(a - (n - 1)*h)) {
1342 ReportException(IException::Programmer,
"CenterFirstDifference()",
1343 "Formula steps outside of domain. For " 1344 +
IString((
int) n) +
"-point center difference, a-(n-1)h = " 1345 +
IString(a - (n - 1)*h) +
" or a+(n-1)h = " 1346 +
IString(a + (n - 1)*h) +
" is out of domain = [" 1348 +
"]. Use smaller value for h or n",
1351 if(!p_dataValidated) ValidateDataSet();
1355 for(
double i = 0; i < n; i++) {
1356 xi = a + h * (i - (n - 1) / 2);
1357 f.push_back(Evaluate(xi));
1363 "CenterFirstDifference() - Unable to calculate center first difference for (a, n, h) = (" 1369 return (-f[0] + f[2]) / (2 * h);
1371 return (f[0] - 8 * f[1] + 8 * f[3] - f[4]) / (12 * h);
1374 "CenterFirstDifference() - Invalid argument. There is no " 1375 +
IString((
int) n) +
"-point center difference formula in use",
1416 double NumericalApproximation::GslSecondDerivative(
const double a) {
1418 if(!GslComputed()) ComputeGsl();
1423 "GslSecondDerivative() - Unable to compute the second derivative at a = " 1424 +
IString(a) +
" using the GSL interpolation",
1427 if(!InsideDomain(a))
1428 ReportException(IException::Programmer,
"GslSecondDerivative()",
1429 "Invalid argument. Value entered, a = " 1430 +
IString(a) +
", is outside of domain = [" 1431 +
IString(DomainMinimum()) +
", " 1432 +
IString(DomainMaximum()) +
"]",
1434 if(!GslInterpType(p_itype))
1435 ReportException(IException::Programmer,
"GslSecondDerivative()",
1436 "Method only valid for GSL interpolation types, may not be used for " 1437 + Name() +
" interpolation",
1441 if(!GslComputed()) ComputeGsl();
1443 GslIntegrityCheck(gsl_spline_eval_deriv2_e(p_interp, a, p_acc, &value),
_FILEINFO_);
1449 "GslSecondDerivative() - Unable to compute the second derivative at a = " 1450 +
IString(a) +
". GSL integrity check failed",
1468 double NumericalApproximation::EvaluateCubicHermiteSecDeriv(
const double a) {
1469 if(p_itype != NumericalApproximation::CubicHermite) {
1470 ReportException(IException::User,
"EvaluateCubicHermiteSecDeriv()",
1471 "This method is only valid for cspline-Hermite interpolation, may not be used for " 1472 + Name() +
" interpolation",
1475 if(p_fprimeOfx.size() != Size()) {
1476 ReportException(IException::User,
"EvaluateCubicHermiteSecDeriv()",
1477 "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.",
1481 int lowerIndex = FindIntervalLowerIndex(a);
1482 double x0, x1, y0, y1, m0, m1;
1484 x0 = p_x[lowerIndex];
1485 x1 = p_x[lowerIndex+1];
1487 y0 = p_y[lowerIndex];
1488 y1 = p_y[lowerIndex+1];
1490 m0 = p_fprimeOfx[lowerIndex];
1491 m1 = p_fprimeOfx[lowerIndex+1];
1497 return ((12 * t - 6) * y0 + (6 * t - 4) * h * m0 + (-12 * t + 6) * y1 + (6 * t - 2) * h * m1) / h;
1540 double NumericalApproximation::BackwardSecondDifference(
const double a,
const unsigned int n,
const double h) {
1541 if(!InsideDomain(a)) {
1542 ReportException(IException::Programmer,
"BackwardSecondDifference()",
1543 "Invalid argument. Value entered, a = " 1544 +
IString(a) +
", is outside of domain = [" 1545 +
IString(DomainMinimum()) +
", " 1546 +
IString(DomainMaximum()) +
"]",
1549 if(!InsideDomain(a - (n - 1)*h)) {
1550 ReportException(IException::Programmer,
"BackwardSecondDifference()",
1551 "Formula steps outside of domain. For " 1552 +
IString((
int) n) +
"-point backward difference, a-(n-1)h = " 1553 +
IString(a - (n - 1)*h) +
" is smaller than domain min = " 1555 +
". Try forward difference or use smaller value for h or n",
1558 if(!p_dataValidated) ValidateDataSet();
1562 for(
double i = 0; i < n; i++) {
1563 xi = a + h * (i - (n - 1));
1564 f.push_back(Evaluate(xi));
1570 "BackwardSecondDifference() - Unable to calculate backward second difference for (a, n, h) = (" 1576 return (f[0] - 2 * f[1] + f[2]) / (h * h);
1579 "BackwardSecondDifference() - Invalid argument. There is no " 1580 +
IString((
int) n) +
"-point backward second difference formula in use",
1622 double NumericalApproximation::ForwardSecondDifference(
const double a,
const unsigned int n,
const double h) {
1623 if(!InsideDomain(a)) {
1624 ReportException(IException::Programmer,
"ForwardSecondDifference()",
1625 "Invalid argument. Value entered, a = " 1626 +
IString(a) +
", is outside of domain = [" 1627 +
IString(DomainMinimum()) +
", " 1628 +
IString(DomainMaximum()) +
"]",
1631 if(!InsideDomain(a + (n - 1)*h)) {
1632 ReportException(IException::Programmer,
"ForwardSecondDifference()",
1633 "Formula steps outside of domain. For " 1634 +
IString((
int) n) +
"-point forward difference, a+(n-1)h = " 1635 +
IString(a + (n - 1)*h) +
" is greater than domain max = " 1637 +
". Try backward difference or use smaller value for h or n",
1640 if(!p_dataValidated) ValidateDataSet();
1644 for(
double i = 0; i < n; i++) {
1646 f.push_back(Evaluate(xi));
1652 "ForwardSecondDifference() - Unable to calculate forward second difference for (a, n, h) = (" 1658 return (f[0] - 2 * f[1] + f[2]) / (h * h);
1661 "ForwardSecondDifference() - Invalid argument. There is no " 1662 +
IString((
int) n) +
"-point forward second difference formula in use",
1710 double NumericalApproximation::CenterSecondDifference(
const double a,
const unsigned int n,
const double h) {
1711 if(!InsideDomain(a)) {
1712 ReportException(IException::Programmer,
"CenterSecondDifference()",
1713 "Invalid argument. Value entered, a = " 1714 +
IString(a) +
", is outside of domain = [" 1715 +
IString(DomainMinimum()) +
", " 1716 +
IString(DomainMaximum()) +
"]",
1719 if(!InsideDomain(a + (n - 1)*h) || !InsideDomain(a - (n - 1)*h)) {
1720 ReportException(IException::Programmer,
"CenterSecondDifference()",
1721 "Formula steps outside of domain. For " 1722 +
IString((
int) n) +
"-point center difference, a-(n-1)h = " 1723 +
IString(a - (n - 1)*h) +
" or a+(n-1)h = " 1724 +
IString(a + (n - 1)*h) +
" is out of domain = [" 1726 +
"]. Use smaller value for h or n",
1729 if(!p_dataValidated) ValidateDataSet();
1733 for(
double i = 0; i < n; i++) {
1734 xi = a + h * (i - (n - 1) / 2);
1735 f.push_back(Evaluate(xi));
1741 "CenterSecondDifference() - Unable to calculate center second difference for (a, n, h) = (" 1747 return (f[0] - 2 * f[1] + f[2]) / (h * h);
1749 return (-f[0] + 16 * f[1] - 30 * f[2] + 16 * f[3] - f[4]) / (12 * h * h);
1752 "CenterSecondDifference() - Invalid argument. There is no " 1753 +
IString((
int) n) +
"-point center second difference formula in use",
1791 double NumericalApproximation::GslIntegral(
const double a,
const double b) {
1793 if(!GslComputed()) ComputeGsl();
1798 "GslIntegral() - Unable to compute the integral on the interval (a,b) = (" 1800 +
") using the GSL interpolation",
1804 ReportException(IException::Programmer,
"GslIntegral()",
1805 "Invalid interval entered: [a,b] = [" 1809 if(!InsideDomain(a) || !InsideDomain(b)) {
1810 ReportException(IException::Programmer,
"GslIntegral()",
1811 "Invalid arguments. Interval entered [" 1813 +
"] is not contained within domain [" 1814 +
IString(DomainMinimum()) +
", " 1815 +
IString(DomainMaximum()) +
"]",
1818 if(!GslInterpType(p_itype)) {
1819 ReportException(IException::Programmer,
"GslIntegral()",
1820 "Method only valid for GSL interpolation types, may not be used for " 1821 + Name() +
" interpolation",
1826 GslIntegrityCheck(gsl_spline_eval_integ_e(p_interp, a, b, p_acc, &value),
_FILEINFO_);
1832 "GslIntegral() - Unable to compute the integral on the interval (a,b) = (" 1834 +
"). GSL integrity check failed",
1862 double NumericalApproximation::TrapezoidalRule(
const double a,
const double b) {
1867 vector <double> f = EvaluateForIntegration(a, b, n);
1868 double h = f.back();
1872 for(
unsigned int i = 0; i < (f.size() - 1) / (n - 1); i++) {
1873 ii = (i + 1) * (n - 1);
1874 result += (f[ii-1] + f[ii]) * h / 2;
1881 "TrapezoidalRule() - Unable to calculate the integral on the interval (a,b) = (" 1883 +
") using the trapeziodal rule",
1914 double NumericalApproximation::Simpsons3PointRule(
const double a,
const double b) {
1919 vector <double> f = EvaluateForIntegration(a, b, n);
1920 double h = f.back();
1923 for(
unsigned int i = 0; i < (f.size() - 1) / (n - 1); i++) {
1924 ii = (i + 1) * (n - 1);
1925 result += (f[ii-2] + 4 * f[ii-1] + f[ii]) * h / 3;
1932 "Simpsons3PointRule() - Unable to calculate the integral on the interval (a,b) = (" 1934 +
") using Simpson's 3 point rule",
1966 double NumericalApproximation::Simpsons4PointRule(
const double a,
const double b) {
1971 vector <double> f = EvaluateForIntegration(a, b, n);
1972 double h = f.back();
1975 for(
unsigned int i = 0; i < (f.size() - 1) / (n - 1); i++) {
1976 ii = (i + 1) * (n - 1);
1977 result += (f[ii-3] + 3 * f[ii-2] + 3 * f[ii-1] + f[ii]) * h * 3 / 8;
1984 "Simpsons4PointRule() - Unable to calculate the integral on the interval (a,b) = (" 1986 +
") using Simpson's 4 point rule",
2021 double NumericalApproximation::BoolesRule(
const double a,
const double b) {
2026 vector <double> f = EvaluateForIntegration(a, b, n);
2027 double h = f.back();
2030 for(
unsigned int i = 0; i < (f.size() - 1) / (n - 1); i++) {
2031 ii = (i + 1) * (n - 1);
2032 result += (7 * f[ii-4] + 32 * f[ii-3] + 12 * f[ii-2] + 32 * f[ii-1] + 7 * f[ii]) * h * 2 / 45;
2039 "BoolesRule() - Unable to calculate the integral on the interval (a,b) = (" 2041 +
") using Boole's rule",
2090 double NumericalApproximation::RefineExtendedTrap(
double a,
double b,
double s,
unsigned int n) {
2097 if(GslInterpType(p_itype) || p_itype == NumericalApproximation::CubicNeighborhood) {
2099 begin = Evaluate(a, NumericalApproximation::NearestEndpoint);
2100 end = Evaluate(b, NumericalApproximation::NearestEndpoint);
2104 begin = Evaluate(a, NumericalApproximation::Extrapolate);
2105 end = Evaluate(b, NumericalApproximation::Extrapolate);
2107 return (0.5 * (b - a) * (begin + end));
2111 double delta, tnm, x, sum;
2112 it = (int)(pow(2.0, (
double)(n - 2)));
2114 delta = (b - a) / tnm;
2115 x = a + 0.5 * delta;
2117 for(
int i = 0; i < it; i++) {
2118 if(GslInterpType(p_itype) || p_itype == NumericalApproximation::CubicNeighborhood) {
2119 sum = sum + Evaluate(x, NumericalApproximation::NearestEndpoint);
2122 sum = sum + Evaluate(x, NumericalApproximation::Extrapolate);
2126 return (0.5 * (s + (b - a) * sum / tnm));
2132 "RefineExtendedTrap() - Unable to calculate the integral on the interval (a,b) = (" 2134 +
") using the extended trapeziodal rule",
2173 double NumericalApproximation::RombergsMethod(
double a,
double b) {
2180 double trap[maxits+1];
2191 for(
int i = 0; i < maxits; i++) {
2194 trap[i] = RefineExtendedTrap(a, b, trap[i], i + 1);
2196 interp.
AddData(5, &h[i-4], &trap[i-4]);
2198 ss = interp.
Evaluate(0.0, NumericalApproximation::Extrapolate);
2202 if(fabs(dss) <= epsilon * fabs(ss))
return ss;
2203 if(fabs(dss) <= epsilon2)
return ss;
2205 trap[i+1] = trap[i];
2206 h[i+1] = 0.25 * h[i];
2217 "RombergsMethod() - Unable to calculate the integral on the interval (a,b) = (" 2219 +
") using Romberg's method",
2223 "RombergsMethod() - Unable to calculate the integral using RombergsMethod() - Failed to converge in " 2224 +
IString(maxits) +
" iterations",
2245 void NumericalApproximation::Reset() {
2246 if(GslInterpType(p_itype)) GslDeallocation();
2247 p_clampedComputed =
false;
2248 p_clampedEndptsSet =
false;
2249 p_dataValidated =
false;
2252 p_clampedSecondDerivs.clear();
2253 p_clampedDerivFirstPt = 0;
2254 p_clampedDerivLastPt = 0;
2255 p_polyNevError.clear();
2256 p_fprimeOfx.clear();
2280 SetInterpType(itype);
2286 "Reset() - Unable to reset interpolation type",
2315 if(GslInterpType(itype)) {
2322 "SetInterpType() - Unable to set interpolation type",
2326 else if(itype > 9) {
2327 ReportException(IException::Programmer,
"SetInterpType()",
2328 "Invalid argument. Unknown interpolation type: " 2335 p_dataValidated =
false;
2336 p_clampedComputed =
false;
2337 p_clampedEndptsSet =
false;
2338 p_clampedSecondDerivs.clear();
2339 p_clampedDerivFirstPt = 0;
2340 p_clampedDerivLastPt = 0;
2341 p_polyNevError.clear();
2342 p_fprimeOfx.clear();
2370 if(p_interpFunctors.empty()) {
2371 p_interpFunctors.insert(make_pair(Linear, gsl_interp_linear));
2372 p_interpFunctors.insert(make_pair(Polynomial, gsl_interp_polynomial));
2373 p_interpFunctors.insert(make_pair(CubicNatural, gsl_interp_cspline));
2374 p_interpFunctors.insert(make_pair(CubicNatPeriodic, gsl_interp_cspline_periodic));
2375 p_interpFunctors.insert(make_pair(Akima, gsl_interp_akima));
2376 p_interpFunctors.insert(make_pair(AkimaPeriodic, gsl_interp_akima_periodic));
2382 SetInterpType(itype);
2387 "Init() - Unable to initialize NumericalApproximation object",
2392 gsl_set_error_handler_off();
2413 if(itype == NumericalApproximation::Linear)
return true;
2414 if(itype == NumericalApproximation::Polynomial)
return true;
2415 if(itype == NumericalApproximation::CubicNatural)
return true;
2416 if(itype == NumericalApproximation::CubicNatPeriodic)
return true;
2417 if(itype == NumericalApproximation::Akima)
return true;
2418 if(itype == NumericalApproximation::AkimaPeriodic)
return true;
2438 void NumericalApproximation::GslAllocation(
unsigned int npoints) {
2441 p_acc = gsl_interp_accel_alloc();
2443 p_interp = gsl_spline_alloc(GslFunctor(p_itype), npoints);
2460 void NumericalApproximation::GslDeallocation() {
2461 if(p_interp) gsl_spline_free(p_interp);
2462 if(p_acc) gsl_interp_accel_free(p_acc);
2489 if(fItr == p_interpFunctors.end()) {
2490 ReportException(IException::Programmer,
"GslFunctor()",
2491 "Invalid argument. Unable to find GSL interpolator with id = " 2495 return (fItr->second);
2517 void NumericalApproximation::GslIntegrityCheck(
int gsl_status,
const char *src,
int line)
2519 if(gsl_status != GSL_SUCCESS) {
2520 if(gsl_status != GSL_EDOM) {
2521 ReportException(IException::Programmer,
"GslIntegrityCheck(int,char,int)",
2522 "GslIntegrityCheck(): GSL error occured: " 2523 +
string(gsl_strerror(gsl_status)), src, line);
2557 void NumericalApproximation::ValidateDataSet() {
2558 if((
int) Size() < MinPoints()) {
2559 ReportException(IException::Programmer,
"ValidateDataSet()",
2560 Name() +
" interpolation requires a minimum of " 2561 +
IString(MinPoints()) +
" data points - currently have " 2565 for(
unsigned int i = 1; i < Size(); i++) {
2567 if(p_x[i-1] == p_x[i]) {
2568 ReportException(IException::Programmer,
"ValidateDataSet()",
2569 "Invalid data set, x-values must be unique: \n\t\tp_x[" 2571 +
" = p_x[" +
IString((
int) i) +
"]",
2574 if(p_x[i-1] > p_x[i]) {
2577 if(p_itype != NumericalApproximation::PolynomialNeville) {
2578 ReportException(IException::Programmer,
"ValidateDataSet()",
2579 "Invalid data set, x-values must be in ascending order for " 2580 + Name() +
" interpolation: \n\t\tx[" 2587 if(p_itype == NumericalApproximation::CubicNatPeriodic) {
2588 if(p_y[0] != p_y[Size()-1]) {
2589 ReportException(IException::Programmer,
"ValidateDataSet()",
2590 "First and last points of the data set must have the same y-value for " 2591 + Name() +
"interpolation to prevent discontinuity at the boundary",
2595 p_dataValidated =
true;
2613 bool NumericalApproximation::InsideDomain(
const double a) {
2615 if(a + DBL_EPSILON < DomainMinimum()) {
2618 if(a - DBL_EPSILON > DomainMaximum()) {
2625 "InsideDomain() - Unable to compute domain boundaries",
2647 bool NumericalApproximation::GslComputed()
const {
2648 if(GslInterpType(p_itype))
return ((p_interp) && (p_acc));
2651 "GslComputed() - Method only valid for GSL interpolation types, may not be used for " 2652 + Name() +
" interpolation",
2677 void NumericalApproximation::ComputeGsl() {
2679 if(GslComputed())
return;
2680 if(!p_dataValidated) ValidateDataSet();
2681 GslAllocation(Size());
2682 GslIntegrityCheck(gsl_spline_init(p_interp, &p_x[0], &p_y[0], Size()),
_FILEINFO_);
2688 "ComputeGsl() - Unable to compute GSL interpolation",
2729 void NumericalApproximation::ComputeCubicClamped() {
2734 if(!p_dataValidated) {
2741 "ComputeCubicClamped() - Unable to compute cubic clamped interpolation",
2745 if(!p_clampedEndptsSet) {
2746 ReportException(IException::Programmer,
"ComputeCubicClamped()",
2747 "Must set endpoint derivative values after adding data in order to compute cubic spline with clamped boundary conditions",
2751 p_clampedSecondDerivs.resize(n);
2753 double p, sig, qn, un;
2755 if(p_clampedDerivFirstPt > 0.99e30) {
2756 p_clampedSecondDerivs[0] = 0.0;
2760 p_clampedSecondDerivs[0] = -0.5;
2761 u[0] = (3.0 / (p_x[1] - p_x[0])) * ((p_y[1] - p_y[0]) / (p_x[1] - p_x[0]) - p_clampedDerivFirstPt);
2763 for(
int i = 1; i < n - 1; i++) {
2764 sig = (p_x[i] - p_x[i-1]) / (p_x[i+1] - p_x[i-1]);
2765 p = sig * p_clampedSecondDerivs[i-1] + 2.0;
2766 p_clampedSecondDerivs[i] = (sig - 1.0) / p;
2767 u[i] = (6.0 * ((p_y[i+1] - p_y[i]) / (p_x[i+1] - p_x[i]) - (p_y[i] - p_y[i-1]) /
2768 (p_x[i] - p_x[i-1])) / (p_x[i+1] - p_x[i-1]) - sig * u[i-1]) / p;
2770 if(p_clampedDerivLastPt > 0.99e30) {
2776 un = (3.0 / (p_x[n-1] - p_x[n-2])) * (p_clampedDerivLastPt - (p_y[n-1] - p_y[n-2]) /
2777 (p_x[n-1] - p_x[n-2]));
2779 p_clampedSecondDerivs[n-1] = (un - qn * u[n-2]) / (qn * p_clampedSecondDerivs[n-2] + 1.0);
2780 for(
int i = n - 2; i >= 0; i--) {
2781 p_clampedSecondDerivs[i] = p_clampedSecondDerivs[i] * p_clampedSecondDerivs[i+1] + u[i];
2783 p_clampedComputed =
true;
2824 double NumericalApproximation::ValueToExtrapolate(
const double a,
const ExtrapType &etype) {
2825 if(etype == NumericalApproximation::ThrowError) {
2826 ReportException(IException::Programmer,
"Evaluate()",
2827 "Invalid argument. Value entered, a = " 2828 +
IString(a) +
", is outside of domain = [" 2829 +
IString(DomainMinimum()) +
", " 2830 +
IString(DomainMaximum()) +
"]",
2833 if(etype == NumericalApproximation::NearestEndpoint) {
2834 if(a + DBL_EPSILON < DomainMinimum()) {
2835 return DomainMinimum();
2838 return DomainMaximum();
2842 if(GslInterpType(p_itype)
2843 || p_itype == NumericalApproximation::CubicNeighborhood) {
2844 ReportException(IException::Programmer,
"Evaluate()",
2845 "Invalid argument. Cannot extrapolate for type " 2846 + Name() +
", must choose to throw error or return nearest neighbor",
2887 double NumericalApproximation::EvaluateCubicNeighborhood(
const double a) {
2889 int s = 0, s_old, s0;
2890 vector <double> x0(4), y0(4);
2892 for(
unsigned int n = 0; n < Size(); n++) {
2893 if(p_x[n] < a) s = n;
2897 else if(s > (
int) Size() - 3) s = Size() - 3;
2901 for(
int n = 0; n < 4; n++) {
2910 return spline.
Evaluate(a, NumericalApproximation::NearestEndpoint);
2915 "EvaluateCubicNeighborhood() - Unable to evaluate cubic neighborhood interpolation at a = " 2967 vector <double> NumericalApproximation::EvaluateCubicNeighborhood(
const vector <double> &a,
2969 vector <double> result(a.size());
2971 vector <double> x0(4), y0(4);
2975 for(
unsigned int i = 0; i < a.size(); i++) {
2976 for(
unsigned int n = 0; n < Size(); n++) {
2984 if(s[i] > ((
int) Size()) - 3) {
2991 for(
unsigned int i = 0; i < a.size(); i++) {
2995 for(
int n = 0; n < 4; n++) {
3004 if(InsideDomain(a[i]))
3006 else a0 = ValueToExtrapolate(a[i], etype);
3008 result[i] = spline.
Evaluate(a0, NumericalApproximation::NearestEndpoint);
3015 "EvaluateCubicNeighborhood() - Unable to evaluate the function at the given vector of points using cubic neighborhood interpolation",
3054 double NumericalApproximation::EvaluateCubicClamped(
double a) {
3070 while(k_Hi - k_Lo > 1) {
3071 k = (k_Hi + k_Lo) / 2;
3080 h = p_x[k_Hi] - p_x[k_Lo];
3081 A = (p_x[k_Hi] - a) / h;
3082 B = (a - p_x[k_Lo]) / h;
3083 result = A * p_y[k_Lo] + B * p_y[k_Hi] + ((pow(A, 3.0) - A) *
3084 p_clampedSecondDerivs[k_Lo] + (pow(B, 3.0) - B) * p_clampedSecondDerivs[k_Hi]) * pow(h, 2.0) / 6.0;
3115 double NumericalApproximation::EvaluateCubicHermite(
const double a) {
3119 if(p_fprimeOfx.size() != Size()) {
3120 ReportException(IException::User,
"EvaluateCubicHermite()",
3121 "Invalid arguments. The size of the first derivative vector does not match the number of (x,y) data points.",
3125 int lowerIndex = FindIntervalLowerIndex(a);
3129 if(a == p_x[lowerIndex]) {
3130 return p_y[lowerIndex];
3132 if(a == p_x[lowerIndex+1]) {
3133 return p_y[lowerIndex+1];
3136 double x0, x1, y0, y1, m0, m1;
3138 x0 = p_x[lowerIndex];
3139 x1 = p_x[lowerIndex+1];
3141 y0 = p_y[lowerIndex];
3142 y1 = p_y[lowerIndex+1];
3144 m0 = p_fprimeOfx[lowerIndex];
3145 m1 = p_fprimeOfx[lowerIndex+1];
3154 return (2 * t * t * t - 3 * t * t + 1) * y0 + (t * t * t - 2 * t * t + t) * h * m0 + (-2 * t * t * t + 3 * t * t) * y1 + (t * t * t - t * t) * h * m1;
3177 int NumericalApproximation::FindIntervalLowerIndex(
const double a) {
3178 if(InsideDomain(a)) {
3180 std::vector<double>::iterator pos;
3182 pos = upper_bound(p_x.begin(), p_x.end(), a);
3184 if(pos != p_x.end()) {
3185 upperIndex = distance(p_x.begin(), pos);
3188 upperIndex = Size() - 1;
3190 return upperIndex - 1;
3192 else if((a + DBL_EPSILON) < DomainMinimum()) {
3236 double NumericalApproximation::EvaluatePolynomialNeville(
const double a) {
3244 double den, dif, dift, c[n], d[n], ho, hp, w;
3247 dif = fabs(a - p_x[0]);
3248 for(
int i = 0; i < n; i++) {
3249 dift = fabs(a - p_x[i]);
3259 for(
int m = 1; m < n; m++) {
3260 for(
int i = 1; i <= n - m; i++) {
3262 hp = p_x[i+m-1] - a;
3269 if(2 * ns < n - m) {
3278 p_polyNevError.push_back(*err);
3300 vector <double> NumericalApproximation::EvaluateForIntegration(
const double a,
const double b,
const unsigned int n) {
3302 ReportException(IException::Programmer,
"EvaluatedForIntegration()",
3303 "Invalid interval entered: [a,b] = [" 3307 if(!InsideDomain(a) || !InsideDomain(b)) {
3308 ReportException(IException::Programmer,
"EvaluateForIntegration()",
3309 "Invalid arguments. Interval entered [" 3311 +
"] is not contained within domain [" 3312 +
IString(DomainMinimum()) +
", " 3313 +
IString(DomainMaximum()) +
"]",
3320 int xSegments = Size() - 1;
3321 while(xSegments % (n - 1) != 0) {
3328 double h = (xMax - xMin) / xSegments;
3331 for(
double i = 0; i < (xSegments + 1); i++) {
3332 double xi = h * i + xMin;
3333 f.push_back(Evaluate(xi));
3341 "EvaluateForIntegration() - Unable to evaluate the data set for integration",
3366 void NumericalApproximation::ReportException(
IException::ErrorType type,
const string &methodName,
const string &message,
3367 const char *filesrc,
int lineno)
3369 string msg = methodName +
" - " + message;
3370 throw IException(type, msg.c_str(), filesrc, lineno);
bool p_clampedEndptsSet
Flag variable to determine whether SetCubicClampedEndptDeriv() has been called after all data was add...
vector< double > p_x
List of X values.
InterpType
This enum defines the types of interpolation supported in this class.
vector< double > p_fprimeOfx
List of first derivatives corresponding to each x value in the data set (i.e. each value in p_x) ...
double p_clampedDerivFirstPt
First derivative of first x-value, p_x[0]. This is only used for the CubicClamped interpolation type...
Namespace for the standard library.
NumericalApproximation provides various numerical analysis methods of interpolation, extrapolation and approximation of a tabulated set of x, y data.
vector< double > p_clampedSecondDerivs
List of second derivatives evaluated at p_x values. This is only used for the CubicClamped interpolat...
double Evaluate(const double a, const ExtrapType &etype=ThrowError)
Calculates interpolated or extrapolated value of tabulated data set for given domain value...
void Reset()
Resets the state of the object.
vector< double > PolynomialNevilleErrorEstimate()
Retrieves the error estimate for the Neville's polynomial interpolation type.
ExtrapType
This enum defines the manner in which a value outside of the domain should be handled if passed to th...
#define _FILEINFO_
Macro for the filename and line number.
double p_clampedDerivLastPt
First derivative of last x-value, p_x[n-1]. This is only used for the CubicClamped interpolation type...
const gsl_interp_type * InterpFunctor
GSL Interpolation specs.
InterpFunctor GslFunctor(NumericalApproximation::InterpType itype) const
Search for a GSL interpolation function.
ErrorType errorType() const
Returns the source of the error for this exception.
ErrorType
Contains a set of exception error types.
void AddData(const double x, const double y)
Add a datapoint to the set.
bool p_dataValidated
Flag variable to determine whether ValidateDataSet() has been called.
Adds specific functionality to C++ strings.
Namespace for ISIS/Bullet specific routines.
vector< double > p_y
List of Y values.
vector< double > p_polyNevError
Estimate of error for interpolation evaluated at x. This is only used for the PolynomialNeville inter...
InterpType p_itype
Interpolation type.
FunctorList::const_iterator FunctorConstIter
GSL Iterator.
bool p_clampedComputed
Flag variable to determine whether ComputeCubicClamped() has been called.