OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
CoordinationNumber.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/CoordinationNumber.hpp"
49
50#include <algorithm>
51#include <fstream>
52#include <sstream>
53
54#include "io/DumpReader.hpp"
55#include "utils/Revision.hpp"
56#include "utils/simError.h"
57
58namespace OpenMD {
59
60 CoordinationNumber::CoordinationNumber(SimInfo* info,
61 const std::string& filename,
62 const std::string& sele1,
63 const std::string& sele2,
64 RealType rCut, int bins) :
65 StaticAnalyser(info, filename, bins),
66 rCut_(rCut), bins_(bins), sele1_(sele1), seleMan1_(info),
67 evaluator1_(info), sele2_(sele2), seleMan2_(info), evaluator2_(info) {
68 setAnalysisType("Coordination Number Distribution");
69 setOutputName(getPrefix(filename) + ".cn");
70
71 nnMax_ = 12;
72 RealType binMax_ = nnMax_ * 1.5;
73 delta_ = binMax_ / bins_;
74
75 std::stringstream params;
76 params << " rcut = " << rCut_ << ", nbins = " << bins_
77 << ", nnMax = " << nnMax_;
78 const std::string paramString = params.str();
79 setParameterString(paramString);
80
81 evaluator1_.loadScriptString(sele1);
82 if (!evaluator1_.isDynamic()) {
83 seleMan1_.setSelectionSet(evaluator1_.evaluate());
84 selectionCount1_ = seleMan1_.getSelectionCount();
85 }
86 evaluator2_.loadScriptString(sele2);
87 if (!evaluator2_.isDynamic()) {
88 seleMan2_.setSelectionSet(evaluator2_.evaluate());
89 selectionCount2_ = seleMan2_.getSelectionCount();
90 }
91 }
92
93 void CoordinationNumber::process() {
94 SelectionManager common(info_);
95
96 std::vector<std::vector<int>> listNN;
97 std::vector<int> globalToLocal;
98
99 StuntDouble* sd1;
100 StuntDouble* sd2;
101
102 Snapshot* currentSnapshot_;
103 bool usePeriodicBoundaryConditions_ =
104 info_->getSimParams()->getUsePeriodicBoundaryConditions();
105
106 int iterator1;
107 int iterator2;
108 unsigned int mapIndex1(0);
109 unsigned int mapIndex2(0);
110 unsigned int whichBin(0);
111 RealType cn(0.0);
112 Vector3d pos1;
113 Vector3d pos2;
114 Vector3d diff;
115 RealType distance;
116
117 histogram_.clear();
118 histogram_.resize(bins_, 0.0);
119
120 DumpReader reader(info_, dumpFilename_);
121 int nFrames = reader.getNFrames();
122 count_ = 0;
123
124 // First have to calculate lists of nearest neighbors (listNN_):
125
126 for (int istep = 0; istep < nFrames; istep += step_) {
127 reader.readFrame(istep);
128 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
129
130 if (evaluator1_.isDynamic()) {
131 seleMan1_.setSelectionSet(evaluator1_.evaluate());
132 selectionCount1_ = seleMan1_.getSelectionCount();
133 }
134 if (evaluator2_.isDynamic()) {
135 seleMan2_.setSelectionSet(evaluator2_.evaluate());
136 selectionCount2_ = seleMan2_.getSelectionCount();
137 }
138
139 // We need a common selection set:
140 common = seleMan1_ | seleMan2_;
141 int commonCount = common.getSelectionCount();
142
143 globalToLocal.clear();
144 globalToLocal.resize(
145 info_->getNGlobalAtoms() + info_->getNGlobalRigidBodies(), -1);
146 for (unsigned int i = 0; i < listNN.size(); i++)
147 listNN.at(i).clear();
148 listNN.clear();
149 listNN.resize(commonCount);
150
151 mapIndex1 = 0;
152 for (sd1 = common.beginSelected(iterator1); sd1 != NULL;
153 sd1 = common.nextSelected(iterator1)) {
154 globalToLocal.at(sd1->getGlobalIndex()) = mapIndex1;
155
156 pos1 = sd1->getPos();
157
158 mapIndex2 = 0;
159 for (sd2 = common.beginSelected(iterator2); sd2 != NULL;
160 sd2 = common.nextSelected(iterator2)) {
161 if (mapIndex1 < mapIndex2) {
162 pos2 = sd2->getPos();
163 diff = pos2 - pos1;
164 if (usePeriodicBoundaryConditions_)
165 currentSnapshot_->wrapVector(diff);
166 distance = diff.length();
167 if (distance < rCut_) {
168 listNN.at(mapIndex1).push_back(mapIndex2);
169 listNN.at(mapIndex2).push_back(mapIndex1);
170 }
171 }
172 mapIndex2++;
173 }
174 mapIndex1++;
175 }
176
177 // Fill up the histogram with cn values
178
179 for (sd1 = seleMan1_.beginSelected(iterator1); sd1 != NULL;
180 sd1 = seleMan1_.nextSelected(iterator1)) {
181 mapIndex1 = globalToLocal.at(sd1->getGlobalIndex());
182
183 cn = computeCoordination(mapIndex1, listNN);
184 whichBin = int(cn / delta_);
185
186 if (whichBin < histogram_.size()) {
187 histogram_[whichBin] += 1;
188 } else {
189 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
190 "Coordination Number: Error: "
191 "In frame, %d, object %d has CN %lf outside of range max.\n",
192 istep, sd1->getGlobalIndex(), cn);
193 painCave.isFatal = 1;
194 simError();
195 }
196 }
197 count_ += selectionCount1_;
198 }
199
200 for (unsigned int n = 0; n < histogram_.size(); n++) {
201 if (count_ > 0)
202 histogram_[n] /= RealType(count_);
203 else
204 histogram_[n] = 0.0;
205 }
206
207 writeOutput();
208 }
209
210 RealType CoordinationNumber::computeCoordination(int a,
211 vector<vector<int>> nl) {
212 return RealType(nl.at(a).size());
213 }
214
215 void CoordinationNumber::writeOutput() {
216 std::ofstream ofs(outputFilename_.c_str(), std::ios::binary);
217
218 if (ofs.is_open()) {
219 Revision r;
220 RealType binValue(0.0);
221
222 ofs << "# " << getAnalysisType() << "\n";
223 ofs << "# OpenMD " << r.getFullRevision() << "\n";
224 ofs << "# " << r.getBuildDate() << "\n";
225 ofs << "# selection script1: \"" << sele1_;
226 ofs << "\"\tselection script2: \"" << sele2_ << "\"\n";
227 if (!paramString_.empty())
228 ofs << "# parameters: " << paramString_ << "\n";
229
230 for (unsigned int n = 0; n < histogram_.size(); n++) {
231 binValue = n * delta_;
232 ofs << binValue << "\t" << histogram_[n] / delta_ << "\n";
233 }
234 }
235 ofs.close();
236 }
237
238 SCN::SCN(SimInfo* info, const std::string& filename, const std::string& sele1,
239 const std::string& sele2, RealType rCut, int bins) :
240 CoordinationNumber(info, filename, sele1, sele2, rCut, bins) {
241 setOutputName(getPrefix(filename) + ".scn");
242 setAnalysisType("Secondary Coordination Number");
243 }
244
245 RealType SCN::computeCoordination(int a, vector<vector<int>> nl) {
246 RealType scn = 0.0;
247 int b;
248
249 if (nl.at(a).size() != 0) {
250 for (unsigned int i = 0; i < nl.at(a).size(); i++) {
251 // b is the index of one of i's nearest neighbors
252 b = nl.at(a).at(i);
253 scn += nl.at(b).size();
254 }
255 return scn / RealType(nl.at(a).size());
256 } else {
257 return 0.0;
258 }
259 }
260
261 GCN::GCN(SimInfo* info, const std::string& filename, const std::string& sele1,
262 const std::string& sele2, RealType rCut, int bins) :
263 CoordinationNumber(info, filename, sele1, sele2, rCut, bins) {
264 setOutputName(getPrefix(filename) + ".gcn");
265 setAnalysisType("Generalized Coordination Number");
266 }
267
268 RealType GCN::computeCoordination(int a, vector<vector<int>> nl) {
269 RealType gcn = 0.0;
270 int b;
271 for (unsigned int i = 0; i < nl.at(a).size(); i++) {
272 // b is the index of one of i's nearest neighbors
273 b = nl.at(a).at(i);
274 gcn += nl.at(b).size();
275 }
276 return gcn / RealType(nnMax_);
277 }
278} // 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.
std::string getPrefix(const std::string &str)
Real distance(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the distance between two DynamicVectors.