--- trunk/src/io/RestWriter.cpp 2009/09/07 16:31:51 1360 +++ trunk/src/io/RestWriter.cpp 2010/05/10 17:28:26 1442 @@ -6,19 +6,10 @@ * redistribute this software in source and binary code form, provided * that the following conditions are met: * - * 1. Acknowledgement of the program authors must be made in any - * publication of scientific results based in part on use of the - * program. An acceptable form of acknowledgement is citation of - * the article in which the program was described (Matthew - * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher - * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented - * Parallel Simulation Engine for Molecular Dynamics," - * J. Comput. Chem. 26, pp. 252-271 (2005)) - * - * 2. Redistributions of source code must retain the above copyright + * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - * 3. Redistributions in binary form must reproduce the above copyright + * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. @@ -37,9 +28,20 @@ * arising out of the use of or inability to use software, even if the * University of Notre Dame has been advised of the possibility of * such damages. + * + * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your + * research, please cite the appropriate papers when you publish your + * work. Good starting points are: + * + * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005). + * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006). + * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008). + * [4] Vardeman & Gezelter, in progress (2009). */ +#include +#include #include #include "io/RestWriter.hpp" @@ -49,18 +51,18 @@ #include #endif -namespace oopse { +namespace OpenMD { RestWriter::RestWriter(SimInfo* info, const std::string& filename, std::vector restraints ) : info_(info){ - - //use master - slave mode, only master node writes to disk + createRestFile_ = true; + #ifdef IS_MPI if(worldRank == 0){ #endif - - output_.open(filename.c_str()); - + + output_ = new std::ofstream(filename.c_str()); + if(!output_){ sprintf( painCave.errMsg, "Could not open %s for restraint output.\n", @@ -69,60 +71,206 @@ namespace oopse { simError(); } - output_ << "#time\t"; - - // TODO: get Restraint info from slave nodes: - std::vector::const_iterator resti; - for(resti=restraints.begin(); resti != restraints.end(); ++resti){ +#ifdef IS_MPI + } +#endif // is_mpi + + +#ifdef IS_MPI + MPI_Status istatus; +#endif + +#ifndef IS_MPI + + (*output_) << "#time\t"; + + std::vector::const_iterator resti; + + for(resti=restraints.begin(); resti != restraints.end(); ++resti){ + if ((*resti)->getPrintRestraint()) { + std::string myName = (*resti)->getRestraintName(); int myType = (*resti)->getRestraintType(); - output_ << myName << ":"; + (*output_) << myName << ":"; if (myType & Restraint::rtDisplacement) - output_ << "\tPosition(angstroms)\tEnergy(kcal/mol)"; + (*output_) << "\tPosition(angstroms)\tEnergy(kcal/mol)"; if (myType & Restraint::rtTwist) - output_ << "\tTwistAngle(radians)\tEnergy(kcal/mol)"; + (*output_) << "\tTwistAngle(radians)\tEnergy(kcal/mol)"; if (myType & Restraint::rtSwingX) - output_ << "\tSwingXAngle(radians)\tEnergy(kcal/mol)"; + (*output_) << "\tSwingXAngle(radians)\tEnergy(kcal/mol)"; + + if (myType & Restraint::rtSwingY) + (*output_) << "\tSwingYAngle(radians)\tEnergy(kcal/mol)"; + } + } + + (*output_) << "\n"; + (*output_).flush(); + +#else + + std::string buffer; + + std::vector::const_iterator resti; + + for(resti=restraints.begin(); resti != restraints.end(); ++resti){ + if ((*resti)->getPrintRestraint()) { + std::string myName = (*resti)->getRestraintName(); + int myType = (*resti)->getRestraintType(); + + buffer += (myName + ":"); + + if (myType & Restraint::rtDisplacement) + buffer += "\tPosition(angstroms)\tEnergy(kcal/mol)"; + + if (myType & Restraint::rtTwist) + buffer += "\tTwistAngle(radians)\tEnergy(kcal/mol)"; + + if (myType & Restraint::rtSwingX) + buffer += "\tSwingXAngle(radians)\tEnergy(kcal/mol)"; + if (myType & Restraint::rtSwingY) - output_ << "\tSwingYAngle(radians)\tEnergy(kcal/mol)"; + buffer += "\tSwingYAngle(radians)\tEnergy(kcal/mol)"; + buffer += "\n"; } - output_ << "\n"; -#ifdef IS_MPI } -#endif - } + + const int masterNode = 0; + + if (worldRank == masterNode) { + (*output_) << "#time\t"; + (*output_) << buffer; + + int nProc; + MPI_Comm_size(MPI_COMM_WORLD, &nProc); + for (int i = 1; i < nProc; ++i) { + + // receive the length of the string buffer that was + // prepared by processor i + + int recvLength; + MPI_Recv(&recvLength, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &istatus); + char* recvBuffer = new char[recvLength]; + if (recvBuffer == NULL) { + } else { + MPI_Recv(recvBuffer, recvLength, MPI_CHAR, i, 0, MPI_COMM_WORLD, + &istatus); + (*output_) << recvBuffer; + delete [] recvBuffer; + } + } + (*output_).flush(); + } else { + int sendBufferLength = buffer.size() + 1; + MPI_Send(&sendBufferLength, 1, MPI_INT, masterNode, 0, MPI_COMM_WORLD); + MPI_Send((void *)buffer.c_str(), sendBufferLength, MPI_CHAR, masterNode, + 0, MPI_COMM_WORLD); + } + +#endif // is_mpi + + } - RestWriter::~RestWriter() { + void RestWriter::writeRest(std::vector > restInfo) { + #ifdef IS_MPI - if(worldRank == 0 ){ -#endif - output_.close(); -#ifdef IS_MPI - } + MPI_Status istatus; #endif - } - - void RestWriter::writeRest(std::vector > restInfo){ - - output_ << info_->getSnapshotManager()->getCurrentSnapshot()->getTime(); - +#ifndef IS_MPI + (*output_) << info_->getSnapshotManager()->getCurrentSnapshot()->getTime(); + // output some information about the molecules std::vector >::const_iterator i; std::map::const_iterator j; + for( i = restInfo.begin(); i != restInfo.end(); ++i){ for(j = (*i).begin(); j != (*i).end(); ++j){ - output_ << "\t" << (j->second).first << "\t" << (j->second).second; + (*output_) << "\t" << (j->second).first << "\t" << (j->second).second; } - output_ << std::endl; + (*output_) << std::endl; } + (*output_).flush(); +#else + std::string buffer, first, second; + std::stringstream ss; + + std::vector >::const_iterator i; + std::map::const_iterator j; + + for( i = restInfo.begin(); i != restInfo.end(); ++i){ + for(j = (*i).begin(); j != (*i).end(); ++j){ + ss.clear(); + ss << (j->second).first; + ss >> first; + ss.clear(); + ss << (j->second).second; + ss >> second; + buffer += ("\t" + first + "\t" + second); + } + buffer += "\n"; + } + + const int masterNode = 0; + + if (worldRank == masterNode) { + (*output_) << info_->getSnapshotManager()->getCurrentSnapshot()->getTime(); + (*output_) << buffer; + + int nProc; + MPI_Comm_size(MPI_COMM_WORLD, &nProc); + for (int i = 1; i < nProc; ++i) { + + // receive the length of the string buffer that was + // prepared by processor i + + int recvLength; + MPI_Recv(&recvLength, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &istatus); + char* recvBuffer = new char[recvLength]; + if (recvBuffer == NULL) { + } else { + MPI_Recv(recvBuffer, recvLength, MPI_CHAR, i, 0, MPI_COMM_WORLD, + &istatus); + (*output_) << recvBuffer; + + delete [] recvBuffer; + } + } + (*output_).flush(); + } else { + int sendBufferLength = buffer.size() + 1; + MPI_Send(&sendBufferLength, 1, MPI_INT, masterNode, 0, MPI_COMM_WORLD); + MPI_Send((void *)buffer.c_str(), sendBufferLength, MPI_CHAR, masterNode, + 0, MPI_COMM_WORLD); + } +#endif // is_mpi } -}// end oopse + RestWriter::~RestWriter() { + +#ifdef IS_MPI + + if (worldRank == 0) { +#endif // is_mpi + if (createRestFile_){ + writeClosing(*output_); + delete output_; + } +#ifdef IS_MPI + } +#endif // is_mpi + } + + void RestWriter::writeClosing(std::ostream& os) { + os.flush(); + } + +}// end namespace OpenMD +