OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
P2OrderParameter.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/P2OrderParameter.hpp"
49
50#include "io/DumpReader.hpp"
52#include "utils/Constants.hpp"
53#include "utils/simError.h"
54
55using namespace std;
56namespace OpenMD {
57
58 P2OrderParameter::P2OrderParameter(SimInfo* info, const string& filename,
59 const string& sele1) :
60 StaticAnalyser(info, filename, 1),
61 doVect_(true), doOffset_(false), selectionScript1_(sele1),
62 seleMan1_(info), seleMan2_(info), evaluator1_(info), evaluator2_(info) {
63 setOutputName(getPrefix(filename) + ".p2");
64
65 evaluator1_.loadScriptString(sele1);
66 }
67
68 P2OrderParameter::P2OrderParameter(SimInfo* info, const string& filename,
69 const string& sele1, const string& sele2) :
70 StaticAnalyser(info, filename, 1),
71 doVect_(false), doOffset_(false), selectionScript1_(sele1),
72 selectionScript2_(sele2), seleMan1_(info), seleMan2_(info),
73 evaluator1_(info), evaluator2_(info) {
74 setOutputName(getPrefix(filename) + ".p2");
75
76 evaluator1_.loadScriptString(sele1);
77 evaluator2_.loadScriptString(sele2);
78 }
79
80 P2OrderParameter::P2OrderParameter(SimInfo* info, const string& filename,
81 const string& sele1, int seleOffset) :
82 StaticAnalyser(info, filename, 1),
83 doVect_(false), doOffset_(true), selectionScript1_(sele1),
84 seleMan1_(info), seleMan2_(info), evaluator1_(info), evaluator2_(info),
85 seleOffset_(seleOffset) {
86 setOutputName(getPrefix(filename) + ".p2");
87
88 evaluator1_.loadScriptString(sele1);
89 }
90
91 void P2OrderParameter::process() {
92 StuntDouble* sd1;
93 StuntDouble* sd2;
94 int ii;
95 int jj;
96 int vecCount;
97 bool usePeriodicBoundaryConditions_ =
98 info_->getSimParams()->getUsePeriodicBoundaryConditions();
99
100 DumpReader reader(info_, dumpFilename_);
101 int nFrames = reader.getNFrames();
102
103 for (int i = 0; i < nFrames; i += step_) {
104 reader.readFrame(i);
105 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
106
107 Mat3x3d orderTensor(0.0);
108 vecCount = 0;
109
110 seleMan1_.setSelectionSet(evaluator1_.evaluate());
111
112 if (doVect_) {
113 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
114 sd1 = seleMan1_.nextSelected(ii)) {
115 if (sd1->isDirectional()) {
116 Vector3d vec = sd1->getA().transpose() * V3Z;
117
118 vec.normalize();
119 orderTensor += outProduct(vec, vec);
120 vecCount++;
121 }
122 }
123
124 orderTensor /= vecCount;
125
126 } else {
127 if (doOffset_) {
128 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
129 sd1 = seleMan1_.nextSelected(ii)) {
130 // This will require careful rewriting if StaticProps is
131 // ever parallelized. For an example, see
132 // Thermo::getTaggedAtomPairDistance
133
134 int sd2Index = sd1->getGlobalIndex() + seleOffset_;
135 sd2 = info_->getIOIndexToIntegrableObject(sd2Index);
136
137 Vector3d vec = sd1->getPos() - sd2->getPos();
138
139 if (usePeriodicBoundaryConditions_)
140 currentSnapshot_->wrapVector(vec);
141
142 vec.normalize();
143
144 orderTensor += outProduct(vec, vec);
145 vecCount++;
146 }
147
148 orderTensor /= vecCount;
149 } else {
150 seleMan2_.setSelectionSet(evaluator2_.evaluate());
151
152 if (seleMan1_.getSelectionCount() != seleMan2_.getSelectionCount()) {
153 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
154 "In frame %d, the number of selected StuntDoubles are\n"
155 "\tnot the same in --sele1 and sele2\n",
156 i);
157 painCave.severity = OPENMD_INFO;
158 painCave.isFatal = 0;
159 simError();
160 }
161
162 for (sd1 = seleMan1_.beginSelected(ii),
163 sd2 = seleMan2_.beginSelected(jj);
164 sd1 != NULL && sd2 != NULL; sd1 = seleMan1_.nextSelected(ii),
165 sd2 = seleMan2_.nextSelected(jj)) {
166 Vector3d vec = sd1->getPos() - sd2->getPos();
167
168 if (usePeriodicBoundaryConditions_)
169 currentSnapshot_->wrapVector(vec);
170
171 vec.normalize();
172
173 orderTensor += outProduct(vec, vec);
174 vecCount++;
175 }
176
177 orderTensor /= vecCount;
178 }
179 }
180
181 if (vecCount == 0) {
182 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
183 "In frame %d, the number of selected vectors was zero.\n"
184 "\tThis will not give a meaningful order parameter.",
185 i);
186 painCave.severity = OPENMD_ERROR;
187 painCave.isFatal = 1;
188 simError();
189 }
190
191 orderTensor -= (RealType)(1.0 / 3.0) * Mat3x3d::identity();
192
193 Vector3d eigenvalues;
194 Mat3x3d eigenvectors;
195
196 Mat3x3d::diagonalize(orderTensor, eigenvalues, eigenvectors);
197
198 int which(-1);
199 RealType maxEval = 0.0;
200 for (int k = 0; k < 3; k++) {
201 if (fabs(eigenvalues[k]) > maxEval) {
202 which = k;
203 maxEval = fabs(eigenvalues[k]);
204 }
205 }
206 RealType p2 = 1.5 * maxEval;
207
208 // the eigen vector is already normalized in SquareMatrix3::diagonalize
209 Vector3d director = eigenvectors.getColumn(which);
210 // if (director[2] < 0) { director.negate(); }
211
212 RealType angle = 0.0;
213 vecCount = 0;
214
215 if (doVect_) {
216 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
217 sd1 = seleMan1_.nextSelected(ii)) {
218 if (sd1->isDirectional()) {
219 Vector3d vec = sd1->getA().transpose() * V3Z;
220 vec.normalize();
221 angle += acos(dot(vec, director));
222 vecCount++;
223 }
224 }
225 angle = angle / (vecCount * Constants::PI) * 180.0;
226
227 } else {
228 if (doOffset_) {
229 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
230 sd1 = seleMan1_.nextSelected(ii)) {
231 // This will require careful rewriting if StaticProps is
232 // ever parallelized. For an example, see
233 // Thermo::getTaggedAtomPairDistance
234
235 int sd2Index = sd1->getGlobalIndex() + seleOffset_;
236 sd2 = info_->getIOIndexToIntegrableObject(sd2Index);
237
238 Vector3d vec = sd1->getPos() - sd2->getPos();
239 if (usePeriodicBoundaryConditions_)
240 currentSnapshot_->wrapVector(vec);
241 vec.normalize();
242 angle += acos(dot(vec, director));
243 vecCount++;
244 }
245 angle = angle / (vecCount * Constants::PI) * 180.0;
246
247 } else {
248 for (sd1 = seleMan1_.beginSelected(ii),
249 sd2 = seleMan2_.beginSelected(jj);
250 sd1 != NULL && sd2 != NULL; sd1 = seleMan1_.nextSelected(ii),
251 sd2 = seleMan2_.nextSelected(jj)) {
252 Vector3d vec = sd1->getPos() - sd2->getPos();
253 if (usePeriodicBoundaryConditions_)
254 currentSnapshot_->wrapVector(vec);
255 vec.normalize();
256 angle += acos(dot(vec, director));
257 vecCount++;
258 }
259 angle = angle / (vecCount * Constants::PI) * 180.0;
260 }
261 }
262
263 OrderParam param;
264 param.p2 = p2;
265 param.director = director;
266 param.angle = angle;
267
268 orderParams_.push_back(param);
269 }
270
271 writeP2();
272 }
273
274 void P2OrderParameter::writeP2() {
275 ofstream os(getOutputFileName().c_str());
276 os << "#P2 Order parameter\n";
277 os << "#selection1: (" << selectionScript1_ << ")\t";
278 if (!doVect_) { os << "selection2: (" << selectionScript2_ << ")\n"; }
279 os << "#p2\tdirector_x\tdirector_y\tdirector_z\tangle(degree)\n";
280
281 RealType p2Sum {};
282 RealType angleSum {};
283 Vector3d directorSum(0.0);
284
285 for (size_t i = 0; i < orderParams_.size(); ++i) {
286 p2Sum += orderParams_[i].p2;
287 directorSum += orderParams_[i].director;
288 angleSum += orderParams_[i].angle;
289 }
290
291 p2Sum /= orderParams_.size();
292 directorSum /= orderParams_.size();
293 angleSum /= orderParams_.size();
294
295 os << p2Sum << "\t" << directorSum[0] << "\t" << directorSum[1] << "\t"
296 << directorSum[2] << "\t" << angleSum << "\n";
297 }
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
static SquareMatrix< Real, Dim > identity()
Returns an identity matrix.
void normalize()
Normalizes this vector in place.
Definition Vector.hpp:406
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)