ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/brains/ForceManager.cpp
Revision: 2057
Committed: Tue Mar 3 15:22:26 2015 UTC (10 years, 1 month ago) by gezelter
File size: 37086 byte(s)
Log Message:
Performance improvements, Removed CutoffPolicy

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, 234107 (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 * @version 1.0
48 */
49
50
51 #include "brains/ForceManager.hpp"
52 #include "primitives/Molecule.hpp"
53 #define __OPENMD_C
54 #include "utils/simError.h"
55 #include "primitives/Bond.hpp"
56 #include "primitives/Bend.hpp"
57 #include "primitives/Torsion.hpp"
58 #include "primitives/Inversion.hpp"
59 #include "nonbonded/NonBondedInteraction.hpp"
60 #include "perturbations/UniformField.hpp"
61 #include "perturbations/UniformGradient.hpp"
62 #include "parallel/ForceMatrixDecomposition.hpp"
63
64 #include <cstdio>
65 #include <iostream>
66 #include <iomanip>
67
68 using namespace std;
69 namespace OpenMD {
70
71 ForceManager::ForceManager(SimInfo * info) : info_(info), switcher_(NULL),
72 initialized_(false) {
73 forceField_ = info_->getForceField();
74 interactionMan_ = new InteractionManager();
75 fDecomp_ = new ForceMatrixDecomposition(info_, interactionMan_);
76 thermo = new Thermo(info_);
77 }
78
79 ForceManager::~ForceManager() {
80 perturbations_.clear();
81
82 delete switcher_;
83 delete interactionMan_;
84 delete fDecomp_;
85 delete thermo;
86 }
87
88 /**
89 * setupCutoffs
90 *
91 * Sets the values of cutoffRadius, switchingRadius, and cutoffMethod
92 *
93 * cutoffRadius : realType
94 * If the cutoffRadius was explicitly set, use that value.
95 * If the cutoffRadius was not explicitly set:
96 * Are there electrostatic atoms? Use 12.0 Angstroms.
97 * No electrostatic atoms? Poll the atom types present in the
98 * simulation for suggested cutoff values (e.g. 2.5 * sigma).
99 * Use the maximum suggested value that was found.
100 *
101 * cutoffMethod : (one of HARD, SWITCHED, SHIFTED_FORCE, TAYLOR_SHIFTED,
102 * SHIFTED_POTENTIAL, or EWALD_FULL)
103 * If cutoffMethod was explicitly set, use that choice.
104 * If cutoffMethod was not explicitly set, use SHIFTED_FORCE
105 *
106 * switchingRadius : realType
107 * If the cutoffMethod was set to SWITCHED:
108 * If the switchingRadius was explicitly set, use that value
109 * (but do a sanity check first).
110 * If the switchingRadius was not explicitly set: use 0.85 *
111 * cutoffRadius_
112 * If the cutoffMethod was not set to SWITCHED:
113 * Set switchingRadius equal to cutoffRadius for safety.
114 */
115 void ForceManager::setupCutoffs() {
116
117 Globals* simParams_ = info_->getSimParams();
118 ForceFieldOptions& forceFieldOptions_ = forceField_->getForceFieldOptions();
119 int mdFileVersion;
120 rCut_ = 0.0; //Needs a value for a later max() call;
121
122 if (simParams_->haveMDfileVersion())
123 mdFileVersion = simParams_->getMDfileVersion();
124 else
125 mdFileVersion = 0;
126
127 // We need the list of simulated atom types to figure out cutoffs
128 // as well as long range corrections.
129
130 set<AtomType*>::iterator i;
131 set<AtomType*> atomTypes_;
132 atomTypes_ = info_->getSimulatedAtomTypes();
133
134 if (simParams_->haveCutoffRadius()) {
135 rCut_ = simParams_->getCutoffRadius();
136 } else {
137 if (info_->usesElectrostaticAtoms()) {
138 sprintf(painCave.errMsg,
139 "ForceManager::setupCutoffs: No value was set for the cutoffRadius.\n"
140 "\tOpenMD will use a default value of 12.0 angstroms"
141 "\tfor the cutoffRadius.\n");
142 painCave.isFatal = 0;
143 painCave.severity = OPENMD_INFO;
144 simError();
145 rCut_ = 12.0;
146 } else {
147 RealType thisCut;
148 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
149 thisCut = interactionMan_->getSuggestedCutoffRadius((*i));
150 rCut_ = max(thisCut, rCut_);
151 }
152 sprintf(painCave.errMsg,
153 "ForceManager::setupCutoffs: No value was set for the cutoffRadius.\n"
154 "\tOpenMD will use %lf angstroms.\n",
155 rCut_);
156 painCave.isFatal = 0;
157 painCave.severity = OPENMD_INFO;
158 simError();
159 }
160 }
161
162 fDecomp_->setCutoffRadius(rCut_);
163 interactionMan_->setCutoffRadius(rCut_);
164 rCutSq_ = rCut_ * rCut_;
165
166 map<string, CutoffMethod> stringToCutoffMethod;
167 stringToCutoffMethod["HARD"] = HARD;
168 stringToCutoffMethod["SWITCHED"] = SWITCHED;
169 stringToCutoffMethod["SHIFTED_POTENTIAL"] = SHIFTED_POTENTIAL;
170 stringToCutoffMethod["SHIFTED_FORCE"] = SHIFTED_FORCE;
171 stringToCutoffMethod["TAYLOR_SHIFTED"] = TAYLOR_SHIFTED;
172 stringToCutoffMethod["EWALD_FULL"] = EWALD_FULL;
173
174 if (simParams_->haveCutoffMethod()) {
175 string cutMeth = toUpperCopy(simParams_->getCutoffMethod());
176 map<string, CutoffMethod>::iterator i;
177 i = stringToCutoffMethod.find(cutMeth);
178 if (i == stringToCutoffMethod.end()) {
179 sprintf(painCave.errMsg,
180 "ForceManager::setupCutoffs: Could not find chosen cutoffMethod %s\n"
181 "\tShould be one of: "
182 "HARD, SWITCHED, SHIFTED_POTENTIAL, TAYLOR_SHIFTED,\n"
183 "\tSHIFTED_FORCE, or EWALD_FULL\n",
184 cutMeth.c_str());
185 painCave.isFatal = 1;
186 painCave.severity = OPENMD_ERROR;
187 simError();
188 } else {
189 cutoffMethod_ = i->second;
190 }
191 } else {
192 if (mdFileVersion > 1) {
193 sprintf(painCave.errMsg,
194 "ForceManager::setupCutoffs: No value was set for the cutoffMethod.\n"
195 "\tOpenMD will use SHIFTED_FORCE.\n");
196 painCave.isFatal = 0;
197 painCave.severity = OPENMD_INFO;
198 simError();
199 cutoffMethod_ = SHIFTED_FORCE;
200 } else {
201 // handle the case where the old file version was in play
202 // (there should be no cutoffMethod, so we have to deduce it
203 // from other data).
204
205 sprintf(painCave.errMsg,
206 "ForceManager::setupCutoffs : DEPRECATED FILE FORMAT!\n"
207 "\tOpenMD found a file which does not set a cutoffMethod.\n"
208 "\tOpenMD will attempt to deduce a cutoffMethod using the\n"
209 "\tbehavior of the older (version 1) code. To remove this\n"
210 "\twarning, add an explicit cutoffMethod and change the top\n"
211 "\tof the file so that it begins with <OpenMD version=2>\n");
212 painCave.isFatal = 0;
213 painCave.severity = OPENMD_WARNING;
214 simError();
215
216 // The old file version tethered the shifting behavior to the
217 // electrostaticSummationMethod keyword.
218
219 if (simParams_->haveElectrostaticSummationMethod()) {
220 string myMethod = simParams_->getElectrostaticSummationMethod();
221 toUpper(myMethod);
222
223 if (myMethod == "SHIFTED_POTENTIAL") {
224 cutoffMethod_ = SHIFTED_POTENTIAL;
225 } else if (myMethod == "SHIFTED_FORCE") {
226 cutoffMethod_ = SHIFTED_FORCE;
227 } else if (myMethod == "TAYLOR_SHIFTED") {
228 cutoffMethod_ = TAYLOR_SHIFTED;
229 } else if (myMethod == "EWALD_FULL") {
230 cutoffMethod_ = EWALD_FULL;
231 }
232
233 if (simParams_->haveSwitchingRadius())
234 rSwitch_ = simParams_->getSwitchingRadius();
235
236 if (myMethod == "SHIFTED_POTENTIAL" || myMethod == "SHIFTED_FORCE" ||
237 myMethod == "TAYLOR_SHIFTED" || myMethod == "EWALD_FULL") {
238 if (simParams_->haveSwitchingRadius()){
239 sprintf(painCave.errMsg,
240 "ForceManager::setupCutoffs : DEPRECATED ERROR MESSAGE\n"
241 "\tA value was set for the switchingRadius\n"
242 "\teven though the electrostaticSummationMethod was\n"
243 "\tset to %s\n", myMethod.c_str());
244 painCave.severity = OPENMD_WARNING;
245 painCave.isFatal = 1;
246 simError();
247 }
248 }
249 if (abs(rCut_ - rSwitch_) < 0.0001) {
250 if (cutoffMethod_ == SHIFTED_FORCE) {
251 sprintf(painCave.errMsg,
252 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
253 "\tcutoffRadius and switchingRadius are set to the\n"
254 "\tsame value. OpenMD will use shifted force\n"
255 "\tpotentials instead of switching functions.\n");
256 painCave.isFatal = 0;
257 painCave.severity = OPENMD_WARNING;
258 simError();
259 } else {
260 cutoffMethod_ = SHIFTED_POTENTIAL;
261 sprintf(painCave.errMsg,
262 "ForceManager::setupCutoffs : DEPRECATED BEHAVIOR\n"
263 "\tcutoffRadius and switchingRadius are set to the\n"
264 "\tsame value. OpenMD will use shifted potentials\n"
265 "\tinstead of switching functions.\n");
266 painCave.isFatal = 0;
267 painCave.severity = OPENMD_WARNING;
268 simError();
269 }
270 }
271 }
272 }
273 }
274
275 // create the switching function object:
276
277 switcher_ = new SwitchingFunction();
278
279 if (cutoffMethod_ == SWITCHED) {
280 if (simParams_->haveSwitchingRadius()) {
281 rSwitch_ = simParams_->getSwitchingRadius();
282 if (rSwitch_ > rCut_) {
283 sprintf(painCave.errMsg,
284 "ForceManager::setupCutoffs: switchingRadius (%f) is larger "
285 "than the cutoffRadius(%f)\n", rSwitch_, rCut_);
286 painCave.isFatal = 1;
287 painCave.severity = OPENMD_ERROR;
288 simError();
289 }
290 } else {
291 rSwitch_ = 0.85 * rCut_;
292 sprintf(painCave.errMsg,
293 "ForceManager::setupCutoffs: No value was set for the switchingRadius.\n"
294 "\tOpenMD will use a default value of 85 percent of the cutoffRadius.\n"
295 "\tswitchingRadius = %f. for this simulation\n", rSwitch_);
296 painCave.isFatal = 0;
297 painCave.severity = OPENMD_WARNING;
298 simError();
299 }
300 } else {
301 if (mdFileVersion > 1) {
302 // throw an error if we define a switching radius and don't need one.
303 // older file versions should not do this.
304 if (simParams_->haveSwitchingRadius()) {
305 map<string, CutoffMethod>::const_iterator it;
306 string theMeth;
307 for (it = stringToCutoffMethod.begin();
308 it != stringToCutoffMethod.end(); ++it) {
309 if (it->second == cutoffMethod_) {
310 theMeth = it->first;
311 break;
312 }
313 }
314 sprintf(painCave.errMsg,
315 "ForceManager::setupCutoffs: the cutoffMethod (%s)\n"
316 "\tis not set to SWITCHED, so switchingRadius value\n"
317 "\twill be ignored for this simulation\n", theMeth.c_str());
318 painCave.isFatal = 0;
319 painCave.severity = OPENMD_WARNING;
320 simError();
321 }
322 }
323 rSwitch_ = rCut_;
324 }
325
326 // Default to cubic switching function.
327 sft_ = cubic;
328 if (simParams_->haveSwitchingFunctionType()) {
329 string funcType = simParams_->getSwitchingFunctionType();
330 toUpper(funcType);
331 if (funcType == "CUBIC") {
332 sft_ = cubic;
333 } else {
334 if (funcType == "FIFTH_ORDER_POLYNOMIAL") {
335 sft_ = fifth_order_poly;
336 } else {
337 // throw error
338 sprintf( painCave.errMsg,
339 "ForceManager::setupSwitching : Unknown switchingFunctionType. (Input file specified %s .)\n"
340 "\tswitchingFunctionType must be one of: "
341 "\"cubic\" or \"fifth_order_polynomial\".",
342 funcType.c_str() );
343 painCave.isFatal = 1;
344 painCave.severity = OPENMD_ERROR;
345 simError();
346 }
347 }
348 }
349 switcher_->setSwitchType(sft_);
350 switcher_->setSwitch(rSwitch_, rCut_);
351 }
352
353 void ForceManager::initialize() {
354
355 if (!info_->isTopologyDone()) {
356
357 info_->update();
358 interactionMan_->setSimInfo(info_);
359 interactionMan_->initialize();
360
361 //! We want to delay the cutoffs until after the interaction
362 //! manager has set up the atom-atom interactions so that we can
363 //! query them for suggested cutoff values
364 setupCutoffs();
365
366 info_->prepareTopology();
367
368 doParticlePot_ = info_->getSimParams()->getOutputParticlePotential();
369 doHeatFlux_ = info_->getSimParams()->getPrintHeatFlux();
370 if (doHeatFlux_) doParticlePot_ = true;
371
372 doElectricField_ = info_->getSimParams()->getOutputElectricField();
373 doSitePotential_ = info_->getSimParams()->getOutputSitePotential();
374
375 }
376
377 ForceFieldOptions& fopts = forceField_->getForceFieldOptions();
378
379 //! Force fields can set options on how to scale van der Waals and
380 //! electrostatic interactions for atoms connected via bonds, bends
381 //! and torsions in this case the topological distance between
382 //! atoms is:
383 //! 0 = topologically unconnected
384 //! 1 = bonded together
385 //! 2 = connected via a bend
386 //! 3 = connected via a torsion
387
388 vdwScale_.reserve(4);
389 fill(vdwScale_.begin(), vdwScale_.end(), 0.0);
390
391 electrostaticScale_.reserve(4);
392 fill(electrostaticScale_.begin(), electrostaticScale_.end(), 0.0);
393
394 vdwScale_[0] = 1.0;
395 vdwScale_[1] = fopts.getvdw12scale();
396 vdwScale_[2] = fopts.getvdw13scale();
397 vdwScale_[3] = fopts.getvdw14scale();
398
399 electrostaticScale_[0] = 1.0;
400 electrostaticScale_[1] = fopts.getelectrostatic12scale();
401 electrostaticScale_[2] = fopts.getelectrostatic13scale();
402 electrostaticScale_[3] = fopts.getelectrostatic14scale();
403
404 if (info_->getSimParams()->haveUniformField()) {
405 UniformField* eField = new UniformField(info_);
406 perturbations_.push_back(eField);
407 }
408 if (info_->getSimParams()->haveUniformGradientStrength() ||
409 info_->getSimParams()->haveUniformGradientDirection1() ||
410 info_->getSimParams()->haveUniformGradientDirection2() ) {
411 UniformGradient* eGrad = new UniformGradient(info_);
412 perturbations_.push_back(eGrad);
413 }
414
415 usePeriodicBoundaryConditions_ = info_->getSimParams()->getUsePeriodicBoundaryConditions();
416
417 fDecomp_->distributeInitialData();
418
419 initialized_ = true;
420
421 }
422
423 void ForceManager::calcForces() {
424
425 if (!initialized_) initialize();
426
427 preCalculation();
428 shortRangeInteractions();
429 longRangeInteractions();
430 postCalculation();
431 }
432
433 void ForceManager::preCalculation() {
434 SimInfo::MoleculeIterator mi;
435 Molecule* mol;
436 Molecule::AtomIterator ai;
437 Atom* atom;
438 Molecule::RigidBodyIterator rbIter;
439 RigidBody* rb;
440 Molecule::CutoffGroupIterator ci;
441 CutoffGroup* cg;
442
443 // forces and potentials are zeroed here, before any are
444 // accumulated.
445
446 Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
447
448 snap->setBondPotential(0.0);
449 snap->setBendPotential(0.0);
450 snap->setTorsionPotential(0.0);
451 snap->setInversionPotential(0.0);
452
453 potVec zeroPot(0.0);
454 snap->setLongRangePotential(zeroPot);
455 snap->setExcludedPotentials(zeroPot);
456
457 snap->setRestraintPotential(0.0);
458 snap->setRawPotential(0.0);
459
460 for (mol = info_->beginMolecule(mi); mol != NULL;
461 mol = info_->nextMolecule(mi)) {
462 for(atom = mol->beginAtom(ai); atom != NULL;
463 atom = mol->nextAtom(ai)) {
464 atom->zeroForcesAndTorques();
465 }
466
467 //change the positions of atoms which belong to the rigidbodies
468 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
469 rb = mol->nextRigidBody(rbIter)) {
470 rb->zeroForcesAndTorques();
471 }
472
473 if(info_->getNGlobalCutoffGroups() != info_->getNGlobalAtoms()){
474 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
475 cg = mol->nextCutoffGroup(ci)) {
476 //calculate the center of mass of cutoff group
477 cg->updateCOM();
478 }
479 }
480 }
481
482 // Zero out the stress tensor
483 stressTensor *= 0.0;
484 // Zero out the heatFlux
485 fDecomp_->setHeatFlux( Vector3d(0.0) );
486 }
487
488 void ForceManager::shortRangeInteractions() {
489 Molecule* mol;
490 RigidBody* rb;
491 Bond* bond;
492 Bend* bend;
493 Torsion* torsion;
494 Inversion* inversion;
495 SimInfo::MoleculeIterator mi;
496 Molecule::RigidBodyIterator rbIter;
497 Molecule::BondIterator bondIter;;
498 Molecule::BendIterator bendIter;
499 Molecule::TorsionIterator torsionIter;
500 Molecule::InversionIterator inversionIter;
501 RealType bondPotential = 0.0;
502 RealType bendPotential = 0.0;
503 RealType torsionPotential = 0.0;
504 RealType inversionPotential = 0.0;
505
506 //calculate short range interactions
507 for (mol = info_->beginMolecule(mi); mol != NULL;
508 mol = info_->nextMolecule(mi)) {
509
510 //change the positions of atoms which belong to the rigidbodies
511 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
512 rb = mol->nextRigidBody(rbIter)) {
513 rb->updateAtoms();
514 }
515
516 for (bond = mol->beginBond(bondIter); bond != NULL;
517 bond = mol->nextBond(bondIter)) {
518 bond->calcForce(doParticlePot_);
519 bondPotential += bond->getPotential();
520 }
521
522 for (bend = mol->beginBend(bendIter); bend != NULL;
523 bend = mol->nextBend(bendIter)) {
524
525 RealType angle;
526 bend->calcForce(angle, doParticlePot_);
527 RealType currBendPot = bend->getPotential();
528
529 bendPotential += bend->getPotential();
530 map<Bend*, BendDataSet>::iterator i = bendDataSets.find(bend);
531 if (i == bendDataSets.end()) {
532 BendDataSet dataSet;
533 dataSet.prev.angle = dataSet.curr.angle = angle;
534 dataSet.prev.potential = dataSet.curr.potential = currBendPot;
535 dataSet.deltaV = 0.0;
536 bendDataSets.insert(map<Bend*, BendDataSet>::value_type(bend,
537 dataSet));
538 }else {
539 i->second.prev.angle = i->second.curr.angle;
540 i->second.prev.potential = i->second.curr.potential;
541 i->second.curr.angle = angle;
542 i->second.curr.potential = currBendPot;
543 i->second.deltaV = fabs(i->second.curr.potential -
544 i->second.prev.potential);
545 }
546 }
547
548 for (torsion = mol->beginTorsion(torsionIter); torsion != NULL;
549 torsion = mol->nextTorsion(torsionIter)) {
550 RealType angle;
551 torsion->calcForce(angle, doParticlePot_);
552 RealType currTorsionPot = torsion->getPotential();
553 torsionPotential += torsion->getPotential();
554 map<Torsion*, TorsionDataSet>::iterator i = torsionDataSets.find(torsion);
555 if (i == torsionDataSets.end()) {
556 TorsionDataSet dataSet;
557 dataSet.prev.angle = dataSet.curr.angle = angle;
558 dataSet.prev.potential = dataSet.curr.potential = currTorsionPot;
559 dataSet.deltaV = 0.0;
560 torsionDataSets.insert(map<Torsion*, TorsionDataSet>::value_type(torsion, dataSet));
561 }else {
562 i->second.prev.angle = i->second.curr.angle;
563 i->second.prev.potential = i->second.curr.potential;
564 i->second.curr.angle = angle;
565 i->second.curr.potential = currTorsionPot;
566 i->second.deltaV = fabs(i->second.curr.potential -
567 i->second.prev.potential);
568 }
569 }
570
571 for (inversion = mol->beginInversion(inversionIter);
572 inversion != NULL;
573 inversion = mol->nextInversion(inversionIter)) {
574 RealType angle;
575 inversion->calcForce(angle, doParticlePot_);
576 RealType currInversionPot = inversion->getPotential();
577 inversionPotential += inversion->getPotential();
578 map<Inversion*, InversionDataSet>::iterator i = inversionDataSets.find(inversion);
579 if (i == inversionDataSets.end()) {
580 InversionDataSet dataSet;
581 dataSet.prev.angle = dataSet.curr.angle = angle;
582 dataSet.prev.potential = dataSet.curr.potential = currInversionPot;
583 dataSet.deltaV = 0.0;
584 inversionDataSets.insert(map<Inversion*, InversionDataSet>::value_type(inversion, dataSet));
585 }else {
586 i->second.prev.angle = i->second.curr.angle;
587 i->second.prev.potential = i->second.curr.potential;
588 i->second.curr.angle = angle;
589 i->second.curr.potential = currInversionPot;
590 i->second.deltaV = fabs(i->second.curr.potential -
591 i->second.prev.potential);
592 }
593 }
594 }
595
596 #ifdef IS_MPI
597 // Collect from all nodes. This should eventually be moved into a
598 // SystemDecomposition, but this is a better place than in
599 // Thermo to do the collection.
600
601 MPI_Allreduce(MPI_IN_PLACE, &bondPotential, 1, MPI_REALTYPE,
602 MPI_SUM, MPI_COMM_WORLD);
603 MPI_Allreduce(MPI_IN_PLACE, &bendPotential, 1, MPI_REALTYPE,
604 MPI_SUM, MPI_COMM_WORLD);
605 MPI_Allreduce(MPI_IN_PLACE, &torsionPotential, 1,
606 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
607 MPI_Allreduce(MPI_IN_PLACE, &inversionPotential, 1,
608 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
609 #endif
610
611 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
612
613 curSnapshot->setBondPotential(bondPotential);
614 curSnapshot->setBendPotential(bendPotential);
615 curSnapshot->setTorsionPotential(torsionPotential);
616 curSnapshot->setInversionPotential(inversionPotential);
617
618 // RealType shortRangePotential = bondPotential + bendPotential +
619 // torsionPotential + inversionPotential;
620
621 // curSnapshot->setShortRangePotential(shortRangePotential);
622 }
623
624 void ForceManager::longRangeInteractions() {
625
626 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
627 DataStorage* config = &(curSnapshot->atomData);
628 DataStorage* cgConfig = &(curSnapshot->cgData);
629 int jstart, jend;
630
631 //calculate the center of mass of cutoff group
632
633 SimInfo::MoleculeIterator mi;
634 Molecule* mol;
635 Molecule::CutoffGroupIterator ci;
636 CutoffGroup* cg;
637
638 if(info_->getNCutoffGroups() != info_->getNAtoms()){
639 for (mol = info_->beginMolecule(mi); mol != NULL;
640 mol = info_->nextMolecule(mi)) {
641 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
642 cg = mol->nextCutoffGroup(ci)) {
643 cg->updateCOM();
644 }
645 }
646 } else {
647 // center of mass of the group is the same as position of the atom
648 // if cutoff group does not exist
649 cgConfig->position = config->position;
650 cgConfig->velocity = config->velocity;
651 }
652
653 fDecomp_->zeroWorkArrays();
654 fDecomp_->distributeData();
655
656 int cg1, cg2, atom1, atom2, topoDist;
657 Vector3d d_grp, dag, d, gvel2, vel2;
658 RealType rgrpsq, rgrp, r2, r;
659 RealType electroMult, vdwMult;
660 RealType vij;
661 Vector3d fij, fg, f1;
662 tuple3<RealType, RealType, RealType> cuts;
663 RealType rCut, rCutSq, rListSq;
664 bool in_switching_region;
665 RealType sw, dswdr, swderiv;
666 vector<int> atomListColumn, atomListRow;
667 InteractionData idat;
668 SelfData sdat;
669 RealType mf;
670 RealType vpair;
671 RealType dVdFQ1(0.0);
672 RealType dVdFQ2(0.0);
673 potVec longRangePotential(0.0);
674 RealType reciprocalPotential(0.0);
675 potVec workPot(0.0);
676 potVec exPot(0.0);
677 Vector3d eField1(0.0);
678 Vector3d eField2(0.0);
679 RealType sPot1(0.0);
680 RealType sPot2(0.0);
681 bool newAtom1;
682
683 vector<int>::iterator ia, jb;
684
685 int loopStart, loopEnd;
686
687 idat.rcut = &rCut_;
688 idat.vdwMult = &vdwMult;
689 idat.electroMult = &electroMult;
690 idat.pot = &workPot;
691 idat.excludedPot = &exPot;
692 sdat.pot = fDecomp_->getEmbeddingPotential();
693 sdat.excludedPot = fDecomp_->getExcludedSelfPotential();
694 idat.vpair = &vpair;
695 idat.dVdFQ1 = &dVdFQ1;
696 idat.dVdFQ2 = &dVdFQ2;
697 idat.eField1 = &eField1;
698 idat.eField2 = &eField2;
699 idat.sPot1 = &sPot1;
700 idat.sPot2 = &sPot2;
701 idat.f1 = &f1;
702 idat.sw = &sw;
703 idat.shiftedPot = (cutoffMethod_ == SHIFTED_POTENTIAL) ? true : false;
704 idat.shiftedForce = (cutoffMethod_ == SHIFTED_FORCE ||
705 cutoffMethod_ == TAYLOR_SHIFTED) ? true : false;
706 idat.doParticlePot = doParticlePot_;
707 idat.doElectricField = doElectricField_;
708 idat.doSitePotential = doSitePotential_;
709 sdat.doParticlePot = doParticlePot_;
710
711 loopEnd = PAIR_LOOP;
712 if (info_->requiresPrepair() ) {
713 loopStart = PREPAIR_LOOP;
714 } else {
715 loopStart = PAIR_LOOP;
716 }
717 for (int iLoop = loopStart; iLoop <= loopEnd; iLoop++) {
718
719 if (iLoop == loopStart) {
720 bool update_nlist = fDecomp_->checkNeighborList();
721 if (update_nlist) {
722 if (!usePeriodicBoundaryConditions_)
723 Mat3x3d bbox = thermo->getBoundingBox();
724 fDecomp_->buildNeighborList(neighborList_, point_);
725 }
726 }
727
728 for (unsigned int cg1 = 0; cg1 < point_.size() - 1; cg1++) {
729
730 atomListRow = fDecomp_->getAtomsInGroupRow(cg1);
731 newAtom1 = true;
732
733 for (int m2 = point_[cg1]; m2 < point_[cg1+1]; m2++) {
734
735 cg2 = neighborList_[m2];
736
737 d_grp = fDecomp_->getIntergroupVector(cg1, cg2);
738
739 // already wrapped in the getIntergroupVector call:
740 // curSnapshot->wrapVector(d_grp);
741 rgrpsq = d_grp.lengthSquare();
742
743 if (rgrpsq < rCutSq_) {
744 if (iLoop == PAIR_LOOP) {
745 vij = 0.0;
746 fij.zero();
747 eField1.zero();
748 eField2.zero();
749 sPot1 = 0.0;
750 sPot2 = 0.0;
751 }
752
753 in_switching_region = switcher_->getSwitch(rgrpsq, sw, dswdr,
754 rgrp);
755
756 atomListColumn = fDecomp_->getAtomsInGroupColumn(cg2);
757
758 if (doHeatFlux_)
759 gvel2 = fDecomp_->getGroupVelocityColumn(cg2);
760
761 for (ia = atomListRow.begin();
762 ia != atomListRow.end(); ++ia) {
763 atom1 = (*ia);
764
765 for (jb = atomListColumn.begin();
766 jb != atomListColumn.end(); ++jb) {
767 atom2 = (*jb);
768
769 if (!fDecomp_->skipAtomPair(atom1, atom2, cg1, cg2)) {
770
771 vpair = 0.0;
772 workPot = 0.0;
773 exPot = 0.0;
774 f1.zero();
775 dVdFQ1 = 0.0;
776 dVdFQ2 = 0.0;
777
778 fDecomp_->fillInteractionData(idat, atom1, atom2, newAtom1);
779
780 topoDist = fDecomp_->getTopologicalDistance(atom1, atom2);
781 vdwMult = vdwScale_[topoDist];
782 electroMult = electrostaticScale_[topoDist];
783
784 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
785 idat.d = &d_grp;
786 idat.r2 = &rgrpsq;
787 if (doHeatFlux_)
788 vel2 = gvel2;
789 } else {
790 d = fDecomp_->getInteratomicVector(atom1, atom2);
791 curSnapshot->wrapVector( d );
792 r2 = d.lengthSquare();
793 idat.d = &d;
794 idat.r2 = &r2;
795 if (doHeatFlux_)
796 vel2 = fDecomp_->getAtomVelocityColumn(atom2);
797 }
798
799 r = sqrt( *(idat.r2) );
800 idat.rij = &r;
801
802 if (iLoop == PREPAIR_LOOP) {
803 interactionMan_->doPrePair(idat);
804 } else {
805 interactionMan_->doPair(idat);
806 fDecomp_->unpackInteractionData(idat, atom1, atom2);
807 vij += vpair;
808 fij += f1;
809 stressTensor -= outProduct( *(idat.d), f1);
810 if (doHeatFlux_)
811 fDecomp_->addToHeatFlux(*(idat.d) * dot(f1, vel2));
812 }
813 }
814 }
815 }
816
817 if (iLoop == PAIR_LOOP) {
818 if (in_switching_region) {
819 swderiv = vij * dswdr / rgrp;
820 fg = swderiv * d_grp;
821 fij += fg;
822
823 if (atomListRow.size() == 1 && atomListColumn.size() == 1) {
824 if (!fDecomp_->skipAtomPair(atomListRow[0],
825 atomListColumn[0],
826 cg1, cg2)) {
827 stressTensor -= outProduct( *(idat.d), fg);
828 if (doHeatFlux_)
829 fDecomp_->addToHeatFlux(*(idat.d) * dot(fg, vel2));
830 }
831 }
832
833 for (ia = atomListRow.begin();
834 ia != atomListRow.end(); ++ia) {
835 atom1 = (*ia);
836 mf = fDecomp_->getMassFactorRow(atom1);
837 // fg is the force on atom ia due to cutoff group's
838 // presence in switching region
839 fg = swderiv * d_grp * mf;
840 fDecomp_->addForceToAtomRow(atom1, fg);
841 if (atomListRow.size() > 1) {
842 if (info_->usesAtomicVirial()) {
843 // find the distance between the atom
844 // and the center of the cutoff group:
845 dag = fDecomp_->getAtomToGroupVectorRow(atom1, cg1);
846 stressTensor -= outProduct(dag, fg);
847 if (doHeatFlux_)
848 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
849 }
850 }
851 }
852 for (jb = atomListColumn.begin();
853 jb != atomListColumn.end(); ++jb) {
854 atom2 = (*jb);
855 mf = fDecomp_->getMassFactorColumn(atom2);
856 // fg is the force on atom jb due to cutoff group's
857 // presence in switching region
858 fg = -swderiv * d_grp * mf;
859 fDecomp_->addForceToAtomColumn(atom2, fg);
860
861 if (atomListColumn.size() > 1) {
862 if (info_->usesAtomicVirial()) {
863 // find the distance between the atom
864 // and the center of the cutoff group:
865 dag = fDecomp_->getAtomToGroupVectorColumn(atom2, cg2);
866 stressTensor -= outProduct(dag, fg);
867 if (doHeatFlux_)
868 fDecomp_->addToHeatFlux( dag * dot(fg, vel2));
869 }
870 }
871 }
872 }
873 //if (!info_->usesAtomicVirial()) {
874 // stressTensor -= outProduct(d_grp, fij);
875 // if (doHeatFlux_)
876 // fDecomp_->addToHeatFlux( d_grp * dot(fij, vel2));
877 //}
878 }
879 }
880 }
881 newAtom1 = false;
882 }
883
884 if (iLoop == PREPAIR_LOOP) {
885 if (info_->requiresPrepair()) {
886
887 fDecomp_->collectIntermediateData();
888
889 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
890 fDecomp_->fillSelfData(sdat, atom1);
891 interactionMan_->doPreForce(sdat);
892 }
893
894 fDecomp_->distributeIntermediateData();
895
896 }
897 }
898 }
899
900 // collects pairwise information
901 fDecomp_->collectData();
902 if (cutoffMethod_ == EWALD_FULL) {
903 interactionMan_->doReciprocalSpaceSum(reciprocalPotential);
904
905 curSnapshot->setReciprocalPotential(reciprocalPotential);
906 }
907
908 if (info_->requiresSelfCorrection()) {
909 for (unsigned int atom1 = 0; atom1 < info_->getNAtoms(); atom1++) {
910 fDecomp_->fillSelfData(sdat, atom1);
911 interactionMan_->doSelfCorrection(sdat);
912 }
913 }
914
915 // collects single-atom information
916 fDecomp_->collectSelfData();
917
918 longRangePotential = *(fDecomp_->getEmbeddingPotential()) +
919 *(fDecomp_->getPairwisePotential());
920
921 curSnapshot->setLongRangePotential(longRangePotential);
922
923 curSnapshot->setExcludedPotentials(*(fDecomp_->getExcludedSelfPotential()) +
924 *(fDecomp_->getExcludedPotential()));
925
926 }
927
928 void ForceManager::postCalculation() {
929
930 vector<Perturbation*>::iterator pi;
931 for (pi = perturbations_.begin(); pi != perturbations_.end(); ++pi) {
932 (*pi)->applyPerturbation();
933 }
934
935 SimInfo::MoleculeIterator mi;
936 Molecule* mol;
937 Molecule::RigidBodyIterator rbIter;
938 RigidBody* rb;
939 Snapshot* curSnapshot = info_->getSnapshotManager()->getCurrentSnapshot();
940
941 // collect the atomic forces onto rigid bodies
942
943 for (mol = info_->beginMolecule(mi); mol != NULL;
944 mol = info_->nextMolecule(mi)) {
945 for (rb = mol->beginRigidBody(rbIter); rb != NULL;
946 rb = mol->nextRigidBody(rbIter)) {
947 Mat3x3d rbTau = rb->calcForcesAndTorquesAndVirial();
948 stressTensor += rbTau;
949 }
950 }
951
952 #ifdef IS_MPI
953 MPI_Allreduce(MPI_IN_PLACE, stressTensor.getArrayPointer(), 9,
954 MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
955 #endif
956 curSnapshot->setStressTensor(stressTensor);
957
958 if (info_->getSimParams()->getUseLongRangeCorrections()) {
959 /*
960 RealType vol = curSnapshot->getVolume();
961 RealType Elrc(0.0);
962 RealType Wlrc(0.0);
963
964 set<AtomType*>::iterator i;
965 set<AtomType*>::iterator j;
966
967 RealType n_i, n_j;
968 RealType rho_i, rho_j;
969 pair<RealType, RealType> LRI;
970
971 for (i = atomTypes_.begin(); i != atomTypes_.end(); ++i) {
972 n_i = RealType(info_->getGlobalCountOfType(*i));
973 rho_i = n_i / vol;
974 for (j = atomTypes_.begin(); j != atomTypes_.end(); ++j) {
975 n_j = RealType(info_->getGlobalCountOfType(*j));
976 rho_j = n_j / vol;
977
978 LRI = interactionMan_->getLongRangeIntegrals( (*i), (*j) );
979
980 Elrc += n_i * rho_j * LRI.first;
981 Wlrc -= rho_i * rho_j * LRI.second;
982 }
983 }
984 Elrc *= 2.0 * NumericConstant::PI;
985 Wlrc *= 2.0 * NumericConstant::PI;
986
987 RealType lrp = curSnapshot->getLongRangePotential();
988 curSnapshot->setLongRangePotential(lrp + Elrc);
989 stressTensor += Wlrc * SquareMatrix3<RealType>::identity();
990 curSnapshot->setStressTensor(stressTensor);
991 */
992
993 }
994 }
995 }

Properties

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