OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
KirkwoodBuff.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/KirkwoodBuff.hpp"
49
50#include <algorithm>
51#include <cmath>
52#include <fstream>
53#include <iomanip>
54#include <sstream>
55
56#include "utils/Revision.hpp"
57#include "utils/simError.h"
58
59namespace OpenMD {
60
61 KirkwoodBuff::KirkwoodBuff(SimInfo* info, const std::string& filename,
62 const std::string& sele1, const std::string& sele2,
63 RealType len, unsigned int nrbins) :
64 MultiComponentRDF {info, filename, sele1, sele2, nrbins},
65 len_ {len}, meanVol_ {0.0} {
66 setAnalysisType("Kirkwood-Buff Integrals");
67 setOutputName(getPrefix(filename) + ".kirkwood-buff");
68
69 // Bins are set to the inner radius of a spherical shell.
70 deltaR_ = len_ / (nBins_ - 1);
71
72 histograms_.resize(MaxPairs);
73 gofrs_.resize(MaxPairs);
74 gCorr_.resize(MaxPairs);
75 G_.resize(MaxPairs);
76
77 for (std::size_t i {}; i < MaxPairs; ++i) {
78 histograms_[i].resize(nBins_);
79 gofrs_[i].resize(nBins_);
80 gCorr_[i].resize(nBins_);
81 G_[i].resize(nBins_);
82 }
83
84 std::stringstream params;
85 params << " len = " << len_ << ", nrbins = " << nBins_;
86 const std::string paramString = params.str();
87 setParameterString(paramString);
88 }
89
90 void KirkwoodBuff::initializeHistograms() {
91 for (auto& pair : histograms_)
92 std::fill(pair.begin(), pair.end(), 0);
93 }
94
95 void KirkwoodBuff::collectHistograms(StuntDouble* sd1, StuntDouble* sd2,
96 int pairIndex) {
97 if (sd1 == sd2) { return; }
98
99 bool usePeriodicBoundaryConditions_ =
100 info_->getSimParams()->getUsePeriodicBoundaryConditions();
101
102 Vector3d pos1 = sd1->getPos();
103 Vector3d pos2 = sd2->getPos();
104 Vector3d r12 = pos2 - pos1;
105 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(r12);
106
107 RealType distance = r12.length();
108
109 // Bins are set to the inner radius of a spherical shell.
110 if (distance < (len_ + deltaR_)) {
111 int whichBin = static_cast<int>(distance / deltaR_);
112 histograms_[pairIndex][whichBin] += 1;
113 }
114 }
115
116 void KirkwoodBuff::processHistograms() {
117 std::vector<int> nPairs = getNPairs();
118 RealType volume =
119 info_->getSnapshotManager()->getCurrentSnapshot()->getVolume();
120
121 meanVol_ += volume;
122
123 for (std::size_t i {}; i < histograms_.size(); ++i) {
124 for (std::size_t j {}; j < histograms_[i].size(); ++j) {
125 RealType rLower = j * deltaR_;
126 RealType rUpper = rLower + deltaR_;
127 RealType volSlice = 4.0 * Constants::PI *
128 (std::pow(rUpper, 3) - std::pow(rLower, 3)) / 3.0;
129 RealType pairDensity = nPairs[i] / volume;
130 RealType nIdeal = volSlice * pairDensity;
131
132 gofrs_[i][j] += histograms_[i][j] / nIdeal;
133 }
134 }
135 }
136
137 void KirkwoodBuff::postProcess() {
138 for (std::size_t i {}; i < gofrs_.size(); ++i) {
139 for (std::size_t j {}; j < gofrs_[i].size(); ++j) {
140 gofrs_[i][j] /= nProcessed_;
141 }
142 } // g(r) is the uncorrected g(r)
143 meanVol_ /= nProcessed_;
144
145 std::vector<int> Ns(MaxPairs);
146 Ns[OneOne] = getNSelected1();
147 Ns[OneTwo] = getNSelected2();
148 Ns[TwoTwo] = getNSelected2();
149
150 std::vector<int> kd(MaxPairs);
151 kd[OneOne] = 1;
152 kd[OneTwo] = 0;
153 kd[TwoTwo] = 1;
154
155 std::vector<RealType> rho(MaxPairs);
156 rho[OneOne] = Ns[OneOne] / meanVol_;
157 rho[OneTwo] = Ns[OneTwo] / meanVol_;
158 rho[TwoTwo] = Ns[TwoTwo] / meanVol_;
159
160 std::vector<std::vector<RealType>> deltaN;
161 deltaN.resize(MaxPairs);
162 for (auto& elem : deltaN)
163 elem.resize(nBins_);
164
165 for (std::size_t i {}; i < deltaN.size(); ++i) {
166 deltaN[i][0] = 0.0;
167 gCorr_[i][0] = 0.0;
168 G_[i][0] = 0.0;
169
170 for (std::size_t j {1}; j < deltaN[i].size(); ++j) {
171 RealType r = deltaR_ * j;
172 RealType V = 4.0 * Constants::PI * r * r * r / 3.0;
173 RealType x = r / len_;
174 RealType w =
175 4.0 * Constants::PI * r * r * (1 - 3 * x / 2 + std::pow(x, 3) / 2);
176
177 deltaN[i][j] += deltaN[i][j - 1] + 4.0 * Constants::PI * r * r *
178 rho[i] * (gofrs_[i][j] - 1) *
179 deltaR_;
180 gCorr_[i][j] = gofrs_[i][j] * (Ns[i] * (1 - V / meanVol_)) /
181 (Ns[i] * (1 - V / meanVol_) - deltaN[i][j] - kd[i]);
182
183 G_[i][j] += G_[i][j - 1] + (gCorr_[i][j] - 1) * w * deltaR_;
184 }
185 }
186 }
187
188 void KirkwoodBuff::writeRdf() {
189 std::ofstream ofs(outputFilename_.c_str());
190 if (ofs.is_open()) {
191 Revision r;
192 ofs << "# " << getAnalysisType() << "\n";
193 ofs << "# OpenMD " << r.getFullRevision() << "\n";
194 ofs << "# " << r.getBuildDate() << "\n";
195 ofs << "# selection script1: \"" << selectionScript1_;
196 ofs << "\"\tselection script2: \"" << selectionScript2_ << "\"\n";
197 if (!paramString_.empty())
198 ofs << "# parameters: " << paramString_ << "\n";
199
200 std::vector<std::string> labels {"g11", "g12", "g22", "gC11", "gC12",
201 "gC22", "G11", "G12", "G22"};
202
203 ofs << "# r";
204
205 for (const auto& label : labels)
206 ofs << "\t" << std::setw(15) << label;
207
208 ofs << '\n';
209
210 for (unsigned int j = 0; j < nBins_; ++j) {
211 RealType r = deltaR_ * j;
212 ofs << r;
213 for (unsigned int i = 0; i < MaxPairs; ++i) {
214 ofs << "\t" << std::setw(15) << gofrs_[i][j];
215 }
216 for (unsigned int i = 0; i < MaxPairs; ++i) {
217 ofs << "\t" << std::setw(15) << gCorr_[i][j];
218 }
219 for (unsigned int i = 0; i < MaxPairs; ++i) {
220 ofs << "\t" << std::setw(15) << G_[i][j];
221 }
222 ofs << "\n";
223 }
224 } else {
225 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
226 "KirkwoodBuff: unable to open %s\n", outputFilename_.c_str());
227 painCave.isFatal = 1;
228 simError();
229 }
230 ofs.close();
231 }
232} // namespace OpenMD
Multi-Component Radial Distribution Function.
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.
std::string getPrefix(const std::string &str)
Real distance(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the distance between two DynamicVectors.