OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
TetrahedralityParamRAngle.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/TetrahedralityParamRAngle.hpp"
49
50#include <algorithm>
51#include <fstream>
52#include <vector>
53
54#include "io/DumpReader.hpp"
56#include "utils/Revision.hpp"
57#include "utils/simError.h"
58
59#define HONKING_LARGE_VALUE 1.0e10
60
61using namespace std;
62namespace OpenMD {
63 TetrahedralityParamRAngle::TetrahedralityParamRAngle(
64 SimInfo* info, const std::string& filename, const std::string& sele1,
65 const std::string& sele2, const std::string& sele3, const int seleOffset3,
66 RealType rCut, RealType len, int nrbins, int nangleBins) :
67 StaticAnalyser(info, filename, nrbins),
68 selectionScript1_(sele1), selectionScript2_(sele2),
69 selectionScript3_(sele3), seleMan1_(info), seleMan2_(info),
70 seleMan3_(info), evaluator1_(info), evaluator2_(info), evaluator3_(info),
71 seleOffset3_(seleOffset3), len_(len), nBins_(nrbins), nAngleBins_(nangleBins) {
72
73 setAnalysisType("Tetrahedrality Parameter(r, cos(theta))");
74
75 evaluator1_.loadScriptString(sele1);
76 if (!evaluator1_.isDynamic()) {
77 seleMan1_.setSelectionSet(evaluator1_.evaluate());
78 }
79
80 evaluator2_.loadScriptString(sele2);
81 if (!evaluator2_.isDynamic()) {
82 seleMan2_.setSelectionSet(evaluator2_.evaluate());
83 }
84
85 evaluator3_.loadScriptString(sele3);
86 if (!evaluator3_.isDynamic()) {
87 seleMan3_.setSelectionSet(evaluator3_.evaluate());
88 }
89
90 // Set up cutoff radius:
91 rCut_ = rCut;
92
93 deltaR_ = len_ / nBins_;
94 deltaCosAngle_ = 2.0 / (double)nAngleBins_;
95
96 // fixed number of bins
97 sliceQ_.resize(nBins_);
98 sliceCount_.resize(nBins_);
99 for (unsigned int i = 0; i < nBins_; ++i) {
100 sliceQ_[i].resize(nAngleBins_);
101 sliceCount_[i].resize(nAngleBins_);
102 std::fill(sliceQ_[i].begin(), sliceQ_[i].end(), 0.0);
103 std::fill(sliceCount_[i].begin(), sliceCount_[i].end(), 0);
104 }
105
106 setOutputName(getPrefix(filename) + ".Qrangle");
107 }
108
109 void TetrahedralityParamRAngle::process() {
110 StuntDouble* sd;
111 StuntDouble* sd2;
112 StuntDouble* sd3;
113 StuntDouble* sdi;
114 StuntDouble* sdj;
115 int myIndex;
116 Vector3d vec;
117 Vector3d ri, rj, rk, rik, rkj;
118 Vector3d r34;
119 RealType r;
120 RealType cospsi;
121 RealType Qk;
122 std::vector<std::pair<RealType, StuntDouble*>> myNeighbors;
123 int isd1;
124 int isd2;
125 int isd3;
126 int whichBin;
127 int whichThetaBin;
128 RealType halfBin;
129 RealType cosAngle;
130
131 bool usePeriodicBoundaryConditions_ =
132 info_->getSimParams()->getUsePeriodicBoundaryConditions();
133
134 DumpReader reader(info_, dumpFilename_);
135 int nFrames = reader.getNFrames();
136
137 for (int istep = 0; istep < nFrames; istep += step_) {
138 reader.readFrame(istep);
139 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
140
141 if (evaluator1_.isDynamic()) {
142 seleMan1_.setSelectionSet(evaluator1_.evaluate());
143 }
144
145 if (evaluator2_.isDynamic()) {
146 seleMan2_.setSelectionSet(evaluator2_.evaluate());
147 }
148
149 if (evaluator3_.isDynamic()) {
150 seleMan3_.setSelectionSet(evaluator3_.evaluate());
151 }
152
153 if (seleMan3_.getSelectionCount() == 0) {
154 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
155 "TetrahedralityParamRAngle:process: third selection has no "
156 "objects at frame %d, skipping frame.\n",
157 istep);
158 painCave.severity = OPENMD_WARNING;
159 painCave.isFatal = 0;
160 simError();
161 continue;
162 }
163
164 // outer loop is over the selected StuntDoubles:
165 for (sd = seleMan1_.beginSelected(isd1); sd != NULL;
166 sd = seleMan1_.nextSelected(isd1)) {
167 myIndex = sd->getGlobalIndex();
168
169 Qk = 1.0;
170 myNeighbors.clear();
171
172 for (sd2 = seleMan2_.beginSelected(isd2); sd2 != NULL;
173 sd2 = seleMan2_.nextSelected(isd2)) {
174 if (sd2->getGlobalIndex() != myIndex) {
175 vec = sd->getPos() - sd2->getPos();
176
177 if (usePeriodicBoundaryConditions_)
178 currentSnapshot_->wrapVector(vec);
179
180 r = vec.length();
181
182 // Check to see if neighbor is in bond cutoff
183
184 if (r < rCut_) { myNeighbors.push_back(std::make_pair(r, sd2)); }
185 }
186 }
187
188 // Sort the vector using predicate and std::sort
189 std::sort(myNeighbors.begin(), myNeighbors.end());
190
191 // Use only the 4 closest neighbors to do the rest of the work:
192
193 int nbors = myNeighbors.size() > 4 ? 4 : myNeighbors.size();
194 int nang = int(0.5 * (nbors * (nbors - 1)));
195
196 rk = sd->getPos();
197
198 for (int i = 0; i < nbors - 1; i++) {
199 sdi = myNeighbors[i].second;
200 ri = sdi->getPos();
201 rik = rk - ri;
202 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(rik);
203
204 rik.normalize();
205
206 for (int j = i + 1; j < nbors; j++) {
207 sdj = myNeighbors[j].second;
208 rj = sdj->getPos();
209 rkj = rk - rj;
210 if (usePeriodicBoundaryConditions_)
211 currentSnapshot_->wrapVector(rkj);
212 rkj.normalize();
213
214 cospsi = dot(rik, rkj);
215
216 // Calculates scaled Qk for each molecule using calculated
217 // angles from 4 or fewer nearest neighbors.
218 Qk -= (pow(cospsi + 1.0 / 3.0, 2) * 2.25 / nang);
219 }
220 }
221
222 if (nang > 0) {
223 RealType shortest = HONKING_LARGE_VALUE;
224
225 // loop over selection 3 to find closest atom in selection 3:
226 for (sd3 = seleMan3_.beginSelected(isd3); sd3 != NULL;
227 sd3 = seleMan3_.nextSelected(isd3)) {
228
229 vec = sd->getPos() - sd3->getPos();
230
231 if (usePeriodicBoundaryConditions_) {
232 currentSnapshot_->wrapVector(vec);
233 }
234
235 r = vec.length();
236
237 if (r < shortest) {
238 shortest = r;
239 vec.normalize();
240 whichBin = int(r / deltaR_);
241
242 // Find the angle that vec makes with the 3->4 vector and figure out the bin:
243 int sd4ind = sd3->getGlobalIndex() + seleOffset3_;
244 StuntDouble* sd4 = info_->getIOIndexToIntegrableObject(sd4ind);
245 r34 = sd4->getPos() - sd3->getPos();
246 if (usePeriodicBoundaryConditions_) {
247 currentSnapshot_->wrapVector(r34);
248 }
249 r34.normalize();
250 cosAngle = dot(r34, vec);
251
252 halfBin = (nAngleBins_ - 1) * 0.5;
253 whichThetaBin = int(halfBin * (cosAngle + 1.0));
254 }
255 }
256
257 if (whichBin < int(nBins_)) {
258 sliceQ_[whichBin][whichThetaBin] += Qk;
259 sliceCount_[whichBin][whichThetaBin] += 1;
260 }
261 }
262 }
263 }
264 writeQrAngle();
265 }
266
267 void TetrahedralityParamRAngle::writeQrAngle() {
268 Revision rev;
269 std::ofstream qRstream(outputFilename_.c_str());
270 if (qRstream.is_open()) {
271 qRstream << "# " << getAnalysisType() << "\n";
272 qRstream << "# OpenMD " << rev.getFullRevision() << "\n";
273 qRstream << "# " << rev.getBuildDate() << "\n";
274 qRstream << "#selection 1: (" << selectionScript1_ << ")\n";
275 qRstream << "#selection 2: (" << selectionScript2_ << ")\n";
276 qRstream << "#selection 3: (" << selectionScript3_ << ")\n";
277 qRstream << "#selection 3 offset: " << seleOffset3_ << "\n";
278 if (!paramString_.empty())
279 qRstream << "# parameters: " << paramString_ << "\n";
280
281 for (unsigned int i = 0; i < sliceQ_.size(); ++i) {
282 for (unsigned int j = 0; j < sliceQ_[i].size(); ++j) {
283 if (sliceCount_[i][j] != 0) {
284 qRstream << sliceQ_[i][j] / (RealType)sliceCount_[i][j] << "\t";
285 } else {
286 qRstream << 0.0 << "\t";
287 }
288 }
289 qRstream << "\n";
290 }
291
292 } else {
293 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
294 "TetrahedralityParamRAngle: unable to open %s\n",
295 outputFilename_.c_str());
296 painCave.isFatal = 1;
297 simError();
298 }
299 qRstream.close();
300 }
301} // 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.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)