OpenMD 3.1
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
ForceManager.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 appropriate papers when you publish your
33 * work. Good starting points are:
34 *
35 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
36 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
37 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
38 * [4] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
39 * [5] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
40 * [6] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
41 * [7] Lamichhane, Newman & Gezelter, J. Chem. Phys. 141, 134110 (2014).
42 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
43 */
44
45/**
46 * @file ForceManager.cpp
47 * @author tlin
48 * @date 11/09/2004
49 * @version 1.0
50 */
51
53
54#define __OPENMD_C
55
56#include <cstdio>
57#include <iomanip>
58#include <iostream>
59
60#include "constraints/ZconstraintForceModifier.hpp"
61#include "integrators/LDForceModifier.hpp"
62#include "integrators/LangevinHullForceModifier.hpp"
63#include "nonbonded/NonBondedInteraction.hpp"
64#include "parallel/ForceMatrixDecomposition.hpp"
66#include "perturbations/LightParameters.hpp"
70#include "primitives/Bend.hpp"
71#include "primitives/Bond.hpp"
75#include "restraints/RestraintForceModifier.hpp"
76#include "restraints/ThermoIntegrationForceModifier.hpp"
77#include "utils/MemoryUtils.hpp"
78#include "utils/simError.h"
79
80using namespace std;
81namespace OpenMD {
82
83 ForceManager::ForceManager(SimInfo* info) :
84 initialized_(false), info_(info), switcher_(NULL), seleMan_(info),
85 evaluator_(info) {
86 forceField_ = info_->getForceField();
87 interactionMan_ = new InteractionManager();
88 fDecomp_ = new ForceMatrixDecomposition(info_, interactionMan_);
89 thermo = new Thermo(info_);
90 }
91
92 ForceManager::~ForceManager() {
93 Utils::deletePointers(forceModifiers_);
94
95 delete switcher_;
96 delete interactionMan_;
97 delete fDecomp_;
98 delete thermo;
99 }
100
101 /**
102 * setupCutoffs
103 *
104 * Sets the values of cutoffRadius, switchingRadius, and cutoffMethod
105 *
106 * cutoffRadius : realType
107 * If the cutoffRadius was explicitly set, use that value.
108 * If the cutoffRadius was not explicitly set:
109 * Are there electrostatic atoms? Use 12.0 Angstroms.
110 * No electrostatic atoms? Poll the atom types present in the
111 * simulation for suggested cutoff values (e.g. 2.5 * sigma).
112 * Use the maximum suggested value that was found.
113 *
114 * cutoffMethod : (one of HARD, SWITCHED, SHIFTED_FORCE, TAYLOR_SHIFTED,
115 * SHIFTED_POTENTIAL, or EWALD_FULL)
116 * If cutoffMethod was explicitly set, use that choice.
117 * If cutoffMethod was not explicitly set, use SHIFTED_FORCE
118 *
119 * switchingRadius : realType
120 * If the cutoffMethod was set to SWITCHED:
121 * If the switchingRadius was explicitly set, use that value
122 * (but do a sanity check first).
123 * If the switchingRadius was not explicitly set: use 0.85 *
124 * cutoffRadius_
125 * If the cutoffMethod was not set to SWITCHED:
126 * Set switchingRadius equal to cutoffRadius for safety.
127 */
129 Globals* simParams_ = info_->getSimParams();
130 int mdFileVersion;
131 rCut_ = 0.0; // Needs a value for a later max() call;
132
133 if (simParams_->haveMDfileVersion())
134 mdFileVersion = simParams_->getMDfileVersion();
135 else
136 mdFileVersion = 0;
137
138 // We need the list of simulated atom types to figure out cutoffs
139 // as well as long range corrections.
140
141 AtomTypeSet::iterator i;
142 AtomTypeSet atomTypes_;
143 atomTypes_ = info_->getSimulatedAtomTypes();
144
145 if (simParams_->haveCutoffRadius()) {
146 rCut_ = simParams_->getCutoffRadius();
147 } else {
148 if (info_->usesElectrostaticAtoms()) {
149 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
150 "ForceManager::setupCutoffs: No value was set for the "
151 "cutoffRadius.\n"
152 "\tOpenMD will use a default value of 12.0 angstroms"
153 "\tfor the cutoffRadius.\n");
154 painCave.isFatal = 0;
155 painCave.severity = OPENMD_INFO;
156 simError();
157 rCut_ = 12.0;
158 } else {
159 RealType thisCut;
160 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
161 thisCut = interactionMan_->getSuggestedCutoffRadius((*i));
162 rCut_ = max(thisCut, rCut_);
163 }
164 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
165 "ForceManager::setupCutoffs: No value was set for the "
166 "cutoffRadius.\n"
167 "\tOpenMD will use %lf angstroms.\n",
168 rCut_);
169 painCave.isFatal = 0;
170 painCave.severity = OPENMD_INFO;
171 simError();
172 }
173 }
174
175 fDecomp_->setCutoffRadius(rCut_);
176 interactionMan_->setCutoffRadius(rCut_);
177 rCutSq_ = rCut_ * rCut_;
178
179 map<string, CutoffMethod> stringToCutoffMethod;
180 stringToCutoffMethod["HARD"] = HARD;
181 stringToCutoffMethod["SWITCHED"] = SWITCHED;
182 stringToCutoffMethod["SHIFTED_POTENTIAL"] = SHIFTED_POTENTIAL;
183 stringToCutoffMethod["SHIFTED_FORCE"] = SHIFTED_FORCE;
184 stringToCutoffMethod["TAYLOR_SHIFTED"] = TAYLOR_SHIFTED;
185 stringToCutoffMethod["EWALD_FULL"] = EWALD_FULL;
186
187 if (simParams_->haveCutoffMethod()) {
188 string cutMeth = toUpperCopy(simParams_->getCutoffMethod());
189 map<string, CutoffMethod>::iterator i;
190 i = stringToCutoffMethod.find(cutMeth);
191 if (i == stringToCutoffMethod.end()) {
192 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
193 "ForceManager::setupCutoffs: Could not find chosen "
194 "cutoffMethod %s\n"
195 "\tShould be one of: "
196 "HARD, SWITCHED, SHIFTED_POTENTIAL, TAYLOR_SHIFTED,\n"
197 "\tSHIFTED_FORCE, or EWALD_FULL\n",
198 cutMeth.c_str());
199 painCave.isFatal = 1;
200 painCave.severity = OPENMD_ERROR;
201 simError();
202 } else {
203 cutoffMethod_ = i->second;
204 }
205 } else {
206 if (mdFileVersion > 1) {
207 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
208 "ForceManager::setupCutoffs: No value was set "
209 "for the cutoffMethod.\n"
210 "\tOpenMD will use SHIFTED_FORCE.\n");
211 painCave.isFatal = 0;
212 painCave.severity = OPENMD_INFO;
213 simError();
214 cutoffMethod_ = SHIFTED_FORCE;
215 } else {
216 // handle the case where the old file version was in play
217 // (there should be no cutoffMethod, so we have to deduce it
218 // from other data).
219
220 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
221 "ForceManager::setupCutoffs : DEPRECATED FILE FORMAT!\n"
222 "\tOpenMD found a file which does not set a cutoffMethod.\n"
223 "\tOpenMD will attempt to deduce a cutoffMethod using the\n"
224 "\tbehavior of the older (version 1) code. To remove this\n"
225 "\twarning, add an explicit cutoffMethod and change the top\n"
226 "\tof the file so that it begins with <OpenMD version=2>\n");
227 painCave.isFatal = 0;
228 painCave.severity = OPENMD_WARNING;
229 simError();
230
231 // The old file version tethered the shifting behavior to the
232 // electrostaticSummationMethod keyword.
233
234 if (simParams_->haveElectrostaticSummationMethod()) {
235 string myMethod = simParams_->getElectrostaticSummationMethod();
236 toUpper(myMethod);
237
238 if (myMethod == "SHIFTED_POTENTIAL") {
239 cutoffMethod_ = SHIFTED_POTENTIAL;
240 } else if (myMethod == "SHIFTED_FORCE") {
241 cutoffMethod_ = SHIFTED_FORCE;
242 } else if (myMethod == "TAYLOR_SHIFTED") {
243 cutoffMethod_ = TAYLOR_SHIFTED;
244 } else if (myMethod == "EWALD_FULL") {
245 cutoffMethod_ = EWALD_FULL;
246 useSurfaceTerm_ = true;
247 }
248
249 if (simParams_->haveSwitchingRadius())
250 rSwitch_ = simParams_->getSwitchingRadius();
251
252 if (myMethod == "SHIFTED_POTENTIAL" || myMethod == "SHIFTED_FORCE" ||
253 myMethod == "TAYLOR_SHIFTED" || myMethod == "EWALD_FULL") {
254 if (simParams_->haveSwitchingRadius()) {
255 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
256 "ForceManager::setupCutoffs : DEPRECATED ERROR MESSAGE\n"
257 "\tA value was set for the switchingRadius\n"
258 "\teven though the electrostaticSummationMethod was\n"
259 "\tset to %s\n",
260 myMethod.c_str());
261 painCave.severity = OPENMD_WARNING;
262 painCave.isFatal = 1;
263 simError();
264 }
265 }
266 if (abs(rCut_ - rSwitch_) < 0.0001) {
267 if (cutoffMethod_ == SHIFTED_FORCE) {
268 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
269 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
270 "\tcutoffRadius and switchingRadius are set to the\n"
271 "\tsame value. OpenMD will use shifted force\n"
272 "\tpotentials instead of switching functions.\n");
273 painCave.isFatal = 0;
274 painCave.severity = OPENMD_WARNING;
275 simError();
276 } else {
277 cutoffMethod_ = SHIFTED_POTENTIAL;
278 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
279 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
280 "\tcutoffRadius and switchingRadius are set to the\n"
281 "\tsame value. OpenMD will use shifted potentials\n"
282 "\tinstead of switching functions.\n");
283 painCave.isFatal = 0;
284 painCave.severity = OPENMD_WARNING;
285 simError();
286 }
287 }
288 }
289 }
290 }
291
292 // create the switching function object:
293
294 switcher_ = new SwitchingFunction();
295
296 if (cutoffMethod_ == SWITCHED) {
297 if (simParams_->haveSwitchingRadius()) {
298 rSwitch_ = simParams_->getSwitchingRadius();
299 if (rSwitch_ > rCut_) {
300 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
301 "ForceManager::setupCutoffs: switchingRadius (%f) is larger "
302 "than the cutoffRadius(%f)\n",
303 rSwitch_, rCut_);
304 painCave.isFatal = 1;
305 painCave.severity = OPENMD_ERROR;
306 simError();
307 }
308 } else {
309 rSwitch_ = 0.85 * rCut_;
310 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
311 "ForceManager::setupCutoffs: No value was set for the "
312 "switchingRadius.\n"
313 "\tOpenMD will use a default value of 85 percent of the "
314 "cutoffRadius.\n"
315 "\tswitchingRadius = %f. for this simulation\n",
316 rSwitch_);
317 painCave.isFatal = 0;
318 painCave.severity = OPENMD_WARNING;
319 simError();
320 }
321 } else {
322 if (mdFileVersion > 1) {
323 // throw an error if we define a switching radius and don't need one.
324 // older file versions should not do this.
325 if (simParams_->haveSwitchingRadius()) {
326 map<string, CutoffMethod>::const_iterator it;
327 string theMeth;
328 for (it = stringToCutoffMethod.begin();
329 it != stringToCutoffMethod.end(); ++it) {
330 if (it->second == cutoffMethod_) {
331 theMeth = it->first;
332 break;
333 }
334 }
335 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
336 "ForceManager::setupCutoffs: the cutoffMethod (%s)\n"
337 "\tis not set to SWITCHED, so switchingRadius value\n"
338 "\twill be ignored for this simulation\n",
339 theMeth.c_str());
340 painCave.isFatal = 0;
341 painCave.severity = OPENMD_WARNING;
342 simError();
343 }
344 }
345 rSwitch_ = rCut_;
346 }
347
348 // Default to cubic switching function.
349 sft_ = cubic;
350 if (simParams_->haveSwitchingFunctionType()) {
351 string funcType = simParams_->getSwitchingFunctionType();
352 toUpper(funcType);
353 if (funcType == "CUBIC") {
354 sft_ = cubic;
355 } else {
356 if (funcType == "FIFTH_ORDER_POLYNOMIAL") {
357 sft_ = fifth_order_poly;
358 } else {
359 // throw error
360 snprintf(
361 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
362 "ForceManager::setupSwitching : Unknown switchingFunctionType. "
363 "(Input "
364 "file specified %s .)\n"
365 "\tswitchingFunctionType must be one of: "
366 "\"cubic\" or \"fifth_order_polynomial\".",
367 funcType.c_str());
368 painCave.isFatal = 1;
369 painCave.severity = OPENMD_ERROR;
370 simError();
371 }
372 }
373 }
374 switcher_->setSwitchType(sft_);
375 switcher_->setSwitch(rSwitch_, rCut_);
376 }
377
379 if (!info_->isTopologyDone()) {
380 info_->update();
381 interactionMan_->setSimInfo(info_);
382 interactionMan_->initialize();
383
384 useSurfaceTerm_ = false; // default, can be set by Ewald or directly
385 useSlabGeometry_ = false;
386
387 //! We want to delay the cutoffs until after the interaction
388 //! manager has set up the atom-atom interactions so that we can
389 //! query them for suggested cutoff values
390 setupCutoffs();
391
392 info_->prepareTopology();
393
394 doParticlePot_ = info_->getSimParams()->getOutputParticlePotential();
395 doHeatFlux_ = info_->getSimParams()->getPrintHeatFlux();
396 if (doHeatFlux_) doParticlePot_ = true;
397
398 doElectricField_ = info_->getSimParams()->getOutputElectricField();
399 doElectricField_ |=
400 info_->getSimParams()->getRNEMDParameters()->requiresElectricField();
401 doSitePotential_ = info_->getSimParams()->getOutputSitePotential();
402 if (info_->getSimParams()->haveUseSurfaceTerm() &&
403 info_->getSimParams()->getUseSurfaceTerm()) {
404 if (info_->usesElectrostaticAtoms()) {
405 useSurfaceTerm_ = info_->getSimParams()->getUseSurfaceTerm();
406 if (info_->getSimParams()->haveUseSlabGeometry()) {
407 useSlabGeometry_ = info_->getSimParams()->getUseSlabGeometry();
408
409 string axis =
410 toUpperCopy(info_->getSimParams()->getPrivilegedAxis());
411 if (axis.compare("X") == 0)
412 axis_ = 0;
413 else if (axis.compare("Y") == 0)
414 axis_ = 1;
415 else
416 axis_ = 2;
417 }
418 } else {
419 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
420 "ForceManager::initialize : useSurfaceTerm was set true\n"
421 "\tbut no electrostatic atoms are present. OpenMD will\n"
422 "\tignore this setting.\n");
423 painCave.isFatal = 0;
424 painCave.severity = OPENMD_WARNING;
425 simError();
426 }
427 }
428 }
429
430 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
431
432 //! Force fields can set options on how to scale van der Waals and
433 //! electrostatic interactions for atoms connected via bonds, bends
434 //! and torsions in this case the topological distance between
435 //! atoms is:
436 //! 0 = topologically unconnected
437 //! 1 = bonded together
438 //! 2 = connected via a bend
439 //! 3 = connected via a torsion
440
441 vdwScale_.reserve(4);
442 fill(vdwScale_.begin(), vdwScale_.end(), 0.0);
443
444 electrostaticScale_.reserve(4);
445 fill(electrostaticScale_.begin(), electrostaticScale_.end(), 0.0);
446
447 vdwScale_[0] = 1.0;
448 vdwScale_[1] = fopts.getvdw12scale();
449 vdwScale_[2] = fopts.getvdw13scale();
450 vdwScale_[3] = fopts.getvdw14scale();
451
452 electrostaticScale_[0] = 1.0;
453 electrostaticScale_[1] = fopts.getelectrostatic12scale();
454 electrostaticScale_[2] = fopts.getelectrostatic13scale();
455 electrostaticScale_[3] = fopts.getelectrostatic14scale();
456
457 // Initialize the perturbations
458 if (info_->getSimParams()->haveUniformField()) {
459 UniformField* eField = new UniformField(info_);
460 forceModifiers_.push_back(eField);
461 }
462
463 if (info_->getSimParams()->haveMagneticField()) {
464 MagneticField* mField = new MagneticField(info_);
465 forceModifiers_.push_back(mField);
466 }
467
468 if (info_->getSimParams()->haveUniformGradientStrength() ||
469 info_->getSimParams()->haveUniformGradientDirection1() ||
470 info_->getSimParams()->haveUniformGradientDirection2()) {
471 UniformGradient* eGrad = new UniformGradient(info_);
472 forceModifiers_.push_back(eGrad);
473 }
474
475 if (info_->getSimParams()->getLightParameters()->getUseLight()) {
476 Perturbations::Light* light = new Perturbations::Light(info_);
477 forceModifiers_.push_back(light);
478 }
479
480 // Initialize the force modifiers (order matters)
481 if (info_->getSimParams()->getUseThermodynamicIntegration()) {
484 forceModifiers_.push_back(thermoInt);
485 } else if (info_->getSimParams()->getUseRestraints()) {
486 RestraintForceModifier* restraint = new RestraintForceModifier(info_);
487 forceModifiers_.push_back(restraint);
488 }
489
490 std::string ensembleParam =
491 toUpperCopy(info_->getSimParams()->getEnsemble());
492
493 if (ensembleParam == "LHULL" || ensembleParam == "LANGEVINHULL" ||
494 ensembleParam == "SMIPD") {
495 LangevinHullForceModifier* langevinHullFM =
496 new LangevinHullForceModifier(info_);
497 forceModifiers_.push_back(langevinHullFM);
498 } else if (ensembleParam == "LANGEVINDYNAMICS" || ensembleParam == "LD") {
499 LDForceModifier* langevinDynamicsFM = new LDForceModifier(info_);
500 forceModifiers_.push_back(langevinDynamicsFM);
501 }
502
503 if (info_->getSimParams()->getNZconsStamps() > 0) {
504 info_->setNZconstraint(info_->getSimParams()->getNZconsStamps());
506 forceModifiers_.push_back(zCons);
507 }
508
509 usePeriodicBoundaryConditions_ =
510 info_->getSimParams()->getUsePeriodicBoundaryConditions();
511
512 fDecomp_->distributeInitialData();
513
514 doPotentialSelection_ = false;
515 if (info_->getSimParams()->havePotentialSelection()) {
516 doPotentialSelection_ = true;
517 selectionScript_ = info_->getSimParams()->getPotentialSelection();
518 evaluator_.loadScriptString(selectionScript_);
519 if (!evaluator_.isDynamic()) {
520 seleMan_.setSelectionSet(evaluator_.evaluate());
521 }
522 }
523
524 initialized_ = true;
525 }
526
527 void ForceManager::calcForces() {
528 if (!initialized_) initialize();
529
530 preCalculation();
531 shortRangeInteractions();
532 longRangeInteractions();
533 postCalculation();
534 }
535
536 void ForceManager::preCalculation() {
537 SimInfo::MoleculeIterator mi;
538 Molecule* mol;
539 Molecule::AtomIterator ai;
540 Atom* atom;
541 Molecule::RigidBodyIterator rbIter;
542 RigidBody* rb;
543 Molecule::CutoffGroupIterator ci;
544 CutoffGroup* cg;
545
546 // forces and potentials are zeroed here, before any are
547 // accumulated.
548
550
551 fDecomp_->setSnapshot(snap);
552
553 snap->setBondPotential(0.0);
554 snap->setBendPotential(0.0);
555 snap->setTorsionPotential(0.0);
556 snap->setInversionPotential(0.0);
557
558 potVec zeroPot(0.0);
559 snap->setLongRangePotentials(zeroPot);
560
561 snap->setExcludedPotentials(zeroPot);
562 if (doPotentialSelection_) snap->setSelectionPotentials(zeroPot);
563
564 snap->setSelfPotentials(0.0);
565 snap->setRestraintPotential(0.0);
566 snap->setRawPotential(0.0);
567
568 for (mol = info_->beginMolecule(mi); mol != NULL;
569 mol = info_->nextMolecule(mi)) {
570 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
571 atom->zeroForcesAndTorques();
572 }
573
574 // change the positions of atoms which belong to the rigidbodies
575 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
576 rb = mol->nextRigidBody(rbIter)) {
578 }
579
580 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
581 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
582 cg = mol->nextCutoffGroup(ci)) {
583 // calculate the center of mass of cutoff group
584 cg->updateCOM();
585 }
586 }
587 }
588
589 // Zero out the virial tensor
590 virialTensor *= 0.0;
591 // Zero out the heatFlux
592 fDecomp_->setHeatFlux(Vector3d(0.0));
593
594 if (doPotentialSelection_) {
595 if (evaluator_.isDynamic()) {
596 seleMan_.setSelectionSet(evaluator_.evaluate());
597 }
598 }
599 }
600
601 void ForceManager::shortRangeInteractions() {
602 Molecule* mol;
603 RigidBody* rb;
604 Bond* bond;
605 Bend* bend;
606 Torsion* torsion;
607 Inversion* inversion;
608 SimInfo::MoleculeIterator mi;
609 Molecule::RigidBodyIterator rbIter;
610 Molecule::BondIterator bondIter;
611
612 Molecule::BendIterator bendIter;
613 Molecule::TorsionIterator torsionIter;
614 Molecule::InversionIterator inversionIter;
615 RealType bondPotential = 0.0;
616 RealType bendPotential = 0.0;
617 RealType torsionPotential = 0.0;
618 RealType inversionPotential = 0.0;
619 potVec selectionPotential(0.0);
620
621 // calculate short range interactions
622 for (mol = info_->beginMolecule(mi); mol != NULL;
623 mol = info_->nextMolecule(mi)) {
624 // change the positions of atoms which belong to the rigidbodies
625 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
626 rb = mol->nextRigidBody(rbIter)) {
627 rb->updateAtoms();
628 }
629
630 for (bond = mol->beginBond(bondIter); bond != NULL;
631 bond = mol->nextBond(bondIter)) {
632 bond->calcForce(doParticlePot_);
633 bondPotential += bond->getPotential();
634 if (doPotentialSelection_) {
635 if (seleMan_.isSelected(bond->getAtomA()) ||
636 seleMan_.isSelected(bond->getAtomB())) {
637 selectionPotential[BONDED_FAMILY] += bond->getPotential();
638 }
639 }
640 }
641
642 for (bend = mol->beginBend(bendIter); bend != NULL;
643 bend = mol->nextBend(bendIter)) {
644 RealType angle;
645 bend->calcForce(angle, doParticlePot_);
646 RealType currBendPot = bend->getPotential();
647
648 bendPotential += bend->getPotential();
649 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
650 if (i == bendDataSets.end()) {
651 BendDataSet dataSet;
652 dataSet.prev.angle = dataSet.curr.angle = angle;
653 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
654 dataSet.deltaV = 0.0;
655 bendDataSets.insert(
656 map<Bend*, BendDataSet>::value_type(bend, dataSet));
657 } else {
658 i->second.prev.angle = i->second.curr.angle;
659 i->second.prev.potential = i->second.curr.potential;
660 i->second.curr.angle = angle;
661 i->second.curr.potential = currBendPot;
662 i->second.deltaV =
663 fabs(i->second.curr.potential - i->second.prev.potential);
664 }
665 if (doPotentialSelection_) {
666 if (seleMan_.isSelected(bend->getAtomA()) ||
667 seleMan_.isSelected(bend->getAtomB()) ||
668 seleMan_.isSelected(bend->getAtomC())) {
669 selectionPotential[BONDED_FAMILY] += bend->getPotential();
670 }
671 }
672 }
673
674 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
675 torsion = mol->nextTorsion(torsionIter)) {
676 RealType angle;
677 torsion->calcForce(angle, doParticlePot_);
678 RealType currTorsionPot = torsion->getPotential();
679 torsionPotential += torsion->getPotential();
680 map<Torsion*, TorsionDataSet>::iterator i =
681 torsionDataSets.find(torsion);
682 if (i == torsionDataSets.end()) {
683 TorsionDataSet dataSet;
684 dataSet.prev.angle = dataSet.curr.angle = angle;
685 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
686 dataSet.deltaV = 0.0;
687 torsionDataSets.insert(
688 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
689 } else {
690 i->second.prev.angle = i->second.curr.angle;
691 i->second.prev.potential = i->second.curr.potential;
692 i->second.curr.angle = angle;
693 i->second.curr.potential = currTorsionPot;
694 i->second.deltaV =
695 fabs(i->second.curr.potential - i->second.prev.potential);
696 }
697 if (doPotentialSelection_) {
698 if (seleMan_.isSelected(torsion->getAtomA()) ||
699 seleMan_.isSelected(torsion->getAtomB()) ||
700 seleMan_.isSelected(torsion->getAtomC()) ||
701 seleMan_.isSelected(torsion->getAtomD())) {
702 selectionPotential[BONDED_FAMILY] += torsion->getPotential();
703 }
704 }
705 }
706
707 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
708 inversion = mol->nextInversion(inversionIter)) {
709 RealType angle;
710 inversion->calcForce(angle, doParticlePot_);
711 RealType currInversionPot = inversion->getPotential();
712 inversionPotential += inversion->getPotential();
713 map<Inversion*, InversionDataSet>::iterator i =
714 inversionDataSets.find(inversion);
715 if (i == inversionDataSets.end()) {
716 InversionDataSet dataSet;
717 dataSet.prev.angle = dataSet.curr.angle = angle;
718 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
719 dataSet.deltaV = 0.0;
720 inversionDataSets.insert(
721 map<Inversion*, InversionDataSet>::value_type(inversion,
722 dataSet));
723 } else {
724 i->second.prev.angle = i->second.curr.angle;
725 i->second.prev.potential = i->second.curr.potential;
726 i->second.curr.angle = angle;
727 i->second.curr.potential = currInversionPot;
728 i->second.deltaV =
729 fabs(i->second.curr.potential - i->second.prev.potential);
730 }
731 if (doPotentialSelection_) {
732 if (seleMan_.isSelected(inversion->getAtomA()) ||
733 seleMan_.isSelected(inversion->getAtomB()) ||
734 seleMan_.isSelected(inversion->getAtomC()) ||
735 seleMan_.isSelected(inversion->getAtomD())) {
736 selectionPotential[BONDED_FAMILY] += inversion->getPotential();
737 }
738 }
739 }
740 }
741
742#ifdef IS_MPI
743 // Collect from all nodes. This should eventually be moved into a
744 // SystemDecomposition, but this is a better place than in
745 // Thermo to do the collection.
746
747 MPI_Allreduce(MPI_IN_PLACE, &bondPotential, 1, MPI_REALTYPE, MPI_SUM,
748 MPI_COMM_WORLD);
749 MPI_Allreduce(MPI_IN_PLACE, &bendPotential, 1, MPI_REALTYPE, MPI_SUM,
750 MPI_COMM_WORLD);
751 MPI_Allreduce(MPI_IN_PLACE, &torsionPotential, 1, MPI_REALTYPE, MPI_SUM,
752 MPI_COMM_WORLD);
753 MPI_Allreduce(MPI_IN_PLACE, &inversionPotential, 1, MPI_REALTYPE, MPI_SUM,
754 MPI_COMM_WORLD);
755 MPI_Allreduce(MPI_IN_PLACE, &selectionPotential[BONDED_FAMILY], 1,
756 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
757#endif
758
759 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
760 fDecomp_->setSnapshot(curSnapshot);
761
762 curSnapshot->setBondPotential(bondPotential);
763 curSnapshot->setBendPotential(bendPotential);
764 curSnapshot->setTorsionPotential(torsionPotential);
765 curSnapshot->setInversionPotential(inversionPotential);
766 curSnapshot->setSelectionPotentials(selectionPotential);
767
768 // RealType shortRangePotential = bondPotential + bendPotential +
769 // torsionPotential + inversionPotential;
770
771 // curSnapshot->setShortRangePotential(shortRangePotential);
772 }
773
774 void ForceManager::longRangeInteractions() {
775 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
776 fDecomp_->setSnapshot(curSnapshot);
777
778 DataStorage* config = &(curSnapshot->atomData);
779 DataStorage* cgConfig = &(curSnapshot->cgData);
780
781 // calculate the center of mass of cutoff group
782
783 SimInfo::MoleculeIterator mi;
784 Molecule* mol;
785 Molecule::CutoffGroupIterator ci;
786 CutoffGroup* cg;
787
788 if (info_->getNCutoffGroups() != info_->getNAtoms()) {
789 for (mol = info_->beginMolecule(mi); mol != NULL;
790 mol = info_->nextMolecule(mi)) {
791 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
792 cg = mol->nextCutoffGroup(ci)) {
793 cg->updateCOM();
794 }
795 }
796 } else {
797 // center of mass of the group is the same as position of the atom
798 // if cutoff group does not exist
799 cgConfig->position = config->position;
800 cgConfig->velocity = config->velocity;
801 }
802
803 fDecomp_->zeroWorkArrays();
804 fDecomp_->distributeData();
805
806 int cg1, cg2, atom1, atom2;
807 Vector3d d_grp, dag, gvel2, vel2;
808 RealType rgrpsq, rgrp;
809 RealType vij(0.0);
810 Vector3d fij, fg, f1;
811 bool in_switching_region;
812 RealType dswdr, swderiv;
813 vector<int> atomListColumn, atomListRow;
814
815 potVec longRangePotential(0.0);
816 potVec selfPotential(0.0);
817 RealType reciprocalPotential(0.0);
818 RealType surfacePotential(0.0);
819 potVec selectionPotential(0.0);
820
821 RealType mf;
822 bool newAtom1;
823 int gid1, gid2;
824
825 vector<int>::iterator ia, jb;
826
827 int loopStart, loopEnd;
828
829 idat.rcut = rCut_;
830 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ? true : false;
831 idat.shiftedForce =
832 (cutoffMethod_ == SHIFTED_FORCE || cutoffMethod_ == TAYLOR_SHIFTED) ?
833 true :
834 false;
835 idat.doParticlePot = doParticlePot_;
836 idat.doElectricField = doElectricField_;
837 idat.doSitePotential = doSitePotential_;
838 sdat.doParticlePot = doParticlePot_;
839
840 loopEnd = PAIR_LOOP;
841 if (info_->requiresPrepair()) {
842 loopStart = PREPAIR_LOOP;
843 } else {
844 loopStart = PAIR_LOOP;
845 }
846 for (int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
847 if (iLoop == loopStart) {
848 bool update_nlist = fDecomp_->checkNeighborList(savedPositions_);
849
850 if (update_nlist) {
851 if (!usePeriodicBoundaryConditions_)
852 Mat3x3d bbox = thermo->getBoundingBox();
853 fDecomp_->buildNeighborList(neighborList_, point_, savedPositions_);
854 }
855 }
856
857 for (cg1 = 0; cg1 < int(point_.size()) - 1; cg1++) {
858 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
859 newAtom1 = true;
860
861 for (int m2 = point_[cg1]; m2 < point_[cg1 + 1]; m2++) {
862 cg2 = neighborList_[m2];
863
864 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
865
866 // already wrapped in the getIntergroupVector call:
867 // curSnapshot->wrapVector(d_grp);
868 rgrpsq = d_grp.lengthSquare();
869
870 if (rgrpsq < rCutSq_) {
871 if (iLoop == PAIR_LOOP) {
872 vij = 0.0;
873 fij.zero();
874 idat.eField1.zero();
875 idat.eField2.zero();
876 idat.sPot1 = 0.0;
877 idat.sPot2 = 0.0;
878 }
879
880 in_switching_region =
881 switcher_->getSwitch(rgrpsq, idat.sw, dswdr, rgrp);
882
883 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
884
885 if (doHeatFlux_) gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
886
887 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
888 atom1 = (*ia);
889 if (atomListRow.size() > 1) newAtom1 = true;
890
891 if (doPotentialSelection_) {
892 gid1 = fDecomp_->getGlobalIDRow(atom1);
893 idat.isSelected = seleMan_.isGlobalIDSelected(gid1);
894 }
895
896 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
897 ++jb) {
898 atom2 = (*jb);
899
900 if (doPotentialSelection_) {
901 gid2 = fDecomp_->getGlobalIDCol(atom2);
902 idat.isSelected |= seleMan_.isGlobalIDSelected(gid2);
903 }
904
905 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
906 idat.vpair = 0.0;
907 idat.pot = 0.0;
908 idat.excludedPot = 0.0;
909 idat.selePot = 0.0;
910 idat.f1.zero();
911 idat.dVdFQ1 = 0.0;
912 idat.dVdFQ2 = 0.0;
913
914 fDecomp_->fillInteractionData(idat, atom1, atom2, newAtom1);
915 newAtom1 = false;
916
917 idat.topoDist =
918 fDecomp_->getTopologicalDistance(atom1, atom2);
919 idat.vdwMult = vdwScale_[idat.topoDist];
920 idat.electroMult = electrostaticScale_[idat.topoDist];
921
922 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
923 idat.d = d_grp;
924 idat.r2 = rgrpsq;
925 if (doHeatFlux_) vel2 = gvel2;
926 } else {
927 idat.d = fDecomp_->getInteratomicVector(atom1, atom2);
928 curSnapshot->wrapVector(idat.d);
929 idat.r2 = idat.d.lengthSquare();
930 if (doHeatFlux_)
931 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
932 }
933
934 idat.rij = sqrt(idat.r2);
935
936 if (iLoop == PREPAIR_LOOP) {
937 interactionMan_->doPrePair(idat);
938 fDecomp_->unpackPrePairData(idat, atom1, atom2);
939 } else {
940 interactionMan_->doPair(idat);
941 fDecomp_->unpackInteractionData(idat, atom1, atom2);
942 vij += idat.vpair;
943 fij += idat.f1;
944 virialTensor -= outProduct(idat.d, idat.f1);
945 if (doHeatFlux_)
946 fDecomp_->addToHeatFlux(idat.d * dot(idat.f1, vel2));
947 }
948 }
949 }
950 }
951
952 if (iLoop == PAIR_LOOP) {
953 if (in_switching_region) {
954 swderiv = vij * dswdr / rgrp;
955 fg = swderiv * d_grp;
956 fij += fg;
957
958 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
959 if (!fDecomp_->skipAtomPair(atomListRow[0], atomListColumn[0],
960 cg1, cg2)) {
961 virialTensor -= outProduct(idat.d, fg);
962 if (doHeatFlux_)
963 fDecomp_->addToHeatFlux(idat.d * dot(fg, vel2));
964 }
965 }
966
967 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
968 atom1 = (*ia);
969 mf = fDecomp_->getMassFactorRow(atom1);
970 // fg is the force on atom ia due to cutoff group's
971 // presence in switching region
972 fg = swderiv * d_grp * mf;
973 fDecomp_->addForceToAtomRow(atom1, fg);
974 if (atomListRow.size() > 1) {
975 if (info_->usesAtomicVirial()) {
976 // find the distance between the atom
977 // and the center of the cutoff group:
978 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
979 virialTensor -= outProduct(dag, fg);
980 if (doHeatFlux_)
981 fDecomp_->addToHeatFlux(dag * dot(fg, vel2));
982 }
983 }
984 }
985 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
986 ++jb) {
987 atom2 = (*jb);
988 mf = fDecomp_->getMassFactorColumn(atom2);
989 // fg is the force on atom jb due to cutoff group's
990 // presence in switching region
991 fg = -swderiv * d_grp * mf;
992 fDecomp_->addForceToAtomColumn(atom2, fg);
993
994 if (atomListColumn.size() > 1) {
995 if (info_->usesAtomicVirial()) {
996 // find the distance between the atom
997 // and the center of the cutoff group:
998 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
999 virialTensor -= outProduct(dag, fg);
1000 if (doHeatFlux_)
1001 fDecomp_->addToHeatFlux(dag * dot(fg, vel2));
1002 }
1003 }
1004 }
1005 }
1006 // if (!info_->usesAtomicVirial()) {
1007 // virialTensor -= outProduct(d_grp, fij);
1008 // if (doHeatFlux_)
1009 // fDecomp_->addToHeatFlux( d_grp * dot(fij, vel2));
1010 //}
1011 }
1012 }
1013 }
1014 }
1015
1016 if (iLoop == PREPAIR_LOOP) {
1017 if (info_->requiresPrepair()) {
1018 fDecomp_->collectIntermediateData();
1019
1020 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1021 if (doPotentialSelection_) {
1022 gid1 = fDecomp_->getGlobalID(atom1);
1023 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1024 }
1025 fDecomp_->fillPreForceData(sdat, atom1);
1026 interactionMan_->doPreForce(sdat);
1027 fDecomp_->unpackPreForceData(sdat, atom1);
1028 }
1029
1030 fDecomp_->distributeIntermediateData();
1031 }
1032 }
1033 }
1034
1035 // collects pairwise information
1036 fDecomp_->collectData();
1037 if (cutoffMethod_ == EWALD_FULL) {
1038 interactionMan_->doReciprocalSpaceSum(reciprocalPotential);
1039 curSnapshot->setReciprocalPotential(reciprocalPotential);
1040 }
1041
1042 if (useSurfaceTerm_) {
1043 interactionMan_->doSurfaceTerm(useSlabGeometry_, axis_, surfacePotential);
1044 curSnapshot->setSurfacePotential(surfacePotential);
1045 }
1046
1047 if (info_->requiresSelfCorrection()) {
1048 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1049 if (doPotentialSelection_) {
1050 gid1 = fDecomp_->getGlobalID(atom1);
1051 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1052 }
1053 fDecomp_->fillSelfData(sdat, atom1);
1054 interactionMan_->doSelfCorrection(sdat);
1055 fDecomp_->unpackSelfData(sdat, atom1);
1056 }
1057 }
1058
1059 // collects single-atom information
1060 fDecomp_->collectSelfData();
1061
1062 longRangePotential = fDecomp_->getPairwisePotential();
1063 curSnapshot->setLongRangePotentials(longRangePotential);
1064
1065 selfPotential = fDecomp_->getSelfPotential();
1066 curSnapshot->setSelfPotentials(selfPotential);
1067
1068 curSnapshot->setExcludedPotentials(fDecomp_->getExcludedSelfPotential() +
1069 fDecomp_->getExcludedPotential());
1070
1071 if (doPotentialSelection_) {
1072 selectionPotential = curSnapshot->getSelectionPotentials();
1073 selectionPotential += fDecomp_->getSelectedSelfPotential();
1074 selectionPotential += fDecomp_->getSelectedPotential();
1075 curSnapshot->setSelectionPotentials(selectionPotential);
1076 }
1077 }
1078
1079 void ForceManager::postCalculation() {
1080 for (auto& forceModifier : forceModifiers_)
1081 forceModifier->modifyForces();
1082
1083 // Modify the rigid bodies in response to the applied force modifications
1084 SimInfo::MoleculeIterator mi;
1085 Molecule* mol;
1086 Molecule::RigidBodyIterator rbIter;
1087 RigidBody* rb;
1088 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1089
1090 // Collect the atomic forces onto rigid bodies
1091 for (mol = info_->beginMolecule(mi); mol != NULL;
1092 mol = info_->nextMolecule(mi)) {
1093 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
1094 rb = mol->nextRigidBody(rbIter)) {
1096 virialTensor += rbTau;
1097 }
1098 }
1099
1100#ifdef IS_MPI
1101 MPI_Allreduce(MPI_IN_PLACE, virialTensor.getArrayPointer(), 9, MPI_REALTYPE,
1102 MPI_SUM, MPI_COMM_WORLD);
1103#endif
1104 curSnapshot->setVirialTensor(virialTensor);
1105
1106 /*
1107 if (info_->getSimParams()->getUseLongRangeCorrections()) {
1108 RealType vol = curSnapshot->getVolume();
1109 RealType Elrc(0.0);
1110 RealType Wlrc(0.0);
1111
1112 AtomTypeSet::iterator i;
1113 AtomTypeSet::iterator j;
1114
1115 RealType n_i, n_j;
1116 RealType rho_i, rho_j;
1117 pair<RealType, RealType> LRI;
1118
1119 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
1120 n_i = RealType(info_->getGlobalCountOfType(*i));
1121 rho_i = n_i / vol;
1122 for (j = atomTypes_.begin(); j != atomTypes_.end(); ++j) {
1123 n_j = RealType(info_->getGlobalCountOfType(*j));
1124 rho_j = n_j / vol;
1125
1126 LRI = interactionMan_->getLongRangeIntegrals( (*i), (*j) );
1127
1128 Elrc += n_i * rho_j * LRI.first;
1129 Wlrc -= rho_i * rho_j * LRI.second;
1130 }
1131 }
1132 Elrc *= 2.0 * Constants::PI;
1133 Wlrc *= 2.0 * Constants::PI;
1134
1135 RealType lrp = curSnapshot->getLongRangePotential();
1136 curSnapshot->setLongRangePotential(lrp + Elrc);
1137 virialTensor += Wlrc * SquareMatrix3<RealType>::identity();
1138 curSnapshot->setVirialTensor(virialTensor);
1139 }
1140 */
1141 }
1142
1143 void ForceManager::calcSelectedForces(Molecule* mol1, Molecule* mol2) {
1144 if (!initialized_) initialize();
1145
1146 selectedPreCalculation(mol1, mol2);
1147 selectedShortRangeInteractions(mol1, mol2);
1148 selectedLongRangeInteractions(mol1, mol2);
1149 selectedPostCalculation(mol1, mol2);
1150 }
1151
1152 void ForceManager::selectedPreCalculation(Molecule* mol1, Molecule* mol2) {
1153 SimInfo::MoleculeIterator mi;
1154 Molecule::AtomIterator ai;
1155 Atom* atom;
1156 Molecule::RigidBodyIterator rbIter;
1157 RigidBody* rb;
1158 Molecule::CutoffGroupIterator ci;
1159 CutoffGroup* cg;
1160
1161 // forces and potentials are zeroed here, before any are
1162 // accumulated.
1163
1165
1166 snap->setBondPotential(0.0);
1167 snap->setBendPotential(0.0);
1168 snap->setTorsionPotential(0.0);
1169 snap->setInversionPotential(0.0);
1170
1171 potVec zeroPot(0.0);
1172 snap->setLongRangePotentials(zeroPot);
1173 snap->setExcludedPotentials(zeroPot);
1174 if (doPotentialSelection_) snap->setSelectionPotentials(zeroPot);
1175
1176 snap->setRestraintPotential(0.0);
1177 snap->setRawPotential(0.0);
1178
1179 // First we zero out for mol1
1180 for (atom = mol1->beginAtom(ai); atom != NULL; atom = mol1->nextAtom(ai)) {
1181 atom->zeroForcesAndTorques();
1182 }
1183 // change the positions of atoms which belong to the rigidbodies
1184 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1185 rb = mol1->nextRigidBody(rbIter)) {
1187 }
1188 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
1189 for (cg = mol1->beginCutoffGroup(ci); cg != NULL;
1190 cg = mol1->nextCutoffGroup(ci)) {
1191 // calculate the center of mass of cutoff group
1192 cg->updateCOM();
1193 }
1194 }
1195
1196 // Next we zero out for mol2
1197 for (atom = mol2->beginAtom(ai); atom != NULL; atom = mol2->nextAtom(ai)) {
1198 atom->zeroForcesAndTorques();
1199 }
1200 // change the positions of atoms which belong to the rigidbodies
1201 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1202 rb = mol2->nextRigidBody(rbIter)) {
1204 }
1205 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
1206 for (cg = mol2->beginCutoffGroup(ci); cg != NULL;
1207 cg = mol2->nextCutoffGroup(ci)) {
1208 // calculate the center of mass of cutoff group
1209 cg->updateCOM();
1210 }
1211 }
1212
1213 // Zero out the virial tensor
1214 virialTensor *= 0.0;
1215 // Zero out the heatFlux
1216 fDecomp_->setHeatFlux(Vector3d(0.0));
1217 }
1218
1219 void ForceManager::selectedShortRangeInteractions(Molecule* mol1,
1220 Molecule* mol2) {
1221 RigidBody* rb;
1222 Bond* bond;
1223 Bend* bend;
1224 Torsion* torsion;
1225 Inversion* inversion;
1226 SimInfo::MoleculeIterator mi;
1227 Molecule::RigidBodyIterator rbIter;
1228 Molecule::BondIterator bondIter;
1229 Molecule::BendIterator bendIter;
1230 Molecule::TorsionIterator torsionIter;
1231 Molecule::InversionIterator inversionIter;
1232 RealType bondPotential = 0.0;
1233 RealType bendPotential = 0.0;
1234 RealType torsionPotential = 0.0;
1235 RealType inversionPotential = 0.0;
1236 potVec selectionPotential(0.0);
1237
1238 // First compute for mol1
1239 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1240 rb = mol1->nextRigidBody(rbIter)) {
1241 rb->updateAtoms();
1242 }
1243
1244 for (bond = mol1->beginBond(bondIter); bond != NULL;
1245 bond = mol1->nextBond(bondIter)) {
1246 bond->calcForce(doParticlePot_);
1247 bondPotential += bond->getPotential();
1248 if (doPotentialSelection_) {
1249 if (seleMan_.isSelected(bond->getAtomA()) ||
1250 seleMan_.isSelected(bond->getAtomB())) {
1251 selectionPotential[BONDED_FAMILY] += bond->getPotential();
1252 }
1253 }
1254 }
1255
1256 for (bend = mol1->beginBend(bendIter); bend != NULL;
1257 bend = mol1->nextBend(bendIter)) {
1258 RealType angle;
1259 bend->calcForce(angle, doParticlePot_);
1260 RealType currBendPot = bend->getPotential();
1261
1262 bendPotential += bend->getPotential();
1263 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
1264 if (i == bendDataSets.end()) {
1265 BendDataSet dataSet;
1266 dataSet.prev.angle = dataSet.curr.angle = angle;
1267 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
1268 dataSet.deltaV = 0.0;
1269 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend, dataSet));
1270 } else {
1271 i->second.prev.angle = i->second.curr.angle;
1272 i->second.prev.potential = i->second.curr.potential;
1273 i->second.curr.angle = angle;
1274 i->second.curr.potential = currBendPot;
1275 i->second.deltaV =
1276 fabs(i->second.curr.potential - i->second.prev.potential);
1277 }
1278 if (doPotentialSelection_) {
1279 if (seleMan_.isSelected(bend->getAtomA()) ||
1280 seleMan_.isSelected(bend->getAtomB()) ||
1281 seleMan_.isSelected(bend->getAtomC())) {
1282 selectionPotential[BONDED_FAMILY] += bend->getPotential();
1283 }
1284 }
1285 }
1286
1287 for (torsion = mol1->beginTorsion(torsionIter); torsion != NULL;
1288 torsion = mol1->nextTorsion(torsionIter)) {
1289 RealType angle;
1290 torsion->calcForce(angle, doParticlePot_);
1291 RealType currTorsionPot = torsion->getPotential();
1292 torsionPotential += torsion->getPotential();
1293 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
1294 if (i == torsionDataSets.end()) {
1295 TorsionDataSet dataSet;
1296 dataSet.prev.angle = dataSet.curr.angle = angle;
1297 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
1298 dataSet.deltaV = 0.0;
1299 torsionDataSets.insert(
1300 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
1301 } else {
1302 i->second.prev.angle = i->second.curr.angle;
1303 i->second.prev.potential = i->second.curr.potential;
1304 i->second.curr.angle = angle;
1305 i->second.curr.potential = currTorsionPot;
1306 i->second.deltaV =
1307 fabs(i->second.curr.potential - i->second.prev.potential);
1308 }
1309 if (doPotentialSelection_) {
1310 if (seleMan_.isSelected(torsion->getAtomA()) ||
1311 seleMan_.isSelected(torsion->getAtomB()) ||
1312 seleMan_.isSelected(torsion->getAtomC()) ||
1313 seleMan_.isSelected(torsion->getAtomD())) {
1314 selectionPotential[BONDED_FAMILY] += torsion->getPotential();
1315 }
1316 }
1317 }
1318
1319 for (inversion = mol1->beginInversion(inversionIter); inversion != NULL;
1320 inversion = mol1->nextInversion(inversionIter)) {
1321 RealType angle;
1322 inversion->calcForce(angle, doParticlePot_);
1323 RealType currInversionPot = inversion->getPotential();
1324 inversionPotential += inversion->getPotential();
1325 map<Inversion*, InversionDataSet>::iterator i =
1326 inversionDataSets.find(inversion);
1327 if (i == inversionDataSets.end()) {
1328 InversionDataSet dataSet;
1329 dataSet.prev.angle = dataSet.curr.angle = angle;
1330 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
1331 dataSet.deltaV = 0.0;
1332 inversionDataSets.insert(
1333 map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
1334 } else {
1335 i->second.prev.angle = i->second.curr.angle;
1336 i->second.prev.potential = i->second.curr.potential;
1337 i->second.curr.angle = angle;
1338 i->second.curr.potential = currInversionPot;
1339 i->second.deltaV =
1340 fabs(i->second.curr.potential - i->second.prev.potential);
1341 }
1342 if (doPotentialSelection_) {
1343 if (seleMan_.isSelected(inversion->getAtomA()) ||
1344 seleMan_.isSelected(inversion->getAtomB()) ||
1345 seleMan_.isSelected(inversion->getAtomC()) ||
1346 seleMan_.isSelected(inversion->getAtomD())) {
1347 selectionPotential[BONDED_FAMILY] += inversion->getPotential();
1348 }
1349 }
1350 }
1351
1352 // Next compute for mol2
1353 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1354 rb = mol2->nextRigidBody(rbIter)) {
1355 rb->updateAtoms();
1356 }
1357
1358 for (bond = mol2->beginBond(bondIter); bond != NULL;
1359 bond = mol2->nextBond(bondIter)) {
1360 bond->calcForce(doParticlePot_);
1361 bondPotential += bond->getPotential();
1362 if (doPotentialSelection_) {
1363 if (seleMan_.isSelected(bond->getAtomA()) ||
1364 seleMan_.isSelected(bond->getAtomB())) {
1365 selectionPotential[BONDED_FAMILY] += bond->getPotential();
1366 }
1367 }
1368 }
1369
1370 for (bend = mol2->beginBend(bendIter); bend != NULL;
1371 bend = mol2->nextBend(bendIter)) {
1372 RealType angle;
1373 bend->calcForce(angle, doParticlePot_);
1374 RealType currBendPot = bend->getPotential();
1375
1376 bendPotential += bend->getPotential();
1377 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
1378 if (i == bendDataSets.end()) {
1379 BendDataSet dataSet;
1380 dataSet.prev.angle = dataSet.curr.angle = angle;
1381 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
1382 dataSet.deltaV = 0.0;
1383 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend, dataSet));
1384 } else {
1385 i->second.prev.angle = i->second.curr.angle;
1386 i->second.prev.potential = i->second.curr.potential;
1387 i->second.curr.angle = angle;
1388 i->second.curr.potential = currBendPot;
1389 i->second.deltaV =
1390 fabs(i->second.curr.potential - i->second.prev.potential);
1391 }
1392 if (doPotentialSelection_) {
1393 if (seleMan_.isSelected(bend->getAtomA()) ||
1394 seleMan_.isSelected(bend->getAtomB()) ||
1395 seleMan_.isSelected(bend->getAtomC())) {
1396 selectionPotential[BONDED_FAMILY] += bend->getPotential();
1397 }
1398 }
1399 }
1400
1401 for (torsion = mol2->beginTorsion(torsionIter); torsion != NULL;
1402 torsion = mol2->nextTorsion(torsionIter)) {
1403 RealType angle;
1404 torsion->calcForce(angle, doParticlePot_);
1405 RealType currTorsionPot = torsion->getPotential();
1406 torsionPotential += torsion->getPotential();
1407 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
1408 if (i == torsionDataSets.end()) {
1409 TorsionDataSet dataSet;
1410 dataSet.prev.angle = dataSet.curr.angle = angle;
1411 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
1412 dataSet.deltaV = 0.0;
1413 torsionDataSets.insert(
1414 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
1415 } else {
1416 i->second.prev.angle = i->second.curr.angle;
1417 i->second.prev.potential = i->second.curr.potential;
1418 i->second.curr.angle = angle;
1419 i->second.curr.potential = currTorsionPot;
1420 i->second.deltaV =
1421 fabs(i->second.curr.potential - i->second.prev.potential);
1422 }
1423 if (doPotentialSelection_) {
1424 if (seleMan_.isSelected(torsion->getAtomA()) ||
1425 seleMan_.isSelected(torsion->getAtomB()) ||
1426 seleMan_.isSelected(torsion->getAtomC()) ||
1427 seleMan_.isSelected(torsion->getAtomD())) {
1428 selectionPotential[BONDED_FAMILY] += torsion->getPotential();
1429 }
1430 }
1431 }
1432
1433 for (inversion = mol2->beginInversion(inversionIter); inversion != NULL;
1434 inversion = mol2->nextInversion(inversionIter)) {
1435 RealType angle;
1436 inversion->calcForce(angle, doParticlePot_);
1437 RealType currInversionPot = inversion->getPotential();
1438 inversionPotential += inversion->getPotential();
1439 map<Inversion*, InversionDataSet>::iterator i =
1440 inversionDataSets.find(inversion);
1441 if (i == inversionDataSets.end()) {
1442 InversionDataSet dataSet;
1443 dataSet.prev.angle = dataSet.curr.angle = angle;
1444 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
1445 dataSet.deltaV = 0.0;
1446 inversionDataSets.insert(
1447 map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
1448 } else {
1449 i->second.prev.angle = i->second.curr.angle;
1450 i->second.prev.potential = i->second.curr.potential;
1451 i->second.curr.angle = angle;
1452 i->second.curr.potential = currInversionPot;
1453 i->second.deltaV =
1454 fabs(i->second.curr.potential - i->second.prev.potential);
1455 }
1456 if (doPotentialSelection_) {
1457 if (seleMan_.isSelected(inversion->getAtomA()) ||
1458 seleMan_.isSelected(inversion->getAtomB()) ||
1459 seleMan_.isSelected(inversion->getAtomC()) ||
1460 seleMan_.isSelected(inversion->getAtomD())) {
1461 selectionPotential[BONDED_FAMILY] += inversion->getPotential();
1462 }
1463 }
1464 }
1465
1466#ifdef IS_MPI
1467 // Collect from all nodes. This should eventually be moved into a
1468 // SystemDecomposition, but this is a better place than in
1469 // Thermo to do the collection.
1470
1471 MPI_Allreduce(MPI_IN_PLACE, &bondPotential, 1, MPI_REALTYPE, MPI_SUM,
1472 MPI_COMM_WORLD);
1473 MPI_Allreduce(MPI_IN_PLACE, &bendPotential, 1, MPI_REALTYPE, MPI_SUM,
1474 MPI_COMM_WORLD);
1475 MPI_Allreduce(MPI_IN_PLACE, &torsionPotential, 1, MPI_REALTYPE, MPI_SUM,
1476 MPI_COMM_WORLD);
1477 MPI_Allreduce(MPI_IN_PLACE, &inversionPotential, 1, MPI_REALTYPE, MPI_SUM,
1478 MPI_COMM_WORLD);
1479 MPI_Allreduce(MPI_IN_PLACE, &selectionPotential[BONDED_FAMILY], 1,
1480 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1481#endif
1482
1483 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1484
1485 curSnapshot->setBondPotential(bondPotential);
1486 curSnapshot->setBendPotential(bendPotential);
1487 curSnapshot->setTorsionPotential(torsionPotential);
1488 curSnapshot->setInversionPotential(inversionPotential);
1489 curSnapshot->setSelectionPotentials(selectionPotential);
1490
1491 // RealType shortRangePotential = bondPotential + bendPotential +
1492 // torsionPotential + inversionPotential;
1493
1494 // curSnapshot->setShortRangePotential(shortRangePotential);
1495 }
1496
1497 void ForceManager::selectedLongRangeInteractions(Molecule* mol1,
1498 Molecule* mol2) {
1499 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1500 DataStorage* config = &(curSnapshot->atomData);
1501 DataStorage* cgConfig = &(curSnapshot->cgData);
1502
1503 // calculate the center of mass of cutoff group
1504
1505 SimInfo::MoleculeIterator mi;
1506 Molecule::CutoffGroupIterator ci;
1507 CutoffGroup* cg;
1508
1509 if (info_->getNCutoffGroups() != info_->getNAtoms()) {
1510 for (cg = mol1->beginCutoffGroup(ci); cg != NULL;
1511 cg = mol1->nextCutoffGroup(ci)) {
1512 cg->updateCOM();
1513 }
1514 for (cg = mol2->beginCutoffGroup(ci); cg != NULL;
1515 cg = mol2->nextCutoffGroup(ci)) {
1516 cg->updateCOM();
1517 }
1518 } else {
1519 // center of mass of the group is the same as position of the atom
1520 // if cutoff group does not exist
1521 cgConfig->position = config->position;
1522 cgConfig->velocity = config->velocity;
1523 }
1524
1525 fDecomp_->zeroWorkArrays();
1526 fDecomp_->distributeData();
1527
1528 int cg1, cg2, atom1, atom2;
1529 Vector3d d_grp, dag, gvel2, vel2;
1530 RealType rgrpsq, rgrp;
1531 RealType vij(0.0);
1532 Vector3d fij, fg;
1533 bool in_switching_region;
1534 RealType dswdr, swderiv;
1535 vector<int> atomListColumn, atomListRow;
1536
1537 potVec longRangePotential(0.0);
1538 potVec selfPotential(0.0);
1539 potVec selectionPotential(0.0);
1540 RealType reciprocalPotential(0.0);
1541 RealType surfacePotential(0.0);
1542
1543 RealType mf;
1544 bool newAtom1;
1545 int gid1, gid2;
1546
1547 vector<int>::iterator ia, jb;
1548
1549 int loopStart, loopEnd;
1550
1551 idat.rcut = rCut_;
1552 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ? true : false;
1553 idat.shiftedForce =
1554 (cutoffMethod_ == SHIFTED_FORCE || cutoffMethod_ == TAYLOR_SHIFTED) ?
1555 true :
1556 false;
1557 idat.doParticlePot = doParticlePot_;
1558 idat.doElectricField = doElectricField_;
1559 idat.doSitePotential = doSitePotential_;
1560 sdat.doParticlePot = doParticlePot_;
1561
1562 loopEnd = PAIR_LOOP;
1563 if (info_->requiresPrepair()) {
1564 loopStart = PREPAIR_LOOP;
1565 } else {
1566 loopStart = PAIR_LOOP;
1567 }
1568 for (int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
1569 if (iLoop == loopStart) {
1570 bool update_nlist = fDecomp_->checkNeighborList(savedPositions_);
1571
1572 if (update_nlist) {
1573 if (!usePeriodicBoundaryConditions_)
1574 Mat3x3d bbox = thermo->getBoundingBox();
1575 fDecomp_->buildNeighborList(neighborList_, point_, savedPositions_);
1576 }
1577 }
1578
1579 for (cg1 = 0; cg1 < int(point_.size()) - 1; cg1++) {
1580 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
1581 newAtom1 = true;
1582
1583 for (int m2 = point_[cg1]; m2 < point_[cg1 + 1]; m2++) {
1584 cg2 = neighborList_[m2];
1585
1586 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
1587
1588 // already wrapped in the getIntergroupVector call:
1589 // curSnapshot->wrapVector(d_grp);
1590 rgrpsq = d_grp.lengthSquare();
1591
1592 if (rgrpsq < rCutSq_) {
1593 if (iLoop == PAIR_LOOP) {
1594 vij = 0.0;
1595 fij.zero();
1596 idat.eField1.zero();
1597 idat.eField2.zero();
1598 idat.sPot1 = 0.0;
1599 idat.sPot2 = 0.0;
1600 }
1601
1602 in_switching_region =
1603 switcher_->getSwitch(rgrpsq, idat.sw, dswdr, rgrp);
1604
1605 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
1606
1607 if (doHeatFlux_) gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
1608
1609 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
1610 if (atomListRow.size() > 1) newAtom1 = true;
1611 atom1 = (*ia);
1612
1613 if (doPotentialSelection_) {
1614 gid1 = fDecomp_->getGlobalIDRow(atom1);
1615 idat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1616 }
1617
1618 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
1619 ++jb) {
1620 atom2 = (*jb);
1621
1622 if (doPotentialSelection_) {
1623 gid2 = fDecomp_->getGlobalIDCol(atom2);
1624 idat.isSelected |= seleMan_.isGlobalIDSelected(gid2);
1625 }
1626
1627 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
1628 idat.vpair = 0.0;
1629 idat.pot = 0.0;
1630 idat.excludedPot = 0.0;
1631 idat.selePot = 0.0;
1632 idat.f1.zero();
1633 idat.dVdFQ1 = 0.0;
1634 idat.dVdFQ2 = 0.0;
1635
1636 fDecomp_->fillInteractionData(idat, atom1, atom2, newAtom1);
1637 newAtom1 = false;
1638
1639 idat.topoDist =
1640 fDecomp_->getTopologicalDistance(atom1, atom2);
1641 idat.vdwMult = vdwScale_[idat.topoDist];
1642 idat.electroMult = electrostaticScale_[idat.topoDist];
1643
1644 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
1645 idat.d = d_grp;
1646 idat.r2 = rgrpsq;
1647 if (doHeatFlux_) vel2 = gvel2;
1648 } else {
1649 idat.d = fDecomp_->getInteratomicVector(atom1, atom2);
1650 curSnapshot->wrapVector(idat.d);
1651 idat.r2 = idat.d.lengthSquare();
1652 if (doHeatFlux_)
1653 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
1654 }
1655
1656 idat.rij = sqrt(idat.r2);
1657
1658 if (iLoop == PREPAIR_LOOP) {
1659 interactionMan_->doPrePair(idat);
1660 fDecomp_->unpackPrePairData(idat, atom1, atom2);
1661 } else {
1662 interactionMan_->doPair(idat);
1663 fDecomp_->unpackInteractionData(idat, atom1, atom2);
1664 vij += idat.vpair;
1665 fij += idat.f1;
1666 virialTensor -= outProduct(idat.d, idat.f1);
1667 if (doHeatFlux_)
1668 fDecomp_->addToHeatFlux(idat.d * dot(idat.f1, vel2));
1669 }
1670 }
1671 }
1672 }
1673
1674 if (iLoop == PAIR_LOOP) {
1675 if (in_switching_region) {
1676 swderiv = vij * dswdr / rgrp;
1677 fg = swderiv * d_grp;
1678 fij += fg;
1679
1680 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
1681 if (!fDecomp_->skipAtomPair(atomListRow[0], atomListColumn[0],
1682 cg1, cg2)) {
1683 virialTensor -= outProduct(idat.d, fg);
1684 if (doHeatFlux_)
1685 fDecomp_->addToHeatFlux(idat.d * dot(fg, vel2));
1686 }
1687 }
1688
1689 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
1690 atom1 = (*ia);
1691 mf = fDecomp_->getMassFactorRow(atom1);
1692 // fg is the force on atom ia due to cutoff group's
1693 // presence in switching region
1694 fg = swderiv * d_grp * mf;
1695 fDecomp_->addForceToAtomRow(atom1, fg);
1696 if (atomListRow.size() > 1) {
1697 if (info_->usesAtomicVirial()) {
1698 // find the distance between the atom
1699 // and the center of the cutoff group:
1700 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
1701 virialTensor -= outProduct(dag, fg);
1702 if (doHeatFlux_)
1703 fDecomp_->addToHeatFlux(dag * dot(fg, vel2));
1704 }
1705 }
1706 }
1707 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
1708 ++jb) {
1709 atom2 = (*jb);
1710 mf = fDecomp_->getMassFactorColumn(atom2);
1711 // fg is the force on atom jb due to cutoff group's
1712 // presence in switching region
1713 fg = -swderiv * d_grp * mf;
1714 fDecomp_->addForceToAtomColumn(atom2, fg);
1715
1716 if (atomListColumn.size() > 1) {
1717 if (info_->usesAtomicVirial()) {
1718 // find the distance between the atom
1719 // and the center of the cutoff group:
1720 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
1721 virialTensor -= outProduct(dag, fg);
1722 if (doHeatFlux_)
1723 fDecomp_->addToHeatFlux(dag * dot(fg, vel2));
1724 }
1725 }
1726 }
1727 }
1728 // if (!info_->usesAtomicVirial()) {
1729 // virialTensor -= outProduct(d_grp, fij);
1730 // if (doHeatFlux_)
1731 // fDecomp_->addToHeatFlux( d_grp * dot(fij, vel2));
1732 //}
1733 }
1734 }
1735 }
1736 }
1737
1738 if (iLoop == PREPAIR_LOOP) {
1739 if (info_->requiresPrepair()) {
1740 fDecomp_->collectIntermediateData();
1741
1742 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1743 if (doPotentialSelection_) {
1744 gid1 = fDecomp_->getGlobalID(atom1);
1745 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1746 }
1747
1748 fDecomp_->fillPreForceData(sdat, atom1);
1749 interactionMan_->doPreForce(sdat);
1750 fDecomp_->unpackPreForceData(sdat, atom1);
1751 }
1752
1753 fDecomp_->distributeIntermediateData();
1754 }
1755 }
1756 }
1757
1758 // collects pairwise information
1759 fDecomp_->collectData();
1760 if (cutoffMethod_ == EWALD_FULL) {
1761 interactionMan_->doReciprocalSpaceSum(reciprocalPotential);
1762 curSnapshot->setReciprocalPotential(reciprocalPotential);
1763 }
1764
1765 if (useSurfaceTerm_) {
1766 interactionMan_->doSurfaceTerm(useSlabGeometry_, axis_, surfacePotential);
1767 curSnapshot->setSurfacePotential(surfacePotential);
1768 }
1769
1770 if (info_->requiresSelfCorrection()) {
1771 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1772 if (doPotentialSelection_) {
1773 gid1 = fDecomp_->getGlobalID(atom1);
1774 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1775 }
1776
1777 fDecomp_->fillSelfData(sdat, atom1);
1778 interactionMan_->doSelfCorrection(sdat);
1779 fDecomp_->unpackSelfData(sdat, atom1);
1780 }
1781 }
1782
1783 // collects single-atom information
1784 fDecomp_->collectSelfData();
1785
1786 longRangePotential = fDecomp_->getPairwisePotential();
1787 curSnapshot->setLongRangePotentials(longRangePotential);
1788
1789 selfPotential = fDecomp_->getSelfPotential();
1790 curSnapshot->setSelfPotentials(selfPotential);
1791
1792 curSnapshot->setExcludedPotentials(fDecomp_->getExcludedSelfPotential() +
1793 fDecomp_->getExcludedPotential());
1794
1795 if (doPotentialSelection_) {
1796 selectionPotential = curSnapshot->getSelectionPotentials();
1797 selectionPotential += fDecomp_->getSelectedSelfPotential();
1798 selectionPotential += fDecomp_->getSelectedPotential();
1799 curSnapshot->setSelectionPotentials(selectionPotential);
1800 }
1801 }
1802
1803 void ForceManager::selectedPostCalculation(Molecule* mol1, Molecule* mol2) {
1804 for (auto& forceModifier : forceModifiers_)
1805 forceModifier->modifyForces();
1806
1807 // Modify the rigid bodies in response to the applied force modifications
1808 SimInfo::MoleculeIterator mi;
1809 Molecule::RigidBodyIterator rbIter;
1810 RigidBody* rb;
1811 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1812
1813 // Collect the atomic forces onto rigid bodies
1814 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1815 rb = mol1->nextRigidBody(rbIter)) {
1817 virialTensor += rbTau;
1818 }
1819
1820 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1821 rb = mol2->nextRigidBody(rbIter)) {
1823 virialTensor += rbTau;
1824 }
1825
1826#ifdef IS_MPI
1827 MPI_Allreduce(MPI_IN_PLACE, virialTensor.getArrayPointer(), 9, MPI_REALTYPE,
1828 MPI_SUM, MPI_COMM_WORLD);
1829#endif
1830 curSnapshot->setVirialTensor(virialTensor);
1831
1832 /*
1833 if (info_->getSimParams()->getUseLongRangeCorrections()) {
1834
1835 RealType vol = curSnapshot->getVolume();
1836 RealType Elrc(0.0);
1837 RealType Wlrc(0.0);
1838
1839 AtomTypeSet::iterator i;
1840 AtomTypeSet::iterator j;
1841
1842 RealType n_i, n_j;
1843 RealType rho_i, rho_j;
1844 pair<RealType, RealType> LRI;
1845
1846 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
1847 n_i = RealType(info_->getGlobalCountOfType(*i));
1848 rho_i = n_i / vol;
1849 for (j = atomTypes_.begin(); j != atomTypes_.end(); ++j) {
1850 n_j = RealType(info_->getGlobalCountOfType(*j));
1851 rho_j = n_j / vol;
1852
1853 LRI = interactionMan_->getLongRangeIntegrals( (*i), (*j) );
1854
1855 Elrc += n_i * rho_j * LRI.first;
1856 Wlrc -= rho_i * rho_j * LRI.second;
1857 }
1858 }
1859 Elrc *= 2.0 * Constants::PI;
1860 Wlrc *= 2.0 * Constants::PI;
1861
1862 RealType lrp = curSnapshot->getLongRangePotential();
1863 curSnapshot->setLongRangePotential(lrp + Elrc);
1864 virialTensor += Wlrc * SquareMatrix3<RealType>::identity();
1865 curSnapshot->setVirialTensor(virialTensor);
1866 }
1867 */
1868 }
1869} // namespace OpenMD
Rotating Electric Field perturbation.
Uniform Magnetic Field perturbation.
Uniform Electric Field perturbation.
Uniform Electric Field Gradient perturbation.
virtual void calcForce(RealType &angle, bool doParticlePot)
Definition Bend.cpp:56
vector< Vector3d > velocity
position array
virtual void setupCutoffs()
setupCutoffs
SwitchingFunctionType sft_
Type of switching function in use.
RealType rCut_
cutoff radius for non-bonded interactions
CutoffMethod cutoffMethod_
Cutoff Method for most non-bonded interactions.
RealType rSwitch_
inner radius of switching function
InteractionManager is responsible for keeping track of the non-bonded interactions (C++)
Force modifier for Langevin Dynamics applying friction and random forces as well as torques.
Force modifier for NPT Langevin Hull Dynamics applying friction and random forces as well as torques.
Applies a uniform (vector) magnetic field to the system.
Applies an EM field representing light to the system.
Definition Light.hpp:104
Real * getArrayPointer()
Returns the pointer of internal array.
void updateAtoms()
update the positions of atoms belong to this rigidbody
Mat3x3d calcForcesAndTorquesAndVirial()
Converts Atomic forces and torques to total forces and torques and computes the rigid body contributi...
bool isDynamic()
Tests if the result from evaluation of script is dynamic.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:93
void setNZconstraint(int nZconstraint)
Sets the number of z-constraint molecules in the system.
Definition SimInfo.hpp:245
Molecule * beginMolecule(MoleculeIterator &i)
Returns the first molecule in this SimInfo and intialize the iterator.
Definition SimInfo.cpp:240
unsigned int getNAtoms()
Returns the number of local atoms.
Definition SimInfo.hpp:172
void prepareTopology()
Do final bookkeeping before Force managers need their data.
Definition SimInfo.cpp:897
int getNGlobalAtoms()
Returns the total number of atoms in the system.
Definition SimInfo.hpp:129
unsigned int getNCutoffGroups()
Returns the number of local cutoff groups.
Definition SimInfo.hpp:195
void update()
update
Definition SimInfo.cpp:697
Molecule * nextMolecule(MoleculeIterator &i)
Returns the next avaliable Molecule based on the iterator.
Definition SimInfo.cpp:245
SnapshotManager * getSnapshotManager()
Returns the snapshot manager.
Definition SimInfo.hpp:248
int getNGlobalCutoffGroups()
Returns the total number of cutoff groups in the system.
Definition SimInfo.hpp:132
AtomTypeSet getSimulatedAtomTypes()
Returns the set of atom types present in this simulation.
Definition SimInfo.cpp:712
The Snapshot class is a repository storing dynamic data during a Simulation.
Definition Snapshot.hpp:147
void wrapVector(Vector3d &v)
Wrapping the vector according to periodic boundary condition.
Definition Snapshot.cpp:337
Snapshot * getCurrentSnapshot()
Returns the pointer of current snapshot.
void zeroForcesAndTorques()
Set the properties of this stuntDouble to zero.
Mat3x3d getBoundingBox()
Returns the Axis-aligned bounding box for the current system.
Definition Thermo.cpp:980
Applies a uniform (vector) electric field to the system.
Applies a uniform electric field gradient to the system.
void zero()
Zeros out the values in this vector in place.
Definition Vector.hpp:194
Real lengthSquare()
Returns the squared length of this vector.
Definition Vector.hpp:399
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.
@ BONDED_FAMILY
directly bonded 1-2, 1-3, or 1-4 interactions
bool shiftedPot
shift the potential up inside the cutoff?
Vector3d d
interatomic vector (already wrapped into box)
RealType sPot2
site potential on second atom
RealType dVdFQ1
fluctuating charge force on atom1
RealType dVdFQ2
fluctuating charge force on atom2
RealType electroMult
multiplier for electrostatic interactions
potVec selePot
potential energies of the selected sites
RealType sw
switching function value at rij
Vector3d eField1
electric field on first atom
bool isSelected
one of the particles has been selected for selection potential
bool doElectricField
should we bother with the electric field?
Vector3d eField2
electric field on second atom
RealType vpair
pair potential
RealType sPot1
site potential on first atom
bool doSitePotential
should we bother with electrostatic site potential
bool shiftedForce
shifted forces smoothly inside the cutoff?
int topoDist
topological distance between atoms
RealType rcut
cutoff radius for this interaction
potVec excludedPot
potential energy excluded from the overall calculation
RealType vdwMult
multiplier for van der Waals interactions
bool doParticlePot
should we bother with the particle pot?
Vector3d f1
force between the two atoms
RealType rij
interatomic separation
bool isSelected
this site has been selected for selection potential
bool doParticlePot
should we bother with the particle pot?