OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
NitrileFrequencyMap.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/NitrileFrequencyMap.hpp"
49
50#include <algorithm>
51#include <fstream>
52
53#include "brains/Thermo.hpp"
54#include "io/DumpReader.hpp"
56#include "utils/simError.h"
57
58namespace OpenMD {
59
60 NitrileFrequencyMap::NitrileFrequencyMap(SimInfo* info,
61 const std::string& filename,
62 const std::string& sele1,
63 int nbins) :
64 StaticAnalyser(info, filename, nbins),
65 info_(info), selectionScript1_(sele1), seleMan1_(info_),
66 evaluator1_(info_) {
67 setOutputName(getPrefix(filename) + ".freqs");
68
69 evaluator1_.loadScriptString(sele1);
70 if (!evaluator1_.isDynamic()) {
71 seleMan1_.setSelectionSet(evaluator1_.evaluate());
72 }
73
74 count_.resize(nBins_);
75 histogram_.resize(nBins_);
76
77 freqs_.resize(info_->getNGlobalMolecules());
78
79 minFreq_ = -50;
80 maxFreq_ = 50;
81
82 // Values from Choi et. al. "Nitrile and thiocyanate IR probes:
83 // Quantum chemistry calculation studies and multivariate
84 // least-square fitting analysis," J. Chem. Phys. 128, 134506 (2008).
85 //
86 // These map site electrostatic potentials onto frequency shifts
87 // in the same energy units that one computes the total potential.
88
89 frequencyMap_["CN"] = 0.0801;
90 frequencyMap_["NC"] = 0.00521;
91 frequencyMap_["RCHar3"] = -0.00182;
92 frequencyMap_["SigmaN"] = 0.00157;
93 frequencyMap_["PiN"] = -0.00167;
94 frequencyMap_["PiC"] = -0.00896;
95
96 ForceField* forceField_ = info_->getForceField();
97 AtomTypeSet atypes = info_->getSimulatedAtomTypes();
98 PairList* excludes = info_->getExcludedInteractions();
99 int nAtoms =
100 info->getSnapshotManager()->getCurrentSnapshot()->getNumberOfAtoms();
101
102 RealType rcut;
103 if (info_->getSimParams()->haveCutoffRadius()) {
104 rcut = info_->getSimParams()->getCutoffRadius();
105 } else {
106 rcut = 12.0;
107 }
108
109 EF_ = V3Zero;
110
111 std::vector<RealType> ef;
112 bool efSpec = false;
113
114 if (info_->getSimParams()->haveElectricField()) {
115 efSpec = true;
116 ef = info_->getSimParams()->getElectricField();
117 }
118 if (info_->getSimParams()->haveUniformField()) {
119 efSpec = true;
120 ef = info_->getSimParams()->getUniformField();
121 }
122 if (efSpec) {
123 if (ef.size() != 3) {
124 snprintf(
125 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
126 "NitrileFrequencyMap: Incorrect number of parameters specified for "
127 "uniformField.\n"
128 "\tthere should be 3 parameters, but %zu were specified.\n",
129 ef.size());
130 painCave.isFatal = 1;
131 simError();
132 }
133 EF_.x() = ef[0];
134 EF_.y() = ef[1];
135 EF_.z() = ef[2];
136 }
137
138 excludesForAtom.clear();
139 excludesForAtom.resize(nAtoms);
140
141 for (int i = 0; i < nAtoms; i++) {
142 for (int j = 0; j < nAtoms; j++) {
143 if (excludes->hasPair(i, j)) excludesForAtom[i].push_back(j);
144 }
145 }
146
147 electrostatic_ = new Electrostatic();
148 electrostatic_->setSimInfo(info_);
149 electrostatic_->setForceField(forceField_);
150 electrostatic_->setSimulatedAtomTypes(atypes);
151 electrostatic_->setCutoffRadius(rcut);
152 }
153
154 bool NitrileFrequencyMap::excludeAtomPair(int atom1, int atom2) {
155 for (vector<int>::iterator i = excludesForAtom[atom1].begin();
156 i != excludesForAtom[atom1].end(); ++i) {
157 if ((*i) == atom2) return true;
158 }
159
160 return false;
161 }
162
163 void NitrileFrequencyMap::process() {
164 Molecule* mol;
165 Atom* atom;
166 AtomType* atype;
167 SimInfo::MoleculeIterator mi;
168 Molecule::AtomIterator ai2;
169 Atom* atom2;
170 StuntDouble* sd1;
171 int ii, sdID, molID, sdID2;
172 RealType li(0.0);
173 RealType sPot, s1, s2;
174 RealType freqShift;
175 std::string name;
176 map<string, RealType>::iterator fi;
177 bool excluded;
178 const RealType chrgToKcal = 23.0609;
179
180 DumpReader reader(info_, dumpFilename_);
181 int nFrames = reader.getNFrames();
182
183 nProcessed_ = nFrames / step_;
184
185 std::fill(histogram_.begin(), histogram_.end(), 0.0);
186 std::fill(count_.begin(), count_.end(), 0);
187
188 for (int istep = 0; istep < nFrames; istep += step_) {
189 reader.readFrame(istep);
190 currentSnapshot_ = info_->getSnapshotManager()->getCurrentSnapshot();
191
192 std::fill(freqs_.begin(), freqs_.end(), 0.0);
193
194 if (evaluator1_.isDynamic()) {
195 seleMan1_.setSelectionSet(evaluator1_.evaluate());
196 }
197
198 for (sd1 = seleMan1_.beginSelected(ii); sd1 != NULL;
199 sd1 = seleMan1_.nextSelected(ii)) {
200 sdID = sd1->getGlobalIndex();
201 molID = info_->getGlobalMolMembership(sdID);
202 mol = info_->getMoleculeByGlobalIndex(molID);
203
204 Vector3d CNcentroid = mol->getRigidBodyAt(2)->getPos();
205 Vector3d ra = sd1->getPos();
206
207 atom = dynamic_cast<Atom*>(sd1);
208 atype = atom->getAtomType();
209 name = atype->getName();
210 fi = frequencyMap_.find(name);
211 if (fi != frequencyMap_.end()) {
212 li = (*fi).second;
213 } else {
214 // throw error
215 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
216 "NitrileFrequencyMap::process: Unknown atype requested.\n"
217 "\t(Selection specified %s .)\n",
218 name.c_str());
219 painCave.isFatal = 1;
220 simError();
221 }
222
223 sPot = sd1->getSitePotential();
224
225 // Subtract out the contribution from every other site on this
226 // molecule:
227 for (atom2 = mol->beginAtom(ai2); atom2 != NULL;
228 atom2 = mol->nextAtom(ai2)) {
229 sdID2 = atom2->getGlobalIndex();
230 if (sdID == sdID2) {
231 excluded = true;
232 } else {
233 excluded = excludeAtomPair(sdID, sdID2);
234 }
235
236 electrostatic_->getSitePotentials(atom, atom2, excluded, s1, s2);
237
238 sPot -= s1;
239 }
240
241 // Add the contribution from the electric field:
242
243 sPot += dot(EF_, ra - CNcentroid) * chrgToKcal;
244
245 freqShift = sPot * li;
246
247 // convert the kcal/mol energies to wavenumbers:
248 freqShift *= 349.757;
249
250 freqs_[molID] += freqShift;
251 }
252
253 for (int i = 0; i < info_->getNGlobalMolecules(); ++i) {
254 int binNo =
255 int(nBins_ * (freqs_[i] - minFreq_) / (maxFreq_ - minFreq_));
256
257 count_[binNo]++;
258 }
259 }
260
261 processHistogram();
262 writeProbs();
263 }
264
265 void NitrileFrequencyMap::processHistogram() {
266 int atot = 0;
267 for (unsigned int i = 0; i < count_.size(); ++i)
268 atot += count_[i];
269
270 for (unsigned int i = 0; i < count_.size(); ++i) {
271 histogram_[i] = double(count_[i] / double(atot));
272 }
273 }
274
275 void NitrileFrequencyMap::writeProbs() {
276 std::ofstream rdfStream(outputFilename_.c_str());
277 if (rdfStream.is_open()) {
278 rdfStream << "#NitrileFrequencyMap\n";
279 rdfStream << "#nFrames:\t" << nProcessed_ << "\n";
280 rdfStream << "#selection1: (" << selectionScript1_ << ")";
281 rdfStream << "\n";
282 rdfStream << "#nu\tp(nu))\n";
283 for (unsigned int i = 0; i < histogram_.size(); ++i) {
284 RealType freq = minFreq_ + (RealType)(i) * (maxFreq_ - minFreq_) /
285 (RealType)histogram_.size();
286 rdfStream << freq << "\t" << histogram_[i] << "\n";
287 }
288
289 } else {
290 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
291 "NitrileFrequencyMap: unable to open %s\n",
292 outputFilename_.c_str());
293 painCave.isFatal = 1;
294 simError();
295 }
296
297 rdfStream.close();
298 }
299
300} // 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)