OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
pAngle.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/* Calculates Rho(theta) */
49
50#include "applications/staticProps/pAngle.hpp"
51
52#include <algorithm>
53#include <fstream>
54
55#include "brains/Thermo.hpp"
56#include "io/DumpReader.hpp"
58#include "utils/simError.h"
59
60namespace OpenMD {
61
62 pAngle::pAngle(SimInfo* info, const std::string& filename,
63 const std::string& sele1, int nthetabins) :
64 StaticAnalyser(info, filename, nthetabins),
65 doVect_(true), doOffset_(false), selectionScript1_(sele1),
66 seleMan1_(info), seleMan2_(info), evaluator1_(info), evaluator2_(info),
67 nThetaBins_(nthetabins) {
68 setOutputName(getPrefix(filename) + ".pAngle");
69
70 evaluator1_.loadScriptString(sele1);
71 if (!evaluator1_.isDynamic()) {
72 seleMan1_.setSelectionSet(evaluator1_.evaluate());
73 }
74
75 count_.resize(nThetaBins_);
76 histogram_.resize(nThetaBins_);
77 }
78
79 pAngle::pAngle(SimInfo* info, const std::string& filename,
80 const std::string& sele1, const std::string& sele2,
81 int nthetabins) :
82 StaticAnalyser(info, filename, nthetabins),
83 doVect_(false), doOffset_(false), selectionScript1_(sele1),
84 selectionScript2_(sele2), seleMan1_(info), seleMan2_(info),
85 evaluator1_(info), evaluator2_(info), nThetaBins_(nthetabins) {
86 setOutputName(getPrefix(filename) + ".pAngle");
87
88 evaluator1_.loadScriptString(sele1);
89 if (!evaluator1_.isDynamic()) {
90 seleMan1_.setSelectionSet(evaluator1_.evaluate());
91 }
92
93 evaluator2_.loadScriptString(sele2);
94 if (!evaluator2_.isDynamic()) {
95 seleMan2_.setSelectionSet(evaluator2_.evaluate());
96 }
97
98 count_.resize(nThetaBins_);
99 histogram_.resize(nThetaBins_);
100 }
101
102 pAngle::pAngle(SimInfo* info, const std::string& filename,
103 const std::string& sele1, int seleOffset, int nthetabins) :
104 StaticAnalyser(info, filename, nthetabins),
105 doVect_(false), doOffset_(true), doOffset2_(false),
106 selectionScript1_(sele1), seleMan1_(info), seleMan2_(info),
107 evaluator1_(info), evaluator2_(info), seleOffset_(seleOffset),
108 nThetaBins_(nthetabins) {
109 setOutputName(getPrefix(filename) + ".pAngle");
110
111 evaluator1_.loadScriptString(sele1);
112 if (!evaluator1_.isDynamic()) {
113 seleMan1_.setSelectionSet(evaluator1_.evaluate());
114 }
115
116 count_.resize(nThetaBins_);
117 histogram_.resize(nThetaBins_);
118 }
119
120 pAngle::pAngle(SimInfo* info, const std::string& filename,
121 const std::string& sele1, int seleOffset, int seleOffset2,
122 int nthetabins) :
123 StaticAnalyser(info, filename, nthetabins),
124 doVect_(false), doOffset_(true), doOffset2_(true),
125 selectionScript1_(sele1), seleMan1_(info), seleMan2_(info),
126 evaluator1_(info), evaluator2_(info), seleOffset_(seleOffset),
127 seleOffset2_(seleOffset2), nThetaBins_(nthetabins) {
128 setOutputName(getPrefix(filename) + ".pAngle");
129
130 evaluator1_.loadScriptString(sele1);
131 if (!evaluator1_.isDynamic()) {
132 seleMan1_.setSelectionSet(evaluator1_.evaluate());
133 }
134
135 count_.resize(nThetaBins_);
136 histogram_.resize(nThetaBins_);
137 }
138
139 void pAngle::process() {
140 StuntDouble* sd1;
141 StuntDouble* sd2;
142 int ii;
143 int jj;
144 bool usePeriodicBoundaryConditions_ =
145 info_->getSimParams()->getUsePeriodicBoundaryConditions();
146
147 Thermo thermo(info_);
148 DumpReader reader(info_, dumpFilename_);
149 int nFrames = reader.getNFrames();
150
151 nProcessed_ = nFrames / step_;
152
153 std::fill(histogram_.begin(), histogram_.end(), 0.0);
154 std::fill(count_.begin(), count_.end(), 0);
155
156 for (int istep = 0; istep < nFrames; istep += step_) {
157 reader.readFrame(istep);
158 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
159
160 Vector3d CenterOfMass = thermo.getCom();
161
162 if (evaluator1_.isDynamic()) {
163 seleMan1_.setSelectionSet(evaluator1_.evaluate());
164 }
165
166 if (doVect_) {
167 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
168 sd1 = seleMan1_.nextSelected(ii)) {
169 Vector3d pos = sd1->getPos();
170
171 Vector3d r1 = CenterOfMass - pos;
172 // only do this if the stunt double actually has a vector associated
173 // with it
174 if (sd1->isDirectional()) {
175 Vector3d vec = sd1->getA().transpose() * V3Z;
176 vec.normalize();
177 r1.normalize();
178 RealType cosangle = dot(r1, vec);
179
180 int binNo = int(nThetaBins_ * (1.0 + cosangle) / 2.0);
181 count_[binNo]++;
182 }
183 }
184 } else {
185 if (doOffset_) {
186 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
187 sd1 = seleMan1_.nextSelected(ii)) {
188 // This will require careful rewriting if StaticProps is
189 // ever parallelized. For an example, see
190 // Thermo::getTaggedAtomPairDistance
191 Vector3d r1;
192
193 if (doOffset2_) {
194 int sd1Aind = sd1->getGlobalIndex() + seleOffset2_;
195 StuntDouble* sd1A = info_->getIOIndexToIntegrableObject(sd1Aind);
196 r1 = CenterOfMass - sd1A->getPos();
197 } else {
198 r1 = CenterOfMass - sd1->getPos();
199 }
200
201 if (usePeriodicBoundaryConditions_)
202 currentSnapshot_->wrapVector(r1);
203
204 int sd2Index = sd1->getGlobalIndex() + seleOffset_;
205 sd2 = info_->getIOIndexToIntegrableObject(sd2Index);
206
207 Vector3d r2 = CenterOfMass - sd2->getPos();
208 if (usePeriodicBoundaryConditions_)
209 currentSnapshot_->wrapVector(r1);
210
211 Vector3d rc = 0.5 * (r1 + r2);
212 if (usePeriodicBoundaryConditions_)
213 currentSnapshot_->wrapVector(rc);
214
215 Vector3d vec = r1 - r2;
216 if (usePeriodicBoundaryConditions_)
217 currentSnapshot_->wrapVector(vec);
218
219 rc.normalize();
220 vec.normalize();
221 RealType cosangle = dot(rc, vec);
222 int binNo = int(nThetaBins_ * (1.0 + cosangle) / 2.0);
223 count_[binNo]++;
224 }
225 } else {
226 if (evaluator2_.isDynamic()) {
227 seleMan2_.setSelectionSet(evaluator2_.evaluate());
228 }
229
230 if (seleMan1_.getSelectionCount() != seleMan2_.getSelectionCount()) {
231 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
232 "In frame %d, the number of selected StuntDoubles are\n"
233 "\tnot the same in --sele1 and sele2\n",
234 istep);
235 painCave.severity = OPENMD_INFO;
236 painCave.isFatal = 0;
237 simError();
238 }
239
240 for (sd1 = seleMan1_.beginSelected(ii),
241 sd2 = seleMan2_.beginSelected(jj);
242 sd1 != NULL && sd2 != NULL; sd1 = seleMan1_.nextSelected(ii),
243 sd2 = seleMan2_.nextSelected(jj)) {
244 Vector3d r1 = CenterOfMass - sd1->getPos();
245 if (usePeriodicBoundaryConditions_)
246 currentSnapshot_->wrapVector(r1);
247
248 Vector3d r2 = CenterOfMass - sd2->getPos();
249 if (usePeriodicBoundaryConditions_)
250 currentSnapshot_->wrapVector(r1);
251
252 Vector3d rc = 0.5 * (r1 + r2);
253 if (usePeriodicBoundaryConditions_)
254 currentSnapshot_->wrapVector(rc);
255
256 Vector3d vec = r1 - r2;
257 if (usePeriodicBoundaryConditions_)
258 currentSnapshot_->wrapVector(vec);
259
260 rc.normalize();
261 vec.normalize();
262 RealType cosangle = dot(rc, vec);
263 int binNo = int(nThetaBins_ * (1.0 + cosangle) / 2.0);
264 count_[binNo]++;
265 }
266 }
267 }
268 }
269
270 processHistogram();
271 writeProbs();
272 }
273
274 void pAngle::processHistogram() {
275 int atot = 0;
276 for (unsigned int i = 0; i < count_.size(); ++i)
277 atot += count_[i];
278
279 for (unsigned int i = 0; i < count_.size(); ++i) {
280 histogram_[i] = double(count_[i] / double(atot));
281 }
282 }
283
284 void pAngle::writeProbs() {
285 std::ofstream rdfStream(outputFilename_.c_str());
286 if (rdfStream.is_open()) {
287 rdfStream << "#pAngle\n";
288 rdfStream << "#nFrames:\t" << nProcessed_ << "\n";
289 rdfStream << "#selection1: (" << selectionScript1_ << ")";
290 if (!doVect_) {
291 rdfStream << "\tselection2: (" << selectionScript2_ << ")";
292 }
293 rdfStream << "\n";
294 rdfStream << "#cos(theta)\tp(cos(theta))\n";
295 RealType dct = 2.0 / histogram_.size();
296 for (unsigned int i = 0; i < histogram_.size(); ++i) {
297 RealType ct = -1.0 + (2.0 * i + 1) / (histogram_.size());
298 rdfStream << ct << "\t" << histogram_[i] / dct << "\n";
299 }
300
301 } else {
302 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
303 "pAngle: unable to open %s\n", outputFilename_.c_str());
304 painCave.isFatal = 1;
305 simError();
306 }
307
308 rdfStream.close();
309 }
310
311} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
void normalize()
Normalizes this vector in place.
Definition Vector.hpp:406
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)