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