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