ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/brains/SimInfo.cpp
Revision: 2419
Committed: Tue Nov 8 13:32:06 2005 UTC (18 years, 8 months ago) by chrisfen
File size: 36730 byte(s)
Log Message:
Added a keyword for output of forces and torques

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. Acknowledgement of the program authors must be made in any
10 * publication of scientific results based in part on use of the
11 * program. An acceptable form of acknowledgement is citation of
12 * the article in which the program was described (Matthew
13 * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14 * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15 * Parallel Simulation Engine for Molecular Dynamics,"
16 * J. Comput. Chem. 26, pp. 252-271 (2005))
17 *
18 * 2. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * 3. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the
24 * distribution.
25 *
26 * This software is provided "AS IS," without a warranty of any
27 * kind. All express or implied conditions, representations and
28 * warranties, including any implied warranty of merchantability,
29 * fitness for a particular purpose or non-infringement, are hereby
30 * excluded. The University of Notre Dame and its licensors shall not
31 * be liable for any damages suffered by licensee as a result of
32 * using, modifying or distributing the software or its
33 * derivatives. In no event will the University of Notre Dame or its
34 * licensors be liable for any lost revenue, profit or data, or for
35 * direct, indirect, special, consequential, incidental or punitive
36 * damages, however caused and regardless of the theory of liability,
37 * arising out of the use of or inability to use software, even if the
38 * University of Notre Dame has been advised of the possibility of
39 * such damages.
40 */
41
42 /**
43 * @file SimInfo.cpp
44 * @author tlin
45 * @date 11/02/2004
46 * @version 1.0
47 */
48
49 #include <algorithm>
50 #include <set>
51
52 #include "brains/SimInfo.hpp"
53 #include "math/Vector3.hpp"
54 #include "primitives/Molecule.hpp"
55 #include "UseTheForce/fCutoffPolicy.h"
56 #include "UseTheForce/DarkSide/fElectrostaticSummationMethod.h"
57 #include "UseTheForce/DarkSide/fElectrostaticScreeningMethod.h"
58 #include "UseTheForce/doForces_interface.h"
59 #include "UseTheForce/DarkSide/electrostatic_interface.h"
60 #include "UseTheForce/notifyCutoffs_interface.h"
61 #include "utils/MemoryUtils.hpp"
62 #include "utils/simError.h"
63 #include "selection/SelectionManager.hpp"
64
65 #ifdef IS_MPI
66 #include "UseTheForce/mpiComponentPlan.h"
67 #include "UseTheForce/DarkSide/simParallel_interface.h"
68 #endif
69
70 namespace oopse {
71
72 SimInfo::SimInfo(MakeStamps* stamps, std::vector<std::pair<MoleculeStamp*, int> >& molStampPairs,
73 ForceField* ff, Globals* simParams) :
74 stamps_(stamps), forceField_(ff), simParams_(simParams),
75 ndf_(0), ndfRaw_(0), ndfTrans_(0), nZconstraint_(0),
76 nGlobalMols_(0), nGlobalAtoms_(0), nGlobalCutoffGroups_(0),
77 nGlobalIntegrableObjects_(0), nGlobalRigidBodies_(0),
78 nAtoms_(0), nBonds_(0), nBends_(0), nTorsions_(0), nRigidBodies_(0),
79 nIntegrableObjects_(0), nCutoffGroups_(0), nConstraints_(0),
80 sman_(NULL), fortranInitialized_(false) {
81
82
83 std::vector<std::pair<MoleculeStamp*, int> >::iterator i;
84 MoleculeStamp* molStamp;
85 int nMolWithSameStamp;
86 int nCutoffAtoms = 0; // number of atoms belong to cutoff groups
87 int nGroups = 0; //total cutoff groups defined in meta-data file
88 CutoffGroupStamp* cgStamp;
89 RigidBodyStamp* rbStamp;
90 int nRigidAtoms = 0;
91
92 for (i = molStampPairs.begin(); i !=molStampPairs.end(); ++i) {
93 molStamp = i->first;
94 nMolWithSameStamp = i->second;
95
96 addMoleculeStamp(molStamp, nMolWithSameStamp);
97
98 //calculate atoms in molecules
99 nGlobalAtoms_ += molStamp->getNAtoms() *nMolWithSameStamp;
100
101
102 //calculate atoms in cutoff groups
103 int nAtomsInGroups = 0;
104 int nCutoffGroupsInStamp = molStamp->getNCutoffGroups();
105
106 for (int j=0; j < nCutoffGroupsInStamp; j++) {
107 cgStamp = molStamp->getCutoffGroup(j);
108 nAtomsInGroups += cgStamp->getNMembers();
109 }
110
111 nGroups += nCutoffGroupsInStamp * nMolWithSameStamp;
112
113 nCutoffAtoms += nAtomsInGroups * nMolWithSameStamp;
114
115 //calculate atoms in rigid bodies
116 int nAtomsInRigidBodies = 0;
117 int nRigidBodiesInStamp = molStamp->getNRigidBodies();
118
119 for (int j=0; j < nRigidBodiesInStamp; j++) {
120 rbStamp = molStamp->getRigidBody(j);
121 nAtomsInRigidBodies += rbStamp->getNMembers();
122 }
123
124 nGlobalRigidBodies_ += nRigidBodiesInStamp * nMolWithSameStamp;
125 nRigidAtoms += nAtomsInRigidBodies * nMolWithSameStamp;
126
127 }
128
129 //every free atom (atom does not belong to cutoff groups) is a cutoff
130 //group therefore the total number of cutoff groups in the system is
131 //equal to the total number of atoms minus number of atoms belong to
132 //cutoff group defined in meta-data file plus the number of cutoff
133 //groups defined in meta-data file
134 nGlobalCutoffGroups_ = nGlobalAtoms_ - nCutoffAtoms + nGroups;
135
136 //every free atom (atom does not belong to rigid bodies) is an
137 //integrable object therefore the total number of integrable objects
138 //in the system is equal to the total number of atoms minus number of
139 //atoms belong to rigid body defined in meta-data file plus the number
140 //of rigid bodies defined in meta-data file
141 nGlobalIntegrableObjects_ = nGlobalAtoms_ - nRigidAtoms
142 + nGlobalRigidBodies_;
143
144 nGlobalMols_ = molStampIds_.size();
145
146 #ifdef IS_MPI
147 molToProcMap_.resize(nGlobalMols_);
148 #endif
149
150 }
151
152 SimInfo::~SimInfo() {
153 std::map<int, Molecule*>::iterator i;
154 for (i = molecules_.begin(); i != molecules_.end(); ++i) {
155 delete i->second;
156 }
157 molecules_.clear();
158
159 delete stamps_;
160 delete sman_;
161 delete simParams_;
162 delete forceField_;
163 }
164
165 int SimInfo::getNGlobalConstraints() {
166 int nGlobalConstraints;
167 #ifdef IS_MPI
168 MPI_Allreduce(&nConstraints_, &nGlobalConstraints, 1, MPI_INT, MPI_SUM,
169 MPI_COMM_WORLD);
170 #else
171 nGlobalConstraints = nConstraints_;
172 #endif
173 return nGlobalConstraints;
174 }
175
176 bool SimInfo::addMolecule(Molecule* mol) {
177 MoleculeIterator i;
178
179 i = molecules_.find(mol->getGlobalIndex());
180 if (i == molecules_.end() ) {
181
182 molecules_.insert(std::make_pair(mol->getGlobalIndex(), mol));
183
184 nAtoms_ += mol->getNAtoms();
185 nBonds_ += mol->getNBonds();
186 nBends_ += mol->getNBends();
187 nTorsions_ += mol->getNTorsions();
188 nRigidBodies_ += mol->getNRigidBodies();
189 nIntegrableObjects_ += mol->getNIntegrableObjects();
190 nCutoffGroups_ += mol->getNCutoffGroups();
191 nConstraints_ += mol->getNConstraintPairs();
192
193 addExcludePairs(mol);
194
195 return true;
196 } else {
197 return false;
198 }
199 }
200
201 bool SimInfo::removeMolecule(Molecule* mol) {
202 MoleculeIterator i;
203 i = molecules_.find(mol->getGlobalIndex());
204
205 if (i != molecules_.end() ) {
206
207 assert(mol == i->second);
208
209 nAtoms_ -= mol->getNAtoms();
210 nBonds_ -= mol->getNBonds();
211 nBends_ -= mol->getNBends();
212 nTorsions_ -= mol->getNTorsions();
213 nRigidBodies_ -= mol->getNRigidBodies();
214 nIntegrableObjects_ -= mol->getNIntegrableObjects();
215 nCutoffGroups_ -= mol->getNCutoffGroups();
216 nConstraints_ -= mol->getNConstraintPairs();
217
218 removeExcludePairs(mol);
219 molecules_.erase(mol->getGlobalIndex());
220
221 delete mol;
222
223 return true;
224 } else {
225 return false;
226 }
227
228
229 }
230
231
232 Molecule* SimInfo::beginMolecule(MoleculeIterator& i) {
233 i = molecules_.begin();
234 return i == molecules_.end() ? NULL : i->second;
235 }
236
237 Molecule* SimInfo::nextMolecule(MoleculeIterator& i) {
238 ++i;
239 return i == molecules_.end() ? NULL : i->second;
240 }
241
242
243 void SimInfo::calcNdf() {
244 int ndf_local;
245 MoleculeIterator i;
246 std::vector<StuntDouble*>::iterator j;
247 Molecule* mol;
248 StuntDouble* integrableObject;
249
250 ndf_local = 0;
251
252 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
253 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
254 integrableObject = mol->nextIntegrableObject(j)) {
255
256 ndf_local += 3;
257
258 if (integrableObject->isDirectional()) {
259 if (integrableObject->isLinear()) {
260 ndf_local += 2;
261 } else {
262 ndf_local += 3;
263 }
264 }
265
266 }//end for (integrableObject)
267 }// end for (mol)
268
269 // n_constraints is local, so subtract them on each processor
270 ndf_local -= nConstraints_;
271
272 #ifdef IS_MPI
273 MPI_Allreduce(&ndf_local,&ndf_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
274 #else
275 ndf_ = ndf_local;
276 #endif
277
278 // nZconstraints_ is global, as are the 3 COM translations for the
279 // entire system:
280 ndf_ = ndf_ - 3 - nZconstraint_;
281
282 }
283
284 void SimInfo::calcNdfRaw() {
285 int ndfRaw_local;
286
287 MoleculeIterator i;
288 std::vector<StuntDouble*>::iterator j;
289 Molecule* mol;
290 StuntDouble* integrableObject;
291
292 // Raw degrees of freedom that we have to set
293 ndfRaw_local = 0;
294
295 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
296 for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
297 integrableObject = mol->nextIntegrableObject(j)) {
298
299 ndfRaw_local += 3;
300
301 if (integrableObject->isDirectional()) {
302 if (integrableObject->isLinear()) {
303 ndfRaw_local += 2;
304 } else {
305 ndfRaw_local += 3;
306 }
307 }
308
309 }
310 }
311
312 #ifdef IS_MPI
313 MPI_Allreduce(&ndfRaw_local,&ndfRaw_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
314 #else
315 ndfRaw_ = ndfRaw_local;
316 #endif
317 }
318
319 void SimInfo::calcNdfTrans() {
320 int ndfTrans_local;
321
322 ndfTrans_local = 3 * nIntegrableObjects_ - nConstraints_;
323
324
325 #ifdef IS_MPI
326 MPI_Allreduce(&ndfTrans_local,&ndfTrans_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
327 #else
328 ndfTrans_ = ndfTrans_local;
329 #endif
330
331 ndfTrans_ = ndfTrans_ - 3 - nZconstraint_;
332
333 }
334
335 void SimInfo::addExcludePairs(Molecule* mol) {
336 std::vector<Bond*>::iterator bondIter;
337 std::vector<Bend*>::iterator bendIter;
338 std::vector<Torsion*>::iterator torsionIter;
339 Bond* bond;
340 Bend* bend;
341 Torsion* torsion;
342 int a;
343 int b;
344 int c;
345 int d;
346
347 for (bond= mol->beginBond(bondIter); bond != NULL; bond = mol->nextBond(bondIter)) {
348 a = bond->getAtomA()->getGlobalIndex();
349 b = bond->getAtomB()->getGlobalIndex();
350 exclude_.addPair(a, b);
351 }
352
353 for (bend= mol->beginBend(bendIter); bend != NULL; bend = mol->nextBend(bendIter)) {
354 a = bend->getAtomA()->getGlobalIndex();
355 b = bend->getAtomB()->getGlobalIndex();
356 c = bend->getAtomC()->getGlobalIndex();
357
358 exclude_.addPair(a, b);
359 exclude_.addPair(a, c);
360 exclude_.addPair(b, c);
361 }
362
363 for (torsion= mol->beginTorsion(torsionIter); torsion != NULL; torsion = mol->nextTorsion(torsionIter)) {
364 a = torsion->getAtomA()->getGlobalIndex();
365 b = torsion->getAtomB()->getGlobalIndex();
366 c = torsion->getAtomC()->getGlobalIndex();
367 d = torsion->getAtomD()->getGlobalIndex();
368
369 exclude_.addPair(a, b);
370 exclude_.addPair(a, c);
371 exclude_.addPair(a, d);
372 exclude_.addPair(b, c);
373 exclude_.addPair(b, d);
374 exclude_.addPair(c, d);
375 }
376
377 Molecule::RigidBodyIterator rbIter;
378 RigidBody* rb;
379 for (rb = mol->beginRigidBody(rbIter); rb != NULL; rb = mol->nextRigidBody(rbIter)) {
380 std::vector<Atom*> atoms = rb->getAtoms();
381 for (int i = 0; i < atoms.size() -1 ; ++i) {
382 for (int j = i + 1; j < atoms.size(); ++j) {
383 a = atoms[i]->getGlobalIndex();
384 b = atoms[j]->getGlobalIndex();
385 exclude_.addPair(a, b);
386 }
387 }
388 }
389
390 }
391
392 void SimInfo::removeExcludePairs(Molecule* mol) {
393 std::vector<Bond*>::iterator bondIter;
394 std::vector<Bend*>::iterator bendIter;
395 std::vector<Torsion*>::iterator torsionIter;
396 Bond* bond;
397 Bend* bend;
398 Torsion* torsion;
399 int a;
400 int b;
401 int c;
402 int d;
403
404 for (bond= mol->beginBond(bondIter); bond != NULL; bond = mol->nextBond(bondIter)) {
405 a = bond->getAtomA()->getGlobalIndex();
406 b = bond->getAtomB()->getGlobalIndex();
407 exclude_.removePair(a, b);
408 }
409
410 for (bend= mol->beginBend(bendIter); bend != NULL; bend = mol->nextBend(bendIter)) {
411 a = bend->getAtomA()->getGlobalIndex();
412 b = bend->getAtomB()->getGlobalIndex();
413 c = bend->getAtomC()->getGlobalIndex();
414
415 exclude_.removePair(a, b);
416 exclude_.removePair(a, c);
417 exclude_.removePair(b, c);
418 }
419
420 for (torsion= mol->beginTorsion(torsionIter); torsion != NULL; torsion = mol->nextTorsion(torsionIter)) {
421 a = torsion->getAtomA()->getGlobalIndex();
422 b = torsion->getAtomB()->getGlobalIndex();
423 c = torsion->getAtomC()->getGlobalIndex();
424 d = torsion->getAtomD()->getGlobalIndex();
425
426 exclude_.removePair(a, b);
427 exclude_.removePair(a, c);
428 exclude_.removePair(a, d);
429 exclude_.removePair(b, c);
430 exclude_.removePair(b, d);
431 exclude_.removePair(c, d);
432 }
433
434 Molecule::RigidBodyIterator rbIter;
435 RigidBody* rb;
436 for (rb = mol->beginRigidBody(rbIter); rb != NULL; rb = mol->nextRigidBody(rbIter)) {
437 std::vector<Atom*> atoms = rb->getAtoms();
438 for (int i = 0; i < atoms.size() -1 ; ++i) {
439 for (int j = i + 1; j < atoms.size(); ++j) {
440 a = atoms[i]->getGlobalIndex();
441 b = atoms[j]->getGlobalIndex();
442 exclude_.removePair(a, b);
443 }
444 }
445 }
446
447 }
448
449
450 void SimInfo::addMoleculeStamp(MoleculeStamp* molStamp, int nmol) {
451 int curStampId;
452
453 //index from 0
454 curStampId = moleculeStamps_.size();
455
456 moleculeStamps_.push_back(molStamp);
457 molStampIds_.insert(molStampIds_.end(), nmol, curStampId);
458 }
459
460 void SimInfo::update() {
461
462 setupSimType();
463
464 #ifdef IS_MPI
465 setupFortranParallel();
466 #endif
467
468 setupFortranSim();
469
470 //setup fortran force field
471 /** @deprecate */
472 int isError = 0;
473
474 setupElectrostaticSummationMethod( isError );
475
476 if(isError){
477 sprintf( painCave.errMsg,
478 "ForceField error: There was an error initializing the forceField in fortran.\n" );
479 painCave.isFatal = 1;
480 simError();
481 }
482
483
484 setupCutoff();
485
486 calcNdf();
487 calcNdfRaw();
488 calcNdfTrans();
489
490 fortranInitialized_ = true;
491 }
492
493 std::set<AtomType*> SimInfo::getUniqueAtomTypes() {
494 SimInfo::MoleculeIterator mi;
495 Molecule* mol;
496 Molecule::AtomIterator ai;
497 Atom* atom;
498 std::set<AtomType*> atomTypes;
499
500 for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
501
502 for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
503 atomTypes.insert(atom->getAtomType());
504 }
505
506 }
507
508 return atomTypes;
509 }
510
511 void SimInfo::setupSimType() {
512 std::set<AtomType*>::iterator i;
513 std::set<AtomType*> atomTypes;
514 atomTypes = getUniqueAtomTypes();
515
516 int useLennardJones = 0;
517 int useElectrostatic = 0;
518 int useEAM = 0;
519 int useCharge = 0;
520 int useDirectional = 0;
521 int useDipole = 0;
522 int useGayBerne = 0;
523 int useSticky = 0;
524 int useStickyPower = 0;
525 int useShape = 0;
526 int useFLARB = 0; //it is not in AtomType yet
527 int useDirectionalAtom = 0;
528 int useElectrostatics = 0;
529 //usePBC and useRF are from simParams
530 int usePBC = simParams_->getUsePeriodicBoundaryConditions();
531 int useRF;
532 int useSF;
533 std::string myMethod;
534
535 // set the useRF logical
536 useRF = 0;
537 useSF = 0;
538
539
540 if (simParams_->haveElectrostaticSummationMethod()) {
541 std::string myMethod = simParams_->getElectrostaticSummationMethod();
542 toUpper(myMethod);
543 if (myMethod == "REACTION_FIELD") {
544 useRF=1;
545 } else {
546 if (myMethod == "SHIFTED_FORCE") {
547 useSF = 1;
548 }
549 }
550 }
551
552 //loop over all of the atom types
553 for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
554 useLennardJones |= (*i)->isLennardJones();
555 useElectrostatic |= (*i)->isElectrostatic();
556 useEAM |= (*i)->isEAM();
557 useCharge |= (*i)->isCharge();
558 useDirectional |= (*i)->isDirectional();
559 useDipole |= (*i)->isDipole();
560 useGayBerne |= (*i)->isGayBerne();
561 useSticky |= (*i)->isSticky();
562 useStickyPower |= (*i)->isStickyPower();
563 useShape |= (*i)->isShape();
564 }
565
566 if (useSticky || useStickyPower || useDipole || useGayBerne || useShape) {
567 useDirectionalAtom = 1;
568 }
569
570 if (useCharge || useDipole) {
571 useElectrostatics = 1;
572 }
573
574 #ifdef IS_MPI
575 int temp;
576
577 temp = usePBC;
578 MPI_Allreduce(&temp, &usePBC, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
579
580 temp = useDirectionalAtom;
581 MPI_Allreduce(&temp, &useDirectionalAtom, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
582
583 temp = useLennardJones;
584 MPI_Allreduce(&temp, &useLennardJones, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
585
586 temp = useElectrostatics;
587 MPI_Allreduce(&temp, &useElectrostatics, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
588
589 temp = useCharge;
590 MPI_Allreduce(&temp, &useCharge, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
591
592 temp = useDipole;
593 MPI_Allreduce(&temp, &useDipole, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
594
595 temp = useSticky;
596 MPI_Allreduce(&temp, &useSticky, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
597
598 temp = useStickyPower;
599 MPI_Allreduce(&temp, &useStickyPower, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
600
601 temp = useGayBerne;
602 MPI_Allreduce(&temp, &useGayBerne, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
603
604 temp = useEAM;
605 MPI_Allreduce(&temp, &useEAM, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
606
607 temp = useShape;
608 MPI_Allreduce(&temp, &useShape, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
609
610 temp = useFLARB;
611 MPI_Allreduce(&temp, &useFLARB, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
612
613 temp = useRF;
614 MPI_Allreduce(&temp, &useRF, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
615
616 temp = useSF;
617 MPI_Allreduce(&temp, &useSF, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
618
619 #endif
620
621 fInfo_.SIM_uses_PBC = usePBC;
622 fInfo_.SIM_uses_DirectionalAtoms = useDirectionalAtom;
623 fInfo_.SIM_uses_LennardJones = useLennardJones;
624 fInfo_.SIM_uses_Electrostatics = useElectrostatics;
625 fInfo_.SIM_uses_Charges = useCharge;
626 fInfo_.SIM_uses_Dipoles = useDipole;
627 fInfo_.SIM_uses_Sticky = useSticky;
628 fInfo_.SIM_uses_StickyPower = useStickyPower;
629 fInfo_.SIM_uses_GayBerne = useGayBerne;
630 fInfo_.SIM_uses_EAM = useEAM;
631 fInfo_.SIM_uses_Shapes = useShape;
632 fInfo_.SIM_uses_FLARB = useFLARB;
633 fInfo_.SIM_uses_RF = useRF;
634 fInfo_.SIM_uses_SF = useSF;
635
636 if( myMethod == "REACTION_FIELD") {
637
638 if (simParams_->haveDielectric()) {
639 fInfo_.dielect = simParams_->getDielectric();
640 } else {
641 sprintf(painCave.errMsg,
642 "SimSetup Error: No Dielectric constant was set.\n"
643 "\tYou are trying to use Reaction Field without"
644 "\tsetting a dielectric constant!\n");
645 painCave.isFatal = 1;
646 simError();
647 }
648 }
649
650 }
651
652 void SimInfo::setupFortranSim() {
653 int isError;
654 int nExclude;
655 std::vector<int> fortranGlobalGroupMembership;
656
657 nExclude = exclude_.getSize();
658 isError = 0;
659
660 //globalGroupMembership_ is filled by SimCreator
661 for (int i = 0; i < nGlobalAtoms_; i++) {
662 fortranGlobalGroupMembership.push_back(globalGroupMembership_[i] + 1);
663 }
664
665 //calculate mass ratio of cutoff group
666 std::vector<double> mfact;
667 SimInfo::MoleculeIterator mi;
668 Molecule* mol;
669 Molecule::CutoffGroupIterator ci;
670 CutoffGroup* cg;
671 Molecule::AtomIterator ai;
672 Atom* atom;
673 double totalMass;
674
675 //to avoid memory reallocation, reserve enough space for mfact
676 mfact.reserve(getNCutoffGroups());
677
678 for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
679 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
680
681 totalMass = cg->getMass();
682 for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
683 // Check for massless groups - set mfact to 1 if true
684 if (totalMass != 0)
685 mfact.push_back(atom->getMass()/totalMass);
686 else
687 mfact.push_back( 1.0 );
688 }
689
690 }
691 }
692
693 //fill ident array of local atoms (it is actually ident of AtomType, it is so confusing !!!)
694 std::vector<int> identArray;
695
696 //to avoid memory reallocation, reserve enough space identArray
697 identArray.reserve(getNAtoms());
698
699 for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
700 for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
701 identArray.push_back(atom->getIdent());
702 }
703 }
704
705 //fill molMembershipArray
706 //molMembershipArray is filled by SimCreator
707 std::vector<int> molMembershipArray(nGlobalAtoms_);
708 for (int i = 0; i < nGlobalAtoms_; i++) {
709 molMembershipArray[i] = globalMolMembership_[i] + 1;
710 }
711
712 //setup fortran simulation
713 int nGlobalExcludes = 0;
714 int* globalExcludes = NULL;
715 int* excludeList = exclude_.getExcludeList();
716 setFortranSim( &fInfo_, &nGlobalAtoms_, &nAtoms_, &identArray[0], &nExclude, excludeList ,
717 &nGlobalExcludes, globalExcludes, &molMembershipArray[0],
718 &mfact[0], &nCutoffGroups_, &fortranGlobalGroupMembership[0], &isError);
719
720 if( isError ){
721
722 sprintf( painCave.errMsg,
723 "There was an error setting the simulation information in fortran.\n" );
724 painCave.isFatal = 1;
725 painCave.severity = OOPSE_ERROR;
726 simError();
727 }
728
729 #ifdef IS_MPI
730 sprintf( checkPointMsg,
731 "succesfully sent the simulation information to fortran.\n");
732 MPIcheckPoint();
733 #endif // is_mpi
734 }
735
736
737 #ifdef IS_MPI
738 void SimInfo::setupFortranParallel() {
739
740 //SimInfo is responsible for creating localToGlobalAtomIndex and localToGlobalGroupIndex
741 std::vector<int> localToGlobalAtomIndex(getNAtoms(), 0);
742 std::vector<int> localToGlobalCutoffGroupIndex;
743 SimInfo::MoleculeIterator mi;
744 Molecule::AtomIterator ai;
745 Molecule::CutoffGroupIterator ci;
746 Molecule* mol;
747 Atom* atom;
748 CutoffGroup* cg;
749 mpiSimData parallelData;
750 int isError;
751
752 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
753
754 //local index(index in DataStorge) of atom is important
755 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
756 localToGlobalAtomIndex[atom->getLocalIndex()] = atom->getGlobalIndex() + 1;
757 }
758
759 //local index of cutoff group is trivial, it only depends on the order of travesing
760 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
761 localToGlobalCutoffGroupIndex.push_back(cg->getGlobalIndex() + 1);
762 }
763
764 }
765
766 //fill up mpiSimData struct
767 parallelData.nMolGlobal = getNGlobalMolecules();
768 parallelData.nMolLocal = getNMolecules();
769 parallelData.nAtomsGlobal = getNGlobalAtoms();
770 parallelData.nAtomsLocal = getNAtoms();
771 parallelData.nGroupsGlobal = getNGlobalCutoffGroups();
772 parallelData.nGroupsLocal = getNCutoffGroups();
773 parallelData.myNode = worldRank;
774 MPI_Comm_size(MPI_COMM_WORLD, &(parallelData.nProcessors));
775
776 //pass mpiSimData struct and index arrays to fortran
777 setFsimParallel(&parallelData, &(parallelData.nAtomsLocal),
778 &localToGlobalAtomIndex[0], &(parallelData.nGroupsLocal),
779 &localToGlobalCutoffGroupIndex[0], &isError);
780
781 if (isError) {
782 sprintf(painCave.errMsg,
783 "mpiRefresh errror: fortran didn't like something we gave it.\n");
784 painCave.isFatal = 1;
785 simError();
786 }
787
788 sprintf(checkPointMsg, " mpiRefresh successful.\n");
789 MPIcheckPoint();
790
791
792 }
793
794 #endif
795
796 double SimInfo::calcMaxCutoffRadius() {
797
798
799 std::set<AtomType*> atomTypes;
800 std::set<AtomType*>::iterator i;
801 std::vector<double> cutoffRadius;
802
803 //get the unique atom types
804 atomTypes = getUniqueAtomTypes();
805
806 //query the max cutoff radius among these atom types
807 for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
808 cutoffRadius.push_back(forceField_->getRcutFromAtomType(*i));
809 }
810
811 double maxCutoffRadius = *(std::max_element(cutoffRadius.begin(), cutoffRadius.end()));
812 #ifdef IS_MPI
813 //pick the max cutoff radius among the processors
814 #endif
815
816 return maxCutoffRadius;
817 }
818
819 void SimInfo::getCutoff(double& rcut, double& rsw) {
820
821 if (fInfo_.SIM_uses_Charges | fInfo_.SIM_uses_Dipoles | fInfo_.SIM_uses_RF) {
822
823 if (!simParams_->haveCutoffRadius()){
824 sprintf(painCave.errMsg,
825 "SimCreator Warning: No value was set for the cutoffRadius.\n"
826 "\tOOPSE will use a default value of 15.0 angstroms"
827 "\tfor the cutoffRadius.\n");
828 painCave.isFatal = 0;
829 simError();
830 rcut = 15.0;
831 } else{
832 rcut = simParams_->getCutoffRadius();
833 }
834
835 if (!simParams_->haveSwitchingRadius()){
836 sprintf(painCave.errMsg,
837 "SimCreator Warning: No value was set for switchingRadius.\n"
838 "\tOOPSE will use a default value of\n"
839 "\t0.85 * cutoffRadius for the switchingRadius\n");
840 painCave.isFatal = 0;
841 simError();
842 rsw = 0.85 * rcut;
843 } else{
844 rsw = simParams_->getSwitchingRadius();
845 }
846
847 } else {
848 // if charge, dipole or reaction field is not used and the cutofff radius is not specified in
849 //meta-data file, the maximum cutoff radius calculated from forcefiled will be used
850
851 if (simParams_->haveCutoffRadius()) {
852 rcut = simParams_->getCutoffRadius();
853 } else {
854 //set cutoff radius to the maximum cutoff radius based on atom types in the whole system
855 rcut = calcMaxCutoffRadius();
856 }
857
858 if (simParams_->haveSwitchingRadius()) {
859 rsw = simParams_->getSwitchingRadius();
860 } else {
861 rsw = rcut;
862 }
863
864 }
865 }
866
867 void SimInfo::setupCutoff() {
868 getCutoff(rcut_, rsw_);
869 double rnblist = rcut_ + 1; // skin of neighbor list
870
871 //Pass these cutoff radius etc. to fortran. This function should be called once and only once
872
873 int cp = TRADITIONAL_CUTOFF_POLICY;
874 if (simParams_->haveCutoffPolicy()) {
875 std::string myPolicy = simParams_->getCutoffPolicy();
876 toUpper(myPolicy);
877 if (myPolicy == "MIX") {
878 cp = MIX_CUTOFF_POLICY;
879 } else {
880 if (myPolicy == "MAX") {
881 cp = MAX_CUTOFF_POLICY;
882 } else {
883 if (myPolicy == "TRADITIONAL") {
884 cp = TRADITIONAL_CUTOFF_POLICY;
885 } else {
886 // throw error
887 sprintf( painCave.errMsg,
888 "SimInfo error: Unknown cutoffPolicy. (Input file specified %s .)\n\tcutoffPolicy must be one of: \"Mix\", \"Max\", or \"Traditional\".", myPolicy.c_str() );
889 painCave.isFatal = 1;
890 simError();
891 }
892 }
893 }
894 }
895
896
897 if (simParams_->haveSkinThickness()) {
898 double skinThickness = simParams_->getSkinThickness();
899 }
900
901 notifyFortranCutoffs(&rcut_, &rsw_, &rnblist, &cp);
902 // also send cutoff notification to electrostatics
903 setElectrostaticCutoffRadius(&rcut_, &rsw_);
904 }
905
906 void SimInfo::setupElectrostaticSummationMethod( int isError ) {
907
908 int errorOut;
909 int esm = NONE;
910 int sm = UNDAMPED;
911 double alphaVal;
912 double dielectric;
913
914 errorOut = isError;
915 alphaVal = simParams_->getDampingAlpha();
916 dielectric = simParams_->getDielectric();
917
918 if (simParams_->haveElectrostaticSummationMethod()) {
919 std::string myMethod = simParams_->getElectrostaticSummationMethod();
920 toUpper(myMethod);
921 if (myMethod == "NONE") {
922 esm = NONE;
923 } else {
924 if (myMethod == "SWITCHING_FUNCTION") {
925 esm = SWITCHING_FUNCTION;
926 } else {
927 if (myMethod == "SHIFTED_POTENTIAL") {
928 esm = SHIFTED_POTENTIAL;
929 } else {
930 if (myMethod == "SHIFTED_FORCE") {
931 esm = SHIFTED_FORCE;
932 } else {
933 if (myMethod == "REACTION_FIELD") {
934 esm = REACTION_FIELD;
935 } else {
936 // throw error
937 sprintf( painCave.errMsg,
938 "SimInfo error: Unknown electrostaticSummationMethod. (Input file specified %s .)\n\telectrostaticSummationMethod must be one of: \"none\", \"shifted_potential\", \"shifted_force\", or \"reaction_field\".", myMethod.c_str() );
939 painCave.isFatal = 1;
940 simError();
941 }
942 }
943 }
944 }
945 }
946 }
947
948 if (simParams_->haveElectrostaticScreeningMethod()) {
949 std::string myScreen = simParams_->getElectrostaticScreeningMethod();
950 toUpper(myScreen);
951 if (myScreen == "UNDAMPED") {
952 sm = UNDAMPED;
953 } else {
954 if (myScreen == "DAMPED") {
955 sm = DAMPED;
956 if (!simParams_->haveDampingAlpha()) {
957 //throw error
958 sprintf( painCave.errMsg,
959 "SimInfo warning: dampingAlpha was not specified in the input file. A default value of %f (1/ang) will be used.", alphaVal);
960 painCave.isFatal = 0;
961 simError();
962 }
963 } else {
964 // throw error
965 sprintf( painCave.errMsg,
966 "SimInfo error: Unknown electrostaticScreeningMethod. (Input file specified %s .)\n\telectrostaticScreeningMethod must be one of: \"undamped\" or \"damped\".", myScreen.c_str() );
967 painCave.isFatal = 1;
968 simError();
969 }
970 }
971 }
972
973 // let's pass some summation method variables to fortran
974 setElectrostaticSummationMethod( &esm );
975 setScreeningMethod( &sm );
976 setDampingAlpha( &alphaVal );
977 setReactionFieldDielectric( &dielectric );
978 initFortranFF( &esm, &errorOut );
979 }
980
981 void SimInfo::addProperty(GenericData* genData) {
982 properties_.addProperty(genData);
983 }
984
985 void SimInfo::removeProperty(const std::string& propName) {
986 properties_.removeProperty(propName);
987 }
988
989 void SimInfo::clearProperties() {
990 properties_.clearProperties();
991 }
992
993 std::vector<std::string> SimInfo::getPropertyNames() {
994 return properties_.getPropertyNames();
995 }
996
997 std::vector<GenericData*> SimInfo::getProperties() {
998 return properties_.getProperties();
999 }
1000
1001 GenericData* SimInfo::getPropertyByName(const std::string& propName) {
1002 return properties_.getPropertyByName(propName);
1003 }
1004
1005 void SimInfo::setSnapshotManager(SnapshotManager* sman) {
1006 if (sman_ == sman) {
1007 return;
1008 }
1009 delete sman_;
1010 sman_ = sman;
1011
1012 Molecule* mol;
1013 RigidBody* rb;
1014 Atom* atom;
1015 SimInfo::MoleculeIterator mi;
1016 Molecule::RigidBodyIterator rbIter;
1017 Molecule::AtomIterator atomIter;;
1018
1019 for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
1020
1021 for (atom = mol->beginAtom(atomIter); atom != NULL; atom = mol->nextAtom(atomIter)) {
1022 atom->setSnapshotManager(sman_);
1023 }
1024
1025 for (rb = mol->beginRigidBody(rbIter); rb != NULL; rb = mol->nextRigidBody(rbIter)) {
1026 rb->setSnapshotManager(sman_);
1027 }
1028 }
1029
1030 }
1031
1032 Vector3d SimInfo::getComVel(){
1033 SimInfo::MoleculeIterator i;
1034 Molecule* mol;
1035
1036 Vector3d comVel(0.0);
1037 double totalMass = 0.0;
1038
1039
1040 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1041 double mass = mol->getMass();
1042 totalMass += mass;
1043 comVel += mass * mol->getComVel();
1044 }
1045
1046 #ifdef IS_MPI
1047 double tmpMass = totalMass;
1048 Vector3d tmpComVel(comVel);
1049 MPI_Allreduce(&tmpMass,&totalMass,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1050 MPI_Allreduce(tmpComVel.getArrayPointer(), comVel.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1051 #endif
1052
1053 comVel /= totalMass;
1054
1055 return comVel;
1056 }
1057
1058 Vector3d SimInfo::getCom(){
1059 SimInfo::MoleculeIterator i;
1060 Molecule* mol;
1061
1062 Vector3d com(0.0);
1063 double totalMass = 0.0;
1064
1065 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1066 double mass = mol->getMass();
1067 totalMass += mass;
1068 com += mass * mol->getCom();
1069 }
1070
1071 #ifdef IS_MPI
1072 double tmpMass = totalMass;
1073 Vector3d tmpCom(com);
1074 MPI_Allreduce(&tmpMass,&totalMass,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1075 MPI_Allreduce(tmpCom.getArrayPointer(), com.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1076 #endif
1077
1078 com /= totalMass;
1079
1080 return com;
1081
1082 }
1083
1084 std::ostream& operator <<(std::ostream& o, SimInfo& info) {
1085
1086 return o;
1087 }
1088
1089
1090 /*
1091 Returns center of mass and center of mass velocity in one function call.
1092 */
1093
1094 void SimInfo::getComAll(Vector3d &com, Vector3d &comVel){
1095 SimInfo::MoleculeIterator i;
1096 Molecule* mol;
1097
1098
1099 double totalMass = 0.0;
1100
1101
1102 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1103 double mass = mol->getMass();
1104 totalMass += mass;
1105 com += mass * mol->getCom();
1106 comVel += mass * mol->getComVel();
1107 }
1108
1109 #ifdef IS_MPI
1110 double tmpMass = totalMass;
1111 Vector3d tmpCom(com);
1112 Vector3d tmpComVel(comVel);
1113 MPI_Allreduce(&tmpMass,&totalMass,1,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1114 MPI_Allreduce(tmpCom.getArrayPointer(), com.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1115 MPI_Allreduce(tmpComVel.getArrayPointer(), comVel.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1116 #endif
1117
1118 com /= totalMass;
1119 comVel /= totalMass;
1120 }
1121
1122 /*
1123 Return intertia tensor for entire system and angular momentum Vector.
1124
1125
1126 [ Ixx -Ixy -Ixz ]
1127 J =| -Iyx Iyy -Iyz |
1128 [ -Izx -Iyz Izz ]
1129 */
1130
1131 void SimInfo::getInertiaTensor(Mat3x3d &inertiaTensor, Vector3d &angularMomentum){
1132
1133
1134 double xx = 0.0;
1135 double yy = 0.0;
1136 double zz = 0.0;
1137 double xy = 0.0;
1138 double xz = 0.0;
1139 double yz = 0.0;
1140 Vector3d com(0.0);
1141 Vector3d comVel(0.0);
1142
1143 getComAll(com, comVel);
1144
1145 SimInfo::MoleculeIterator i;
1146 Molecule* mol;
1147
1148 Vector3d thisq(0.0);
1149 Vector3d thisv(0.0);
1150
1151 double thisMass = 0.0;
1152
1153
1154
1155
1156 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1157
1158 thisq = mol->getCom()-com;
1159 thisv = mol->getComVel()-comVel;
1160 thisMass = mol->getMass();
1161 // Compute moment of intertia coefficients.
1162 xx += thisq[0]*thisq[0]*thisMass;
1163 yy += thisq[1]*thisq[1]*thisMass;
1164 zz += thisq[2]*thisq[2]*thisMass;
1165
1166 // compute products of intertia
1167 xy += thisq[0]*thisq[1]*thisMass;
1168 xz += thisq[0]*thisq[2]*thisMass;
1169 yz += thisq[1]*thisq[2]*thisMass;
1170
1171 angularMomentum += cross( thisq, thisv ) * thisMass;
1172
1173 }
1174
1175
1176 inertiaTensor(0,0) = yy + zz;
1177 inertiaTensor(0,1) = -xy;
1178 inertiaTensor(0,2) = -xz;
1179 inertiaTensor(1,0) = -xy;
1180 inertiaTensor(1,1) = xx + zz;
1181 inertiaTensor(1,2) = -yz;
1182 inertiaTensor(2,0) = -xz;
1183 inertiaTensor(2,1) = -yz;
1184 inertiaTensor(2,2) = xx + yy;
1185
1186 #ifdef IS_MPI
1187 Mat3x3d tmpI(inertiaTensor);
1188 Vector3d tmpAngMom;
1189 MPI_Allreduce(tmpI.getArrayPointer(), inertiaTensor.getArrayPointer(),9,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1190 MPI_Allreduce(tmpAngMom.getArrayPointer(), angularMomentum.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1191 #endif
1192
1193 return;
1194 }
1195
1196 //Returns the angular momentum of the system
1197 Vector3d SimInfo::getAngularMomentum(){
1198
1199 Vector3d com(0.0);
1200 Vector3d comVel(0.0);
1201 Vector3d angularMomentum(0.0);
1202
1203 getComAll(com,comVel);
1204
1205 SimInfo::MoleculeIterator i;
1206 Molecule* mol;
1207
1208 Vector3d thisr(0.0);
1209 Vector3d thisp(0.0);
1210
1211 double thisMass;
1212
1213 for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1214 thisMass = mol->getMass();
1215 thisr = mol->getCom()-com;
1216 thisp = (mol->getComVel()-comVel)*thisMass;
1217
1218 angularMomentum += cross( thisr, thisp );
1219
1220 }
1221
1222 #ifdef IS_MPI
1223 Vector3d tmpAngMom;
1224 MPI_Allreduce(tmpAngMom.getArrayPointer(), angularMomentum.getArrayPointer(),3,MPI_DOUBLE,MPI_SUM, MPI_COMM_WORLD);
1225 #endif
1226
1227 return angularMomentum;
1228 }
1229
1230
1231 }//end namespace oopse
1232