OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
RestWriter.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#include "io/RestWriter.hpp"
49
50#include <iostream>
51#include <sstream>
52#include <string>
53
54#ifdef IS_MPI
55#include <mpi.h>
56#endif
57
59#include "utils/simError.h"
60
61namespace OpenMD {
62 RestWriter::RestWriter(SimInfo* info, const std::string& filename,
63 std::vector<Restraint*> restraints) :
64 info_(info) {
65 std::vector<Restraint*>::const_iterator resti;
66
67 createRestFile_ = false;
68
69#ifdef IS_MPI
70 MPI_Status istatus;
71#endif
72
73 int printAny = 0;
74 for (resti = restraints.begin(); resti != restraints.end(); ++resti) {
75 if ((*resti)->getPrintRestraint()) { printAny = 1; }
76 }
77
78#ifdef IS_MPI
79 MPI_Allreduce(MPI_IN_PLACE, &printAny, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
80#endif
81
82 if (printAny) createRestFile_ = true;
83
84#ifdef IS_MPI
85 if (worldRank == 0) {
86#endif
87
88 if (createRestFile_) {
89 output_ = new std::ofstream(filename.c_str());
90
91 if (!output_) {
92 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
93 "Could not open %s for restraint output.\n",
94 filename.c_str());
95 painCave.isFatal = 1;
96 simError();
97 }
98 }
99
100#ifdef IS_MPI
101 }
102#endif // is_mpi
103
104#ifndef IS_MPI
105
106 if (createRestFile_) (*output_) << "#time\t";
107
108 for (resti = restraints.begin(); resti != restraints.end(); ++resti) {
109 if ((*resti)->getPrintRestraint()) {
110 std::string myName = (*resti)->getRestraintName();
111 int myType = (*resti)->getRestraintType();
112
113 (*output_) << myName << ":";
114
115 if (myType & Restraint::rtDisplacement)
116 (*output_) << "\tPosition(angstroms)\tEnergy(kcal/mol)";
117
118 if (myType & Restraint::rtAbsoluteZ)
119 (*output_) << "\tPosition(angstroms)\tEnergy(kcal/mol)";
120
121 if (myType & Restraint::rtTwist)
122 (*output_) << "\tTwistAngle(radians)\tEnergy(kcal/mol)";
123
124 if (myType & Restraint::rtSwingX)
125 (*output_) << "\tSwingXAngle(radians)\tEnergy(kcal/mol)";
126
127 if (myType & Restraint::rtSwingY)
128 (*output_) << "\tSwingYAngle(radians)\tEnergy(kcal/mol)";
129 }
130 }
131
132 if (createRestFile_) (*output_) << "\n";
133 if (createRestFile_) (*output_).flush();
134
135#else
136
137 std::string buffer;
138
139 for (resti = restraints.begin(); resti != restraints.end(); ++resti) {
140 if ((*resti)->getPrintRestraint()) {
141 std::string myName = (*resti)->getRestraintName();
142 int myType = (*resti)->getRestraintType();
143
144 buffer += (myName + ":");
145
146 if (myType & Restraint::rtDisplacement)
147 buffer += "\tPosition(angstroms)\tEnergy(kcal/mol)";
148
149 if (myType & Restraint::rtAbsoluteZ)
150 buffer += "\tPosition(angstroms)\tEnergy(kcal/mol)";
151
152 if (myType & Restraint::rtTwist)
153 buffer += "\tTwistAngle(radians)\tEnergy(kcal/mol)";
154
155 if (myType & Restraint::rtSwingX)
156 buffer += "\tSwingXAngle(radians)\tEnergy(kcal/mol)";
157
158 if (myType & Restraint::rtSwingY)
159 buffer += "\tSwingYAngle(radians)\tEnergy(kcal/mol)";
160
161 buffer += "\n";
162 }
163 }
164
165 const int primaryNode = 0;
166
167 if (worldRank == primaryNode) {
168 if (createRestFile_) (*output_) << "#time\t";
169 if (createRestFile_) (*output_) << buffer;
170
171 int nProc;
172 MPI_Comm_size(MPI_COMM_WORLD, &nProc);
173
174 for (int i = 1; i < nProc; ++i) {
175 // receive the length of the string buffer that was
176 // prepared by processor i
177
178 int recvLength;
179 MPI_Recv(&recvLength, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &istatus);
180 char* recvBuffer = new char[recvLength];
181 if (recvBuffer == NULL) {
182 } else {
183 MPI_Recv(recvBuffer, recvLength, MPI_CHAR, i, 0, MPI_COMM_WORLD,
184 &istatus);
185 if (createRestFile_) (*output_) << recvBuffer;
186 delete[] recvBuffer;
187 }
188 }
189 if (createRestFile_) (*output_).flush();
190 } else {
191 int sendBufferLength = buffer.size() + 1;
192 MPI_Send(&sendBufferLength, 1, MPI_INT, primaryNode, 0, MPI_COMM_WORLD);
193 MPI_Send((void*)buffer.c_str(), sendBufferLength, MPI_CHAR, primaryNode,
194 0, MPI_COMM_WORLD);
195 }
196
197#endif // is_mpi
198 }
199
200 void RestWriter::writeRest(
201 std::vector<std::map<int, Restraint::RealPair>> restInfo) {
202#ifdef IS_MPI
203 MPI_Status istatus;
204#endif
205
206#ifndef IS_MPI
207 if (createRestFile_)
208 (*output_)
209 << info_->getSnapshotManager()->getCurrentSnapshot()->getTime();
210
211 // output some information about the molecules
212 std::vector<std::map<int, Restraint::RealPair>>::const_iterator i;
213 std::map<int, Restraint::RealPair>::const_iterator j;
214
215 if (createRestFile_) {
216 for (i = restInfo.begin(); i != restInfo.end(); ++i) {
217 for (j = (*i).begin(); j != (*i).end(); ++j) {
218 (*output_) << "\t" << (j->second).first << "\t" << (j->second).second;
219 }
220 (*output_) << std::endl;
221 }
222 (*output_).flush();
223 }
224#else
225 std::string buffer, first, second;
226 std::stringstream ss;
227
228 std::vector<std::map<int, Restraint::RealPair>>::const_iterator i;
229 std::map<int, Restraint::RealPair>::const_iterator j;
230
231 if (createRestFile_) {
232 for (i = restInfo.begin(); i != restInfo.end(); ++i) {
233 for (j = (*i).begin(); j != (*i).end(); ++j) {
234 ss.clear();
235 ss << (j->second).first;
236 ss >> first;
237 ss.clear();
238 ss << (j->second).second;
239 ss >> second;
240 buffer += ("\t" + first + "\t" + second);
241 }
242 buffer += "\n";
243 }
244 }
245
246 const int primaryNode = 0;
247
248 if (createRestFile_) {
249 if (worldRank == primaryNode) {
250 (*output_)
251 << info_->getSnapshotManager()->getCurrentSnapshot()->getTime();
252 (*output_) << buffer;
253
254 int nProc;
255 MPI_Comm_size(MPI_COMM_WORLD, &nProc);
256 for (int i = 1; i < nProc; ++i) {
257 // receive the length of the string buffer that was
258 // prepared by processor i
259
260 int recvLength;
261 MPI_Recv(&recvLength, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &istatus);
262 char* recvBuffer = new char[recvLength];
263 if (recvBuffer == NULL) {
264 } else {
265 MPI_Recv(recvBuffer, recvLength, MPI_CHAR, i, 0, MPI_COMM_WORLD,
266 &istatus);
267 if (createRestFile_) (*output_) << recvBuffer;
268
269 delete[] recvBuffer;
270 }
271 }
272 (*output_).flush();
273 } else {
274 int sendBufferLength = buffer.size() + 1;
275 MPI_Send(&sendBufferLength, 1, MPI_INT, primaryNode, 0, MPI_COMM_WORLD);
276 MPI_Send((void*)buffer.c_str(), sendBufferLength, MPI_CHAR, primaryNode,
277 0, MPI_COMM_WORLD);
278 }
279 }
280#endif // is_mpi
281 }
282
283 RestWriter::~RestWriter() {
284#ifdef IS_MPI
285
286 if (worldRank == 0) {
287#endif // is_mpi
288 if (createRestFile_) {
289 writeClosing(*output_);
290 delete output_;
291 }
292#ifdef IS_MPI
293 }
294#endif // is_mpi
295 }
296
297 void RestWriter::writeClosing(std::ostream& os) { os.flush(); }
298
299} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.