OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
TetrahedralityParamXYZ.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/TetrahedralityParamXYZ.hpp"
49
50#include <algorithm>
51#include <fstream>
52#include <vector>
53
54#include "io/DumpReader.hpp"
56#include "utils/Constants.hpp"
57#include "utils/simError.h"
58
59using namespace std;
60namespace OpenMD {
61 TetrahedralityParamXYZ::TetrahedralityParamXYZ(
62 SimInfo* info, const std::string& filename, const std::string& sele1,
63 const std::string& sele2, RealType rCut, RealType voxelSize,
64 RealType gaussWidth) :
65 StaticAnalyser(info, filename, 1),
66 selectionScript1_(sele1), selectionScript2_(sele2), seleMan1_(info),
67 seleMan2_(info), evaluator1_(info), evaluator2_(info), rCut_(rCut),
68 voxelSize_(voxelSize), gaussWidth_(gaussWidth) {
69 evaluator1_.loadScriptString(sele1);
70 if (!evaluator1_.isDynamic()) {
71 seleMan1_.setSelectionSet(evaluator1_.evaluate());
72 }
73 evaluator2_.loadScriptString(sele2);
74 if (!evaluator2_.isDynamic()) {
75 seleMan2_.setSelectionSet(evaluator2_.evaluate());
76 }
77
78 Mat3x3d hmat = info->getSnapshotManager()->getCurrentSnapshot()->getHmat();
79
80 nBins_(0) = int(hmat(0, 0) / voxelSize);
81 nBins_(1) = int(hmat(1, 1) / voxelSize);
82 nBins_(2) = int(hmat(2, 2) / voxelSize);
83
84 hist_.resize(nBins_(0));
85 count_.resize(nBins_(0));
86 for (int i = 0; i < nBins_(0); ++i) {
87 hist_[i].resize(nBins_(1));
88 count_[i].resize(nBins_(1));
89 for (int j = 0; j < nBins_(1); ++j) {
90 hist_[i][j].resize(nBins_(2));
91 count_[i][j].resize(nBins_(2));
92 std::fill(hist_[i][j].begin(), hist_[i][j].end(), 0.0);
93 std::fill(count_[i][j].begin(), count_[i][j].end(), 0.0);
94 }
95 }
96
97 setOutputName(getPrefix(filename) + ".Qxyz");
98 }
99
100 void TetrahedralityParamXYZ::process() {
101 StuntDouble* sd;
102 StuntDouble* sd2;
103 StuntDouble* sdi;
104 StuntDouble* sdj;
105 int myIndex;
106 Vector3d vec;
107 Vector3d ri, rj, rk, rik, rkj;
108 RealType r;
109 RealType cospsi;
110 RealType Qk;
111 std::vector<std::pair<RealType, StuntDouble*>> myNeighbors;
112 // std::vector<std::pair<Vector3d, RealType> > qvals;
113 // std::vector<std::pair<Vector3d, RealType> >::iterator qiter;
114 int isd1;
115 int isd2;
116 bool usePeriodicBoundaryConditions_ =
117 info_->getSimParams()->getUsePeriodicBoundaryConditions();
118
119 int kMax = int(5.0 * gaussWidth_ / voxelSize_);
120 int kSqLim = kMax * kMax;
121 cerr << "gw = " << gaussWidth_ << " vS = " << voxelSize_
122 << " kMax = " << kMax << " kSqLim = " << kSqLim << "\n";
123
124 DumpReader reader(info_, dumpFilename_);
125 int nFrames = reader.getNFrames();
126
127 for (int istep = 0; istep < nFrames; istep += step_) {
128 reader.readFrame(istep);
129
130 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
131 Mat3x3d hmat = currentSnapshot_->getHmat();
132 Vector3d halfBox = Vector3d(hmat(0, 0), hmat(1, 1), hmat(2, 2)) / 2.0;
133
134 if (evaluator1_.isDynamic()) {
135 seleMan1_.setSelectionSet(evaluator1_.evaluate());
136 }
137
138 if (evaluator2_.isDynamic()) {
139 seleMan2_.setSelectionSet(evaluator2_.evaluate());
140 }
141
142 // qvals.clear();
143
144 // outer loop is over the selected StuntDoubles:
145 for (sd = seleMan1_.beginSelected(isd1); sd != NULL;
146 sd = seleMan1_.nextSelected(isd1)) {
147 myIndex = sd->getGlobalIndex();
148
149 Qk = 1.0;
150 myNeighbors.clear();
151
152 for (sd2 = seleMan2_.beginSelected(isd2); sd2 != NULL;
153 sd2 = seleMan2_.nextSelected(isd2)) {
154 if (sd2->getGlobalIndex() != myIndex) {
155 vec = sd->getPos() - sd2->getPos();
156
157 if (usePeriodicBoundaryConditions_)
158 currentSnapshot_->wrapVector(vec);
159
160 r = vec.length();
161
162 // Check to see if neighbor is in bond cutoff
163
164 if (r < rCut_) { myNeighbors.push_back(std::make_pair(r, sd2)); }
165 }
166 }
167
168 // Sort the vector using predicate and std::sort
169 std::sort(myNeighbors.begin(), myNeighbors.end());
170
171 // Use only the 4 closest neighbors to do the rest of the work:
172
173 int nbors = myNeighbors.size() > 4 ? 4 : myNeighbors.size();
174 int nang = int(0.5 * (nbors * (nbors - 1)));
175
176 rk = sd->getPos();
177
178 for (int i = 0; i < nbors - 1; i++) {
179 sdi = myNeighbors[i].second;
180 ri = sdi->getPos();
181 rik = rk - ri;
182 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(rik);
183
184 rik.normalize();
185
186 for (int j = i + 1; j < nbors; j++) {
187 sdj = myNeighbors[j].second;
188 rj = sdj->getPos();
189 rkj = rk - rj;
190 if (usePeriodicBoundaryConditions_)
191 currentSnapshot_->wrapVector(rkj);
192 rkj.normalize();
193
194 cospsi = dot(rik, rkj);
195
196 // Calculates scaled Qk for each molecule using calculated
197 // angles from 4 or fewer nearest neighbors.
198 Qk -= (pow(cospsi + 1.0 / 3.0, 2) * 2.25 / nang);
199 }
200 }
201
202 if (nang > 0) {
203 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(rk);
204 // qvals.push_back(std::make_pair(rk, Qk));
205
206 Vector3d pos = rk + halfBox;
207
208 Vector3i whichVoxel(int(pos[0] / voxelSize_),
209 int(pos[1] / voxelSize_),
210 int(pos[2] / voxelSize_));
211
212 for (int l = -kMax; l <= kMax; l++) {
213 for (int m = -kMax; m <= kMax; m++) {
214 for (int n = -kMax; n <= kMax; n++) {
215 int kk = l * l + m * m + n * n;
216 if (kk <= kSqLim) {
217 int ll = (whichVoxel[0] + l) % nBins_(0);
218 ll = ll < 0 ? nBins_(0) + ll : ll;
219 int mm = (whichVoxel[1] + m) % nBins_(1);
220 mm = mm < 0 ? nBins_(1) + mm : mm;
221 int nn = (whichVoxel[2] + n) % nBins_(2);
222 nn = nn < 0 ? nBins_(2) + nn : nn;
223
224 Vector3d bPos = Vector3d(ll, mm, nn) * voxelSize_ - halfBox;
225 Vector3d d = bPos - rk;
226 currentSnapshot_->wrapVector(d);
227 RealType denom =
228 pow(2.0 * sqrt(Constants::PI) * gaussWidth_, 3);
229 RealType exponent = -dot(d, d) / pow(2.0 * gaussWidth_, 2);
230 RealType weight = exp(exponent) / denom;
231 count_[ll][mm][nn] += weight;
232 hist_[ll][mm][nn] += weight * Qk;
233 }
234 }
235 }
236 }
237 }
238 }
239
240 // for (int i = 0; i < nBins_(0); ++i) {
241 // for(int j = 0; j < nBins_(1); ++j) {
242 // for(int k = 0; k < nBins_(2); ++k) {
243 // Vector3d pos = Vector3d(i, j, k) * voxelSize_ - halfBox;
244 // for(qiter = qvals.begin(); qiter != qvals.end(); ++qiter) {
245 // Vector3d d = pos - (*qiter).first;
246 // currentSnapshot_->wrapVector(d);
247 // RealType denom = pow(2.0 * sqrt(Constants::PI) * gaussWidth_,
248 // 3); RealType exponent = -dot(d,d) / pow(2.0*gaussWidth_, 2);
249 // RealType weight = exp(exponent) / denom;
250 // count_[i][j][k] += weight;
251 // hist_[i][j][k] += weight * (*qiter).second;
252 // }
253 // }
254 // }
255 // }
256 }
257 // writeQxyz();
258 writeVTKGrid();
259 }
260
261 void TetrahedralityParamXYZ::writeVTKGrid() {
262 Mat3x3d hmat = info_->getSnapshotManager()->getCurrentSnapshot()->getHmat();
263
264 // normalize by total weight in voxel:
265 for (unsigned int i = 0; i < hist_.size(); ++i) {
266 for (unsigned int j = 0; j < hist_[i].size(); ++j) {
267 for (unsigned int k = 0; k < hist_[i][j].size(); ++k) {
268 hist_[i][j][k] = hist_[i][j][k] / count_[i][j][k];
269 }
270 }
271 }
272
273 std::ofstream qXYZstream(outputFilename_.c_str());
274 if (qXYZstream.is_open()) {
275 qXYZstream << "# vtk DataFile Version 2.0\n";
276 qXYZstream << "Tetrahedrality Parameter volume rendering\n";
277 qXYZstream << "ASCII\n";
278 qXYZstream << "DATASET RECTILINEAR_GRID\n";
279 qXYZstream << "DIMENSIONS " << hist_.size() << " " << hist_[0].size()
280 << " " << hist_[0][0].size() << "\n";
281 qXYZstream << "X_COORDINATES " << hist_.size() << " float\n";
282 for (std::size_t i = 0; i < hist_.size(); ++i) {
283 qXYZstream << (RealType(i) / nBins_.x()) * hmat(0, 0) << " ";
284 }
285 qXYZstream << "\n";
286 qXYZstream << "Y_COORDINATES " << hist_[0].size() << " float\n";
287 for (std::size_t j = 0; j < hist_[0].size(); ++j) {
288 qXYZstream << (RealType(j) / nBins_.y()) * hmat(1, 1) << " ";
289 }
290 qXYZstream << "\n";
291 qXYZstream << "Z_COORDINATES " << hist_[0][0].size() << " float\n";
292 for (std::size_t k = 0; k < hist_[0][0].size(); ++k) {
293 qXYZstream << (RealType(k) / nBins_.z()) * hmat(2, 2) << " ";
294 }
295 qXYZstream << "\n";
296 qXYZstream << "POINT_DATA "
297 << hist_.size() * hist_[0].size() * hist_[0][0].size() << "\n";
298 qXYZstream << "SCALARS scalars float\n";
299 qXYZstream << "LOOKUP_TABLE default\n";
300
301 for (std::size_t k = 0; k < hist_[0][0].size(); ++k) {
302 for (std::size_t j = 0; j < hist_[0].size(); ++j) {
303 for (std::size_t i = 0; i < hist_.size(); ++i) {
304 qXYZstream << hist_[i][j][k] << " ";
305
306 // qXYZstream.write(reinterpret_cast<char *>( &hist_[i][j][k] ),
307 // sizeof( hist_[i][j][k] ));
308 }
309 }
310 }
311 qXYZstream << "\n";
312 } else {
313 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
314 "TetrahedralityParamXYZ: unable to open %s\n",
315 outputFilename_.c_str());
316 painCave.isFatal = 1;
317 simError();
318 }
319 qXYZstream.close();
320 }
321
322 void TetrahedralityParamXYZ::writeQxyz() {
323 Mat3x3d hmat = info_->getSnapshotManager()->getCurrentSnapshot()->getHmat();
324
325 // normalize by total weight in voxel:
326 for (unsigned int i = 0; i < hist_.size(); ++i) {
327 for (unsigned int j = 0; j < hist_[i].size(); ++j) {
328 for (unsigned int k = 0; k < hist_[i][j].size(); ++k) {
329 hist_[i][j][k] = hist_[i][j][k] / count_[i][j][k];
330 }
331 }
332 }
333
334 std::ofstream qXYZstream(outputFilename_.c_str());
335 if (qXYZstream.is_open()) {
336 qXYZstream << "# AmiraMesh ASCII 1.0\n\n";
337 qXYZstream << "# Dimensions in x-, y-, and z-direction\n";
338 qXYZstream << " define Lattice " << hist_.size() << " "
339 << hist_[0].size() << " " << hist_[0][0].size() << "\n";
340
341 qXYZstream << "Parameters {\n";
342 qXYZstream << " CoordType \"uniform\",\n";
343 qXYZstream << " # BoundingBox is xmin xmax ymin ymax zmin zmax\n";
344 qXYZstream << " BoundingBox 0.0 " << hmat(0, 0) << " 0.0 "
345 << hmat(1, 1) << " 0.0 " << hmat(2, 2) << "\n";
346 qXYZstream << "}\n";
347
348 qXYZstream << "Lattice { double ScalarField } = @1\n";
349
350 qXYZstream << "@1\n";
351
352 for (std::size_t k = 0; k < hist_[0][0].size(); ++k) {
353 for (std::size_t j = 0; j < hist_[0].size(); ++j) {
354 for (std::size_t i = 0; i < hist_.size(); ++i) {
355 qXYZstream << hist_[i][j][k] << " ";
356
357 // qXYZstream.write(reinterpret_cast<char *>( &hist_[i][j][k] ),
358 // sizeof( hist_[i][j][k] ));
359 }
360 }
361 }
362
363 } else {
364 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
365 "TetrahedralityParamXYZ: unable to open %s\n",
366 outputFilename_.c_str());
367 painCave.isFatal = 1;
368 simError();
369 }
370 qXYZstream.close();
371 }
372} // 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.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
std::string getPrefix(const std::string &str)