OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
DistanceFinder.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 "selection/DistanceFinder.hpp"
49
50#ifdef IS_MPI
51#include <mpi.h>
52#endif
53
55
56namespace OpenMD {
57
58 DistanceFinder::DistanceFinder(SimInfo* info) : info_(info) {
59 nObjects_.push_back(info_->getNGlobalAtoms() +
60 info_->getNGlobalRigidBodies());
61 nObjects_.push_back(info_->getNGlobalBonds());
62 nObjects_.push_back(info_->getNGlobalBends());
63 nObjects_.push_back(info_->getNGlobalTorsions());
64 nObjects_.push_back(info_->getNGlobalInversions());
65 nObjects_.push_back(info_->getNGlobalMolecules());
66
67 stuntdoubles_.resize(nObjects_[STUNTDOUBLE]);
68 bonds_.resize(nObjects_[BOND]);
69 bends_.resize(nObjects_[BEND]);
70 torsions_.resize(nObjects_[TORSION]);
71 inversions_.resize(nObjects_[INVERSION]);
72 molecules_.resize(nObjects_[MOLECULE]);
73
74 SimInfo::MoleculeIterator mi;
75 Molecule::AtomIterator ai;
76 Molecule::RigidBodyIterator rbIter;
77 Molecule::BondIterator bondIter;
78 Molecule::BendIterator bendIter;
79 Molecule::TorsionIterator torsionIter;
80 Molecule::InversionIterator inversionIter;
81
82 Molecule* mol;
83 Atom* atom;
84 RigidBody* rb;
85 Bond* bond;
86 Bend* bend;
87 Torsion* torsion;
88 Inversion* inversion;
89
90 for (mol = info_->beginMolecule(mi); mol != NULL;
91 mol = info_->nextMolecule(mi)) {
92 molecules_[mol->getGlobalIndex()] = mol;
93
94 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
95 stuntdoubles_[atom->getGlobalIndex()] = atom;
96 }
97 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
98 rb = mol->nextRigidBody(rbIter)) {
99 stuntdoubles_[rb->getGlobalIndex()] = rb;
100 }
101 for (bond = mol->beginBond(bondIter); bond != NULL;
102 bond = mol->nextBond(bondIter)) {
103 bonds_[bond->getGlobalIndex()] = bond;
104 }
105 for (bend = mol->beginBend(bendIter); bend != NULL;
106 bend = mol->nextBend(bendIter)) {
107 bends_[bend->getGlobalIndex()] = bend;
108 }
109 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
110 torsion = mol->nextTorsion(torsionIter)) {
111 torsions_[torsion->getGlobalIndex()] = torsion;
112 }
113 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
114 inversion = mol->nextInversion(inversionIter)) {
115 inversions_[inversion->getGlobalIndex()] = inversion;
116 }
117 }
118 }
119
120 SelectionSet DistanceFinder::find(const SelectionSet& bs,
121 RealType distance) {
122 return findImpl(bs, distance, -1);
123 }
124
125 SelectionSet DistanceFinder::find(const SelectionSet& bs, RealType distance,
126 int frame) {
127 return findImpl(bs, distance, frame);
128 }
129
130 SelectionSet DistanceFinder::findImpl(const SelectionSet& bs,
131 RealType distance, int frame) {
132 const bool useCurrent = (frame < 0);
133 Snapshot* currSnapshot = useCurrent
134 ? info_->getSnapshotManager()->getCurrentSnapshot()
135 : info_->getSnapshotManager()->getSnapshot(frame);
136
137 // Position-retrieval helpers that dispatch on frame
138 auto getPos = [useCurrent, frame](StuntDouble* sd) -> Vector3d {
139 return useCurrent ? sd->getPos() : sd->getPos(frame);
140 };
141 auto getCom = [useCurrent, frame](Molecule* mol) -> Vector3d {
142 return useCurrent ? mol->getCom() : mol->getCom(frame);
143 };
144
145 SelectionSet bsResult(nObjects_);
146 assert(bsResult.size() == bs.size());
147
148#ifdef IS_MPI
149 int mol;
150 int proc;
151 RealType data[3];
152 int worldRank;
153 MPI_Comm_rank(MPI_COMM_WORLD, &worldRank);
154#endif
155
156 for (unsigned int j = 0; j < stuntdoubles_.size(); ++j) {
157 if (stuntdoubles_[j] != NULL) {
158 if (stuntdoubles_[j]->isRigidBody()) {
159 RigidBody* rb = static_cast<RigidBody*>(stuntdoubles_[j]);
160 useCurrent ? rb->updateAtoms() : rb->updateAtoms(frame);
161 }
162 }
163 }
164
165 // Helper: check if pos is within distance of centerPos (min-image)
166 // and set the bit if so.
167 auto checkDistance = [&](const Vector3d& centerPos, const Vector3d& pos,
168 OpenMDBitSet& bits, size_t idx) {
169 Vector3d r = centerPos - pos;
170 currSnapshot->wrapVector(r);
171 if (r.length() <= distance) { bits.setBitOn(idx); }
172 };
173
174 SelectionSet bsTemp = bs;
175 bsTemp = bsTemp.parallelReduce();
176
177 for (size_t i = 0; i < bsTemp.bitsets_[STUNTDOUBLE].size(); ++i) {
178 if (!bsTemp.bitsets_[STUNTDOUBLE][i]) continue;
179
180 Vector3d centerPos;
181
182#ifdef IS_MPI
183 mol = info_->getGlobalMolMembership(i);
184 proc = info_->getMolToProc(mol);
185
186 if (proc == worldRank) {
187 centerPos = getPos(stuntdoubles_[i]);
188 data[0] = centerPos.x();
189 data[1] = centerPos.y();
190 data[2] = centerPos.z();
191 MPI_Bcast(data, 3, MPI_REALTYPE, proc, MPI_COMM_WORLD);
192 } else {
193 MPI_Bcast(data, 3, MPI_REALTYPE, proc, MPI_COMM_WORLD);
194 centerPos = Vector3d(data);
195 }
196#else
197 centerPos = getPos(stuntdoubles_[i]);
198#endif
199
200 // Molecules
201 for (size_t j = 0; j < molecules_.size(); ++j) {
202 if (molecules_[j] != NULL)
203 checkDistance(centerPos, getCom(molecules_[j]),
204 bsResult.bitsets_[MOLECULE], j);
205 }
206
207 // StuntDoubles (atoms and rigid bodies)
208 for (size_t j = 0; j < stuntdoubles_.size(); ++j) {
209 if (stuntdoubles_[j] != NULL)
210 checkDistance(centerPos, getPos(stuntdoubles_[j]),
211 bsResult.bitsets_[STUNTDOUBLE], j);
212 }
213
214 // Bonds (midpoint of two atoms)
215 for (size_t j = 0; j < bonds_.size(); ++j) {
216 if (bonds_[j] != NULL) {
217 Vector3d loc = getPos(bonds_[j]->getAtomA())
218 + getPos(bonds_[j]->getAtomB());
219 checkDistance(centerPos, loc / 2.0,
220 bsResult.bitsets_[BOND], j);
221 }
222 }
223
224 // Bends (centroid of three atoms)
225 for (size_t j = 0; j < bends_.size(); ++j) {
226 if (bends_[j] != NULL) {
227 Vector3d loc = getPos(bends_[j]->getAtomA())
228 + getPos(bends_[j]->getAtomB())
229 + getPos(bends_[j]->getAtomC());
230 checkDistance(centerPos, loc / 3.0,
231 bsResult.bitsets_[BEND], j);
232 }
233 }
234
235 // Torsions (centroid of four atoms)
236 for (size_t j = 0; j < torsions_.size(); ++j) {
237 if (torsions_[j] != NULL) {
238 Vector3d loc = getPos(torsions_[j]->getAtomA())
239 + getPos(torsions_[j]->getAtomB())
240 + getPos(torsions_[j]->getAtomC())
241 + getPos(torsions_[j]->getAtomD());
242 checkDistance(centerPos, loc / 4.0,
243 bsResult.bitsets_[TORSION], j);
244 }
245 }
246
247 // Inversions (centroid of four atoms)
248 for (size_t j = 0; j < inversions_.size(); ++j) {
249 if (inversions_[j] != NULL) {
250 Vector3d loc = getPos(inversions_[j]->getAtomA())
251 + getPos(inversions_[j]->getAtomB())
252 + getPos(inversions_[j]->getAtomC())
253 + getPos(inversions_[j]->getAtomD());
254 checkDistance(centerPos, loc / 4.0,
255 bsResult.bitsets_[INVERSION], j);
256 }
257 }
258 }
259 return bsResult;
260 }
261} // 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.
@ STUNTDOUBLE
StuntDoubles (Atoms & RigidBodies).