ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/math/CubicSpline.cpp
Revision: 1618
Committed: Mon Sep 12 17:09:26 2011 UTC (13 years, 7 months ago) by gezelter
Original Path: branches/development/src/math/CubicSpline.cpp
File size: 8765 byte(s)
Log Message:
Build fixes for qhull 2011, fixes for compilation with PGI.


File Contents

# User Rev Content
1 gezelter 1475 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9     * 1. Redistributions of source code must retain the above copyright
10     * notice, this list of conditions and the following disclaimer.
11     *
12     * 2. Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31     *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38     * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39     * [4] Vardeman & Gezelter, in progress (2009).
40     */
41    
42     #include "math/CubicSpline.hpp"
43     #include "utils/simError.h"
44     #include <cmath>
45 gezelter 1618 #include <cstdio>
46 gezelter 1475 #include <algorithm>
47    
48     using namespace OpenMD;
49     using namespace std;
50    
51 gezelter 1536 CubicSpline::CubicSpline() : generated(false), isUniform(true) {
52     data_.clear();
53     }
54 gezelter 1475
55 gezelter 1536 void CubicSpline::addPoint(const RealType xp, const RealType yp) {
56     data_.push_back(make_pair(xp, yp));
57 gezelter 1475 }
58    
59     void CubicSpline::addPoints(const vector<RealType>& xps,
60     const vector<RealType>& yps) {
61    
62     if (xps.size() != yps.size()) {
63     printf( painCave.errMsg,
64     "CubicSpline::addPoints was passed vectors of different length!\n");
65     painCave.severity = OPENMD_ERROR;
66     painCave.isFatal = 1;
67     simError();
68     }
69    
70     for (int i = 0; i < xps.size(); i++)
71 gezelter 1536 data_.push_back(make_pair(xps[i], yps[i]));
72 gezelter 1475 }
73    
74     void CubicSpline::generate() {
75     // Calculate coefficients defining a smooth cubic interpolatory spline.
76     //
77     // class values constructed:
78 gezelter 1536 // n = number of data_ points.
79 gezelter 1475 // x = vector of independent variable values
80     // y = vector of dependent variable values
81     // b = vector of S'(x[i]) values.
82     // c = vector of S"(x[i])/2 values.
83     // d = vector of S'''(x[i]+)/6 values (i < n).
84     // Local variables:
85 gezelter 1536
86 gezelter 1475 RealType fp1, fpn, h, p;
87    
88     // make sure the sizes match
89    
90 gezelter 1536 n = data_.size();
91 gezelter 1475 b.resize(n);
92     c.resize(n);
93     d.resize(n);
94    
95     // make sure we are monotonically increasing in x:
96    
97     bool sorted = true;
98    
99     for (int i = 1; i < n; i++) {
100 gezelter 1536 if ( (data_[i].first - data_[i-1].first ) <= 0.0 ) sorted = false;
101 gezelter 1475 }
102    
103     // sort if necessary
104    
105 gezelter 1536 if (!sorted) sort(data_.begin(), data_.end());
106 gezelter 1475
107     // Calculate coefficients for the tridiagonal system: store
108     // sub-diagonal in B, diagonal in D, difference quotient in C.
109    
110 gezelter 1536 b[0] = data_[1].first - data_[0].first;
111     c[0] = (data_[1].second - data_[0].second) / b[0];
112 gezelter 1475
113     if (n == 2) {
114    
115     // Assume the derivatives at both endpoints are zero. Another
116     // assumption could be made to have a linear interpolant between
117     // the two points. In that case, the b coefficients below would be
118 gezelter 1536 // (data_[1].second - data_[0].second) / (data_[1].first - data_[0].first)
119 gezelter 1475 // and the c and d coefficients would both be zero.
120     b[0] = 0.0;
121 gezelter 1536 c[0] = -3.0 * pow((data_[1].second - data_[0].second) /
122     (data_[1].first-data_[0].first), 2);
123     d[0] = -2.0 * pow((data_[1].second - data_[0].second) /
124     (data_[1].first-data_[0].first), 3);
125 gezelter 1475 b[1] = b[0];
126     c[1] = 0.0;
127     d[1] = 0.0;
128 gezelter 1536 dx = 1.0 / (data_[1].first - data_[0].first);
129 gezelter 1475 isUniform = true;
130     generated = true;
131     return;
132     }
133    
134     d[0] = 2.0 * b[0];
135    
136     for (int i = 1; i < n-1; i++) {
137 gezelter 1536 b[i] = data_[i+1].first - data_[i].first;
138 gezelter 1475 if ( fabs( b[i] - b[0] ) / b[0] > 1.0e-5) isUniform = false;
139 gezelter 1536 c[i] = (data_[i+1].second - data_[i].second) / b[i];
140 gezelter 1475 d[i] = 2.0 * (b[i] + b[i-1]);
141     }
142    
143     d[n-1] = 2.0 * b[n-2];
144    
145     // Calculate estimates for the end slopes using polynomials
146 gezelter 1536 // that interpolate the data_ nearest the end.
147 gezelter 1475
148     fp1 = c[0] - b[0]*(c[1] - c[0])/(b[0] + b[1]);
149     if (n > 3) fp1 = fp1 + b[0]*((b[0] + b[1]) * (c[2] - c[1]) /
150     (b[1] + b[2]) -
151 gezelter 1536 c[1] + c[0]) / (data_[3].first - data_[0].first);
152 gezelter 1475
153     fpn = c[n-2] + b[n-2]*(c[n-2] - c[n-3])/(b[n-3] + b[n-2]);
154    
155     if (n > 3) fpn = fpn + b[n-2] *
156     (c[n-2] - c[n-3] - (b[n-3] + b[n-2]) *
157 gezelter 1536 (c[n-3] - c[n-4])/(b[n-3] + b[n-4]))/(data_[n-1].first - data_[n-4].first);
158 gezelter 1475
159    
160     // Calculate the right hand side and store it in C.
161    
162     c[n-1] = 3.0 * (fpn - c[n-2]);
163     for (int i = n-2; i > 0; i--)
164     c[i] = 3.0 * (c[i] - c[i-1]);
165     c[0] = 3.0 * (c[0] - fp1);
166    
167     // Solve the tridiagonal system.
168    
169     for (int k = 1; k < n; k++) {
170     p = b[k-1] / d[k-1];
171     d[k] = d[k] - p*b[k-1];
172     c[k] = c[k] - p*c[k-1];
173     }
174    
175     c[n-1] = c[n-1] / d[n-1];
176    
177     for (int k = n-2; k >= 0; k--)
178     c[k] = (c[k] - b[k] * c[k+1]) / d[k];
179    
180     // Calculate the coefficients defining the spline.
181    
182     for (int i = 0; i < n-1; i++) {
183 gezelter 1536 h = data_[i+1].first - data_[i].first;
184 gezelter 1475 d[i] = (c[i+1] - c[i]) / (3.0 * h);
185 gezelter 1536 b[i] = (data_[i+1].second - data_[i].second)/h - h * (c[i] + h * d[i]);
186 gezelter 1475 }
187    
188     b[n-1] = b[n-2] + h * (2.0 * c[n-2] + h * 3.0 * d[n-2]);
189    
190 gezelter 1536 if (isUniform) dx = 1.0 / (data_[1].first - data_[0].first);
191 gezelter 1475
192     generated = true;
193     return;
194     }
195    
196     RealType CubicSpline::getValueAt(RealType t) {
197     // Evaluate the spline at t using coefficients
198     //
199     // Input parameters
200     // t = point where spline is to be evaluated.
201     // Output:
202     // value of spline at t.
203    
204     if (!generated) generate();
205     RealType dt;
206    
207 gezelter 1536 if ( t < data_[0].first || t > data_[n-1].first ) {
208 gezelter 1475 sprintf( painCave.errMsg,
209     "CubicSpline::getValueAt was passed a value outside the range of the spline!\n");
210     painCave.severity = OPENMD_ERROR;
211     painCave.isFatal = 1;
212     simError();
213     }
214    
215     // Find the interval ( x[j], x[j+1] ) that contains or is nearest
216     // to t.
217    
218     int j;
219    
220     if (isUniform) {
221    
222 gezelter 1536 j = max(0, min(n-1, int((t - data_[0].first) * dx)));
223 gezelter 1475
224     } else {
225    
226     j = n-1;
227    
228     for (int i = 0; i < n; i++) {
229 gezelter 1536 if ( t < data_[i].first ) {
230 gezelter 1475 j = i-1;
231     break;
232     }
233     }
234     }
235    
236     // Evaluate the cubic polynomial.
237    
238 gezelter 1536 dt = t - data_[j].first;
239     return data_[j].second + dt*(b[j] + dt*(c[j] + dt*d[j]));
240 gezelter 1475
241     }
242    
243    
244     pair<RealType, RealType> CubicSpline::getValueAndDerivativeAt(RealType t) {
245     // Evaluate the spline and first derivative at t using coefficients
246     //
247     // Input parameters
248     // t = point where spline is to be evaluated.
249     // Output:
250     // pair containing value of spline at t and first derivative at t
251    
252     if (!generated) generate();
253     RealType dt;
254    
255 gezelter 1536 if ( t < data_.front().first || t > data_.back().first ) {
256 gezelter 1475 sprintf( painCave.errMsg,
257     "CubicSpline::getValueAndDerivativeAt was passed a value outside the range of the spline!\n");
258     painCave.severity = OPENMD_ERROR;
259     painCave.isFatal = 1;
260     simError();
261     }
262    
263     // Find the interval ( x[j], x[j+1] ) that contains or is nearest
264     // to t.
265    
266     int j;
267    
268     if (isUniform) {
269    
270 gezelter 1536 j = max(0, min(n-1, int((t - data_[0].first) * dx)));
271 gezelter 1475
272     } else {
273    
274     j = n-1;
275    
276     for (int i = 0; i < n; i++) {
277 gezelter 1536 if ( t < data_[i].first ) {
278 gezelter 1475 j = i-1;
279     break;
280     }
281     }
282     }
283    
284     // Evaluate the cubic polynomial.
285    
286 gezelter 1536 dt = t - data_[j].first;
287 gezelter 1475
288 gezelter 1536 RealType yval = data_[j].second + dt*(b[j] + dt*(c[j] + dt*d[j]));
289 gezelter 1475 RealType dydx = b[j] + dt*(2.0 * c[j] + 3.0 * dt * d[j]);
290    
291     return make_pair(yval, dydx);
292     }

Properties

Name Value
svn:eol-style native