/* -------------------------------------------------------------------------- * * 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 #include "BrookFloatStreamInternal.h" #include "BrookPlatform.h" #include "openmm/OpenMMException.h" using namespace OpenMM; /** * BrookFloatStreamInternal constructor * * @param name stream name * @param size stream size * @param type stream type (float, float2, ...) * @param platform platform * @param inputStreamWidth stream width * @param inputDefaultDangleValue default dangle value * * @throw exception if stream type not recognized or stream width < 1 * */ BrookFloatStreamInternal::BrookFloatStreamInternal( const std::string& name, int size, int streamWidth, BrookStreamInternal::DataType type, double inputDefaultDangleValue ) : BrookStreamInternal( name, size, streamWidth, type ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::BrookFloatStreamInternal"; // --------------------------------------------------------------------------------------- //fprintf( stderr,"%s %s\n", methodName.c_str(), getName().c_str() ); //fflush( stderr ); // set base type (currently only FLOAT supported) switch( type ){ case BrookStreamInternal::Float: case BrookStreamInternal::Float2: case BrookStreamInternal::Float3: case BrookStreamInternal::Float4: _baseType = BrookStreamInternal::Float; break; case BrookStreamInternal::Double: case BrookStreamInternal::Double2: case BrookStreamInternal::Double3: case BrookStreamInternal::Double4: _baseType = BrookStreamInternal::Double; break; default: std::stringstream message; message << methodName << " stream=" << name << " input type=" << type << " not recognized."; throw OpenMMException( message.str() ); break; } // set _width (FLOAT, FLOAT2, ... ) switch( type ){ case BrookStreamInternal::Float: case BrookStreamInternal::Double: _width = 1; break; case BrookStreamInternal::Float2: case BrookStreamInternal::Double2: _width = 2; break; case BrookStreamInternal::Float3: case BrookStreamInternal::Double3: _width = 3; break; case BrookStreamInternal::Float4: case BrookStreamInternal::Double4: _width = 4; break; } _defaultDangleValue = (float) inputDefaultDangleValue; // set stream height based on specified stream _width if( streamWidth < 1 ){ std::stringstream message; message << methodName << " stream=" << name << " input stream width=" << streamWidth << " is less than 1."; throw OpenMMException( message.str() ); } // create Brook stream handle switch( _width ){ case 1: _aStream = brook::stream::create( _streamHeight, _streamWidth ); break; case 2: _aStream = brook::stream::create( _streamHeight, _streamWidth ); break; case 3: _aStream = brook::stream::create( _streamHeight, _streamWidth ); break; case 4: _aStream = brook::stream::create( _streamHeight, _streamWidth ); break; } int streamSize = getStreamSize(); // allocate memory for data buffer _data = new float[streamSize*_width]; //printf( "%s %s data=%u stream=%d [%d %d] width=%d\n", methodName.c_str(), getName().c_str(), (unsigned int) _data, streamSize, _streamHeight, _streamWidth, _width ); //fflush( stdout ); } /** * BrookFloatStreamInternal destructor * */ BrookFloatStreamInternal::~BrookFloatStreamInternal( ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::~BrookFloatStreamInternal"; // --------------------------------------------------------------------------------------- //printf( "%s %s data=%u stream=%d [%d %d] width=%d\n", methodName.c_str(), getName().c_str(), (unsigned int) _data, getStreamSize(), _streamHeight, _streamWidth, _width ); //fflush( stdout ); delete[] _data; } /** * Get dangle value * * @return dangle value */ double BrookFloatStreamInternal::getDangleValue( void ) const { return _defaultDangleValue; } /** * Load data from input array * * @param array a pointer to the start of the array. The array is assumed to have the same length as this stream, * and to contain elements of the correct _data type for this stream. If the stream has a compound _data type, all * the values should be packed into a single array: all the values for the first element, followed by all the values * for the next element, etc. * * @throw exception if baseType not recognized * */ void BrookFloatStreamInternal::loadFromArray( const void* array ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookFloatStreamInternal::loadFromArray"; // --------------------------------------------------------------------------------------- return loadFromArray( array, getBaseDataType() ); } /** * Load data from input array * * @param array a pointer to the start of the array. The array is assumed to have the same length as this stream, * and to contain elements of the correct _data type for this stream. If the stream has a compound _data type, all * the values should be packed into a single array: all the values for the first element, followed by all the values * for the next element, etc. * * @throw exception if baseType not float, double, or integer * */ void BrookFloatStreamInternal::loadFromArray( const void* array, BrookStreamInternal::DataType baseType ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::loadFromArray"; // --------------------------------------------------------------------------------------- int totalSize = getSize()*getWidth(); //int totalSize = getSize(); /* fprintf( stderr, "%s %s data=%p stream=%d [%d %d] width=%d type=%d\n", methodName.c_str(), getName().c_str(), _data, getStreamSize(), _streamHeight, _streamWidth, _width, baseType ); fflush( stderr ); */ if( baseType == BrookStreamInternal::Float ){ memcpy( _data, array, sizeof( float )*totalSize ); /* float* arrayData = (float*) array; for( int ii = 0; ii < totalSize; ii++ ){ _data[ii] = (BrookOpenMMFloat) arrayData[ii]; } */ } else if( baseType == BrookStreamInternal::Double ){ double* arrayData = (double*) array; for( int ii = 0; ii < totalSize; ii++ ){ _data[ii] = (BrookOpenMMFloat) arrayData[ii]; } } else if( baseType == BrookStreamInternal::Integer ){ int* arrayData = (int*) array; for( int ii = 0; ii < totalSize; ii++ ){ _data[ii] = (BrookOpenMMFloat) arrayData[ii]; } } else { std::stringstream message; message << methodName << " stream=" << getName() << " base type=" << getTypeString( baseType ) << " not recognized."; throw OpenMMException( message.str() ); } // set dangling values _loadDanglingValues(); // write to GPU _aStream.read( _data ); } /** * Save data to input array * * @param array a pointer to the start of the array. The array is assumed to have the same length as this stream, * and to contain elements of the correct _data type for this stream. If the stream has a compound _data type, all * the values should be packed into a single array: all the values for the first element, followed by all the values * for the next element, etc. * * @throw exception if baseType not float, double, or integer * */ void BrookFloatStreamInternal::saveToArray( void* array ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::saveToArray"; // --------------------------------------------------------------------------------------- // get _data from GPU _aStream.write( _data ); // load into array int totalSize = getSize()*getWidth(); BrookStreamInternal::DataType baseType = getBaseDataType(); if( baseType == BrookStreamInternal::Float ){ //printf( "%s Basetype is float\n", methodName.c_str() ); //fflush( stdout ); memcpy( array, _data, sizeof( float )*totalSize ); /* float* arrayData = (float*) array; for( int ii = 0; ii < totalSize; ii++ ){ arrayData[ii] = (float) _data[ii]; } */ } else if( baseType == BrookStreamInternal::Double ){ //printf( "%s Basetype is double\n", methodName.c_str() ); //fflush( stdout ); double* arrayData = (double*) array; for( int ii = 0; ii < totalSize; ii++ ){ arrayData[ii] = (double) _data[ii]; } } else if( baseType == BrookStreamInternal::Integer ){ //printf( "%s Basetype is int\n", methodName.c_str() ); //fflush( stdout ); int* arrayData = (int*) array; for( int ii = 0; ii < totalSize; ii++ ){ arrayData[ii] = (int) _data[ii]; } } else { std::stringstream message; message << methodName << " stream=" << getName() << " base type=" << getTypeString( baseType ) << " not recognized."; throw OpenMMException( message.str() ); } } /** * Fill stream w/ specified value * * @param value value to fill stream w/ * */ void BrookFloatStreamInternal::fillWithValue( void* value ){ // --------------------------------------------------------------------------------------- // static const std::string methodName = "BrookFloatStreamInternal::fillWithValue"; // static const int debug = 1; // --------------------------------------------------------------------------------------- BrookOpenMMFloat valueData; if( _baseType == BrookStreamInternal::Float) { valueData = (BrookOpenMMFloat) *((float*) value); } else { valueData = (BrookOpenMMFloat) *((double*) value); } //memset( _data, valueData, sizeof( float )*getSize()*getWidth() ); int totalSize = getSize()*getWidth(); for( int ii = 0; ii < totalSize; ii++ ){ _data[ii] = valueData; } _loadDanglingValues(); _aStream.read( _data ); } /** * Get data * * @param readFromBoard if set, read values on board * * @return data array * */ void* BrookFloatStreamInternal::getData( int readFromBoard ){ // --------------------------------------------------------------------------------------- // static const std::string methodName = "BrookFloatStreamInternal::getData"; // --------------------------------------------------------------------------------------- if( readFromBoard ){ _aStream.write( _data ); } return (void*) _data; } /** * Get data * * @return data array * */ void* BrookFloatStreamInternal::getData( void ){ // --------------------------------------------------------------------------------------- // static const std::string methodName = "BrookFloatStreamInternal::getData"; // --------------------------------------------------------------------------------------- return getData( 0 ); } /** * Load dangling value into stream * * @param danglingValue dangling value to load * */ void BrookFloatStreamInternal::_loadDanglingValues( float danglingValue ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::_loadDanglingValues"; // --------------------------------------------------------------------------------------- int width = getWidth(); int arraySize = getSize()*width; int streamSize = getStreamSize()*width; //printf( "%s array=%d stream=%d width=%d %s\n", methodName.c_str(), arraySize, streamSize, width, getName().c_str() ); //fflush( stdout ); if( arraySize < streamSize ){ for( int ii = arraySize; ii < streamSize; ii++ ){ _data[ii] = danglingValue; } } } /** * Load default dangling value into stream * */ void BrookFloatStreamInternal::_loadDanglingValues( void ){ _loadDanglingValues( _defaultDangleValue ); } /* * Get contents of object * * @param level level of dump * * @return string containing contents * * */ const std::string BrookFloatStreamInternal::getContentsString( int level ) const { // --------------------------------------------------------------------------------------- // static const std::string methodName = "BrookFloatStreamInternal::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 WIN32 #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 (void) LOCAL_SPRINTF( value, "%s", getName().c_str() ); message << _getLine( tab, "Name:", value ); (void) LOCAL_SPRINTF( value, "%d", getWidth() ); message << _getLine( tab, "Width:", value ); (void) LOCAL_SPRINTF( value, "%d", getStreamSize() ); message << _getLine( tab, "Stream size:", value ); (void) LOCAL_SPRINTF( value, "%d", getStreamWidth() ); message << _getLine( tab, "Stream width:", value ); (void) LOCAL_SPRINTF( value, "%d", getStreamHeight() ); message << _getLine( tab, "Stream height:", value ); (void) LOCAL_SPRINTF( value, "%3e", getDangleValue() ); message << _getLine( tab, "Dangle value:", value ); return message.str(); } /* * Print array contents of object to file * * @param log file to print to * * @return DefaultReturnValue * * */ int BrookFloatStreamInternal::_bodyPrintToFile( FILE* log, int maxPrint ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookStreamInternal::_bodyPrintToFile"; static const unsigned int MAX_LINE_CHARS = 256; char value[MAX_LINE_CHARS]; // --------------------------------------------------------------------------------------- assert( log ); void* dataArrayV = getData( 1 ); #ifdef WIN32 #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 int streamSize = getStreamSize(); int width = getWidth(); int index = 0; maxPrint = maxPrint < 0 ? streamSize : maxPrint; maxPrint *= width; const float* dataArray = (float*) dataArrayV; for( int ii = 0; ii < streamSize && ii < maxPrint; ii++ ){ std::stringstream message; (void) LOCAL_SPRINTF( value, "%6d ", ii ); message << value << " [ "; for( int jj = 0; jj < width; jj++ ){ (void) LOCAL_SPRINTF( value, "%16.7e ", dataArray[index++] ); message << value; } message << "]\n"; if( index == (_size+1)*width ){ (void) fprintf( log, "\n" ); } (void) fprintf( log, "%s", message.str().c_str() ); } return DefaultReturnValue; } /* * Get stats * * @return statistics vector * * */ int BrookFloatStreamInternal::getStatistics( std::vector >& statistics, int maxScan ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookStreamInternal::getStatistics"; static const int MinIndex = 4; static const int MinIndexIndex = 5; static const int MaxIndex = 6; static const int MaxIndexIndex = 7; static const int CountIndex = 8; static const int vectorSize = CountIndex + 1; static const double bigValue = 1.0e+10; // --------------------------------------------------------------------------------------- void* dataArrayV = getData( 1 ); statistics.resize( vectorSize ); int streamSize = getStreamSize(); int width = getWidth(); int index = 0; const float* dataArray = (float*) dataArrayV; for( int ii = 0; ii < vectorSize; ii++ ){ for( int jj = 0; jj < width; jj++ ){ if( ii == MinIndex ){ statistics[ii].push_back( bigValue ); } else if( ii == MaxIndex ){ statistics[ii].push_back( -bigValue ); } else { statistics[ii].push_back( 0.0 ); } } } for( int ii = 0; ii < streamSize && ii < maxScan; ii++ ){ for( int jj = 0; jj < width; jj++ ){ double value = (double) dataArray[index++]; statistics[0][jj] += value; statistics[1][jj] += value*value; statistics[2][jj] += fabs( value ); statistics[CountIndex][jj] += 1.0; if( value < statistics[MinIndex][jj] ){ statistics[MinIndex][jj] = value; statistics[MinIndexIndex][jj] = ii; } if( value > statistics[MaxIndex][jj] ){ statistics[MaxIndex][jj] = value; statistics[MaxIndexIndex][jj] = ii; } } } for( int jj = 0; jj < width; jj++ ){ if( statistics[CountIndex][jj] > 0.0 ){ statistics[3][jj] = statistics[0][jj]; statistics[0][jj] /= statistics[CountIndex][jj]; statistics[2][jj] /= statistics[CountIndex][jj]; statistics[1][jj] = statistics[1][jj] - statistics[0][jj]*statistics[0][jj]*statistics[CountIndex][jj]; if( statistics[CountIndex][jj] > 1.0 ){ statistics[1][jj] = sqrt( statistics[1][jj]/( statistics[CountIndex][jj] - 1.0 ) ); } } } return DefaultReturnValue; } /** * Get array of appropritate size for loading data * * @return data array -- user's responsibility to free */ void* BrookFloatStreamInternal::getDataArray( void ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookStreamInternal::getDataArray"; // --------------------------------------------------------------------------------------- int totalSize = getStreamSize()*getWidth(); BrookStreamInternal::DataType baseType = getBaseDataType(); if( baseType == Double || baseType == Double2 || baseType == Double3 || baseType == Double4 ){ totalSize *= 2; } return new float[totalSize]; } /** * BrookFloatStreamInternal constructor * * @param stopIndex index to stop sum * @param sum array of size=getWidth() * * @return DefaultReturnValue * * @throw exception if stopIndex is too large */ int BrookFloatStreamInternal::sumByDimension( int stopIndex, double* sum ){ // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookFloatStreamInternal::sumByDimension"; // --------------------------------------------------------------------------------------- if( stopIndex > getSize() ){ std::stringstream message; message << methodName << " stream=" << getName() << " input topIndex" << stopIndex << " is too large: stream size=" << getSize(); throw OpenMMException( message.str() ); } // get _data from GPU _aStream.write( _data ); int width = getWidth(); int widthM1 = getWidth() - 1; stopIndex *= width; for( int ii = 0; ii < width; ii++ ){ sum[ii] = 0.0; } int index = 0; for( int ii = 0; ii < stopIndex; ii++ ){ sum[index] += (double) _data[ii]; if( index == widthM1 ){ index = 0; } else { index++; } } return DefaultReturnValue; }