OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
AngleR.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 Angle(R) for DirectionalAtoms*/
49
50#include "applications/staticProps/AngleR.hpp"
51
52#include <algorithm>
53#include <cmath>
54#include <fstream>
55#include <sstream>
56
57#include "brains/Thermo.hpp"
58#include "io/DumpReader.hpp"
60#include "utils/Revision.hpp"
61#include "utils/simError.h"
62
63namespace OpenMD {
64
65 AngleR::AngleR(SimInfo* info, const std::string& filename,
66 const std::string& sele1, RealType len, int nrbins) :
67 StaticAnalyser(info, filename, nrbins),
68 doVect_(true), doOffset_(false), selectionScript1_(sele1),
69 seleMan1_(info), seleMan2_(info), evaluator1_(info), evaluator2_(info),
70 len_(len), nRBins_(nrbins) {
71 evaluator1_.loadScriptString(sele1);
72 if (!evaluator1_.isDynamic()) {
73 seleMan1_.setSelectionSet(evaluator1_.evaluate());
74 }
75
76 deltaR_ = len_ / nRBins_;
77
78 histogram_.resize(nRBins_);
79 count_.resize(nRBins_);
80 avgAngleR_.resize(nRBins_);
81
82 setAnalysisType("radial density function Angle(r)");
83 setOutputName(getPrefix(filename) + ".AngleR");
84 std::stringstream params;
85 params << " len = " << len_ << ", nrbins = " << nRBins_;
86 const std::string paramString = params.str();
87 setParameterString(paramString);
88 }
89
90 AngleR::AngleR(SimInfo* info, const std::string& filename,
91 const std::string& sele1, const std::string& sele2,
92 RealType len, int nrbins) :
93 StaticAnalyser(info, filename, nrbins),
94 doVect_(false), doOffset_(false), selectionScript1_(sele1),
95 selectionScript2_(sele2), seleMan1_(info), seleMan2_(info),
96 evaluator1_(info), evaluator2_(info), len_(len), nRBins_(nrbins) {
97 setOutputName(getPrefix(filename) + ".AngleR");
98
99 evaluator1_.loadScriptString(sele1);
100 if (!evaluator1_.isDynamic()) {
101 seleMan1_.setSelectionSet(evaluator1_.evaluate());
102 }
103
104 evaluator2_.loadScriptString(sele2);
105 if (!evaluator2_.isDynamic()) {
106 seleMan2_.setSelectionSet(evaluator2_.evaluate());
107 }
108
109 deltaR_ = len_ / nRBins_;
110
111 histogram_.resize(nRBins_);
112 count_.resize(nRBins_);
113 avgAngleR_.resize(nRBins_);
114
115 setAnalysisType("radial density function Angle(r)");
116 setOutputName(getPrefix(filename) + ".AngleR");
117 std::stringstream params;
118 params << " len = " << len_ << ", nrbins = " << nRBins_;
119 const std::string paramString = params.str();
120 setParameterString(paramString);
121 }
122
123 AngleR::AngleR(SimInfo* info, const std::string& filename,
124 const std::string& sele1, int seleOffset, RealType len,
125 int nrbins) :
126 StaticAnalyser(info, filename, nrbins),
127 doVect_(false), doOffset_(true), doOffset2_(false),
128 selectionScript1_(sele1), seleMan1_(info), seleMan2_(info),
129 evaluator1_(info), evaluator2_(info), seleOffset_(seleOffset), len_(len),
130 nRBins_(nrbins) {
131 setOutputName(getPrefix(filename) + ".AngleR");
132
133 evaluator1_.loadScriptString(sele1);
134 if (!evaluator1_.isDynamic()) {
135 seleMan1_.setSelectionSet(evaluator1_.evaluate());
136 }
137
138 deltaR_ = len_ / nRBins_;
139
140 histogram_.resize(nRBins_);
141 count_.resize(nRBins_);
142 avgAngleR_.resize(nRBins_);
143
144 setAnalysisType("radial density function Angle(r)");
145 setOutputName(getPrefix(filename) + ".AngleR");
146 std::stringstream params;
147 params << " len = " << len_ << ", nrbins = " << nRBins_;
148 const std::string paramString = params.str();
149 setParameterString(paramString);
150 }
151
152 AngleR::AngleR(SimInfo* info, const std::string& filename,
153 const std::string& sele1, int seleOffset, int seleOffset2,
154 RealType len, int nrbins) :
155 StaticAnalyser(info, filename, nrbins),
156 doVect_(false), doOffset_(true), doOffset2_(true),
157 selectionScript1_(sele1), seleMan1_(info), seleMan2_(info),
158 evaluator1_(info), evaluator2_(info), seleOffset_(seleOffset),
159 seleOffset2_(seleOffset2), len_(len), nRBins_(nrbins) {
160 setOutputName(getPrefix(filename) + ".AngleR");
161
162 evaluator1_.loadScriptString(sele1);
163 if (!evaluator1_.isDynamic()) {
164 seleMan1_.setSelectionSet(evaluator1_.evaluate());
165 }
166
167 histogram_.resize(nRBins_);
168 count_.resize(nRBins_);
169 avgAngleR_.resize(nRBins_);
170
171 setAnalysisType("radial density function Angle(r)");
172 setOutputName(getPrefix(filename) + ".AngleR");
173 std::stringstream params;
174 params << " len = " << len_ << ", nrbins = " << nRBins_;
175 const std::string paramString = params.str();
176 setParameterString(paramString);
177 }
178
179 void AngleR::process() {
180 StuntDouble* sd1;
181 StuntDouble* sd2;
182 int ii;
183 int jj;
184 RealType distance;
185 bool usePeriodicBoundaryConditions_ =
186 info_->getSimParams()->getUsePeriodicBoundaryConditions();
187
188 Thermo thermo(info_);
189 DumpReader reader(info_, dumpFilename_);
190 int nFrames = reader.getNFrames();
191
192 nProcessed_ = nFrames / step_;
193
194 std::fill(avgAngleR_.begin(), avgAngleR_.end(), 0.0);
195 std::fill(histogram_.begin(), histogram_.end(), 0.0);
196 std::fill(count_.begin(), count_.end(), 0);
197
198 for (int istep = 0; istep < nFrames; istep += step_) {
199 reader.readFrame(istep);
200 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
201
202 Vector3d CenterOfMass = thermo.getCom();
203
204 if (evaluator1_.isDynamic()) {
205 seleMan1_.setSelectionSet(evaluator1_.evaluate());
206 }
207
208 if (doVect_) {
209 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
210 sd1 = seleMan1_.nextSelected(ii)) {
211 Vector3d pos = sd1->getPos();
212
213 Vector3d r1 = CenterOfMass - pos;
214 distance = r1.length();
215 // only do this if the stunt double actually has a vector associated
216 // with it
217 if (sd1->isDirectional()) {
218 Vector3d vec = sd1->getA().transpose() * V3Z;
219 vec.normalize();
220 r1.normalize();
221 RealType cosangle = dot(r1, vec);
222
223 if (distance < len_) {
224 int whichBin = int(distance / deltaR_);
225 histogram_[whichBin] += cosangle;
226 count_[whichBin] += 1;
227 }
228 }
229 }
230 } else {
231 if (doOffset_) {
232 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
233 sd1 = seleMan1_.nextSelected(ii)) {
234 // This will require careful rewriting if StaticProps is
235 // ever parallelized. For an example, see
236 // Thermo::getTaggedAtomPairDistance
237 Vector3d r1;
238
239 if (doOffset2_) {
240 int sd1Aind = sd1->getGlobalIndex() + seleOffset2_;
241 StuntDouble* sd1A = info_->getIOIndexToIntegrableObject(sd1Aind);
242 r1 = CenterOfMass - sd1A->getPos();
243 } else {
244 r1 = CenterOfMass - sd1->getPos();
245 }
246
247 if (usePeriodicBoundaryConditions_)
248 currentSnapshot_->wrapVector(r1);
249
250 int sd2Index = sd1->getGlobalIndex() + seleOffset_;
251 sd2 = info_->getIOIndexToIntegrableObject(sd2Index);
252
253 Vector3d r2 = CenterOfMass - sd2->getPos();
254 if (usePeriodicBoundaryConditions_)
255 currentSnapshot_->wrapVector(r1);
256
257 Vector3d rc = 0.5 * (r1 + r2);
258 if (usePeriodicBoundaryConditions_)
259 currentSnapshot_->wrapVector(rc);
260
261 distance = rc.length();
262
263 Vector3d vec = r1 - r2;
264 if (usePeriodicBoundaryConditions_)
265 currentSnapshot_->wrapVector(vec);
266
267 rc.normalize();
268 vec.normalize();
269 RealType cosangle = dot(rc, vec);
270 if (distance < len_) {
271 int whichBin = int(distance / deltaR_);
272 histogram_[whichBin] += cosangle;
273 count_[whichBin] += 1;
274 }
275 }
276 } else {
277 if (evaluator2_.isDynamic()) {
278 seleMan2_.setSelectionSet(evaluator2_.evaluate());
279 }
280
281 if (seleMan1_.getSelectionCount() != seleMan2_.getSelectionCount()) {
282 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
283 "In frame %d, the number of selected StuntDoubles are\n"
284 "\tnot the same in --sele1 and sele2\n",
285 istep);
286 painCave.severity = OPENMD_INFO;
287 painCave.isFatal = 0;
288 simError();
289 }
290
291 for (sd1 = seleMan1_.beginSelected(ii),
292 sd2 = seleMan2_.beginSelected(jj);
293 sd1 != NULL && sd2 != NULL; sd1 = seleMan1_.nextSelected(ii),
294 sd2 = seleMan2_.nextSelected(jj)) {
295 Vector3d r1 = CenterOfMass - sd1->getPos();
296 if (usePeriodicBoundaryConditions_)
297 currentSnapshot_->wrapVector(r1);
298
299 Vector3d r2 = CenterOfMass - sd2->getPos();
300 if (usePeriodicBoundaryConditions_)
301 currentSnapshot_->wrapVector(r1);
302
303 Vector3d rc = 0.5 * (r1 + r2);
304 if (usePeriodicBoundaryConditions_)
305 currentSnapshot_->wrapVector(rc);
306
307 Vector3d vec = r1 - r2;
308 if (usePeriodicBoundaryConditions_)
309 currentSnapshot_->wrapVector(vec);
310
311 distance = rc.length();
312
313 rc.normalize();
314 vec.normalize();
315 RealType cosangle = dot(rc, vec);
316 if (distance < len_) {
317 int whichBin = int(distance / deltaR_);
318 histogram_[whichBin] += cosangle;
319 count_[whichBin] += 1;
320 }
321 }
322 }
323 }
324 }
325 processHistogram();
326 writeAngleR();
327 }
328
329 void AngleR::processHistogram() {
330 for (unsigned int i = 0; i < histogram_.size(); ++i) {
331 if (count_[i] > 0)
332 avgAngleR_[i] += histogram_[i] / count_[i];
333 else
334 avgAngleR_[i] = 0.0;
335
336 std::cerr << " count = " << count_[i] << " avgAngle = " << avgAngleR_[i]
337 << "\n";
338 }
339 }
340
341 void AngleR::writeAngleR() {
342 std::ofstream ofs(outputFilename_.c_str());
343 if (ofs.is_open()) {
344 Revision rev;
345
346 ofs << "# " << getAnalysisType() << "\n";
347 ofs << "# OpenMD " << rev.getFullRevision() << "\n";
348 ofs << "# " << rev.getBuildDate() << "\n";
349 ofs << "#nFrames:\t" << nProcessed_ << "\n";
350 ofs << "#selection1: (" << selectionScript1_ << ")";
351 if (!doVect_) { ofs << "\tselection2: (" << selectionScript2_ << ")"; }
352 if (!paramString_.empty())
353 ofs << "# parameters: " << paramString_ << "\n";
354
355 ofs << "#r\tcorrValue\n";
356 for (unsigned int i = 0; i < avgAngleR_.size(); ++i) {
357 RealType r = deltaR_ * (i + 0.5);
358 ofs << r << "\t" << avgAngleR_[i] << "\n";
359 }
360
361 } else {
362 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
363 "AngleR: unable to open %s\n", outputFilename_.c_str());
364 painCave.isFatal = 1;
365 simError();
366 }
367
368 ofs.close();
369 }
370
371} // 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)
Real distance(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the distance between two DynamicVectors.