ReferenceTabulatedFunction.cpp 13.6 KB
Newer Older
peastman's avatar
peastman committed
1
2
3
4
5
6
7
8
/* -------------------------------------------------------------------------- *
 *                                   OpenMM                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the OpenMM molecular simulation toolkit originating from   *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
9
 * Portions copyright (c) 2014-2019 Stanford University and the Authors.      *
peastman's avatar
peastman committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

#include "ReferenceTabulatedFunction.h"
#include "openmm/OpenMMException.h"
#include "openmm/internal/SplineFitter.h"

smikes's avatar
smikes committed
36
#ifdef _MSC_VER
37
38

#if _MSC_VER < 1800
peastman's avatar
peastman committed
39
40
41
42
43
44
/**
 * We need to define this ourselves, since Visual Studio is missing round() from cmath.
 */
static int round(double x) {
    return (int) (x+0.5);
}
45
46
47
48
49
#else
#include <cmath>
#endif  // MSC_VER < 1800


50
51
52
53
#else
#include <cmath>
#endif

54
55
56
57
58
59
static double wrap(double t, double min, double max) {
    double L = max - min;
    double s = (t - min)/L;
    return min + L*(s - floor(s));
}

60
61
62
using namespace OpenMM;
using namespace std;
using Lepton::CustomFunction;
peastman's avatar
peastman committed
63

64
extern "C" OPENMM_EXPORT CustomFunction* createReferenceTabulatedFunction(const TabulatedFunction& function) {
65
    CustomFunction* fn;
peastman's avatar
peastman committed
66
    if (dynamic_cast<const Continuous1DFunction*>(&function) != NULL)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
        fn = new ReferenceContinuous1DFunction(dynamic_cast<const Continuous1DFunction&>(function));
    else if (dynamic_cast<const Continuous2DFunction*>(&function) != NULL)
        fn = new ReferenceContinuous2DFunction(dynamic_cast<const Continuous2DFunction&>(function));
    else if (dynamic_cast<const Continuous3DFunction*>(&function) != NULL)
        fn = new ReferenceContinuous3DFunction(dynamic_cast<const Continuous3DFunction&>(function));
    else if (dynamic_cast<const Discrete1DFunction*>(&function) != NULL)
        fn = new ReferenceDiscrete1DFunction(dynamic_cast<const Discrete1DFunction&>(function));
    else if (dynamic_cast<const Discrete2DFunction*>(&function) != NULL)
        fn = new ReferenceDiscrete2DFunction(dynamic_cast<const Discrete2DFunction&>(function));
    else if (dynamic_cast<const Discrete3DFunction*>(&function) != NULL)
        fn = new ReferenceDiscrete3DFunction(dynamic_cast<const Discrete3DFunction&>(function));
    else
        throw OpenMMException("createReferenceTabulatedFunction: Unknown function type");
    return new SharedFunctionWrapper(shared_ptr<const CustomFunction>(fn));
peastman's avatar
peastman committed
81
82
83
}

ReferenceContinuous1DFunction::ReferenceContinuous1DFunction(const Continuous1DFunction& function) : function(function) {
84
    periodic = function.getPeriodic();
85
    function.getFunctionParameters(values, min, max);
peastman's avatar
peastman committed
86
87
88
89
    int numValues = values.size();
    x.resize(numValues);
    for (int i = 0; i < numValues; i++)
        x[i] = min+i*(max-min)/(numValues-1);
90
    SplineFitter::createSpline(x, values, periodic, derivs);
peastman's avatar
peastman committed
91
92
}

93
ReferenceContinuous1DFunction::ReferenceContinuous1DFunction(const ReferenceContinuous1DFunction& other) : function(other.function) {
94
    periodic = function.getPeriodic();
95
    function.getFunctionParameters(values, min, max);
96
97
98
99
100
    x = other.x;
    values = other.values;
    derivs = other.derivs;
}

peastman's avatar
peastman committed
101
102
103
104
105
int ReferenceContinuous1DFunction::getNumArguments() const {
    return 1;
}

double ReferenceContinuous1DFunction::evaluate(const double* arguments) const {
106
107
108
    double t = periodic ? wrap(arguments[0], min, max) : arguments[0];
    if (t < min || t > max)
        return 0.0;
peastman's avatar
peastman committed
109
110
111
112
    return SplineFitter::evaluateSpline(x, values, derivs, t);
}

double ReferenceContinuous1DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
113
114
115
    double t = periodic ? wrap(arguments[0], min, max) : arguments[0];
    if (t < min || t > max)
        return 0.0;
peastman's avatar
peastman committed
116
117
118
119
    return SplineFitter::evaluateSplineDerivative(x, values, derivs, t);
}

CustomFunction* ReferenceContinuous1DFunction::clone() const {
120
    return new ReferenceContinuous1DFunction(*this);
peastman's avatar
peastman committed
121
122
123
}

ReferenceContinuous2DFunction::ReferenceContinuous2DFunction(const Continuous2DFunction& function) : function(function) {
124
    periodic = function.getPeriodic();
peastman's avatar
peastman committed
125
126
127
128
129
130
131
    function.getFunctionParameters(xsize, ysize, values, xmin, xmax, ymin, ymax);
    x.resize(xsize);
    y.resize(ysize);
    for (int i = 0; i < xsize; i++)
        x[i] = xmin+i*(xmax-xmin)/(xsize-1);
    for (int i = 0; i < ysize; i++)
        y[i] = ymin+i*(ymax-ymin)/(ysize-1);
132
    SplineFitter::create2DSpline(x, y, values, periodic, c);
peastman's avatar
peastman committed
133
134
}

135
ReferenceContinuous2DFunction::ReferenceContinuous2DFunction(const ReferenceContinuous2DFunction& other) : function(other.function) {
136
    periodic = function.getPeriodic();
137
138
139
140
141
142
143
    function.getFunctionParameters(xsize, ysize, values, xmin, xmax, ymin, ymax);
    x = other.x;
    y = other.y;
    values = other.values;
    c = other.c;
}

peastman's avatar
peastman committed
144
145
146
147
148
int ReferenceContinuous2DFunction::getNumArguments() const {
    return 2;
}

double ReferenceContinuous2DFunction::evaluate(const double* arguments) const {
149
    double u = periodic ? wrap(arguments[0], xmin, xmax) : arguments[0];
peastman's avatar
peastman committed
150
151
    if (u < xmin || u > xmax)
        return 0.0;
152
    double v = periodic ? wrap(arguments[1], ymin, ymax) : arguments[1];
peastman's avatar
peastman committed
153
154
155
156
157
158
    if (v < ymin || v > ymax)
        return 0.0;
    return SplineFitter::evaluate2DSpline(x, y, values, c, u, v);
}

double ReferenceContinuous2DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
159
    double u = periodic ? wrap(arguments[0], xmin, xmax) : arguments[0];
peastman's avatar
peastman committed
160
161
    if (u < xmin || u > xmax)
        return 0.0;
162
    double v = periodic ? wrap(arguments[1], ymin, ymax) : arguments[1];
peastman's avatar
peastman committed
163
164
165
166
167
168
169
170
171
172
173
174
    if (v < ymin || v > ymax)
        return 0.0;
    double dx, dy;
    SplineFitter::evaluate2DSplineDerivatives(x, y, values, c, u, v, dx, dy);
    if (derivOrder[0] == 1 && derivOrder[1] == 0)
        return dx;
    if (derivOrder[0] == 0 && derivOrder[1] == 1)
        return dy;
    throw OpenMMException("ReferenceContinuous2DFunction: Unsupported derivative order");
}

CustomFunction* ReferenceContinuous2DFunction::clone() const {
175
    return new ReferenceContinuous2DFunction(*this);
peastman's avatar
peastman committed
176
177
178
}

ReferenceContinuous3DFunction::ReferenceContinuous3DFunction(const Continuous3DFunction& function) : function(function) {
179
    periodic = function.getPeriodic();
peastman's avatar
peastman committed
180
181
182
183
184
185
186
187
188
189
    function.getFunctionParameters(xsize, ysize, zsize, values, xmin, xmax, ymin, ymax, zmin, zmax);
    x.resize(xsize);
    y.resize(ysize);
    z.resize(zsize);
    for (int i = 0; i < xsize; i++)
        x[i] = xmin+i*(xmax-xmin)/(xsize-1);
    for (int i = 0; i < ysize; i++)
        y[i] = ymin+i*(ymax-ymin)/(ysize-1);
    for (int i = 0; i < zsize; i++)
        z[i] = zmin+i*(zmax-zmin)/(zsize-1);
190
    SplineFitter::create3DSpline(x, y, z, values, periodic, c);
peastman's avatar
peastman committed
191
192
}

193
ReferenceContinuous3DFunction::ReferenceContinuous3DFunction(const ReferenceContinuous3DFunction& other) : function(other.function) {
194
    periodic = function.getPeriodic();
195
196
197
198
199
200
201
202
    function.getFunctionParameters(xsize, ysize, zsize, values, xmin, xmax, ymin, ymax, zmin, zmax);
    x = other.x;
    y = other.y;
    z = other.z;
    values = other.values;
    c = other.c;
}

peastman's avatar
peastman committed
203
204
205
206
207
int ReferenceContinuous3DFunction::getNumArguments() const {
    return 3;
}

double ReferenceContinuous3DFunction::evaluate(const double* arguments) const {
208
    double u = periodic ? wrap(arguments[0], xmin, xmax) : arguments[0];
peastman's avatar
peastman committed
209
210
    if (u < xmin || u > xmax)
        return 0.0;
211
    double v = periodic ? wrap(arguments[1], ymin, ymax) : arguments[1];
peastman's avatar
peastman committed
212
213
    if (v < ymin || v > ymax)
        return 0.0;
214
    double w = periodic ? wrap(arguments[2], zmin, zmax) : arguments[2];
peastman's avatar
peastman committed
215
216
217
218
219
220
    if (w < zmin || w > zmax)
        return 0.0;
    return SplineFitter::evaluate3DSpline(x, y, z, values, c, u, v, w);
}

double ReferenceContinuous3DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
221
    double u = periodic ? wrap(arguments[0], xmin, xmax) : arguments[0];
peastman's avatar
peastman committed
222
223
    if (u < xmin || u > xmax)
        return 0.0;
224
    double v = periodic ? wrap(arguments[1], ymin, ymax) : arguments[1];
peastman's avatar
peastman committed
225
226
    if (v < ymin || v > ymax)
        return 0.0;
227
    double w = periodic ? wrap(arguments[2], zmin, zmax) : arguments[2];
peastman's avatar
peastman committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    if (w < zmin || w > zmax)
        return 0.0;
    double dx, dy, dz;
    SplineFitter::evaluate3DSplineDerivatives(x, y, z, values, c, u, v, w, dx, dy, dz);
    if (derivOrder[0] == 1 && derivOrder[1] == 0 && derivOrder[2] == 0)
        return dx;
    if (derivOrder[0] == 0 && derivOrder[1] == 1 && derivOrder[2] == 0)
        return dy;
    if (derivOrder[0] == 0 && derivOrder[1] == 0 && derivOrder[2] == 1)
        return dz;
    throw OpenMMException("ReferenceContinuous3DFunction: Unsupported derivative order");
}

CustomFunction* ReferenceContinuous3DFunction::clone() const {
242
    return new ReferenceContinuous3DFunction(*this);
peastman's avatar
peastman committed
243
244
245
246
247
248
249
250
251
252
253
}

ReferenceDiscrete1DFunction::ReferenceDiscrete1DFunction(const Discrete1DFunction& function) : function(function) {
    function.getFunctionParameters(values);
}

int ReferenceDiscrete1DFunction::getNumArguments() const {
    return 1;
}

double ReferenceDiscrete1DFunction::evaluate(const double* arguments) const {
254
    int i = (int) round(arguments[0]);
255
    i = max(0, min((int) values.size()-1, i));
peastman's avatar
peastman committed
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    return values[i];
}

double ReferenceDiscrete1DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
    return 0.0;
}

CustomFunction* ReferenceDiscrete1DFunction::clone() const {
    return new ReferenceDiscrete1DFunction(function);
}

ReferenceDiscrete2DFunction::ReferenceDiscrete2DFunction(const Discrete2DFunction& function) : function(function) {
    function.getFunctionParameters(xsize, ysize, values);
}

int ReferenceDiscrete2DFunction::getNumArguments() const {
    return 2;
}

double ReferenceDiscrete2DFunction::evaluate(const double* arguments) const {
276
277
    int i = (int) round(arguments[0]);
    int j = (int) round(arguments[1]);
278
279
    i = max(0, min(xsize-1, i));
    j = max(0, min(ysize-1, j));
peastman's avatar
peastman committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
    return values[i+j*xsize];
}

double ReferenceDiscrete2DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
    return 0.0;
}

CustomFunction* ReferenceDiscrete2DFunction::clone() const {
    return new ReferenceDiscrete2DFunction(function);
}

ReferenceDiscrete3DFunction::ReferenceDiscrete3DFunction(const Discrete3DFunction& function) : function(function) {
    function.getFunctionParameters(xsize, ysize, zsize, values);
}

int ReferenceDiscrete3DFunction::getNumArguments() const {
    return 3;
}

double ReferenceDiscrete3DFunction::evaluate(const double* arguments) const {
300
301
302
    int i = (int) round(arguments[0]);
    int j = (int) round(arguments[1]);
    int k = (int) round(arguments[2]);
303
304
305
    i = max(0, min(xsize-1, i));
    j = max(0, min(ysize-1, j));
    k = max(0, min(zsize-1, k));
peastman's avatar
peastman committed
306
307
308
309
310
311
312
313
314
315
    return values[i+(j+k*ysize)*xsize];
}

double ReferenceDiscrete3DFunction::evaluateDerivative(const double* arguments, const int* derivOrder) const {
    return 0.0;
}

CustomFunction* ReferenceDiscrete3DFunction::clone() const {
    return new ReferenceDiscrete3DFunction(function);
}
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

SharedFunctionWrapper::SharedFunctionWrapper(shared_ptr<const CustomFunction> pointer) : pointer(pointer) {
}

int SharedFunctionWrapper::getNumArguments() const {
    return pointer->getNumArguments();
}

double SharedFunctionWrapper::evaluate(const double* arguments) const {
    return pointer->evaluate(arguments);
}

double SharedFunctionWrapper::evaluateDerivative(const double* arguments, const int* derivOrder) const {
    return pointer->evaluateDerivative(arguments, derivOrder);
}

CustomFunction* SharedFunctionWrapper::clone() const {
    return new SharedFunctionWrapper(pointer);
}