ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/brains/ForceManager.cpp
Revision: 1761
Committed: Fri Jun 22 20:01:37 2012 UTC (12 years, 10 months ago) by gezelter
File size: 33845 byte(s)
Log Message:
fixes for fluctuating charges

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 #ifdef IS_MPI
591 // Collect from all nodes. This should eventually be moved into a
592 // SystemDecomposition, but this is a better place than in
593 // Thermo to do the collection.
594 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &bondPotential, 1, MPI::REALTYPE,
595 MPI::SUM);
596 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &bendPotential, 1, MPI::REALTYPE,
597 MPI::SUM);
598 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &torsionPotential, 1,
599 MPI::REALTYPE, MPI::SUM);
600 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &inversionPotential, 1,
601 MPI::REALTYPE, MPI::SUM);
602 #endif
603
604 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
605
606 curSnapshot->setBondPotential(bondPotential);
607 curSnapshot->setBendPotential(bendPotential);
608 curSnapshot->setTorsionPotential(torsionPotential);
609 curSnapshot->setInversionPotential(inversionPotential);
610
611 RealType shortRangePotential = bondPotential + bendPotential +
612 torsionPotential + inversionPotential;
613
614 curSnapshot->setShortRangePotential(shortRangePotential);
615 }
616
617 void ForceManager::longRangeInteractions() {
618
619
620 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
621 DataStorage* config = &(curSnapshot->atomData);
622 DataStorage* cgConfig = &(curSnapshot->cgData);
623
624 //calculate the center of mass of cutoff group
625
626 SimInfo::MoleculeIterator mi;
627 Molecule* mol;
628 Molecule::CutoffGroupIterator ci;
629 CutoffGroup* cg;
630
631 if(info_->getNCutoffGroups() > 0){
632 for (mol = info_->beginMolecule(mi); mol != NULL;
633 mol = info_->nextMolecule(mi)) {
634 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
635 cg = mol->nextCutoffGroup(ci)) {
636 cg->updateCOM();
637 }
638 }
639 } else {
640 // center of mass of the group is the same as position of the atom
641 // if cutoff group does not exist
642 cgConfig->position = config->position;
643 cgConfig->velocity = config->velocity;
644 }
645
646 fDecomp_->zeroWorkArrays();
647 fDecomp_->distributeData();
648
649 int cg1, cg2, atom1, atom2, topoDist;
650 Vector3d d_grp, dag, d, gvel2, vel2;
651 RealType rgrpsq, rgrp, r2, r;
652 RealType electroMult, vdwMult;
653 RealType vij;
654 Vector3d fij, fg, f1;
655 tuple3<RealType, RealType, RealType> cuts;
656 RealType rCutSq;
657 bool in_switching_region;
658 RealType sw, dswdr, swderiv;
659 vector<int> atomListColumn, atomListRow, atomListLocal;
660 InteractionData idat;
661 SelfData sdat;
662 RealType mf;
663 RealType lrPot;
664 RealType vpair;
665 RealType dVdFQ1(0.0);
666 RealType dVdFQ2(0.0);
667 potVec longRangePotential(0.0);
668 potVec workPot(0.0);
669 potVec exPot(0.0);
670 vector<int>::iterator ia, jb;
671
672 int loopStart, loopEnd;
673
674 idat.vdwMult = &vdwMult;
675 idat.electroMult = &electroMult;
676 idat.pot = &workPot;
677 idat.excludedPot = &exPot;
678 sdat.pot = fDecomp_->getEmbeddingPotential();
679 sdat.excludedPot = fDecomp_->getExcludedSelfPotential();
680 idat.vpair = &vpair;
681 idat.dVdFQ1 = &dVdFQ1;
682 idat.dVdFQ2 = &dVdFQ2;
683 idat.f1 = &f1;
684 idat.sw = &sw;
685 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ? true : false;
686 idat.shiftedForce = (cutoffMethod_ == SHIFTED_FORCE) ? true : false;
687 idat.doParticlePot = doParticlePot_;
688 sdat.doParticlePot = doParticlePot_;
689
690 loopEnd = PAIR_LOOP;
691 if (info_->requiresPrepair() ) {
692 loopStart = PREPAIR_LOOP;
693 } else {
694 loopStart = PAIR_LOOP;
695 }
696 for (int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
697
698 if (iLoop == loopStart) {
699 bool update_nlist = fDecomp_->checkNeighborList();
700 if (update_nlist)
701 neighborList = fDecomp_->buildNeighborList();
702 }
703
704 for (vector<pair<int, int> >::iterator it = neighborList.begin();
705 it != neighborList.end(); ++it) {
706
707 cg1 = (*it).first;
708 cg2 = (*it).second;
709
710 cuts = fDecomp_->getGroupCutoffs(cg1, cg2);
711
712 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
713
714 curSnapshot->wrapVector(d_grp);
715 rgrpsq = d_grp.lengthSquare();
716 rCutSq = cuts.second;
717
718 if (rgrpsq < rCutSq) {
719 idat.rcut = &cuts.first;
720 if (iLoop == PAIR_LOOP) {
721 vij = 0.0;
722 fij = V3Zero;
723 }
724
725 in_switching_region = switcher_->getSwitch(rgrpsq, sw, dswdr,
726 rgrp);
727
728 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
729 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
730
731 if (doHeatFlux_)
732 gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
733
734 for (ia = atomListRow.begin();
735 ia != atomListRow.end(); ++ia) {
736 atom1 = (*ia);
737
738 for (jb = atomListColumn.begin();
739 jb != atomListColumn.end(); ++jb) {
740 atom2 = (*jb);
741
742 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
743
744 vpair = 0.0;
745 workPot = 0.0;
746 exPot = 0.0;
747 f1 = V3Zero;
748 dVdFQ1 = 0.0;
749 dVdFQ2 = 0.0;
750
751 fDecomp_->fillInteractionData(idat, atom1, atom2);
752
753 topoDist = fDecomp_->getTopologicalDistance(atom1, atom2);
754 vdwMult = vdwScale_[topoDist];
755 electroMult = electrostaticScale_[topoDist];
756
757 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
758 idat.d = &d_grp;
759 idat.r2 = &rgrpsq;
760 if (doHeatFlux_)
761 vel2 = gvel2;
762 } else {
763 d = fDecomp_->getInteratomicVector(atom1, atom2);
764 curSnapshot->wrapVector( d );
765 r2 = d.lengthSquare();
766 idat.d = &d;
767 idat.r2 = &r2;
768 if (doHeatFlux_)
769 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
770 }
771
772 r = sqrt( *(idat.r2) );
773 idat.rij = &r;
774
775 if (iLoop == PREPAIR_LOOP) {
776 interactionMan_->doPrePair(idat);
777 } else {
778 interactionMan_->doPair(idat);
779 fDecomp_->unpackInteractionData(idat, atom1, atom2);
780 vij += vpair;
781 fij += f1;
782 stressTensor -= outProduct( *(idat.d), f1);
783 if (doHeatFlux_)
784 fDecomp_->addToHeatFlux(*(idat.d) * dot(f1, vel2));
785 }
786 }
787 }
788 }
789
790 if (iLoop == PAIR_LOOP) {
791 if (in_switching_region) {
792 swderiv = vij * dswdr / rgrp;
793 fg = swderiv * d_grp;
794 fij += fg;
795
796 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
797 stressTensor -= outProduct( *(idat.d), fg);
798 if (doHeatFlux_)
799 fDecomp_->addToHeatFlux(*(idat.d) * dot(fg, vel2));
800
801 }
802
803 for (ia = atomListRow.begin();
804 ia != atomListRow.end(); ++ia) {
805 atom1 = (*ia);
806 mf = fDecomp_->getMassFactorRow(atom1);
807 // fg is the force on atom ia due to cutoff group's
808 // presence in switching region
809 fg = swderiv * d_grp * mf;
810 fDecomp_->addForceToAtomRow(atom1, fg);
811 if (atomListRow.size() > 1) {
812 if (info_->usesAtomicVirial()) {
813 // find the distance between the atom
814 // and the center of the cutoff group:
815 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
816 stressTensor -= outProduct(dag, fg);
817 if (doHeatFlux_)
818 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
819 }
820 }
821 }
822 for (jb = atomListColumn.begin();
823 jb != atomListColumn.end(); ++jb) {
824 atom2 = (*jb);
825 mf = fDecomp_->getMassFactorColumn(atom2);
826 // fg is the force on atom jb due to cutoff group's
827 // presence in switching region
828 fg = -swderiv * d_grp * mf;
829 fDecomp_->addForceToAtomColumn(atom2, fg);
830
831 if (atomListColumn.size() > 1) {
832 if (info_->usesAtomicVirial()) {
833 // find the distance between the atom
834 // and the center of the cutoff group:
835 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
836 stressTensor -= outProduct(dag, fg);
837 if (doHeatFlux_)
838 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
839 }
840 }
841 }
842 }
843 //if (!info_->usesAtomicVirial()) {
844 // stressTensor -= outProduct(d_grp, fij);
845 // if (doHeatFlux_)
846 // fDecomp_->addToHeatFlux( d_grp * dot(fij, vel2));
847 //}
848 }
849 }
850 }
851
852 if (iLoop == PREPAIR_LOOP) {
853 if (info_->requiresPrepair()) {
854
855 fDecomp_->collectIntermediateData();
856
857 for (int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
858 fDecomp_->fillSelfData(sdat, atom1);
859 interactionMan_->doPreForce(sdat);
860 }
861
862 fDecomp_->distributeIntermediateData();
863
864 }
865 }
866 }
867
868 // collects pairwise information
869 fDecomp_->collectData();
870
871 if (info_->requiresSelfCorrection()) {
872 for (int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
873 fDecomp_->fillSelfData(sdat, atom1);
874 interactionMan_->doSelfCorrection(sdat);
875 }
876 }
877
878 // collects single-atom information
879 fDecomp_->collectSelfData();
880
881 longRangePotential = *(fDecomp_->getEmbeddingPotential()) +
882 *(fDecomp_->getPairwisePotential());
883
884 curSnapshot->setLongRangePotentialFamilies(longRangePotential);
885
886 lrPot = longRangePotential.sum();
887
888 //store the long range potential
889 curSnapshot->setLongRangePotential(lrPot);
890
891 curSnapshot->setExcludedPotentials(*(fDecomp_->getExcludedSelfPotential()) +
892 *(fDecomp_->getExcludedPotential()));
893
894 }
895
896
897 void ForceManager::postCalculation() {
898 SimInfo::MoleculeIterator mi;
899 Molecule* mol;
900 Molecule::RigidBodyIterator rbIter;
901 RigidBody* rb;
902 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
903
904 // collect the atomic forces onto rigid bodies
905
906 for (mol = info_->beginMolecule(mi); mol != NULL;
907 mol = info_->nextMolecule(mi)) {
908 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
909 rb = mol->nextRigidBody(rbIter)) {
910 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
911 stressTensor += rbTau;
912 }
913 }
914
915 #ifdef IS_MPI
916 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, stressTensor.getArrayPointer(), 9,
917 MPI::REALTYPE, MPI::SUM);
918 #endif
919 curSnapshot->setStressTensor(stressTensor);
920
921 }
922
923 } //end namespace OpenMD

Properties

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