OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SimInfo.cpp
Go to the documentation of this file.
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/**
49 * @file SimInfo.cpp
50 * @author tlin
51 * @date 11/02/2004
52 * @version 1.0
53 */
54
55#include "brains/SimInfo.hpp"
56
57#include <algorithm>
58#include <cstdint>
59#include <map>
60#include <memory>
61#include <random>
62#include <set>
63
64#ifdef IS_MPI
65#include <mpi.h>
66#endif
67
68#include "brains/ForceField.hpp"
69#include "io/ForceFieldOptions.hpp"
70#include "math/Vector3.hpp"
71#include "nonbonded/SwitchingFunction.hpp"
74#include "selection/SelectionManager.hpp"
75#include "utils/MemoryUtils.hpp"
76#include "utils/RandNumGen.hpp"
77#include "utils/simError.h"
78
79using namespace std;
80namespace OpenMD {
81
83 forceField_(ff), simParams_(simParams), randNumGen_ {nullptr}, nAtoms_(0),
84 nBonds_(0), nBends_(0), nTorsions_(0), nInversions_(0), nRigidBodies_(0),
85 nIntegrableObjects_(0), nCutoffGroups_(0), nConstraints_(0),
86 nFluctuatingCharges_(0), nGlobalMols_(0), nGlobalAtoms_(0),
87 nGlobalCutoffGroups_(0), nGlobalIntegrableObjects_(0),
88 nGlobalRigidBodies_(0), nGlobalFluctuatingCharges_(0), nGlobalBonds_(0),
89 nGlobalBends_(0), nGlobalTorsions_(0), nGlobalInversions_(0),
90 nGlobalConstraints_(0), hasNGlobalConstraints_(false), ndf_(0),
91 fdf_local(0), ndfRaw_(0), ndfTrans_(0), nZconstraint_(0), sman_(NULL),
92 topologyDone_(false), calcBoxDipole_(false), calcBoxQuadrupole_(false),
93 useAtomicVirial_(true) {
94 MoleculeStamp* molStamp;
95 int nMolWithSameStamp;
96 int nCutoffAtoms = 0; // number of atoms belong to cutoff groups
97 int nGroups = 0; // total cutoff groups defined in meta-data file
98 CutoffGroupStamp* cgStamp;
99 RigidBodyStamp* rbStamp;
100 int nRigidAtoms = 0;
101
102 vector<Component*> components = simParams->getComponents();
103
104 for (vector<Component*>::iterator i = components.begin();
105 i != components.end(); ++i) {
106 molStamp = (*i)->getMoleculeStamp();
107 if ((*i)->haveRegion()) {
108 molStamp->setRegion((*i)->getRegion());
109 } else {
110 // set the region to a disallowed value:
111 molStamp->setRegion(-1);
112 }
113
114 nMolWithSameStamp = (*i)->getNMol();
115
116 addMoleculeStamp(molStamp, nMolWithSameStamp);
117
118 // calculate atoms in molecules
119 nGlobalAtoms_ += molStamp->getNAtoms() * nMolWithSameStamp;
120 nGlobalBonds_ += molStamp->getNBonds() * nMolWithSameStamp;
121 nGlobalBends_ += molStamp->getNBends() * nMolWithSameStamp;
122 nGlobalTorsions_ += molStamp->getNTorsions() * nMolWithSameStamp;
123 nGlobalInversions_ += molStamp->getNInversions() * nMolWithSameStamp;
124
125 // calculate atoms in cutoff groups
126 int nAtomsInGroups = 0;
127 int nCutoffGroupsInStamp = molStamp->getNCutoffGroups();
128
129 for (int j = 0; j < nCutoffGroupsInStamp; j++) {
130 cgStamp = molStamp->getCutoffGroupStamp(j);
131 nAtomsInGroups += cgStamp->getNMembers();
132 }
133
134 nGroups += nCutoffGroupsInStamp * nMolWithSameStamp;
135
136 nCutoffAtoms += nAtomsInGroups * nMolWithSameStamp;
137
138 // calculate atoms in rigid bodies
139 int nAtomsInRigidBodies = 0;
140 int nRigidBodiesInStamp = molStamp->getNRigidBodies();
141
142 for (int j = 0; j < nRigidBodiesInStamp; j++) {
143 rbStamp = molStamp->getRigidBodyStamp(j);
144 nAtomsInRigidBodies += rbStamp->getNMembers();
145 }
146
147 nGlobalRigidBodies_ += nRigidBodiesInStamp * nMolWithSameStamp;
148 nRigidAtoms += nAtomsInRigidBodies * nMolWithSameStamp;
149 }
150
151 // every free atom (atom does not belong to cutoff groups) is a cutoff
152 // group therefore the total number of cutoff groups in the system is
153 // equal to the total number of atoms minus number of atoms belong to
154 // cutoff group defined in meta-data file plus the number of cutoff
155 // groups defined in meta-data file
156
157 nGlobalCutoffGroups_ = nGlobalAtoms_ - nCutoffAtoms + nGroups;
158
159 // every free atom (atom does not belong to rigid bodies) is an
160 // integrable object therefore the total number of integrable objects
161 // in the system is equal to the total number of atoms minus number of
162 // atoms belong to rigid body defined in meta-data file plus the number
163 // of rigid bodies defined in meta-data file
164 nGlobalIntegrableObjects_ =
165 nGlobalAtoms_ - nRigidAtoms + nGlobalRigidBodies_;
166
167 nGlobalMols_ = molStampIds_.size();
168 molToProcMap_.resize(nGlobalMols_);
169
170 // Initialize the random number generator on each processing
171 // element using either the user-supplied seed or a default seed
172 std::uint_fast32_t seed;
173
174 if (simParams_->haveSeed())
175 seed = static_cast<std::uint_fast32_t>(simParams_->getSeed());
176 else
177 seed = std::mt19937::default_seed;
178
179 randNumGen_ = std::make_shared<Utils::RandNumGen>(seed);
180 }
181
182 SimInfo::~SimInfo() {
183 Utils::deletePointers(molecules_);
184
185 delete sman_;
186 delete simParams_;
187 delete forceField_;
188 }
189
191 MoleculeIterator i;
192
193 i = molecules_.find(mol->getGlobalIndex());
194 if (i == molecules_.end()) {
195 molecules_.insert(make_pair(mol->getGlobalIndex(), mol));
196
197 nAtoms_ += mol->getNAtoms();
198 nBonds_ += mol->getNBonds();
199 nBends_ += mol->getNBends();
200 nTorsions_ += mol->getNTorsions();
201 nInversions_ += mol->getNInversions();
202 nRigidBodies_ += mol->getNRigidBodies();
203 nIntegrableObjects_ += mol->getNIntegrableObjects();
204 nCutoffGroups_ += mol->getNCutoffGroups();
205 nConstraints_ += mol->getNConstraintPairs();
206
208
209 return true;
210 } else {
211 return false;
212 }
213 }
214
216 MoleculeIterator i;
217 i = molecules_.find(mol->getGlobalIndex());
218
219 if (i != molecules_.end()) {
220 assert(mol == i->second);
221
222 nAtoms_ -= mol->getNAtoms();
223 nBonds_ -= mol->getNBonds();
224 nBends_ -= mol->getNBends();
225 nTorsions_ -= mol->getNTorsions();
226 nInversions_ -= mol->getNInversions();
227 nRigidBodies_ -= mol->getNRigidBodies();
228 nIntegrableObjects_ -= mol->getNIntegrableObjects();
229 nCutoffGroups_ -= mol->getNCutoffGroups();
230 nConstraints_ -= mol->getNConstraintPairs();
231
233 molecules_.erase(mol->getGlobalIndex());
234
235 delete mol;
236
237 return true;
238 } else {
239 return false;
240 }
241 }
242
243 Molecule* SimInfo::beginMolecule(MoleculeIterator& i) {
244 i = molecules_.begin();
245 return i == molecules_.end() ? NULL : i->second;
246 }
247
248 Molecule* SimInfo::nextMolecule(MoleculeIterator& i) {
249 ++i;
250 return i == molecules_.end() ? NULL : i->second;
251 }
252
253 void SimInfo::calcNdf() {
254 int ndf_local, nfq_local;
255 MoleculeIterator i;
256 vector<StuntDouble*>::iterator j;
257 vector<Atom*>::iterator k;
258
259 Molecule* mol;
260 StuntDouble* sd;
261 Atom* atom;
262
263 ndf_local = 0;
264 nfq_local = 0;
265
266 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
267 for (sd = mol->beginIntegrableObject(j); sd != NULL;
268 sd = mol->nextIntegrableObject(j)) {
269 ndf_local += 3;
270
271 if (sd->isDirectional()) {
272 if (sd->isLinear()) {
273 ndf_local += 2;
274 } else {
275 ndf_local += 3;
276 }
277 }
278 }
279
280 for (atom = mol->beginFluctuatingCharge(k); atom != NULL;
281 atom = mol->nextFluctuatingCharge(k)) {
282 if (atom->isFluctuatingCharge()) { nfq_local++; }
283 }
284 }
285
286 ndfLocal_ = ndf_local;
287
288 // n_constraints is local, so subtract them on each processor
289 ndf_local -= nConstraints_;
290
291#ifdef IS_MPI
292 MPI_Allreduce(&ndf_local, &ndf_, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
293 MPI_Allreduce(&nfq_local, &nGlobalFluctuatingCharges_, 1, MPI_INT, MPI_SUM,
294 MPI_COMM_WORLD);
295#else
296 ndf_ = ndf_local;
297 nGlobalFluctuatingCharges_ = nfq_local;
298#endif
299
300 // nZconstraints_ is global, as are the 3 COM translations for the
301 // entire system:
302 ndf_ = ndf_ - 3 - nZconstraint_;
303 }
304
305 int SimInfo::getFdf() {
306#ifdef IS_MPI
307 MPI_Allreduce(&fdf_local, &fdf_, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
308#else
309 fdf_ = fdf_local;
310#endif
311 return fdf_;
312 }
313
315 int nLocalCutoffAtoms = 0;
316 Molecule* mol;
317 MoleculeIterator mi;
318 CutoffGroup* cg;
319 Molecule::CutoffGroupIterator ci;
320
321 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
322 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
323 cg = mol->nextCutoffGroup(ci)) {
324 nLocalCutoffAtoms += cg->getNumAtom();
325 }
326 }
327
328 return nAtoms_ - nLocalCutoffAtoms + nCutoffGroups_;
329 }
330
331 void SimInfo::calcNdfRaw() {
332 int ndfRaw_local;
333
334 MoleculeIterator i;
335 vector<StuntDouble*>::iterator j;
336 Molecule* mol;
337 StuntDouble* sd;
338
339 // Raw degrees of freedom that we have to set
340 ndfRaw_local = 0;
341
342 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
343 for (sd = mol->beginIntegrableObject(j); sd != NULL;
344 sd = mol->nextIntegrableObject(j)) {
345 ndfRaw_local += 3;
346
347 if (sd->isDirectional()) {
348 if (sd->isLinear()) {
349 ndfRaw_local += 2;
350 } else {
351 ndfRaw_local += 3;
352 }
353 }
354 }
355 }
356
357#ifdef IS_MPI
358 MPI_Allreduce(&ndfRaw_local, &ndfRaw_, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
359#else
360 ndfRaw_ = ndfRaw_local;
361#endif
362 }
363
364 void SimInfo::calcNdfTrans() {
365 int ndfTrans_local;
366
367 ndfTrans_local = 3 * nIntegrableObjects_ - nConstraints_;
368
369#ifdef IS_MPI
370 MPI_Allreduce(&ndfTrans_local, &ndfTrans_, 1, MPI_INT, MPI_SUM,
371 MPI_COMM_WORLD);
372#else
373 ndfTrans_ = ndfTrans_local;
374#endif
375
376 ndfTrans_ = ndfTrans_ - 3 - nZconstraint_;
377 }
378
380 ForceFieldOptions& options_ = forceField_->getForceFieldOptions();
381 vector<Bond*>::iterator bondIter;
382 vector<Bend*>::iterator bendIter;
383 vector<Torsion*>::iterator torsionIter;
384 vector<Inversion*>::iterator inversionIter;
385 Bond* bond;
386 Bend* bend;
387 Torsion* torsion;
388 Inversion* inversion;
389 int a;
390 int b;
391 int c;
392 int d;
393
394 // atomGroups can be used to add special interaction maps between
395 // groups of atoms that are in two separate rigid bodies.
396 // However, most site-site interactions between two rigid bodies
397 // are probably not special, just the ones between the physically
398 // bonded atoms. Interactions *within* a single rigid body should
399 // always be excluded. These are done at the bottom of this
400 // function.
401
402 map<int, set<int>> atomGroups;
403 Molecule::RigidBodyIterator rbIter;
404 RigidBody* rb;
405 Molecule::IntegrableObjectIterator ii;
406 StuntDouble* sd;
407
408 for (sd = mol->beginIntegrableObject(ii); sd != NULL;
409 sd = mol->nextIntegrableObject(ii)) {
410 if (sd->isRigidBody()) {
411 rb = static_cast<RigidBody*>(sd);
412 vector<Atom*> atoms = rb->getAtoms();
413 set<int> rigidAtoms;
414 for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
415 rigidAtoms.insert(atoms[i]->getGlobalIndex());
416 }
417 for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
418 atomGroups.insert(map<int, set<int>>::value_type(
419 atoms[i]->getGlobalIndex(), rigidAtoms));
420 }
421 } else {
422 set<int> oneAtomSet;
423 oneAtomSet.insert(sd->getGlobalIndex());
424 atomGroups.insert(
425 map<int, set<int>>::value_type(sd->getGlobalIndex(), oneAtomSet));
426 }
427 }
428
429 for (bond = mol->beginBond(bondIter); bond != NULL;
430 bond = mol->nextBond(bondIter)) {
431 a = bond->getAtomA()->getGlobalIndex();
432 b = bond->getAtomB()->getGlobalIndex();
433
434 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
435 oneTwoInteractions_.addPair(a, b);
436 } else {
437 excludedInteractions_.addPair(a, b);
438 }
439 }
440
441 for (bend = mol->beginBend(bendIter); bend != NULL;
442 bend = mol->nextBend(bendIter)) {
443 a = bend->getAtomA()->getGlobalIndex();
444 b = bend->getAtomB()->getGlobalIndex();
445 c = bend->getAtomC()->getGlobalIndex();
446
447 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
448 oneTwoInteractions_.addPair(a, b);
449 oneTwoInteractions_.addPair(b, c);
450 } else {
451 excludedInteractions_.addPair(a, b);
452 excludedInteractions_.addPair(b, c);
453 }
454
455 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
456 oneThreeInteractions_.addPair(a, c);
457 } else {
458 excludedInteractions_.addPair(a, c);
459 }
460 }
461
462 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
463 torsion = mol->nextTorsion(torsionIter)) {
464 a = torsion->getAtomA()->getGlobalIndex();
465 b = torsion->getAtomB()->getGlobalIndex();
466 c = torsion->getAtomC()->getGlobalIndex();
467 d = torsion->getAtomD()->getGlobalIndex();
468
469 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
470 oneTwoInteractions_.addPair(a, b);
471 oneTwoInteractions_.addPair(b, c);
472 oneTwoInteractions_.addPair(c, d);
473 } else {
474 excludedInteractions_.addPair(a, b);
475 excludedInteractions_.addPair(b, c);
476 excludedInteractions_.addPair(c, d);
477 }
478
479 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
480 oneThreeInteractions_.addPair(a, c);
481 oneThreeInteractions_.addPair(b, d);
482 } else {
483 excludedInteractions_.addPair(a, c);
484 excludedInteractions_.addPair(b, d);
485 }
486
487 if (options_.havevdw14scale() || options_.haveelectrostatic14scale()) {
488 oneFourInteractions_.addPair(a, d);
489 } else {
490 excludedInteractions_.addPair(a, d);
491 }
492 }
493
494 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
495 inversion = mol->nextInversion(inversionIter)) {
496 a = inversion->getAtomA()->getGlobalIndex();
497 b = inversion->getAtomB()->getGlobalIndex();
498 c = inversion->getAtomC()->getGlobalIndex();
499 d = inversion->getAtomD()->getGlobalIndex();
500
501 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
502 oneTwoInteractions_.addPair(a, b);
503 oneTwoInteractions_.addPair(a, c);
504 oneTwoInteractions_.addPair(a, d);
505 } else {
506 excludedInteractions_.addPair(a, b);
507 excludedInteractions_.addPair(a, c);
508 excludedInteractions_.addPair(a, d);
509 }
510
511 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
512 oneThreeInteractions_.addPair(b, c);
513 oneThreeInteractions_.addPair(b, d);
514 oneThreeInteractions_.addPair(c, d);
515 } else {
516 excludedInteractions_.addPair(b, c);
517 excludedInteractions_.addPair(b, d);
518 excludedInteractions_.addPair(c, d);
519 }
520 }
521
522 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
523 rb = mol->nextRigidBody(rbIter)) {
524 vector<Atom*> atoms = rb->getAtoms();
525 for (int i = 0; i < static_cast<int>(atoms.size()) - 1; ++i) {
526 for (int j = i + 1; j < static_cast<int>(atoms.size()); ++j) {
527 a = atoms[i]->getGlobalIndex();
528 b = atoms[j]->getGlobalIndex();
529 excludedInteractions_.addPair(a, b);
530 }
531 }
532 }
533 }
534
536 ForceFieldOptions& options_ = forceField_->getForceFieldOptions();
537 vector<Bond*>::iterator bondIter;
538 vector<Bend*>::iterator bendIter;
539 vector<Torsion*>::iterator torsionIter;
540 vector<Inversion*>::iterator inversionIter;
541 Bond* bond;
542 Bend* bend;
543 Torsion* torsion;
544 Inversion* inversion;
545 int a;
546 int b;
547 int c;
548 int d;
549
550 map<int, set<int>> atomGroups;
551 Molecule::RigidBodyIterator rbIter;
552 RigidBody* rb;
553 Molecule::IntegrableObjectIterator ii;
554 StuntDouble* sd;
555
556 for (sd = mol->beginIntegrableObject(ii); sd != NULL;
557 sd = mol->nextIntegrableObject(ii)) {
558 if (sd->isRigidBody()) {
559 rb = static_cast<RigidBody*>(sd);
560 vector<Atom*> atoms = rb->getAtoms();
561 set<int> rigidAtoms;
562 for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
563 rigidAtoms.insert(atoms[i]->getGlobalIndex());
564 }
565 for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
566 atomGroups.insert(map<int, set<int>>::value_type(
567 atoms[i]->getGlobalIndex(), rigidAtoms));
568 }
569 } else {
570 set<int> oneAtomSet;
571 oneAtomSet.insert(sd->getGlobalIndex());
572 atomGroups.insert(
573 map<int, set<int>>::value_type(sd->getGlobalIndex(), oneAtomSet));
574 }
575 }
576
577 for (bond = mol->beginBond(bondIter); bond != NULL;
578 bond = mol->nextBond(bondIter)) {
579 a = bond->getAtomA()->getGlobalIndex();
580 b = bond->getAtomB()->getGlobalIndex();
581
582 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
583 oneTwoInteractions_.removePair(a, b);
584 } else {
585 excludedInteractions_.removePair(a, b);
586 }
587 }
588
589 for (bend = mol->beginBend(bendIter); bend != NULL;
590 bend = mol->nextBend(bendIter)) {
591 a = bend->getAtomA()->getGlobalIndex();
592 b = bend->getAtomB()->getGlobalIndex();
593 c = bend->getAtomC()->getGlobalIndex();
594
595 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
596 oneTwoInteractions_.removePair(a, b);
597 oneTwoInteractions_.removePair(b, c);
598 } else {
599 excludedInteractions_.removePair(a, b);
600 excludedInteractions_.removePair(b, c);
601 }
602
603 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
604 oneThreeInteractions_.removePair(a, c);
605 } else {
606 excludedInteractions_.removePair(a, c);
607 }
608 }
609
610 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
611 torsion = mol->nextTorsion(torsionIter)) {
612 a = torsion->getAtomA()->getGlobalIndex();
613 b = torsion->getAtomB()->getGlobalIndex();
614 c = torsion->getAtomC()->getGlobalIndex();
615 d = torsion->getAtomD()->getGlobalIndex();
616
617 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
618 oneTwoInteractions_.removePair(a, b);
619 oneTwoInteractions_.removePair(b, c);
620 oneTwoInteractions_.removePair(c, d);
621 } else {
622 excludedInteractions_.removePair(a, b);
623 excludedInteractions_.removePair(b, c);
624 excludedInteractions_.removePair(c, d);
625 }
626
627 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
628 oneThreeInteractions_.removePair(a, c);
629 oneThreeInteractions_.removePair(b, d);
630 } else {
631 excludedInteractions_.removePair(a, c);
632 excludedInteractions_.removePair(b, d);
633 }
634
635 if (options_.havevdw14scale() || options_.haveelectrostatic14scale()) {
636 oneFourInteractions_.removePair(a, d);
637 } else {
638 excludedInteractions_.removePair(a, d);
639 }
640 }
641
642 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
643 inversion = mol->nextInversion(inversionIter)) {
644 a = inversion->getAtomA()->getGlobalIndex();
645 b = inversion->getAtomB()->getGlobalIndex();
646 c = inversion->getAtomC()->getGlobalIndex();
647 d = inversion->getAtomD()->getGlobalIndex();
648
649 if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
650 oneTwoInteractions_.removePair(a, b);
651 oneTwoInteractions_.removePair(a, c);
652 oneTwoInteractions_.removePair(a, d);
653 } else {
654 excludedInteractions_.removePair(a, b);
655 excludedInteractions_.removePair(a, c);
656 excludedInteractions_.removePair(a, d);
657 }
658
659 if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
660 oneThreeInteractions_.removePair(b, c);
661 oneThreeInteractions_.removePair(b, d);
662 oneThreeInteractions_.removePair(c, d);
663 } else {
664 excludedInteractions_.removePair(b, c);
665 excludedInteractions_.removePair(b, d);
666 excludedInteractions_.removePair(c, d);
667 }
668 }
669
670 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
671 rb = mol->nextRigidBody(rbIter)) {
672 vector<Atom*> atoms = rb->getAtoms();
673 for (int i = 0; i < static_cast<int>(atoms.size()) - 1; ++i) {
674 for (int j = i + 1; j < static_cast<int>(atoms.size()); ++j) {
675 a = atoms[i]->getGlobalIndex();
676 b = atoms[j]->getGlobalIndex();
677 excludedInteractions_.removePair(a, b);
678 }
679 }
680 }
681 }
682
683 void SimInfo::addMoleculeStamp(MoleculeStamp* molStamp, int nmol) {
684 int curStampId;
685
686 // index from 0
687 curStampId = moleculeStamps_.size();
688
689 moleculeStamps_.push_back(molStamp);
690 moleculeStamps_[moleculeStamps_.size() - 1]->setIdent(curStampId);
691 molStampIds_.insert(molStampIds_.end(), nmol, curStampId);
692 }
693
694 /**
695 * update
696 *
697 * Performs the global checks and variable settings after the
698 * objects have been created.
699 *
700 */
702 setupSimVariables();
703 calcNConstraints();
704 calcNdf();
705 calcNdfRaw();
706 calcNdfTrans();
707 }
708
709 /**
710 * getSimulatedAtomTypes
711 *
712 * Returns an STL set of AtomType* that are actually present in this
713 * simulation. Must query all processors to assemble this information.
714 *
715 */
717 SimInfo::MoleculeIterator mi;
718 Molecule* mol;
719 Molecule::AtomIterator ai;
720 Atom* atom;
721 AtomTypeSet atomTypes;
722
723 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
724 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
725 atomTypes.insert(atom->getAtomType());
726 }
727 }
728
729#ifdef IS_MPI
730
731 // loop over the found atom types on this processor, and add their
732 // numerical idents to a vector:
733
734 vector<int> foundTypes;
735 AtomTypeSet::iterator i;
736 for (i = atomTypes.begin(); i != atomTypes.end(); ++i)
737 foundTypes.push_back((*i)->getIdent());
738
739 // count_local holds the number of found types on this processor
740 int count_local = foundTypes.size();
741
742 int nproc;
743 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
744
745 // we need arrays to hold the counts and displacement vectors for
746 // all processors
747 vector<int> counts(nproc, 0);
748 vector<int> disps(nproc, 0);
749
750 // fill the counts array
751 MPI_Allgather(&count_local, 1, MPI_INT, &counts[0], 1, MPI_INT,
752 MPI_COMM_WORLD);
753
754 // use the processor counts to compute the displacement array
755 disps[0] = 0;
756 int totalCount = counts[0];
757 for (int iproc = 1; iproc < nproc; iproc++) {
758 disps[iproc] = disps[iproc - 1] + counts[iproc - 1];
759 totalCount += counts[iproc];
760 }
761
762 // we need a (possibly redundant) set of all found types:
763 vector<int> ftGlobal(totalCount);
764
765 // now spray out the foundTypes to all the other processors:
766 MPI_Allgatherv(&foundTypes[0], count_local, MPI_INT, &ftGlobal[0],
767 &counts[0], &disps[0], MPI_INT, MPI_COMM_WORLD);
768
769 vector<int>::iterator j;
770
771 // foundIdents is a stl set, so inserting an already found ident
772 // will have no effect.
773 set<int> foundIdents;
774
775 for (j = ftGlobal.begin(); j != ftGlobal.end(); ++j)
776 foundIdents.insert((*j));
777
778 // now iterate over the foundIdents and get the actual atom types
779 // that correspond to these:
780 set<int>::iterator it;
781 for (it = foundIdents.begin(); it != foundIdents.end(); ++it)
782 atomTypes.insert(forceField_->getAtomType((*it)));
783
784#endif
785
786 return atomTypes;
787 }
788
789 int getGlobalCountOfType(AtomType*) {
790 /*
791 AtomTypeSet atypes = getSimulatedAtomTypes();
792 map<AtomType*, int> counts_;
793
794 for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
795 for(atom = mol->beginAtom(ai); atom != NULL;
796 atom = mol->nextAtom(ai)) {
797 atom->getAtomType();
798 }
799 }
800 */
801 return 0;
802 }
803
804 void SimInfo::setupSimVariables() {
805 useAtomicVirial_ = simParams_->getUseAtomicVirial();
806 // we only call setAccumulateBoxDipole if the accumulateBoxDipole
807 // parameter is true
808 calcBoxDipole_ = false;
809 if (simParams_->haveAccumulateBoxDipole())
810 if (simParams_->getAccumulateBoxDipole()) { calcBoxDipole_ = true; }
811 // we only call setAccumulateBoxQuadrupole if the accumulateBoxQuadrupole
812 // parameter is true
813 calcBoxQuadrupole_ = false;
814 if (simParams_->haveAccumulateBoxQuadrupole())
815 if (simParams_->getAccumulateBoxQuadrupole()) {
816 calcBoxQuadrupole_ = true;
817 }
818
819 AtomTypeSet::iterator i;
820 AtomTypeSet atomTypes;
821 atomTypes = getSimulatedAtomTypes();
822 bool usesElectrostatic = false;
823 bool usesMetallic = false;
824 bool usesDirectional = false;
825 bool usesFluctuatingCharges = false;
826 // loop over all of the atom types
827 for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
828 usesElectrostatic |= (*i)->isElectrostatic();
829 usesMetallic |= (*i)->isMetal();
830 usesDirectional |= (*i)->isDirectional();
831 usesFluctuatingCharges |= (*i)->isFluctuatingCharge();
832 }
833
834#ifdef IS_MPI
835 int temp;
836
837 temp = usesDirectional;
838 MPI_Allreduce(MPI_IN_PLACE, &temp, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
839 usesDirectionalAtoms_ = (temp == 0) ? false : true;
840
841 temp = usesMetallic;
842 MPI_Allreduce(MPI_IN_PLACE, &temp, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
843 usesMetallicAtoms_ = (temp == 0) ? false : true;
844
845 temp = usesElectrostatic;
846 MPI_Allreduce(MPI_IN_PLACE, &temp, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
847 usesElectrostaticAtoms_ = (temp == 0) ? false : true;
848
849 temp = usesFluctuatingCharges;
850 MPI_Allreduce(MPI_IN_PLACE, &temp, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
851 usesFluctuatingCharges_ = (temp == 0) ? false : true;
852#else
853
854 usesDirectionalAtoms_ = usesDirectional;
855 usesMetallicAtoms_ = usesMetallic;
856 usesElectrostaticAtoms_ = usesElectrostatic;
857 usesFluctuatingCharges_ = usesFluctuatingCharges;
858
859#endif
860
861 requiresPrepair_ = usesMetallicAtoms_ ? true : false;
862 requiresSkipCorrection_ = usesElectrostaticAtoms_ ? true : false;
863 requiresSelfCorrection_ = usesElectrostaticAtoms_ ? true : false;
864 }
865
867 SimInfo::MoleculeIterator mi;
868 Molecule* mol;
869 Molecule::AtomIterator ai;
870 Atom* atom;
871
872 vector<int> GlobalAtomIndices(getNAtoms(), 0);
873
874 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
875 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
876 GlobalAtomIndices[atom->getLocalIndex()] = atom->getGlobalIndex();
877 }
878 }
879 return GlobalAtomIndices;
880 }
881
883 SimInfo::MoleculeIterator mi;
884 Molecule* mol;
885 Molecule::CutoffGroupIterator ci;
886 CutoffGroup* cg;
887
888 vector<int> GlobalGroupIndices;
889
890 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
891 // local index of cutoff group is trivial, it only depends on the
892 // order of travesing
893 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
894 cg = mol->nextCutoffGroup(ci)) {
895 GlobalGroupIndices.push_back(cg->getGlobalIndex());
896 }
897 }
898 return GlobalGroupIndices;
899 }
900
902 // calculate mass ratio of cutoff group
903 SimInfo::MoleculeIterator mi;
904 Molecule* mol;
905 Molecule::CutoffGroupIterator ci;
906 CutoffGroup* cg;
907 Molecule::AtomIterator ai;
908 Atom* atom;
909 RealType totalMass;
910
911 /**
912 * The mass factor is the relative mass of an atom to the total
913 * mass of the cutoff group it belongs to. By default, all atoms
914 * are their own cutoff groups, and therefore have mass factors of
915 * 1. We need some special handling for massless atoms, which
916 * will be treated as carrying the entire mass of the cutoff
917 * group.
918 */
919 massFactors_.clear();
920 massFactors_.resize(getNAtoms(), 1.0);
921
922 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
923 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
924 cg = mol->nextCutoffGroup(ci)) {
925 totalMass = cg->getMass();
926 for (atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
927 // Check for massless groups - set mfact to 1 if true
928 if (totalMass != 0)
929 massFactors_[atom->getLocalIndex()] = atom->getMass() / totalMass;
930 else
931 massFactors_[atom->getLocalIndex()] = 1.0;
932 }
933 }
934 }
935
936 // Build the identArray_ and regions_
937
938 identArray_.clear();
939 identArray_.reserve(getNAtoms());
940 regions_.clear();
941 regions_.reserve(getNAtoms());
942
943 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
944 int reg = mol->getRegion();
945 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
946 identArray_.push_back(atom->getIdent());
947 regions_.push_back(reg);
948 }
949 }
950
951 topologyDone_ = true;
952 }
953
954 void SimInfo::addProperty(std::shared_ptr<GenericData> genData) {
955 properties_.addProperty(genData);
956 }
957
958 void SimInfo::removeProperty(const string& propName) {
959 properties_.removeProperty(propName);
960 }
961
962 std::vector<string> SimInfo::getPropertyNames() {
963 return properties_.getPropertyNames();
964 }
965
966 std::vector<std::shared_ptr<GenericData>> SimInfo::getProperties() {
967 return properties_.getProperties();
968 }
969
970 std::shared_ptr<GenericData> SimInfo::getPropertyByName(
971 const string& propName) {
972 return properties_.getPropertyByName(propName);
973 }
974
976 if (sman_ == sman) { return; }
977 delete sman_;
978 sman_ = sman;
979
980 SimInfo::MoleculeIterator mi;
981 Molecule::AtomIterator ai;
982 Molecule::RigidBodyIterator rbIter;
983 Molecule::CutoffGroupIterator cgIter;
984 Molecule::BondIterator bondIter;
985 Molecule::BendIterator bendIter;
986 Molecule::TorsionIterator torsionIter;
987 Molecule::InversionIterator inversionIter;
988
989 Molecule* mol;
990 Atom* atom;
991 RigidBody* rb;
992 CutoffGroup* cg;
993 Bond* bond;
994 Bend* bend;
995 Torsion* torsion;
996 Inversion* inversion;
997
998 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
999 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
1000 atom->setSnapshotManager(sman_);
1001 }
1002 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
1003 rb = mol->nextRigidBody(rbIter)) {
1004 rb->setSnapshotManager(sman_);
1005 }
1006 for (cg = mol->beginCutoffGroup(cgIter); cg != NULL;
1007 cg = mol->nextCutoffGroup(cgIter)) {
1008 cg->setSnapshotManager(sman_);
1009 }
1010 for (bond = mol->beginBond(bondIter); bond != NULL;
1011 bond = mol->nextBond(bondIter)) {
1012 bond->setSnapshotManager(sman_);
1013 }
1014 for (bend = mol->beginBend(bendIter); bend != NULL;
1015 bend = mol->nextBend(bendIter)) {
1016 bend->setSnapshotManager(sman_);
1017 }
1018 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
1019 torsion = mol->nextTorsion(torsionIter)) {
1020 torsion->setSnapshotManager(sman_);
1021 }
1022 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
1023 inversion = mol->nextInversion(inversionIter)) {
1024 inversion->setSnapshotManager(sman_);
1025 }
1026 }
1027 }
1028
1029 ostream& operator<<(ostream& o, SimInfo&) { return o; }
1030
1032 if (index >= int(IOIndexToIntegrableObject.size())) {
1033 snprintf(
1034 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
1035 "SimInfo::getIOIndexToIntegrableObject Error: Integrable Object\n"
1036 "\tindex exceeds number of known objects!\n");
1037 painCave.isFatal = 1;
1038 simError();
1039 return NULL;
1040 } else
1041 return IOIndexToIntegrableObject.at(index);
1042 }
1043
1044 void SimInfo::setIOIndexToIntegrableObject(const vector<StuntDouble*>& v) {
1045 IOIndexToIntegrableObject = v;
1046 }
1047
1048 void SimInfo::calcNConstraints() {
1049#ifdef IS_MPI
1050 MPI_Allreduce(&nConstraints_, &nGlobalConstraints_, 1, MPI_INT, MPI_SUM,
1051 MPI_COMM_WORLD);
1052#else
1053 nGlobalConstraints_ = nConstraints_;
1054#endif
1055 }
1056} // namespace OpenMD
AtomType * getAtomType()
Returns the AtomType of this Atom.
Definition Atom.hpp:86
AtomType is what OpenMD looks to for unchanging data about an atom.
Definition AtomType.hpp:69
void setSnapshotManager(SnapshotManager *sman)
Sets the Snapshot Manager of this cutoffGroup.
size_t getNIntegrableObjects()
Returns the total number of integrable objects in this molecule.
Definition Molecule.hpp:183
size_t getNInversions()
Returns the total number of improper torsions in this molecule.
Definition Molecule.hpp:177
int getGlobalIndex()
Returns the global index of this molecule.
Definition Molecule.hpp:109
size_t getNBends()
Returns the total number of bends in this molecule.
Definition Molecule.hpp:171
size_t getNConstraintPairs()
Returns the total number of constraints in this molecule.
Definition Molecule.hpp:189
size_t getNAtoms()
Returns the total number of atoms in this molecule.
Definition Molecule.hpp:165
size_t getNRigidBodies()
Returns the total number of rigid bodies in this molecule.
Definition Molecule.hpp:180
size_t getNBonds()
Returns the total number of bonds in this molecule.
Definition Molecule.hpp:168
size_t getNCutoffGroups()
Returns the total number of cutoff groups in this molecule.
Definition Molecule.hpp:186
size_t getNTorsions()
Returns the total number of torsions in this molecule.
Definition Molecule.hpp:174
std::vector< Atom * > getAtoms()
Returns the atoms of this rigid body.
void setSnapshotManager(SnapshotManager *sman)
Sets the Snapshot Manager of this ShortRangeInteraction.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
bool removeMolecule(Molecule *mol)
Removes a molecule from SimInfo.
Definition SimInfo.cpp:215
std::vector< std::shared_ptr< GenericData > > getProperties()
Returns all of the properties in PropertyMap.
Definition SimInfo.cpp:966
std::vector< int > getGlobalGroupIndices()
returns a vector which maps the local cutoff group index on this processor to the global cutoff group...
Definition SimInfo.cpp:882
void removeInteractionPairs(Molecule *mol)
remove all special interaction pairs which belong to a molecule from the appropriate lists.
Definition SimInfo.cpp:535
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:243
unsigned int getNAtoms()
Returns the number of local atoms.
Definition SimInfo.hpp:175
void prepareTopology()
Do final bookkeeping before Force managers need their data.
Definition SimInfo.cpp:901
std::shared_ptr< GenericData > getPropertyByName(const std::string &propName)
Returns property.
Definition SimInfo.cpp:970
void setSnapshotManager(SnapshotManager *sman)
Sets the snapshot manager.
Definition SimInfo.cpp:975
bool addMolecule(Molecule *mol)
Adds a molecule.
Definition SimInfo.cpp:190
std::vector< std::string > getPropertyNames()
Returns all names of properties.
Definition SimInfo.cpp:962
void addInteractionPairs(Molecule *mol)
add all special interaction pairs (including excluded interactions) in a molecule into the appropriat...
Definition SimInfo.cpp:379
void update()
update
Definition SimInfo.cpp:701
unsigned int getNLocalCutoffGroups()
Returns the number of effective cutoff groups on local processor.
Definition SimInfo.cpp:314
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:248
StuntDouble * getIOIndexToIntegrableObject(int index)
return an integral objects by its global index.
Definition SimInfo.cpp:1031
void addProperty(std::shared_ptr< GenericData > genData)
Adds property into property map.
Definition SimInfo.cpp:954
std::vector< int > getGlobalAtomIndices()
returns a vector which maps the local atom index on this processor to the global atom index.
Definition SimInfo.cpp:866
void removeProperty(const std::string &propName)
Removes property from PropertyMap by name.
Definition SimInfo.cpp:958
AtomTypeSet getSimulatedAtomTypes()
Returns the set of atom types present in this simulation.
Definition SimInfo.cpp:716
SimInfo(ForceField *ff, Globals *simParams)
Constructor of SimInfo.
Definition SimInfo.cpp:82
SnapshotManager class is an abstract class which maintains a series of snapshots.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
RealType getMass()
Returns the mass of this stuntDouble.
bool isLinear()
Tests the if this stuntDouble is a linear rigidbody.
void setSnapshotManager(SnapshotManager *sman)
Sets the Snapshot Manager of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
int getGlobalIndex()
Returns the global index of this stuntDouble.
bool isDirectional()
Tests if this stuntDouble is a directional one.
int getLocalIndex()
Returns the local index of this stuntDouble.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.