SimTKOpenMMUtilities.cpp 5.78 KB
Newer Older
1

2
/* Portions copyright (c) 2006-2009 Stanford University and Simbios.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * Contributors: Pande Group
 *
 * 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.
 */

// class of shared, static utility methods

27
#include "openmm/internal/OSRngSeed.h"
28
#include "SimTKOpenMMUtilities.h"
29
#include "sfmt/SFMT.h"
30
31
32

// fabs(), ...

33
34
#include <cmath>
#include <cstdio>
35
#include <string.h>
Peter Eastman's avatar
Peter Eastman committed
36
#include <iostream>
37

38
39
using namespace OpenMM;

40
41
uint32_t SimTKOpenMMUtilities::_randomNumberSeed = 0;
bool SimTKOpenMMUtilities::_randomInitialized = false;
42
bool SimTKOpenMMUtilities::nextGaussianIsValid = false;
peastman's avatar
peastman committed
43
double SimTKOpenMMUtilities::nextGaussian = 0;
44
OpenMM_SFMT::SFMT SimTKOpenMMUtilities::sfmt;
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
/* ---------------------------------------------------------------------------------------

   Compute cross product of two 3-vectors and place in 3rd vector  -- helper method

   vectorZ = vectorX x vectorY

   @param vectorX             x-vector
   @param vectorY             y-vector
   @param vectorZ             z-vector

   @return vector is vectorZ

   --------------------------------------------------------------------------------------- */
     
peastman's avatar
peastman committed
60
61
62
void SimTKOpenMMUtilities::crossProductVector3(double* vectorX,
                                               double* vectorY,
                                               double* vectorZ) {
63
64
65
66
67
68
69
   vectorZ[0]  = vectorX[1]*vectorY[2] - vectorX[2]*vectorY[1];
   vectorZ[1]  = vectorX[2]*vectorY[0] - vectorX[0]*vectorY[2];
   vectorZ[2]  = vectorX[0]*vectorY[1] - vectorX[1]*vectorY[0];

   return;
}

70
71
72
73
74
75
76
77
/**---------------------------------------------------------------------------------------

   Get normally distributed random number

   @return random value

   --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
78
double SimTKOpenMMUtilities::getNormallyDistributedRandomNumber() {
79
80
81
    if (nextGaussianIsValid) {
        nextGaussianIsValid = false;
        return nextGaussian;
82
83
    }
    if (!_randomInitialized) {
84
        init_gen_rand(_randomNumberSeed, sfmt);
85
        _randomInitialized = true;
86
        nextGaussianIsValid = false;
87
88
89
90
    }
    
    // Use the polar form of the Box-Muller transformation to generate two Gaussian random numbers.
    
peastman's avatar
peastman committed
91
    double x, y, r2;
92
    do {
peastman's avatar
peastman committed
93
94
        x = 2.0 * genrand_real2(sfmt) - 1.0;
        y = 2.0 * genrand_real2(sfmt) - 1.0;
95
96
        r2 = x*x + y*y;
    } while (r2 >= 1.0 || r2 == 0.0);
peastman's avatar
peastman committed
97
    double multiplier = sqrt((-2.0*log(r2))/r2);
98
99
    nextGaussian = y*multiplier;
    nextGaussianIsValid = true;
100
101
102
103
104
105
106
107
108
109
110
    return x*multiplier;
}

/**---------------------------------------------------------------------------------------

   Get uniformly distributed random number in the range [0, 1)

   @return random value

   --------------------------------------------------------------------------------------- */

peastman's avatar
peastman committed
111
double SimTKOpenMMUtilities::getUniformlyDistributedRandomNumber() {
112
    if (!_randomInitialized) {
113
        init_gen_rand(_randomNumberSeed, sfmt);
114
        _randomInitialized = true;
115
        nextGaussianIsValid = false;
116
    }
peastman's avatar
peastman committed
117
    double value = genrand_real2(sfmt);
118
    return value;
119
120
121
122
123
124
125
126
127
128
}

/**---------------------------------------------------------------------------------------

   Get random number seed

   @return random number seed

   --------------------------------------------------------------------------------------- */

129
uint32_t SimTKOpenMMUtilities::getRandomNumberSeed() {
130
131
132
133
134
135
136
137
138
139
140
   return _randomNumberSeed;
}

/**---------------------------------------------------------------------------------------

   Set random number seed

   @param seed    new seed value

   --------------------------------------------------------------------------------------- */

141
void SimTKOpenMMUtilities::setRandomNumberSeed(uint32_t seed) {
142
    // If the seed is 0, use a unique seed
143
144
145
146
    if (seed == 0)
        _randomNumberSeed = (uint32_t) osrngseed();
    else
        _randomNumberSeed = seed;
147
   _randomInitialized = false;
Peter Eastman's avatar
Peter Eastman committed
148
   nextGaussianIsValid = false;
149
}
Peter Eastman's avatar
Peter Eastman committed
150
151
152
153
154
155

void SimTKOpenMMUtilities::createCheckpoint(std::ostream& stream) {
    stream.write((char*) &_randomNumberSeed, sizeof(uint32_t));
    stream.write((char*) &_randomInitialized, sizeof(bool));
    if (_randomInitialized) {
        stream.write((char*) &nextGaussianIsValid, sizeof(bool));
peastman's avatar
peastman committed
156
        stream.write((char*) &nextGaussian, sizeof(double));
Peter Eastman's avatar
Peter Eastman committed
157
158
159
160
161
162
        sfmt.createCheckpoint(stream);
    }
}

void SimTKOpenMMUtilities::loadCheckpoint(std::istream& stream) {
    stream.read((char*) &_randomNumberSeed, sizeof(uint32_t));
163
    bool prevInitialized = _randomInitialized;
Peter Eastman's avatar
Peter Eastman committed
164
165
    stream.read((char*) &_randomInitialized, sizeof(bool));
    if (_randomInitialized) {
166
167
        if (!prevInitialized)
            init_gen_rand(0, sfmt);
Peter Eastman's avatar
Peter Eastman committed
168
        stream.read((char*) &nextGaussianIsValid, sizeof(bool));
peastman's avatar
peastman committed
169
        stream.read((char*) &nextGaussian, sizeof(double));
Peter Eastman's avatar
Peter Eastman committed
170
171
172
        sfmt.loadCheckpoint(stream);
    }
}