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