OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
DirectionalAtom.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#include "types/DirectionalAdapter.hpp"
51#include "types/MultipoleAdapter.hpp"
52#include "utils/simError.h"
53
54namespace OpenMD {
55
56 DirectionalAtom::DirectionalAtom(AtomType* dAtomType) : Atom(dAtomType) {
57 objType_ = otDAtom;
58
59 DirectionalAdapter da = DirectionalAdapter(dAtomType);
60 I_ = da.getI();
61
62 MultipoleAdapter ma = MultipoleAdapter(dAtomType);
63 if (ma.isDipole()) { dipole_ = ma.getDipole(); }
64 if (ma.isQuadrupole()) { quadrupole_ = ma.getQuadrupole(); }
65
66 // Check if one of the diagonal inertia tensor of this directional
67 // atom is zero:
68 int nLinearAxis = 0;
69 Mat3x3d inertiaTensor = getI();
70 for (int i = 0; i < 3; i++) {
71 if (fabs(inertiaTensor(i, i)) < OpenMD::epsilon) {
72 linear_ = true;
73 linearAxis_ = i;
74 ++nLinearAxis;
75 }
76 }
77
78 if (nLinearAxis > 1) {
79 snprintf(
80 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
81 "Directional Atom warning.\n"
82 "\tOpenMD found more than one axis in this directional atom with a "
83 "vanishing \n"
84 "\tmoment of inertia.");
85 painCave.isFatal = 0;
86 simError();
87 }
88 }
89
90 Mat3x3d DirectionalAtom::getI() { return I_; }
91
92 void DirectionalAtom::setPrevA(const RotMat3x3d& a) {
93 ((snapshotMan_->getPrevSnapshot())->*storage_).aMat[localIndex_] = a;
94
95 if (atomType_->isMultipole()) {
96 RotMat3x3d atrans = a.transpose();
97
98 if (atomType_->isDipole()) {
99 ((snapshotMan_->getPrevSnapshot())->*storage_).dipole[localIndex_] =
100 atrans * dipole_;
101 }
102
103 if (atomType_->isQuadrupole()) {
104 ((snapshotMan_->getPrevSnapshot())->*storage_).quadrupole[localIndex_] =
105 atrans * quadrupole_ * a;
106 }
107 }
108 }
109
110 void DirectionalAtom::setA(const RotMat3x3d& a) {
111 ((snapshotMan_->getCurrentSnapshot())->*storage_).aMat[localIndex_] = a;
112
113 if (atomType_->isMultipole()) {
114 RotMat3x3d atrans = a.transpose();
115
116 if (atomType_->isDipole()) {
117 ((snapshotMan_->getCurrentSnapshot())->*storage_).dipole[localIndex_] =
118 atrans * dipole_;
119 }
120
121 if (atomType_->isQuadrupole()) {
122 ((snapshotMan_->getCurrentSnapshot())->*storage_)
123 .quadrupole[localIndex_] = atrans * quadrupole_ * a;
124 }
125 }
126 }
127
128 void DirectionalAtom::setA(const RotMat3x3d& a, int snapshotNo) {
129 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_).aMat[localIndex_] = a;
130
131 if (atomType_->isMultipole()) {
132 RotMat3x3d atrans = a.transpose();
133
134 if (atomType_->isDipole()) {
135 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_)
136 .dipole[localIndex_] = atrans * dipole_;
137 }
138
139 if (atomType_->isQuadrupole()) {
140 ((snapshotMan_->getSnapshot(snapshotNo))->*storage_)
141 .quadrupole[localIndex_] = atrans * quadrupole_ * a;
142 }
143 }
144 }
145
146 void DirectionalAtom::rotateBy(const RotMat3x3d& m) { setA(m * getA()); }
147
148 std::vector<RealType> DirectionalAtom::getGrad() {
149 std::vector<RealType> grad(6, 0.0);
150 Vector3d force;
151 Vector3d torque;
152 Vector3d myEuler;
153 RealType phi, theta;
154 RealType cphi, sphi, ctheta, stheta;
155 Vector3d ephi;
156 Vector3d etheta;
157 Vector3d epsi;
158
159 force = getFrc();
160 torque = getTrq();
161
162 myEuler = getA().toEulerAngles();
163
164 phi = myEuler[0];
165 theta = myEuler[1];
166
167 cphi = cos(phi);
168 sphi = sin(phi);
169 ctheta = cos(theta);
170 stheta = sin(theta);
171
172 if (fabs(stheta) < 1.0E-9) { stheta = 1.0E-9; }
173
174 ephi[0] = -sphi * ctheta / stheta;
175 ephi[1] = cphi * ctheta / stheta;
176 ephi[2] = 1.0;
177
178 etheta[0] = cphi;
179 etheta[1] = sphi;
180 etheta[2] = 0.0;
181
182 epsi[0] = sphi / stheta;
183 epsi[1] = -cphi / stheta;
184 epsi[2] = 0.0;
185
186 // gradient is equal to -force
187 for (int j = 0; j < 3; j++)
188 grad[j] = -force[j];
189
190 for (int j = 0; j < 3; j++) {
191 grad[3] -= torque[j] * ephi[j];
192 grad[4] -= torque[j] * etheta[j];
193 grad[5] -= torque[j] * epsi[j];
194 }
195
196 return grad;
197 }
198
199 void DirectionalAtom::accept(BaseVisitor* v) { v->visit(this); }
200} // namespace OpenMD
AtomType is what OpenMD looks to for unchanging data about an atom.
Definition AtomType.hpp:69
virtual void setA(const RotMat3x3d &a)
Sets the current rotation matrix of this stuntdouble.
virtual void accept(BaseVisitor *v)
virtual Mat3x3d getI()
Returns the inertia tensor of this stuntdouble.
virtual std::vector< RealType > getGrad()
Returns the gradient of this stuntdouble.
void rotateBy(const RotMat3x3d &m)
Left multiple rotation matrix by another rotation matrix.
virtual void setPrevA(const RotMat3x3d &a)
Sets the previous rotation matrix of this stuntdouble.
Vector3d getTrq()
Returns the current torque of this stuntDouble.
RotMat3x3d getA()
Returns the current rotation matrix of this stuntDouble.
Vector3d getFrc()
Returns the current force of this stuntDouble.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.