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