OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
GofAngle2.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/GofAngle2.hpp"
46
47#include <algorithm>
48#include <fstream>
49#include <sstream>
50
51#include "primitives/Atom.hpp"
52#include "types/MultipoleAdapter.hpp"
53#include "utils/Revision.hpp"
54#include "utils/simError.h"
55
56namespace OpenMD {
57
58 GofAngle2::GofAngle2(SimInfo* info, const std::string& filename,
59 const std::string& sele1, const std::string& sele2,
60 int nangleBins) :
61 RadialDistrFunc(info, filename, sele1, sele2, nangleBins),
62 doSele3_(false), seleMan3_(info), evaluator3_(info) {
63 setAnalysisType("Radial Distribution Function");
64 setOutputName(getPrefix(filename) + ".gto");
65
66 deltaCosAngle_ = 2.0 / nBins_;
67
68 std::stringstream params;
69 params << " nAngleBins = " << nBins_
70 << ", deltaCosAngle = " << deltaCosAngle_;
71 const std::string paramString = params.str();
72 setParameterString(paramString);
73
74 histogram_.resize(nBins_);
75 avgGofr_.resize(nBins_);
76 for (unsigned int i = 0; i < nBins_; ++i) {
77 histogram_[i].resize(nBins_);
78 avgGofr_[i].resize(nBins_);
79 }
80 }
81
82 GofAngle2::GofAngle2(SimInfo* info, const std::string& filename,
83 const std::string& sele1, const std::string& sele2,
84 const std::string& sele3, int nangleBins) :
85 RadialDistrFunc(info, filename, sele1, sele2, nangleBins),
86 doSele3_(true), seleMan3_(info), evaluator3_(info),
87 selectionScript3_(sele3) {
88 setOutputName(getPrefix(filename) + ".gto");
89
90 deltaCosAngle_ = 2.0 / nBins_;
91
92 histogram_.resize(nBins_);
93 avgGofr_.resize(nBins_);
94 for (unsigned int i = 0; i < nBins_; ++i) {
95 histogram_[i].resize(nBins_);
96 avgGofr_[i].resize(nBins_);
97 }
98 evaluator3_.loadScriptString(sele3);
99 if (!evaluator3_.isDynamic()) {
100 seleMan3_.setSelectionSet(evaluator3_.evaluate());
101 }
102 }
103
104 void GofAngle2::processNonOverlapping(SelectionManager& sman1,
105 SelectionManager& sman2) {
106 StuntDouble* sd1;
107 StuntDouble* sd2;
108 StuntDouble* sd3;
109 int i;
110 int j;
111 int k;
112
113 // This is the same as a non-overlapping pairwise loop structure:
114 // for (int i = 0; i < ni ; ++i ) {
115 // for (int j = 0; j < nj; ++j) {}
116 // }
117
118 if (doSele3_) {
119 if (evaluator3_.isDynamic()) {
120 seleMan3_.setSelectionSet(evaluator3_.evaluate());
121 }
122 if (sman1.getSelectionCount() != seleMan3_.getSelectionCount()) {
123 RadialDistrFunc::processNonOverlapping(sman1, sman2);
124 }
125
126 for (sd1 = sman1.beginSelected(i), sd3 = seleMan3_.beginSelected(k);
127 sd1 != NULL && sd3 != NULL;
128 sd1 = sman1.nextSelected(i), sd3 = seleMan3_.nextSelected(k)) {
129 for (sd2 = sman2.beginSelected(j); sd2 != NULL;
130 sd2 = sman2.nextSelected(j)) {
131 collectHistogram(sd1, sd2, sd3);
132 }
133 }
134 } else {
135 RadialDistrFunc::processNonOverlapping(sman1, sman2);
136 }
137 }
138
139 void GofAngle2::processOverlapping(SelectionManager& sman) {
140 StuntDouble* sd1;
141 StuntDouble* sd2;
142 StuntDouble* sd3;
143 int i;
144 int j;
145 int k;
146
147 // This is the same as a pairwise loop structure:
148 // for (int i = 0; i < n-1 ; ++i ) {
149 // for (int j = i + 1; j < n; ++j) {}
150 // }
151
152 if (doSele3_) {
153 if (evaluator3_.isDynamic()) {
154 seleMan3_.setSelectionSet(evaluator3_.evaluate());
155 }
156 if (sman.getSelectionCount() != seleMan3_.getSelectionCount()) {
157 RadialDistrFunc::processOverlapping(sman);
158 }
159 for (sd1 = sman.beginSelected(i), sd3 = seleMan3_.beginSelected(k);
160 sd1 != NULL && sd3 != NULL;
161 sd1 = sman.nextSelected(i), sd3 = seleMan3_.nextSelected(k)) {
162 for (j = i, sd2 = sman.nextSelected(j); sd2 != NULL;
163 sd2 = sman.nextSelected(j)) {
164 collectHistogram(sd1, sd2, sd3);
165 }
166 }
167 } else {
168 RadialDistrFunc::processOverlapping(sman);
169 }
170 }
171
172 void GofAngle2::preProcess() {
173 for (unsigned int i = 0; i < avgGofr_.size(); ++i) {
174 std::fill(avgGofr_[i].begin(), avgGofr_[i].end(), 0);
175 }
176 }
177
178 void GofAngle2::initializeHistogram() {
179 npairs_ = 0;
180 for (unsigned int i = 0; i < histogram_.size(); ++i)
181 std::fill(histogram_[i].begin(), histogram_[i].end(), 0);
182 }
183
184 void GofAngle2::processHistogram() {
185 // std::for_each(avgGofr_.begin(), avgGofr_.end(),
186 // std::plus<std::vector<int>>)
187 }
188
189 void GofAngle2::collectHistogram(StuntDouble* sd1, StuntDouble* sd2) {
190 bool usePeriodicBoundaryConditions_ =
191 info_->getSimParams()->getUsePeriodicBoundaryConditions();
192
193 if (sd1 == sd2) { return; }
194
195 Vector3d pos1 = sd1->getPos();
196 Vector3d pos2 = sd2->getPos();
197 Vector3d r12 = pos1 - pos2;
198 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(r12);
199
200 AtomType* atype1 = static_cast<Atom*>(sd1)->getAtomType();
201 AtomType* atype2 = static_cast<Atom*>(sd2)->getAtomType();
202 MultipoleAdapter ma1 = MultipoleAdapter(atype1);
203 MultipoleAdapter ma2 = MultipoleAdapter(atype2);
204
205 if (!sd1->isDirectional()) {
206 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
207 "GofAngle2: attempted to use a non-directional object: %s\n",
208 sd1->getType().c_str());
209 painCave.isFatal = 1;
210 simError();
211 }
212
213 if (!sd2->isDirectional()) {
214 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
215 "GofAngle2: attempted to use a non-directional object: %s\n",
216 sd2->getType().c_str());
217 painCave.isFatal = 1;
218 simError();
219 }
220
221 Vector3d dipole1, dipole2;
222 if (ma1.isDipole())
223 dipole1 = sd1->getDipole();
224 else
225 dipole1 = sd1->getA().transpose() * V3Z;
226
227 if (ma2.isDipole())
228 dipole2 = sd2->getDipole();
229 else
230 dipole2 = sd2->getA().transpose() * V3Z;
231
232 r12.normalize();
233 dipole1.normalize();
234 dipole2.normalize();
235
236 RealType cosAngle1 = dot(r12, dipole1);
237 RealType cosAngle2 = dot(dipole1, dipole2);
238
239 RealType halfBin = (nBins_ - 1) * 0.5;
240 int angleBin1 = int(halfBin * (cosAngle1 + 1.0));
241 int angleBin2 = int(halfBin * (cosAngle2 + 1.0));
242
243 ++histogram_[angleBin1][angleBin2];
244 ++npairs_;
245 }
246
247 void GofAngle2::collectHistogram(StuntDouble* sd1, StuntDouble* sd2,
248 StuntDouble* sd3) {
249 bool usePeriodicBoundaryConditions_ =
250 info_->getSimParams()->getUsePeriodicBoundaryConditions();
251
252 if (sd1 == sd2) { return; }
253
254 Vector3d p1 = sd1->getPos();
255 Vector3d p3 = sd3->getPos();
256
257 Vector3d c = 0.5 * (p1 + p3);
258 Vector3d r13 = p3 - p1;
259
260 Vector3d r12 = sd2->getPos() - c;
261
262 if (usePeriodicBoundaryConditions_) {
263 currentSnapshot_->wrapVector(r12);
264 currentSnapshot_->wrapVector(r13);
265 }
266 r12.normalize();
267 r13.normalize();
268
269 if (!sd2->isDirectional()) {
270 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
271 "GofAngle2: attempted to use a non-directional object: %s\n",
272 sd2->getType().c_str());
273 painCave.isFatal = 1;
274 simError();
275 }
276
277 AtomType* atype2 = static_cast<Atom*>(sd2)->getAtomType();
278 MultipoleAdapter ma2 = MultipoleAdapter(atype2);
279
280 Vector3d dipole2;
281 if (ma2.isDipole())
282 dipole2 = sd2->getDipole();
283 else
284 dipole2 = sd2->getA().transpose() * V3Z;
285
286 dipole2.normalize();
287
288 RealType cosAngle1 = dot(r12, r13);
289 RealType cosAngle2 = dot(r13, dipole2);
290
291 RealType halfBin = (nBins_ - 1) * 0.5;
292 int angleBin1 = int(halfBin * (cosAngle1 + 1.0));
293 int angleBin2 = int(halfBin * (cosAngle2 + 1.0));
294
295 ++histogram_[angleBin1][angleBin2];
296 ++npairs_;
297 }
298
299 void GofAngle2::writeRdf() {
300 std::ofstream ofs(outputFilename_.c_str());
301 if (ofs.is_open()) {
302 Revision r;
303 ofs << "# " << getAnalysisType() << "\n";
304 ofs << "# OpenMD " << r.getFullRevision() << "\n";
305 ofs << "# " << r.getBuildDate() << "\n";
306 ofs << "# selection script1: \"" << selectionScript1_;
307 ofs << "\"\tselection script2: \"" << selectionScript2_ << "\"";
308 if (doSele3_) {
309 ofs << "\tselection script3: \"" << selectionScript3_ << "\"\n";
310 } else {
311 ofs << "\n";
312 }
313
314 if (!paramString_.empty())
315 ofs << "# parameters: " << paramString_ << "\n";
316
317 for (unsigned int i = 0; i < avgGofr_.size(); ++i) {
318 // RealType cosAngle1 = -1.0 + (i + 0.5)*deltaCosAngle_;
319
320 for (unsigned int j = 0; j < avgGofr_[i].size(); ++j) {
321 // RealType cosAngle2 = -1.0 + (j + 0.5)*deltaCosAngle_;
322 ofs << avgGofr_[i][j] / nProcessed_ << "\t";
323 }
324 ofs << "\n";
325 }
326
327 } else {
328 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
329 "GofAngle2: unable to open %s\n", outputFilename_.c_str());
330 painCave.isFatal = 1;
331 simError();
332 }
333
334 ofs.close();
335 }
336
337} // namespace OpenMD
void normalize()
Normalizes this vector in place.
Definition Vector.hpp:402
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)