ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/integrators/SMIPDForceManager.cpp
Revision: 3459
Committed: Tue Oct 7 17:12:48 2008 UTC (16 years, 6 months ago) by chuckv
File size: 19277 byte(s)
Log Message:
Work continues on constant pressure langevin dynamics.

File Contents

# Content
1 /*
2 * Copyright (c) 2008 The University of Notre Dame. All Rights Reserved.
3 *
4 * The University of Notre Dame grants you ("Licensee") a
5 * non-exclusive, royalty free, license to use, modify and
6 * redistribute this software in source and binary code form, provided
7 * that the following conditions are met:
8 *
9 * 1. Acknowledgement of the program authors must be made in any
10 * publication of scientific results based in part on use of the
11 * program. An acceptable form of acknowledgement is citation of
12 * the article in which the program was described (Matthew
13 * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14 * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15 * Parallel Simulation Engine for Molecular Dynamics,"
16 * J. Comput. Chem. 26, pp. 252-271 (2005))
17 *
18 * 2. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 3. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the
24 * distribution.
25 *
26 * This software is provided "AS IS," without a warranty of any
27 * kind. All express or implied conditions, representations and
28 * warranties, including any implied warranty of merchantability,
29 * fitness for a particular purpose or non-infringement, are hereby
30 * excluded. The University of Notre Dame and its licensors shall not
31 * be liable for any damages suffered by licensee as a result of
32 * using, modifying or distributing the software or its
33 * derivatives. In no event will the University of Notre Dame or its
34 * licensors be liable for any lost revenue, profit or data, or for
35 * direct, indirect, special, consequential, incidental or punitive
36 * damages, however caused and regardless of the theory of liability,
37 * arising out of the use of or inability to use software, even if the
38 * University of Notre Dame has been advised of the possibility of
39 * such damages.
40 */
41 #include <fstream>
42 #include <iostream>
43 #include "integrators/SMIPDForceManager.hpp"
44 #include "math/CholeskyDecomposition.hpp"
45 #include "utils/OOPSEConstant.hpp"
46 #include "hydrodynamics/Sphere.hpp"
47 #include "hydrodynamics/Ellipsoid.hpp"
48 #include "utils/ElementsTable.hpp"
49 #include "math/ConvexHull.hpp"
50 #include "math/Triangle.hpp"
51
52
53 namespace oopse {
54
55 SMIPDForceManager::SMIPDForceManager(SimInfo* info) : ForceManager(info), forceTolerance_(1e-6), maxIterNum_(4) {
56 simParams = info->getSimParams();
57 veloMunge = new Velocitizer(info);
58
59 // Create Hull, Convex Hull for now, other options later.
60 surfaceMesh_ = new ConvexHull();
61
62
63 /* Check that the simulation has target pressure and target
64 temperature set*/
65
66 if (!simParams->haveTargetTemp()) {
67 sprintf(painCave.errMsg, "You can't use the SMIPDynamics integrator without a targetTemp!\n");
68 painCave.isFatal = 1;
69 painCave.severity = OOPSE_ERROR;
70 simError();
71 } else {
72 targetTemp_ = simParams->getTargetTemp();
73 }
74
75 if (!simParams->haveTargetPressure()) {
76 sprintf(painCave.errMsg, "SMIPDynamics error: You can't use the SMIPD integrator\n"
77 " without a targetPressure!\n");
78
79 painCave.isFatal = 1;
80 simError();
81 } else {
82 targetPressure_ = simParams->getTargetPressure();
83 }
84
85
86 if (simParams->getUsePeriodicBoundaryConditions()) {
87 sprintf(painCave.errMsg, "SMIPDynamics error: You can't use the SMIPD integrator\n"
88 " with periodic boundary conditions !\n");
89
90 painCave.isFatal = 1;
91 simError();
92 }
93
94
95 // Build the hydroProp map:
96 std::map<std::string, HydroProp*> hydroPropMap;
97
98 Molecule* mol;
99 StuntDouble* integrableObject;
100 SimInfo::MoleculeIterator i;
101 Molecule::IntegrableObjectIterator j;
102 bool needHydroPropFile = false;
103
104 for (mol = info->beginMolecule(i); mol != NULL;
105 mol = info->nextMolecule(i)) {
106 for (integrableObject = mol->beginIntegrableObject(j);
107 integrableObject != NULL;
108 integrableObject = mol->nextIntegrableObject(j)) {
109
110 if (integrableObject->isRigidBody()) {
111 RigidBody* rb = static_cast<RigidBody*>(integrableObject);
112 if (rb->getNumAtoms() > 1) needHydroPropFile = true;
113 }
114
115 }
116 }
117
118
119 if (needHydroPropFile) {
120 if (simParams->haveHydroPropFile()) {
121 hydroPropMap = parseFrictionFile(simParams->getHydroPropFile());
122 } else {
123 sprintf( painCave.errMsg,
124 "HydroPropFile must be set to a file name if SMIPDynamics\n"
125 "\tis specified for rigidBodies which contain more than one atom\n"
126 "\tTo create a HydroPropFile, run the \"Hydro\" program.\n\n"
127 "\tFor use with SMIPD, the default viscosity in Hydro should be\n"
128 "\tset to 1.0 because the friction and random forces will be\n"
129 "\tdynamically re-set assuming this is true.\n");
130 painCave.severity = OOPSE_ERROR;
131 painCave.isFatal = 1;
132 simError();
133 }
134
135 for (mol = info->beginMolecule(i); mol != NULL;
136 mol = info->nextMolecule(i)) {
137 for (integrableObject = mol->beginIntegrableObject(j);
138 integrableObject != NULL;
139 integrableObject = mol->nextIntegrableObject(j)) {
140
141 std::map<std::string, HydroProp*>::iterator iter = hydroPropMap.find(integrableObject->getType());
142 if (iter != hydroPropMap.end()) {
143 hydroProps_.push_back(iter->second);
144 } else {
145 sprintf( painCave.errMsg,
146 "Can not find resistance tensor for atom [%s]\n", integrableObject->getType().c_str());
147 painCave.severity = OOPSE_ERROR;
148 painCave.isFatal = 1;
149 simError();
150 }
151 }
152 }
153 } else {
154
155 std::map<std::string, HydroProp*> hydroPropMap;
156 for (mol = info->beginMolecule(i); mol != NULL;
157 mol = info->nextMolecule(i)) {
158 for (integrableObject = mol->beginIntegrableObject(j);
159 integrableObject != NULL;
160 integrableObject = mol->nextIntegrableObject(j)) {
161 Shape* currShape = NULL;
162
163 if (integrableObject->isAtom()){
164 Atom* atom = static_cast<Atom*>(integrableObject);
165 AtomType* atomType = atom->getAtomType();
166 if (atomType->isGayBerne()) {
167 DirectionalAtomType* dAtomType = dynamic_cast<DirectionalAtomType*>(atomType);
168 GenericData* data = dAtomType->getPropertyByName("GayBerne");
169 if (data != NULL) {
170 GayBerneParamGenericData* gayBerneData = dynamic_cast<GayBerneParamGenericData*>(data);
171
172 if (gayBerneData != NULL) {
173 GayBerneParam gayBerneParam = gayBerneData->getData();
174 currShape = new Ellipsoid(V3Zero,
175 gayBerneParam.GB_l / 2.0,
176 gayBerneParam.GB_d / 2.0,
177 Mat3x3d::identity());
178 } else {
179 sprintf( painCave.errMsg,
180 "Can not cast GenericData to GayBerneParam\n");
181 painCave.severity = OOPSE_ERROR;
182 painCave.isFatal = 1;
183 simError();
184 }
185 } else {
186 sprintf( painCave.errMsg, "Can not find Parameters for GayBerne\n");
187 painCave.severity = OOPSE_ERROR;
188 painCave.isFatal = 1;
189 simError();
190 }
191 } else {
192 if (atomType->isLennardJones()){
193 GenericData* data = atomType->getPropertyByName("LennardJones");
194 if (data != NULL) {
195 LJParamGenericData* ljData = dynamic_cast<LJParamGenericData*>(data);
196 if (ljData != NULL) {
197 LJParam ljParam = ljData->getData();
198 currShape = new Sphere(atom->getPos(), ljParam.sigma/2.0);
199 } else {
200 sprintf( painCave.errMsg,
201 "Can not cast GenericData to LJParam\n");
202 painCave.severity = OOPSE_ERROR;
203 painCave.isFatal = 1;
204 simError();
205 }
206 }
207 } else {
208 int aNum = etab.GetAtomicNum((atom->getType()).c_str());
209 if (aNum != 0) {
210 currShape = new Sphere(atom->getPos(), etab.GetVdwRad(aNum));
211 } else {
212 sprintf( painCave.errMsg,
213 "Could not find atom type in default element.txt\n");
214 painCave.severity = OOPSE_ERROR;
215 painCave.isFatal = 1;
216 simError();
217 }
218 }
219 }
220 }
221 HydroProp* currHydroProp = currShape->getHydroProp(1.0,simParams->getTargetTemp());
222 std::map<std::string, HydroProp*>::iterator iter = hydroPropMap.find(integrableObject->getType());
223 if (iter != hydroPropMap.end())
224 hydroProps_.push_back(iter->second);
225 else {
226 currHydroProp->complete();
227 hydroPropMap.insert(std::map<std::string, HydroProp*>::value_type(integrableObject->getType(), currHydroProp));
228 hydroProps_.push_back(currHydroProp);
229 }
230 }
231 }
232 }
233
234 /* Compute hull first time through to get the area of t=0*/
235
236 /* Build a vector of integrable objects to determine if the are surface atoms */
237 for (mol = info_->beginMolecule(i); mol != NULL; mol = info_->nextMolecule(i)) {
238 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
239 integrableObject = mol->nextIntegrableObject(j)) {
240 localSites_.push_back(integrableObject);
241 }
242 }
243
244 surfaceMesh_->computeHull(localSites_);
245 Area0_ = surfaceMesh_->getArea();
246 //variance_ = 2.0 * OOPSEConstant::kb*simParams->getTargetTemp()/simParams->getDt();
247
248 }
249
250 std::map<std::string, HydroProp*> SMIPDForceManager::parseFrictionFile(const std::string& filename) {
251 std::map<std::string, HydroProp*> props;
252 std::ifstream ifs(filename.c_str());
253 if (ifs.is_open()) {
254
255 }
256
257 const unsigned int BufferSize = 65535;
258 char buffer[BufferSize];
259 while (ifs.getline(buffer, BufferSize)) {
260 HydroProp* currProp = new HydroProp(buffer);
261 props.insert(std::map<std::string, HydroProp*>::value_type(currProp->getName(), currProp));
262 }
263
264 return props;
265 }
266
267 void SMIPDForceManager::postCalculation(bool needStress){
268 SimInfo::MoleculeIterator i;
269 Molecule::IntegrableObjectIterator j;
270 Molecule* mol;
271 StuntDouble* integrableObject;
272 RealType mass;
273 Vector3d pos;
274 Vector3d frc;
275 Mat3x3d A;
276 Mat3x3d Atrans;
277 Vector3d Tb;
278 Vector3d ji;
279 unsigned int index = 0;
280 int fdf;
281
282 fdf = 0;
283
284 /*Compute surface Mesh*/
285 surfaceMesh_->computeHull(localSites_);
286
287 /* Get area and number of surface stunt doubles and compute new variance */
288 RealType area = surfaceMesh_->getArea();
289 int nSurfaceSDs = surfaceMesh_->getNs();
290
291 /* Compute variance for random forces */
292
293 variance_ = sqrt(2.0*NumericConstant::PI)*((targetPressure_/OOPSEConstant::pressureConvert)*area/nSurfaceSDs);
294
295 std::vector<Triangle*> sMesh = surfaceMesh_->getMesh();
296 std::vector<RealType> randNums = genTriangleForces(sMesh.size(),variance_);
297
298 /* Loop over the mesh faces and apply random force to each of the faces*/
299
300
301 std::vector<Triangle*>::iterator face;
302 std::vector<StuntDouble*>::iterator vertex;
303 int thisNumber = 0;
304 for (face = sMesh.begin(); face != sMesh.end(); ++face){
305
306 Triangle* thisTriangle = *face;
307 std::vector<StuntDouble*> vertexSDs = thisTriangle->getVertices();
308
309 /* Get Random Force */
310 Vector3d unitNormal = thisTriangle->getNormal();
311 unitNormal.normalize();
312 Vector3d randomForce = -randNums[thisNumber] * unitNormal;
313
314 for (vertex = vertexSDs.begin(); vertex != vertexSDs.end(); ++vertex){
315
316 // mass = integrableObject->getMass();
317
318 (*vertex)->addFrc(randomForce/3.0);
319 }
320 }
321
322 /* Now loop over all surface particles and apply the drag*/
323
324 std::vector<StuntDouble*> surfaceSDs = surfaceMesh_->getSurfaceAtoms();
325 for (vertex = surfaceSDs.begin(); vertex != surfaceSDs.end(); ++vertex){
326 integrableObject = *vertex;
327 mass = integrableObject->getMass();
328 if (integrableObject->isDirectional()){
329
330 // preliminaries for directional objects:
331
332 A = integrableObject->getA();
333 Atrans = A.transpose();
334 Vector3d rcrLab = Atrans * hydroProps_[index]->getCOR();
335
336
337 Mat3x3d I = integrableObject->getI();
338 Vector3d omegaBody;
339
340 // What remains contains velocity explicitly, but the velocity required
341 // is at the full step: v(t + h), while we have initially the velocity
342 // at the half step: v(t + h/2). We need to iterate to converge the
343 // friction force and friction torque vectors.
344
345 // this is the velocity at the half-step:
346
347 Vector3d vel =integrableObject->getVel();
348 Vector3d angMom = integrableObject->getJ();
349
350 //estimate velocity at full-step using everything but friction forces:
351
352 frc = integrableObject->getFrc();
353 Vector3d velStep = vel + (dt2_ /mass * OOPSEConstant::energyConvert) * frc;
354
355 Tb = integrableObject->lab2Body(integrableObject->getTrq());
356 Vector3d angMomStep = angMom + (dt2_ * OOPSEConstant::energyConvert) * Tb;
357
358 Vector3d omegaLab;
359 Vector3d vcdLab;
360 Vector3d vcdBody;
361 Vector3d frictionForceBody;
362 Vector3d frictionForceLab(0.0);
363 Vector3d oldFFL; // used to test for convergence
364 Vector3d frictionTorqueBody(0.0);
365 Vector3d oldFTB; // used to test for convergence
366 Vector3d frictionTorqueLab;
367 RealType fdot;
368 RealType tdot;
369
370 //iteration starts here:
371
372 for (int k = 0; k < maxIterNum_; k++) {
373
374 if (integrableObject->isLinear()) {
375 int linearAxis = integrableObject->linearAxis();
376 int l = (linearAxis +1 )%3;
377 int m = (linearAxis +2 )%3;
378 omegaBody[l] = angMomStep[l] /I(l, l);
379 omegaBody[m] = angMomStep[m] /I(m, m);
380
381 } else {
382 omegaBody[0] = angMomStep[0] /I(0, 0);
383 omegaBody[1] = angMomStep[1] /I(1, 1);
384 omegaBody[2] = angMomStep[2] /I(2, 2);
385 }
386
387 omegaLab = Atrans * omegaBody;
388
389 // apply friction force and torque at center of resistance
390
391 vcdLab = velStep + cross(omegaLab, rcrLab);
392 vcdBody = A * vcdLab;
393 frictionForceBody = -(hydroProps_[index]->getXitt() * vcdBody + hydroProps_[index]->getXirt() * omegaBody);
394 oldFFL = frictionForceLab;
395 frictionForceLab = Atrans * frictionForceBody;
396 oldFTB = frictionTorqueBody;
397 frictionTorqueBody = -(hydroProps_[index]->getXitr() * vcdBody + hydroProps_[index]->getXirr() * omegaBody);
398 frictionTorqueLab = Atrans * frictionTorqueBody;
399
400 // re-estimate velocities at full-step using friction forces:
401
402 velStep = vel + (dt2_ / mass * OOPSEConstant::energyConvert) * (frc + frictionForceLab);
403 angMomStep = angMom + (dt2_ * OOPSEConstant::energyConvert) * (Tb + frictionTorqueBody);
404
405 // check for convergence (if the vectors have converged, fdot and tdot will both be 1.0):
406
407 fdot = dot(frictionForceLab, oldFFL) / frictionForceLab.lengthSquare();
408 tdot = dot(frictionTorqueBody, oldFTB) / frictionTorqueBody.lengthSquare();
409
410 if (fabs(1.0 - fdot) <= forceTolerance_ && fabs(1.0 - tdot) <= forceTolerance_)
411 break; // iteration ends here
412 }
413
414 integrableObject->addFrc(frictionForceLab);
415 integrableObject->addTrq(frictionTorqueLab + cross(rcrLab, frictionForceLab));
416
417
418 } else {
419 //spherical atom
420
421
422 // What remains contains velocity explicitly, but the velocity required
423 // is at the full step: v(t + h), while we have initially the velocity
424 // at the half step: v(t + h/2). We need to iterate to converge the
425 // friction force vector.
426
427 // this is the velocity at the half-step:
428
429 Vector3d vel =integrableObject->getVel();
430
431 //estimate velocity at full-step using everything but friction forces:
432
433 frc = integrableObject->getFrc();
434 Vector3d velStep = vel + (dt2_ / mass * OOPSEConstant::energyConvert) * frc;
435
436 Vector3d frictionForce(0.0);
437 Vector3d oldFF; // used to test for convergence
438 RealType fdot;
439
440 //iteration starts here:
441
442 for (int k = 0; k < maxIterNum_; k++) {
443
444 oldFF = frictionForce;
445 frictionForce = -hydroProps_[index]->getXitt() * velStep;
446
447 // re-estimate velocities at full-step using friction forces:
448
449 velStep = vel + (dt2_ / mass * OOPSEConstant::energyConvert) * (frc + frictionForce);
450
451 // check for convergence (if the vector has converged, fdot will be 1.0):
452
453 fdot = dot(frictionForce, oldFF) / frictionForce.lengthSquare();
454
455 if (fabs(1.0 - fdot) <= forceTolerance_)
456 break; // iteration ends here
457 }
458
459 integrableObject->addFrc(frictionForce);
460
461
462 }
463
464
465 }
466 Snapshot* currSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
467 currSnapshot->setVolume(surfaceMesh_->getVolume());
468
469 ForceManager::postCalculation(needStress);
470 }
471
472 void SMIPDForceManager::genRandomForceAndTorque(Vector3d& force, Vector3d& torque, unsigned int index, RealType variance) {
473
474
475 Vector<RealType, 6> Z;
476 Vector<RealType, 6> generalForce;
477
478
479 Z[0] = randNumGen_.randNorm(0, variance);
480 Z[1] = randNumGen_.randNorm(0, variance);
481 Z[2] = randNumGen_.randNorm(0, variance);
482 Z[3] = randNumGen_.randNorm(0, variance);
483 Z[4] = randNumGen_.randNorm(0, variance);
484 Z[5] = randNumGen_.randNorm(0, variance);
485
486 generalForce = hydroProps_[index]->getS()*Z;
487
488 force[0] = generalForce[0];
489 force[1] = generalForce[1];
490 force[2] = generalForce[2];
491 torque[0] = generalForce[3];
492 torque[1] = generalForce[4];
493 torque[2] = generalForce[5];
494
495 }
496 std::vector<RealType> SMIPDForceManager::genTriangleForces(int nTriangles, RealType variance) {
497
498 // zero fill the random vector before starting:
499 std::vector<RealType> gaussRand;
500 gaussRand.resize(nTriangles);
501 std::fill(gaussRand.begin(), gaussRand.end(), 0.0);
502
503
504 #ifdef IS_MPI
505 if (worldRank == 0) {
506 #endif
507 for (int i = 0; i < nTriangles; i++) {
508 gaussRand[i] = fabs(randNumGen_.randNorm(0.0, 1.0));
509 }
510 #ifdef IS_MPI
511 }
512 #endif
513
514 // push these out to the other processors
515
516 #ifdef IS_MPI
517 if (worldRank == 0) {
518 MPI_Bcast(&gaussRand[0], nTriangles, MPI_REAL, 0, MPI_COMM_WORLD);
519 } else {
520 MPI_Bcast(&gaussRand[0], nTriangles, MPI_REAL, 0, MPI_COMM_WORLD);
521 }
522 #endif
523
524 for (int i = 0; i < nTriangles; i++) {
525 gaussRand[i] = gaussRand[i] * variance;
526 }
527
528 return gaussRand;
529 }
530
531 }

Properties

Name Value
svn:executable *