OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
RippleOP.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/staticProps/RippleOP.hpp"
49
50#include "io/DumpReader.hpp"
52#include "types/MultipoleAdapter.hpp"
53#include "utils/simError.h"
54
55namespace OpenMD {
56
57 RippleOP::RippleOP(SimInfo* info, const std::string& filename,
58 const std::string& sele1, const std::string& sele2) :
59 StaticAnalyser(info, filename, 1),
60 selectionScript1_(sele1), selectionScript2_(sele2), seleMan1_(info),
61 seleMan2_(info), evaluator1_(info), evaluator2_(info) {
62 setOutputName(getPrefix(filename) + ".rp2");
63
64 evaluator1_.loadScriptString(sele1);
65 evaluator2_.loadScriptString(sele2);
66
67 if (!evaluator1_.isDynamic()) {
68 seleMan1_.setSelectionSet(evaluator1_.evaluate());
69 } else {
70 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
71 "--sele1 must be static selection\n");
72 painCave.severity = OPENMD_ERROR;
73 painCave.isFatal = 1;
74 simError();
75 }
76
77 if (!evaluator2_.isDynamic()) {
78 seleMan2_.setSelectionSet(evaluator2_.evaluate());
79 } else {
80 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
81 "--sele2 must be static selection\n");
82 painCave.severity = OPENMD_ERROR;
83 painCave.isFatal = 1;
84 simError();
85 }
86
87 if (seleMan1_.getSelectionCount() != seleMan2_.getSelectionCount()) {
88 snprintf(
89 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
90 "The number of selected Stuntdoubles are not the same in --sele1 "
91 "and sele2\n");
92 painCave.severity = OPENMD_ERROR;
93 painCave.isFatal = 1;
94 simError();
95 }
96
97 int i;
98 int j;
99 StuntDouble* sd1;
100 StuntDouble* sd2;
101 for (sd1 = seleMan1_.beginSelected(i), sd2 = seleMan2_.beginSelected(j);
102 sd1 != NULL && sd2 != NULL;
103 sd1 = seleMan1_.nextSelected(i), sd2 = seleMan2_.nextSelected(j)) {
104 sdPairs_.push_back(std::make_pair(sd1, sd2));
105 }
106 }
107
108 void RippleOP::process() {
109 StuntDouble* j1;
110 StuntDouble* j2;
111 StuntDouble* sd3;
112 bool usePeriodicBoundaryConditions_ =
113 info_->getSimParams()->getUsePeriodicBoundaryConditions();
114
115 DumpReader reader(info_, dumpFilename_);
116 int nFrames = reader.getNFrames();
117
118 for (int i = 0; i < nFrames; i += step_) {
119 reader.readFrame(i);
120 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
121 int nMolecules = info_->getNGlobalMolecules();
122 int i1;
123 int nUpper = 0;
124 int nLower = 0;
125 int nTail = 0;
126 RealType sumZ = 0.0;
127
128 for (sd3 = seleMan2_.beginSelected(i1); sd3 != NULL;
129 sd3 = seleMan2_.nextSelected(i1)) {
130 Vector3d pos1 = sd3->getPos();
131 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(pos1);
132 sd3->setPos(pos1);
133 }
134
135 for (sd3 = seleMan2_.beginSelected(i1); sd3 != NULL;
136 sd3 = seleMan2_.nextSelected(i1)) {
137 Vector3d pos1 = sd3->getPos();
138 sumZ += pos1.z();
139 }
140 RealType avgZ = sumZ / (RealType)nMolecules;
141
142 Mat3x3d orderTensorHeadUpper(0.0);
143 Mat3x3d orderTensorTail(0.0);
144 Mat3x3d orderTensorHeadLower(0.0);
145 for (j1 = seleMan1_.beginSelected(i1); j1 != NULL;
146 j1 = seleMan1_.nextSelected(i1)) {
147 Vector3d pos = j1->getPos();
148 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(pos);
149 Vector3d vecHeadUpper;
150 if (pos.z() >= avgZ) {
151 AtomType* atype1 = static_cast<Atom*>(j1)->getAtomType();
152 MultipoleAdapter ma1 = MultipoleAdapter(atype1);
153 if (ma1.isDipole())
154 vecHeadUpper = j1->getDipole();
155 else
156 vecHeadUpper = j1->getA().transpose() * V3Z;
157 nUpper++;
158 }
159 Vector3d vecHeadLower;
160 if (pos.z() <= avgZ) {
161 AtomType* atype1 = static_cast<Atom*>(j1)->getAtomType();
162 MultipoleAdapter ma1 = MultipoleAdapter(atype1);
163 if (ma1.isDipole())
164 vecHeadLower = j1->getDipole();
165 else
166 vecHeadLower = j1->getA().transpose() * V3Z;
167 nLower++;
168 }
169 orderTensorHeadUpper += outProduct(vecHeadUpper, vecHeadUpper);
170 orderTensorHeadLower += outProduct(vecHeadLower, vecHeadLower);
171 }
172 for (j2 = seleMan2_.beginSelected(i1); j2 != NULL;
173 j2 = seleMan2_.nextSelected(i1)) {
174 // The lab frame vector corresponding to the body-fixed
175 // z-axis is simply the second column of A.transpose()
176 // or, identically, the second row of A itself.
177
178 Vector3d vecTail = j2->getA().transpose() * V3Z;
179 orderTensorTail += outProduct(vecTail, vecTail);
180 nTail++;
181 }
182
183 orderTensorHeadUpper /= (RealType)nUpper;
184 orderTensorHeadLower /= (RealType)nLower;
185 orderTensorHeadUpper -= (RealType)(1.0 / 3.0) * Mat3x3d::identity();
186 orderTensorHeadLower -= (RealType)(1.0 / 3.0) * Mat3x3d::identity();
187
188 orderTensorTail /= (RealType)nTail;
189 orderTensorTail -= (RealType)(1.0 / 3.0) * Mat3x3d::identity();
190
191 Vector3d eigenvaluesHeadUpper, eigenvaluesHeadLower, eigenvaluesTail;
192 Mat3x3d eigenvectorsHeadUpper, eigenvectorsHeadLower, eigenvectorsTail;
193 Mat3x3d::diagonalize(orderTensorHeadUpper, eigenvaluesHeadUpper,
194 eigenvectorsHeadUpper);
195 Mat3x3d::diagonalize(orderTensorHeadLower, eigenvaluesHeadLower,
196 eigenvectorsHeadLower);
197 Mat3x3d::diagonalize(orderTensorTail, eigenvaluesTail, eigenvectorsTail);
198
199 int whichUpper(-1), whichLower(-1), whichTail(-1);
200 RealType maxEvalUpper = 0.0;
201 RealType maxEvalLower = 0.0;
202 RealType maxEvalTail = 0.0;
203 for (int k = 0; k < 3; k++) {
204 if (fabs(eigenvaluesHeadUpper[k]) > maxEvalUpper) {
205 whichUpper = k;
206 maxEvalUpper = fabs(eigenvaluesHeadUpper[k]);
207 }
208 }
209 RealType p2HeadUpper = 1.5 * maxEvalUpper;
210 for (int k = 0; k < 3; k++) {
211 if (fabs(eigenvaluesHeadLower[k]) > maxEvalLower) {
212 whichLower = k;
213 maxEvalLower = fabs(eigenvaluesHeadLower[k]);
214 }
215 }
216 RealType p2HeadLower = 1.5 * maxEvalLower;
217 for (int k = 0; k < 3; k++) {
218 if (fabs(eigenvaluesTail[k]) > maxEvalTail) {
219 whichTail = k;
220 maxEvalTail = fabs(eigenvaluesTail[k]);
221 }
222 }
223 RealType p2Tail = 1.5 * maxEvalTail;
224
225 // the eigenvector is already normalized in SquareMatrix3::diagonalize
226 Vector3d directorHeadUpper = eigenvectorsHeadUpper.getColumn(whichUpper);
227 if (directorHeadUpper[0] < 0) { directorHeadUpper.negate(); }
228 Vector3d directorHeadLower = eigenvectorsHeadLower.getColumn(whichLower);
229 if (directorHeadLower[0] < 0) { directorHeadLower.negate(); }
230 Vector3d directorTail = eigenvectorsTail.getColumn(whichTail);
231 if (directorTail[0] < 0) { directorTail.negate(); }
232
233 OrderParam paramHeadUpper, paramHeadLower, paramTail;
234 paramHeadUpper.p2 = p2HeadUpper;
235 paramHeadUpper.director = directorHeadUpper;
236 paramHeadLower.p2 = p2HeadLower;
237 paramHeadLower.director = directorHeadLower;
238 paramTail.p2 = p2Tail;
239 paramTail.director = directorTail;
240
241 orderParamsHeadUpper_.push_back(paramHeadUpper);
242 orderParamsHeadLower_.push_back(paramHeadLower);
243 orderParamsTail_.push_back(paramTail);
244 }
245
246 OrderParam sumOPHeadUpper, errsumOPHeadUpper;
247 OrderParam sumOPHeadLower, errsumOPHeadLower;
248 OrderParam sumOPTail, errsumOPTail;
249
250 sumOPHeadUpper.p2 = 0.0;
251 errsumOPHeadUpper.p2 = 0.0;
252 sumOPHeadLower.p2 = 0.0;
253 errsumOPHeadLower.p2 = 0.0;
254 for (std::size_t i = 0; i < orderParamsHeadUpper_.size(); ++i) {
255 sumOPHeadUpper.p2 += orderParamsHeadUpper_[i].p2;
256 sumOPHeadUpper.director[0] += orderParamsHeadUpper_[i].director[0];
257 sumOPHeadUpper.director[1] += orderParamsHeadUpper_[i].director[1];
258 sumOPHeadUpper.director[2] += orderParamsHeadUpper_[i].director[2];
259 }
260
261 avgOPHeadUpper.p2 =
262 sumOPHeadUpper.p2 / (RealType)orderParamsHeadUpper_.size();
263 avgOPHeadUpper.director[0] =
264 sumOPHeadUpper.director[0] / (RealType)orderParamsHeadUpper_.size();
265 avgOPHeadUpper.director[1] =
266 sumOPHeadUpper.director[1] / (RealType)orderParamsHeadUpper_.size();
267 avgOPHeadUpper.director[2] =
268 sumOPHeadUpper.director[2] / (RealType)orderParamsHeadUpper_.size();
269 for (std::size_t i = 0; i < orderParamsHeadUpper_.size(); ++i) {
270 errsumOPHeadUpper.p2 +=
271 pow((orderParamsHeadUpper_[i].p2 - avgOPHeadUpper.p2), 2);
272 }
273 errOPHeadUpper.p2 =
274 sqrt(errsumOPHeadUpper.p2 / (RealType)orderParamsHeadUpper_.size());
275 for (std::size_t i = 0; i < orderParamsHeadLower_.size(); ++i) {
276 sumOPHeadLower.p2 += orderParamsHeadLower_[i].p2;
277 sumOPHeadLower.director[0] += orderParamsHeadLower_[i].director[0];
278 sumOPHeadLower.director[1] += orderParamsHeadLower_[i].director[1];
279 sumOPHeadLower.director[2] += orderParamsHeadLower_[i].director[2];
280 }
281
282 avgOPHeadLower.p2 =
283 sumOPHeadLower.p2 / (RealType)orderParamsHeadLower_.size();
284 avgOPHeadLower.director[0] =
285 sumOPHeadLower.director[0] / (RealType)orderParamsHeadLower_.size();
286 avgOPHeadLower.director[1] =
287 sumOPHeadLower.director[1] / (RealType)orderParamsHeadLower_.size();
288 avgOPHeadLower.director[2] =
289 sumOPHeadLower.director[2] / (RealType)orderParamsHeadLower_.size();
290 for (std::size_t i = 0; i < orderParamsHeadLower_.size(); ++i) {
291 errsumOPHeadLower.p2 +=
292 pow((orderParamsHeadLower_[i].p2 - avgOPHeadLower.p2), 2);
293 }
294 errOPHeadLower.p2 =
295 sqrt(errsumOPHeadLower.p2 / (RealType)orderParamsHeadLower_.size());
296
297 sumOPTail.p2 = 0.0;
298 errsumOPTail.p2 = 0.0;
299 for (std::size_t i = 0; i < orderParamsTail_.size(); ++i) {
300 sumOPTail.p2 += orderParamsTail_[i].p2;
301 sumOPTail.director[0] += orderParamsTail_[i].director[0];
302 sumOPTail.director[1] += orderParamsTail_[i].director[1];
303 sumOPTail.director[2] += orderParamsTail_[i].director[2];
304 }
305
306 avgOPTail.p2 = sumOPTail.p2 / (RealType)orderParamsTail_.size();
307 avgOPTail.director[0] =
308 sumOPTail.director[0] / (RealType)orderParamsTail_.size();
309 avgOPTail.director[1] =
310 sumOPTail.director[1] / (RealType)orderParamsTail_.size();
311 avgOPTail.director[2] =
312 sumOPTail.director[2] / (RealType)orderParamsTail_.size();
313 for (std::size_t i = 0; i < orderParamsTail_.size(); ++i) {
314 errsumOPTail.p2 += pow((orderParamsTail_[i].p2 - avgOPTail.p2), 2);
315 }
316 errOPTail.p2 = sqrt(errsumOPTail.p2 / (RealType)orderParamsTail_.size());
317
318 writeP2();
319 }
320
321 void RippleOP::writeP2() {
322 std::ofstream os(getOutputFileName().c_str());
323 os << "#selection1: (" << selectionScript1_ << ")\n";
324 os << "#p2\terror\tdirector_x\tdirector_y\tdiretor_z\n";
325
326 os << avgOPHeadUpper.p2 << "\t" << errOPHeadUpper.p2 << "\t"
327 << avgOPHeadUpper.director[0] << "\t" << avgOPHeadUpper.director[1]
328 << "\t" << avgOPHeadUpper.director[2] << "\n";
329
330 os << avgOPHeadLower.p2 << "\t" << errOPHeadLower.p2 << "\t"
331 << avgOPHeadLower.director[0] << "\t" << avgOPHeadLower.director[1]
332 << "\t" << avgOPHeadLower.director[2] << "\n";
333
334 os << "selection2: (" << selectionScript2_ << ")\n";
335 os << "#p2\terror\tdirector_x\tdirector_y\tdiretor_z\n";
336
337 os << avgOPTail.p2 << "\t" << errOPTail.p2 << "\t" << avgOPTail.director[0]
338 << "\t" << avgOPTail.director[1] << "\t" << avgOPTail.director[2]
339 << "\n";
340 }
341
342} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
static SquareMatrix< Real, Dim > identity()
Returns an identity matrix.
Real & z()
Returns reference of the third element of Vector3.
Definition Vector3.hpp:123
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
std::string getPrefix(const std::string &str)