LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
Public Types | Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
lsst::afw::math::detail::TautSpline Class Reference

#include <Spline.h>

Inheritance diagram for lsst::afw::math::detail::TautSpline:
lsst::afw::math::detail::Spline

Public Types

enum  Symmetry { Unknown , Odd , Even }
 

Public Member Functions

 TautSpline (std::vector< double > const &x, std::vector< double > const &y, double const gamma=0, Symmetry type=Unknown)
 Construct cubic spline interpolant to given data. More...
 
void interpolate (std::vector< double > const &x, std::vector< double > &y) const
 Interpolate a Spline. More...
 
void derivative (std::vector< double > const &x, std::vector< double > &dydx) const
 Find the derivative of a Spline. More...
 
std::vector< double > roots (double const value, double const x0, double const x1) const
 Find the roots of Spline - val = 0 in the range [x0, x1). More...
 

Protected Member Functions

void _allocateSpline (int const nknot)
 Allocate the storage a Spline needs. More...
 

Protected Attributes

std::vector< double > _knots
 
std::vector< std::vector< double > > _coeffs
 

Detailed Description

Definition at line 59 of file Spline.h.

Member Enumeration Documentation

◆ Symmetry

Enumerator
Unknown 
Odd 
Even 

Definition at line 61 of file Spline.h.

Constructor & Destructor Documentation

◆ TautSpline()

lsst::afw::math::detail::TautSpline::TautSpline ( std::vector< double > const &  x,
std::vector< double > const &  y,
double const  gamma = 0,
Symmetry  type = Unknown 
)

Construct cubic spline interpolant to given data.

Adapted from A Practical Guide to Splines by C. de Boor (N.Y. : Springer-Verlag, 1978). (His routine tautsp converted to C by Robert Lupton and then to C++ by an older and grayer Robert Lupton)

If gamma > 0, additional knots are introduced where needed to make the interpolant more flexible locally. This avoids extraneous inflection points typical of cubic spline interpolation at knots to rapidly changing data. Values for gamma are:

  • = 0, no additional knots
  • in (0, 3), under certain conditions on the given data at points i-1, i, i+1, and i+2, a knot is added in the i-th interval, i=1,...,ntau-3. See notes below. The interpolant gets rounded with increasing gamma. A value of 2.5 for gamma is typical.
  • in (3, 6), same as above, except that knots might also be added in intervals in which an inflection point would be permitted. A value of 5.5 for gamma is typical.
Parameters
xpoints where function's specified
yvalues of function at tau[]
gammacontrol extra knots. See main description for details.
typespecify the desired symmetry (e.g. Even)
Exceptions
pex::exceptions::InvalidParameterErrorThrown if x and y do not have the same length or do not have at least two points
Note
on the i-th interval, (tau[i], tau[i+1]), the interpolant is of the form (*) f(u(x)) = a + b*u + c*h(u,z) + d*h(1-u,1-z) , with u = u(x) = (x - tau[i])/dtau[i]. Here, z = z(i) = addg(i+1)/(addg(i) + addg(i+1)) (= .5, in case the denominator vanishes). with ddg(j) = dg(j+1) - dg(j), addg(j) = abs(ddg(j)), dg(j) = divdif(j) = (gtau[j+1] - gtau[j])/dtau[j] and h(u,z) = alpha*u**3 + (1 - alpha)*(max(((u-zeta)/(1-zeta)),0)**3 with alpha(z) = (1-gamma/3)/zeta zeta(z) = 1 - gamma*min((1 - z), 1/3) thus, for 1/3 .le. z .le. 2/3, f is just a cubic polynomial on the interval i. otherwise, it has one additional knot, at tau[i] + zeta*dtau[i] . as z approaches 1, h(.,z) has an increasingly sharp bend near 1, thus allowing f to turn rapidly near the additional knot. in terms of f(j) = gtau[j] and fsecnd[j] = 2*derivative of f at tau[j], the coefficients for (*) are given as a = f(i) - d b = (f(i+1) - f(i)) - (c - d) c = fsecnd[i+1]*dtau[i]**2/hsecnd(1,z) d = fsecnd[i]*dtau[i]**2/hsecnd(1,1-z) hence can be computed once fsecnd[i],i=0,...,ntau-1, is fixed.
f is automatically continuous and has a continuous second derivat- ive (except when z = 0 or 1 for some i). we determine fscnd(.) from the requirement that also the first derivative of f be continuous. in addition, we require that the third derivative be continuous across tau[1] and across tau[ntau-2] . this leads to a strictly diagonally dominant tridiagonal linear system for the fsecnd[i] which we solve by gauss elimination without pivoting.
There must be at least 4 interpolation points for us to fit a taut cubic spline, but if you provide fewer we'll fit a quadratic or linear polynomial (but you must provide at least 2)

Definition at line 86 of file Spline.cc.

87  {
88  if (x.size() != y.size()) {
90  (boost::format("TautSpline: x and y must have the same size; saw %d %d\n") %
91  x.size() % y.size())
92  .str());
93  }
94 
95  int const ntau = x.size(); /* size of tau and gtau, must be >= 2*/
96  if (ntau < 2) {
98  (boost::format("TautSpline: ntau = %d, should be >= 2\n") % ntau).str());
99  }
100 
101  switch (type) {
102  case Unknown:
103  calculateTautSpline(x, y, gamma0);
104  break;
105  case Even:
106  case Odd:
107  calculateTautSplineEvenOdd(x, y, gamma0, type == Even);
108  break;
109  }
110 }
double x
table::Key< int > type
Definition: Detector.cc:163
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
int y
Definition: SpanSet.cc:48
Reports invalid arguments.
Definition: Runtime.h:66
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174

Member Function Documentation

◆ _allocateSpline()

void lsst::afw::math::detail::Spline::_allocateSpline ( int const  nknot)
protectedinherited

Allocate the storage a Spline needs.

Definition at line 21 of file Spline.cc.

21  {
22  _knots.resize(nknot);
23  _coeffs.resize(4);
24  for (unsigned int i = 0; i != _coeffs.size(); ++i) {
25  _coeffs[i].reserve(nknot);
26  }
27 }
std::vector< double > _knots
Definition: Spline.h:55
std::vector< std::vector< double > > _coeffs
Definition: Spline.h:56
T reserve(T... args)
T resize(T... args)
T size(T... args)

◆ derivative()

void lsst::afw::math::detail::Spline::derivative ( std::vector< double > const &  x,
std::vector< double > &  dydx 
) const
inherited

Find the derivative of a Spline.

Parameters
[in]xpoints to evaluate derivative at
[out]dydxderivatives at x

Definition at line 57 of file Spline.cc.

57  {
58  int const nknot = _knots.size();
59  int const n = x.size();
60 
61  dydx.resize(n); // may default-construct elements which is a little inefficient
62  /*
63  * For _knots[i] <= x <= _knots[i+1], the * interpolant has the form
64  * val = _coeff[0][i] +dx*(_coeff[1][i] + dx*(_coeff[2][i]/2 + dx*_coeff[3][i]/6))
65  * with
66  * dx = x - knots[i]
67  * so the derivative is
68  * val = _coeff[1][i] + dx*(_coeff[2][i] + dx*_coeff[3][i]/2))
69  */
70 
71  int ind = -1; // no idea initially
72  for (int i = 0; i != n; ++i) {
73  ind = search_array(x[i], &_knots[0], nknot, ind);
74 
75  if (ind < 0) { // off bottom
76  ind = 0;
77  } else if (ind >= nknot) { // off top
78  ind = nknot - 1;
79  }
80 
81  double const dx = x[i] - _knots[ind];
82  dydx[i] = _coeffs[1][ind] + dx * (_coeffs[2][ind] + dx * _coeffs[3][ind] / 2);
83  }
84 }

◆ interpolate()

void lsst::afw::math::detail::Spline::interpolate ( std::vector< double > const &  x,
std::vector< double > &  y 
) const
inherited

Interpolate a Spline.

Parameters
[in]xpoints to interpolate at
[out]yvalues of spline interpolation at x

Definition at line 29 of file Spline.cc.

29  {
30  int const nknot = _knots.size();
31  int const n = x.size();
32 
33  y.resize(n); // may default-construct elements which is a little inefficient
34  /*
35  * For _knots[i] <= x <= _knots[i+1], the interpolant
36  * has the form
37  * val = _coeff[0][i] +dx*(_coeff[1][i] + dx*(_coeff[2][i]/2 + dx*_coeff[3][i]/6))
38  * with
39  * dx = x - knots[i]
40  */
41  int ind = -1; // no idea initially
42  for (int i = 0; i != n; ++i) {
43  ind = search_array(x[i], &_knots[0], nknot, ind);
44 
45  if (ind < 0) { // off bottom
46  ind = 0;
47  } else if (ind >= nknot) { // off top
48  ind = nknot - 1;
49  }
50 
51  double const dx = x[i] - _knots[ind];
52  y[i] = _coeffs[0][ind] +
53  dx * (_coeffs[1][ind] + dx * (_coeffs[2][ind] / 2 + dx * _coeffs[3][ind] / 6));
54  }
55 }

◆ roots()

std::vector< double > lsst::afw::math::detail::Spline::roots ( double const  value,
double const  x0,
double const  x1 
) const
inherited

Find the roots of Spline - val = 0 in the range [x0, x1).

Return a vector of all the roots found

Parameters
valuedesired value
x0,x1specify desired range is [x0,x1)

Definition at line 1226 of file Spline.cc.

1226  {
1227  /*
1228  * Strategy: we know that the interpolant has the form
1229  * val = coef[0][i] +dx*(coef[1][i] + dx*(coef[2][i]/2 + dx*coef[3][i]/6))
1230  * so we can use the usual analytic solution for a cubic. Note that the
1231  * cubic quoted above returns dx, the distance from the previous knot,
1232  * rather than x itself
1233  */
1234  std::vector<double> roots; /* the roots found */
1235  double x0 = a; // lower end of current range
1236  double const x1 = b;
1237  int const nknot = _knots.size();
1238 
1239  int i0 = search_array(x0, &_knots[0], nknot, -1);
1240  int const i1 = search_array(x1, &_knots[0], nknot, i0);
1241  assert(i1 >= i0 && i1 <= nknot - 1);
1242 
1243  std::vector<double> newRoots; // the roots we find in some interval
1244  /*
1245  * Deal with special case that x0 may be off one end or the other of
1246  * the array of knots.
1247  */
1248  if (i0 < 0) { /* off bottom */
1249  i0 = 0;
1250  do_cubic(_coeffs[3][i0] / 6, _coeffs[2][i0] / 2, _coeffs[1][i0], _coeffs[0][i0] - value, newRoots);
1251  //
1252  // Could use
1253  // std::transform(newRoots.begin(), newRoots.end(), newRoots.begin(),
1254  // std::bind(std::plus<double>(), _1, _knots[i0]));
1255  // but let's not
1256  //
1257  for (unsigned int j = 0; j != newRoots.size(); ++j) {
1258  newRoots[j] += _knots[i0];
1259  }
1260  keep_valid_roots(roots, newRoots, x0, _knots[i0]);
1261 
1262  x0 = _knots[i0];
1263  } else if (i0 >= nknot) { /* off top */
1264  i0 = nknot - 1;
1265  assert(i0 >= 0);
1266  do_cubic(_coeffs[3][i0] / 6, _coeffs[2][i0] / 2, _coeffs[1][i0], _coeffs[0][i0] - value, newRoots);
1267 
1268  for (unsigned int j = 0; j != newRoots.size(); ++j) {
1269  newRoots[j] += _knots[i0];
1270  }
1271  keep_valid_roots(roots, newRoots, x0, x1);
1272 
1273  return roots;
1274  }
1275  /*
1276  * OK, now search in main body of spline. Note that i1 may be nknot - 1, and
1277  * in any case the right hand limit of the last segment is at x1, not a knot
1278  */
1279  for (int i = i0; i <= i1; i++) {
1280  do_cubic(_coeffs[3][i] / 6, _coeffs[2][i] / 2, _coeffs[1][i], _coeffs[0][i] - value, newRoots);
1281 
1282  for (unsigned int j = 0; j != newRoots.size(); ++j) {
1283  newRoots[j] += _knots[i];
1284  }
1285  keep_valid_roots(roots, newRoots, ((i == i0) ? x0 : _knots[i]), ((i == i1) ? x1 : _knots[i + 1]));
1286  }
1287 
1288  return roots;
1289 }
table::Key< int > b
table::Key< int > a
std::vector< double > roots(double const value, double const x0, double const x1) const
Find the roots of Spline - val = 0 in the range [x0, x1).
Definition: Spline.cc:1226

Member Data Documentation

◆ _coeffs

std::vector<std::vector<double> > lsst::afw::math::detail::Spline::_coeffs
protectedinherited

Definition at line 56 of file Spline.h.

◆ _knots

std::vector<double> lsst::afw::math::detail::Spline::_knots
protectedinherited

Definition at line 55 of file Spline.h.


The documentation for this class was generated from the following files: