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