47#include "integrators/LDForceModifier.hpp"
55#include "brains/ForceModifier.hpp"
56#include "hydrodynamics/Ellipsoid.hpp"
57#include "hydrodynamics/HydroIO.hpp"
58#include "hydrodynamics/Sphere.hpp"
59#include "math/CholeskyDecomposition.hpp"
61#include "types/GayBerneAdapter.hpp"
62#include "types/LennardJonesAdapter.hpp"
63#include "utils/Constants.hpp"
69 LDForceModifier::LDForceModifier(
SimInfo* info) :
70 ForceModifier {info}, maxIterNum_ {6}, forceTolerance_ {1e-6},
71 randNumGen_ {info->getRandomNumberGenerator()},
72 simParams_ {info->getSimParams()} {
73 RealType dt = simParams_->getDt();
76 veloMunge_ = std::make_unique<Velocitizer>(info_);
78 sphericalBoundaryConditions_ =
false;
79 if (simParams_->getUseSphericalBoundaryConditions()) {
80 sphericalBoundaryConditions_ =
true;
81 if (simParams_->haveLangevinBufferRadius()) {
82 langevinBufferRadius_ = simParams_->getLangevinBufferRadius();
84 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
85 "langevinBufferRadius must be specified "
86 "when useSphericalBoundaryConditions is turned on.\n");
87 painCave.severity = OPENMD_ERROR;
92 if (simParams_->haveFrozenBufferRadius()) {
93 frozenBufferRadius_ = simParams_->getFrozenBufferRadius();
95 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
96 "frozenBufferRadius must be specified "
97 "when useSphericalBoundaryConditions is turned on.\n");
98 painCave.severity = OPENMD_ERROR;
103 if (frozenBufferRadius_ < langevinBufferRadius_) {
104 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
105 "frozenBufferRadius has been set smaller than the "
106 "langevinBufferRadius. This is probably an error.\n");
107 painCave.severity = OPENMD_WARNING;
108 painCave.isFatal = 0;
116 SimInfo::MoleculeIterator i;
117 Molecule::IntegrableObjectIterator j;
118 bool needHydroPropFile =
false;
120 for (mol = info_->beginMolecule(i); mol != NULL;
121 mol = info_->nextMolecule(i)) {
122 for (sd = mol->beginIntegrableObject(j); sd != NULL;
123 sd = mol->nextIntegrableObject(j)) {
124 if (sd->isRigidBody()) {
125 RigidBody* rb =
static_cast<RigidBody*
>(sd);
126 if (rb->getNumAtoms() > 1) needHydroPropFile =
true;
131 if (needHydroPropFile) {
132 if (simParams_->haveHydroPropFile()) {
133 HydroIO* hio =
new HydroIO();
134 hydroPropMap_ = hio->parseHydroFile(simParams_->getHydroPropFile());
137 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
138 "HydroPropFile must be set to a file name if Langevin Dynamics\n"
139 "\tis specified for rigidBodies which contain more than one atom\n"
140 "\tTo create a HydroPropFile, run the \"Hydro\" program.\n");
141 painCave.severity = OPENMD_ERROR;
142 painCave.isFatal = 1;
146 for (mol = info_->beginMolecule(i); mol != NULL;
147 mol = info_->nextMolecule(i)) {
148 for (sd = mol->beginIntegrableObject(j); sd != NULL;
149 sd = mol->nextIntegrableObject(j)) {
150 map<string, HydroProp*>::iterator iter =
151 hydroPropMap_.find(sd->getType());
152 if (iter != hydroPropMap_.end()) {
153 hydroProps_.push_back(iter->second);
154 moments_.push_back(getMomentData(sd));
157 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
158 "Can not find resistance tensor for atom [%s]\n",
159 sd->getType().c_str());
160 painCave.severity = OPENMD_ERROR;
161 painCave.isFatal = 1;
168 for (mol = info_->beginMolecule(i); mol != NULL;
169 mol = info_->nextMolecule(i)) {
170 for (sd = mol->beginIntegrableObject(j); sd != NULL;
171 sd = mol->nextIntegrableObject(j)) {
172 Shape* currShape = NULL;
175 Atom* atom =
static_cast<Atom*
>(sd);
176 AtomType* atomType = atom->getAtomType();
177 GayBerneAdapter gba = GayBerneAdapter(atomType);
178 if (gba.isGayBerne()) {
179 currShape =
new Ellipsoid(V3Zero, gba.getL() / 2.0,
182 LennardJonesAdapter lja = LennardJonesAdapter(atomType);
183 if (lja.isLennardJones()) {
184 currShape =
new Sphere(V3Zero, lja.getSigma() / 2.0);
187 vector<AtomType*> atChain = atomType->allYourBase();
188 vector<AtomType*>::iterator i;
189 for (i = atChain.begin(); i != atChain.end(); ++i) {
192 currShape =
new Sphere(V3Zero, etab.
GetVdwRad(aNum));
197 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
198 "Could not find atom type in default element.txt\n");
199 painCave.severity = OPENMD_ERROR;
200 painCave.isFatal = 1;
207 if (!simParams_->haveTargetTemp()) {
208 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
209 "You can't use LangevinDynamics without a targetTemp!\n");
210 painCave.isFatal = 1;
211 painCave.severity = OPENMD_ERROR;
215 if (!simParams_->haveViscosity()) {
216 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
217 "You can't use LangevinDynamics without a viscosity!\n");
218 painCave.isFatal = 1;
219 painCave.severity = OPENMD_ERROR;
223 HydroProp* currHydroProp =
224 currShape->getHydroProp(simParams_->getViscosity());
225 map<string, HydroProp*>::iterator iter =
226 hydroPropMap_.find(sd->getType());
227 if (iter != hydroPropMap_.end()) {
228 hydroProps_.push_back(iter->second);
229 moments_.push_back(getMomentData(sd));
232 currHydroProp->complete();
233 hydroPropMap_.insert(map<string, HydroProp*>::value_type(
234 sd->getType(), currHydroProp));
235 hydroProps_.push_back(currHydroProp);
236 moments_.push_back(getMomentData(sd));
244 std::sqrt(2.0 * Constants::kb * simParams_->getTargetTemp() / dt);
246 forceDistribution_ = std::normal_distribution<RealType>(0.0, stdDev);
249 MomentData* LDForceModifier::getMomentData(StuntDouble* sd) {
250 map<string, MomentData*>::iterator j = momentsMap_.find(sd->getType());
251 if (j != momentsMap_.end()) {
254 MomentData* moment =
new MomentData;
255 map<string, HydroProp*>::iterator i = hydroPropMap_.find(sd->getType());
257 if (i != hydroPropMap_.end()) {
259 moment->rcr = i->second->getCenterOfResistance();
262 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
263 "LDForceManager createMomentData: Couldn't find HydroProp for\n"
265 sd->getType().c_str());
266 painCave.isFatal = 1;
267 painCave.severity = OPENMD_ERROR;
271 if (sd->isRigidBody())
272 moment->rcr -=
dynamic_cast<RigidBody*
>(sd)->getRefCOM();
276 RealType mass = sd->getMass();
277 moment->Icr = sd->getI();
280 outProduct(moment->rcr, moment->rcr));
281 moment->IcrInv = moment->Icr.inverse();
284 map<string, MomentData*>::value_type(sd->getType(), moment));
289 void LDForceModifier::modifyForces() {
290 SimInfo::MoleculeIterator i;
291 Molecule::IntegrableObjectIterator j;
301 unsigned int index = 0;
302 bool doLangevinForces;
308 for (mol = info_->beginMolecule(i); mol != NULL;
309 mol = info_->nextMolecule(i)) {
310 doLangevinForces =
true;
311 freezeMolecule =
false;
313 if (sphericalBoundaryConditions_) {
314 Vector3d molPos = mol->getCom();
315 RealType molRad = molPos.
length();
317 doLangevinForces =
false;
319 if (molRad > langevinBufferRadius_) {
320 doLangevinForces =
true;
321 freezeMolecule =
false;
323 if (molRad > frozenBufferRadius_) {
324 doLangevinForces =
false;
325 freezeMolecule =
true;
329 for (sd = mol->beginIntegrableObject(j); sd != NULL;
330 sd = mol->nextIntegrableObject(j)) {
331 if (freezeMolecule) fdf += sd->freeze();
333 if (doLangevinForces) {
334 mass = sd->getMass();
335 if (sd->isDirectional()) {
339 Atrans = A.transpose();
341 Vector3d rcrLab = Atrans * moments_[index]->rcr;
345 Vector3d randomForceBody;
346 Vector3d randomTorqueBody;
347 genRandomForceAndTorque(randomForceBody, randomTorqueBody, index);
348 Vector3d randomForceLab = Atrans * randomForceBody;
349 Vector3d randomTorqueLab = Atrans * randomTorqueBody;
351 sd->addFrc(randomForceLab);
352 sd->addTrq(randomTorqueLab +
cross(rcrLab, randomForceLab));
364 Vector3d vel = sd->getVel();
365 Vector3d angMom = sd->getJ();
373 vel + (dt2_ / mass * Constants::energyConvert) * frc;
375 Tb = sd->lab2Body(sd->getTrq());
376 Vector3d angMomStep =
377 angMom + (dt2_ * Constants::energyConvert) * Tb;
382 Vector3d frictionForceBody;
383 Vector3d frictionForceLab(0.0);
385 Vector3d frictionTorqueBody(0.0);
387 Vector3d frictionTorqueLab;
393 for (
int k = 0; k < maxIterNum_; k++) {
394 if (sd->isLinear()) {
395 int linearAxis = sd->linearAxis();
396 int l = (linearAxis + 1) % 3;
397 int m = (linearAxis + 2) % 3;
398 omegaBody[l] = angMomStep[l] / moments_[index]->Icr(l, l);
399 omegaBody[m] = angMomStep[m] / moments_[index]->Icr(m, m);
402 omegaBody = moments_[index]->IcrInv * angMomStep;
408 omegaLab = Atrans * omegaBody;
412 vcdLab = velStep +
cross(omegaLab, rcrLab);
413 vcdBody = A * vcdLab;
414 frictionForceBody = -(hydroProps_[index]->getXitt() * vcdBody +
415 hydroProps_[index]->getXirt() * omegaBody);
416 oldFFL = frictionForceLab;
417 frictionForceLab = Atrans * frictionForceBody;
418 oldFTB = frictionTorqueBody;
419 frictionTorqueBody = -(hydroProps_[index]->getXitr() * vcdBody +
420 hydroProps_[index]->getXirr() * omegaBody);
421 frictionTorqueLab = Atrans * frictionTorqueBody;
425 velStep = vel + (dt2_ / mass * Constants::energyConvert) *
426 (frc + frictionForceLab);
427 angMomStep = angMom + (dt2_ * Constants::energyConvert) *
428 (Tb + frictionTorqueBody);
433 fdot =
dot(frictionForceLab, oldFFL) /
434 frictionForceLab.lengthSquare();
435 tdot =
dot(frictionTorqueBody, oldFTB) /
436 frictionTorqueBody.lengthSquare();
438 if (fabs(1.0 - fdot) <= forceTolerance_ &&
439 fabs(1.0 - tdot) <= forceTolerance_)
443 sd->addFrc(frictionForceLab);
444 sd->addTrq(frictionTorqueLab +
cross(rcrLab, frictionForceLab));
449 Vector3d systemForce;
450 Vector3d randomForce;
451 Vector3d randomTorque;
452 genRandomForceAndTorque(randomForce, randomTorque, index);
453 systemForce = sd->getFrc();
454 sd->addFrc(randomForce);
464 Vector3d vel = sd->getVel();
471 vel + (dt2_ / mass * Constants::energyConvert) * frc;
473 Vector3d frictionForce(0.0);
479 for (
int k = 0; k < maxIterNum_; k++) {
480 oldFF = frictionForce;
481 frictionForce = -hydroProps_[index]->getXitt() * velStep;
485 velStep = vel + (dt2_ / mass * Constants::energyConvert) *
486 (frc + frictionForce);
491 fdot =
dot(frictionForce, oldFF) / frictionForce.lengthSquare();
493 if (fabs(1.0 - fdot) <= forceTolerance_)
497 sd->addFrc(frictionForce);
506 if (simParams_->getConserveLinearMomentum()) veloMunge_->removeComDrift();
508 if (!simParams_->getUsePeriodicBoundaryConditions() &&
509 simParams_->getConserveAngularMomentum())
510 veloMunge_->removeAngularDrift();
513 void LDForceModifier::genRandomForceAndTorque(Vector3d& force,
515 unsigned int index) {
516 Vector<RealType, 6> Z;
517 Vector<RealType, 6> generalForce;
519 Z[0] = forceDistribution_(*randNumGen_);
520 Z[1] = forceDistribution_(*randNumGen_);
521 Z[2] = forceDistribution_(*randNumGen_);
522 Z[3] = forceDistribution_(*randNumGen_);
523 Z[4] = forceDistribution_(*randNumGen_);
524 Z[5] = forceDistribution_(*randNumGen_);
526 generalForce = hydroProps_[index]->getS() * Z;
528 force[0] = generalForce[0];
529 force[1] = generalForce[1];
530 force[2] = generalForce[2];
531 torque[0] = generalForce[3];
532 torque[1] = generalForce[4];
533 torque[2] = generalForce[5];
This basic Periodic Table class was originally taken from the data.h file in OpenBabel.
RealType GetVdwRad(int atomicnum)
int GetAtomicNum(const char *str)
Abstract class for external ForceModifier classes.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
static SquareMatrix< Real, Dim > identity()
Returns an identity matrix.
Real length() const
Returns the length of this vector.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
Vector3< Real > cross(const Vector3< Real > &v1, const Vector3< Real > &v2)
Returns the cross product of two Vectors.
Real dot(const DynamicVector< Real > &v1, const DynamicVector< Real > &v2)
Returns the dot product of two DynamicVectors.