OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
PotentialEnergyObjectiveFunction.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 "optimization/PotentialEnergyObjectiveFunction.hpp"
49
50#ifdef IS_MPI
51#include <mpi.h>
52#endif
53
54namespace OpenMD {
55
56 PotentialEnergyObjectiveFunction::PotentialEnergyObjectiveFunction(
57 SimInfo* info, ForceManager* forceMan) :
58 info_(info),
59 forceMan_(forceMan), thermo(info), hasFlucQ_(false) {
60 shake_ = new Shake(info_);
61
62 if (info_->usesFluctuatingCharges()) {
63 if (info_->getNFluctuatingCharges() > 0) {
64 hasFlucQ_ = true;
65 fqConstraints_ = new FluctuatingChargeConstraints(info_);
66 bool cr = info_->getSimParams()
67 ->getFluctuatingChargeParameters()
68 ->getConstrainRegions();
69 fqConstraints_->setConstrainRegions(cr);
70 }
71 }
72 }
73
74 PotentialEnergyObjectiveFunction::~PotentialEnergyObjectiveFunction() {
75 delete shake_;
76 }
77
79 const DynamicVector<RealType>& x) {
80 setCoor(x);
81 shake_->constraintR();
82 forceMan_->calcForces();
83 if (hasFlucQ_) fqConstraints_->applyConstraints();
84 shake_->constraintF();
85 return thermo.getPotential();
86 }
87
90 setCoor(x);
91 shake_->constraintR();
92 forceMan_->calcForces();
93 if (hasFlucQ_) fqConstraints_->applyConstraints();
94 shake_->constraintF();
95 getGrad(grad);
96 }
97
100 setCoor(x);
101 shake_->constraintR();
102 forceMan_->calcForces();
103 if (hasFlucQ_) fqConstraints_->applyConstraints();
104 shake_->constraintF();
105 getGrad(grad);
106 return thermo.getPotential();
107 }
108
109 void PotentialEnergyObjectiveFunction::setCoor(
110 const DynamicVector<RealType>& x) const {
111 Vector3d position;
112 Vector3d eulerAngle;
113 SimInfo::MoleculeIterator i;
114 Molecule::IntegrableObjectIterator j;
115 Molecule::AtomIterator ai;
116 Molecule* mol;
117 StuntDouble* sd;
118 Atom* atom;
119
120 info_->getSnapshotManager()->advance();
121
122 int index;
123#ifdef IS_MPI
124 index = displacements_[myrank_];
125#else
126 index = 0;
127#endif
128
129 info_->getSnapshotManager()->advance();
130
131 for (mol = info_->beginMolecule(i); mol != NULL;
132 mol = info_->nextMolecule(i)) {
133 for (sd = mol->beginIntegrableObject(j); sd != NULL;
134 sd = mol->nextIntegrableObject(j)) {
135 position[0] = x[index++];
136 position[1] = x[index++];
137 position[2] = x[index++];
138
139 sd->setPos(position);
140
141 if (sd->isDirectional()) {
142 eulerAngle[0] = x[index++];
143 eulerAngle[1] = x[index++];
144 eulerAngle[2] = x[index++];
145
146 sd->setEuler(eulerAngle);
147
148 if (sd->isRigidBody()) {
149 RigidBody* rb = static_cast<RigidBody*>(sd);
150 rb->updateAtoms();
151 }
152 }
153 }
154 }
155
156 if (hasFlucQ_) {
157 for (mol = info_->beginMolecule(i); mol != NULL;
158 mol = info_->nextMolecule(i)) {
159 for (atom = mol->beginFluctuatingCharge(ai); atom != NULL;
160 atom = mol->nextFluctuatingCharge(ai)) {
161 atom->setFlucQPos(x[index++]);
162 }
163 }
164 }
165 }
166
167 void PotentialEnergyObjectiveFunction::getGrad(
169 SimInfo::MoleculeIterator i;
170 Molecule::IntegrableObjectIterator j;
171 Molecule::AtomIterator ai;
172 Molecule* mol;
173 StuntDouble* sd;
174 Atom* atom;
175 std::vector<RealType> myGrad;
176
177 int index;
178#ifdef IS_MPI
179 index = displacements_[myrank_];
180 grad.setZero();
181#else
182 index = 0;
183#endif
184
185 for (mol = info_->beginMolecule(i); mol != NULL;
186 mol = info_->nextMolecule(i)) {
187 for (sd = mol->beginIntegrableObject(j); sd != NULL;
188 sd = mol->nextIntegrableObject(j)) {
189 myGrad = sd->getGrad();
190
191 for (size_t k = 0; k < myGrad.size(); ++k) {
192 grad[index++] = myGrad[k];
193 }
194 }
195 }
196
197 if (hasFlucQ_) {
198 for (mol = info_->beginMolecule(i); mol != NULL;
199 mol = info_->nextMolecule(i)) {
200 for (atom = mol->beginFluctuatingCharge(ai); atom != NULL;
201 atom = mol->nextFluctuatingCharge(ai)) {
202 grad[index++] = -atom->getFlucQFrc();
203 }
204 }
205 }
206#ifdef IS_MPI
207 MPI_Allreduce(MPI_IN_PLACE, &grad[0], ndf_, MPI_REALTYPE, MPI_SUM,
208 MPI_COMM_WORLD);
209#endif
210 }
211
212 DynamicVector<RealType> PotentialEnergyObjectiveFunction::setInitialCoords() {
213#ifdef IS_MPI
214 MPI_Comm_size(MPI_COMM_WORLD, &nproc_);
215 MPI_Comm_rank(MPI_COMM_WORLD, &myrank_);
216 std::vector<int> onProc(nproc_, 0);
217
218 displacements_.clear();
219 displacements_.resize(nproc_, 0);
220#endif
221
222 SimInfo::MoleculeIterator i;
223 Molecule::IntegrableObjectIterator j;
224 Molecule::AtomIterator ai;
225 Molecule* mol;
226 StuntDouble* sd;
227 Atom* atom;
228
229 Vector3d pos;
230 Vector3d eulerAngle;
231
232 ndf_ = 0;
233
234 for (mol = info_->beginMolecule(i); mol != NULL;
235 mol = info_->nextMolecule(i)) {
236 for (sd = mol->beginIntegrableObject(j); sd != NULL;
237 sd = mol->nextIntegrableObject(j)) {
238 ndf_ += 3;
239
240 if (sd->isDirectional()) { ndf_ += 3; }
241 }
242 }
243
244 if (hasFlucQ_) {
245 for (mol = info_->beginMolecule(i); mol != NULL;
246 mol = info_->nextMolecule(i)) {
247 for (atom = mol->beginFluctuatingCharge(ai); atom != NULL;
248 atom = mol->nextFluctuatingCharge(ai)) {
249 ndf_++;
250 }
251 }
252 }
253
254#ifdef IS_MPI
255 MPI_Allgather(&ndf_, 1, MPI_INT, &onProc[0], 1, MPI_INT, MPI_COMM_WORLD);
256
257 ndf_ = 0;
258 for (int iproc = 0; iproc < nproc_; iproc++) {
259 ndf_ += onProc[iproc];
260 }
261
262 displacements_[0] = 0;
263 for (int iproc = 1; iproc < nproc_; iproc++) {
264 displacements_[iproc] = displacements_[iproc - 1] + onProc[iproc - 1];
265 }
266#endif
267
268 DynamicVector<RealType> xinit(ndf_, 0.0);
269
270 int index;
271#ifdef IS_MPI
272 index = displacements_[myrank_];
273#else
274 index = 0;
275#endif
276
277 for (mol = info_->beginMolecule(i); mol != NULL;
278 mol = info_->nextMolecule(i)) {
279 for (sd = mol->beginIntegrableObject(j); sd != NULL;
280 sd = mol->nextIntegrableObject(j)) {
281 pos = sd->getPos();
282 xinit[index++] = pos[0];
283 xinit[index++] = pos[1];
284 xinit[index++] = pos[2];
285
286 if (sd->isDirectional()) {
287 eulerAngle = sd->getEuler();
288 xinit[index++] = eulerAngle[0];
289 xinit[index++] = eulerAngle[1];
290 xinit[index++] = eulerAngle[2];
291 }
292 }
293 }
294
295 if (hasFlucQ_) {
296 for (mol = info_->beginMolecule(i); mol != NULL;
297 mol = info_->nextMolecule(i)) {
298 for (atom = mol->beginFluctuatingCharge(ai); atom != NULL;
299 atom = mol->nextFluctuatingCharge(ai)) {
300 xinit[index++] = atom->getFlucQPos();
301 }
302 }
303 }
304
305 return xinit;
306 }
307} // namespace OpenMD
Dynamically-sized vector class.
void setZero()
zero out the vector
ForceManager is responsible for calculating both the short range (bonded) interactions and long range...
RealType value(const DynamicVector< RealType > &x)
method to overload to compute the objective function value in x
void gradient(DynamicVector< RealType > &grad, const DynamicVector< RealType > &x)
method to overload to compute grad_f, the first derivative of
RealType valueAndGradient(DynamicVector< RealType > &grad, const DynamicVector< RealType > &x)
method to overload to compute grad_f, the first derivative
void updateAtoms()
update the positions of atoms belong to this rigidbody
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:243
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:248
SnapshotManager * getSnapshotManager()
Returns the snapshot manager.
Definition SimInfo.hpp:251
"Don't move, or you're dead! Stand up! Captain, we've got them!"
Vector3d getEuler()
Returns the current euler angles of this stuntDouble.
void setFlucQPos(RealType charge)
Sets the current fluctuating charge of this stuntDouble.
Vector3d getPos()
Returns the current position of this stuntDouble.
RealType getFlucQFrc()
Returns the current charge force of this stuntDouble.
RealType getFlucQPos()
Returns the current fluctuating charge of this stuntDouble.
void setPos(const Vector3d &pos)
Sets the current position of this stuntDouble.
void setEuler(const Vector3d &euler)
Sets the current euler angles of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
bool isDirectional()
Tests if this stuntDouble is a directional one.
virtual std::vector< RealType > getGrad()=0
Returns the gradient of this stuntDouble.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.