48#include "integrators/LangevinHullForceModifier.hpp"
62#include "brains/ForceModifier.hpp"
63#include "math/AlphaHull.hpp"
64#include "math/CholeskyDecomposition.hpp"
65#include "math/ConvexHull.hpp"
66#include "math/Triangle.hpp"
67#include "utils/Constants.hpp"
73 LangevinHullForceModifier::LangevinHullForceModifier(
SimInfo* info) :
75 simParams_ = info->getSimParams();
76 veloMunge = std::make_unique<Velocitizer>(info);
80 stringToEnumMap_[
"Convex"] = hullConvex;
81 stringToEnumMap_[
"AlphaShape"] = hullAlphaShape;
82 stringToEnumMap_[
"Unknown"] = hullUnknown;
84 const std::string ht = simParams_->getHULL_Method();
86 std::map<std::string, HullTypeEnum>::iterator iter;
87 iter = stringToEnumMap_.find(ht);
88 hullType_ = (iter == stringToEnumMap_.end()) ?
89 LangevinHullForceModifier::hullUnknown :
94 surfaceMesh_ =
new ConvexHull();
97 surfaceMesh_ =
new AlphaHull(simParams_->getAlpha());
102 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
103 "LangevinHullForceModifier: Unknown Hull_Method was requested!\n");
104 painCave.isFatal = 1;
109 doThermalCoupling_ =
true;
110 doPressureCoupling_ =
true;
114 if (!simParams_->haveTargetTemp()) {
115 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
116 "LangevinHullForceModifier: no targetTemp (K) was set.\n"
117 "\tOpenMD is turning off the thermal coupling to the bath.\n");
118 painCave.isFatal = 0;
119 painCave.severity = OPENMD_INFO;
121 doThermalCoupling_ =
false;
123 targetTemp_ = simParams_->getTargetTemp();
125 if (!simParams_->haveViscosity()) {
126 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
127 "LangevinHullForceModifier: no viscosity was set.\n"
128 "\tOpenMD is turning off the thermal coupling to the bath.\n");
129 painCave.isFatal = 0;
130 painCave.severity = OPENMD_INFO;
132 doThermalCoupling_ =
false;
134 viscosity_ = simParams_->getViscosity();
135 if (fabs(viscosity_) < 1e-6) {
137 painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
138 "LangevinHullForceModifier: The bath viscosity was set lower\n"
139 "\tthan 1e-6 poise. OpenMD is turning off the thermal\n"
140 "\tcoupling to the bath.\n");
141 painCave.isFatal = 0;
142 painCave.severity = OPENMD_INFO;
144 doThermalCoupling_ =
false;
148 if (!simParams_->haveTargetPressure()) {
149 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
150 "LangevinHullForceModifier: no targetPressure (atm) was set.\n"
151 "\tOpenMD is turning off the pressure coupling to the bath.\n");
152 painCave.isFatal = 0;
153 painCave.severity = OPENMD_INFO;
155 doPressureCoupling_ =
false;
159 simParams_->getTargetPressure() / Constants::pressureConvert;
161 if (simParams_->getUsePeriodicBoundaryConditions()) {
162 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
163 "LangevinHullForceModifier: You can't use the Langevin Hull\n"
164 "\tintegrator with periodic boundary conditions turned on!\n");
165 painCave.isFatal = 1;
169 dt_ = simParams_->getDt();
172 if (worldRank == 0) {
174 if (doThermalCoupling_) {
175 randNumGen_ = info->getRandomNumberGenerator();
177 RealType stdDev = std::sqrt(2.0 * Constants::kb * targetTemp_ / dt_);
179 forceDistribution_ = std::normal_distribution<RealType>(0.0, stdDev);
189 SimInfo::MoleculeIterator i;
190 Molecule::IntegrableObjectIterator j;
192 for (mol = info_->beginMolecule(i); mol != NULL;
193 mol = info_->nextMolecule(i)) {
194 for (sd = mol->beginIntegrableObject(j); sd != NULL;
195 sd = mol->nextIntegrableObject(j)) {
196 localSites_.push_back(sd);
204 surfaceMesh_->computeHull(localSites_);
207 LangevinHullForceModifier::~LangevinHullForceModifier() {
211 void LangevinHullForceModifier::modifyForces() {
212 int nTriangles, thisFacet;
214 std::vector<Triangle> sMesh;
215 Triangle thisTriangle;
216 std::vector<Triangle>::iterator face;
217 std::vector<StuntDouble*> vertexSDs;
218 std::vector<StuntDouble*>::iterator vertex;
220 Vector3d unitNormal, centroid, facetVel;
221 Vector3d langevinForce, vertexForce;
222 Vector3d extPressure, randomForce, dragForce;
224 Mat3x3d hydroTensor, S;
225 std::vector<Vector3d> randNums;
228 surfaceMesh_->computeHull(localSites_);
230 sMesh = surfaceMesh_->getMesh();
231 nTriangles = sMesh.size();
233 if (doThermalCoupling_) {
235 randNums = genTriangleForces(nTriangles);
240 for (face = sMesh.begin(); face != sMesh.end(); ++face) {
241 thisTriangle = *face;
242 vertexSDs = thisTriangle.getVertices();
243 thisArea = thisTriangle.getArea();
244 unitNormal = thisTriangle.getUnitNormal();
245 centroid = thisTriangle.getCentroid();
246 facetVel = thisTriangle.getFacetVelocity();
248 langevinForce = V3Zero;
250 if (doPressureCoupling_) {
251 extPressure = -unitNormal * (targetPressure_ * thisArea) /
252 Constants::energyConvert;
253 langevinForce += extPressure;
256 if (doThermalCoupling_) {
257 hydroTensor = thisTriangle.computeHydrodynamicTensor(viscosity_);
258 hydroTensor *= Constants::viscoConvert;
259 CholeskyDecomposition(hydroTensor, S);
260 randomForce = S * randNums[thisFacet++];
261 dragForce = -hydroTensor * facetVel;
262 langevinForce += randomForce + dragForce;
266 for (vertex = vertexSDs.begin(); vertex != vertexSDs.end(); ++vertex) {
267 if ((*vertex) != NULL) {
268 vertexForce = langevinForce / RealType(3.0);
269 (*vertex)->addFrc(vertexForce);
274 if (simParams_->getConserveLinearMomentum()) veloMunge->removeComDrift();
275 if (simParams_->getConserveAngularMomentum())
276 veloMunge->removeAngularDrift();
278 Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
279 currSnapshot->setVolume(surfaceMesh_->getVolume());
280 currSnapshot->setHullVolume(surfaceMesh_->getVolume());
283 std::vector<Vector3d> LangevinHullForceModifier::genTriangleForces(
286 std::vector<Vector3d> gaussRand(nTriangles);
287 std::fill(gaussRand.begin(), gaussRand.end(), V3Zero);
290 if (worldRank == 0) {
292 for (
int i = 0; i < nTriangles; i++) {
293 gaussRand[i][0] = forceDistribution_(*randNumGen_);
294 gaussRand[i][1] = forceDistribution_(*randNumGen_);
295 gaussRand[i][2] = forceDistribution_(*randNumGen_);
301 MPI_Bcast(gaussRand[0].getArrayPointer(), nTriangles * 3, MPI_REALTYPE, 0,
Abstract class for external ForceModifier classes.
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.