OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
ChargeDensityZ.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/ChargeDensityZ.hpp"
49
50#include <algorithm>
51#include <functional>
52
53#include "brains/Thermo.hpp"
54#include "io/DumpReader.hpp"
56#include "types/FixedChargeAdapter.hpp"
57#include "types/FluctuatingChargeAdapter.hpp"
58#include "utils/Constants.hpp"
59#include "utils/simError.h"
60
61namespace OpenMD {
62
63 ChargeDensityZ::ChargeDensityZ(SimInfo* info, const std::string& filename,
64 const std::string& sele, int nzbins,
65 RealType vRadius, std::string atomName,
66 bool xyzGen, int axis) :
67 StaticAnalyser(info, filename, nzbins),
68 selectionScript_(sele), evaluator_(info), seleMan_(info), thermo_(info),
69 axis_(axis), vRadius_(vRadius), fileName_(filename),
70 atomFlucCharge_(atomName), genXYZ_(xyzGen) {
71 evaluator_.loadScriptString(sele);
72 if (!evaluator_.isDynamic()) {
73 seleMan_.setSelectionSet(evaluator_.evaluate());
74 }
75
76 // fixed number of bins
77
78 densityZAverageAllFrame_.resize(nBins_);
79 densityFlucZAverageAllFrame_.resize(nBins_);
80 absDensityFlucZAverageAllFrame_.resize(nBins_);
81 averageDensityZ_.resize(nBins_);
82 flucDensityZAverageAllFrame_.resize(nBins_);
83 std::fill(densityFlucZAverageAllFrame_.begin(),
84 densityFlucZAverageAllFrame_.end(), 0);
85 std::fill(densityZAverageAllFrame_.begin(), densityZAverageAllFrame_.end(),
86 0);
87 std::fill(absDensityFlucZAverageAllFrame_.begin(),
88 absDensityFlucZAverageAllFrame_.end(), 0);
89 std::fill(averageDensityZ_.begin(), averageDensityZ_.end(), 0);
90 std::fill(flucDensityZAverageAllFrame_.begin(),
91 flucDensityZAverageAllFrame_.end(), 0);
92
93 densityFlucZAverageFirstFrame_.resize(nBins_);
94 absDensityFlucZAverageFirstFrame_.resize(nBins_);
95 std::fill(densityFlucZAverageFirstFrame_.begin(),
96 densityFlucZAverageFirstFrame_.end(), 0);
97 std::fill(absDensityFlucZAverageFirstFrame_.begin(),
98 absDensityFlucZAverageFirstFrame_.end(), 0);
99
100 switch (axis_) {
101 case 0:
102 axisLabel_ = "x";
103 break;
104 case 1:
105 axisLabel_ = "y";
106 break;
107 case 2:
108 default:
109 axisLabel_ = "z";
110 break;
111 }
112
113 setOutputName(getPrefix(filename) + ".ChargeDensityZ");
114 }
115 void ChargeDensityZ::process() {
116 bool usePeriodicBoundaryConditions_ =
117 info_->getSimParams()->getUsePeriodicBoundaryConditions();
118
119 DumpReader reader(info_, dumpFilename_);
120 int nFrames_ = reader.getNFrames();
121 nProcessed_ = nFrames_ / step_;
122
123 // test using global index starts hereby
124
125 reader.readFrame(1);
126 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
127
128 hmat_ = currentSnapshot_->getHmat();
129 zBox_.push_back(hmat_(axis_, axis_));
130
131 std::vector<RealType>::iterator j;
132 RealType zSum = 0.0;
133 for (j = zBox_.begin(); j != zBox_.end(); ++j) {
134 zSum += *j;
135 }
136
137 RealType zAve = zSum / zBox_.size();
138 set<int> axisValues;
139 axisValues.insert(0);
140 axisValues.insert(1);
141 axisValues.insert(2);
142 axisValues.erase(axis_);
143 set<int>::iterator axis_it;
144 std::vector<int> cartesian_axis;
145 for (axis_it = axisValues.begin(); axis_it != axisValues.end(); ++axis_it) {
146 cartesian_axis.push_back(*axis_it);
147 }
148 x_ = cartesian_axis[0];
149 y_ = cartesian_axis[1];
150 RealType area = hmat_(x_, x_) * hmat_(y_, y_);
151 RealType sliceVolume = zAve / densityZAverageAllFrame_.size() * area;
152
153 for (int i = 1; i < nFrames_; i += step_) {
154 reader.readFrame(i);
155 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
156
157 if (evaluator_.isDynamic()) {
158 seleMan_.setSelectionSet(evaluator_.evaluate());
159 }
160
161 int kk;
162 for (StuntDouble* sd = seleMan_.beginSelected(kk); sd != NULL;
163 sd = seleMan_.nextSelected(kk)) {
164 if (!sd->isAtom()) {
165 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
166 "Can not calculate charge density distribution if it is not "
167 "atom\n");
168 painCave.severity = OPENMD_ERROR;
169 painCave.isFatal = 1;
170 simError();
171 }
172
173 RealType q = 0.0;
174 Atom* atom = static_cast<Atom*>(sd);
175
176 AtomType* atomType = atom->getAtomType();
177
178 if (sd->isAtom()) {
179 FixedChargeAdapter fca = FixedChargeAdapter(atomType);
180 if (fca.isFixedCharge()) { q += fca.getCharge(); }
181
182 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atomType);
183 if (fqa.isFluctuatingCharge()) { q += atom->getFlucQPos(); }
184 }
185 int obanum(0);
186 RealType sigma(0);
187 std::string atomName;
188 std::vector<AtomType*> atChain = atomType->allYourBase();
189 std::vector<AtomType*>::iterator i;
190 for (i = atChain.begin(); i != atChain.end(); ++i) {
191 atomName = (*i)->getName().c_str();
192 obanum = etab.GetAtomicNum((*i)->getName().c_str());
193 if (obanum != 0) {
194 sigma = etab.GetVdwRad(obanum);
195 break;
196 }
197 }
198 if (obanum == 0) { sigma = vRadius_; }
199
200 Vector3d pos = sd->getPos();
201 if (usePeriodicBoundaryConditions_) currentSnapshot_->wrapVector(pos);
202 sd->setPos(pos);
203
204 pos = sd->getPos();
205
206 int globalIndex = sd->getGlobalIndex();
207
208 atomNameGlobalIndex_[globalIndex] = atomName;
209 averageChargeUsingGlobalIndex_[globalIndex] =
210 (countUsingGlobalIndex_[globalIndex] *
211 averageChargeUsingGlobalIndex_[globalIndex] +
212 q) /
213 (countUsingGlobalIndex_[globalIndex] + 1);
214 totalChargeUsingGlobalIndex_[globalIndex].push_back(q);
215 zPosUsingGlobalIndex_[globalIndex].push_back(pos[axis_]);
216 xPosUsingGlobalIndex_[globalIndex].push_back(pos[x_]);
217 yPosUsingGlobalIndex_[globalIndex].push_back(pos[y_]);
218
219 vanderRUsingGlobalIndex_[globalIndex] = sigma;
220 countUsingGlobalIndex_[globalIndex]++;
221 }
222
223 for (std::map<int, std::string>::iterator it =
224 atomNameGlobalIndex_.begin();
225 it != atomNameGlobalIndex_.end(); ++it) {
226 int g_Index = it->first;
227 std::string a_name = it->second;
228 averageChargeForEachType_[a_name] =
229 (SDCount_[a_name] * averageChargeForEachType_[a_name] +
230 totalChargeUsingGlobalIndex_[g_Index].front()) /
231 (SDCount_[a_name] + 1);
232 SDCount_[a_name]++;
233 }
234 }
235 RealType epsilon = 1e-10;
236 for (std::map<int, std::string>::iterator it = atomNameGlobalIndex_.begin();
237 it != atomNameGlobalIndex_.end(); ++it) {
238 int key = it->first;
239 std::string a_name = it->second;
240
241 RealType averageCharge = averageChargeUsingGlobalIndex_[key];
242 RealType averageChargeUsingFirstFrame = averageChargeForEachType_[a_name];
243 RealType v_radius = vanderRUsingGlobalIndex_[key];
244 RealType v_radius2 = v_radius * v_radius;
245 for (size_t index = 0; index < zPosUsingGlobalIndex_[key].size();
246 ++index) {
247 RealType z_pos = zPosUsingGlobalIndex_[key][index];
248 RealType charge = totalChargeUsingGlobalIndex_[key][index];
249 RealType chargeDiff =
250 fabs(charge - averageCharge) > epsilon ? charge - averageCharge : 0;
251 RealType chargeDiffUsingFirstFrameAverage =
252 fabs(charge - averageChargeUsingFirstFrame) > epsilon ?
253 charge - averageChargeUsingFirstFrame :
254 0;
255
256 for (size_t i = 0; i < densityFlucZAverageAllFrame_.size(); ++i) {
257 RealType z = -zAve / 2 + i * zAve / densityZAverageAllFrame_.size();
258 RealType zdist = z_pos - z;
259
260 RealType gaussian_scale =
261 exp(-zdist * zdist / (v_radius2 * 2.0)) /
262 (sliceVolume * (sqrt(2 * Constants::PI * v_radius * v_radius)));
263 densityZAverageAllFrame_[i] += charge * gaussian_scale;
264
265 densityFlucZAverageAllFrame_[i] += chargeDiff * gaussian_scale;
266 absDensityFlucZAverageAllFrame_[i] +=
267 abs(chargeDiff) * abs(chargeDiff) * gaussian_scale;
268
269 densityFlucZAverageFirstFrame_[i] +=
270 chargeDiffUsingFirstFrameAverage * gaussian_scale;
271 absDensityFlucZAverageFirstFrame_[i] +=
272 abs(chargeDiffUsingFirstFrameAverage) *
273 abs(chargeDiffUsingFirstFrameAverage) * gaussian_scale;
274 }
275 }
276 }
277
278 writeDensity();
279
280 if (genXYZ_) generateXYZForLastFrame();
281 }
282
283 void ChargeDensityZ::writeDensity() {
284 // compute average box length:
285 std::vector<RealType>::iterator j;
286 RealType zSum = 0.0;
287 for (j = zBox_.begin(); j != zBox_.end(); ++j) {
288 zSum += *j;
289 }
290 RealType zAve = zSum / zBox_.size();
291
292 std::ofstream rdfStream(outputFilename_.c_str());
293 if (rdfStream.is_open()) {
294 rdfStream << "#ChargeDensityZ "
295 << "\n";
296 rdfStream << "#selection: (" << selectionScript_ << ")\n";
297 rdfStream
298 << "#" << axisLabel_
299 << "\tchargeDensity\tchargeDensityFluctuations_Average_on_all_frame\t"
300 << "Absolute_chargeDensityFluctuations_Average_on_all_frame\t"
301 << "chargeDensityFluctuations_Average_On_first_frame\t"
302 << "Absolute_chargeDensityFluctuations_Average_on_first_frame\n";
303
304 for (unsigned int i = 0; i < densityFlucZAverageAllFrame_.size(); ++i) {
305 RealType z = zAve * (i + 0.5) / densityFlucZAverageAllFrame_.size();
306 rdfStream << z << "\t" << densityZAverageAllFrame_[i] / nProcessed_
307 << "\t" << densityFlucZAverageAllFrame_[i] / (nProcessed_)
308 << "\t" << absDensityFlucZAverageAllFrame_[i] / (nProcessed_)
309 << "\t" << densityFlucZAverageFirstFrame_[i] / (nProcessed_)
310 << "\t"
311 << absDensityFlucZAverageFirstFrame_[i] / (nProcessed_)
312 << "\n";
313 }
314
315 } else {
316 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
317 "ChargeDensityZ: unable to open %s\n", outputFilename_.c_str());
318 painCave.isFatal = 1;
319 simError();
320 }
321
322 rdfStream.close();
323 }
324
325 void ChargeDensityZ::generateXYZForLastFrame() {
326 std::string XYZFile(getPrefix(fileName_) + ".xyz");
327 std::ofstream rdfStream(XYZFile.c_str());
328 int nAtoms = zPosUsingGlobalIndex_.size();
329
330 if (rdfStream.is_open()) {
331 rdfStream << nAtoms << "\n";
332 rdfStream << 1 << ";\t" << hmat_(x_, x_) << "\t" << hmat_(x_, y_) << "\t"
333 << hmat_(x_, axis_) << "\t" << hmat_(y_, x_) << "\t"
334 << hmat_(y_, y_) << "\t" << hmat_(y_, axis_) << "\t"
335 << hmat_(axis_, x_) << "\t" << hmat_(axis_, y_) << "\t"
336 << hmat_(axis_, axis_) << "\n";
337
338 for (std::map<int, std::string>::iterator it =
339 atomNameGlobalIndex_.begin();
340 it != atomNameGlobalIndex_.end(); ++it) {
341 int key = it->first;
342 std::string a_name = it->second;
343 RealType x = zPosUsingGlobalIndex_[key].back();
344 RealType y = xPosUsingGlobalIndex_[key].back();
345 RealType z = yPosUsingGlobalIndex_[key].back();
346 RealType charge = 0;
347
348 if (a_name == atomFlucCharge_) {
349 for (std::map<int, std::string>::iterator it1 =
350 atomNameGlobalIndex_.begin();
351 it1 != atomNameGlobalIndex_.end(); ++it1) {
352 int key1 = it1->first;
353 std::string a_name1 = it1->second;
354
355 RealType v_radius = vanderRUsingGlobalIndex_[key1];
356 RealType v_radius2 = v_radius * v_radius;
357 RealType averageCharge = averageChargeUsingGlobalIndex_[key1];
358
359 for (size_t index = 0; index < zPosUsingGlobalIndex_[key1].size();
360 ++index) {
361 RealType xt = xPosUsingGlobalIndex_[key][index];
362 RealType yt = yPosUsingGlobalIndex_[key][index];
363 RealType zt = zPosUsingGlobalIndex_[key][index];
364
365 RealType z_pos = zPosUsingGlobalIndex_[key1][index];
366 RealType x_pos = xPosUsingGlobalIndex_[key1][index];
367 RealType y_pos = yPosUsingGlobalIndex_[key1][index];
368 RealType r2 = (xt - x_pos) * (xt - x_pos) +
369 (yt - y_pos) * (yt - y_pos) +
370 (zt - z_pos) * (zt - z_pos);
371
372 RealType charge_for_atom =
373 totalChargeUsingGlobalIndex_[key1][index];
374 RealType chargeDiff =
375 fabs(charge_for_atom - averageCharge) > epsilon ?
376 charge_for_atom - averageCharge :
377 0;
378 RealType gaussian_scale =
379 exp(-r2 / (v_radius2 * 2.0)) /
380 (sqrt(2 * Constants::PI * v_radius * v_radius));
381 // RealType gaussian_scale = 2 * (r2 /( v_radius2 * v_radius)) *
382 // exp(-r2/(v_radius2*2.0)) / (sqrt(2*Constants::PI)* v_radius2 *
383 // v_radius);
384 charge += chargeDiff * gaussian_scale;
385 }
386 }
387 charge /= (nProcessed_ * atomNameGlobalIndex_.size());
388
389 } else {
390 charge = totalChargeUsingGlobalIndex_[key].back();
391 }
392
393 rdfStream << a_name << "\t" << x << "\t" << y << "\t" << z << "\t"
394 << charge << "\n";
395 }
396
397 } else {
398 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
399 "XYZ file: unable to open %s\n", outputFilename_.c_str());
400 painCave.isFatal = 1;
401 simError();
402 }
403
404 rdfStream.close();
405 }
406} // namespace OpenMD
RealType GetVdwRad(int atomicnum)
int GetAtomicNum(const char *str)
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)