44#include "integrators/LDForceModifier.hpp"
52#include "brains/ForceModifier.hpp"
53#include "hydrodynamics/Ellipsoid.hpp"
54#include "hydrodynamics/HydroIO.hpp"
55#include "hydrodynamics/Sphere.hpp"
56#include "math/CholeskyDecomposition.hpp"
58#include "types/GayBerneAdapter.hpp"
59#include "types/LennardJonesAdapter.hpp"
60#include "utils/Constants.hpp"
66 LDForceModifier::LDForceModifier(SimInfo* info) :
67 ForceModifier {info}, maxIterNum_ {6}, forceTolerance_ {1e-6},
68 randNumGen_ {info->getRandomNumberGenerator()},
69 simParams_ {info->getSimParams()} {
70 RealType dt = simParams_->getDt();
73 veloMunge_ = std::make_unique<Velocitizer>(info_);
75 sphericalBoundaryConditions_ =
false;
76 if (simParams_->getUseSphericalBoundaryConditions()) {
77 sphericalBoundaryConditions_ =
true;
78 if (simParams_->haveLangevinBufferRadius()) {
79 langevinBufferRadius_ = simParams_->getLangevinBufferRadius();
81 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
82 "langevinBufferRadius must be specified "
83 "when useSphericalBoundaryConditions is turned on.\n");
84 painCave.severity = OPENMD_ERROR;
89 if (simParams_->haveFrozenBufferRadius()) {
90 frozenBufferRadius_ = simParams_->getFrozenBufferRadius();
92 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
93 "frozenBufferRadius must be specified "
94 "when useSphericalBoundaryConditions is turned on.\n");
95 painCave.severity = OPENMD_ERROR;
100 if (frozenBufferRadius_ < langevinBufferRadius_) {
101 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
102 "frozenBufferRadius has been set smaller than the "
103 "langevinBufferRadius. This is probably an error.\n");
104 painCave.severity = OPENMD_WARNING;
105 painCave.isFatal = 0;
113 SimInfo::MoleculeIterator i;
114 Molecule::IntegrableObjectIterator j;
115 bool needHydroPropFile =
false;
117 for (mol = info_->beginMolecule(i); mol != NULL;
118 mol = info_->nextMolecule(i)) {
119 for (sd = mol->beginIntegrableObject(j); sd != NULL;
120 sd = mol->nextIntegrableObject(j)) {
121 if (sd->isRigidBody()) {
122 RigidBody* rb =
static_cast<RigidBody*
>(sd);
123 if (rb->getNumAtoms() > 1) needHydroPropFile =
true;
128 if (needHydroPropFile) {
129 if (simParams_->haveHydroPropFile()) {
130 HydroIO* hio =
new HydroIO();
131 hydroPropMap_ = hio->parseHydroFile(simParams_->getHydroPropFile());
134 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
135 "HydroPropFile must be set to a file name if Langevin Dynamics\n"
136 "\tis specified for rigidBodies which contain more than one atom\n"
137 "\tTo create a HydroPropFile, run the \"Hydro\" program.\n");
138 painCave.severity = OPENMD_ERROR;
139 painCave.isFatal = 1;
143 for (mol = info_->beginMolecule(i); mol != NULL;
144 mol = info_->nextMolecule(i)) {
145 for (sd = mol->beginIntegrableObject(j); sd != NULL;
146 sd = mol->nextIntegrableObject(j)) {
147 map<string, HydroProp*>::iterator iter =
148 hydroPropMap_.find(sd->getType());
149 if (iter != hydroPropMap_.end()) {
150 hydroProps_.push_back(iter->second);
151 moments_.push_back(getMomentData(sd));
154 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
155 "Can not find resistance tensor for atom [%s]\n",
156 sd->getType().c_str());
157 painCave.severity = OPENMD_ERROR;
158 painCave.isFatal = 1;
165 for (mol = info_->beginMolecule(i); mol != NULL;
166 mol = info_->nextMolecule(i)) {
167 for (sd = mol->beginIntegrableObject(j); sd != NULL;
168 sd = mol->nextIntegrableObject(j)) {
169 Shape* currShape = NULL;
172 Atom* atom =
static_cast<Atom*
>(sd);
173 AtomType* atomType = atom->getAtomType();
174 GayBerneAdapter gba = GayBerneAdapter(atomType);
175 if (gba.isGayBerne()) {
176 currShape =
new Ellipsoid(V3Zero, gba.getL() / 2.0,
177 gba.getD() / 2.0, Mat3x3d::identity());
179 LennardJonesAdapter lja = LennardJonesAdapter(atomType);
180 if (lja.isLennardJones()) {
181 currShape =
new Sphere(V3Zero, lja.getSigma() / 2.0);
184 vector<AtomType*> atChain = atomType->allYourBase();
185 vector<AtomType*>::iterator i;
186 for (i = atChain.begin(); i != atChain.end(); ++i) {
189 currShape =
new Sphere(V3Zero, etab.
GetVdwRad(aNum));
194 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
195 "Could not find atom type in default element.txt\n");
196 painCave.severity = OPENMD_ERROR;
197 painCave.isFatal = 1;
204 if (!simParams_->haveTargetTemp()) {
205 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
206 "You can't use LangevinDynamics without a targetTemp!\n");
207 painCave.isFatal = 1;
208 painCave.severity = OPENMD_ERROR;
212 if (!simParams_->haveViscosity()) {
213 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
214 "You can't use LangevinDynamics without a viscosity!\n");
215 painCave.isFatal = 1;
216 painCave.severity = OPENMD_ERROR;
220 HydroProp* currHydroProp =
221 currShape->getHydroProp(simParams_->getViscosity());
222 map<string, HydroProp*>::iterator iter =
223 hydroPropMap_.find(sd->getType());
224 if (iter != hydroPropMap_.end()) {
225 hydroProps_.push_back(iter->second);
226 moments_.push_back(getMomentData(sd));
229 currHydroProp->complete();
230 hydroPropMap_.insert(map<string, HydroProp*>::value_type(
231 sd->getType(), currHydroProp));
232 hydroProps_.push_back(currHydroProp);
233 moments_.push_back(getMomentData(sd));
241 std::sqrt(2.0 * Constants::kb * simParams_->getTargetTemp() / dt);
243 forceDistribution_ = std::normal_distribution<RealType>(0.0, stdDev);
246 MomentData* LDForceModifier::getMomentData(StuntDouble* sd) {
247 map<string, MomentData*>::iterator j = momentsMap_.find(sd->getType());
248 if (j != momentsMap_.end()) {
251 MomentData* moment =
new MomentData;
252 map<string, HydroProp*>::iterator i = hydroPropMap_.find(sd->getType());
254 if (i != hydroPropMap_.end()) {
256 moment->rcr = i->second->getCenterOfResistance();
259 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
260 "LDForceManager createMomentData: Couldn't find HydroProp for\n"
262 sd->getType().c_str());
263 painCave.isFatal = 1;
264 painCave.severity = OPENMD_ERROR;
268 if (sd->isRigidBody())
269 moment->rcr -=
dynamic_cast<RigidBody*
>(sd)->getRefCOM();
273 RealType mass = sd->getMass();
274 moment->Icr = sd->getI();
276 mass * (
dot(moment->rcr, moment->rcr) * Mat3x3d::identity() +
277 outProduct(moment->rcr, moment->rcr));
278 moment->IcrInv = moment->Icr.inverse();
281 map<string, MomentData*>::value_type(sd->getType(), moment));
286 void LDForceModifier::modifyForces() {
287 SimInfo::MoleculeIterator i;
288 Molecule::IntegrableObjectIterator j;
298 unsigned int index = 0;
299 bool doLangevinForces;
305 for (mol = info_->beginMolecule(i); mol != NULL;
306 mol = info_->nextMolecule(i)) {
307 doLangevinForces =
true;
308 freezeMolecule =
false;
310 if (sphericalBoundaryConditions_) {
311 Vector3d molPos = mol->getCom();
312 RealType molRad = molPos.
length();
314 doLangevinForces =
false;
316 if (molRad > langevinBufferRadius_) {
317 doLangevinForces =
true;
318 freezeMolecule =
false;
320 if (molRad > frozenBufferRadius_) {
321 doLangevinForces =
false;
322 freezeMolecule =
true;
326 for (sd = mol->beginIntegrableObject(j); sd != NULL;
327 sd = mol->nextIntegrableObject(j)) {
328 if (freezeMolecule) fdf += sd->freeze();
330 if (doLangevinForces) {
331 mass = sd->getMass();
332 if (sd->isDirectional()) {
336 Atrans = A.transpose();
338 Vector3d rcrLab = Atrans * moments_[index]->rcr;
342 Vector3d randomForceBody;
343 Vector3d randomTorqueBody;
344 genRandomForceAndTorque(randomForceBody, randomTorqueBody, index);
345 Vector3d randomForceLab = Atrans * randomForceBody;
346 Vector3d randomTorqueLab = Atrans * randomTorqueBody;
348 sd->addFrc(randomForceLab);
349 sd->addTrq(randomTorqueLab +
cross(rcrLab, randomForceLab));
361 Vector3d vel = sd->getVel();
362 Vector3d angMom = sd->getJ();
370 vel + (dt2_ / mass * Constants::energyConvert) * frc;
372 Tb = sd->lab2Body(sd->getTrq());
373 Vector3d angMomStep =
374 angMom + (dt2_ * Constants::energyConvert) * Tb;
379 Vector3d frictionForceBody;
380 Vector3d frictionForceLab(0.0);
382 Vector3d frictionTorqueBody(0.0);
384 Vector3d frictionTorqueLab;
390 for (
int k = 0; k < maxIterNum_; k++) {
391 if (sd->isLinear()) {
392 int linearAxis = sd->linearAxis();
393 int l = (linearAxis + 1) % 3;
394 int m = (linearAxis + 2) % 3;
395 omegaBody[l] = angMomStep[l] / moments_[index]->Icr(l, l);
396 omegaBody[m] = angMomStep[m] / moments_[index]->Icr(m, m);
399 omegaBody = moments_[index]->IcrInv * angMomStep;
405 omegaLab = Atrans * omegaBody;
409 vcdLab = velStep +
cross(omegaLab, rcrLab);
410 vcdBody = A * vcdLab;
411 frictionForceBody = -(hydroProps_[index]->getXitt() * vcdBody +
412 hydroProps_[index]->getXirt() * omegaBody);
413 oldFFL = frictionForceLab;
414 frictionForceLab = Atrans * frictionForceBody;
415 oldFTB = frictionTorqueBody;
416 frictionTorqueBody = -(hydroProps_[index]->getXitr() * vcdBody +
417 hydroProps_[index]->getXirr() * omegaBody);
418 frictionTorqueLab = Atrans * frictionTorqueBody;
422 velStep = vel + (dt2_ / mass * Constants::energyConvert) *
423 (frc + frictionForceLab);
424 angMomStep = angMom + (dt2_ * Constants::energyConvert) *
425 (Tb + frictionTorqueBody);
430 fdot =
dot(frictionForceLab, oldFFL) /
431 frictionForceLab.lengthSquare();
432 tdot =
dot(frictionTorqueBody, oldFTB) /
433 frictionTorqueBody.lengthSquare();
435 if (fabs(1.0 - fdot) <= forceTolerance_ &&
436 fabs(1.0 - tdot) <= forceTolerance_)
440 sd->addFrc(frictionForceLab);
441 sd->addTrq(frictionTorqueLab +
cross(rcrLab, frictionForceLab));
446 Vector3d systemForce;
447 Vector3d randomForce;
448 Vector3d randomTorque;
449 genRandomForceAndTorque(randomForce, randomTorque, index);
450 systemForce = sd->getFrc();
451 sd->addFrc(randomForce);
461 Vector3d vel = sd->getVel();
468 vel + (dt2_ / mass * Constants::energyConvert) * frc;
470 Vector3d frictionForce(0.0);
476 for (
int k = 0; k < maxIterNum_; k++) {
477 oldFF = frictionForce;
478 frictionForce = -hydroProps_[index]->getXitt() * velStep;
482 velStep = vel + (dt2_ / mass * Constants::energyConvert) *
483 (frc + frictionForce);
488 fdot =
dot(frictionForce, oldFF) / frictionForce.lengthSquare();
490 if (fabs(1.0 - fdot) <= forceTolerance_)
494 sd->addFrc(frictionForce);
503 if(simParams_->getConserveLinearMomentum()) veloMunge_->removeComDrift();
505 if (!simParams_->getUsePeriodicBoundaryConditions() &&
506 simParams_->getConserveAngularMomentum())
507 veloMunge_->removeAngularDrift();
510 void LDForceModifier::genRandomForceAndTorque(Vector3d& force,
512 unsigned int index) {
513 Vector<RealType, 6> Z;
514 Vector<RealType, 6> generalForce;
516 Z[0] = forceDistribution_(*randNumGen_);
517 Z[1] = forceDistribution_(*randNumGen_);
518 Z[2] = forceDistribution_(*randNumGen_);
519 Z[3] = forceDistribution_(*randNumGen_);
520 Z[4] = forceDistribution_(*randNumGen_);
521 Z[5] = forceDistribution_(*randNumGen_);
523 generalForce = hydroProps_[index]->getS() * Z;
525 force[0] = generalForce[0];
526 force[1] = generalForce[1];
527 force[2] = generalForce[2];
528 torque[0] = generalForce[3];
529 torque[1] = generalForce[4];
530 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)
Real length()
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.