/* -------------------------------------------------------------------------- * * 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 "BrookShakeAlgorithm.h" #include "BrookPlatform.h" #include "BrookStreamImpl.h" using namespace OpenMM; using namespace std; /** * * Constructor * */ BrookShakeAlgorithm::BrookShakeAlgorithm( ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookShakeAlgorithm::BrookShakeAlgorithm"; BrookOpenMMFloat zero = static_cast( 0.0 ); BrookOpenMMFloat one = static_cast( 1.0 ); // --------------------------------------------------------------------------------------- _numberOfParticles = -1; _numberOfConstraints = -1; _maxIterations = 25; _shakeTolerance = static_cast(1.0e-04); // mark stream dimension variables as unset _shakeParticleStreamWidth = -1; _shakeParticleStreamHeight = -1; _shakeParticleStreamSize = -1; _shakeConstraintStreamSize = -1; _shakeConstraintStreamWidth = -1; _shakeConstraintStreamHeight = -1; for( int ii = 0; ii < LastStreamIndex; ii++ ){ _shakeStreams[ii] = NULL; } // setup inverse sqrt masses _inverseSqrtMasses = NULL; } /** * Destructor * */ BrookShakeAlgorithm::~BrookShakeAlgorithm( ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookShakeAlgorithm::~BrookShakeAlgorithm"; // --------------------------------------------------------------------------------------- for( int ii = 0; ii < LastStreamIndex; ii++ ){ delete _shakeStreams[ii]; } delete[] _inverseSqrtMasses; } /** * Get number of constraints * * @return number of constraints * */ int BrookShakeAlgorithm::getNumberOfConstraints( void ) const { return _numberOfConstraints; } /** * Get max iterations * * @return max iterations * */ int BrookShakeAlgorithm::getMaxIterations( void ) const { return _maxIterations; } /** * Set max iterations * * @param max iterations * * @return DefaultReturnValue * */ int BrookShakeAlgorithm::setMaxIterations( int maxIterations ){ _maxIterations = maxIterations; return DefaultReturnValue; } /** * Get SHAKE tolerance * * @return SHAKE tolerance * */ BrookOpenMMFloat BrookShakeAlgorithm::getShakeTolerance( void ) const { return _shakeTolerance; } /** * Set SHAKE tolerance * * @param SHAKE tolerance * * @return DefaultReturnValue * */ int BrookShakeAlgorithm::setShakeTolerance( BrookOpenMMFloat tolerance ){ _shakeTolerance = tolerance; return DefaultReturnValue; } /** * Get Particle stream size * * @return Particle stream size * */ int BrookShakeAlgorithm::getShakeParticleStreamSize( void ) const { return _shakeParticleStreamSize; } /** * Get particle stream width * * @return particle stream width * */ int BrookShakeAlgorithm::getShakeParticleStreamWidth( void ) const { return _shakeParticleStreamWidth; } /** * Get particle stream height * * @return particle stream height */ int BrookShakeAlgorithm::getShakeParticleStreamHeight( void ) const { return _shakeParticleStreamHeight; } /** * Get Constraint stream size * * @return Constraint stream size * */ int BrookShakeAlgorithm::getShakeConstraintStreamSize( void ) const { return _shakeConstraintStreamSize; } /** * Get constraint stream width * * @return constraint stream width * */ int BrookShakeAlgorithm::getShakeConstraintStreamWidth( void ) const { return _shakeConstraintStreamWidth; } /** * Get constraint stream height * * @return constraint stream height */ int BrookShakeAlgorithm::getShakeConstraintStreamHeight( void ) const { return _shakeConstraintStreamHeight; } /** * Get Shake particle indices stream * * @return Shake particle indices stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeParticleIndicesStream( void ) const { return _shakeStreams[ShakeParticleIndicesStream]; } /** * Get Shake particle parameter stream * * @return Shake particle parameter sStream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeParticleParameterStream( void ) const { return _shakeStreams[ShakeParticleParameterStream]; } /** * Get Shake XCons0 stream * * @return XCons0 stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeXCons0Stream( void ) const { return _shakeStreams[ShakeXCons0Stream]; } /** * Get Shake XCons1 stream * * @return XCons1 stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeXCons1Stream( void ) const { return _shakeStreams[ShakeXCons1Stream]; } /** * Get Shake XCons2 stream * * @return XCons2 stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeXCons2Stream( void ) const { return _shakeStreams[ShakeXCons2Stream]; } /** * Get Shake XCons3 stream * * @return XCons3 stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeXCons3Stream( void ) const { return _shakeStreams[ShakeXCons3Stream]; } /** * Get Shake inverse map stream * * @return Shake inverse map stream * */ BrookFloatStreamInternal* BrookShakeAlgorithm::getShakeInverseMapStream( void ) const { return _shakeStreams[ShakeInverseMapStream]; } /** * Initialize stream dimensions * * @param numberOfParticles number of particles * @param numberOfConstraints number of constraints * @param platform platform * * @return ErrorReturnValue if error, else DefaultReturnValue * */ int BrookShakeAlgorithm::_initializeStreamSizes( int numberOfParticles, int numberOfConstraints, const Platform& platform ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookShakeAlgorithm::_initializeStreamSizes"; // --------------------------------------------------------------------------------------- _shakeParticleStreamSize = getParticleStreamSize( platform ); _shakeParticleStreamWidth = getParticleStreamWidth( platform ); _shakeParticleStreamHeight = getParticleStreamHeight( platform ); // get constraint stream width & height, and then set stream size to the product BrookCommon::getStreamDimensions( numberOfConstraints, &_shakeConstraintStreamWidth, &_shakeConstraintStreamHeight ); _shakeConstraintStreamSize = _shakeConstraintStreamWidth*_shakeConstraintStreamHeight; return DefaultReturnValue; } /** * Initialize streams * * @param platform platform * * @return ErrorReturnValue if error, else DefaultReturnValue * */ int BrookShakeAlgorithm::_initializeStreams( const Platform& platform ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookShakeAlgorithm::_initializeStreams"; BrookOpenMMFloat dangleValue = static_cast( 0.0 ); // --------------------------------------------------------------------------------------- int shakeParticleStreamSize = getShakeParticleStreamSize(); int shakeParticleStreamWidth = getShakeParticleStreamWidth(); int shakeConstraintStreamSize = getShakeConstraintStreamSize(); int shakeConstraintStreamWidth = getShakeConstraintStreamWidth(); _shakeStreams[ShakeParticleIndicesStream] = new BrookFloatStreamInternal( BrookCommon::ShakeParticleIndicesStream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float4, dangleValue ); _shakeStreams[ShakeParticleParameterStream] = new BrookFloatStreamInternal( BrookCommon::ShakeParticleParameterStream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float4, dangleValue ); _shakeStreams[ShakeXCons0Stream] = new BrookFloatStreamInternal( BrookCommon::ShakeXCons0Stream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float3, dangleValue ); _shakeStreams[ShakeXCons1Stream] = new BrookFloatStreamInternal( BrookCommon::ShakeXCons1Stream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float3, dangleValue ); _shakeStreams[ShakeXCons2Stream] = new BrookFloatStreamInternal( BrookCommon::ShakeXCons2Stream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float3, dangleValue ); _shakeStreams[ShakeXCons3Stream] = new BrookFloatStreamInternal( BrookCommon::ShakeXCons3Stream, shakeConstraintStreamSize, shakeConstraintStreamWidth, BrookStreamInternal::Float3, dangleValue ); _shakeStreams[ShakeInverseMapStream] = new BrookFloatStreamInternal( BrookCommon::ShakeInverseMapStream, shakeParticleStreamSize, shakeParticleStreamWidth, BrookStreamInternal::Float2, dangleValue ); return DefaultReturnValue; } /* * Set Shake streams * * @param masses masses * @param constraintIndices constraint particle indices * @param constraintLengths constraint lengths * @param platform platform reference * * @return ErrorReturnValue if error * * @throw OpenMMException if constraintIndices.size() != constraintLengths.size() * */ int BrookShakeAlgorithm::_setShakeStreams( const std::vector& masses, const std::vector< std::vector >& constraintIndices, const std::vector& constraintLengths, const Platform& platform ){ // --------------------------------------------------------------------------------------- BrookOpenMMFloat one = static_cast( 1.0 ); BrookOpenMMFloat half = static_cast( 0.5 ); static const std::string methodName = "BrookShakeAlgorithm::_updateSdStreams"; // --------------------------------------------------------------------------------------- FILE* log = getLog(); // check that number of constraints for two input vectors is consistent if( constraintIndices.size() != constraintLengths.size() ){ std::stringstream message; message << methodName << " constraintIndices size=" << constraintIndices.size() << " does not equal constraintLengths size=" << constraintLengths.size(); throw OpenMMException( message.str() ); return ErrorReturnValue; } // get constraint count for each atom vector constraintCount( masses.size(), 0); std::vector< std::vector >::const_iterator particleIterator = constraintIndices.begin(); while( particleIterator != constraintIndices.end() ){ std::vector particleVector = *particleIterator; int atomI = particleVector[0]; int atomJ = particleVector[1]; // check that atom indices are not out of range if( atomI < 0 || atomI > (int) masses.size() ){ std::stringstream message; message << methodName << " constraint I-index=" << atomI << " is out of range [0, " << masses.size() << "]" << std::endl; throw OpenMMException( message.str() ); return ErrorReturnValue; } if( atomJ < 0 || atomJ > (int) masses.size() ){ std::stringstream message; message << methodName << " constraint J-index=" << atomJ << " is out of range [0, " << masses.size() << "]" << std::endl; throw OpenMMException( message.str() ); return ErrorReturnValue; } constraintCount[atomI]++; constraintCount[atomJ]++; particleIterator++; } _numberOfConstraints = static_cast(constraintIndices.size()); if( _numberOfConstraints < 1 )return DefaultReturnValue; // Find clusters consisting of a central atom with up to three peripheral atoms. particleIterator = constraintIndices.begin(); std::vector::const_iterator distanceIterator = constraintLengths.begin(); while( particleIterator != constraintIndices.end() ){ float distance = static_cast( *distanceIterator ); std::vector particleVector = *particleIterator; int atomI = particleVector[0]; int atomJ = particleVector[1]; // Determine the central atom. bool firstIsCentral; if( constraintCount[atomI] > 1 ){ firstIsCentral = true; } else if( constraintCount[atomJ] > 1 ){ firstIsCentral = false; } else if( atomI < atomJ ){ firstIsCentral = true; } else { firstIsCentral = false; } int centralID, peripheralID; float centralInvMass, peripheralInvMass; if( firstIsCentral ){ centralID = atomI; peripheralID = atomJ; centralInvMass = static_cast( masses[atomI] ); peripheralInvMass = static_cast( masses[atomJ] ); } else { centralID = atomJ; peripheralID = atomI; centralInvMass = static_cast( masses[atomJ] ); peripheralInvMass = static_cast( masses[atomI] ); } if( constraintCount[peripheralID] != 1 ){ throw OpenMMException("Only bonds to hydrogens may be constrained"); } // Add it to the cluster if( _clusters.find(centralID) == _clusters.end() ){ _clusters[centralID] = ShakeCluster( centralID, 1.0f/centralInvMass ); } _clusters[centralID].addAtom( peripheralID, distance, 1.0f/peripheralInvMass ); particleIterator++; distanceIterator++; } // allocate space for streams _initializeStreamSizes( (int) masses.size(), (int) _clusters.size(), platform ); _initializeStreams( platform ); int shakeParticleStreamSize = getShakeParticleStreamSize(); int shakeConstraintStreamSize = getShakeConstraintStreamSize(); // allocate arrays to be read down to board and initialize BrookOpenMMFloat* particleIndices = new BrookOpenMMFloat[4*shakeConstraintStreamSize]; BrookOpenMMFloat* shakeParameters = new BrookOpenMMFloat[4*shakeConstraintStreamSize]; BrookOpenMMFloat minusOne = static_cast(-1.0); for( int ii = 0; ii < 4*shakeConstraintStreamSize; ii++ ){ particleIndices[ii] = minusOne; } memset( shakeParameters, 0, 4*shakeConstraintStreamSize*sizeof( BrookOpenMMFloat ) ); // load indices & parameters int constraintIndex = 0; for( map::const_iterator iter = _clusters.begin(); iter != _clusters.end(); ++iter ){ const ShakeCluster& cluster = iter->second; particleIndices[constraintIndex] = static_cast( cluster._centralID ); for( int ii = 0; ii < cluster._size; ii++ ){ particleIndices[constraintIndex+ii+1] = static_cast( cluster._peripheralID[ii] ); } shakeParameters[constraintIndex] = static_cast( cluster._centralInvMass ); shakeParameters[constraintIndex+1] = half/( static_cast( cluster._centralInvMass + cluster._peripheralInvMass ) ); shakeParameters[constraintIndex+2] = static_cast( cluster._distance*cluster._distance ); shakeParameters[constraintIndex+3] = static_cast( cluster._peripheralInvMass ); constraintIndex += 4; } // write entries to board _shakeStreams[ShakeParticleIndicesStream]->loadFromArray( particleIndices ); _shakeStreams[ShakeParticleParameterStream]->loadFromArray( shakeParameters ); delete[] shakeParameters; // initialize inverse map BrookOpenMMFloat* inverseMap = new BrookOpenMMFloat[2*shakeParticleStreamSize]; for( int ii = 0; ii < shakeParticleStreamSize*2; ii++ ){ inverseMap[ii] = static_cast(-1.0); } // build inverse map for( int ii = 0; ii < shakeConstraintStreamSize; ii++ ){ int ii4 = ii << 2; for( int jj = 0; jj < 4; jj++ ){ if( particleIndices[ii4+jj] > -1.0f ){ int particleIndex = (int) (particleIndices[ii4+jj] + 0.001); inverseMap[particleIndex*2] = (float) ii; inverseMap[particleIndex*2+1] = (float) jj; } } } _shakeStreams[ShakeInverseMapStream]->loadFromArray( inverseMap ); delete[] particleIndices; delete[] inverseMap; return DefaultReturnValue; } /* * Setup of Shake parameters * * @param masses masses * @param constraintIndices constraint particle indices * @param constraintLengths constraint lengths * @param platform Brook platform * * @return ErrorReturnValue if error * */ int BrookShakeAlgorithm::setup( const std::vector& masses, const std::vector >& constraintIndices, const std::vector& constraintLengths, const Platform& platform ){ // --------------------------------------------------------------------------------------- //static const std::string methodName = "BrookShakeAlgorithm::setup"; // --------------------------------------------------------------------------------------- int numberOfParticles = (int) masses.size(); setNumberOfParticles( numberOfParticles ); _setShakeStreams( masses, constraintIndices, constraintLengths, platform ); return DefaultReturnValue; } /* * Check constraints * * @param positions atom positions * @param outputString output message * @param tolerance tolerance to compare (if < 0, then use algorithm tolerance * * @return number of errors * */ int BrookShakeAlgorithm::checkConstraints( BrookStreamInternal* positions, std::string& outputString, float tolerance ) const { // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookShakeAlgorithm::checkConstraints"; static const int maxErrorToPrint = -10; // --------------------------------------------------------------------------------------- void* posArrayV = positions->getData( 1 ); const float* posArray = (float*) posArrayV; /* fprintf( log, "ShakeCoords\n" ); for( int ii = 0; ii < 30; ii++ ){ if( !(ii % 3 ) )fprintf( log, "%d [", ii ); fprintf( log, "%16.7e ", posArray[ii] ); if( !(ii % 2 ) )fprintf( log, "]\n", posArray[ii] ); } */ // loop over constraints checking if distances are satisfied // build up message string if errors are detected // also track max difference in case all constraints satisfied // to within specified tolerance std::stringstream message; int errors = 0; float maxDiff = -1.0f; int maxDiffCentralIndex = -1; int maxDiffPeripheralIndex = -1; tolerance = tolerance > 0.0f ? tolerance : _shakeTolerance; for( map::const_iterator iter = _clusters.begin(); iter != _clusters.end(); ++iter ){ const ShakeCluster& cluster = iter->second; // multiply by 3 to get index into 1d array int centralAtomIndex = 3*cluster._centralID; for( int ii = 0; ii < cluster._size; ii++ ){ int peripheralAtomIndex = 3*cluster._peripheralID[ii]; if( peripheralAtomIndex > -1 && centralAtomIndex > -1 ){ float distance = sqrtf( (posArray[centralAtomIndex] - posArray[peripheralAtomIndex] )*(posArray[centralAtomIndex] - posArray[peripheralAtomIndex] ) + (posArray[centralAtomIndex+1] - posArray[peripheralAtomIndex+1])*(posArray[centralAtomIndex+1] - posArray[peripheralAtomIndex+1]) + (posArray[centralAtomIndex+2] - posArray[peripheralAtomIndex+2])*(posArray[centralAtomIndex+2] - posArray[peripheralAtomIndex+2]) ); float diff = fabsf( distance - cluster._distance ); if( diff > tolerance && (errors++ < maxErrorToPrint || maxErrorToPrint < 0) ){ char value[1024]; #ifdef _MSC_VER sprintf_s( value, 1024, "Error: Atom [%6d %6d] d[%16.7e %16.7e] diff=%16.7e [%16.7e %16.7e %16.7e] [%16.7e %16.7e %16.7e]\n", centralAtomIndex/3, peripheralAtomIndex/3, distance, cluster._distance, diff, posArray[centralAtomIndex], posArray[centralAtomIndex+1], posArray[centralAtomIndex+2], posArray[peripheralAtomIndex], posArray[peripheralAtomIndex+1], posArray[peripheralAtomIndex+2] ); #else sprintf( value, "Error: Atom [%6d %6d] diff=%16.7e d[%16.7e %16.7e] [%16.7e %16.7e %16.7e] [%16.7e %16.7e %16.7e]\n", centralAtomIndex/3, peripheralAtomIndex/3, diff, distance, cluster._distance, posArray[centralAtomIndex][0], posArray[centralAtomIndex][1], posArray[centralAtomIndex][2], posArray[peripheralAtomIndex][0], posArray[peripheralAtomIndex][1], posArray[peripheralAtomIndex][2] ); #endif message << value; } if( diff > maxDiff ){ maxDiffCentralIndex = centralAtomIndex/3; maxDiffPeripheralIndex = peripheralAtomIndex/3; maxDiff = diff; } } } } // report findings std::stringstream outputMessage; char text[1024]; if( errors ){ #ifdef _MSC_VER (void) sprintf_s( text, 1024, "Shake errors=%d tol=%.3e mxDff=%.3e atoms[%d %d]", errors, tolerance, maxDiff, maxDiffCentralIndex, maxDiffPeripheralIndex ); #else (void) sprintf( text, "Shake errors=%d tol=%.3e mxDff=%.3e atoms[%d %d]", errors, tolerance, maxDiff, maxDiffCentralIndex, maxDiffPeripheralIndex ); #endif outputMessage << text; if( errors >= maxErrorToPrint ){ #ifdef _MSC_VER (void) sprintf_s( text, 1024, " only printing first %d errors", maxErrorToPrint ); #else (void) sprintf( text, " only printing first %d errors", maxErrorToPrint ); #endif outputMessage << text; } outputMessage << message.str(); } else { #ifdef _MSC_VER (void) sprintf_s( text, 1024, "Shake no errors: tol=%.3e mxDff=%.3e", tolerance, maxDiff ); #else (void) sprintf( text, "Shake no errors: tol=%.3e mxDff=%.3e", tolerance, maxDiff ); #endif outputMessage << text; } outputString = outputMessage.str(); return errors; } /* * Get contents of object * * @param level level of dump * * @return string containing contents * * */ std::string BrookShakeAlgorithm::getContentsString( int level ) const { // --------------------------------------------------------------------------------------- static const std::string methodName = "BrookShakeAlgorithm::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 (void) LOCAL_SPRINTF( value, "%d", getNumberOfConstraints() ); message << _getLine( tab, "Number of constraints:", value ); (void) LOCAL_SPRINTF( value, "%d", getNumberOfParticles() ); message << _getLine( tab, "Number of particles:", value ); (void) LOCAL_SPRINTF( value, "%d", getMaxIterations() ); message << _getLine( tab, "Max iterations:", value ); (void) LOCAL_SPRINTF( value, "%2e", getShakeTolerance() ); message << _getLine( tab, "Tolerance:", value ); (void) LOCAL_SPRINTF( value, "%d", getParticleStreamWidth() ); message << _getLine( tab, "Particle stream width:", value ); (void) LOCAL_SPRINTF( value, "%d", getParticleStreamHeight() ); message << _getLine( tab, "Particle stream height:", value ); (void) LOCAL_SPRINTF( value, "%d", getParticleStreamSize() ); message << _getLine( tab, "Particle stream size:", value ); (void) LOCAL_SPRINTF( value, "%d", getShakeConstraintStreamWidth() ); message << _getLine( tab, "Constraint stream width:", value ); (void) LOCAL_SPRINTF( value, "%d", getShakeConstraintStreamHeight() ); message << _getLine( tab, "Constraint stream height:", value ); (void) LOCAL_SPRINTF( value, "%d", getShakeConstraintStreamSize() ); message << _getLine( tab, "Constraint stream size:", value ); message << _getLine( tab, "Constraints:", " " ); int index = 0; for( map::const_iterator iter = _clusters.begin(); iter != _clusters.end(); ++iter ){ char buffer[1024]; const ShakeCluster& cluster = iter->second; #ifdef _MSC_VER sprintf_s( buffer, 1024, "%5d %6d [%6d %6d %6d] d=%.3f m[%12.5f %12.5f]", index++, cluster._centralID, cluster._peripheralID[0], cluster._peripheralID[1], cluster._peripheralID[2], cluster._distance, cluster._centralInvMass, cluster._peripheralInvMass ); #endif message << _getLine( tab, " ", buffer ); } message << _getLine( tab, "Log:", (getLog() ? Set : NotSet) ); message << _getLine( tab, "ParticleIndices:", (getShakeParticleIndicesStream() ? Set : NotSet) ); message << _getLine( tab, "ParticleParameters:", (getShakeParticleParameterStream() ? Set : NotSet) ); message << _getLine( tab, "XCons0:", (getShakeXCons0Stream() ? Set : NotSet) ); message << _getLine( tab, "XCons1:", (getShakeXCons1Stream() ? Set : NotSet) ); message << _getLine( tab, "XCons2:", (getShakeXCons2Stream() ? Set : NotSet) ); message << _getLine( tab, "XCons3:", (getShakeXCons3Stream() ? Set : NotSet) ); message << _getLine( tab, "InverseMap:", (getShakeInverseMapStream() ? Set : NotSet) ); for( int ii = 0; ii < LastStreamIndex; ii++ ){ message << std::endl; if( _shakeStreams[ii] ){ message << _shakeStreams[ii]->getContentsString( ); } } #undef LOCAL_SPRINTF return message.str(); }