OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
UniformGradient.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
49
50#ifdef IS_MPI
51#include <mpi.h>
52#endif
53
54#include "brains/ForceModifier.hpp"
55#include "nonbonded/NonBondedInteraction.hpp"
57#include "types/FixedChargeAdapter.hpp"
58#include "types/FluctuatingChargeAdapter.hpp"
59#include "types/MultipoleAdapter.hpp"
60#include "utils/Constants.hpp"
61
62namespace OpenMD {
63 UniformGradient::UniformGradient(SimInfo* info) :
64 ForceModifier {info}, initialized {false}, doUniformGradient {false},
65 doParticlePot {false} {
66 simParams = info_->getSimParams();
67 }
68
69 void UniformGradient::initialize() {
70 bool haveA = false;
71 bool haveB = false;
72 bool haveG = false;
73
74 if (simParams->haveUniformGradientDirection1()) {
75 std::vector<RealType> d1 = simParams->getUniformGradientDirection1();
76 if (d1.size() != 3) {
77 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
78 "uniformGradientDirection1: Incorrect number of parameters\n"
79 "\tspecified. There should be 3 parameters, but %zu were\n"
80 "\tspecified.\n",
81 d1.size());
82 painCave.isFatal = 1;
83 simError();
84 }
85 a_.x() = d1[0];
86 a_.y() = d1[1];
87 a_.z() = d1[2];
88
89 a_.normalize();
90 haveA = true;
91 }
92
93 if (simParams->haveUniformGradientDirection2()) {
94 std::vector<RealType> d2 = simParams->getUniformGradientDirection2();
95 if (d2.size() != 3) {
96 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
97 "uniformGradientDirection2: Incorrect number of parameters\n"
98 "\tspecified. There should be 3 parameters, but %zu were\n"
99 "\tspecified.\n",
100 d2.size());
101 painCave.isFatal = 1;
102 simError();
103 }
104 b_.x() = d2[0];
105 b_.y() = d2[1];
106 b_.z() = d2[2];
107
108 b_.normalize();
109 haveB = true;
110 }
111
112 if (simParams->haveUniformGradientStrength()) {
113 g_ = simParams->getUniformGradientStrength();
114 haveG = true;
115 }
116
117 if (haveA && haveB && haveG) {
118 doUniformGradient = true;
119 cpsi_ = dot(a_, b_);
120
121 Grad_(0, 0) = 2.0 * (a_.x() * b_.x() - cpsi_ / 3.0);
122 Grad_(0, 1) = a_.x() * b_.y() + a_.y() * b_.x();
123 Grad_(0, 2) = a_.x() * b_.z() + a_.z() * b_.x();
124 Grad_(1, 0) = Grad_(0, 1);
125 Grad_(1, 1) = 2.0 * (a_.y() * b_.y() - cpsi_ / 3.0);
126 Grad_(1, 2) = a_.y() * b_.z() + a_.z() * b_.y();
127 Grad_(2, 0) = Grad_(0, 2);
128 Grad_(2, 1) = Grad_(1, 2);
129 Grad_(2, 2) = 2.0 * (a_.z() * b_.z() - cpsi_ / 3.0);
130
131 Grad_ *= g_ / 2.0;
132
133 } else {
134 if (!haveA) {
135 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
136 "UniformGradient: uniformGradientDirection1 not specified.\n");
137 painCave.isFatal = 1;
138 simError();
139 }
140 if (!haveB) {
141 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
142 "UniformGradient: uniformGradientDirection2 not specified.\n");
143 painCave.isFatal = 1;
144 simError();
145 }
146 if (!haveG) {
147 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
148 "UniformGradient: uniformGradientStrength not specified.\n");
149 painCave.isFatal = 1;
150 simError();
151 }
152 }
153
154 int storageLayout_ = info_->getSnapshotManager()->getAtomStorageLayout();
155 if (storageLayout_ & DataStorage::dslParticlePot) doParticlePot = true;
156 initialized = true;
157 }
158
159 void UniformGradient::modifyForces() {
160 if (!initialized) initialize();
161
162 SimInfo::MoleculeIterator i;
163 Molecule::AtomIterator j;
164 Molecule* mol;
165 Atom* atom;
166 AtomType* atype;
167 potVec longRangePotential(0.0);
168
169 RealType C;
170 Vector3d D;
171 Mat3x3d Q;
172
173 RealType U;
174 RealType fPot;
175 Vector3d t;
176 Vector3d f;
177
178 Vector3d r;
179 Vector3d EF;
180
181 bool isCharge;
182
183 if (doUniformGradient) {
184 U = 0.0;
185 fPot = 0.0;
186
187 for (mol = info_->beginMolecule(i); mol != NULL;
188 mol = info_->nextMolecule(i)) {
189 for (atom = mol->beginAtom(j); atom != NULL; atom = mol->nextAtom(j)) {
190 isCharge = false;
191 C = 0.0;
192
193 atype = atom->getAtomType();
194
195 r = atom->getPos();
196 info_->getSnapshotManager()->getCurrentSnapshot()->wrapVector(r);
197
198 EF = Grad_ * r;
199
200 atom->addElectricField(EF * Constants::chargeFieldConvert);
201
202 FixedChargeAdapter fca = FixedChargeAdapter(atype);
203 if (fca.isFixedCharge()) {
204 isCharge = true;
205 C = fca.getCharge();
206 }
207
208 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter(atype);
209 if (fqa.isFluctuatingCharge()) {
210 isCharge = true;
211 C += atom->getFlucQPos();
212 atom->addFlucQFrc(dot(r, EF) * Constants::chargeFieldConvert);
213 }
214
215 if (isCharge) {
216 f = EF * C * Constants::chargeFieldConvert;
217 atom->addFrc(f);
218
219 U = -dot(r, f);
220 if (doParticlePot) { atom->addParticlePot(U); }
221 fPot += U;
222 }
223
224 MultipoleAdapter ma = MultipoleAdapter(atype);
225 if (ma.isDipole()) {
226 D = atom->getDipole() * Constants::dipoleFieldConvert;
227
228 f = D * Grad_;
229 atom->addFrc(f);
230
231 t = cross(D, EF);
232 atom->addTrq(t);
233
234 U = -dot(D, EF);
235 if (doParticlePot) { atom->addParticlePot(U); }
236 fPot += U;
237 }
238
239 if (ma.isQuadrupole()) {
240 Q = atom->getQuadrupole() * Constants::dipoleFieldConvert;
241
242 t = 2.0 * mCross(Q, Grad_);
243 atom->addTrq(t);
244
245 U = -doubleDot(Q, Grad_);
246 if (doParticlePot) { atom->addParticlePot(U); }
247 fPot += U;
248 }
249 }
250 }
251
252#ifdef IS_MPI
253 MPI_Allreduce(MPI_IN_PLACE, &fPot, 1, MPI_REALTYPE, MPI_SUM,
254 MPI_COMM_WORLD);
255#endif
256
257 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
258 longRangePotential = snap->getLongRangePotentials();
259 longRangePotential[ELECTROSTATIC_FAMILY] += fPot;
260 snap->setLongRangePotentials(longRangePotential);
261 }
262 }
263} // namespace OpenMD
Uniform Electric Field Gradient perturbation.
Abstract class for external ForceModifier classes.
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 doubleDot(const RectMatrix< Real, Row, Col > &t1, const RectMatrix< Real, Row, Col > &t2)
Returns the tensor contraction (double dot product) of two rank 2 tensors (or Matrices).
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Definition Vector3.hpp:139
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
Vector< Real, Row > mCross(const RectMatrix< Real, Row, Col > &t1, const RectMatrix< Real, Row, Col > &t2)
Returns the vector (cross) product of two matrices.
@ ELECTROSTATIC_FAMILY
Coulombic and point-multipole interactions.