OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
TranslationalOrderParameterR.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/TranslationalOrderParamR.hpp"
46
47#include <algorithm>
48#include <fstream>
49#include <vector>
50
51#include "io/DumpReader.hpp"
53#include "utils/Revision.hpp"
54#include "utils/simError.h"
55
56#define HONKING_LARGE_VALUE 1.0e10
57
58using namespace std;
59namespace OpenMD {
60 TranslationalOrderParamR::TranslationalOrderParamR(
61 SimInfo* info, const std::string& filename, const std::string& sele1,
62 const std::string& sele2, const std::string& sele3, RealType rCut,
63 RealType len, int nrbins) :
64 StaticAnalyser(info, filename, nrbins),
65 selectionScript1_(sele1), selectionScript2_(sele2),
66 selectionScript3_(sele3), seleMan1_(info), seleMan2_(info),
67 seleMan3_(info), evaluator1_(info), evaluator2_(info), evaluator3_(info),
68 len_(len), nBins_(nrbins) {
69 setAnalysisType("Translational Order Parameter(r)");
70
71 evaluator1_.loadScriptString(sele1);
72 if (!evaluator1_.isDynamic()) {
73 seleMan1_.setSelectionSet(evaluator1_.evaluate());
74 validateSelection1(seleMan1_);
75 }
76
77 evaluator2_.loadScriptString(sele2);
78 if (!evaluator2_.isDynamic()) {
79 seleMan2_.setSelectionSet(evaluator2_.evaluate());
80 validateSelection2(seleMan2_);
81 }
82
83 if (!evaluator1_.isDynamic() && !evaluator2_.isDynamic()) {
84 // If all selections are static, we can precompute the number
85 // of real pairs.
86 common_ = seleMan1_ & seleMan2_;
87 sele1_minus_common_ = seleMan1_ - common_;
88 sele2_minus_common_ = seleMan2_ - common_;
89
90 nSelected1_ = seleMan1_.getSelectionCount();
91 nSelected2_ = seleMan2_.getSelectionCount();
92 int nIntersect = common_.getSelectionCount();
93
94 nPairs_ = nSelected1_ * nSelected2_ - (nIntersect + 1) * nIntersect / 2;
95 }
96
97 evaluator3_.loadScriptString(sele3);
98 if (!evaluator3_.isDynamic()) {
99 seleMan3_.setSelectionSet(evaluator3_.evaluate());
100 }
101
102 deltaR_ = len_ / nBins_;
103
104 // fixed number of bins
105 sliceT_.resize(nBins_);
106 sliceCount_.resize(nBins_);
107 std::fill(sliceT_.begin(), sliceQ_.end(), 0.0);
108 std::fill(sliceCount_.begin(), sliceCount_.end(), 0);
109
110 setOutputName(getPrefix(filename) + ".Tr");
111 }
112
113 void TranslationalOrderParamR::process() {
114 StuntDouble* sd;
115 StuntDouble* sd2;
116 StuntDouble* sd3;
117 StuntDouble* sdi;
118 StuntDouble* sdj;
119 int myIndex;
120 Vector3d vec;
121 Vector3d ri, rj, rk, rik, rkj;
122 RealType r;
123 RealType cospsi;
124 RealType Qk;
125 std::vector<std::pair<RealType, StuntDouble*>> myNeighbors;
126 int isd1;
127 int isd2;
128 int isd3;
129 bool usePeriodicBoundaryConditions_ =
130 info_->getSimParams()->getUsePeriodicBoundaryConditions();
131
132 DumpReader reader(info_, dumpFilename_);
133 int nFrames = reader.getNFrames();
134
135 for (int istep = 0; istep < nFrames; istep += step_) {
136 reader.readFrame(istep);
137 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
138
139 if (evaluator1_.isDynamic()) {
140 seleMan1_.setSelectionSet(evaluator1_.evaluate());
141 validateSelection1(seleMan1_);
142 }
143
144 if (evaluator2_.isDynamic()) {
145 seleMan2_.setSelectionSet(evaluator2_.evaluate());
146 validateSelection2(seleMan2_);
147 }
148
149 if (evaluator3_.isDynamic()) {
150 seleMan3_.setSelectionSet(evaluator3_.evaluate());
151 }
152
153 if (evaluator1_.isDynamic() || evaluator2_.isDynamic()) {
154 common_ = seleMan1_ & seleMan2_;
155 sele1_minus_common_ = seleMan1_ - common_;
156 sele2_minus_common_ = seleMan2_ - common_;
157 nSelected1_ = seleMan1_.getSelectionCount();
158 nSelected2_ = seleMan2_.getSelectionCount();
159 int nIntersect = common_.getSelectionCount();
160
161 nPairs_ = nSelected1_ * nSelected2_ - (nIntersect + 1) * nIntersect / 2;
162 }
163
164 processNonOverlapping(sele1_minus_common_, seleMan2_);
165 processNonOverlapping(common_, sele2_minus_common_);
166 processOverlapping(common_);
167
168 processHistogram();
169 }
170
171 postProcess();
172
173 writeTr();
174 }
175
176 void TranslationalOrderParamR::processNonOverlapping(SelectionManager& sman1,
177 SelectionManager& sman2) {
178 StuntDouble* sd1;
179 StuntDouble* sd2;
180 int i;
181 int j;
182
183 // This is the same as a non-overlapping pairwise loop structure:
184 // for (int i = 0; i < ni ; ++i ) {
185 // for (int j = 0; j < nj; ++j) {}
186 // }
187
188 for (sd1 = sman1.beginSelected(i); sd1 != NULL;
189 sd1 = sman1.nextSelected(i)) {
190 for (sd2 = sman2.beginSelected(j); sd2 != NULL;
191 sd2 = sman2.nextSelected(j)) {
192 collectHistogram(sd1, sd2);
193 }
194 }
195 }
196
197 void TranslationalOrderParamR::processOverlapping(SelectionManager& sman) {
198 StuntDouble* sd1;
199 StuntDouble* sd2;
200 int i;
201 int j;
202
203 // This is the same as a pairwise loop structure:
204 // for (int i = 0; i < n-1 ; ++i ) {
205 // for (int j = i + 1; j < n; ++j) {}
206 // }
207
208 for (sd1 = sman.beginSelected(i); sd1 != NULL; sd1 = sman.nextSelected(i)) {
209 for (j = i, sd2 = sman.nextSelected(j); sd2 != NULL;
210 sd2 = sman.nextSelected(j)) {
211 collectHistogram(sd1, sd2);
212 }
213 }
214 }
215
216
217 void TranslationalOrderParamR::collectHistogram(StuntDouble* sd1,
218 StuntDouble* sd2) {
219 if (sd1 == sd2) { return; }
220
221 bool usePeriodicBoundaryConditions_ =
222 info_->getSimParams()->getUsePeriodicBoundaryConditions();
223
224 Vector3d pos1 = sd1->getPos();
225 Vector3d pos2 = sd2->getPos();
226 Vector3d r12 = pos2 - pos1;
227 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(r12);
228
229 RealType distance = r12.length();
230
231 if (distance < len_) {
232 int whichBin = int(distance / deltaR_);
233 histogram_[whichBin] += 2;
234 }
235 }
236
237
238 // outer loop is over the selected StuntDoubles:
239 for (sd = seleMan1_.beginSelected(isd1); sd != NULL;
240 sd = seleMan1_.nextSelected(isd1)) {
241 myIndex = sd->getGlobalIndex();
242
243 std::fill(histogram_.begin(), histogram_.end(), 0);
244
245 for (sd2 = seleMan2_.beginSelected(isd2); sd2 != NULL;
246 sd2 = seleMan2_.nextSelected(isd2)) {
247 if (sd2->getGlobalIndex() != myIndex) {
248 vec = sd->getPos() - sd2->getPos();
249
250 if (usePeriodicBoundaryConditions_)
251 currentSnapshot_->wrapVector(vec);
252
253 r = vec.length();
254
255 if (r < len_) {
256 int whichBin = int(distance / deltaR_);
257 histogram_[whichBin] += 2;
258 }
259 }
260 }
261
262
263 for (int i = 0; i < nbors - 1; i++) {
264 sdi = myNeighbors[i].second;
265 ri = sdi->getPos();
266 rik = rk - ri;
267 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(rik);
268
269 rik.normalize();
270
271 for (int j = i + 1; j < nbors; j++) {
272 sdj = myNeighbors[j].second;
273 rj = sdj->getPos();
274 rkj = rk - rj;
275 if (usePeriodicBoundaryConditions_)
276 currentSnapshot_->wrapVector(rkj);
277 rkj.normalize();
278
279 cospsi = dot(rik, rkj);
280
281 // Calculates scaled Qk for each molecule using calculated
282 // angles from 4 or fewer nearest neighbors.
283 Qk -= (pow(cospsi + 1.0 / 3.0, 2) * 2.25 / nang);
284 }
285 }
286
287 if (nang > 0) {
288 RealType shortest = HONKING_LARGE_VALUE;
289
290 // loop over selection 3 to find closest atom in selection 3:
291 for (sd3 = seleMan3_.beginSelected(isd3); sd3 != NULL;
292 sd3 = seleMan3_.nextSelected(isd3)) {
293 vec = sd->getPos() - sd3->getPos();
294
295 if (usePeriodicBoundaryConditions_)
296 currentSnapshot_->wrapVector(vec);
297
298 r = vec.length();
299
300 if (r < shortest) shortest = r;
301 }
302
303 int whichBin = int(shortest / deltaR_);
304 if (whichBin < int(nBins_)) {
305 sliceT_[whichBin] += Qk;
306 sliceCount_[whichBin] += 1;
307 }
308 }
309 }
310 }
311 writeTr();
312 }
313
314 void TranslationalOrderParamR::writeTr() {
315 Revision rev;
316 std::ofstream tRstream(outputFilename_.c_str());
317 if (tRstream.is_open()) {
318 tRstream << "# " << getAnalysisType() << "\n";
319 tRstream << "# OpenMD " << rev.getFullRevision() << "\n";
320 tRstream << "# " << rev.getBuildDate() << "\n";
321 tRstream << "#selection 1: (" << selectionScript1_ << ")\n";
322 tRstream << "#selection 2: (" << selectionScript2_ << ")\n";
323 tRstream << "#selection 3: (" << selectionScript3_ << ")\n";
324 if (!paramString_.empty())
325 tRstream << "# parameters: " << paramString_ << "\n";
326
327 tRstream << "#distance"
328 << "\tT(r)\n";
329 for (unsigned int i = 0; i < sliceT_.size(); ++i) {
330 RealType Rval = (i + 0.5) * deltaR_;
331 if (sliceCount_[i] != 0) {
332 tRstream << Rval << "\t" << sliceT_[i] / (RealType)sliceCount_[i]
333 << "\n";
334 }
335 }
336
337 } else {
338 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
339 "TranslationalOrderParamR: unable to open %s\n",
340 outputFilename_.c_str());
341 painCave.isFatal = 1;
342 simError();
343 }
344 tRstream.close();
345 }
346} // namespace OpenMD
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)
Real distance(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the distance between two DynamicVectors.