63#include "constraints/ZconstraintForceModifier.hpp"
64#include "integrators/LDForceModifier.hpp"
66#include "integrators/LangevinHullForceModifier.hpp"
67#include "nonbonded/NonBondedInteraction.hpp"
68#include "parallel/ForceMatrixDecomposition.hpp"
70#include "perturbations/LightParameters.hpp"
79#include "restraints/RestraintForceModifier.hpp"
80#include "restraints/ThermoIntegrationForceModifier.hpp"
82#include "utils/simError.h"
87 ForceManager::ForceManager(
SimInfo* info) :
88 initialized_(false), info_(info), switcher_(NULL), seleMan_(info),
90 forceField_ = info_->getForceField();
91 interactionMan_ =
new InteractionManager();
92 fDecomp_ =
new ForceMatrixDecomposition(info_, interactionMan_);
93 thermo =
new Thermo(info_);
96 ForceManager::~ForceManager() {
97 Utils::deletePointers(forceModifiers_);
100 delete interactionMan_;
133 Globals* simParams_ = info_->getSimParams();
137 if (simParams_->haveMDfileVersion())
138 mdFileVersion = simParams_->getMDfileVersion();
145 AtomTypeSet::iterator i;
146 AtomTypeSet atomTypes_;
147 atomTypes_ = info_->getSimulatedAtomTypes();
149 if (simParams_->haveCutoffRadius()) {
150 rCut_ = simParams_->getCutoffRadius();
152 if (info_->usesElectrostaticAtoms()) {
153 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
154 "ForceManager::setupCutoffs: No value was set for the "
156 "\tOpenMD will use a default value of 12.0 angstroms "
157 "for the cutoffRadius.\n");
158 painCave.isFatal = 0;
159 painCave.severity = OPENMD_INFO;
164 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
165 thisCut = interactionMan_->getSuggestedCutoffRadius((*i));
168 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
169 "ForceManager::setupCutoffs: No value was set for the "
171 "\tOpenMD will use %lf angstroms.\n",
173 painCave.isFatal = 0;
174 painCave.severity = OPENMD_INFO;
179 fDecomp_->setCutoffRadius(
rCut_);
180 interactionMan_->setCutoffRadius(
rCut_);
183 map<string, CutoffMethod> stringToCutoffMethod;
184 stringToCutoffMethod[
"HARD"] = HARD;
185 stringToCutoffMethod[
"SWITCHED"] = SWITCHED;
186 stringToCutoffMethod[
"SHIFTED_POTENTIAL"] = SHIFTED_POTENTIAL;
187 stringToCutoffMethod[
"SHIFTED_FORCE"] = SHIFTED_FORCE;
188 stringToCutoffMethod[
"TAYLOR_SHIFTED"] = TAYLOR_SHIFTED;
189 stringToCutoffMethod[
"EWALD_FULL"] = EWALD_FULL;
191 if (simParams_->haveCutoffMethod()) {
192 string cutMeth = toUpperCopy(simParams_->getCutoffMethod());
193 map<string, CutoffMethod>::iterator i;
194 i = stringToCutoffMethod.find(cutMeth);
195 if (i == stringToCutoffMethod.end()) {
196 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
197 "ForceManager::setupCutoffs: Could not find chosen "
199 "\tShould be one of: "
200 "HARD, SWITCHED, SHIFTED_POTENTIAL, TAYLOR_SHIFTED,\n"
201 "\tSHIFTED_FORCE, or EWALD_FULL\n",
203 painCave.isFatal = 1;
204 painCave.severity = OPENMD_ERROR;
210 if (mdFileVersion > 1) {
211 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
212 "ForceManager::setupCutoffs: No value was set "
213 "for the cutoffMethod.\n"
214 "\tOpenMD will use SHIFTED_FORCE.\n");
215 painCave.isFatal = 0;
216 painCave.severity = OPENMD_INFO;
224 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
225 "ForceManager::setupCutoffs : DEPRECATED FILE FORMAT!\n"
226 "\tOpenMD found a file which does not set a cutoffMethod.\n"
227 "\tOpenMD will attempt to deduce a cutoffMethod using the\n"
228 "\tbehavior of the older (version 1) code. To remove this\n"
229 "\twarning, add an explicit cutoffMethod and change the top\n"
230 "\tof the file so that it begins with <OpenMD version=2>\n");
231 painCave.isFatal = 0;
232 painCave.severity = OPENMD_WARNING;
238 if (simParams_->haveElectrostaticSummationMethod()) {
239 string myMethod = simParams_->getElectrostaticSummationMethod();
242 if (myMethod ==
"SHIFTED_POTENTIAL") {
244 }
else if (myMethod ==
"SHIFTED_FORCE") {
246 }
else if (myMethod ==
"TAYLOR_SHIFTED") {
248 }
else if (myMethod ==
"EWALD_FULL") {
250 useSurfaceTerm_ =
true;
253 if (simParams_->haveSwitchingRadius())
254 rSwitch_ = simParams_->getSwitchingRadius();
256 if (myMethod ==
"SHIFTED_POTENTIAL" || myMethod ==
"SHIFTED_FORCE" ||
257 myMethod ==
"TAYLOR_SHIFTED" || myMethod ==
"EWALD_FULL") {
258 if (simParams_->haveSwitchingRadius()) {
259 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
260 "ForceManager::setupCutoffs : DEPRECATED ERROR MESSAGE\n"
261 "\tA value was set for the switchingRadius\n"
262 "\teven though the electrostaticSummationMethod was\n"
265 painCave.severity = OPENMD_WARNING;
266 painCave.isFatal = 1;
272 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
273 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
274 "\tcutoffRadius and switchingRadius are set to the\n"
275 "\tsame value. OpenMD will use shifted force\n"
276 "\tpotentials instead of switching functions.\n");
277 painCave.isFatal = 0;
278 painCave.severity = OPENMD_WARNING;
282 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
283 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
284 "\tcutoffRadius and switchingRadius are set to the\n"
285 "\tsame value. OpenMD will use shifted potentials\n"
286 "\tinstead of switching functions.\n");
287 painCave.isFatal = 0;
288 painCave.severity = OPENMD_WARNING;
301 if (simParams_->haveSwitchingRadius()) {
302 rSwitch_ = simParams_->getSwitchingRadius();
304 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
305 "ForceManager::setupCutoffs: switchingRadius (%f) is larger "
306 "than the cutoffRadius(%f)\n",
308 painCave.isFatal = 1;
309 painCave.severity = OPENMD_ERROR;
314 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
315 "ForceManager::setupCutoffs: No value was set for the "
317 "\tOpenMD will use a default value of 85 percent of the "
319 "\tswitchingRadius = %f. for this simulation\n",
321 painCave.isFatal = 0;
322 painCave.severity = OPENMD_WARNING;
326 if (mdFileVersion > 1) {
329 if (simParams_->haveSwitchingRadius()) {
330 map<string, CutoffMethod>::const_iterator it;
332 for (it = stringToCutoffMethod.begin();
333 it != stringToCutoffMethod.end(); ++it) {
339 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
340 "ForceManager::setupCutoffs: the cutoffMethod (%s)\n"
341 "\tis not set to SWITCHED, so switchingRadius value\n"
342 "\twill be ignored for this simulation\n",
344 painCave.isFatal = 0;
345 painCave.severity = OPENMD_WARNING;
354 if (simParams_->haveSwitchingFunctionType()) {
355 string funcType = simParams_->getSwitchingFunctionType();
357 if (funcType ==
"CUBIC") {
360 if (funcType ==
"FIFTH_ORDER_POLYNOMIAL") {
361 sft_ = fifth_order_poly;
365 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
366 "ForceManager::setupSwitching : Unknown switchingFunctionType. "
368 "file specified %s .)\n"
369 "\tswitchingFunctionType must be one of: "
370 "\"cubic\" or \"fifth_order_polynomial\".",
372 painCave.isFatal = 1;
373 painCave.severity = OPENMD_ERROR;
378 switcher_->setSwitchType(
sft_);
383 if (!info_->isTopologyDone()) {
385 interactionMan_->setSimInfo(info_);
386 interactionMan_->initialize();
388 useSurfaceTerm_ =
false;
389 useSlabGeometry_ =
false;
396 info_->prepareTopology();
398 doParticlePot_ = info_->getSimParams()->getOutputParticlePotential();
399 doHeatFlux_ = info_->getSimParams()->getPrintHeatFlux();
400 if (doHeatFlux_) doParticlePot_ =
true;
402 doElectricField_ = info_->getSimParams()->getOutputElectricField();
404 info_->getSimParams()->getRNEMDParameters()->requiresElectricField();
405 doSitePotential_ = info_->getSimParams()->getOutputSitePotential();
406 if (info_->getSimParams()->haveUseSurfaceTerm() &&
407 info_->getSimParams()->getUseSurfaceTerm()) {
408 if (info_->usesElectrostaticAtoms()) {
409 useSurfaceTerm_ = info_->getSimParams()->getUseSurfaceTerm();
410 if (info_->getSimParams()->haveUseSlabGeometry()) {
411 useSlabGeometry_ = info_->getSimParams()->getUseSlabGeometry();
414 toUpperCopy(info_->getSimParams()->getPrivilegedAxis());
415 if (axis.compare(
"X") == 0)
417 else if (axis.compare(
"Y") == 0)
423 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
424 "ForceManager::initialize : useSurfaceTerm was set true\n"
425 "\tbut no electrostatic atoms are present. OpenMD will\n"
426 "\tignore this setting.\n");
427 painCave.isFatal = 0;
428 painCave.severity = OPENMD_WARNING;
446 fill(vdwScale_.begin(), vdwScale_.end(), 0.0);
448 electrostaticScale_.resize(4);
449 fill(electrostaticScale_.begin(), electrostaticScale_.end(), 0.0);
452 vdwScale_[1] = fopts.getvdw12scale();
453 vdwScale_[2] = fopts.getvdw13scale();
454 vdwScale_[3] = fopts.getvdw14scale();
456 electrostaticScale_[0] = 1.0;
457 electrostaticScale_[1] = fopts.getelectrostatic12scale();
458 electrostaticScale_[2] = fopts.getelectrostatic13scale();
459 electrostaticScale_[3] = fopts.getelectrostatic14scale();
462 if (info_->getSimParams()->haveUniformField()) {
464 forceModifiers_.push_back(eField);
467 if (info_->getSimParams()->haveMagneticField()) {
469 forceModifiers_.push_back(mField);
472 if (info_->getSimParams()->haveUniformGradientStrength() ||
473 info_->getSimParams()->haveUniformGradientDirection1() ||
474 info_->getSimParams()->haveUniformGradientDirection2()) {
476 forceModifiers_.push_back(eGrad);
479 if (info_->getSimParams()->getLightParameters()->getUseLight()) {
481 forceModifiers_.push_back(light);
485 if (info_->getSimParams()->getUseThermodynamicIntegration()) {
488 forceModifiers_.push_back(thermoInt);
489 }
else if (info_->getSimParams()->getUseRestraints()) {
491 forceModifiers_.push_back(restraint);
494 std::string ensembleParam =
495 toUpperCopy(info_->getSimParams()->getEnsemble());
497 if (ensembleParam ==
"LHULL" || ensembleParam ==
"LANGEVINHULL" ||
498 ensembleParam ==
"SMIPD") {
499#if defined(HAVE_QHULL)
502 forceModifiers_.push_back(langevinHullFM);
505 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
506 "ForceManager: Cannot use the LangevinHull ensembles without qhull.\n"
507 "\tPlease rebuild OpenMD with qhull enabled.");
508 painCave.severity = OPENMD_ERROR;
509 painCave.isFatal = 1;
512 }
else if (ensembleParam ==
"LANGEVINDYNAMICS" || ensembleParam ==
"LD") {
514 forceModifiers_.push_back(langevinDynamicsFM);
515 }
else if (ensembleParam ==
"RPYDYNAMICS" || ensembleParam ==
"RPY"
516 || ensembleParam ==
"LHD" || ensembleParam ==
"LANGEVINHYDRODYNAMICS" ) {
518 forceModifiers_.push_back(lhdFM);
521 if (info_->getSimParams()->getNZconsStamps() > 0) {
522 info_->setNZconstraint(info_->getSimParams()->getNZconsStamps());
524 forceModifiers_.push_back(zCons);
527 usePeriodicBoundaryConditions_ =
528 info_->getSimParams()->getUsePeriodicBoundaryConditions();
530 fDecomp_->distributeInitialData();
532 doPotentialSelection_ =
false;
533 if (info_->getSimParams()->havePotentialSelection()) {
534 doPotentialSelection_ =
true;
535 selectionScript_ = info_->getSimParams()->getPotentialSelection();
536 evaluator_.loadScriptString(selectionScript_);
537 if (!evaluator_.isDynamic()) {
538 seleMan_.setSelectionSet(evaluator_.evaluate());
545 void ForceManager::calcForces() {
546 if (!initialized_) initialize();
549 shortRangeInteractions();
550 if (info_->getSimParams()->getSkipPairLoop() ==
false)
551 longRangeInteractions();
555 void ForceManager::preCalculation() {
556 SimInfo::MoleculeIterator mi;
558 Molecule::AtomIterator ai;
560 Molecule::RigidBodyIterator rbIter;
562 Molecule::CutoffGroupIterator ci;
568 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
570 fDecomp_->setSnapshot(snap);
572 snap->setBondPotential(0.0);
573 snap->setBendPotential(0.0);
574 snap->setTorsionPotential(0.0);
575 snap->setInversionPotential(0.0);
578 snap->setLongRangePotentials(zeroPot);
580 snap->setExcludedPotentials(zeroPot);
581 if (doPotentialSelection_) snap->setSelectionPotentials(zeroPot);
583 snap->setSelfPotentials(0.0);
584 snap->setRestraintPotential(0.0);
585 snap->setRawPotential(0.0);
587 for (mol = info_->beginMolecule(mi); mol != NULL;
588 mol = info_->nextMolecule(mi)) {
589 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
590 atom->zeroForcesAndTorques();
594 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
595 rb = mol->nextRigidBody(rbIter)) {
596 rb->zeroForcesAndTorques();
599 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
600 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
601 cg = mol->nextCutoffGroup(ci)) {
611 fDecomp_->setHeatFlux(Vector3d(0.0));
613 if (doPotentialSelection_) {
614 if (evaluator_.isDynamic()) {
615 seleMan_.setSelectionSet(evaluator_.evaluate());
620 void ForceManager::shortRangeInteractions() {
626 Inversion* inversion;
627 SimInfo::MoleculeIterator mi;
628 Molecule::RigidBodyIterator rbIter;
629 Molecule::BondIterator bondIter;
631 Molecule::BendIterator bendIter;
632 Molecule::TorsionIterator torsionIter;
633 Molecule::InversionIterator inversionIter;
634 RealType bondPotential = 0.0;
635 RealType bendPotential = 0.0;
636 RealType torsionPotential = 0.0;
637 RealType inversionPotential = 0.0;
638 potVec selectionPotential(0.0);
641 for (mol = info_->beginMolecule(mi); mol != NULL;
642 mol = info_->nextMolecule(mi)) {
644 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
645 rb = mol->nextRigidBody(rbIter)) {
649 for (bond = mol->beginBond(bondIter); bond != NULL;
650 bond = mol->nextBond(bondIter)) {
651 bond->calcForce(doParticlePot_);
652 bondPotential += bond->getPotential();
653 if (doPotentialSelection_) {
654 if (seleMan_.isSelected(bond->getAtomA()) ||
655 seleMan_.isSelected(bond->getAtomB())) {
661 for (bend = mol->beginBend(bendIter); bend != NULL;
662 bend = mol->nextBend(bendIter)) {
664 bend->calcForce(angle, doParticlePot_);
665 RealType currBendPot = bend->getPotential();
667 bendPotential += currBendPot;
668 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
669 if (i == bendDataSets.end()) {
671 dataSet.prev.angle = dataSet.curr.angle = angle;
672 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
673 dataSet.deltaV = 0.0;
675 map<Bend*, BendDataSet>::value_type(bend, dataSet));
677 i->second.prev.angle = i->second.curr.angle;
678 i->second.prev.potential = i->second.curr.potential;
679 i->second.curr.angle = angle;
680 i->second.curr.potential = currBendPot;
682 fabs(i->second.curr.potential - i->second.prev.potential);
684 if (doPotentialSelection_) {
685 if (seleMan_.isSelected(bend->getAtomA()) ||
686 seleMan_.isSelected(bend->getAtomB()) ||
687 seleMan_.isSelected(bend->getAtomC())) {
693 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
694 torsion = mol->nextTorsion(torsionIter)) {
696 torsion->calcForce(angle, doParticlePot_);
697 RealType currTorsionPot = torsion->getPotential();
698 torsionPotential += currTorsionPot;
699 map<Torsion*, TorsionDataSet>::iterator i =
700 torsionDataSets.find(torsion);
701 if (i == torsionDataSets.end()) {
702 TorsionDataSet dataSet;
703 dataSet.prev.angle = dataSet.curr.angle = angle;
704 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
705 dataSet.deltaV = 0.0;
706 torsionDataSets.insert(
707 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
709 i->second.prev.angle = i->second.curr.angle;
710 i->second.prev.potential = i->second.curr.potential;
711 i->second.curr.angle = angle;
712 i->second.curr.potential = currTorsionPot;
714 fabs(i->second.curr.potential - i->second.prev.potential);
716 if (doPotentialSelection_) {
717 if (seleMan_.isSelected(torsion->getAtomA()) ||
718 seleMan_.isSelected(torsion->getAtomB()) ||
719 seleMan_.isSelected(torsion->getAtomC()) ||
720 seleMan_.isSelected(torsion->getAtomD())) {
726 for (inversion = mol->beginInversion(inversionIter); inversion != NULL;
727 inversion = mol->nextInversion(inversionIter)) {
729 inversion->calcForce(angle, doParticlePot_);
730 RealType currInversionPot = inversion->getPotential();
731 inversionPotential += currInversionPot;
732 map<Inversion*, InversionDataSet>::iterator i =
733 inversionDataSets.find(inversion);
734 if (i == inversionDataSets.end()) {
735 InversionDataSet dataSet;
736 dataSet.prev.angle = dataSet.curr.angle = angle;
737 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
738 dataSet.deltaV = 0.0;
739 inversionDataSets.insert(
740 map<Inversion*, InversionDataSet>::value_type(inversion,
743 i->second.prev.angle = i->second.curr.angle;
744 i->second.prev.potential = i->second.curr.potential;
745 i->second.curr.angle = angle;
746 i->second.curr.potential = currInversionPot;
748 fabs(i->second.curr.potential - i->second.prev.potential);
750 if (doPotentialSelection_) {
751 if (seleMan_.isSelected(inversion->getAtomA()) ||
752 seleMan_.isSelected(inversion->getAtomB()) ||
753 seleMan_.isSelected(inversion->getAtomC()) ||
754 seleMan_.isSelected(inversion->getAtomD())) {
766 MPI_Allreduce(MPI_IN_PLACE, &bondPotential, 1, MPI_REALTYPE, MPI_SUM,
768 MPI_Allreduce(MPI_IN_PLACE, &bendPotential, 1, MPI_REALTYPE, MPI_SUM,
770 MPI_Allreduce(MPI_IN_PLACE, &torsionPotential, 1, MPI_REALTYPE, MPI_SUM,
772 MPI_Allreduce(MPI_IN_PLACE, &inversionPotential, 1, MPI_REALTYPE, MPI_SUM,
774 MPI_Allreduce(MPI_IN_PLACE, &selectionPotential[BONDED_FAMILY], 1,
775 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
778 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
779 fDecomp_->setSnapshot(curSnapshot);
781 curSnapshot->setBondPotential(bondPotential);
782 curSnapshot->setBendPotential(bendPotential);
783 curSnapshot->setTorsionPotential(torsionPotential);
784 curSnapshot->setInversionPotential(inversionPotential);
785 curSnapshot->setSelectionPotentials(selectionPotential);
793 void ForceManager::longRangeInteractions() {
794 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
795 fDecomp_->setSnapshot(curSnapshot);
797 DataStorage* config = &(curSnapshot->atomData);
798 DataStorage* cgConfig = &(curSnapshot->cgData);
802 SimInfo::MoleculeIterator mi;
804 Molecule::CutoffGroupIterator ci;
807 if (info_->getNCutoffGroups() != info_->getNAtoms()) {
808 for (mol = info_->beginMolecule(mi); mol != NULL;
809 mol = info_->nextMolecule(mi)) {
810 for (cg = mol->beginCutoffGroup(ci); cg != NULL;
811 cg = mol->nextCutoffGroup(ci)) {
818 cgConfig->position = config->position;
819 cgConfig->velocity = config->velocity;
822 fDecomp_->zeroWorkArrays();
823 fDecomp_->distributeData();
825 int cg1, cg2, atom1, atom2;
826 Vector3d d_grp, dag, gvel2, vel2;
827 RealType rgrpsq, rgrp;
829 Vector3d fij, fg, f1;
830 bool in_switching_region;
831 RealType dswdr, swderiv;
832 vector<int> atomListColumn, atomListRow;
834 potVec longRangePotential(0.0);
835 potVec selfPotential(0.0);
836 RealType reciprocalPotential(0.0);
837 RealType surfacePotential(0.0);
838 potVec selectionPotential(0.0);
844 vector<int>::iterator ia, jb;
846 int loopStart, loopEnd;
849 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ?
true : false;
851 (cutoffMethod_ == SHIFTED_FORCE || cutoffMethod_ == TAYLOR_SHIFTED) ?
854 idat.doParticlePot = doParticlePot_;
855 idat.doElectricField = doElectricField_;
856 idat.doSitePotential = doSitePotential_;
857 sdat.doParticlePot = doParticlePot_;
860 if (info_->requiresPrepair()) {
861 loopStart = PREPAIR_LOOP;
863 loopStart = PAIR_LOOP;
865 for (
int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
866 if (iLoop == loopStart) {
867 bool update_nlist = fDecomp_->checkNeighborList(savedPositions_);
870 if (!usePeriodicBoundaryConditions_)
871 Mat3x3d bbox = thermo->getBoundingBox();
872 fDecomp_->buildNeighborList(neighborList_, point_, savedPositions_);
876 for (cg1 = 0; cg1 < int(point_.size()) - 1; cg1++) {
877 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
880 for (
int m2 = point_[cg1]; m2 < point_[cg1 + 1]; m2++) {
881 cg2 = neighborList_[m2];
883 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
887 rgrpsq = d_grp.lengthSquare();
889 if (rgrpsq < rCutSq_) {
890 if (iLoop == PAIR_LOOP) {
899 in_switching_region =
900 switcher_->getSwitch(rgrpsq, idat.sw, dswdr, rgrp);
902 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
904 if (doHeatFlux_) gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
906 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
908 if (atomListRow.size() > 1) newAtom1 =
true;
910 if (doPotentialSelection_) {
911 gid1 = fDecomp_->getGlobalIDRow(atom1);
912 idat.isSelected = seleMan_.isGlobalIDSelected(gid1);
915 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
919 if (doPotentialSelection_) {
920 gid2 = fDecomp_->getGlobalIDCol(atom2);
921 idat.isSelected |= seleMan_.isGlobalIDSelected(gid2);
924 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
927 idat.excludedPot = 0.0;
933 fDecomp_->fillInteractionData(idat, atom1, atom2, newAtom1);
937 fDecomp_->getTopologicalDistance(atom1, atom2);
938 idat.vdwMult = vdwScale_[idat.topoDist];
939 idat.electroMult = electrostaticScale_[idat.topoDist];
941 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
944 if (doHeatFlux_) vel2 = gvel2;
946 idat.d = fDecomp_->getInteratomicVector(atom1, atom2);
947 curSnapshot->wrapVector(idat.d);
948 idat.r2 = idat.d.lengthSquare();
950 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
953 idat.rij = sqrt(idat.r2);
955 if (iLoop == PREPAIR_LOOP) {
956 interactionMan_->doPrePair(idat);
957 fDecomp_->unpackPrePairData(idat, atom1, atom2);
959 interactionMan_->doPair(idat);
960 fDecomp_->unpackInteractionData(idat, atom1, atom2);
963 virialTensor -= outProduct(idat.d, idat.f1);
965 fDecomp_->addToHeatFlux(idat.d *
dot(idat.f1, vel2));
971 if (iLoop == PAIR_LOOP) {
972 if (in_switching_region) {
973 swderiv = vij * dswdr / rgrp;
974 fg = swderiv * d_grp;
977 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
978 if (!fDecomp_->skipAtomPair(atomListRow[0], atomListColumn[0],
980 virialTensor -= outProduct(idat.d, fg);
982 fDecomp_->addToHeatFlux(idat.d *
dot(fg, vel2));
986 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
988 mf = fDecomp_->getMassFactorRow(atom1);
991 fg = swderiv * d_grp * mf;
992 fDecomp_->addForceToAtomRow(atom1, fg);
993 if (atomListRow.size() > 1) {
994 if (info_->usesAtomicVirial()) {
997 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
998 virialTensor -= outProduct(dag, fg);
1000 fDecomp_->addToHeatFlux(dag *
dot(fg, vel2));
1004 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
1007 mf = fDecomp_->getMassFactorColumn(atom2);
1010 fg = -swderiv * d_grp * mf;
1011 fDecomp_->addForceToAtomColumn(atom2, fg);
1013 if (atomListColumn.size() > 1) {
1014 if (info_->usesAtomicVirial()) {
1017 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
1018 virialTensor -= outProduct(dag, fg);
1020 fDecomp_->addToHeatFlux(dag *
dot(fg, vel2));
1035 if (iLoop == PREPAIR_LOOP) {
1036 if (info_->requiresPrepair()) {
1037 fDecomp_->collectIntermediateData();
1039 for (
unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1040 if (doPotentialSelection_) {
1041 gid1 = fDecomp_->getGlobalID(atom1);
1042 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1044 fDecomp_->fillPreForceData(sdat, atom1);
1045 interactionMan_->doPreForce(sdat);
1046 fDecomp_->unpackPreForceData(sdat, atom1);
1049 fDecomp_->distributeIntermediateData();
1055 fDecomp_->collectData();
1056 if (cutoffMethod_ == EWALD_FULL) {
1057 interactionMan_->doReciprocalSpaceSum(reciprocalPotential);
1058 curSnapshot->setReciprocalPotential(reciprocalPotential);
1061 if (useSurfaceTerm_) {
1062 interactionMan_->doSurfaceTerm(useSlabGeometry_, axis_, surfacePotential);
1063 curSnapshot->setSurfacePotential(surfacePotential);
1066 if (info_->requiresSelfCorrection()) {
1067 for (
unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1068 if (doPotentialSelection_) {
1069 gid1 = fDecomp_->getGlobalID(atom1);
1070 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1072 fDecomp_->fillSelfData(sdat, atom1);
1073 interactionMan_->doSelfCorrection(sdat);
1074 fDecomp_->unpackSelfData(sdat, atom1);
1079 fDecomp_->collectSelfData();
1081 longRangePotential = fDecomp_->getPairwisePotential();
1082 curSnapshot->setLongRangePotentials(longRangePotential);
1084 selfPotential = fDecomp_->getSelfPotential();
1085 curSnapshot->setSelfPotentials(selfPotential);
1087 curSnapshot->setExcludedPotentials(fDecomp_->getExcludedSelfPotential() +
1088 fDecomp_->getExcludedPotential());
1090 if (doPotentialSelection_) {
1091 selectionPotential = curSnapshot->getSelectionPotentials();
1092 selectionPotential += fDecomp_->getSelectedSelfPotential();
1093 selectionPotential += fDecomp_->getSelectedPotential();
1094 curSnapshot->setSelectionPotentials(selectionPotential);
1098 void ForceManager::postCalculation() {
1099 for (
auto& forceModifier : forceModifiers_)
1100 forceModifier->modifyForces();
1103 SimInfo::MoleculeIterator mi;
1105 Molecule::RigidBodyIterator rbIter;
1107 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1110 for (mol = info_->beginMolecule(mi); mol != NULL;
1111 mol = info_->nextMolecule(mi)) {
1112 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
1113 rb = mol->nextRigidBody(rbIter)) {
1114 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
1115 virialTensor += rbTau;
1120 MPI_Allreduce(MPI_IN_PLACE, virialTensor.getArrayPointer(), 9, MPI_REALTYPE,
1121 MPI_SUM, MPI_COMM_WORLD);
1123 curSnapshot->setVirialTensor(virialTensor);
1162 RealType pe = curSnapshot->getPotentialEnergy();
1163 if (std::isinf(pe) || std::isnan(pe)) {
1165 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
1166 "ForceManager detected a numerical error in the potential energy.\n"
1167 "\tStopping the simulation.");
1168 painCave.isFatal = 1;
1174 Molecule::IntegrableObjectIterator ii;
1177 for (mol = info_->beginMolecule(mi); mol != NULL;
1178 mol = info_->nextMolecule(mi)) {
1179 for (sd = mol->beginIntegrableObject(ii); sd != NULL;
1180 sd = mol->nextIntegrableObject(ii)) {
1182 if (std::isinf(f[0]) || std::isnan(f[0]) || std::isinf(f[1]) ||
1183 std::isnan(f[1]) || std::isinf(f[2]) || std::isnan(f[2])) {
1184 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
1185 "ForceManager detected a numerical error in the force"
1187 sd->getGlobalIndex());
1188 painCave.isFatal = 1;
1191 if (sd->isDirectional()) {
1193 if (std::isinf(t[0]) || std::isnan(t[0]) || std::isinf(t[1]) ||
1194 std::isnan(t[1]) || std::isinf(t[2]) || std::isnan(t[2])) {
1195 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
1196 "ForceManager detected a numerical error in the torque"
1198 sd->getGlobalIndex());
1199 painCave.isFatal = 1;
1208 void ForceManager::calcSelectedForces(Molecule* mol1, Molecule* mol2) {
1209 if (!initialized_) initialize();
1211 selectedPreCalculation(mol1, mol2);
1212 selectedShortRangeInteractions(mol1, mol2);
1213 selectedLongRangeInteractions(mol1, mol2);
1214 selectedPostCalculation(mol1, mol2);
1217 void ForceManager::selectedPreCalculation(Molecule* mol1, Molecule* mol2) {
1218 SimInfo::MoleculeIterator mi;
1219 Molecule::AtomIterator ai;
1221 Molecule::RigidBodyIterator rbIter;
1223 Molecule::CutoffGroupIterator ci;
1229 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1231 snap->setBondPotential(0.0);
1232 snap->setBendPotential(0.0);
1233 snap->setTorsionPotential(0.0);
1234 snap->setInversionPotential(0.0);
1236 potVec zeroPot(0.0);
1237 snap->setLongRangePotentials(zeroPot);
1238 snap->setExcludedPotentials(zeroPot);
1239 if (doPotentialSelection_) snap->setSelectionPotentials(zeroPot);
1241 snap->setRestraintPotential(0.0);
1242 snap->setRawPotential(0.0);
1245 for (atom = mol1->beginAtom(ai); atom != NULL; atom = mol1->nextAtom(ai)) {
1246 atom->zeroForcesAndTorques();
1249 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1250 rb = mol1->nextRigidBody(rbIter)) {
1251 rb->zeroForcesAndTorques();
1253 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
1254 for (cg = mol1->beginCutoffGroup(ci); cg != NULL;
1255 cg = mol1->nextCutoffGroup(ci)) {
1262 for (atom = mol2->beginAtom(ai); atom != NULL; atom = mol2->nextAtom(ai)) {
1263 atom->zeroForcesAndTorques();
1266 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1267 rb = mol2->nextRigidBody(rbIter)) {
1268 rb->zeroForcesAndTorques();
1270 if (info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()) {
1271 for (cg = mol2->beginCutoffGroup(ci); cg != NULL;
1272 cg = mol2->nextCutoffGroup(ci)) {
1279 virialTensor *= 0.0;
1281 fDecomp_->setHeatFlux(Vector3d(0.0));
1284 void ForceManager::selectedShortRangeInteractions(Molecule* mol1,
1290 Inversion* inversion;
1291 SimInfo::MoleculeIterator mi;
1292 Molecule::RigidBodyIterator rbIter;
1293 Molecule::BondIterator bondIter;
1294 Molecule::BendIterator bendIter;
1295 Molecule::TorsionIterator torsionIter;
1296 Molecule::InversionIterator inversionIter;
1297 RealType bondPotential = 0.0;
1298 RealType bendPotential = 0.0;
1299 RealType torsionPotential = 0.0;
1300 RealType inversionPotential = 0.0;
1301 potVec selectionPotential(0.0);
1304 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1305 rb = mol1->nextRigidBody(rbIter)) {
1309 for (bond = mol1->beginBond(bondIter); bond != NULL;
1310 bond = mol1->nextBond(bondIter)) {
1311 bond->calcForce(doParticlePot_);
1312 bondPotential += bond->getPotential();
1313 if (doPotentialSelection_) {
1314 if (seleMan_.isSelected(bond->getAtomA()) ||
1315 seleMan_.isSelected(bond->getAtomB())) {
1321 for (bend = mol1->beginBend(bendIter); bend != NULL;
1322 bend = mol1->nextBend(bendIter)) {
1324 bend->calcForce(angle, doParticlePot_);
1325 RealType currBendPot = bend->getPotential();
1327 bendPotential += bend->getPotential();
1328 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
1329 if (i == bendDataSets.end()) {
1330 BendDataSet dataSet;
1331 dataSet.prev.angle = dataSet.curr.angle = angle;
1332 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
1333 dataSet.deltaV = 0.0;
1334 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend, dataSet));
1336 i->second.prev.angle = i->second.curr.angle;
1337 i->second.prev.potential = i->second.curr.potential;
1338 i->second.curr.angle = angle;
1339 i->second.curr.potential = currBendPot;
1341 fabs(i->second.curr.potential - i->second.prev.potential);
1343 if (doPotentialSelection_) {
1344 if (seleMan_.isSelected(bend->getAtomA()) ||
1345 seleMan_.isSelected(bend->getAtomB()) ||
1346 seleMan_.isSelected(bend->getAtomC())) {
1352 for (torsion = mol1->beginTorsion(torsionIter); torsion != NULL;
1353 torsion = mol1->nextTorsion(torsionIter)) {
1355 torsion->calcForce(angle, doParticlePot_);
1356 RealType currTorsionPot = torsion->getPotential();
1357 torsionPotential += torsion->getPotential();
1358 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
1359 if (i == torsionDataSets.end()) {
1360 TorsionDataSet dataSet;
1361 dataSet.prev.angle = dataSet.curr.angle = angle;
1362 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
1363 dataSet.deltaV = 0.0;
1364 torsionDataSets.insert(
1365 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
1367 i->second.prev.angle = i->second.curr.angle;
1368 i->second.prev.potential = i->second.curr.potential;
1369 i->second.curr.angle = angle;
1370 i->second.curr.potential = currTorsionPot;
1372 fabs(i->second.curr.potential - i->second.prev.potential);
1374 if (doPotentialSelection_) {
1375 if (seleMan_.isSelected(torsion->getAtomA()) ||
1376 seleMan_.isSelected(torsion->getAtomB()) ||
1377 seleMan_.isSelected(torsion->getAtomC()) ||
1378 seleMan_.isSelected(torsion->getAtomD())) {
1379 selectionPotential[
BONDED_FAMILY] += torsion->getPotential();
1384 for (inversion = mol1->beginInversion(inversionIter); inversion != NULL;
1385 inversion = mol1->nextInversion(inversionIter)) {
1387 inversion->calcForce(angle, doParticlePot_);
1388 RealType currInversionPot = inversion->getPotential();
1389 inversionPotential += inversion->getPotential();
1390 map<Inversion*, InversionDataSet>::iterator i =
1391 inversionDataSets.find(inversion);
1392 if (i == inversionDataSets.end()) {
1393 InversionDataSet dataSet;
1394 dataSet.prev.angle = dataSet.curr.angle = angle;
1395 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
1396 dataSet.deltaV = 0.0;
1397 inversionDataSets.insert(
1398 map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
1400 i->second.prev.angle = i->second.curr.angle;
1401 i->second.prev.potential = i->second.curr.potential;
1402 i->second.curr.angle = angle;
1403 i->second.curr.potential = currInversionPot;
1405 fabs(i->second.curr.potential - i->second.prev.potential);
1407 if (doPotentialSelection_) {
1408 if (seleMan_.isSelected(inversion->getAtomA()) ||
1409 seleMan_.isSelected(inversion->getAtomB()) ||
1410 seleMan_.isSelected(inversion->getAtomC()) ||
1411 seleMan_.isSelected(inversion->getAtomD())) {
1412 selectionPotential[
BONDED_FAMILY] += inversion->getPotential();
1418 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1419 rb = mol2->nextRigidBody(rbIter)) {
1423 for (bond = mol2->beginBond(bondIter); bond != NULL;
1424 bond = mol2->nextBond(bondIter)) {
1425 bond->calcForce(doParticlePot_);
1426 bondPotential += bond->getPotential();
1427 if (doPotentialSelection_) {
1428 if (seleMan_.isSelected(bond->getAtomA()) ||
1429 seleMan_.isSelected(bond->getAtomB())) {
1435 for (bend = mol2->beginBend(bendIter); bend != NULL;
1436 bend = mol2->nextBend(bendIter)) {
1438 bend->calcForce(angle, doParticlePot_);
1439 RealType currBendPot = bend->getPotential();
1441 bendPotential += bend->getPotential();
1442 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
1443 if (i == bendDataSets.end()) {
1444 BendDataSet dataSet;
1445 dataSet.prev.angle = dataSet.curr.angle = angle;
1446 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
1447 dataSet.deltaV = 0.0;
1448 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend, dataSet));
1450 i->second.prev.angle = i->second.curr.angle;
1451 i->second.prev.potential = i->second.curr.potential;
1452 i->second.curr.angle = angle;
1453 i->second.curr.potential = currBendPot;
1455 fabs(i->second.curr.potential - i->second.prev.potential);
1457 if (doPotentialSelection_) {
1458 if (seleMan_.isSelected(bend->getAtomA()) ||
1459 seleMan_.isSelected(bend->getAtomB()) ||
1460 seleMan_.isSelected(bend->getAtomC())) {
1466 for (torsion = mol2->beginTorsion(torsionIter); torsion != NULL;
1467 torsion = mol2->nextTorsion(torsionIter)) {
1469 torsion->calcForce(angle, doParticlePot_);
1470 RealType currTorsionPot = torsion->getPotential();
1471 torsionPotential += torsion->getPotential();
1472 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
1473 if (i == torsionDataSets.end()) {
1474 TorsionDataSet dataSet;
1475 dataSet.prev.angle = dataSet.curr.angle = angle;
1476 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
1477 dataSet.deltaV = 0.0;
1478 torsionDataSets.insert(
1479 map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
1481 i->second.prev.angle = i->second.curr.angle;
1482 i->second.prev.potential = i->second.curr.potential;
1483 i->second.curr.angle = angle;
1484 i->second.curr.potential = currTorsionPot;
1486 fabs(i->second.curr.potential - i->second.prev.potential);
1488 if (doPotentialSelection_) {
1489 if (seleMan_.isSelected(torsion->getAtomA()) ||
1490 seleMan_.isSelected(torsion->getAtomB()) ||
1491 seleMan_.isSelected(torsion->getAtomC()) ||
1492 seleMan_.isSelected(torsion->getAtomD())) {
1493 selectionPotential[
BONDED_FAMILY] += torsion->getPotential();
1498 for (inversion = mol2->beginInversion(inversionIter); inversion != NULL;
1499 inversion = mol2->nextInversion(inversionIter)) {
1501 inversion->calcForce(angle, doParticlePot_);
1502 RealType currInversionPot = inversion->getPotential();
1503 inversionPotential += inversion->getPotential();
1504 map<Inversion*, InversionDataSet>::iterator i =
1505 inversionDataSets.find(inversion);
1506 if (i == inversionDataSets.end()) {
1507 InversionDataSet dataSet;
1508 dataSet.prev.angle = dataSet.curr.angle = angle;
1509 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
1510 dataSet.deltaV = 0.0;
1511 inversionDataSets.insert(
1512 map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
1514 i->second.prev.angle = i->second.curr.angle;
1515 i->second.prev.potential = i->second.curr.potential;
1516 i->second.curr.angle = angle;
1517 i->second.curr.potential = currInversionPot;
1519 fabs(i->second.curr.potential - i->second.prev.potential);
1521 if (doPotentialSelection_) {
1522 if (seleMan_.isSelected(inversion->getAtomA()) ||
1523 seleMan_.isSelected(inversion->getAtomB()) ||
1524 seleMan_.isSelected(inversion->getAtomC()) ||
1525 seleMan_.isSelected(inversion->getAtomD())) {
1526 selectionPotential[
BONDED_FAMILY] += inversion->getPotential();
1536 MPI_Allreduce(MPI_IN_PLACE, &bondPotential, 1, MPI_REALTYPE, MPI_SUM,
1538 MPI_Allreduce(MPI_IN_PLACE, &bendPotential, 1, MPI_REALTYPE, MPI_SUM,
1540 MPI_Allreduce(MPI_IN_PLACE, &torsionPotential, 1, MPI_REALTYPE, MPI_SUM,
1542 MPI_Allreduce(MPI_IN_PLACE, &inversionPotential, 1, MPI_REALTYPE, MPI_SUM,
1544 MPI_Allreduce(MPI_IN_PLACE, &selectionPotential[BONDED_FAMILY], 1,
1545 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1548 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1550 curSnapshot->setBondPotential(bondPotential);
1551 curSnapshot->setBendPotential(bendPotential);
1552 curSnapshot->setTorsionPotential(torsionPotential);
1553 curSnapshot->setInversionPotential(inversionPotential);
1554 curSnapshot->setSelectionPotentials(selectionPotential);
1562 void ForceManager::selectedLongRangeInteractions(Molecule* mol1,
1564 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1565 DataStorage* config = &(curSnapshot->atomData);
1566 DataStorage* cgConfig = &(curSnapshot->cgData);
1570 SimInfo::MoleculeIterator mi;
1571 Molecule::CutoffGroupIterator ci;
1574 if (info_->getNCutoffGroups() != info_->getNAtoms()) {
1575 for (cg = mol1->beginCutoffGroup(ci); cg != NULL;
1576 cg = mol1->nextCutoffGroup(ci)) {
1579 for (cg = mol2->beginCutoffGroup(ci); cg != NULL;
1580 cg = mol2->nextCutoffGroup(ci)) {
1586 cgConfig->position = config->position;
1587 cgConfig->velocity = config->velocity;
1590 fDecomp_->zeroWorkArrays();
1591 fDecomp_->distributeData();
1593 int cg1, cg2, atom1, atom2;
1594 Vector3d d_grp, dag, gvel2, vel2;
1595 RealType rgrpsq, rgrp;
1598 bool in_switching_region;
1599 RealType dswdr, swderiv;
1600 vector<int> atomListColumn, atomListRow;
1602 potVec longRangePotential(0.0);
1603 potVec selfPotential(0.0);
1604 potVec selectionPotential(0.0);
1605 RealType reciprocalPotential(0.0);
1606 RealType surfacePotential(0.0);
1612 vector<int>::iterator ia, jb;
1614 int loopStart, loopEnd;
1617 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ?
true : false;
1619 (cutoffMethod_ == SHIFTED_FORCE || cutoffMethod_ == TAYLOR_SHIFTED) ?
1622 idat.doParticlePot = doParticlePot_;
1623 idat.doElectricField = doElectricField_;
1624 idat.doSitePotential = doSitePotential_;
1625 sdat.doParticlePot = doParticlePot_;
1627 loopEnd = PAIR_LOOP;
1628 if (info_->requiresPrepair()) {
1629 loopStart = PREPAIR_LOOP;
1631 loopStart = PAIR_LOOP;
1633 for (
int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
1634 if (iLoop == loopStart) {
1635 bool update_nlist = fDecomp_->checkNeighborList(savedPositions_);
1638 if (!usePeriodicBoundaryConditions_)
1639 Mat3x3d bbox = thermo->getBoundingBox();
1640 fDecomp_->buildNeighborList(neighborList_, point_, savedPositions_);
1644 for (cg1 = 0; cg1 < int(point_.size()) - 1; cg1++) {
1645 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
1648 for (
int m2 = point_[cg1]; m2 < point_[cg1 + 1]; m2++) {
1649 cg2 = neighborList_[m2];
1651 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
1655 rgrpsq = d_grp.lengthSquare();
1657 if (rgrpsq < rCutSq_) {
1658 if (iLoop == PAIR_LOOP) {
1661 idat.eField1.zero();
1662 idat.eField2.zero();
1667 in_switching_region =
1668 switcher_->getSwitch(rgrpsq, idat.sw, dswdr, rgrp);
1670 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
1672 if (doHeatFlux_) gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
1674 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
1675 if (atomListRow.size() > 1) newAtom1 =
true;
1678 if (doPotentialSelection_) {
1679 gid1 = fDecomp_->getGlobalIDRow(atom1);
1680 idat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1683 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
1687 if (doPotentialSelection_) {
1688 gid2 = fDecomp_->getGlobalIDCol(atom2);
1689 idat.isSelected |= seleMan_.isGlobalIDSelected(gid2);
1692 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
1695 idat.excludedPot = 0.0;
1701 fDecomp_->fillInteractionData(idat, atom1, atom2, newAtom1);
1705 fDecomp_->getTopologicalDistance(atom1, atom2);
1706 idat.vdwMult = vdwScale_[idat.topoDist];
1707 idat.electroMult = electrostaticScale_[idat.topoDist];
1709 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
1712 if (doHeatFlux_) vel2 = gvel2;
1714 idat.d = fDecomp_->getInteratomicVector(atom1, atom2);
1715 curSnapshot->wrapVector(idat.d);
1716 idat.r2 = idat.d.lengthSquare();
1718 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
1721 idat.rij = sqrt(idat.r2);
1723 if (iLoop == PREPAIR_LOOP) {
1724 interactionMan_->doPrePair(idat);
1725 fDecomp_->unpackPrePairData(idat, atom1, atom2);
1727 interactionMan_->doPair(idat);
1728 fDecomp_->unpackInteractionData(idat, atom1, atom2);
1731 virialTensor -= outProduct(idat.d, idat.f1);
1733 fDecomp_->addToHeatFlux(idat.d *
dot(idat.f1, vel2));
1739 if (iLoop == PAIR_LOOP) {
1740 if (in_switching_region) {
1741 swderiv = vij * dswdr / rgrp;
1742 fg = swderiv * d_grp;
1745 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
1746 if (!fDecomp_->skipAtomPair(atomListRow[0], atomListColumn[0],
1748 virialTensor -= outProduct(idat.d, fg);
1750 fDecomp_->addToHeatFlux(idat.d *
dot(fg, vel2));
1754 for (ia = atomListRow.begin(); ia != atomListRow.end(); ++ia) {
1756 mf = fDecomp_->getMassFactorRow(atom1);
1759 fg = swderiv * d_grp * mf;
1760 fDecomp_->addForceToAtomRow(atom1, fg);
1761 if (atomListRow.size() > 1) {
1762 if (info_->usesAtomicVirial()) {
1765 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
1766 virialTensor -= outProduct(dag, fg);
1768 fDecomp_->addToHeatFlux(dag *
dot(fg, vel2));
1772 for (jb = atomListColumn.begin(); jb != atomListColumn.end();
1775 mf = fDecomp_->getMassFactorColumn(atom2);
1778 fg = -swderiv * d_grp * mf;
1779 fDecomp_->addForceToAtomColumn(atom2, fg);
1781 if (atomListColumn.size() > 1) {
1782 if (info_->usesAtomicVirial()) {
1785 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
1786 virialTensor -= outProduct(dag, fg);
1788 fDecomp_->addToHeatFlux(dag *
dot(fg, vel2));
1803 if (iLoop == PREPAIR_LOOP) {
1804 if (info_->requiresPrepair()) {
1805 fDecomp_->collectIntermediateData();
1807 for (
unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1808 if (doPotentialSelection_) {
1809 gid1 = fDecomp_->getGlobalID(atom1);
1810 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1813 fDecomp_->fillPreForceData(sdat, atom1);
1814 interactionMan_->doPreForce(sdat);
1815 fDecomp_->unpackPreForceData(sdat, atom1);
1818 fDecomp_->distributeIntermediateData();
1824 fDecomp_->collectData();
1825 if (cutoffMethod_ == EWALD_FULL) {
1826 interactionMan_->doReciprocalSpaceSum(reciprocalPotential);
1827 curSnapshot->setReciprocalPotential(reciprocalPotential);
1830 if (useSurfaceTerm_) {
1831 interactionMan_->doSurfaceTerm(useSlabGeometry_, axis_, surfacePotential);
1832 curSnapshot->setSurfacePotential(surfacePotential);
1835 if (info_->requiresSelfCorrection()) {
1836 for (
unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
1837 if (doPotentialSelection_) {
1838 gid1 = fDecomp_->getGlobalID(atom1);
1839 sdat.isSelected = seleMan_.isGlobalIDSelected(gid1);
1842 fDecomp_->fillSelfData(sdat, atom1);
1843 interactionMan_->doSelfCorrection(sdat);
1844 fDecomp_->unpackSelfData(sdat, atom1);
1849 fDecomp_->collectSelfData();
1851 longRangePotential = fDecomp_->getPairwisePotential();
1852 curSnapshot->setLongRangePotentials(longRangePotential);
1854 selfPotential = fDecomp_->getSelfPotential();
1855 curSnapshot->setSelfPotentials(selfPotential);
1857 curSnapshot->setExcludedPotentials(fDecomp_->getExcludedSelfPotential() +
1858 fDecomp_->getExcludedPotential());
1860 if (doPotentialSelection_) {
1861 selectionPotential = curSnapshot->getSelectionPotentials();
1862 selectionPotential += fDecomp_->getSelectedSelfPotential();
1863 selectionPotential += fDecomp_->getSelectedPotential();
1864 curSnapshot->setSelectionPotentials(selectionPotential);
1868 void ForceManager::selectedPostCalculation(Molecule* mol1, Molecule* mol2) {
1869 for (
auto& forceModifier : forceModifiers_)
1870 forceModifier->modifyForces();
1874 SimInfo::MoleculeIterator mi;
1875 Molecule::RigidBodyIterator rbIter;
1877 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
1880 for (rb = mol1->beginRigidBody(rbIter); rb != NULL;
1881 rb = mol1->nextRigidBody(rbIter)) {
1882 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
1883 virialTensor += rbTau;
1886 for (rb = mol2->beginRigidBody(rbIter); rb != NULL;
1887 rb = mol2->nextRigidBody(rbIter)) {
1888 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
1889 virialTensor += rbTau;
1893 MPI_Allreduce(MPI_IN_PLACE, virialTensor.getArrayPointer(), 9, MPI_REALTYPE,
1894 MPI_SUM, MPI_COMM_WORLD);
1896 curSnapshot->setVirialTensor(virialTensor);
Langevin force modifier with intramolecular RPY hydrodynamic interactions for flexible bead molecules...
Rotating Electric Field perturbation.
Uniform Magnetic Field perturbation.
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
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.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
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