OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SurfaceDiffusion.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/* Surface Diffusion
49 * Attempting to track/measure the surface diffusion rates of particles on...
50 * wait for it.. a surface. This program was initially created to track Platinum
51 * particles moving around a 557 surface. Hence why we are trying to keep the x
52 * and y movement separate.
53 *
54 */
55
56#include "applications/staticProps/SurfaceDiffusion.hpp"
57
58#include <algorithm>
59#include <fstream>
60
61#include "io/DumpReader.hpp"
63#include "utils/simError.h"
64
65namespace OpenMD {
66
67 SurfaceDiffusion::SurfaceDiffusion(SimInfo* info, const std::string& filename,
68 const std::string& sele, RealType) :
69 StaticAnalyser(info, filename, 1),
70 selectionScript_(sele), evaluator_(info), seleMan1_(info) {
71 evaluator_.loadScriptString(sele);
72 if (!evaluator_.isDynamic()) {
73 seleMan1_.setSelectionSet(evaluator_.evaluate());
74 }
75
76 // Depending on the selection 'sele1="select Pt"' need a vector equal to the
77 // number of Platinums in the system (for this specific case)
78 selectionCount_ = seleMan1_.getSelectionCount();
79 cout << "SelectionCount_: " << selectionCount_ << "\n";
80
81 moBool_.resize(selectionCount_);
82 positions_.resize(selectionCount_);
83
84 filename_ = filename;
85 singleMoveDistance_ = 2.0;
86 }
87
88 void SurfaceDiffusion::process() {
89 StuntDouble* sd;
90 bool usePeriodicBoundaryConditions_ =
91 info_->getSimParams()->getUsePeriodicBoundaryConditions();
92
93 DumpReader reader(info_, dumpFilename_);
94 int nFrames = reader.getNFrames();
95 frames_ = 0;
96 nProcessed_ = nFrames / step_;
97
98 // positions_ and moBool_ are 2D arrays, need the second dimension
99 // filled as well
100 for (int i = 0; i < selectionCount_; i++) {
101 moBool_[i].resize(nFrames);
102 positions_[i].resize(nFrames);
103 }
104
105 int iterator;
106 int index = 0;
107 /* Loop over all frames storing the positions in a vec< vec<pos> >
108 * At the end, positions.length() should equal seleMan1_.size() or
109 * w/e And positions[index].length() should equal nFrames (or
110 * nFrames/istep)
111 */
112 for (int istep = 0; istep < nFrames; istep += step_) {
113 frames_++;
114 reader.readFrame(istep);
115 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
116
117 index = 0; // count over atoms since iterators aren't the most
118 // friendly for such plebian things
119 for (sd = seleMan1_.beginSelected(iterator); sd != NULL;
120 sd = seleMan1_.nextSelected(iterator)) {
121 Vector3d pos = sd->getPos();
122 positions_[index][istep] = pos;
123 index++;
124 }
125 }
126
127 cout << "Position Array size: " << positions_.size() << "\n";
128 cout << "Frames analyzed: " << positions_[0].size() << "\n";
129
130 for (std::size_t i = 0; i < positions_.size(); i++) {
131 int frameIndex = positions_[i].size();
132 for (int j = 1; j < frameIndex; j++) {
133 Vector3d posF1 = positions_[i][j - 1];
134 Vector3d posF2 = positions_[i][j];
135 Vector3d diff = posF2 - posF1;
136 if (usePeriodicBoundaryConditions_) {
137 currentSnapshot_->wrapVector(diff);
138 }
139 double dist = diff.length();
140 if (dist > singleMoveDistance_) {
141 moBool_[i][j] = true;
142 } else {
143 moBool_[i][j] = false;
144 }
145 }
146 }
147
148 int mobileAtomCount = 0;
149 for (std::size_t i = 0; i < moBool_.size(); i++) {
150 int frameIndex = moBool_[i].size();
151 bool mobileAtom = false;
152 for (int j = 0; j < frameIndex; j++) {
153 mobileAtom = mobileAtom || moBool_[i][j];
154 }
155 moBool_[i][0] = mobileAtom; // is true if any value later in the
156 // array is true, false otherwise
157 if (mobileAtom) { mobileAtomCount++; }
158 }
159
160 cout << "Mobile atom count: " << mobileAtomCount << "\n";
161
162 // Here I shrink the size of the arrays, why look through 3888,
163 // when you only need ~800. Additionally, all of these are mobile
164 // at some point in time, the others aren't, dead weight and
165 // memory
166 positions2_.resize(mobileAtomCount);
167 moBool2_.resize(mobileAtomCount);
168 int pos2index = 0;
169 for (std::size_t i = 0; i < positions_.size(); i++) {
170 int frameCount = positions_[i].size();
171 if (moBool_[i][0]) {
172 for (int j = 0; j < frameCount; j++) {
173 positions2_[pos2index].push_back(positions_[i][j]);
174 moBool2_[pos2index].push_back(moBool_[i][j]);
175 }
176 pos2index++;
177 }
178 }
179
180 positions_.clear();
181 moBool_.clear();
182
183 cout << "positions_ has been cleared: " << positions_.size() << "\n";
184 cout << "positions2_ has been filled: " << positions2_.size() << "\n";
185 cout << "positions2_ has " << positions2_[0].size() << " frames\n";
186
187 // The important one!
188 positionCorrelation();
189
190 // Write out my data
191 std::ofstream diffStream;
192 setOutputName(getPrefix(filename_) + ".Mdiffusion");
193 diffStream.open(outputFilename_.c_str());
194 diffStream << "#X&Y diffusion amounts\n";
195 diffStream << "#singleMoveDistance_: " << singleMoveDistance_ << "\n";
196 diffStream << "#Number of mobile atoms: " << positions2_.size() << "\n";
197 diffStream << "#time, <x(t)-x(0)>, <y(t)-y(0)>, <r(t)-r(0)>\n";
198
199 for (std::size_t i = 0; i < xHist_.size(); i++) {
200 diffStream << i << ", " << xHist_[i] << ", " << yHist_[i] << ", "
201 << rHist_[i] << "\n";
202 }
203 diffStream.close();
204 }
205
206 void SurfaceDiffusion::positionCorrelation() {
207 RealType xDist = 0.0;
208 RealType yDist = 0.0;
209 RealType rDist = 0.0;
210 int timeShift = 0;
211 Vector3d kPos;
212 Vector3d jPos;
213 // biggest timeShift is positions2_[0].size() - 1?
214 xHist_.clear();
215 yHist_.clear();
216 rHist_.clear();
217 count_.clear();
218 int frameResize = positions2_[0].size();
219 xHist_.resize(frameResize);
220 yHist_.resize(frameResize);
221 rHist_.resize(frameResize);
222 count_.resize(frameResize);
223 // loop over particles
224 // loop over frames starting at j
225 // loop over frames starting at k = j (time shift of 0)
226 for (std::size_t i = 0; i < positions2_.size(); i++) {
227 int frames = positions2_[i].size() - 1; // for counting
228 // properly, otherwise
229 // moBool2_[i][j+1] will
230 // go over
231 for (int j = 0; j < frames; j++) {
232 // if the particle is mobile between j and j + 1, then count
233 // it for all timeShifts
234 if (moBool2_[i][j + 1]) {
235 for (std::size_t k = j; k < positions2_[0].size(); k++) {
236 //<x(t)-x(0)> <y(t)-y(0)> <r(t)-r(0)>
237 // The positions stored are not wrapped, thus I don't need
238 // to worry about pbc
239 // Mean square displacement
240 // So I do want the squared distances
241
242 kPos = positions2_[i][k];
243 jPos = positions2_[i][j];
244 xDist = kPos.x() - jPos.x();
245 xDist = xDist * xDist;
246
247 yDist = kPos.y() - jPos.y();
248 yDist = yDist * yDist;
249
250 rDist = (kPos - jPos).lengthSquare();
251
252 timeShift = k - j;
253 xHist_[timeShift] += xDist;
254 yHist_[timeShift] += yDist;
255 rHist_[timeShift] += rDist;
256 count_[timeShift]++;
257 }
258 }
259 }
260 }
261 cout << "X, Y, R calculated\n";
262
263 for (std::size_t i = 0; i < xHist_.size(); i++) {
264 xHist_[i] = xHist_[i] / (count_[i]);
265 yHist_[i] = yHist_[i] / (count_[i]);
266 rHist_[i] = rHist_[i] / (count_[i]);
267 }
268 cout << "X, Y, R normalized\n";
269 }
270
271} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
Real length() const
Returns the length of this vector.
Definition Vector.hpp:397
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
std::string getPrefix(const std::string &str)