Commit a8148ba2 authored by Charlles Abreu's avatar Charlles Abreu
Browse files

Periodic 2D and 3D spline filters

parent bff7086a
...@@ -43,6 +43,18 @@ namespace OpenMM { ...@@ -43,6 +43,18 @@ namespace OpenMM {
class OPENMM_EXPORT SplineFitter { class OPENMM_EXPORT SplineFitter {
public: public:
/**
* Fit a cubic spline to a set of data points. The resulting spline interpolates all the
* data points and has a continuous second derivative everywhere. The second derivatives are
* identical at the end points if periodic=true or 0 at the end points if periodic=false.
*
* @param x the values of the independent variable at the data points to interpolate. They must
* be strictly increasing: x[i] > x[i-1].
* @param y the values of the dependent variable at the data points to interpolate
* @param periodic whether the interpolated function is periodic
* @param deriv on exit, this contains the second derivative of the spline at each of the data points
*/
static void createSpline(const std::vector<double>& x, const std::vector<double>& y, bool periodic, std::vector<double>& deriv);
/** /**
* Fit a natural cubic spline to a set of data points. The resulting spline interpolates all the * Fit a natural cubic spline to a set of data points. The resulting spline interpolates all the
* data points, has a continuous second derivative everywhere, and has a second derivative of 0 at * data points, has a continuous second derivative everywhere, and has a second derivative of 0 at
...@@ -86,6 +98,21 @@ public: ...@@ -86,6 +98,21 @@ public:
* @return the value of the spline's derivative at the specified point * @return the value of the spline's derivative at the specified point
*/ */
static double evaluateSplineDerivative(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& deriv, double t); static double evaluateSplineDerivative(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& deriv, double t);
/**
* Fit a cubic spline surface f(x,y) to a 2D set of data points. The resulting spline interpolates all the
* data points and has a continuous second derivative everywhere. The second derivatives are identical at
* the boundary if periodic=true or 0 at the boundary if periodic=false.
*
* @param x the values of the first independent variable at the data points to interpolate. They must
* be strictly increasing: x[i] > x[i-1].
* @param y the values of the second independent variable at the data points to interpolate. They must
* be strictly increasing: y[i] > y[i-1].
* @param values the values of the dependent variable at the data points to interpolate. They must be ordered
* so that values[i+xsize*j] = f(x[i],y[j]), where xsize is the length of x.
* @param periodic whether the interpolated function is periodic
* @param c on exit, this contains the spline coefficients at each of the data points
*/
static void create2DSpline(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& values, bool periodic, std::vector<std::vector<double> >& c);
/** /**
* Fit a natural cubic spline surface f(x,y) to a 2D set of data points. The resulting spline interpolates all the * Fit a natural cubic spline surface f(x,y) to a 2D set of data points. The resulting spline interpolates all the
* data points, has a continuous second derivative everywhere, and has a second derivative of 0 at the boundary. * data points, has a continuous second derivative everywhere, and has a second derivative of 0 at the boundary.
...@@ -124,6 +151,24 @@ public: ...@@ -124,6 +151,24 @@ public:
* @param dy on exit, the y derivative of the spline at the specified point * @param dy on exit, the y derivative of the spline at the specified point
*/ */
static void evaluate2DSplineDerivatives(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& values, const std::vector<std::vector<double> >& c, double u, double v, double& dx, double& dy); static void evaluate2DSplineDerivatives(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& values, const std::vector<std::vector<double> >& c, double u, double v, double& dx, double& dy);
/**
* Fit a cubic spline surface f(x,y,z) to a 3D set of data points. The resulting spline interpolates all the
* data points and has a continuous second derivative everywhere. The second derivatives are identical at
* the boundary if periodic=true or 0 at the boundary if periodic=false.
*
* @param x the values of the first independent variable at the data points to interpolate. They must
* be strictly increasing: x[i] > x[i-1].
* @param y the values of the second independent variable at the data points to interpolate. They must
* be strictly increasing: y[i] > y[i-1].
* @param z the values of the third independent variable at the data points to interpolate. They must
* be strictly increasing: z[i] > z[i-1].
* @param values the values of the dependent variable at the data points to interpolate. They must be ordered
* so that values[i+xsize*j+xsize*ysize*k] = f(x[i],y[j],z[k]), where xsize is the length of x
* and ysize is the length of y.
* @param periodic whether the interpolated function is periodic
* @param c on exit, this contains the spline coefficients at each of the data points
*/
static void create3DSpline(const std::vector<double>& x, const std::vector<double>& y, const std::vector<double>& z, const std::vector<double>& values, bool periodic, std::vector<std::vector<double> >& c);
/** /**
* Fit a natural cubic spline surface f(x,y,z) to a 3D set of data points. The resulting spline interpolates all the * Fit a natural cubic spline surface f(x,y,z) to a 3D set of data points. The resulting spline interpolates all the
* data points, has a continuous second derivative everywhere, and has a second derivative of 0 at the boundary. * data points, has a continuous second derivative everywhere, and has a second derivative of 0 at the boundary.
......
...@@ -37,6 +37,13 @@ ...@@ -37,6 +37,13 @@
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
void SplineFitter::createSpline(const vector<double>& x, const vector<double>& y, bool periodic, vector<double>& deriv) {
if (periodic)
SplineFitter::createPeriodicSpline(x, y, deriv);
else
SplineFitter::createNaturalSpline(x, y, deriv);
}
void SplineFitter::createNaturalSpline(const vector<double>& x, const vector<double>& y, vector<double>& deriv) { void SplineFitter::createNaturalSpline(const vector<double>& x, const vector<double>& y, vector<double>& deriv) {
int n = x.size(); int n = x.size();
if (y.size() != n) if (y.size() != n)
...@@ -183,16 +190,16 @@ void SplineFitter::solveTridiagonalMatrix(const vector<double>& a, const vector< ...@@ -183,16 +190,16 @@ void SplineFitter::solveTridiagonalMatrix(const vector<double>& a, const vector<
sol[i] = (rhs[i]-a[i]*sol[i-1])/beta; sol[i] = (rhs[i]-a[i]*sol[i-1])/beta;
} }
// Perform backsubstitation. // Perform backsubstitution.
for (int i = n-2; i >= 0; i--) for (int i = n-2; i >= 0; i--)
sol[i] -= gamma[i+1]*sol[i+1]; sol[i] -= gamma[i+1]*sol[i+1];
} }
void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<double>& y, const vector<double>& values, vector<vector<double> >& c) { void SplineFitter::create2DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& values, bool periodic, vector<vector<double> >& c) {
int xsize = x.size(), ysize = y.size(); int xsize = x.size(), ysize = y.size();
if (xsize < 2 || ysize < 2) // if (xsize < 2 || ysize < 2)
throw OpenMMException("create2DNaturalSpline: must have at least two points along each axis"); // throw OpenMMException("create2DNaturalSpline: must have at least two points along each axis");
if (values.size() != xsize*ysize) if (values.size() != xsize*ysize)
throw OpenMMException("create2DNaturalSpline: incorrect number of values"); throw OpenMMException("create2DNaturalSpline: incorrect number of values");
vector<double> d1(xsize*ysize), d2(xsize*ysize), d12(xsize*ysize); vector<double> d1(xsize*ysize), d2(xsize*ysize), d12(xsize*ysize);
...@@ -203,7 +210,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d ...@@ -203,7 +210,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d
for (int i = 0; i < ysize; i++) { for (int i = 0; i < ysize; i++) {
for (int j = 0; j < xsize; j++) for (int j = 0; j < xsize; j++)
t[j] = values[j+xsize*i]; t[j] = values[j+xsize*i];
SplineFitter::createNaturalSpline(x, t, deriv); SplineFitter::createSpline(x, t, periodic, deriv);
for (int j = 0; j < xsize; j++) for (int j = 0; j < xsize; j++)
d1[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]); d1[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]);
} }
...@@ -215,7 +222,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d ...@@ -215,7 +222,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d
for (int i = 0; i < xsize; i++) { for (int i = 0; i < xsize; i++) {
for (int j = 0; j < ysize; j++) for (int j = 0; j < ysize; j++)
t[j] = values[i+xsize*j]; t[j] = values[i+xsize*j];
SplineFitter::createNaturalSpline(y, t, deriv); SplineFitter::createSpline(y, t, periodic, deriv);
for (int j = 0; j < ysize; j++) for (int j = 0; j < ysize; j++)
d2[i+xsize*j] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[j]); d2[i+xsize*j] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[j]);
} }
...@@ -227,7 +234,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d ...@@ -227,7 +234,7 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d
for (int i = 0; i < ysize; i++) { for (int i = 0; i < ysize; i++) {
for (int j = 0; j < xsize; j++) for (int j = 0; j < xsize; j++)
t[j] = d2[j+xsize*i]; t[j] = d2[j+xsize*i];
SplineFitter::createNaturalSpline(x, t, deriv); SplineFitter::createSpline(x, t, periodic, deriv);
for (int j = 0; j < xsize; j++) for (int j = 0; j < xsize; j++)
d12[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]); d12[j+xsize*i] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[j]);
} }
...@@ -285,6 +292,10 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d ...@@ -285,6 +292,10 @@ void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<d
} }
} }
void SplineFitter::create2DNaturalSpline(const vector<double>& x, const vector<double>& y, const vector<double>& values, vector<vector<double> >& c) {
SplineFitter::create2DSpline(x, y, values, false, c);
}
double SplineFitter::evaluate2DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& values, const vector<vector<double> >& c, double u, double v) { double SplineFitter::evaluate2DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& values, const vector<vector<double> >& c, double u, double v) {
int xsize = x.size(); int xsize = x.size();
int ysize = y.size(); int ysize = y.size();
...@@ -369,11 +380,11 @@ void SplineFitter::evaluate2DSplineDerivatives(const vector<double>& x, const ve ...@@ -369,11 +380,11 @@ void SplineFitter::evaluate2DSplineDerivatives(const vector<double>& x, const ve
dy /= deltay; dy /= deltay;
} }
void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<double>& y, const vector<double>& z, const vector<double>& values, vector<vector<double> >& c) { void SplineFitter::create3DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& z, const vector<double>& values, bool periodic, vector<vector<double> >& c) {
int xsize = x.size(), ysize = y.size(), zsize = z.size(); int xsize = x.size(), ysize = y.size(), zsize = z.size();
int xysize = xsize*ysize; int xysize = xsize*ysize;
if (xsize < 2 || ysize < 2 || zsize < 2) // if (xsize < 2 || ysize < 2 || zsize < 2)
throw OpenMMException("create2DNaturalSpline: must have at least two points along each axis"); // throw OpenMMException("create2DNaturalSpline: must have at least two points along each axis");
if (values.size() != xsize*ysize*zsize) if (values.size() != xsize*ysize*zsize)
throw OpenMMException("create2DNaturalSpline: incorrect number of values"); throw OpenMMException("create2DNaturalSpline: incorrect number of values");
vector<double> d1(xsize*ysize*zsize), d2(xsize*ysize*zsize), d3(xsize*ysize*zsize); vector<double> d1(xsize*ysize*zsize), d2(xsize*ysize*zsize), d3(xsize*ysize*zsize);
...@@ -386,7 +397,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -386,7 +397,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < zsize; j++) { for (int j = 0; j < zsize; j++) {
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
t[k] = values[k+xsize*i+xysize*j]; t[k] = values[k+xsize*i+xysize*j];
SplineFitter::createNaturalSpline(x, t, deriv); SplineFitter::createSpline(x, t, periodic, deriv);
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
d1[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]); d1[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]);
} }
...@@ -400,7 +411,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -400,7 +411,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < zsize; j++) { for (int j = 0; j < zsize; j++) {
for (int k = 0; k < ysize; k++) for (int k = 0; k < ysize; k++)
t[k] = values[i+xsize*k+xysize*j]; t[k] = values[i+xsize*k+xysize*j];
SplineFitter::createNaturalSpline(y, t, deriv); SplineFitter::createSpline(y, t, periodic, deriv);
for (int k = 0; k < ysize; k++) for (int k = 0; k < ysize; k++)
d2[i+xsize*k+xysize*j] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[k]); d2[i+xsize*k+xysize*j] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[k]);
} }
...@@ -414,7 +425,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -414,7 +425,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < ysize; j++) { for (int j = 0; j < ysize; j++) {
for (int k = 0; k < zsize; k++) for (int k = 0; k < zsize; k++)
t[k] = values[i+xsize*j+xysize*k]; t[k] = values[i+xsize*j+xysize*k];
SplineFitter::createNaturalSpline(z, t, deriv); SplineFitter::createSpline(z, t, periodic, deriv);
for (int k = 0; k < zsize; k++) for (int k = 0; k < zsize; k++)
d3[i+xsize*j+xysize*k] = SplineFitter::evaluateSplineDerivative(z, t, deriv, z[k]); d3[i+xsize*j+xysize*k] = SplineFitter::evaluateSplineDerivative(z, t, deriv, z[k]);
} }
...@@ -428,7 +439,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -428,7 +439,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < zsize; j++) { for (int j = 0; j < zsize; j++) {
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
t[k] = d2[k+xsize*i+xysize*j]; t[k] = d2[k+xsize*i+xysize*j];
SplineFitter::createNaturalSpline(x, t, deriv); SplineFitter::createSpline(x, t, periodic, deriv);
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
d12[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]); d12[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]);
} }
...@@ -442,7 +453,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -442,7 +453,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < xsize; j++) { for (int j = 0; j < xsize; j++) {
for (int k = 0; k < ysize; k++) for (int k = 0; k < ysize; k++)
t[k] = d3[j+xsize*k+xysize*i]; t[k] = d3[j+xsize*k+xysize*i];
SplineFitter::createNaturalSpline(y, t, deriv); SplineFitter::createSpline(y, t, periodic, deriv);
for (int k = 0; k < ysize; k++) for (int k = 0; k < ysize; k++)
d23[j+xsize*k+xysize*i] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[k]); d23[j+xsize*k+xysize*i] = SplineFitter::evaluateSplineDerivative(y, t, deriv, y[k]);
} }
...@@ -456,7 +467,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -456,7 +467,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < ysize; j++) { for (int j = 0; j < ysize; j++) {
for (int k = 0; k < zsize; k++) for (int k = 0; k < zsize; k++)
t[k] = d1[i+xsize*j+xysize*k]; t[k] = d1[i+xsize*j+xysize*k];
SplineFitter::createNaturalSpline(z, t, deriv); SplineFitter::createSpline(z, t, periodic, deriv);
for (int k = 0; k < zsize; k++) for (int k = 0; k < zsize; k++)
d13[i+xsize*j+xysize*k] = SplineFitter::evaluateSplineDerivative(z, t, deriv, z[k]); d13[i+xsize*j+xysize*k] = SplineFitter::evaluateSplineDerivative(z, t, deriv, z[k]);
} }
...@@ -470,7 +481,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -470,7 +481,7 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
for (int j = 0; j < zsize; j++) { for (int j = 0; j < zsize; j++) {
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
t[k] = d23[k+xsize*i+xysize*j]; t[k] = d23[k+xsize*i+xysize*j];
SplineFitter::createNaturalSpline(x, t, deriv); SplineFitter::createSpline(x, t, periodic, deriv);
for (int k = 0; k < xsize; k++) for (int k = 0; k < xsize; k++)
d123[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]); d123[k+xsize*i+xysize*j] = SplineFitter::evaluateSplineDerivative(x, t, deriv, x[k]);
} }
...@@ -599,6 +610,10 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d ...@@ -599,6 +610,10 @@ void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<d
} }
} }
void SplineFitter::create3DNaturalSpline(const vector<double>& x, const vector<double>& y, const vector<double>& z, const vector<double>& values, vector<vector<double> >& c) {
SplineFitter::create3DSpline(x, y, z, values, false, c);
}
double SplineFitter::evaluate3DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& z, const vector<double>& values, const vector<vector<double> >& c, double u, double v, double w) { double SplineFitter::evaluate3DSpline(const vector<double>& x, const vector<double>& y, const vector<double>& z, const vector<double>& values, const vector<vector<double> >& c, double u, double v, double w) {
int xsize = x.size(); int xsize = x.size();
int ysize = y.size(); int ysize = y.size();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment