OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
HBondGeometric.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/HBondGeometric.hpp"
49
50#include <vector>
51
52#include "io/DumpReader.hpp"
54#include "utils/Constants.hpp"
55#include "utils/simError.h"
56
57namespace OpenMD {
58
59 HBondGeometric::HBondGeometric(SimInfo* info, const std::string& filename,
60 const std::string& sele1,
61 const std::string& sele2, double rCut,
62 double thetaCut, int nbins) :
63 StaticAnalyser(info, filename, nbins),
64 selectionScript1_(sele1), seleMan1_(info), evaluator1_(info),
65 selectionScript2_(sele2), seleMan2_(info), evaluator2_(info) {
66 setOutputName(getPrefix(filename) + ".hbg");
67
68 ff_ = info_->getForceField();
69
70 evaluator1_.loadScriptString(sele1);
71 if (!evaluator1_.isDynamic()) {
72 seleMan1_.setSelectionSet(evaluator1_.evaluate());
73 }
74 evaluator2_.loadScriptString(sele2);
75 if (!evaluator2_.isDynamic()) {
76 seleMan2_.setSelectionSet(evaluator2_.evaluate());
77 }
78
79 // Set up cutoff values:
80 nBins_ = nbins;
81 rCut_ = rCut;
82 thetaCut_ = thetaCut;
83
84 nHBonds_.resize(nBins_);
85 nDonor_.resize(nBins_);
86 nAcceptor_.resize(nBins_);
87
88 initializeHistogram();
89 }
90
91 void HBondGeometric::initializeHistogram() {
92 std::fill(nHBonds_.begin(), nHBonds_.end(), 0);
93 std::fill(nDonor_.begin(), nDonor_.end(), 0);
94 std::fill(nAcceptor_.begin(), nAcceptor_.end(), 0);
95 nSelected_ = 0;
96 }
97
98 void HBondGeometric::process() {
99 Molecule* mol1;
100 Molecule* mol2;
101 Molecule::HBondDonor* hbd1;
102 Molecule::HBondDonor* hbd2;
103 std::vector<Molecule::HBondDonor*>::iterator hbdi;
104 std::vector<Molecule::HBondDonor*>::iterator hbdj;
105 std::vector<Atom*>::iterator hbai;
106 std::vector<Atom*>::iterator hbaj;
107 Atom* hba1;
108 Atom* hba2;
109 Vector3d dPos;
110 Vector3d aPos;
111 Vector3d hPos;
112 Vector3d DH;
113 Vector3d DA;
114 RealType DAdist, DHdist, theta, ctheta;
115 int ii, jj;
116 int nHB, nA, nD;
117
118 DumpReader reader(info_, dumpFilename_);
119 int nFrames = reader.getNFrames();
120 frameCounter_ = 0;
121
122 for (int istep = 0; istep < nFrames; istep += step_) {
123 reader.readFrame(istep);
124 frameCounter_++;
125 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
126
127 if (evaluator1_.isDynamic()) {
128 seleMan1_.setSelectionSet(evaluator1_.evaluate());
129 }
130 if (evaluator2_.isDynamic()) {
131 seleMan2_.setSelectionSet(evaluator2_.evaluate());
132 }
133
134 for (mol1 = seleMan1_.beginSelectedMolecule(ii); mol1 != NULL;
135 mol1 = seleMan1_.nextSelectedMolecule(ii)) {
136 // We're collecting statistics on the molecules in selection 1:
137 nHB = 0;
138 nA = 0;
139 nD = 0;
140
141 for (mol2 = seleMan2_.beginSelectedMolecule(jj); mol2 != NULL;
142 mol2 = seleMan2_.nextSelectedMolecule(jj)) {
143 // loop over the possible donors in molecule 1:
144 for (hbd1 = mol1->beginHBondDonor(hbdi); hbd1 != NULL;
145 hbd1 = mol1->nextHBondDonor(hbdi)) {
146 dPos = hbd1->donorAtom->getPos();
147 hPos = hbd1->donatedHydrogen->getPos();
148 DH = hPos - dPos;
149 currentSnapshot_->wrapVector(DH);
150 DHdist = DH.length();
151
152 // loop over the possible acceptors in molecule 2:
153 for (hba2 = mol2->beginHBondAcceptor(hbaj); hba2 != NULL;
154 hba2 = mol2->nextHBondAcceptor(hbaj)) {
155 aPos = hba2->getPos();
156 DA = aPos - dPos;
157 currentSnapshot_->wrapVector(DA);
158 DAdist = DA.length();
159
160 // Distance criteria: are the donor and acceptor atoms
161 // close enough?
162 if (DAdist < rCut_) {
163 ctheta = dot(DH, DA) / (DHdist * DAdist);
164 theta = acos(ctheta) * 180.0 / Constants::PI;
165
166 // Angle criteria: are the D-H and D-A and vectors close?
167 if (theta < thetaCut_) {
168 // molecule 1 is a Hbond donor:
169 nHB++;
170 nD++;
171 }
172 }
173 }
174 }
175
176 // now loop over the possible acceptors in molecule 1:
177 for (hba1 = mol1->beginHBondAcceptor(hbai); hba1 != NULL;
178 hba1 = mol1->nextHBondAcceptor(hbai)) {
179 aPos = hba1->getPos();
180
181 // loop over the possible donors in molecule 2:
182 for (hbd2 = mol2->beginHBondDonor(hbdj); hbd2 != NULL;
183 hbd2 = mol2->nextHBondDonor(hbdj)) {
184 dPos = hbd2->donorAtom->getPos();
185
186 DA = aPos - dPos;
187 currentSnapshot_->wrapVector(DA);
188 DAdist = DA.length();
189
190 // Distance criteria: are the donor and acceptor atoms
191 // close enough?
192 if (DAdist < rCut_) {
193 hPos = hbd2->donatedHydrogen->getPos();
194 DH = hPos - dPos;
195 currentSnapshot_->wrapVector(DH);
196 DHdist = DH.length();
197 ctheta = dot(DH, DA) / (DHdist * DAdist);
198 theta = acos(ctheta) * 180.0 / Constants::PI;
199 // Angle criteria: are the D-H and D-A and vectors close?
200 if (theta < thetaCut_) {
201 // molecule 1 is a Hbond acceptor:
202 nHB++;
203 nA++;
204 }
205 }
206 }
207 }
208 }
209 collectHistogram(nHB, nA, nD);
210 }
211 }
212 writeHistogram();
213 }
214
215 void HBondGeometric::collectHistogram(int nHB, int nA, int nD) {
216 nHBonds_[nHB] += 1;
217 nAcceptor_[nA] += 1;
218 nDonor_[nD] += 1;
219 nSelected_++;
220 }
221
222 void HBondGeometric::writeHistogram() {
223 std::ofstream osq(getOutputFileName().c_str());
224
225 if (osq.is_open()) {
226 osq << "# HydrogenBonding Statistics\n";
227 osq << "# selection1: (" << selectionScript1_ << ")"
228 << "\tselection2: (" << selectionScript2_ << ")\n";
229 osq << "# molecules in selection1: " << nSelected_ << "\n";
230 osq << "# "
231 "nHBonds\tnAcceptor\tnDonor\tp(nHBonds)\tp(nAcceptor)\tp(nDonor)"
232 "\n";
233 // Normalize by number of frames and write it out:
234 for (int i = 0; i < nBins_; ++i) {
235 osq << i;
236 osq << "\t" << nHBonds_[i];
237 osq << "\t" << nAcceptor_[i];
238 osq << "\t" << nDonor_[i];
239 osq << "\t" << (RealType)(nHBonds_[i]) / nSelected_;
240 osq << "\t" << (RealType)(nAcceptor_[i]) / nSelected_;
241 osq << "\t" << (RealType)(nDonor_[i]) / nSelected_;
242 osq << "\n";
243 }
244 osq.close();
245
246 } else {
247 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
248 "HBondGeometric: unable to open %s\n",
249 (getOutputFileName() + "q").c_str());
250 painCave.isFatal = 1;
251 simError();
252 }
253 }
254} // 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)