OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
BOPofR.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/BOPofR.hpp"
49
50#include "brains/Thermo.hpp"
51#include "io/DumpReader.hpp"
52#include "math/Wigner3jm.hpp"
54#include "utils/Constants.hpp"
55#include "utils/Revision.hpp"
56#include "utils/simError.h"
57
58using namespace MATPACK;
59namespace OpenMD {
60
61 BOPofR::BOPofR(SimInfo* info, const std::string& filename,
62 const std::string& sele, double rCut, unsigned int nbins,
63 RealType len) :
64 StaticAnalyser(info, filename, nbins),
65 selectionScript_(sele), seleMan_(info), evaluator_(info) {
66 setOutputName(getPrefix(filename) + ".bo");
67 setAnalysisType("Bond Order Parameter(r)");
68
69 evaluator_.loadScriptString(sele);
70 if (!evaluator_.isDynamic()) {
71 seleMan_.setSelectionSet(evaluator_.evaluate());
72 }
73
74 // Set up cutoff radius and order of the Legendre Polynomial:
75
76 rCut_ = rCut;
77 len_ = len;
78
79 std::stringstream params;
80 params << " rcut = " << rCut_ << ", len = " << len_
81 << ", nbins = " << nBins_;
82 const std::string paramString = params.str();
83 setParameterString(paramString);
84
85 deltaR_ = len_ / nBins_;
86 RCount_.resize(nBins_);
87 WofR_.resize(nBins_);
88 QofR_.resize(nBins_);
89
90 for (unsigned int i = 0; i < nBins_; i++) {
91 RCount_[i] = 0;
92 WofR_[i] = 0;
93 QofR_[i] = 0;
94 }
95
96 // Make arrays for Wigner3jm
97 RealType* THRCOF = new RealType[2 * lMax_ + 1];
98 // Variables for Wigner routine
99 RealType lPass, m1Pass, m2m, m2M;
100 int error, mSize;
101 mSize = 2 * lMax_ + 1;
102
103 for (int l = 0; l <= lMax_; l++) {
104 lPass = (RealType)l;
105 for (int m1 = -l; m1 <= l; m1++) {
106 m1Pass = (RealType)m1;
107
108 std::pair<int, int> lm = std::make_pair(l, m1);
109
110 // Zero work array
111 for (int ii = 0; ii < 2 * l + 1; ii++) {
112 THRCOF[ii] = 0.0;
113 }
114
115 // Get Wigner coefficients
116 Wigner3jm(lPass, lPass, lPass, m1Pass, m2m, m2M, THRCOF, mSize, error);
117
118 m2Min[lm] = (int)floor(m2m);
119 m2Max[lm] = (int)floor(m2M);
120
121 for (int mmm = 0; mmm <= (int)(m2M - m2m); mmm++) {
122 w3j[lm].push_back(THRCOF[mmm]);
123 }
124 }
125 }
126
127 delete[] THRCOF;
128 THRCOF = NULL;
129 }
130
131 void BOPofR::initializeHistogram() {
132 for (unsigned int i = 0; i < nBins_; i++) {
133 RCount_[i] = 0;
134 WofR_[i] = 0;
135 QofR_[i] = 0;
136 }
137 }
138
139 void BOPofR::process() {
140 Molecule* mol;
141 Atom* atom;
142 int myIndex;
143 SimInfo::MoleculeIterator mi;
144 Molecule::AtomIterator ai;
145 StuntDouble* sd;
146 Vector3d vec;
147 RealType costheta;
148 RealType phi;
149 RealType r;
150 Vector3d rCOM;
151 RealType distCOM;
152 Vector3d pos;
153 Vector3d CenterOfMass;
154 std::map<std::pair<int, int>, ComplexType> q;
155 std::vector<RealType> q_l;
156 std::vector<RealType> q2;
157 std::vector<ComplexType> w;
158 std::vector<ComplexType> w_hat;
159 std::vector<RealType> Q2;
160 std::vector<RealType> Q;
161 std::vector<ComplexType> W;
162 std::vector<ComplexType> W_hat;
163 int nBonds;
164 SphericalHarmonic sphericalHarmonic;
165 int i;
166 bool usePeriodicBoundaryConditions_ =
167 info_->getSimParams()->getUsePeriodicBoundaryConditions();
168
169 DumpReader reader(info_, dumpFilename_);
170 int nFrames = reader.getNFrames();
171 frameCounter_ = 0;
172
173 Thermo thermo(info_);
174
175 q_l.resize(lMax_ + 1);
176 q2.resize(lMax_ + 1);
177 w.resize(lMax_ + 1);
178 w_hat.resize(lMax_ + 1);
179
180 Q2.resize(lMax_ + 1);
181 Q.resize(lMax_ + 1);
182 W.resize(lMax_ + 1);
183 W_hat.resize(lMax_ + 1);
184
185 for (int istep = 0; istep < nFrames; istep += step_) {
186 reader.readFrame(istep);
187 frameCounter_++;
188 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
189 CenterOfMass = thermo.getCom();
190 if (evaluator_.isDynamic()) {
191 seleMan_.setSelectionSet(evaluator_.evaluate());
192 }
193
194 // outer loop is over the selected StuntDoubles:
195
196 for (sd = seleMan_.beginSelected(i); sd != NULL;
197 sd = seleMan_.nextSelected(i)) {
198 myIndex = sd->getGlobalIndex();
199
200 nBonds = 0;
201
202 for (int l = 0; l <= lMax_; l++) {
203 for (int m = -l; m <= l; m++) {
204 q[std::make_pair(l, m)] = 0.0;
205 }
206 }
207 pos = sd->getPos();
208 rCOM = CenterOfMass - pos;
209 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(rCOM);
210 distCOM = rCOM.length();
211
212 // inner loop is over all other atoms in the system:
213
214 for (mol = info_->beginMolecule(mi); mol != NULL;
215 mol = info_->nextMolecule(mi)) {
216 for (atom = mol->beginAtom(ai); atom != NULL;
217 atom = mol->nextAtom(ai)) {
218 if (atom->getGlobalIndex() != myIndex) {
219 vec = pos - atom->getPos();
220
221 if (usePeriodicBoundaryConditions_)
222 currentSnapshot_->wrapVector(vec);
223
224 // Calculate "bonds" and build Q_lm(r) where
225 // Q_lm = Y_lm(theta(r),phi(r))
226 // The spherical harmonics are wrt any arbitrary coordinate
227 // system, we choose standard spherical coordinates
228
229 r = vec.length();
230
231 // Check to see if neighbor is in bond cutoff
232
233 if (r < rCut_) {
234 costheta = vec.z() / r;
235 phi = atan2(vec.y(), vec.x());
236
237 for (int l = 0; l <= lMax_; l++) {
238 sphericalHarmonic.setL(l);
239 for (int m = -l; m <= l; m++) {
240 sphericalHarmonic.setM(m);
241 q[std::make_pair(l, m)] +=
242 sphericalHarmonic.getValueAt(costheta, phi);
243 }
244 }
245 nBonds++;
246 }
247 }
248 }
249 }
250
251 for (int l = 0; l <= lMax_; l++) {
252 q2[l] = 0.0;
253 for (int m = -l; m <= l; m++) {
254 q[std::make_pair(l, m)] /= (RealType)nBonds;
255 q2[l] += norm(q[std::make_pair(l, m)]);
256 }
257 q_l[l] = sqrt(q2[l] * 4.0 * Constants::PI / (RealType)(2 * l + 1));
258 }
259
260 // Find Third Order Invariant W_l
261
262 for (int l = 0; l <= lMax_; l++) {
263 w[l] = 0.0;
264 for (int m1 = -l; m1 <= l; m1++) {
265 std::pair<int, int> lm = std::make_pair(l, m1);
266 for (int mmm = 0; mmm <= (m2Max[lm] - m2Min[lm]); mmm++) {
267 int m2 = m2Min[lm] + mmm;
268 int m3 = -m1 - m2;
269 w[l] += w3j[lm][mmm] * q[lm] * q[std::make_pair(l, m2)] *
270 q[std::make_pair(l, m3)];
271 }
272 }
273
274 w_hat[l] = w[l] / pow(q2[l], RealType(1.5));
275 }
276
277 collectHistogram(q_l, w_hat, distCOM);
278
279 // printf( "%s %18.10g %18.10g %18.10g %18.10g \n",
280 // sd->getType().c_str(),pos[0],pos[1],pos[2],real(w_hat[6]));
281 }
282 }
283
284 writeOrderParameter();
285 }
286
287 IcosahedralOfR::IcosahedralOfR(SimInfo* info, const std::string& filename,
288 const std::string& sele, double rCut,
289 unsigned int nbins, RealType len) :
290 BOPofR(info, filename, sele, rCut, nbins, len) {
291 setAnalysisType("Icosahedral Bond Order Parameter(r)");
292 }
293
294 void IcosahedralOfR::collectHistogram(std::vector<RealType> q,
295 std::vector<ComplexType> what,
296 RealType distCOM) {
297 if (distCOM < len_) {
298 // Figure out where this distance goes...
299 int whichBin = int(distCOM / deltaR_);
300 RCount_[whichBin]++;
301
302 if (real(what[6]) < -0.15) { WofR_[whichBin]++; }
303 if (q[6] > 0.5) { QofR_[whichBin]++; }
304 }
305 }
306
307 FCCOfR::FCCOfR(SimInfo* info, const std::string& filename,
308 const std::string& sele, double rCut, unsigned int nbins,
309 RealType len) :
310 BOPofR(info, filename, sele, rCut, nbins, len) {
311 setAnalysisType("FCC Bond Order Parameter(r)");
312 }
313
314 void FCCOfR::collectHistogram(std::vector<RealType>,
315 std::vector<ComplexType> what,
316 RealType distCOM) {
317 if (distCOM < len_) {
318 // Figure out where this distance goes...
319 int whichBin = int(distCOM / deltaR_);
320 RCount_[whichBin]++;
321
322 if (real(what[4]) < -0.12) { WofR_[whichBin]++; }
323 }
324 }
325
326 void IcosahedralOfR::writeOrderParameter() {
327 Revision rev;
328 std::ofstream osq((getOutputFileName() + "qr").c_str());
329
330 if (osq.is_open()) {
331 osq << "# " << getAnalysisType() << "\n";
332 osq << "# OpenMD " << rev.getFullRevision() << "\n";
333 osq << "# " << rev.getBuildDate() << "\n";
334 osq << "# selection script: \"" << selectionScript_ << "\"\n";
335 if (!paramString_.empty())
336 osq << "# parameters: " << paramString_ << "\n";
337
338 // Normalize by number of frames and write it out:
339
340 for (unsigned int i = 0; i < nBins_; ++i) {
341 RealType Rval = (i + 0.5) * deltaR_;
342 osq << Rval;
343 if (RCount_[i] == 0) {
344 osq << "\t" << 0;
345 osq << "\n";
346 } else {
347 osq << "\t" << (RealType)QofR_[i] / (RealType)RCount_[i];
348 osq << "\n";
349 }
350 }
351
352 osq.close();
353
354 } else {
355 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
356 "IcosahedralOfR: unable to open %s\n",
357 (getOutputFileName() + "q").c_str());
358 painCave.isFatal = 1;
359 simError();
360 }
361
362 std::ofstream osw((getOutputFileName() + "wr").c_str());
363
364 if (osw.is_open()) {
365 osw << "# " << getAnalysisType() << "\n";
366 osw << "# OpenMD " << rev.getFullRevision() << "\n";
367 osw << "# " << rev.getBuildDate() << "\n";
368 osw << "# selection script: \"" << selectionScript_ << "\"\n";
369 if (!paramString_.empty())
370 osw << "# parameters: " << paramString_ << "\n";
371
372 // Normalize by number of frames and write it out:
373 for (unsigned int i = 0; i < nBins_; ++i) {
374 RealType Rval = deltaR_ * (i + 0.5);
375 osw << Rval;
376 if (RCount_[i] == 0) {
377 osw << "\t" << 0;
378 osw << "\n";
379 } else {
380 osw << "\t" << (RealType)WofR_[i] / (RealType)RCount_[i];
381 osw << "\n";
382 }
383 }
384
385 osw.close();
386 } else {
387 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
388 "IcosahedralOfR: unable to open %s\n",
389 (getOutputFileName() + "w").c_str());
390 painCave.isFatal = 1;
391 simError();
392 }
393 }
394 void FCCOfR::writeOrderParameter() {
395 std::ofstream osw((getOutputFileName() + "wr").c_str());
396
397 if (osw.is_open()) {
398 Revision rev;
399 osw << "# " << getAnalysisType() << "\n";
400 osw << "# OpenMD " << rev.getFullRevision() << "\n";
401 osw << "# " << rev.getBuildDate() << "\n";
402 osw << "# selection script: \"" << selectionScript_ << "\"\n";
403 if (!paramString_.empty())
404 osw << "# parameters: " << paramString_ << "\n";
405
406 // Normalize by number of frames and write it out:
407 for (unsigned int i = 0; i < nBins_; ++i) {
408 RealType Rval = deltaR_ * (i + 0.5);
409 osw << Rval;
410 if (RCount_[i] == 0) {
411 osw << "\t" << 0;
412 osw << "\n";
413 } else {
414 osw << "\t" << (RealType)WofR_[i] / (RealType)RCount_[i];
415 osw << "\n";
416 }
417 }
418
419 osw.close();
420 } else {
421 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
422 "FCCOfR: unable to open %s\n",
423 (getOutputFileName() + "w").c_str());
424 painCave.isFatal = 1;
425 simError();
426 }
427 }
428} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
std::string getPrefix(const std::string &str)