/* -------------------------------------------------------------------------- *
* 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. *
* *
* Portions copyright (c) 2009 Stanford University and the Authors. *
* Authors: Mark Friedrichs, Mike Houston *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see . *
* -------------------------------------------------------------------------- */
#include "BrookRandomNumberGenerator.h"
#include "../../reference/src/SimTKUtilities/SimTKOpenMMUtilities.h"
#include "openmm/OpenMMException.h"
#include "kernels/kupdatesd.h"
#include
using namespace OpenMM;
using namespace std;
/**
*
* Constructor
*
*/
BrookRandomNumberGenerator::BrookRandomNumberGenerator( ){
// ---------------------------------------------------------------------------------------
//static const std::string methodName = "BrookRandomNumberGenerator::BrookRandomNumberGenerator";
// ---------------------------------------------------------------------------------------
// fixed for now
_numberOfRandomNumberStreams = 2;
_randomNumberGeneratorStreams = NULL;
// mark stream dimension variables as unset
_randomNumberStreamWidth = -1;
_randomNumberStreamHeight = -1;
_randomNumberStreamSize = -1;
_rvStreamIndex = 0;
_rvStreamOffset = 0;
_numberOfShuffles = 0;
//_maxShuffles = 0;
_maxShuffles = 100;
_loadBuffer = NULL;
_shuffleIndices = NULL;
for( int ii = 0; ii < LastStreamIndex; ii++ ){
_auxiliaryStreams[ii] = NULL;
}
// set randomNumber seed & generator
_randomNumberSeed = 1393;
//_randomNumberGenerator = Mersenne;
_randomNumberGenerator = Kiss;
//_randomNumberGenerator = FixedValue;
//SimTKOpenMMUtilities::setRandomNumberSeed( randomNumberSeed );
}
/**
* Destructor
*
*/
BrookRandomNumberGenerator::~BrookRandomNumberGenerator( ){
// ---------------------------------------------------------------------------------------
//static const std::string methodName = "BrookRandomNumberGenerator::~BrookRandomNumberGenerator";
// ---------------------------------------------------------------------------------------
for( int ii = 0; ii < LastStreamIndex; ii++ ){
delete _auxiliaryStreams[ii];
}
delete[] _randomNumberGeneratorStreams;
delete[] _loadBuffer;
delete[] _shuffleIndices;
}
/**
* Get number of random number streams
*
* @return number of random number streams
*
*/
int BrookRandomNumberGenerator::getNumberOfRandomNumberStreams( void ) const {
return _numberOfRandomNumberStreams;
}
/**
* Get random number stream width
*
* @return nndom number stream width
*
*/
int BrookRandomNumberGenerator::getRandomNumberStreamWidth( void ) const {
return _randomNumberStreamWidth;
}
/**
* Get random number stream height
*
* @return nndom number stream height
*
*/
int BrookRandomNumberGenerator::getRandomNumberStreamHeight( void ) const {
return _randomNumberStreamHeight;
}
/**
* Get random number seed
*
* @return random number seed
*/
unsigned long int BrookRandomNumberGenerator::getRandomNumberSeed( void ) const {
return _randomNumberSeed;
}
/**
* Increment random number seed
*
* @param increment amount to increment random number seed; default = 1
*
* @return updated random number seed
*/
unsigned long int BrookRandomNumberGenerator::incrementRandomNumberSeed( unsigned long int increment ){
_randomNumberSeed += increment;
return _randomNumberSeed;
}
/**
* Set random number seed
*
* @param new random number seed; default = 1
*
* @return random number seed
*/
unsigned long int BrookRandomNumberGenerator::setRandomNumberSeed( unsigned long int seed ){
_randomNumberSeed = seed;
return _randomNumberSeed;
}
/**
* Generate a random number using algorithm in Gromacs
*
* @param ig seed
*
* @return random number
*
*/
BrookOpenMMFloat BrookRandomNumberGenerator::_generateGromacsRandomNumber( unsigned long int* ig ){
// ---------------------------------------------------------------------------------------
// static const std::string methodName = "\nBrookRandomNumberGenerator::_generateGromacsRandomNumber";
int irand;
int m = 100000000;
float rm = 100000000.0; /* same number as m, but real format */
int m1 = 10000;
int mult = 31415821;
BrookOpenMMFloat r;
int irandh,irandl,multh,multl;
// ---------------------------------------------------------------------------------------
unsigned long int igg = (*ig > 0) ? *ig : -1*(*ig);
irand = igg % m;
/* multiply irand by mult, but take into account that overflow
* must be discarded, and do not generate an error.
*/
irandh = irand / m1;
irandl = irand % m1;
multh = mult / m1;
multl = mult % m1;
irand = ((irandh*multl+irandl*multh) % m1) * m1 + irandl*multl;
irand = (irand + 1) % m;
/* convert irand to a real random number between 0 and 1. */
r = (BrookOpenMMFloat) (irand / 10);
r = r * 10 / rm;
if ((r <= 0) || (r > 1))
r = 0.0;
*ig = irand;
return r;
}
inline int MaxInt( unsigned int x, unsigned int y ){ return x > y ? x : y; }
/**
* Generate a random number using algorithm in Kiss code
* http://www.helsbreth.org/random/rng_kiss.html
*
* @param randomV1 output random value
* @param randomV2 output random value
* @param randomV3 output random value
* @param state state
*
*/
void BrookRandomNumberGenerator::_generateRandomsKiss( float* randomV1, float* randomV2, float* randomV3,
unsigned int state[4] ){
// ---------------------------------------------------------------------------------------
// static const std::string methodName = "\nBrookRandomNumberGenerator::_generateRandomsKiss";
unsigned int carry = 0;
// ---------------------------------------------------------------------------------------
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
unsigned int k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
unsigned int m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
unsigned int z1 = MaxInt(state[0] + state[1] + state[3], 0x00000001);
float x1 = (float) ( (double) z1 / (double)UINT_MAX );
/*
if( x1 < 0.0f ){
unsigned int z1 = MaxInt(state[0] + state[1] + state[3], 0x00000001);
double z2 = (double) z1/((double) UINT_MAX);
(void) fprintf( logFile, "x1=%.6e state[%u %u %u] sum %u %.6e den=%u z2=%.6e\n",
x1, state[0], state[1], state[3],
(state[0] + state[1] + state[3]), (float) (state[0] + state[1] + state[3]), z1, z2 );
}
*/
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
x1 = sqrt(-2.0f * log(x1));
k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
float x2 = (float)(state[0] + state[1] + state[3]) / (float)UINT_MAX;
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
*randomV1 = x1 * cos(2.0f * 3.14159265f * x2);
k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
unsigned int z3 = MaxInt(state[0] + state[1] + state[3], 0x00000001);
float x3 = (float) ( (double) z3 / (double)UINT_MAX );
//float x3 = (float)MaxInt(state[0] + state[1] + state[3], 0x00000001) / (float)UINT_MAX;
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
x3 = sqrt(-2.0f * log(x3));
k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
float x4 = (float)(state[0] + state[1] + state[3]) / (float)UINT_MAX;
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
*randomV2 = x3 * cos(2.0f * 3.14159265f * x4);
k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
//float x5 = (float)MaxInt(state[0] + state[1] + state[3], 0x00000001) / (float)UINT_MAX;
unsigned int z5 = MaxInt(state[0] + state[1] + state[3], 0x00000001);
float x5 = (float) ( (double) z5 / (double)UINT_MAX );
state[0] = state[0] * 69069 + 1;
state[1] ^= state[1] << 13;
state[1] ^= state[1] >> 17;
state[1] ^= state[1] << 5;
x5 = sqrt(-2.0f * log(x5));
k = (state[2] >> 2) + (state[3] >> 3) + (carry >> 2);
m = state[3] + state[3] + state[2] + carry;
state[2] = state[3];
state[3] = m;
carry = k >> 30;
float x6 = (float)(state[0] + state[1] + state[3]) / (float)UINT_MAX;
*randomV3 = x5 * cos(2.0f * 3.14159265f * x6);
//(void) fprintf( logFile, "rv=%.6e %.6e %.6e\n", *randomV1, *randomV2, *randomV3 );
//exit(0);
return;
}
/**
* Load random number streams using Kiss algorithm
*
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::_loadRandomNumberStreamsKiss( void ){
// ---------------------------------------------------------------------------------------
static unsigned int state[4];
static int stateInitialized = 0;
int printOn = 0;
FILE* log;
static const int reseed = 10000;
static std::string methodName = "\nBrookRandomNumberGenerator::_loadRandomNumberStreamsKiss";
// ---------------------------------------------------------------------------------------
if( printOn && getLog() ){
log = getLog();
} else {
printOn = 0;
}
// periodically reset seeds
if( !stateInitialized || !(stateInitialized % reseed) ){
state[0] = rand();
state[1] = rand();
state[2] = rand();
state[3] = rand();
if( printOn ){
(void) fprintf( log, "%s reset state seeds stateInitialized=%d reseed=%d [%u %u %u %u]\n",
methodName.c_str(), stateInitialized, reseed, state[0], state[1], state[2], state[3] );
(void) fflush( log );
}
}
stateInitialized++;
// allocate memory once for download of random nos.
float* loadBuffer = _getLoadBuffer();
if( printOn ){
static float count = 0.0f;
float block = (float) (3*getRandomNumberStreamSize() );
count += 1.0f;
(void) fprintf( log, "%s: count=%.1f ttl=%.3e no./count=%.1f %d %d\n", methodName.c_str(),
count, block*count, block, getRandomNumberStreamSize(), getNumberOfRandomNumberStreams() );
(void) fflush( log );
}
for( int jj = 0; jj < getNumberOfRandomNumberStreams(); jj++ ){
for( int ii = 0; ii < 3*getRandomNumberStreamSize(); ii += 3 ){
float v1,v2,v3;
_generateRandomsKiss( &v1, &v2, &v3, state );
loadBuffer[ii] = v1;
loadBuffer[ii+1] = v2;
loadBuffer[ii+2] = v3;
}
getRandomNumberStream( jj )->loadFromArray( loadBuffer );
}
if( printOn ){
FILE* log = getLog() ? getLog() : stderr;
(void) fprintf( log, "%s: stats\n%s\n", methodName.c_str(), getStatisticsString().c_str() );
(void) fflush( log );
}
return DefaultReturnValue;
}
/**
* Load random number streams using Mersenne algorithm
*
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::_loadRandomNumberStreamsMersenne( void ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nBrookRandomNumberGenerator::_loadRandomNumberStreamsMersenne";
int printOn = 0;
// ---------------------------------------------------------------------------------------
// allocate memory once for download of random nos.
float* loadBuffer = _getLoadBuffer();
for( int jj = 0; jj < getNumberOfRandomNumberStreams(); jj++ ){
for( int ii = 0; ii < 3*getRandomNumberStreamSize(); ii += 3 ){
loadBuffer[ii] = (float) SimTKOpenMMUtilities::getNormallyDistributedRandomNumber();
loadBuffer[ii+1] = (float) SimTKOpenMMUtilities::getNormallyDistributedRandomNumber();
loadBuffer[ii+2] = (float) SimTKOpenMMUtilities::getNormallyDistributedRandomNumber();
}
getRandomNumberStream( jj )->loadFromArray( loadBuffer );
}
if( printOn ){
FILE* log = getLog() ? getLog() : stderr;
(void) fprintf( log, "%s: stats\n%s\n", methodName.c_str(), getStatisticsString().c_str() );
(void) fflush( log );
}
return DefaultReturnValue;
}
/**
* Load random number streams w/ fixed value
*
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::_loadRandomNumberStreamsFixedValue( void ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nBrookRandomNumberGenerator::_loadRandomNumberStreamsFixedValue";
int printOn = 0;
// ---------------------------------------------------------------------------------------
// load fixed value
float fixedValue = 0.1f;
for( int jj = 0; jj < getNumberOfRandomNumberStreams(); jj++ ){
getRandomNumberStream( jj )->fillWithValue( &fixedValue );
}
if( printOn ){
FILE* log = getLog() ? getLog() : stderr;
(void) fprintf( log, "%s: stats\n%s\n", methodName.c_str(), getStatisticsString().c_str() );
(void) fflush( log );
}
return DefaultReturnValue;
}
/**
* Load random number streams using original gpu algorithm
*
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::_loadGVStreamsOriginal( void ){
// ---------------------------------------------------------------------------------------
unsigned long int jran;
// static const std::string methodName = "\nBrookRandomNumberGenerator::_loadGVStreamsOriginal";
// ---------------------------------------------------------------------------------------
float* loadBuffer = _getLoadBuffer();
jran = getRandomNumberSeed();
for( int jj = 0; jj < getNumberOfRandomNumberStreams(); jj++ ){
for( int ii = 0; ii < 3*getRandomNumberStreamSize(); ii++ ){
loadBuffer[ii] = _generateGromacsRandomNumber( &jran );
}
getRandomNumberStream( jj )->loadFromArray( loadBuffer );
}
incrementRandomNumberSeed( 1 );
return DefaultReturnValue;
}
/**
* Get load buffer
*
* @return ptr to load buffer
*
* @throw OpenMMException if rv stream size is < 1
*
**/
float* BrookRandomNumberGenerator::_getLoadBuffer( void ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nBrookRandomNumberGenerator::_getLoadBuffer";
// ---------------------------------------------------------------------------------------
if( getRandomNumberStreamSize() < 1 ){
std::stringstream message;
message << methodName << " rv stream size=" << getRandomNumberStreamSize() << " is less than 1.";
throw OpenMMException( message.str() );
return NULL;
}
if( _loadBuffer == NULL ){
_loadBuffer = (float*) malloc( sizeof(float)*3*getRandomNumberStreamSize() );
}
return _loadBuffer;
}
/**
* Get ptr to shuffle indices
*
* @return ptr to shuffle indices
*
* @throw OpenMMException if size is < 1
*
**/
int* BrookRandomNumberGenerator::_getShuffleIndices( int size ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nBrookRandomNumberGenerator::_getShuffleIndices";
// ---------------------------------------------------------------------------------------
if( size < 1 ){
std::stringstream message;
message << methodName << " size=" << size << " is less than 1.";
throw OpenMMException( message.str() );
return NULL;
}
if( _shuffleIndices == NULL ){
_shuffleIndices = (int*) malloc( sizeof(int)*size );
}
return _shuffleIndices;
}
/**
* Loads a permutation of indices from 0 to gvSize-1 in
* sdp->strShuffle. To make sure that the order of the
* permutation is atleast NGVSHUFFLE, we create the
* permutation by introducing a random number of p-cycles
* where p is randomly determined from 2,3,5,7 and 11.
* The LCM of these numbers is 2310.
* Ofcourse the p-cycles are not necessarily disjoint
* the way it's done here, but there's a good chance
* there will enough disjoint cycles to make the
* order of the permutation larger than NGVSHUFFLE
*
*
* This function is only called once at startup
*
* @return DefaultReturnValue;
**/
int BrookRandomNumberGenerator::_loadGVShuffle( void ){
// ---------------------------------------------------------------------------------------
const int p[] = { 2, 3, 5, 7, 11 };
const int np = sizeof(p) / sizeof(p[0]);
const int pmax = p[np-1];
static const std::string methodName = "BrookRandomNumberGenerator::loadGVShuffle";
int printOn = 0;
// ---------------------------------------------------------------------------------------
float* loadBuffer = _getLoadBuffer();
int* indices = _getShuffleIndices( pmax );
int rvSize = getRandomNumberStreamSize();
for ( int ii = 0; ii < rvSize; ii++ ) {
loadBuffer[ii] = (float) ii;
}
//How to come up with this number here?
unsigned long int seed = getRandomNumberSeed();
for( int iter = 0; iter < 1000000; iter++ ) {
//for each p
for( int ii = 0; ii < np; ii++ ){
//Come up with p random indices
//Not checking that they are distinct
//because that should be fairly rare
for ( int jj = 0; jj < p[ii]; jj++ ) {
//indices[j] = (int) ( gmx_rando( &sdp->seed ) * sdp->gvSize );
indices[jj] = (int) ( _generateGromacsRandomNumber( &seed )*rvSize );
}
// do a p-cycle
float tmp = loadBuffer[ indices[0] ];
for ( int jj = 0; jj < p[ii]-1; jj++ ) {
loadBuffer[ indices[jj] ] = loadBuffer[ indices[jj+1] ];
}
loadBuffer[ indices[ p[ii]-1 ] ] = tmp;
}
}
_getShuffleStream()->loadFromArray( loadBuffer );
if( printOn ){
FILE* log = getLog() ? getLog() : stderr;
(void) fprintf( log, "%s: sz=%d pmax=%d np=%d sample indices:\n", methodName.c_str(), rvSize, pmax, np );
float maxIdx = -1.0f;
float minIdx = (float) (rvSize)*2.0f;
for( int ii = 0; ii < rvSize; ii++ ){
if( ii < 30 || ii > (rvSize-30) ){
(void) fprintf( log, " %d %.8f\n", ii, loadBuffer[ii] );
}
if( loadBuffer[ii] < minIdx ){
minIdx = loadBuffer[ii];
}
if( loadBuffer[ii] > maxIdx ){
maxIdx = loadBuffer[ii];
}
}
(void) fprintf( log, "%s: min-max indices: %.8f %.8f\n", methodName.c_str(), minIdx, maxIdx );
}
return DefaultReturnValue;
}
/**
* Shuffle streams
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::_shuffleGVStreams( void ){
// ---------------------------------------------------------------------------------------
// static const std::string methodName = "\nBrookRandomNumberGenerator::_shuffleGVStreams";
// ---------------------------------------------------------------------------------------
int numberOfRvStreams = getNumberOfRandomNumberStreams();
for( int ii = 0; ii < (numberOfRvStreams - 1); ii++ ){
kpermute_vectors( (float) getRandomNumberStreamWidth(),
_getShuffleStream()->getBrookStream(),
getRandomNumberStream( ii + 1 )->getBrookStream(),
getRandomNumberStream( ii )->getBrookStream() );
}
kpermute_vectors( (float) getRandomNumberStreamWidth(),
_getShuffleStream()->getBrookStream(),
getRandomNumberStream( 0 )->getBrookStream(),
getRandomNumberStream( numberOfRvStreams - 1 )->getBrookStream() );
return DefaultReturnValue;
}
/**
* Advances the current position by 2*gpu->particles
* If we run out of rand numbers, we shuffle and
* reuse a few times before reloading from the cpu
*
* @param numberOfRandomValuesConsumedPerIteration number of random values consumed/iteration
*
* @return DefaultReturnValue;
*/
int BrookRandomNumberGenerator::advanceGVCursor( int numberOfRandomValuesConsumedPerIteration ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "BrookRandomNumberGenerator::advanceGVCursor";
int printOn = 0;
FILE* log;
// ---------------------------------------------------------------------------------------
//setLog( stderr );
if( printOn && getLog() ){
log = getLog();
} else {
printOn = 0;
}
int rvStreamSize = getRandomNumberStreamSize();
// use 2 random values per sd
_rvStreamOffset += numberOfRandomValuesConsumedPerIteration;
//Check if we've used up this texture
char* action = "none";
if ( _rvStreamOffset > rvStreamSize - numberOfRandomValuesConsumedPerIteration ){
// next one if available
_rvStreamOffset = 0;
if ( _rvStreamIndex < _numberOfRandomNumberStreams - 1 ){
_rvStreamIndex++;
action = "incremented stream index";
} else {
//No more textures, need to shuffle
if( _numberOfShuffles < _maxShuffles ){
_shuffleGVStreams( );
_numberOfShuffles++;
action = "shuffled streams";
} else { //Need to refresh random numbers from cpu
if( _randomNumberGenerator == Mersenne ){
action = "loaded new values to GPU using Mersenne rng";
_loadRandomNumberStreamsMersenne( );
} else if( _randomNumberGenerator == Kiss ){
action = "loaded new values to GPU using KISS rng";
_loadRandomNumberStreamsKiss( );
} else if( _randomNumberGenerator == Original ){
action = "loaded new values to GPU using original Gromac's rng";
_loadGVStreamsOriginal( );
} else if( _randomNumberGenerator == FixedValue ){
action = "loaded new fixed values to GPU";
_loadRandomNumberStreamsFixedValue( );
}
_numberOfShuffles = 0;
}
_rvStreamIndex = 0;
}
if( printOn ){
(void) fprintf( log, "%s offset=%d consume/itr=%d StrmSz=%d idx=%d shffle=%d action=%s\n",
methodName.c_str(), _rvStreamOffset, numberOfRandomValuesConsumedPerIteration,
rvStreamSize, _rvStreamIndex, _numberOfShuffles, action );
(void) fflush( log );
}
/*
// check rng distribution
static int count = 0;
if( count++ < 2 ){
// accumulate rng -- stats will be in cumulative fields in stat string
int testIterations = 1000;
for( int ii = 0; ii < testIterations; ii++ ){
//_loadRandomNumberStreamsKiss( );
_loadRandomNumberStreamsMersenne( );
getStatisticsString();
}
(void) fprintf( log, "%s: stats\n%s\n", methodName.c_str(), getStatisticsString().c_str() );
}
*/
}
return DefaultReturnValue;
}
/**
* Get random number stream size
*
* @return random number stream size
*
*/
int BrookRandomNumberGenerator::getRandomNumberStreamSize( void ) const {
return _randomNumberStreamSize;
}
/**
* Get Shuffle stream
*
* @return shuffle stream
*
*/
BrookFloatStreamInternal* BrookRandomNumberGenerator::_getShuffleStream( void ) const {
return _auxiliaryStreams[ShuffleStream];
}
/**
* Get random number stream
*
* @param index random number stream index
*
* @return random number stream
*
* @throw OpenMMException if index is invalid or _randomNumberGeneratorStreams not set
*
*/
BrookFloatStreamInternal* BrookRandomNumberGenerator::getRandomNumberStream( int index ){
// ---------------------------------------------------------------------------------------
static const std::string methodName = "\nBrookRandomNumberGenerator::getRandomNumberStream";
// ---------------------------------------------------------------------------------------
if( index < 0 || index >= _numberOfRandomNumberStreams ){
std::stringstream message;
message << methodName << " index=" << index << " is out of range: [0," << _numberOfRandomNumberStreams;
throw OpenMMException( message.str() );
return NULL;
}
if( _randomNumberGeneratorStreams == NULL ){
std::stringstream message;
message << methodName << " rv streams not initialized; input index=" << index;
throw OpenMMException( message.str() );
return NULL;
}
return _randomNumberGeneratorStreams[index];
}
/**
* Get random value stream index
*
* @return random value stream index
*
*/
int BrookRandomNumberGenerator::getRvStreamIndex( void ) const {
return _rvStreamIndex;
}
/**
* Get random value stream offset
*
* @return random value stream offset
*
*/
int BrookRandomNumberGenerator::getRvStreamOffset( void ) const {
return _rvStreamOffset;
}
/**
* Get max shuffles
*
* @return max shuffles
*
*/
int BrookRandomNumberGenerator::getMaxShuffles( void ) const {
return _maxShuffles;
}
/**
* Get number of shuffles
*
* @return number of shuffles
*
*/
int BrookRandomNumberGenerator::_getNumberOfShuffles( void ) const {
return _numberOfShuffles;
}
/**
* Initialize stream dimensions
*
* @param numberOfParticles number of particles
* @param platform platform
*
* @return ErrorReturnValue if error, else DefaultReturnValue
*
*/
int BrookRandomNumberGenerator::_initializeStreamSizes( int numberOfParticles, const Platform& platform ){
// ---------------------------------------------------------------------------------------
//static const std::string methodName = "BrookRandomNumberGenerator::_initializeStreamSizes";
// ---------------------------------------------------------------------------------------
setNumberOfParticles( numberOfParticles );
// get randomNumber stream dimensions
const BrookPlatform& brookPlatform = dynamic_cast (platform);
const BrookStreamFactory& brookStreamFactory = dynamic_cast (platform.getDefaultStreamFactory() );
_randomNumberStreamWidth = brookStreamFactory.getDefaultRandomNumberStreamWidth();
_randomNumberStreamSize = brookStreamFactory.getDefaultRandomNumberStreamSize();
_randomNumberStreamHeight = (int) ( ((float) _randomNumberStreamSize)/( (float) _randomNumberStreamWidth) + 0.001);
_randomNumberStreamSize = _randomNumberStreamWidth*_randomNumberStreamHeight;
return DefaultReturnValue;
}
/**
* Initialize streams
*
* @param platform platform
*
* @return ErrorReturnValue if error, else DefaultReturnValue
*
*/
int BrookRandomNumberGenerator::_initializeStreams( const Platform& platform ){
// ---------------------------------------------------------------------------------------
//static const std::string methodName = "BrookRandomNumberGenerator::_initializeStreams";
float dangleValue = 0.0f;
// ---------------------------------------------------------------------------------------
int randomNumberStreamSize = getRandomNumberStreamSize();
int randomNumberStreamWidth = getRandomNumberStreamWidth();
_auxiliaryStreams[ShuffleStream] = new BrookFloatStreamInternal( BrookCommon::ShuffleStream,
randomNumberStreamSize, randomNumberStreamWidth,
BrookStreamInternal::Float, dangleValue );
// insure number of random number streams is > 0
// delete if already allocated and then initialize
if( _numberOfRandomNumberStreams < 1 ){
_numberOfRandomNumberStreams = 1;
}
if( _randomNumberGeneratorStreams ){
delete[] _randomNumberGeneratorStreams;
}
_randomNumberGeneratorStreams = new BrookFloatStreamInternal*[_numberOfRandomNumberStreams];
for( int ii = 0; ii < _numberOfRandomNumberStreams; ii++ ){
_randomNumberGeneratorStreams[ii] = new BrookFloatStreamInternal( BrookCommon::RandomValuesStream,
randomNumberStreamSize, randomNumberStreamWidth,
BrookStreamInternal::Float3, dangleValue );
}
// create shuffle stream
_loadGVShuffle();
return DefaultReturnValue;
}
/*
* Setup of streams, ... associated w/ random number generator
*
* @param numberOfParticles number of particles
* @param platform Brook platform
*
* @return nonzero value if error
*
* */
int BrookRandomNumberGenerator::setup( int numberOfParticles, const Platform& platform ){
// ---------------------------------------------------------------------------------------
//static const std::string methodName = "BrookRandomNumberGenerator::setup";
// ---------------------------------------------------------------------------------------
const BrookPlatform& brookPlatform = dynamic_cast (platform);
setLog( brookPlatform.getLog() );
// set stream sizes and then create streams
_initializeStreamSizes( numberOfParticles, platform );
_initializeStreams( platform );
if( _randomNumberGenerator == Mersenne ){
_loadRandomNumberStreamsMersenne( );
} else if( _randomNumberGenerator == Kiss ){
_loadRandomNumberStreamsKiss( );
} else if( _randomNumberGenerator == Original ){
_loadGVStreamsOriginal( );
} else if( _randomNumberGenerator == FixedValue ){
_loadRandomNumberStreamsFixedValue( );
}
return DefaultReturnValue;
}
/*
* Get contents of object
*
* @param level level of dump
*
* @return string containing contents
*
* */
std::string BrookRandomNumberGenerator::getContentsString( int level ) const {
// ---------------------------------------------------------------------------------------
static const std::string methodName = "BrookRandomNumberGenerator::getContentsString";
static const unsigned int MAX_LINE_CHARS = 256;
char value[MAX_LINE_CHARS];
static const char* Set = "Set";
static const char* NotSet = "Not set";
// ---------------------------------------------------------------------------------------
std::stringstream message;
std::string tab = " ";
#ifdef _MSC_VER
#define LOCAL_SPRINTF(a,b,c) sprintf_s( (a), MAX_LINE_CHARS, (b), (c) );
#else
#define LOCAL_SPRINTF(a,b,c) sprintf( (a), (b), (c) );
#endif
if( _randomNumberGenerator == Mersenne ){
(void) LOCAL_SPRINTF( value, "%s", "Mersenne Rng");
} else if( _randomNumberGenerator == Kiss ){
(void) LOCAL_SPRINTF( value, "%s", "Kiss Rng");
} else if( _randomNumberGenerator == Original ){
(void) LOCAL_SPRINTF( value, "%s", "Original Gromacs Rng");
} else if( _randomNumberGenerator == FixedValue ){
(void) LOCAL_SPRINTF( value, "%s", "Fixed value Rng");
}
message << _getLine( tab, "Random number generator:", value );
(void) LOCAL_SPRINTF( value, "%d", getRandomNumberStreamSize() );
message << _getLine( tab, "RandomNumber stream size:", value );
(void) LOCAL_SPRINTF( value, "%d", getRandomNumberStreamWidth() );
message << _getLine( tab, "RandomNumber stream width:", value );
(void) LOCAL_SPRINTF( value, "%d", getRandomNumberStreamHeight() );
message << _getLine( tab, "RandomNumber stream height:", value );
(void) LOCAL_SPRINTF( value, "%d", getNumberOfRandomNumberStreams() );
message << _getLine( tab, "Number of RandomNumber streams:", value );
(void) LOCAL_SPRINTF( value, "%ld", getRandomNumberSeed() );
message << _getLine( tab, "Seed:", value );
(void) LOCAL_SPRINTF( value, "%d", getRvStreamIndex() );
message << _getLine( tab, "Rv stream index:", value );
(void) LOCAL_SPRINTF( value, "%d", getRvStreamOffset() );
message << _getLine( tab, "Rv stream offset:", value );
(void) LOCAL_SPRINTF( value, "%d", _getNumberOfShuffles() );
message << _getLine( tab, "Number of rv stream shuffles:", value );
(void) LOCAL_SPRINTF( value, "%d", getMaxShuffles() );
message << _getLine( tab, "Max number of rv stream shuffles:", value );
message << _getLine( tab, "Log:", (getLog() ? Set : NotSet) );
message << _getLine( tab, "Shuffle:", (_getShuffleStream() ? Set : NotSet) );
// show stats
message << getStatisticsString( );
for( int ii = 0; ii < LastStreamIndex; ii++ ){
message << std::endl;
if( _auxiliaryStreams[ii] ){
message << _auxiliaryStreams[ii]->getContentsString( );
}
}
for( int ii = 0; ii < _numberOfRandomNumberStreams; ii++ ){
message << std::endl;
if( _randomNumberGeneratorStreams[ii] ){
message << _randomNumberGeneratorStreams[ii]->getContentsString();
}
}
#undef LOCAL_SPRINTF
return message.str();
}
/*
* Get statistics
*
* @return string containing contents
*
* */
std::string BrookRandomNumberGenerator::getStatisticsString( void ) const {
// ---------------------------------------------------------------------------------------
static const std::string methodName = "BrookRandomNumberGenerator::getStatisticsString";
static const unsigned int MAX_LINE_CHARS = 256;
char value[MAX_LINE_CHARS];
static const char* Set = "Set";
static const char* NotSet = "Not set";
static double cumulativeStatistics[7] = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0e+99, -1.0e+99 };
// ---------------------------------------------------------------------------------------
std::stringstream message;
std::string tab = " ";
#ifdef _MSC_VER
#define LOCAL_SPRINTF(a,b,c) sprintf_s( (a), MAX_LINE_CHARS, (b), (c) );
#else
#define LOCAL_SPRINTF(a,b,c) sprintf( (a), (b), (c) );
#endif
message << "\n Statistics:\n";
double statistics[7];
getStatistics( statistics, -1, cumulativeStatistics );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[4] );
message << _getLine( tab, "Count:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[0] );
message << _getLine( tab, "Average:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[1] );
message << _getLine( tab, "StdDev:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[3] );
message << _getLine( tab, "Kurtosis:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[5] );
message << _getLine( tab, "Min:", value );
(void) LOCAL_SPRINTF( value, "%.6e", statistics[6] );
message << _getLine( tab, "Max:", value );
if( cumulativeStatistics[4] > 1000.0 ){
for( int ii = 0; ii < 7; ii++ ){
statistics[ii] = cumulativeStatistics[ii];
}
statistics[0] /= statistics[4];
statistics[1] = statistics[1] - statistics[4]*statistics[0]*statistics[0];
if( statistics[4] > 1.0 ){
statistics[1] = sqrt( statistics[1]/( statistics[4] - 1.0 ) );
}
statistics[3] = (statistics[3]/(statistics[4]*statistics[1]*statistics[1]) ) - 3.0;
(void) LOCAL_SPRINTF( value, "%.5e", statistics[4] );
message << _getLine( tab, "Cumulative Count:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[0] );
message << _getLine( tab, "Cumulative Average:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[1] );
message << _getLine( tab, "Cumulative StdDev:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[3] );
message << _getLine( tab, "Cumulative Kurtosis:", value );
(void) LOCAL_SPRINTF( value, "%.5e", statistics[5] );
message << _getLine( tab, "Cumulative Min:", value );
(void) LOCAL_SPRINTF( value, "%.6e", statistics[6] );
message << _getLine( tab, "Cumulative Max:", value );
}
#undef LOCAL_SPRINTF
return message.str();
}
/*
* Get statistics
*
* @param statistics array of size 5:
* 0: mean
* 1: std dev
* 2: 3rd moment (not normalized)
* 3: kurtosis
* 4: count
* 5: min
* 6: max
*
* @param streamIndex stream index to analyze
*
* @return DefaultReturnValue
*
* */
int BrookRandomNumberGenerator::getStatistics( double statistics[7], int streamIndex, double cumulativeStatistics[7] ) const {
// ---------------------------------------------------------------------------------------
static const std::string methodName = "BrookRandomNumberGenerator::";
// ---------------------------------------------------------------------------------------
statistics[0] = 0.0;
statistics[1] = 0.0;
statistics[2] = 0.0;
statistics[3] = 0.0;
statistics[4] = 0.0;
statistics[5] = 1.0e+99;
statistics[6] = -1.0e+99;
for( int ii = 0; ii < _numberOfRandomNumberStreams; ii++ ){
if( streamIndex < 0 || ii == streamIndex ){
void* dataArrayV = _randomNumberGeneratorStreams[ii]->getData( 1 );
int numberOfValues = _randomNumberGeneratorStreams[ii]->getStreamSize()*_randomNumberGeneratorStreams[ii]->getWidth();
const float* dataArray = (float*) dataArrayV;
for( int ii = 0; ii < numberOfValues; ii++ ){
statistics[0] += dataArray[ii];
double rv2 = dataArray[ii]*dataArray[ii];
statistics[1] += rv2;
statistics[2] += rv2*dataArray[ii];
statistics[3] += rv2*rv2;
if( statistics[5] > dataArray[ii] ){
statistics[5] = dataArray[ii];
}
if( statistics[6] < dataArray[ii] ){
statistics[6] = dataArray[ii];
}
}
statistics[4] += (double) numberOfValues;
}
}
// accumulate moments, ... in cumulativeStatistics array
for( int ii = 0; ii < 5; ii++ ){
cumulativeStatistics[ii] += statistics[ii];
}
if( statistics[5] < cumulativeStatistics[5] ){
cumulativeStatistics[5] = statistics[5];
}
if( statistics[6] > cumulativeStatistics[6] ){
cumulativeStatistics[6] = statistics[6];
}
if( statistics[4] > 0.0 ){
statistics[0] /= statistics[4];
statistics[1] = statistics[1] - statistics[4]*statistics[0]*statistics[0];
if( statistics[4] > 1.0 ){
statistics[1] = sqrt( statistics[1]/( statistics[4] - 1.0 ) );
}
statistics[3] = (statistics[3]/(statistics[4]*statistics[1]*statistics[1]) ) - 3.0;
}
return DefaultReturnValue;
}