OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
cOHz.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 "applications/dynamicProps/cOHz.hpp"
49
50#include <sstream>
51
53#include "utils/Revision.hpp"
54#include "utils/simError.h"
55
56namespace OpenMD {
57 COHZ::COHZ(SimInfo* info, const std::string& filename,
58 const std::string& sele1, const std::string& sele2, int order,
59 int nZbins, int axis) :
60 MoleculeACF<Vector<RealType, 4>>(info, filename, sele1, sele2),
61 nZBins_(nZbins), axis_(axis) {
62 setCorrFuncType("Legendre Correlation Function");
63 setOutputName(getPrefix(dumpFilename_) + ".lcorr");
64
65 std::stringstream params;
66 params << " order = " << order << ", nzbins = " << nZBins_;
67 const std::string paramString = params.str();
68 setParameterString(paramString);
69
70 if (!uniqueSelections_) { seleMan2_ = seleMan1_; }
71
72 // Compute complementary axes to the privileged axis
73 xaxis_ = (axis_ + 1) % 3;
74 yaxis_ = (axis_ + 2) % 3;
75
76 switch (axis_) {
77 case 0:
78 axisLabel_ = "x";
79 break;
80 case 1:
81 axisLabel_ = "y";
82 break;
83 case 2:
84 default:
85 axisLabel_ = "z";
86 break;
87 }
88
89 rotMats_.resize(nTimeBins_);
90 zbin_.resize(nTimeBins_);
91 histogram_.resize(nTimeBins_);
92 counts_.resize(nTimeBins_);
93 for (unsigned int i = 0; i < nTimeBins_; i++) {
94 histogram_[i].resize(nZBins_);
95 std::fill(histogram_[i].begin(), histogram_[i].end(),
96 Vector<RealType, 4>(0.0));
97 counts_[i].resize(nZBins_);
98 std::fill(counts_[i].begin(), counts_[i].end(), 0);
99 }
100 LegendrePolynomial polynomial(order);
101 legendre_ = polynomial.getLegendrePolynomial(order);
102 }
103
104 void COHZ::computeFrame(int frame) {
105 Mat3x3d hmat = currentSnapshot_->getHmat();
106 boxZ_ = hmat(axis_, axis_);
107 halfBoxZ_ = boxZ_ / 2.0;
108
109 MoleculeACF<Vector<RealType, 4>>::computeFrame(frame);
110 }
111
112 int COHZ::computeProperty1(int frame, Molecule* mol) {
113 RotMat3x3d A = mol->getRigidBodyAt(0)->getA();
114 rotMats_[frame].push_back(A);
115
116 Vector3d pos = mol->getCom();
117 if (info_->getSimParams()->getUsePeriodicBoundaryConditions())
118 currentSnapshot_->wrapVector(pos);
119 int zBin = int(nZBins_ * (halfBoxZ_ + pos[axis_]) / boxZ_);
120 zbin_[frame].push_back(zBin);
121
122 return rotMats_[frame].size() - 1;
123 }
124
125 Vector<RealType, 4> COHZ::calcCorrVal(int frame1, int frame2, int id1,
126 int id2) {
127 // Vectors v1x, v1y, and v1z are the body-fixed axes on the
128 // molecule in frame 1 in the laboratory frame.
129
130 // Vectors v2x, v2y, and v2z are the body-fixed axes on the
131 // molecule in frame 2 in the laboratory frame.
132
133 // Vectors u1 & u2 are the first OH bond vector in frames 1 & 2
134 // respectively. Here we assume SPC/E geometry.
135
136 // Vectors w1 & w2 are the second OH bond vector in frames 1 & 2
137 // respectively. Here we assume SPC/E geometry.
138
139 // Vectors h1 & h2 are the HH bond vectors in frames 1 & 2
140 // respectively. Here we assume SPC/E geometry again.
141
142 // Vector3d v1x = sd1->getA(frame1).getRow(0);
143 // Vector3d v2x = sd2->getA(frame2).getRow(0);
144
145 Vector3d v1y = rotMats_[frame1][id1].getRow(yaxis_);
146 Vector3d v1z = rotMats_[frame1][id1].getRow(axis_);
147
148 Vector3d v2y = rotMats_[frame2][id2].getRow(yaxis_);
149 Vector3d v2z = rotMats_[frame2][id2].getRow(axis_);
150
151 Vector3d u1 = 0.81649 * v1y + 0.57736 * v1z;
152 Vector3d u2 = 0.81649 * v2y + 0.57736 * v2z;
153
154 Vector3d w1 = -0.81649 * v1y + 0.57736 * v1z;
155 Vector3d w2 = -0.81649 * v2y + 0.57736 * v2z;
156
157 Vector3d h1 = 1.63298 * v1y;
158 Vector3d h2 = 1.63298 * v2y;
159
160 // result is a Vector<RealType, 4> with Dipole, OH1, OH2, and HH:
161 Vector<RealType, 4> r(0.0);
162 r[0] = legendre_.evaluate(dot(v1z, v2z) / (v1z.length() * v2z.length()));
163 r[1] = legendre_.evaluate(dot(u1, u2) / (u1.length() * u2.length()));
164 r[2] = legendre_.evaluate(dot(w1, w2) / (w1.length() * w2.length()));
165 r[3] = legendre_.evaluate(dot(h1, h2) / (h1.length() * h2.length()));
166 return r;
167 }
168
169 void COHZ::correlateFrames(int frame1, int frame2, int timeBin) {
170 std::vector<int> s1;
171 std::vector<int> s2;
172
173 std::vector<int>::iterator i1;
174 std::vector<int>::iterator i2;
175
176 Vector<RealType, 4> corrVal(0.0);
177
178 s1 = sele1ToIndex_[frame1];
179
180 if (uniqueSelections_)
181 s2 = sele2ToIndex_[frame2];
182 else
183 s2 = sele1ToIndex_[frame2];
184
185 for (i1 = s1.begin(), i2 = s2.begin(); i1 != s1.end() && i2 != s2.end();
186 ++i1, ++i2) {
187 // If the selections are dynamic, they might not have the
188 // same objects in both frames, so we need to roll either of
189 // the selections until we have the same object to
190 // correlate.
191
192 while (i1 != s1.end() && *i1 < *i2) {
193 ++i1;
194 }
195
196 while (i2 != s2.end() && *i2 < *i1) {
197 ++i2;
198 }
199
200 if (i1 == s1.end() || i2 == s2.end()) break;
201
202 corrVal = calcCorrVal(frame1, frame2, i1 - s1.begin(), i2 - s2.begin());
203 int zBin = zbin_[frame1][i1 - s1.begin()];
204
205 histogram_[timeBin][zBin] += corrVal;
206 counts_[timeBin][zBin]++;
207 }
208 }
209
210 void COHZ::postCorrelate() {
211 for (unsigned int i = 0; i < nTimeBins_; ++i) {
212 for (unsigned int j = 0; j < nZBins_; ++j) {
213 if (counts_[i][j] > 0) { histogram_[i][j] /= counts_[i][j]; }
214 }
215 }
216 }
217
218 void COHZ::validateSelection(SelectionManager&) {
219 Molecule* mol;
220 int i;
221 for (mol = seleMan1_.beginSelectedMolecule(i); mol != NULL;
222 mol = seleMan1_.nextSelectedMolecule(i)) {
223 if (mol->getNRigidBodies() < 1) {
224 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
225 "COHZ::validateSelection Error: "
226 "at least one selected molecule does not have a rigid body\n");
227 painCave.isFatal = 1;
228 simError();
229 }
230 }
231 }
232
233 void COHZ::writeCorrelate() {
234 std::string Dfile = getOutputFileName() + "D";
235 std::string OHfile = getOutputFileName() + "OH";
236 std::string HHfile = getOutputFileName() + "HH";
237
238 std::ofstream ofs1(Dfile.c_str());
239 std::ofstream ofs2(OHfile.c_str());
240 std::ofstream ofs3(HHfile.c_str());
241
242 if (ofs1.is_open()) {
243 Revision r;
244
245 ofs1 << "# " << getCorrFuncType() << " for dipole vectors in water\n";
246 ofs1 << "# OpenMD " << r.getFullRevision() << "\n";
247 ofs1 << "# " << r.getBuildDate() << "\n";
248 ofs1 << "# selection script1: \"" << selectionScript1_;
249 ofs1 << "\"\tselection script2: \"" << selectionScript2_ << "\"\n";
250 ofs1 << "# privilegedAxis computed as " << axisLabel_ << " axis \n";
251 if (!paramString_.empty())
252 ofs1 << "# parameters: " << paramString_ << "\n";
253
254 ofs1 << "#time\tPn(costheta_z)\n";
255
256 for (unsigned int i = 0; i < nTimeBins_; ++i) {
257 ofs1 << times_[i] - times_[0];
258
259 for (unsigned int j = 0; j < nZBins_; ++j) {
260 ofs1 << "\t" << histogram_[i][j][0];
261 }
262 ofs1 << "\n";
263 }
264
265 } else {
266 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
267 "COHz::writeCorrelate Error: failed to open %s\n",
268 Dfile.c_str());
269 painCave.isFatal = 1;
270 simError();
271 }
272 ofs1.close();
273
274 if (ofs2.is_open()) {
275 Revision r;
276
277 ofs2 << "# " << getCorrFuncType() << " for OH bond vectors in water\n";
278 ofs2 << "# OpenMD " << r.getFullRevision() << "\n";
279 ofs2 << "# " << r.getBuildDate() << "\n";
280 ofs2 << "# selection script1: \"" << selectionScript1_;
281 ofs2 << "\"\tselection script2: \"" << selectionScript2_ << "\"\n";
282 ofs2 << "# privilegedAxis computed as " << axisLabel_ << " axis \n";
283 if (!paramString_.empty())
284 ofs2 << "# parameters: " << paramString_ << "\n";
285
286 ofs2 << "#time\tPn(costheta_z)\n";
287
288 for (unsigned int i = 0; i < nTimeBins_; ++i) {
289 ofs2 << times_[i] - times_[0];
290
291 for (unsigned int j = 0; j < nZBins_; ++j) {
292 ofs2 << "\t" << 0.5 * (histogram_[i][j][1] + histogram_[i][j][2]);
293 }
294 ofs2 << "\n";
295 }
296
297 } else {
298 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
299 "COHz::writeCorrelate Error: failed to open %s\n",
300 OHfile.c_str());
301 painCave.isFatal = 1;
302 simError();
303 }
304 ofs2.close();
305
306 if (ofs3.is_open()) {
307 Revision r;
308
309 ofs3 << "# " << getCorrFuncType() << " for HH bond vectors in water\n";
310 ofs3 << "# OpenMD " << r.getFullRevision() << "\n";
311 ofs3 << "# " << r.getBuildDate() << "\n";
312 ofs3 << "# selection script1: \"" << selectionScript1_;
313 ofs3 << "\"\tselection script2: \"" << selectionScript2_ << "\"\n";
314 ofs3 << "# privilegedAxis computed as " << axisLabel_ << " axis \n";
315 if (!paramString_.empty())
316 ofs3 << "# parameters: " << paramString_ << "\n";
317
318 ofs3 << "#time\tPn(costheta_z)\n";
319
320 for (unsigned int i = 0; i < nTimeBins_; ++i) {
321 ofs3 << times_[i] - times_[0];
322
323 for (unsigned int j = 0; j < nZBins_; ++j) {
324 ofs3 << "\t" << histogram_[i][j][3];
325 }
326 ofs3 << "\n";
327 }
328
329 } else {
330 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
331 "COHz::writeCorrelate Error: failed to open %s\n",
332 HHfile.c_str());
333 painCave.isFatal = 1;
334 simError();
335 }
336 ofs3.close();
337 }
338} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
Fix length vector class.
Definition Vector.hpp:81
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)