ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/brains/ForceManager.cpp
Revision: 1756
Committed: Mon Jun 18 18:23:20 2012 UTC (12 years, 10 months ago) by gezelter
File size: 33102 byte(s)
Log Message:
bugfixes for self interactions (particularly in parallel)

File Contents

# Content
1 /*
2 * Copyright (c) 2005 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. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * This software is provided "AS IS," without a warranty of any
18 * kind. All express or implied conditions, representations and
19 * warranties, including any implied warranty of merchantability,
20 * fitness for a particular purpose or non-infringement, are hereby
21 * excluded. The University of Notre Dame and its licensors shall not
22 * be liable for any damages suffered by licensee as a result of
23 * using, modifying or distributing the software or its
24 * derivatives. In no event will the University of Notre Dame or its
25 * licensors be liable for any lost revenue, profit or data, or for
26 * direct, indirect, special, consequential, incidental or punitive
27 * damages, however caused and regardless of the theory of liability,
28 * arising out of the use of or inability to use software, even if the
29 * University of Notre Dame has been advised of the possibility of
30 * such damages.
31 *
32 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33 * research, please cite the appropriate papers when you publish your
34 * work. Good starting points are:
35 *
36 * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37 * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 * [4] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 */
42
43 /**
44 * @file ForceManager.cpp
45 * @author tlin
46 * @date 11/09/2004
47 * @time 10:39am
48 * @version 1.0
49 */
50
51
52 #include "brains/ForceManager.hpp"
53 #include "primitives/Molecule.hpp"
54 #define __OPENMD_C
55 #include "utils/simError.h"
56 #include "primitives/Bond.hpp"
57 #include "primitives/Bend.hpp"
58 #include "primitives/Torsion.hpp"
59 #include "primitives/Inversion.hpp"
60 #include "nonbonded/NonBondedInteraction.hpp"
61 #include "parallel/ForceMatrixDecomposition.hpp"
62
63 #include <cstdio>
64 #include <iostream>
65 #include <iomanip>
66
67 using namespace std;
68 namespace OpenMD {
69
70 ForceManager::ForceManager(SimInfo * info) : info_(info) {
71 forceField_ = info_->getForceField();
72 interactionMan_ = new InteractionManager();
73 fDecomp_ = new ForceMatrixDecomposition(info_, interactionMan_);
74 }
75
76 /**
77 * setupCutoffs
78 *
79 * Sets the values of cutoffRadius, switchingRadius, cutoffMethod,
80 * and cutoffPolicy
81 *
82 * cutoffRadius : realType
83 * If the cutoffRadius was explicitly set, use that value.
84 * If the cutoffRadius was not explicitly set:
85 * Are there electrostatic atoms? Use 12.0 Angstroms.
86 * No electrostatic atoms? Poll the atom types present in the
87 * simulation for suggested cutoff values (e.g. 2.5 * sigma).
88 * Use the maximum suggested value that was found.
89 *
90 * cutoffMethod : (one of HARD, SWITCHED, SHIFTED_FORCE,
91 * or SHIFTED_POTENTIAL)
92 * If cutoffMethod was explicitly set, use that choice.
93 * If cutoffMethod was not explicitly set, use SHIFTED_FORCE
94 *
95 * cutoffPolicy : (one of MIX, MAX, TRADITIONAL)
96 * If cutoffPolicy was explicitly set, use that choice.
97 * If cutoffPolicy was not explicitly set, use TRADITIONAL
98 *
99 * switchingRadius : realType
100 * If the cutoffMethod was set to SWITCHED:
101 * If the switchingRadius was explicitly set, use that value
102 * (but do a sanity check first).
103 * If the switchingRadius was not explicitly set: use 0.85 *
104 * cutoffRadius_
105 * If the cutoffMethod was not set to SWITCHED:
106 * Set switchingRadius equal to cutoffRadius for safety.
107 */
108 void ForceManager::setupCutoffs() {
109
110 Globals* simParams_ = info_->getSimParams();
111 ForceFieldOptions& forceFieldOptions_ = forceField_->getForceFieldOptions();
112 int mdFileVersion;
113 rCut_ = 0.0; //Needs a value for a later max() call;
114
115 if (simParams_->haveMDfileVersion())
116 mdFileVersion = simParams_->getMDfileVersion();
117 else
118 mdFileVersion = 0;
119
120 if (simParams_->haveCutoffRadius()) {
121 rCut_ = simParams_->getCutoffRadius();
122 } else {
123 if (info_->usesElectrostaticAtoms()) {
124 sprintf(painCave.errMsg,
125 "ForceManager::setupCutoffs: No value was set for the cutoffRadius.\n"
126 "\tOpenMD will use a default value of 12.0 angstroms"
127 "\tfor the cutoffRadius.\n");
128 painCave.isFatal = 0;
129 painCave.severity = OPENMD_INFO;
130 simError();
131 rCut_ = 12.0;
132 } else {
133 RealType thisCut;
134 set<AtomType*>::iterator i;
135 set<AtomType*> atomTypes;
136 atomTypes = info_->getSimulatedAtomTypes();
137 for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
138 thisCut = interactionMan_->getSuggestedCutoffRadius((*i));
139 rCut_ = max(thisCut, rCut_);
140 }
141 sprintf(painCave.errMsg,
142 "ForceManager::setupCutoffs: No value was set for the cutoffRadius.\n"
143 "\tOpenMD will use %lf angstroms.\n",
144 rCut_);
145 painCave.isFatal = 0;
146 painCave.severity = OPENMD_INFO;
147 simError();
148 }
149 }
150
151 fDecomp_->setUserCutoff(rCut_);
152 interactionMan_->setCutoffRadius(rCut_);
153
154 map<string, CutoffMethod> stringToCutoffMethod;
155 stringToCutoffMethod["HARD"] = HARD;
156 stringToCutoffMethod["SWITCHED"] = SWITCHED;
157 stringToCutoffMethod["SHIFTED_POTENTIAL"] = SHIFTED_POTENTIAL;
158 stringToCutoffMethod["SHIFTED_FORCE"] = SHIFTED_FORCE;
159
160 if (simParams_->haveCutoffMethod()) {
161 string cutMeth = toUpperCopy(simParams_->getCutoffMethod());
162 map<string, CutoffMethod>::iterator i;
163 i = stringToCutoffMethod.find(cutMeth);
164 if (i == stringToCutoffMethod.end()) {
165 sprintf(painCave.errMsg,
166 "ForceManager::setupCutoffs: Could not find chosen cutoffMethod %s\n"
167 "\tShould be one of: "
168 "HARD, SWITCHED, SHIFTED_POTENTIAL, or SHIFTED_FORCE\n",
169 cutMeth.c_str());
170 painCave.isFatal = 1;
171 painCave.severity = OPENMD_ERROR;
172 simError();
173 } else {
174 cutoffMethod_ = i->second;
175 }
176 } else {
177 if (mdFileVersion > 1) {
178 sprintf(painCave.errMsg,
179 "ForceManager::setupCutoffs: No value was set for the cutoffMethod.\n"
180 "\tOpenMD will use SHIFTED_FORCE.\n");
181 painCave.isFatal = 0;
182 painCave.severity = OPENMD_INFO;
183 simError();
184 cutoffMethod_ = SHIFTED_FORCE;
185 } else {
186 // handle the case where the old file version was in play
187 // (there should be no cutoffMethod, so we have to deduce it
188 // from other data).
189
190 sprintf(painCave.errMsg,
191 "ForceManager::setupCutoffs : DEPRECATED FILE FORMAT!\n"
192 "\tOpenMD found a file which does not set a cutoffMethod.\n"
193 "\tOpenMD will attempt to deduce a cutoffMethod using the\n"
194 "\tbehavior of the older (version 1) code. To remove this\n"
195 "\twarning, add an explicit cutoffMethod and change the top\n"
196 "\tof the file so that it begins with <OpenMD version=2>\n");
197 painCave.isFatal = 0;
198 painCave.severity = OPENMD_WARNING;
199 simError();
200
201 // The old file version tethered the shifting behavior to the
202 // electrostaticSummationMethod keyword.
203
204 if (simParams_->haveElectrostaticSummationMethod()) {
205 string myMethod = simParams_->getElectrostaticSummationMethod();
206 toUpper(myMethod);
207
208 if (myMethod == "SHIFTED_POTENTIAL") {
209 cutoffMethod_ = SHIFTED_POTENTIAL;
210 } else if (myMethod == "SHIFTED_FORCE") {
211 cutoffMethod_ = SHIFTED_FORCE;
212 }
213
214 if (simParams_->haveSwitchingRadius())
215 rSwitch_ = simParams_->getSwitchingRadius();
216
217 if (myMethod == "SHIFTED_POTENTIAL" || myMethod == "SHIFTED_FORCE") {
218 if (simParams_->haveSwitchingRadius()){
219 sprintf(painCave.errMsg,
220 "ForceManager::setupCutoffs : DEPRECATED ERROR MESSAGE\n"
221 "\tA value was set for the switchingRadius\n"
222 "\teven though the electrostaticSummationMethod was\n"
223 "\tset to %s\n", myMethod.c_str());
224 painCave.severity = OPENMD_WARNING;
225 painCave.isFatal = 1;
226 simError();
227 }
228 }
229 if (abs(rCut_ - rSwitch_) < 0.0001) {
230 if (cutoffMethod_ == SHIFTED_FORCE) {
231 sprintf(painCave.errMsg,
232 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
233 "\tcutoffRadius and switchingRadius are set to the\n"
234 "\tsame value. OpenMD will use shifted force\n"
235 "\tpotentials instead of switching functions.\n");
236 painCave.isFatal = 0;
237 painCave.severity = OPENMD_WARNING;
238 simError();
239 } else {
240 cutoffMethod_ = SHIFTED_POTENTIAL;
241 sprintf(painCave.errMsg,
242 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
243 "\tcutoffRadius and switchingRadius are set to the\n"
244 "\tsame value. OpenMD will use shifted potentials\n"
245 "\tinstead of switching functions.\n");
246 painCave.isFatal = 0;
247 painCave.severity = OPENMD_WARNING;
248 simError();
249 }
250 }
251 }
252 }
253 }
254
255 map<string, CutoffPolicy> stringToCutoffPolicy;
256 stringToCutoffPolicy["MIX"] = MIX;
257 stringToCutoffPolicy["MAX"] = MAX;
258 stringToCutoffPolicy["TRADITIONAL"] = TRADITIONAL;
259
260 string cutPolicy;
261 if (forceFieldOptions_.haveCutoffPolicy()){
262 cutPolicy = forceFieldOptions_.getCutoffPolicy();
263 }else if (simParams_->haveCutoffPolicy()) {
264 cutPolicy = simParams_->getCutoffPolicy();
265 }
266
267 if (!cutPolicy.empty()){
268 toUpper(cutPolicy);
269 map<string, CutoffPolicy>::iterator i;
270 i = stringToCutoffPolicy.find(cutPolicy);
271
272 if (i == stringToCutoffPolicy.end()) {
273 sprintf(painCave.errMsg,
274 "ForceManager::setupCutoffs: Could not find chosen cutoffPolicy %s\n"
275 "\tShould be one of: "
276 "MIX, MAX, or TRADITIONAL\n",
277 cutPolicy.c_str());
278 painCave.isFatal = 1;
279 painCave.severity = OPENMD_ERROR;
280 simError();
281 } else {
282 cutoffPolicy_ = i->second;
283 }
284 } else {
285 sprintf(painCave.errMsg,
286 "ForceManager::setupCutoffs: No value was set for the cutoffPolicy.\n"
287 "\tOpenMD will use TRADITIONAL.\n");
288 painCave.isFatal = 0;
289 painCave.severity = OPENMD_INFO;
290 simError();
291 cutoffPolicy_ = TRADITIONAL;
292 }
293
294 fDecomp_->setCutoffPolicy(cutoffPolicy_);
295
296 // create the switching function object:
297
298 switcher_ = new SwitchingFunction();
299
300 if (cutoffMethod_ == SWITCHED) {
301 if (simParams_->haveSwitchingRadius()) {
302 rSwitch_ = simParams_->getSwitchingRadius();
303 if (rSwitch_ > rCut_) {
304 sprintf(painCave.errMsg,
305 "ForceManager::setupCutoffs: switchingRadius (%f) is larger "
306 "than the cutoffRadius(%f)\n", rSwitch_, rCut_);
307 painCave.isFatal = 1;
308 painCave.severity = OPENMD_ERROR;
309 simError();
310 }
311 } else {
312 rSwitch_ = 0.85 * rCut_;
313 sprintf(painCave.errMsg,
314 "ForceManager::setupCutoffs: No value was set for the switchingRadius.\n"
315 "\tOpenMD will use a default value of 85 percent of the cutoffRadius.\n"
316 "\tswitchingRadius = %f. for this simulation\n", rSwitch_);
317 painCave.isFatal = 0;
318 painCave.severity = OPENMD_WARNING;
319 simError();
320 }
321 } else {
322 if (mdFileVersion > 1) {
323 // throw an error if we define a switching radius and don't need one.
324 // older file versions should not do this.
325 if (simParams_->haveSwitchingRadius()) {
326 map<string, CutoffMethod>::const_iterator it;
327 string theMeth;
328 for (it = stringToCutoffMethod.begin();
329 it != stringToCutoffMethod.end(); ++it) {
330 if (it->second == cutoffMethod_) {
331 theMeth = it->first;
332 break;
333 }
334 }
335 sprintf(painCave.errMsg,
336 "ForceManager::setupCutoffs: the cutoffMethod (%s)\n"
337 "\tis not set to SWITCHED, so switchingRadius value\n"
338 "\twill be ignored for this simulation\n", theMeth.c_str());
339 painCave.isFatal = 0;
340 painCave.severity = OPENMD_WARNING;
341 simError();
342 }
343 }
344 rSwitch_ = rCut_;
345 }
346
347 // Default to cubic switching function.
348 sft_ = cubic;
349 if (simParams_->haveSwitchingFunctionType()) {
350 string funcType = simParams_->getSwitchingFunctionType();
351 toUpper(funcType);
352 if (funcType == "CUBIC") {
353 sft_ = cubic;
354 } else {
355 if (funcType == "FIFTH_ORDER_POLYNOMIAL") {
356 sft_ = fifth_order_poly;
357 } else {
358 // throw error
359 sprintf( painCave.errMsg,
360 "ForceManager::setupSwitching : Unknown switchingFunctionType. (Input file specified %s .)\n"
361 "\tswitchingFunctionType must be one of: "
362 "\"cubic\" or \"fifth_order_polynomial\".",
363 funcType.c_str() );
364 painCave.isFatal = 1;
365 painCave.severity = OPENMD_ERROR;
366 simError();
367 }
368 }
369 }
370 switcher_->setSwitchType(sft_);
371 switcher_->setSwitch(rSwitch_, rCut_);
372 interactionMan_->setSwitchingRadius(rSwitch_);
373 }
374
375
376
377
378 void ForceManager::initialize() {
379
380 if (!info_->isTopologyDone()) {
381
382 info_->update();
383 interactionMan_->setSimInfo(info_);
384 interactionMan_->initialize();
385
386 // We want to delay the cutoffs until after the interaction
387 // manager has set up the atom-atom interactions so that we can
388 // query them for suggested cutoff values
389 setupCutoffs();
390
391 info_->prepareTopology();
392
393 doParticlePot_ = info_->getSimParams()->getOutputParticlePotential();
394 doHeatFlux_ = info_->getSimParams()->getPrintHeatFlux();
395 if (doHeatFlux_) doParticlePot_ = true;
396
397 }
398
399 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
400
401 // Force fields can set options on how to scale van der Waals and
402 // electrostatic interactions for atoms connected via bonds, bends
403 // and torsions in this case the topological distance between
404 // atoms is:
405 // 0 = topologically unconnected
406 // 1 = bonded together
407 // 2 = connected via a bend
408 // 3 = connected via a torsion
409
410 vdwScale_.reserve(4);
411 fill(vdwScale_.begin(), vdwScale_.end(), 0.0);
412
413 electrostaticScale_.reserve(4);
414 fill(electrostaticScale_.begin(), electrostaticScale_.end(), 0.0);
415
416 vdwScale_[0] = 1.0;
417 vdwScale_[1] = fopts.getvdw12scale();
418 vdwScale_[2] = fopts.getvdw13scale();
419 vdwScale_[3] = fopts.getvdw14scale();
420
421 electrostaticScale_[0] = 1.0;
422 electrostaticScale_[1] = fopts.getelectrostatic12scale();
423 electrostaticScale_[2] = fopts.getelectrostatic13scale();
424 electrostaticScale_[3] = fopts.getelectrostatic14scale();
425
426 fDecomp_->distributeInitialData();
427
428 initialized_ = true;
429
430 }
431
432 void ForceManager::calcForces() {
433
434 if (!initialized_) initialize();
435
436 preCalculation();
437 shortRangeInteractions();
438 longRangeInteractions();
439 postCalculation();
440 }
441
442 void ForceManager::preCalculation() {
443 SimInfo::MoleculeIterator mi;
444 Molecule* mol;
445 Molecule::AtomIterator ai;
446 Atom* atom;
447 Molecule::RigidBodyIterator rbIter;
448 RigidBody* rb;
449 Molecule::CutoffGroupIterator ci;
450 CutoffGroup* cg;
451
452 // forces are zeroed here, before any are accumulated.
453
454 for (mol = info_->beginMolecule(mi); mol != NULL;
455 mol = info_->nextMolecule(mi)) {
456 for(atom = mol->beginAtom(ai); atom != NULL;
457 atom = mol->nextAtom(ai)) {
458 atom->zeroForcesAndTorques();
459 }
460
461 //change the positions of atoms which belong to the rigidbodies
462 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
463 rb = mol->nextRigidBody(rbIter)) {
464 rb->zeroForcesAndTorques();
465 }
466
467 if(info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()){
468 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
469 cg = mol->nextCutoffGroup(ci)) {
470 //calculate the center of mass of cutoff group
471 cg->updateCOM();
472 }
473 }
474 }
475
476 // Zero out the stress tensor
477 stressTensor *= 0.0;
478 // Zero out the heatFlux
479 fDecomp_->setHeatFlux( Vector3d(0.0) );
480 }
481
482 void ForceManager::shortRangeInteractions() {
483 Molecule* mol;
484 RigidBody* rb;
485 Bond* bond;
486 Bend* bend;
487 Torsion* torsion;
488 Inversion* inversion;
489 SimInfo::MoleculeIterator mi;
490 Molecule::RigidBodyIterator rbIter;
491 Molecule::BondIterator bondIter;;
492 Molecule::BendIterator bendIter;
493 Molecule::TorsionIterator torsionIter;
494 Molecule::InversionIterator inversionIter;
495 RealType bondPotential = 0.0;
496 RealType bendPotential = 0.0;
497 RealType torsionPotential = 0.0;
498 RealType inversionPotential = 0.0;
499
500 //calculate short range interactions
501 for (mol = info_->beginMolecule(mi); mol != NULL;
502 mol = info_->nextMolecule(mi)) {
503
504 //change the positions of atoms which belong to the rigidbodies
505 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
506 rb = mol->nextRigidBody(rbIter)) {
507 rb->updateAtoms();
508 }
509
510 for (bond = mol->beginBond(bondIter); bond != NULL;
511 bond = mol->nextBond(bondIter)) {
512 bond->calcForce(doParticlePot_);
513 bondPotential += bond->getPotential();
514 }
515
516 for (bend = mol->beginBend(bendIter); bend != NULL;
517 bend = mol->nextBend(bendIter)) {
518
519 RealType angle;
520 bend->calcForce(angle, doParticlePot_);
521 RealType currBendPot = bend->getPotential();
522
523 bendPotential += bend->getPotential();
524 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
525 if (i == bendDataSets.end()) {
526 BendDataSet dataSet;
527 dataSet.prev.angle = dataSet.curr.angle = angle;
528 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
529 dataSet.deltaV = 0.0;
530 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend,
531 dataSet));
532 }else {
533 i->second.prev.angle = i->second.curr.angle;
534 i->second.prev.potential = i->second.curr.potential;
535 i->second.curr.angle = angle;
536 i->second.curr.potential = currBendPot;
537 i->second.deltaV = fabs(i->second.curr.potential -
538 i->second.prev.potential);
539 }
540 }
541
542 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
543 torsion = mol->nextTorsion(torsionIter)) {
544 RealType angle;
545 torsion->calcForce(angle, doParticlePot_);
546 RealType currTorsionPot = torsion->getPotential();
547 torsionPotential += torsion->getPotential();
548 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
549 if (i == torsionDataSets.end()) {
550 TorsionDataSet dataSet;
551 dataSet.prev.angle = dataSet.curr.angle = angle;
552 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
553 dataSet.deltaV = 0.0;
554 torsionDataSets.insert(map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
555 }else {
556 i->second.prev.angle = i->second.curr.angle;
557 i->second.prev.potential = i->second.curr.potential;
558 i->second.curr.angle = angle;
559 i->second.curr.potential = currTorsionPot;
560 i->second.deltaV = fabs(i->second.curr.potential -
561 i->second.prev.potential);
562 }
563 }
564
565 for (inversion = mol->beginInversion(inversionIter);
566 inversion != NULL;
567 inversion = mol->nextInversion(inversionIter)) {
568 RealType angle;
569 inversion->calcForce(angle, doParticlePot_);
570 RealType currInversionPot = inversion->getPotential();
571 inversionPotential += inversion->getPotential();
572 map<Inversion*, InversionDataSet>::iterator i = inversionDataSets.find(inversion);
573 if (i == inversionDataSets.end()) {
574 InversionDataSet dataSet;
575 dataSet.prev.angle = dataSet.curr.angle = angle;
576 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
577 dataSet.deltaV = 0.0;
578 inversionDataSets.insert(map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
579 }else {
580 i->second.prev.angle = i->second.curr.angle;
581 i->second.prev.potential = i->second.curr.potential;
582 i->second.curr.angle = angle;
583 i->second.curr.potential = currInversionPot;
584 i->second.deltaV = fabs(i->second.curr.potential -
585 i->second.prev.potential);
586 }
587 }
588 }
589
590 RealType shortRangePotential = bondPotential + bendPotential +
591 torsionPotential + inversionPotential;
592 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
593 curSnapshot->statData[Stats::SHORT_RANGE_POTENTIAL] = shortRangePotential;
594 curSnapshot->statData[Stats::BOND_POTENTIAL] = bondPotential;
595 curSnapshot->statData[Stats::BEND_POTENTIAL] = bendPotential;
596 curSnapshot->statData[Stats::DIHEDRAL_POTENTIAL] = torsionPotential;
597 curSnapshot->statData[Stats::INVERSION_POTENTIAL] = inversionPotential;
598 }
599
600 void ForceManager::longRangeInteractions() {
601
602
603 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
604 DataStorage* config = &(curSnapshot->atomData);
605 DataStorage* cgConfig = &(curSnapshot->cgData);
606
607 //calculate the center of mass of cutoff group
608
609 SimInfo::MoleculeIterator mi;
610 Molecule* mol;
611 Molecule::CutoffGroupIterator ci;
612 CutoffGroup* cg;
613
614 if(info_->getNCutoffGroups() > 0){
615 for (mol = info_->beginMolecule(mi); mol != NULL;
616 mol = info_->nextMolecule(mi)) {
617 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
618 cg = mol->nextCutoffGroup(ci)) {
619 cg->updateCOM();
620 }
621 }
622 } else {
623 // center of mass of the group is the same as position of the atom
624 // if cutoff group does not exist
625 cgConfig->position = config->position;
626 cgConfig->velocity = config->velocity;
627 }
628
629 fDecomp_->zeroWorkArrays();
630 fDecomp_->distributeData();
631
632 int cg1, cg2, atom1, atom2, topoDist;
633 Vector3d d_grp, dag, d, gvel2, vel2;
634 RealType rgrpsq, rgrp, r2, r;
635 RealType electroMult, vdwMult;
636 RealType vij;
637 Vector3d fij, fg, f1;
638 tuple3<RealType, RealType, RealType> cuts;
639 RealType rCutSq;
640 bool in_switching_region;
641 RealType sw, dswdr, swderiv;
642 vector<int> atomListColumn, atomListRow, atomListLocal;
643 InteractionData idat;
644 SelfData sdat;
645 RealType mf;
646 RealType lrPot;
647 RealType vpair;
648 RealType dVdFQ1(0.0);
649 RealType dVdFQ2(0.0);
650 potVec longRangePotential(0.0);
651 potVec workPot(0.0);
652 vector<int>::iterator ia, jb;
653
654 int loopStart, loopEnd;
655
656 idat.vdwMult = &vdwMult;
657 idat.electroMult = &electroMult;
658 idat.pot = &workPot;
659 sdat.pot = fDecomp_->getEmbeddingPotential();
660 idat.vpair = &vpair;
661 idat.dVdFQ1 = &dVdFQ1;
662 idat.dVdFQ2 = &dVdFQ2;
663 idat.f1 = &f1;
664 idat.sw = &sw;
665 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ? true : false;
666 idat.shiftedForce = (cutoffMethod_ == SHIFTED_FORCE) ? true : false;
667 idat.doParticlePot = doParticlePot_;
668 sdat.doParticlePot = doParticlePot_;
669
670 loopEnd = PAIR_LOOP;
671 if (info_->requiresPrepair() ) {
672 loopStart = PREPAIR_LOOP;
673 } else {
674 loopStart = PAIR_LOOP;
675 }
676 for (int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
677
678 if (iLoop == loopStart) {
679 bool update_nlist = fDecomp_->checkNeighborList();
680 if (update_nlist)
681 neighborList = fDecomp_->buildNeighborList();
682 }
683
684 for (vector<pair<int, int> >::iterator it = neighborList.begin();
685 it != neighborList.end(); ++it) {
686
687 cg1 = (*it).first;
688 cg2 = (*it).second;
689
690 cuts = fDecomp_->getGroupCutoffs(cg1, cg2);
691
692 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
693
694 curSnapshot->wrapVector(d_grp);
695 rgrpsq = d_grp.lengthSquare();
696 rCutSq = cuts.second;
697
698 if (rgrpsq < rCutSq) {
699 idat.rcut = &cuts.first;
700 if (iLoop == PAIR_LOOP) {
701 vij = 0.0;
702 fij = V3Zero;
703 }
704
705 in_switching_region = switcher_->getSwitch(rgrpsq, sw, dswdr,
706 rgrp);
707
708 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
709 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
710
711 if (doHeatFlux_)
712 gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
713
714 for (ia = atomListRow.begin();
715 ia != atomListRow.end(); ++ia) {
716 atom1 = (*ia);
717
718 for (jb = atomListColumn.begin();
719 jb != atomListColumn.end(); ++jb) {
720 atom2 = (*jb);
721
722 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
723
724 vpair = 0.0;
725 workPot = 0.0;
726 f1 = V3Zero;
727 dVdFQ1 = 0.0;
728 dVdFQ2 = 0.0;
729
730 fDecomp_->fillInteractionData(idat, atom1, atom2);
731
732 topoDist = fDecomp_->getTopologicalDistance(atom1, atom2);
733 vdwMult = vdwScale_[topoDist];
734 electroMult = electrostaticScale_[topoDist];
735
736 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
737 idat.d = &d_grp;
738 idat.r2 = &rgrpsq;
739 if (doHeatFlux_)
740 vel2 = gvel2;
741 } else {
742 d = fDecomp_->getInteratomicVector(atom1, atom2);
743 curSnapshot->wrapVector( d );
744 r2 = d.lengthSquare();
745 idat.d = &d;
746 idat.r2 = &r2;
747 if (doHeatFlux_)
748 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
749 }
750
751 r = sqrt( *(idat.r2) );
752 idat.rij = &r;
753
754 if (iLoop == PREPAIR_LOOP) {
755 interactionMan_->doPrePair(idat);
756 } else {
757 interactionMan_->doPair(idat);
758 fDecomp_->unpackInteractionData(idat, atom1, atom2);
759 vij += vpair;
760 fij += f1;
761 stressTensor -= outProduct( *(idat.d), f1);
762 if (doHeatFlux_)
763 fDecomp_->addToHeatFlux(*(idat.d) * dot(f1, vel2));
764 }
765 }
766 }
767 }
768
769 if (iLoop == PAIR_LOOP) {
770 if (in_switching_region) {
771 swderiv = vij * dswdr / rgrp;
772 fg = swderiv * d_grp;
773 fij += fg;
774
775 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
776 stressTensor -= outProduct( *(idat.d), fg);
777 if (doHeatFlux_)
778 fDecomp_->addToHeatFlux(*(idat.d) * dot(fg, vel2));
779
780 }
781
782 for (ia = atomListRow.begin();
783 ia != atomListRow.end(); ++ia) {
784 atom1 = (*ia);
785 mf = fDecomp_->getMassFactorRow(atom1);
786 // fg is the force on atom ia due to cutoff group's
787 // presence in switching region
788 fg = swderiv * d_grp * mf;
789 fDecomp_->addForceToAtomRow(atom1, fg);
790 if (atomListRow.size() > 1) {
791 if (info_->usesAtomicVirial()) {
792 // find the distance between the atom
793 // and the center of the cutoff group:
794 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
795 stressTensor -= outProduct(dag, fg);
796 if (doHeatFlux_)
797 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
798 }
799 }
800 }
801 for (jb = atomListColumn.begin();
802 jb != atomListColumn.end(); ++jb) {
803 atom2 = (*jb);
804 mf = fDecomp_->getMassFactorColumn(atom2);
805 // fg is the force on atom jb due to cutoff group's
806 // presence in switching region
807 fg = -swderiv * d_grp * mf;
808 fDecomp_->addForceToAtomColumn(atom2, fg);
809
810 if (atomListColumn.size() > 1) {
811 if (info_->usesAtomicVirial()) {
812 // find the distance between the atom
813 // and the center of the cutoff group:
814 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
815 stressTensor -= outProduct(dag, fg);
816 if (doHeatFlux_)
817 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
818 }
819 }
820 }
821 }
822 //if (!info_->usesAtomicVirial()) {
823 // stressTensor -= outProduct(d_grp, fij);
824 // if (doHeatFlux_)
825 // fDecomp_->addToHeatFlux( d_grp * dot(fij, vel2));
826 //}
827 }
828 }
829 }
830
831 if (iLoop == PREPAIR_LOOP) {
832 if (info_->requiresPrepair()) {
833
834 fDecomp_->collectIntermediateData();
835
836 for (int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
837 fDecomp_->fillSelfData(sdat, atom1);
838 interactionMan_->doPreForce(sdat);
839 }
840
841 fDecomp_->distributeIntermediateData();
842
843 }
844 }
845 }
846
847 // collects pairwise information
848 fDecomp_->collectData();
849
850 if (info_->requiresSelfCorrection()) {
851 for (int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
852 fDecomp_->fillSelfData(sdat, atom1);
853 interactionMan_->doSelfCorrection(sdat);
854 }
855 }
856
857 // collects single-atom information
858 fDecomp_->collectSelfData();
859
860 longRangePotential = *(fDecomp_->getEmbeddingPotential()) +
861 *(fDecomp_->getPairwisePotential());
862
863 lrPot = longRangePotential.sum();
864
865 //store the stressTensor and long range potential
866 curSnapshot->statData[Stats::LONG_RANGE_POTENTIAL] = lrPot;
867 curSnapshot->statData[Stats::VANDERWAALS_POTENTIAL] = longRangePotential[VANDERWAALS_FAMILY];
868 curSnapshot->statData[Stats::ELECTROSTATIC_POTENTIAL] = longRangePotential[ELECTROSTATIC_FAMILY];
869 }
870
871
872 void ForceManager::postCalculation() {
873 SimInfo::MoleculeIterator mi;
874 Molecule* mol;
875 Molecule::RigidBodyIterator rbIter;
876 RigidBody* rb;
877 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
878
879 // collect the atomic forces onto rigid bodies
880
881 for (mol = info_->beginMolecule(mi); mol != NULL;
882 mol = info_->nextMolecule(mi)) {
883 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
884 rb = mol->nextRigidBody(rbIter)) {
885 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
886 stressTensor += rbTau;
887 }
888 }
889
890 #ifdef IS_MPI
891 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, stressTensor.getArrayPointer(), 9,
892 MPI::REALTYPE, MPI::SUM);
893 #endif
894 curSnapshot->setStressTensor(stressTensor);
895
896 }
897
898 } //end namespace OpenMD

Properties

Name Value
svn:executable *
svn:keywords Author Id Revision Date