ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/brains/SimInfo.cpp
(Generate patch)

Comparing:
trunk/src/brains/SimInfo.cpp (file contents), Revision 143 by chrisfen, Fri Oct 22 22:54:01 2004 UTC vs.
branches/development/src/brains/SimInfo.cpp (file contents), Revision 1530 by gezelter, Tue Dec 28 21:47:55 2010 UTC

# Line 1 | Line 1
1 < #include <stdlib.h>
2 < #include <string.h>
3 < #include <math.h>
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]  Vardeman & Gezelter, in progress (2009).                        
40 > */
41 >
42 > /**
43 > * @file SimInfo.cpp
44 > * @author    tlin
45 > * @date  11/02/2004
46 > * @version 1.0
47 > */
48  
49 < #include <iostream>
50 < using namespace std;
49 > #include <algorithm>
50 > #include <set>
51 > #include <map>
52  
53   #include "brains/SimInfo.hpp"
54 < #define __C
55 < #include "brains/fSimulation.h"
54 > #include "math/Vector3.hpp"
55 > #include "primitives/Molecule.hpp"
56 > #include "primitives/StuntDouble.hpp"
57 > #include "UseTheForce/fCutoffPolicy.h"
58 > #include "UseTheForce/doForces_interface.h"
59 > #include "UseTheForce/DarkSide/neighborLists_interface.h"
60 > #include "utils/MemoryUtils.hpp"
61   #include "utils/simError.h"
62 < #include "UseTheForce/DarkSide/simulation_interface.h"
63 < #include "UseTheForce/notifyCutoffs_interface.h"
62 > #include "selection/SelectionManager.hpp"
63 > #include "io/ForceFieldOptions.hpp"
64 > #include "UseTheForce/ForceField.hpp"
65 > #include "nonbonded/SwitchingFunction.hpp"
66  
15 //#include "UseTheForce/fortranWrappers.hpp"
67  
17 #include "math/MatVec3.h"
18
68   #ifdef IS_MPI
69 < #include "brains/mpiSimulation.hpp"
70 < #endif
69 > #include "UseTheForce/mpiComponentPlan.h"
70 > #include "UseTheForce/DarkSide/simParallel_interface.h"
71 > #endif
72  
73 < inline double roundMe( double x ){
74 <  return ( x >= 0 ) ? floor( x + 0.5 ) : ceil( x - 0.5 );
75 < }
76 <          
77 < inline double min( double a, double b ){
78 <  return (a < b ) ? a : b;
79 < }
73 > using namespace std;
74 > namespace OpenMD {
75 >  
76 >  SimInfo::SimInfo(ForceField* ff, Globals* simParams) :
77 >    forceField_(ff), simParams_(simParams),
78 >    ndf_(0), fdf_local(0), ndfRaw_(0), ndfTrans_(0), nZconstraint_(0),
79 >    nGlobalMols_(0), nGlobalAtoms_(0), nGlobalCutoffGroups_(0),
80 >    nGlobalIntegrableObjects_(0), nGlobalRigidBodies_(0),
81 >    nAtoms_(0), nBonds_(0),  nBends_(0), nTorsions_(0), nInversions_(0),
82 >    nRigidBodies_(0), nIntegrableObjects_(0), nCutoffGroups_(0),
83 >    nConstraints_(0), sman_(NULL), fortranInitialized_(false),
84 >    calcBoxDipole_(false), useAtomicVirial_(true) {    
85 >    
86 >    MoleculeStamp* molStamp;
87 >    int nMolWithSameStamp;
88 >    int nCutoffAtoms = 0; // number of atoms belong to cutoff groups
89 >    int nGroups = 0;       //total cutoff groups defined in meta-data file
90 >    CutoffGroupStamp* cgStamp;    
91 >    RigidBodyStamp* rbStamp;
92 >    int nRigidAtoms = 0;
93 >    
94 >    vector<Component*> components = simParams->getComponents();
95 >    
96 >    for (vector<Component*>::iterator i = components.begin(); i !=components.end(); ++i) {
97 >      molStamp = (*i)->getMoleculeStamp();
98 >      nMolWithSameStamp = (*i)->getNMol();
99 >      
100 >      addMoleculeStamp(molStamp, nMolWithSameStamp);
101 >      
102 >      //calculate atoms in molecules
103 >      nGlobalAtoms_ += molStamp->getNAtoms() *nMolWithSameStamp;  
104 >      
105 >      //calculate atoms in cutoff groups
106 >      int nAtomsInGroups = 0;
107 >      int nCutoffGroupsInStamp = molStamp->getNCutoffGroups();
108 >      
109 >      for (int j=0; j < nCutoffGroupsInStamp; j++) {
110 >        cgStamp = molStamp->getCutoffGroupStamp(j);
111 >        nAtomsInGroups += cgStamp->getNMembers();
112 >      }
113 >      
114 >      nGroups += nCutoffGroupsInStamp * nMolWithSameStamp;
115 >      
116 >      nCutoffAtoms += nAtomsInGroups * nMolWithSameStamp;            
117 >      
118 >      //calculate atoms in rigid bodies
119 >      int nAtomsInRigidBodies = 0;
120 >      int nRigidBodiesInStamp = molStamp->getNRigidBodies();
121 >      
122 >      for (int j=0; j < nRigidBodiesInStamp; j++) {
123 >        rbStamp = molStamp->getRigidBodyStamp(j);
124 >        nAtomsInRigidBodies += rbStamp->getNMembers();
125 >      }
126 >      
127 >      nGlobalRigidBodies_ += nRigidBodiesInStamp * nMolWithSameStamp;
128 >      nRigidAtoms += nAtomsInRigidBodies * nMolWithSameStamp;            
129 >      
130 >    }
131 >    
132 >    //every free atom (atom does not belong to cutoff groups) is a cutoff
133 >    //group therefore the total number of cutoff groups in the system is
134 >    //equal to the total number of atoms minus number of atoms belong to
135 >    //cutoff group defined in meta-data file plus the number of cutoff
136 >    //groups defined in meta-data file
137 >    nGlobalCutoffGroups_ = nGlobalAtoms_ - nCutoffAtoms + nGroups;
138 >    
139 >    //every free atom (atom does not belong to rigid bodies) is an
140 >    //integrable object therefore the total number of integrable objects
141 >    //in the system is equal to the total number of atoms minus number of
142 >    //atoms belong to rigid body defined in meta-data file plus the number
143 >    //of rigid bodies defined in meta-data file
144 >    nGlobalIntegrableObjects_ = nGlobalAtoms_ - nRigidAtoms
145 >      + nGlobalRigidBodies_;
146 >    
147 >    nGlobalMols_ = molStampIds_.size();
148 >    molToProcMap_.resize(nGlobalMols_);
149 >  }
150 >  
151 >  SimInfo::~SimInfo() {
152 >    map<int, Molecule*>::iterator i;
153 >    for (i = molecules_.begin(); i != molecules_.end(); ++i) {
154 >      delete i->second;
155 >    }
156 >    molecules_.clear();
157 >      
158 >    delete sman_;
159 >    delete simParams_;
160 >    delete forceField_;
161 >  }
162  
31 SimInfo* currentInfo;
163  
164 < SimInfo::SimInfo(){
165 <
166 <  n_constraints = 0;
167 <  nZconstraints = 0;
168 <  n_oriented = 0;
169 <  n_dipoles = 0;
170 <  ndf = 0;
171 <  ndfRaw = 0;
172 <  nZconstraints = 0;
173 <  the_integrator = NULL;
174 <  setTemp = 0;
175 <  thermalTime = 0.0;
176 <  currentTime = 0.0;
177 <  rCut = 0.0;
178 <  rSw = 0.0;
179 <
180 <  haveRcut = 0;
181 <  haveRsw = 0;
182 <  boxIsInit = 0;
164 >  bool SimInfo::addMolecule(Molecule* mol) {
165 >    MoleculeIterator i;
166 >    
167 >    i = molecules_.find(mol->getGlobalIndex());
168 >    if (i == molecules_.end() ) {
169 >      
170 >      molecules_.insert(make_pair(mol->getGlobalIndex(), mol));
171 >      
172 >      nAtoms_ += mol->getNAtoms();
173 >      nBonds_ += mol->getNBonds();
174 >      nBends_ += mol->getNBends();
175 >      nTorsions_ += mol->getNTorsions();
176 >      nInversions_ += mol->getNInversions();
177 >      nRigidBodies_ += mol->getNRigidBodies();
178 >      nIntegrableObjects_ += mol->getNIntegrableObjects();
179 >      nCutoffGroups_ += mol->getNCutoffGroups();
180 >      nConstraints_ += mol->getNConstraintPairs();
181 >      
182 >      addInteractionPairs(mol);
183 >      
184 >      return true;
185 >    } else {
186 >      return false;
187 >    }
188 >  }
189    
190 <  resetTime = 1e99;
190 >  bool SimInfo::removeMolecule(Molecule* mol) {
191 >    MoleculeIterator i;
192 >    i = molecules_.find(mol->getGlobalIndex());
193  
194 <  orthoRhombic = 0;
56 <  orthoTolerance = 1E-6;
57 <  useInitXSstate = true;
194 >    if (i != molecules_.end() ) {
195  
196 <  usePBC = 0;
197 <  useDirectionalAtoms = 0;
198 <  useLennardJones = 0;
199 <  useElectrostatics = 0;
200 <  useCharges = 0;
201 <  useDipoles = 0;
202 <  useSticky = 0;
203 <  useGayBerne = 0;
204 <  useEAM = 0;
205 <  useShapes = 0;
206 <  useFLARB = 0;
196 >      assert(mol == i->second);
197 >        
198 >      nAtoms_ -= mol->getNAtoms();
199 >      nBonds_ -= mol->getNBonds();
200 >      nBends_ -= mol->getNBends();
201 >      nTorsions_ -= mol->getNTorsions();
202 >      nInversions_ -= mol->getNInversions();
203 >      nRigidBodies_ -= mol->getNRigidBodies();
204 >      nIntegrableObjects_ -= mol->getNIntegrableObjects();
205 >      nCutoffGroups_ -= mol->getNCutoffGroups();
206 >      nConstraints_ -= mol->getNConstraintPairs();
207  
208 <  useSolidThermInt = 0;
209 <  useLiquidThermInt = 0;
208 >      removeInteractionPairs(mol);
209 >      molecules_.erase(mol->getGlobalIndex());
210  
211 <  haveCutoffGroups = false;
211 >      delete mol;
212 >        
213 >      return true;
214 >    } else {
215 >      return false;
216 >    }
217 >  }    
218  
219 <  excludes = Exclude::Instance();
219 >        
220 >  Molecule* SimInfo::beginMolecule(MoleculeIterator& i) {
221 >    i = molecules_.begin();
222 >    return i == molecules_.end() ? NULL : i->second;
223 >  }    
224  
225 <  myConfiguration = new SimState();
225 >  Molecule* SimInfo::nextMolecule(MoleculeIterator& i) {
226 >    ++i;
227 >    return i == molecules_.end() ? NULL : i->second;    
228 >  }
229  
80  has_minimizer = false;
81  the_minimizer =NULL;
230  
231 <  ngroup = 0;
231 >  void SimInfo::calcNdf() {
232 >    int ndf_local;
233 >    MoleculeIterator i;
234 >    vector<StuntDouble*>::iterator j;
235 >    Molecule* mol;
236 >    StuntDouble* integrableObject;
237  
238 < }
238 >    ndf_local = 0;
239 >    
240 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
241 >      for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
242 >           integrableObject = mol->nextIntegrableObject(j)) {
243  
244 +        ndf_local += 3;
245  
246 < SimInfo::~SimInfo(){
246 >        if (integrableObject->isDirectional()) {
247 >          if (integrableObject->isLinear()) {
248 >            ndf_local += 2;
249 >          } else {
250 >            ndf_local += 3;
251 >          }
252 >        }
253 >            
254 >      }
255 >    }
256 >    
257 >    // n_constraints is local, so subtract them on each processor
258 >    ndf_local -= nConstraints_;
259  
260 <  delete myConfiguration;
260 > #ifdef IS_MPI
261 >    MPI_Allreduce(&ndf_local,&ndf_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
262 > #else
263 >    ndf_ = ndf_local;
264 > #endif
265  
266 <  map<string, GenericData*>::iterator i;
267 <  
268 <  for(i = properties.begin(); i != properties.end(); i++)
95 <    delete (*i).second;
266 >    // nZconstraints_ is global, as are the 3 COM translations for the
267 >    // entire system:
268 >    ndf_ = ndf_ - 3 - nZconstraint_;
269  
270 < }
270 >  }
271  
272 < void SimInfo::setBox(double newBox[3]) {
273 <  
274 <  int i, j;
275 <  double tempMat[3][3];
276 <
277 <  for(i=0; i<3; i++)
278 <    for (j=0; j<3; j++) tempMat[i][j] = 0.0;;
106 <
107 <  tempMat[0][0] = newBox[0];
108 <  tempMat[1][1] = newBox[1];
109 <  tempMat[2][2] = newBox[2];
110 <
111 <  setBoxM( tempMat );
112 <
113 < }
114 <
115 < void SimInfo::setBoxM( double theBox[3][3] ){
116 <  
117 <  int i, j;
118 <  double FortranHmat[9]; // to preserve compatibility with Fortran the
119 <                         // ordering in the array is as follows:
120 <                         // [ 0 3 6 ]
121 <                         // [ 1 4 7 ]
122 <                         // [ 2 5 8 ]
123 <  double FortranHmatInv[9]; // the inverted Hmat (for Fortran);
124 <
125 <  if( !boxIsInit ) boxIsInit = 1;
126 <
127 <  for(i=0; i < 3; i++)
128 <    for (j=0; j < 3; j++) Hmat[i][j] = theBox[i][j];
129 <  
130 <  calcBoxL();
131 <  calcHmatInv();
132 <
133 <  for(i=0; i < 3; i++) {
134 <    for (j=0; j < 3; j++) {
135 <      FortranHmat[3*j + i] = Hmat[i][j];
136 <      FortranHmatInv[3*j + i] = HmatInv[i][j];
137 <    }
272 >  int SimInfo::getFdf() {
273 > #ifdef IS_MPI
274 >    MPI_Allreduce(&fdf_local,&fdf_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
275 > #else
276 >    fdf_ = fdf_local;
277 > #endif
278 >    return fdf_;
279    }
280 +    
281 +  void SimInfo::calcNdfRaw() {
282 +    int ndfRaw_local;
283  
284 <  setFortranBox(FortranHmat, FortranHmatInv, &orthoRhombic);
285 <
286 < }
287 <
284 >    MoleculeIterator i;
285 >    vector<StuntDouble*>::iterator j;
286 >    Molecule* mol;
287 >    StuntDouble* integrableObject;
288  
289 < void SimInfo::getBoxM (double theBox[3][3]) {
289 >    // Raw degrees of freedom that we have to set
290 >    ndfRaw_local = 0;
291 >    
292 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
293 >      for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
294 >           integrableObject = mol->nextIntegrableObject(j)) {
295  
296 <  int i, j;
148 <  for(i=0; i<3; i++)
149 <    for (j=0; j<3; j++) theBox[i][j] = Hmat[i][j];
150 < }
296 >        ndfRaw_local += 3;
297  
298 <
299 < void SimInfo::scaleBox(double scale) {
300 <  double theBox[3][3];
301 <  int i, j;
302 <
303 <  // cerr << "Scaling box by " << scale << "\n";
304 <
305 <  for(i=0; i<3; i++)
160 <    for (j=0; j<3; j++) theBox[i][j] = Hmat[i][j]*scale;
161 <
162 <  setBoxM(theBox);
163 <
164 < }
165 <
166 < void SimInfo::calcHmatInv( void ) {
167 <  
168 <  int oldOrtho;
169 <  int i,j;
170 <  double smallDiag;
171 <  double tol;
172 <  double sanity[3][3];
173 <
174 <  invertMat3( Hmat, HmatInv );
175 <
176 <  // check to see if Hmat is orthorhombic
177 <  
178 <  oldOrtho = orthoRhombic;
179 <
180 <  smallDiag = fabs(Hmat[0][0]);
181 <  if(smallDiag > fabs(Hmat[1][1])) smallDiag = fabs(Hmat[1][1]);
182 <  if(smallDiag > fabs(Hmat[2][2])) smallDiag = fabs(Hmat[2][2]);
183 <  tol = smallDiag * orthoTolerance;
184 <
185 <  orthoRhombic = 1;
186 <  
187 <  for (i = 0; i < 3; i++ ) {
188 <    for (j = 0 ; j < 3; j++) {
189 <      if (i != j) {
190 <        if (orthoRhombic) {
191 <          if ( fabs(Hmat[i][j]) >= tol) orthoRhombic = 0;
192 <        }        
298 >        if (integrableObject->isDirectional()) {
299 >          if (integrableObject->isLinear()) {
300 >            ndfRaw_local += 2;
301 >          } else {
302 >            ndfRaw_local += 3;
303 >          }
304 >        }
305 >            
306        }
307      }
195  }
196
197  if( oldOrtho != orthoRhombic ){
308      
309 <    if( orthoRhombic ) {
310 <      sprintf( painCave.errMsg,
311 <               "OOPSE is switching from the default Non-Orthorhombic\n"
312 <               "\tto the faster Orthorhombic periodic boundary computations.\n"
313 <               "\tThis is usually a good thing, but if you wan't the\n"
204 <               "\tNon-Orthorhombic computations, make the orthoBoxTolerance\n"
205 <               "\tvariable ( currently set to %G ) smaller.\n",
206 <               orthoTolerance);
207 <      painCave.severity = OOPSE_INFO;
208 <      simError();
209 <    }
210 <    else {
211 <      sprintf( painCave.errMsg,
212 <               "OOPSE is switching from the faster Orthorhombic to the more\n"
213 <               "\tflexible Non-Orthorhombic periodic boundary computations.\n"
214 <               "\tThis is usually because the box has deformed under\n"
215 <               "\tNPTf integration. If you wan't to live on the edge with\n"
216 <               "\tthe Orthorhombic computations, make the orthoBoxTolerance\n"
217 <               "\tvariable ( currently set to %G ) larger.\n",
218 <               orthoTolerance);
219 <      painCave.severity = OOPSE_WARNING;
220 <      simError();
221 <    }
309 > #ifdef IS_MPI
310 >    MPI_Allreduce(&ndfRaw_local,&ndfRaw_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
311 > #else
312 >    ndfRaw_ = ndfRaw_local;
313 > #endif
314    }
223 }
315  
316 < void SimInfo::calcBoxL( void ){
316 >  void SimInfo::calcNdfTrans() {
317 >    int ndfTrans_local;
318  
319 <  double dx, dy, dz, dsq;
319 >    ndfTrans_local = 3 * nIntegrableObjects_ - nConstraints_;
320  
229  // boxVol = Determinant of Hmat
321  
322 <  boxVol = matDet3( Hmat );
322 > #ifdef IS_MPI
323 >    MPI_Allreduce(&ndfTrans_local,&ndfTrans_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
324 > #else
325 >    ndfTrans_ = ndfTrans_local;
326 > #endif
327  
328 <  // boxLx
329 <  
330 <  dx = Hmat[0][0]; dy = Hmat[1][0]; dz = Hmat[2][0];
236 <  dsq = dx*dx + dy*dy + dz*dz;
237 <  boxL[0] = sqrt( dsq );
238 <  //maxCutoff = 0.5 * boxL[0];
328 >    ndfTrans_ = ndfTrans_ - 3 - nZconstraint_;
329 >
330 >  }
331  
332 <  // boxLy
333 <  
334 <  dx = Hmat[0][1]; dy = Hmat[1][1]; dz = Hmat[2][1];
335 <  dsq = dx*dx + dy*dy + dz*dz;
336 <  boxL[1] = sqrt( dsq );
337 <  //if( (0.5 * boxL[1]) < maxCutoff ) maxCutoff = 0.5 * boxL[1];
332 >  void SimInfo::addInteractionPairs(Molecule* mol) {
333 >    ForceFieldOptions& options_ = forceField_->getForceFieldOptions();
334 >    vector<Bond*>::iterator bondIter;
335 >    vector<Bend*>::iterator bendIter;
336 >    vector<Torsion*>::iterator torsionIter;
337 >    vector<Inversion*>::iterator inversionIter;
338 >    Bond* bond;
339 >    Bend* bend;
340 >    Torsion* torsion;
341 >    Inversion* inversion;
342 >    int a;
343 >    int b;
344 >    int c;
345 >    int d;
346  
347 +    // atomGroups can be used to add special interaction maps between
348 +    // groups of atoms that are in two separate rigid bodies.
349 +    // However, most site-site interactions between two rigid bodies
350 +    // are probably not special, just the ones between the physically
351 +    // bonded atoms.  Interactions *within* a single rigid body should
352 +    // always be excluded.  These are done at the bottom of this
353 +    // function.
354  
355 <  // boxLz
356 <  
357 <  dx = Hmat[0][2]; dy = Hmat[1][2]; dz = Hmat[2][2];
358 <  dsq = dx*dx + dy*dy + dz*dz;
359 <  boxL[2] = sqrt( dsq );
360 <  //if( (0.5 * boxL[2]) < maxCutoff ) maxCutoff = 0.5 * boxL[2];
355 >    map<int, set<int> > atomGroups;
356 >    Molecule::RigidBodyIterator rbIter;
357 >    RigidBody* rb;
358 >    Molecule::IntegrableObjectIterator ii;
359 >    StuntDouble* integrableObject;
360 >    
361 >    for (integrableObject = mol->beginIntegrableObject(ii);
362 >         integrableObject != NULL;
363 >         integrableObject = mol->nextIntegrableObject(ii)) {
364 >      
365 >      if (integrableObject->isRigidBody()) {
366 >        rb = static_cast<RigidBody*>(integrableObject);
367 >        vector<Atom*> atoms = rb->getAtoms();
368 >        set<int> rigidAtoms;
369 >        for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
370 >          rigidAtoms.insert(atoms[i]->getGlobalIndex());
371 >        }
372 >        for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
373 >          atomGroups.insert(map<int, set<int> >::value_type(atoms[i]->getGlobalIndex(), rigidAtoms));
374 >        }      
375 >      } else {
376 >        set<int> oneAtomSet;
377 >        oneAtomSet.insert(integrableObject->getGlobalIndex());
378 >        atomGroups.insert(map<int, set<int> >::value_type(integrableObject->getGlobalIndex(), oneAtomSet));        
379 >      }
380 >    }  
381 >          
382 >    for (bond= mol->beginBond(bondIter); bond != NULL;
383 >         bond = mol->nextBond(bondIter)) {
384  
385 <  //calculate the max cutoff
386 <  maxCutoff =  calcMaxCutOff();
387 <  
388 <  checkCutOffs();
385 >      a = bond->getAtomA()->getGlobalIndex();
386 >      b = bond->getAtomB()->getGlobalIndex();  
387 >    
388 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
389 >        oneTwoInteractions_.addPair(a, b);
390 >      } else {
391 >        excludedInteractions_.addPair(a, b);
392 >      }
393 >    }
394  
395 < }
395 >    for (bend= mol->beginBend(bendIter); bend != NULL;
396 >         bend = mol->nextBend(bendIter)) {
397  
398 +      a = bend->getAtomA()->getGlobalIndex();
399 +      b = bend->getAtomB()->getGlobalIndex();        
400 +      c = bend->getAtomC()->getGlobalIndex();
401 +      
402 +      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
403 +        oneTwoInteractions_.addPair(a, b);      
404 +        oneTwoInteractions_.addPair(b, c);
405 +      } else {
406 +        excludedInteractions_.addPair(a, b);
407 +        excludedInteractions_.addPair(b, c);
408 +      }
409  
410 < double SimInfo::calcMaxCutOff(){
410 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
411 >        oneThreeInteractions_.addPair(a, c);      
412 >      } else {
413 >        excludedInteractions_.addPair(a, c);
414 >      }
415 >    }
416  
417 <  double ri[3], rj[3], rk[3];
418 <  double rij[3], rjk[3], rki[3];
267 <  double minDist;
417 >    for (torsion= mol->beginTorsion(torsionIter); torsion != NULL;
418 >         torsion = mol->nextTorsion(torsionIter)) {
419  
420 <  ri[0] = Hmat[0][0];
421 <  ri[1] = Hmat[1][0];
422 <  ri[2] = Hmat[2][0];
420 >      a = torsion->getAtomA()->getGlobalIndex();
421 >      b = torsion->getAtomB()->getGlobalIndex();        
422 >      c = torsion->getAtomC()->getGlobalIndex();        
423 >      d = torsion->getAtomD()->getGlobalIndex();      
424  
425 <  rj[0] = Hmat[0][1];
426 <  rj[1] = Hmat[1][1];
427 <  rj[2] = Hmat[2][1];
425 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
426 >        oneTwoInteractions_.addPair(a, b);      
427 >        oneTwoInteractions_.addPair(b, c);
428 >        oneTwoInteractions_.addPair(c, d);
429 >      } else {
430 >        excludedInteractions_.addPair(a, b);
431 >        excludedInteractions_.addPair(b, c);
432 >        excludedInteractions_.addPair(c, d);
433 >      }
434  
435 <  rk[0] = Hmat[0][2];
436 <  rk[1] = Hmat[1][2];
437 <  rk[2] = Hmat[2][2];
438 <    
439 <  crossProduct3(ri, rj, rij);
440 <  distXY = dotProduct3(rk,rij) / norm3(rij);
435 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
436 >        oneThreeInteractions_.addPair(a, c);      
437 >        oneThreeInteractions_.addPair(b, d);      
438 >      } else {
439 >        excludedInteractions_.addPair(a, c);
440 >        excludedInteractions_.addPair(b, d);
441 >      }
442  
443 <  crossProduct3(rj,rk, rjk);
444 <  distYZ = dotProduct3(ri,rjk) / norm3(rjk);
443 >      if (options_.havevdw14scale() || options_.haveelectrostatic14scale()) {
444 >        oneFourInteractions_.addPair(a, d);      
445 >      } else {
446 >        excludedInteractions_.addPair(a, d);
447 >      }
448 >    }
449  
450 <  crossProduct3(rk,ri, rki);
451 <  distZX = dotProduct3(rj,rki) / norm3(rki);
450 >    for (inversion= mol->beginInversion(inversionIter); inversion != NULL;
451 >         inversion = mol->nextInversion(inversionIter)) {
452  
453 <  minDist = min(min(distXY, distYZ), distZX);
454 <  return minDist/2;
455 <  
456 < }
453 >      a = inversion->getAtomA()->getGlobalIndex();
454 >      b = inversion->getAtomB()->getGlobalIndex();        
455 >      c = inversion->getAtomC()->getGlobalIndex();        
456 >      d = inversion->getAtomD()->getGlobalIndex();        
457  
458 < void SimInfo::wrapVector( double thePos[3] ){
458 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
459 >        oneTwoInteractions_.addPair(a, b);      
460 >        oneTwoInteractions_.addPair(a, c);
461 >        oneTwoInteractions_.addPair(a, d);
462 >      } else {
463 >        excludedInteractions_.addPair(a, b);
464 >        excludedInteractions_.addPair(a, c);
465 >        excludedInteractions_.addPair(a, d);
466 >      }
467  
468 <  int i;
469 <  double scaled[3];
468 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
469 >        oneThreeInteractions_.addPair(b, c);    
470 >        oneThreeInteractions_.addPair(b, d);    
471 >        oneThreeInteractions_.addPair(c, d);      
472 >      } else {
473 >        excludedInteractions_.addPair(b, c);
474 >        excludedInteractions_.addPair(b, d);
475 >        excludedInteractions_.addPair(c, d);
476 >      }
477 >    }
478  
479 <  if( !orthoRhombic ){
480 <    // calc the scaled coordinates.
481 <  
479 >    for (rb = mol->beginRigidBody(rbIter); rb != NULL;
480 >         rb = mol->nextRigidBody(rbIter)) {
481 >      vector<Atom*> atoms = rb->getAtoms();
482 >      for (int i = 0; i < static_cast<int>(atoms.size()) -1 ; ++i) {
483 >        for (int j = i + 1; j < static_cast<int>(atoms.size()); ++j) {
484 >          a = atoms[i]->getGlobalIndex();
485 >          b = atoms[j]->getGlobalIndex();
486 >          excludedInteractions_.addPair(a, b);
487 >        }
488 >      }
489 >    }        
490  
491 <    matVecMul3(HmatInv, thePos, scaled);
491 >  }
492 >
493 >  void SimInfo::removeInteractionPairs(Molecule* mol) {
494 >    ForceFieldOptions& options_ = forceField_->getForceFieldOptions();
495 >    vector<Bond*>::iterator bondIter;
496 >    vector<Bend*>::iterator bendIter;
497 >    vector<Torsion*>::iterator torsionIter;
498 >    vector<Inversion*>::iterator inversionIter;
499 >    Bond* bond;
500 >    Bend* bend;
501 >    Torsion* torsion;
502 >    Inversion* inversion;
503 >    int a;
504 >    int b;
505 >    int c;
506 >    int d;
507 >
508 >    map<int, set<int> > atomGroups;
509 >    Molecule::RigidBodyIterator rbIter;
510 >    RigidBody* rb;
511 >    Molecule::IntegrableObjectIterator ii;
512 >    StuntDouble* integrableObject;
513      
514 <    for(i=0; i<3; i++)
515 <      scaled[i] -= roundMe(scaled[i]);
516 <    
517 <    // calc the wrapped real coordinates from the wrapped scaled coordinates
518 <    
519 <    matVecMul3(Hmat, scaled, thePos);
514 >    for (integrableObject = mol->beginIntegrableObject(ii);
515 >         integrableObject != NULL;
516 >         integrableObject = mol->nextIntegrableObject(ii)) {
517 >      
518 >      if (integrableObject->isRigidBody()) {
519 >        rb = static_cast<RigidBody*>(integrableObject);
520 >        vector<Atom*> atoms = rb->getAtoms();
521 >        set<int> rigidAtoms;
522 >        for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
523 >          rigidAtoms.insert(atoms[i]->getGlobalIndex());
524 >        }
525 >        for (int i = 0; i < static_cast<int>(atoms.size()); ++i) {
526 >          atomGroups.insert(map<int, set<int> >::value_type(atoms[i]->getGlobalIndex(), rigidAtoms));
527 >        }      
528 >      } else {
529 >        set<int> oneAtomSet;
530 >        oneAtomSet.insert(integrableObject->getGlobalIndex());
531 >        atomGroups.insert(map<int, set<int> >::value_type(integrableObject->getGlobalIndex(), oneAtomSet));        
532 >      }
533 >    }  
534  
535 <  }
536 <  else{
537 <    // calc the scaled coordinates.
535 >    for (bond= mol->beginBond(bondIter); bond != NULL;
536 >         bond = mol->nextBond(bondIter)) {
537 >      
538 >      a = bond->getAtomA()->getGlobalIndex();
539 >      b = bond->getAtomB()->getGlobalIndex();  
540      
541 <    for(i=0; i<3; i++)
542 <      scaled[i] = thePos[i]*HmatInv[i][i];
543 <    
544 <    // wrap the scaled coordinates
545 <    
546 <    for(i=0; i<3; i++)
323 <      scaled[i] -= roundMe(scaled[i]);
324 <    
325 <    // calc the wrapped real coordinates from the wrapped scaled coordinates
326 <    
327 <    for(i=0; i<3; i++)
328 <      thePos[i] = scaled[i]*Hmat[i][i];
329 <  }
330 <    
331 < }
541 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
542 >        oneTwoInteractions_.removePair(a, b);
543 >      } else {
544 >        excludedInteractions_.removePair(a, b);
545 >      }
546 >    }
547  
548 +    for (bend= mol->beginBend(bendIter); bend != NULL;
549 +         bend = mol->nextBend(bendIter)) {
550  
551 < int SimInfo::getNDF(){
552 <  int ndf_local;
551 >      a = bend->getAtomA()->getGlobalIndex();
552 >      b = bend->getAtomB()->getGlobalIndex();        
553 >      c = bend->getAtomC()->getGlobalIndex();
554 >      
555 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
556 >        oneTwoInteractions_.removePair(a, b);      
557 >        oneTwoInteractions_.removePair(b, c);
558 >      } else {
559 >        excludedInteractions_.removePair(a, b);
560 >        excludedInteractions_.removePair(b, c);
561 >      }
562  
563 <  ndf_local = 0;
564 <  
565 <  for(int i = 0; i < integrableObjects.size(); i++){
566 <    ndf_local += 3;
567 <    if (integrableObjects[i]->isDirectional()) {
342 <      if (integrableObjects[i]->isLinear())
343 <        ndf_local += 2;
344 <      else
345 <        ndf_local += 3;
563 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
564 >        oneThreeInteractions_.removePair(a, c);      
565 >      } else {
566 >        excludedInteractions_.removePair(a, c);
567 >      }
568      }
347  }
569  
570 <  // n_constraints is local, so subtract them on each processor:
570 >    for (torsion= mol->beginTorsion(torsionIter); torsion != NULL;
571 >         torsion = mol->nextTorsion(torsionIter)) {
572  
573 <  ndf_local -= n_constraints;
573 >      a = torsion->getAtomA()->getGlobalIndex();
574 >      b = torsion->getAtomB()->getGlobalIndex();        
575 >      c = torsion->getAtomC()->getGlobalIndex();        
576 >      d = torsion->getAtomD()->getGlobalIndex();      
577 >  
578 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
579 >        oneTwoInteractions_.removePair(a, b);      
580 >        oneTwoInteractions_.removePair(b, c);
581 >        oneTwoInteractions_.removePair(c, d);
582 >      } else {
583 >        excludedInteractions_.removePair(a, b);
584 >        excludedInteractions_.removePair(b, c);
585 >        excludedInteractions_.removePair(c, d);
586 >      }
587  
588 < #ifdef IS_MPI
589 <  MPI_Allreduce(&ndf_local,&ndf,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
590 < #else
591 <  ndf = ndf_local;
592 < #endif
588 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
589 >        oneThreeInteractions_.removePair(a, c);      
590 >        oneThreeInteractions_.removePair(b, d);      
591 >      } else {
592 >        excludedInteractions_.removePair(a, c);
593 >        excludedInteractions_.removePair(b, d);
594 >      }
595  
596 <  // nZconstraints is global, as are the 3 COM translations for the
597 <  // entire system:
596 >      if (options_.havevdw14scale() || options_.haveelectrostatic14scale()) {
597 >        oneFourInteractions_.removePair(a, d);      
598 >      } else {
599 >        excludedInteractions_.removePair(a, d);
600 >      }
601 >    }
602  
603 <  ndf = ndf - 3 - nZconstraints;
603 >    for (inversion= mol->beginInversion(inversionIter); inversion != NULL;
604 >         inversion = mol->nextInversion(inversionIter)) {
605  
606 <  return ndf;
607 < }
606 >      a = inversion->getAtomA()->getGlobalIndex();
607 >      b = inversion->getAtomB()->getGlobalIndex();        
608 >      c = inversion->getAtomC()->getGlobalIndex();        
609 >      d = inversion->getAtomD()->getGlobalIndex();        
610  
611 < int SimInfo::getNDFraw() {
612 <  int ndfRaw_local;
611 >      if (options_.havevdw12scale() || options_.haveelectrostatic12scale()) {
612 >        oneTwoInteractions_.removePair(a, b);      
613 >        oneTwoInteractions_.removePair(a, c);
614 >        oneTwoInteractions_.removePair(a, d);
615 >      } else {
616 >        excludedInteractions_.removePair(a, b);
617 >        excludedInteractions_.removePair(a, c);
618 >        excludedInteractions_.removePair(a, d);
619 >      }
620  
621 <  // Raw degrees of freedom that we have to set
622 <  ndfRaw_local = 0;
623 <
624 <  for(int i = 0; i < integrableObjects.size(); i++){
625 <    ndfRaw_local += 3;
626 <    if (integrableObjects[i]->isDirectional()) {
627 <       if (integrableObjects[i]->isLinear())
628 <        ndfRaw_local += 2;
629 <      else
379 <        ndfRaw_local += 3;
621 >      if (options_.havevdw13scale() || options_.haveelectrostatic13scale()) {
622 >        oneThreeInteractions_.removePair(b, c);    
623 >        oneThreeInteractions_.removePair(b, d);    
624 >        oneThreeInteractions_.removePair(c, d);      
625 >      } else {
626 >        excludedInteractions_.removePair(b, c);
627 >        excludedInteractions_.removePair(b, d);
628 >        excludedInteractions_.removePair(c, d);
629 >      }
630      }
631 +
632 +    for (rb = mol->beginRigidBody(rbIter); rb != NULL;
633 +         rb = mol->nextRigidBody(rbIter)) {
634 +      vector<Atom*> atoms = rb->getAtoms();
635 +      for (int i = 0; i < static_cast<int>(atoms.size()) -1 ; ++i) {
636 +        for (int j = i + 1; j < static_cast<int>(atoms.size()); ++j) {
637 +          a = atoms[i]->getGlobalIndex();
638 +          b = atoms[j]->getGlobalIndex();
639 +          excludedInteractions_.removePair(a, b);
640 +        }
641 +      }
642 +    }        
643 +    
644    }
645 +  
646 +  
647 +  void SimInfo::addMoleculeStamp(MoleculeStamp* molStamp, int nmol) {
648 +    int curStampId;
649      
650 < #ifdef IS_MPI
651 <  MPI_Allreduce(&ndfRaw_local,&ndfRaw,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
385 < #else
386 <  ndfRaw = ndfRaw_local;
387 < #endif
650 >    //index from 0
651 >    curStampId = moleculeStamps_.size();
652  
653 <  return ndfRaw;
654 < }
653 >    moleculeStamps_.push_back(molStamp);
654 >    molStampIds_.insert(molStampIds_.end(), nmol, curStampId);
655 >  }
656  
392 int SimInfo::getNDFtranslational() {
393  int ndfTrans_local;
657  
658 <  ndfTrans_local = 3 * integrableObjects.size() - n_constraints;
658 >  /**
659 >   * update
660 >   *
661 >   *  Performs the global checks and variable settings after the objects have been
662 >   *  created.
663 >   *
664 >   */
665 >  void SimInfo::update() {
666 >    
667 >    setupSimVariables();
668 >    setupCutoffs();
669 >    setupSwitching();
670 >    setupElectrostatics();
671 >    setupNeighborlists();
672 >
673 > #ifdef IS_MPI
674 >    setupFortranParallel();
675 > #endif
676 >    setupFortranSim();
677 >    fortranInitialized_ = true;
678 >
679 >    calcNdf();
680 >    calcNdfRaw();
681 >    calcNdfTrans();
682 >  }
683 >  
684 >  set<AtomType*> SimInfo::getSimulatedAtomTypes() {
685 >    SimInfo::MoleculeIterator mi;
686 >    Molecule* mol;
687 >    Molecule::AtomIterator ai;
688 >    Atom* atom;
689 >    set<AtomType*> atomTypes;
690 >    
691 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {      
692 >      for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
693 >        atomTypes.insert(atom->getAtomType());
694 >      }      
695 >    }    
696 >    return atomTypes;        
697 >  }
698  
699 +  /**
700 +   * setupCutoffs
701 +   *
702 +   * Sets the values of cutoffRadius and cutoffMethod
703 +   *
704 +   * cutoffRadius : realType
705 +   *  If the cutoffRadius was explicitly set, use that value.
706 +   *  If the cutoffRadius was not explicitly set:
707 +   *      Are there electrostatic atoms?  Use 12.0 Angstroms.
708 +   *      No electrostatic atoms?  Poll the atom types present in the
709 +   *      simulation for suggested cutoff values (e.g. 2.5 * sigma).
710 +   *      Use the maximum suggested value that was found.
711 +   *
712 +   * cutoffMethod : (one of HARD, SWITCHED, SHIFTED_FORCE, SHIFTED_POTENTIAL)
713 +   *      If cutoffMethod was explicitly set, use that choice.
714 +   *      If cutoffMethod was not explicitly set, use SHIFTED_FORCE
715 +   */
716 +  void SimInfo::setupCutoffs() {
717 +    
718 +    if (simParams_->haveCutoffRadius()) {
719 +      cutoffRadius_ = simParams_->getCutoffRadius();
720 +    } else {      
721 +      if (usesElectrostaticAtoms_) {
722 +        sprintf(painCave.errMsg,
723 +                "SimInfo: No value was set for the cutoffRadius.\n"
724 +                "\tOpenMD will use a default value of 12.0 angstroms"
725 +                "\tfor the cutoffRadius.\n");
726 +        painCave.isFatal = 0;
727 +        painCave.severity = OPENMD_INFO;
728 +        simError();
729 +        cutoffRadius_ = 12.0;
730 +      } else {
731 +        RealType thisCut;
732 +        set<AtomType*>::iterator i;
733 +        set<AtomType*> atomTypes;
734 +        atomTypes = getSimulatedAtomTypes();        
735 +        for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
736 +          thisCut = InteractionManager::Instance()->getSuggestedCutoffRadius((*i));
737 +          cutoffRadius_ = max(thisCut, cutoffRadius_);
738 +        }
739 +        sprintf(painCave.errMsg,
740 +                "SimInfo: No value was set for the cutoffRadius.\n"
741 +                "\tOpenMD will use %lf angstroms.\n",
742 +                cutoffRadius_);
743 +        painCave.isFatal = 0;
744 +        painCave.severity = OPENMD_INFO;
745 +        simError();
746 +      }            
747 +    }
748  
749 < #ifdef IS_MPI
399 <  MPI_Allreduce(&ndfTrans_local,&ndfTrans,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
400 < #else
401 <  ndfTrans = ndfTrans_local;
402 < #endif
749 >    InteractionManager::Instance()->setCutoffRadius(cutoffRadius_);
750  
751 <  ndfTrans = ndfTrans - 3 - nZconstraints;
751 >    map<string, CutoffMethod> stringToCutoffMethod;
752 >    stringToCutoffMethod["HARD"] = HARD;
753 >    stringToCutoffMethod["SWITCHING_FUNCTION"] = SWITCHING_FUNCTION;
754 >    stringToCutoffMethod["SHIFTED_POTENTIAL"] = SHIFTED_POTENTIAL;    
755 >    stringToCutoffMethod["SHIFTED_FORCE"] = SHIFTED_FORCE;
756 >  
757 >    if (simParams_->haveCutoffMethod()) {
758 >      string cutMeth = toUpperCopy(simParams_->getCutoffMethod());
759 >      map<string, CutoffMethod>::iterator i;
760 >      i = stringToCutoffMethod.find(cutMeth);
761 >      if (i == stringToCutoffMethod.end()) {
762 >        sprintf(painCave.errMsg,
763 >                "SimInfo: Could not find chosen cutoffMethod %s\n"
764 >                "\tShould be one of: "
765 >                "HARD, SWITCHING_FUNCTION, SHIFTED_POTENTIAL, or SHIFTED_FORCE\n",
766 >                cutMeth.c_str());
767 >        painCave.isFatal = 1;
768 >        painCave.severity = OPENMD_ERROR;
769 >        simError();
770 >      } else {
771 >        cutoffMethod_ = i->second;
772 >      }
773 >    } else {
774 >      sprintf(painCave.errMsg,
775 >              "SimInfo: No value was set for the cutoffMethod.\n"
776 >              "\tOpenMD will use SHIFTED_FORCE.\n");
777 >        painCave.isFatal = 0;
778 >        painCave.severity = OPENMD_INFO;
779 >        simError();
780 >        cutoffMethod_ = SHIFTED_FORCE;        
781 >    }
782  
783 <  return ndfTrans;
784 < }
783 >    InteractionManager::Instance()->setCutoffMethod(cutoffMethod_);
784 >  }
785 >  
786 >  /**
787 >   * setupSwitching
788 >   *
789 >   * Sets the values of switchingRadius and
790 >   *  If the switchingRadius was explicitly set, use that value (but check it)
791 >   *  If the switchingRadius was not explicitly set: use 0.85 * cutoffRadius_
792 >   */
793 >  void SimInfo::setupSwitching() {
794 >    
795 >    if (simParams_->haveSwitchingRadius()) {
796 >      switchingRadius_ = simParams_->getSwitchingRadius();
797 >      if (switchingRadius_ > cutoffRadius_) {        
798 >        sprintf(painCave.errMsg,
799 >                "SimInfo: switchingRadius (%f) is larger than cutoffRadius(%f)\n",
800 >                switchingRadius_, cutoffRadius_);
801 >        painCave.isFatal = 1;
802 >        painCave.severity = OPENMD_ERROR;
803 >        simError();
804 >      }
805 >    } else {      
806 >      switchingRadius_ = 0.85 * cutoffRadius_;
807 >      sprintf(painCave.errMsg,
808 >              "SimInfo: No value was set for the switchingRadius.\n"
809 >              "\tOpenMD will use a default value of 85 percent of the cutoffRadius.\n"
810 >              "\tswitchingRadius = %f. for this simulation\n", switchingRadius_);
811 >      painCave.isFatal = 0;
812 >      painCave.severity = OPENMD_WARNING;
813 >      simError();
814 >    }          
815 >  
816 >    InteractionManager::Instance()->setSwitchingRadius(switchingRadius_);
817  
818 < int SimInfo::getTotIntegrableObjects() {
819 <  int nObjs_local;
820 <  int nObjs;
818 >    SwitchingFunctionType ft;
819 >    
820 >    if (simParams_->haveSwitchingFunctionType()) {
821 >      string funcType = simParams_->getSwitchingFunctionType();
822 >      toUpper(funcType);
823 >      if (funcType == "CUBIC") {
824 >        ft = cubic;
825 >      } else {
826 >        if (funcType == "FIFTH_ORDER_POLYNOMIAL") {
827 >          ft = fifth_order_poly;
828 >        } else {
829 >          // throw error        
830 >          sprintf( painCave.errMsg,
831 >                   "SimInfo : Unknown switchingFunctionType. (Input file specified %s .)\n"
832 >                   "\tswitchingFunctionType must be one of: "
833 >                   "\"cubic\" or \"fifth_order_polynomial\".",
834 >                   funcType.c_str() );
835 >          painCave.isFatal = 1;
836 >          painCave.severity = OPENMD_ERROR;
837 >          simError();
838 >        }          
839 >      }
840 >    }
841  
842 <  nObjs_local =  integrableObjects.size();
842 >    InteractionManager::Instance()->setSwitchingFunctionType(ft);
843 >  }
844  
845 +  /**
846 +   * setupSkinThickness
847 +   *
848 +   *  If the skinThickness was explicitly set, use that value (but check it)
849 +   *  If the skinThickness was not explicitly set: use 1.0 angstroms
850 +   */
851 +  void SimInfo::setupSkinThickness() {    
852 +    if (simParams_->haveSkinThickness()) {
853 +      skinThickness_ = simParams_->getSkinThickness();
854 +    } else {      
855 +      skinThickness_ = 1.0;
856 +      sprintf(painCave.errMsg,
857 +              "SimInfo Warning: No value was set for the skinThickness.\n"
858 +              "\tOpenMD will use a default value of %f Angstroms\n"
859 +              "\tfor this simulation\n", skinThickness_);
860 +      painCave.isFatal = 0;
861 +      simError();
862 +    }            
863 +  }
864  
865 < #ifdef IS_MPI
866 <  MPI_Allreduce(&nObjs_local,&nObjs,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
867 < #else
868 <  nObjs = nObjs_local;
420 < #endif
865 >  void SimInfo::setupSimType() {
866 >    set<AtomType*>::iterator i;
867 >    set<AtomType*> atomTypes;
868 >    atomTypes = getSimulatedAtomTypes();
869  
870 +    useAtomicVirial_ = simParams_->getUseAtomicVirial();
871  
872 <  return nObjs;
873 < }
872 >    int usesElectrostatic = 0;
873 >    int usesMetallic = 0;
874 >    int usesDirectional = 0;
875 >    //loop over all of the atom types
876 >    for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
877 >      usesElectrostatic |= (*i)->isElectrostatic();
878 >      usesMetallic |= (*i)->isMetal();
879 >      usesDirectional |= (*i)->isDirectional();
880 >    }
881  
882 < void SimInfo::refreshSim(){
882 > #ifdef IS_MPI    
883 >    int temp;
884 >    temp = usesDirectional;
885 >    MPI_Allreduce(&temp, &usesDirectionalAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
886  
887 <  simtype fInfo;
888 <  int isError;
430 <  int n_global;
431 <  int* excl;
887 >    temp = usesMetallic;
888 >    MPI_Allreduce(&temp, &usesMetallicAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
889  
890 <  fInfo.dielect = 0.0;
891 <
892 <  if( useDipoles ){
893 <    if( useReactionField )fInfo.dielect = dielectric;
890 >    temp = usesElectrostatic;
891 >    MPI_Allreduce(&temp, &usesElectrostaticAtoms_, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
892 > #endif
893 >    fInfo_.SIM_uses_PBC = usesPeriodicBoundaries_;    
894 >    fInfo_.SIM_uses_DirectionalAtoms = usesDirectionalAtoms_;
895 >    fInfo_.SIM_uses_MetallicAtoms = usesMetallicAtoms_;
896 >    fInfo_.SIM_requires_SkipCorrection = usesElectrostaticAtoms_;
897 >    fInfo_.SIM_requires_SelfCorrection = usesElectrostaticAtoms_;
898 >    fInfo_.SIM_uses_AtomicVirial = usesAtomicVirial_;
899    }
900  
901 <  fInfo.SIM_uses_PBC = usePBC;
901 >  void SimInfo::setupFortranSim() {
902 >    int isError;
903 >    int nExclude, nOneTwo, nOneThree, nOneFour;
904 >    vector<int> fortranGlobalGroupMembership;
905 >    
906 >    notifyFortranSkinThickness(&skinThickness_);
907  
908 <  if (useSticky || useDipoles || useGayBerne || useShapes) {
909 <    useDirectionalAtoms = 1;
910 <    fInfo.SIM_uses_DirectionalAtoms = useDirectionalAtoms;
444 <  }
908 >    int ljsp = cutoffMethod_ == SHIFTED_POTENTIAL ? 1 : 0;
909 >    int ljsf = cutoffMethod_ == SHIFTED_FORCE ? 1 : 0;
910 >    notifyFortranCutoffs(&cutoffRadius_, &switchingRadius_, &ljsp, &ljsf);
911  
912 <  fInfo.SIM_uses_LennardJones = useLennardJones;
912 >    isError = 0;
913  
914 <  if (useCharges || useDipoles) {
915 <    useElectrostatics = 1;
916 <    fInfo.SIM_uses_Electrostatics = useElectrostatics;
917 <  }
914 >    //globalGroupMembership_ is filled by SimCreator    
915 >    for (int i = 0; i < nGlobalAtoms_; i++) {
916 >      fortranGlobalGroupMembership.push_back(globalGroupMembership_[i] + 1);
917 >    }
918  
919 <  fInfo.SIM_uses_Charges = useCharges;
920 <  fInfo.SIM_uses_Dipoles = useDipoles;
921 <  fInfo.SIM_uses_Sticky = useSticky;
922 <  fInfo.SIM_uses_GayBerne = useGayBerne;
923 <  fInfo.SIM_uses_EAM = useEAM;
924 <  fInfo.SIM_uses_Shapes = useShapes;
925 <  fInfo.SIM_uses_FLARB = useFLARB;
926 <  fInfo.SIM_uses_RF = useReactionField;
919 >    //calculate mass ratio of cutoff group
920 >    vector<RealType> mfact;
921 >    SimInfo::MoleculeIterator mi;
922 >    Molecule* mol;
923 >    Molecule::CutoffGroupIterator ci;
924 >    CutoffGroup* cg;
925 >    Molecule::AtomIterator ai;
926 >    Atom* atom;
927 >    RealType totalMass;
928  
929 <  n_exclude = excludes->getSize();
930 <  excl = excludes->getFortranArray();
464 <  
465 < #ifdef IS_MPI
466 <  n_global = mpiSim->getNAtomsGlobal();
467 < #else
468 <  n_global = n_atoms;
469 < #endif
470 <  
471 <  isError = 0;
472 <  
473 <  getFortranGroupArrays(this, FglobalGroupMembership, mfact);
474 <  //it may not be a good idea to pass the address of first element in vector
475 <  //since c++ standard does not require vector to be stored continuously in meomory
476 <  //Most of the compilers will organize the memory of vector continuously
477 <  setFortranSim( &fInfo, &n_global, &n_atoms, identArray, &n_exclude, excl,
478 <                  &nGlobalExcludes, globalExcludes, molMembershipArray,
479 <                  &mfact[0], &ngroup, &FglobalGroupMembership[0], &isError);
480 <
481 <  if( isError ){
929 >    //to avoid memory reallocation, reserve enough space for mfact
930 >    mfact.reserve(getNCutoffGroups());
931      
932 <    sprintf( painCave.errMsg,
933 <             "There was an error setting the simulation information in fortran.\n" );
485 <    painCave.isFatal = 1;
486 <    painCave.severity = OOPSE_ERROR;
487 <    simError();
488 <  }
489 <  
490 < #ifdef IS_MPI
491 <  sprintf( checkPointMsg,
492 <           "succesfully sent the simulation information to fortran.\n");
493 <  MPIcheckPoint();
494 < #endif // is_mpi
495 <  
496 <  this->ndf = this->getNDF();
497 <  this->ndfRaw = this->getNDFraw();
498 <  this->ndfTrans = this->getNDFtranslational();
499 < }
932 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {        
933 >      for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
934  
935 < void SimInfo::setDefaultRcut( double theRcut ){
936 <  
937 <  haveRcut = 1;
938 <  rCut = theRcut;
939 <  rList = rCut + 1.0;
940 <  
941 <  notifyFortranCutoffs( &rCut, &rSw, &rList );
942 < }
935 >        totalMass = cg->getMass();
936 >        for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
937 >          // Check for massless groups - set mfact to 1 if true
938 >          if (totalMass != 0)
939 >            mfact.push_back(atom->getMass()/totalMass);
940 >          else
941 >            mfact.push_back( 1.0 );
942 >        }
943 >      }      
944 >    }
945  
946 < void SimInfo::setDefaultRcut( double theRcut, double theRsw ){
946 >    //fill ident array of local atoms (it is actually ident of AtomType, it is so confusing !!!)
947 >    vector<int> identArray;
948  
949 <  rSw = theRsw;
950 <  setDefaultRcut( theRcut );
951 < }
949 >    //to avoid memory reallocation, reserve enough space identArray
950 >    identArray.reserve(getNAtoms());
951 >    
952 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {        
953 >      for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
954 >        identArray.push_back(atom->getIdent());
955 >      }
956 >    }    
957  
958 +    //fill molMembershipArray
959 +    //molMembershipArray is filled by SimCreator    
960 +    vector<int> molMembershipArray(nGlobalAtoms_);
961 +    for (int i = 0; i < nGlobalAtoms_; i++) {
962 +      molMembershipArray[i] = globalMolMembership_[i] + 1;
963 +    }
964 +    
965 +    //setup fortran simulation
966  
967 < void SimInfo::checkCutOffs( void ){
968 <  
969 <  if( boxIsInit ){
967 >    nExclude = excludedInteractions_.getSize();
968 >    nOneTwo = oneTwoInteractions_.getSize();
969 >    nOneThree = oneThreeInteractions_.getSize();
970 >    nOneFour = oneFourInteractions_.getSize();
971 >
972 >    int* excludeList = excludedInteractions_.getPairList();
973 >    int* oneTwoList = oneTwoInteractions_.getPairList();
974 >    int* oneThreeList = oneThreeInteractions_.getPairList();
975 >    int* oneFourList = oneFourInteractions_.getPairList();
976 >
977 >    setFortranSim( &fInfo_, &nGlobalAtoms_, &nAtoms_, &identArray[0],
978 >                   &nExclude, excludeList,
979 >                   &nOneTwo, oneTwoList,
980 >                   &nOneThree, oneThreeList,
981 >                   &nOneFour, oneFourList,
982 >                   &molMembershipArray[0], &mfact[0], &nCutoffGroups_,
983 >                   &fortranGlobalGroupMembership[0], &isError);
984      
985 <    //we need to check cutOffs against the box
986 <    
523 <    if( rCut > maxCutoff ){
985 >    if( isError ){
986 >      
987        sprintf( painCave.errMsg,
988 <               "cutoffRadius is too large for the current periodic box.\n"
526 <               "\tCurrent Value of cutoffRadius = %G at time %G\n "
527 <               "\tThis is larger than half of at least one of the\n"
528 <               "\tperiodic box vectors.  Right now, the Box matrix is:\n"
529 <               "\n"
530 <               "\t[ %G %G %G ]\n"
531 <               "\t[ %G %G %G ]\n"
532 <               "\t[ %G %G %G ]\n",
533 <               rCut, currentTime,
534 <               Hmat[0][0], Hmat[0][1], Hmat[0][2],
535 <               Hmat[1][0], Hmat[1][1], Hmat[1][2],
536 <               Hmat[2][0], Hmat[2][1], Hmat[2][2]);
537 <      painCave.severity = OOPSE_ERROR;
988 >               "There was an error setting the simulation information in fortran.\n" );
989        painCave.isFatal = 1;
990 +      painCave.severity = OPENMD_ERROR;
991        simError();
992 <    }    
993 <  } else {
994 <    // initialize this stuff before using it, OK?
995 <    sprintf( painCave.errMsg,
996 <             "Trying to check cutoffs without a box.\n"
997 <             "\tOOPSE should have better programmers than that.\n" );
998 <    painCave.severity = OOPSE_ERROR;
999 <    painCave.isFatal = 1;
1000 <    simError();      
992 >    }
993 >    
994 >    
995 >    sprintf( checkPointMsg,
996 >             "succesfully sent the simulation information to fortran.\n");
997 >    
998 >    errorCheckPoint();
999 >    
1000 >    // Setup number of neighbors in neighbor list if present
1001 >    if (simParams_->haveNeighborListNeighbors()) {
1002 >      int nlistNeighbors = simParams_->getNeighborListNeighbors();
1003 >      setNeighbors(&nlistNeighbors);
1004 >    }
1005 >  
1006 >
1007    }
550  
551 }
1008  
553 void SimInfo::addProperty(GenericData* prop){
1009  
1010 <  map<string, GenericData*>::iterator result;
1011 <  result = properties.find(prop->getID());
1012 <  
1013 <  //we can't simply use  properties[prop->getID()] = prop,
1014 <  //it will cause memory leak if we already contain a propery which has the same name of prop
1015 <  
1016 <  if(result != properties.end()){
1017 <    
1018 <    delete (*result).second;
1019 <    (*result).second = prop;
1020 <      
1021 <  }
1022 <  else{
1010 >  void SimInfo::setupFortranParallel() {
1011 > #ifdef IS_MPI    
1012 >    //SimInfo is responsible for creating localToGlobalAtomIndex and localToGlobalGroupIndex
1013 >    vector<int> localToGlobalAtomIndex(getNAtoms(), 0);
1014 >    vector<int> localToGlobalCutoffGroupIndex;
1015 >    SimInfo::MoleculeIterator mi;
1016 >    Molecule::AtomIterator ai;
1017 >    Molecule::CutoffGroupIterator ci;
1018 >    Molecule* mol;
1019 >    Atom* atom;
1020 >    CutoffGroup* cg;
1021 >    mpiSimData parallelData;
1022 >    int isError;
1023  
1024 <    properties[prop->getID()] = prop;
1024 >    for (mol = beginMolecule(mi); mol != NULL; mol  = nextMolecule(mi)) {
1025  
1026 +      //local index(index in DataStorge) of atom is important
1027 +      for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
1028 +        localToGlobalAtomIndex[atom->getLocalIndex()] = atom->getGlobalIndex() + 1;
1029 +      }
1030 +
1031 +      //local index of cutoff group is trivial, it only depends on the order of travesing
1032 +      for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
1033 +        localToGlobalCutoffGroupIndex.push_back(cg->getGlobalIndex() + 1);
1034 +      }        
1035 +        
1036 +    }
1037 +
1038 +    //fill up mpiSimData struct
1039 +    parallelData.nMolGlobal = getNGlobalMolecules();
1040 +    parallelData.nMolLocal = getNMolecules();
1041 +    parallelData.nAtomsGlobal = getNGlobalAtoms();
1042 +    parallelData.nAtomsLocal = getNAtoms();
1043 +    parallelData.nGroupsGlobal = getNGlobalCutoffGroups();
1044 +    parallelData.nGroupsLocal = getNCutoffGroups();
1045 +    parallelData.myNode = worldRank;
1046 +    MPI_Comm_size(MPI_COMM_WORLD, &(parallelData.nProcessors));
1047 +
1048 +    //pass mpiSimData struct and index arrays to fortran
1049 +    setFsimParallel(&parallelData, &(parallelData.nAtomsLocal),
1050 +                    &localToGlobalAtomIndex[0],  &(parallelData.nGroupsLocal),
1051 +                    &localToGlobalCutoffGroupIndex[0], &isError);
1052 +
1053 +    if (isError) {
1054 +      sprintf(painCave.errMsg,
1055 +              "mpiRefresh errror: fortran didn't like something we gave it.\n");
1056 +      painCave.isFatal = 1;
1057 +      simError();
1058 +    }
1059 +
1060 +    sprintf(checkPointMsg, " mpiRefresh successful.\n");
1061 +    errorCheckPoint();
1062 +
1063 + #endif
1064    }
1065 +
1066 +
1067 +  void SimInfo::setupSwitchingFunction() {    
1068 +
1069 +  }
1070 +
1071 +  void SimInfo::setupAccumulateBoxDipole() {    
1072 +
1073 +    // we only call setAccumulateBoxDipole if the accumulateBoxDipole parameter is true
1074 +    if ( simParams_->haveAccumulateBoxDipole() )
1075 +      if ( simParams_->getAccumulateBoxDipole() ) {
1076 +        calcBoxDipole_ = true;
1077 +      }
1078 +
1079 +  }
1080 +
1081 +  void SimInfo::addProperty(GenericData* genData) {
1082 +    properties_.addProperty(genData);  
1083 +  }
1084 +
1085 +  void SimInfo::removeProperty(const string& propName) {
1086 +    properties_.removeProperty(propName);  
1087 +  }
1088 +
1089 +  void SimInfo::clearProperties() {
1090 +    properties_.clearProperties();
1091 +  }
1092 +
1093 +  vector<string> SimInfo::getPropertyNames() {
1094 +    return properties_.getPropertyNames();  
1095 +  }
1096 +      
1097 +  vector<GenericData*> SimInfo::getProperties() {
1098 +    return properties_.getProperties();
1099 +  }
1100 +
1101 +  GenericData* SimInfo::getPropertyByName(const string& propName) {
1102 +    return properties_.getPropertyByName(propName);
1103 +  }
1104 +
1105 +  void SimInfo::setSnapshotManager(SnapshotManager* sman) {
1106 +    if (sman_ == sman) {
1107 +      return;
1108 +    }    
1109 +    delete sman_;
1110 +    sman_ = sman;
1111 +
1112 +    Molecule* mol;
1113 +    RigidBody* rb;
1114 +    Atom* atom;
1115 +    SimInfo::MoleculeIterator mi;
1116 +    Molecule::RigidBodyIterator rbIter;
1117 +    Molecule::AtomIterator atomIter;;
1118 +
1119 +    for (mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
1120 +        
1121 +      for (atom = mol->beginAtom(atomIter); atom != NULL; atom = mol->nextAtom(atomIter)) {
1122 +        atom->setSnapshotManager(sman_);
1123 +      }
1124 +        
1125 +      for (rb = mol->beginRigidBody(rbIter); rb != NULL; rb = mol->nextRigidBody(rbIter)) {
1126 +        rb->setSnapshotManager(sman_);
1127 +      }
1128 +    }    
1129      
1130 < }
1130 >  }
1131  
1132 < GenericData* SimInfo::getProperty(const string& propName){
1132 >  Vector3d SimInfo::getComVel(){
1133 >    SimInfo::MoleculeIterator i;
1134 >    Molecule* mol;
1135 >
1136 >    Vector3d comVel(0.0);
1137 >    RealType totalMass = 0.0;
1138 >    
1139  
1140 <  map<string, GenericData*>::iterator result;
1141 <  
1142 <  //string lowerCaseName = ();
1143 <  
1144 <  result = properties.find(propName);
582 <  
583 <  if(result != properties.end())
584 <    return (*result).second;  
585 <  else  
586 <    return NULL;  
587 < }
1140 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1141 >      RealType mass = mol->getMass();
1142 >      totalMass += mass;
1143 >      comVel += mass * mol->getComVel();
1144 >    }  
1145  
1146 + #ifdef IS_MPI
1147 +    RealType tmpMass = totalMass;
1148 +    Vector3d tmpComVel(comVel);    
1149 +    MPI_Allreduce(&tmpMass,&totalMass,1,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1150 +    MPI_Allreduce(tmpComVel.getArrayPointer(), comVel.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1151 + #endif
1152  
1153 < void SimInfo::getFortranGroupArrays(SimInfo* info,
591 <                                    vector<int>& FglobalGroupMembership,
592 <                                    vector<double>& mfact){
593 <  
594 <  Molecule* myMols;
595 <  Atom** myAtoms;
596 <  int numAtom;
597 <  double mtot;
598 <  int numMol;
599 <  int numCutoffGroups;
600 <  CutoffGroup* myCutoffGroup;
601 <  vector<CutoffGroup*>::iterator iterCutoff;
602 <  Atom* cutoffAtom;
603 <  vector<Atom*>::iterator iterAtom;
604 <  int atomIndex;
605 <  double totalMass;
606 <  
607 <  mfact.clear();
608 <  FglobalGroupMembership.clear();
609 <  
1153 >    comVel /= totalMass;
1154  
1155 <  // Fix the silly fortran indexing problem
1155 >    return comVel;
1156 >  }
1157 >
1158 >  Vector3d SimInfo::getCom(){
1159 >    SimInfo::MoleculeIterator i;
1160 >    Molecule* mol;
1161 >
1162 >    Vector3d com(0.0);
1163 >    RealType totalMass = 0.0;
1164 >    
1165 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1166 >      RealType mass = mol->getMass();
1167 >      totalMass += mass;
1168 >      com += mass * mol->getCom();
1169 >    }  
1170 >
1171   #ifdef IS_MPI
1172 <  numAtom = mpiSim->getNAtomsGlobal();
1173 < #else
1174 <  numAtom = n_atoms;
1172 >    RealType tmpMass = totalMass;
1173 >    Vector3d tmpCom(com);    
1174 >    MPI_Allreduce(&tmpMass,&totalMass,1,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1175 >    MPI_Allreduce(tmpCom.getArrayPointer(), com.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1176   #endif
617  for (int i = 0; i < numAtom; i++)
618    FglobalGroupMembership.push_back(globalGroupMembership[i] + 1);
619  
1177  
1178 <  myMols = info->molecules;
622 <  numMol = info->n_mol;
623 <  for(int i  = 0; i < numMol; i++){
624 <    numCutoffGroups = myMols[i].getNCutoffGroups();
625 <    for(myCutoffGroup =myMols[i].beginCutoffGroup(iterCutoff);
626 <        myCutoffGroup != NULL;
627 <        myCutoffGroup =myMols[i].nextCutoffGroup(iterCutoff)){
1178 >    com /= totalMass;
1179  
1180 <      totalMass = myCutoffGroup->getMass();
1180 >    return com;
1181 >
1182 >  }        
1183 >
1184 >  ostream& operator <<(ostream& o, SimInfo& info) {
1185 >
1186 >    return o;
1187 >  }
1188 >  
1189 >  
1190 >   /*
1191 >   Returns center of mass and center of mass velocity in one function call.
1192 >   */
1193 >  
1194 >   void SimInfo::getComAll(Vector3d &com, Vector3d &comVel){
1195 >      SimInfo::MoleculeIterator i;
1196 >      Molecule* mol;
1197        
1198 <      for(cutoffAtom = myCutoffGroup->beginAtom(iterAtom);
1199 <          cutoffAtom != NULL;
1200 <          cutoffAtom = myCutoffGroup->nextAtom(iterAtom)){
1201 <        mfact.push_back(cutoffAtom->getMass()/totalMass);
1198 >    
1199 >      RealType totalMass = 0.0;
1200 >    
1201 >
1202 >      for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1203 >         RealType mass = mol->getMass();
1204 >         totalMass += mass;
1205 >         com += mass * mol->getCom();
1206 >         comVel += mass * mol->getComVel();          
1207        }  
1208 +      
1209 + #ifdef IS_MPI
1210 +      RealType tmpMass = totalMass;
1211 +      Vector3d tmpCom(com);  
1212 +      Vector3d tmpComVel(comVel);
1213 +      MPI_Allreduce(&tmpMass,&totalMass,1,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1214 +      MPI_Allreduce(tmpCom.getArrayPointer(), com.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1215 +      MPI_Allreduce(tmpComVel.getArrayPointer(), comVel.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1216 + #endif
1217 +      
1218 +      com /= totalMass;
1219 +      comVel /= totalMass;
1220 +   }        
1221 +  
1222 +   /*
1223 +   Return intertia tensor for entire system and angular momentum Vector.
1224 +
1225 +
1226 +       [  Ixx -Ixy  -Ixz ]
1227 +    J =| -Iyx  Iyy  -Iyz |
1228 +       [ -Izx -Iyz   Izz ]
1229 +    */
1230 +
1231 +   void SimInfo::getInertiaTensor(Mat3x3d &inertiaTensor, Vector3d &angularMomentum){
1232 +      
1233 +
1234 +      RealType xx = 0.0;
1235 +      RealType yy = 0.0;
1236 +      RealType zz = 0.0;
1237 +      RealType xy = 0.0;
1238 +      RealType xz = 0.0;
1239 +      RealType yz = 0.0;
1240 +      Vector3d com(0.0);
1241 +      Vector3d comVel(0.0);
1242 +      
1243 +      getComAll(com, comVel);
1244 +      
1245 +      SimInfo::MoleculeIterator i;
1246 +      Molecule* mol;
1247 +      
1248 +      Vector3d thisq(0.0);
1249 +      Vector3d thisv(0.0);
1250 +
1251 +      RealType thisMass = 0.0;
1252 +    
1253 +      
1254 +      
1255 +  
1256 +      for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
1257 +        
1258 +         thisq = mol->getCom()-com;
1259 +         thisv = mol->getComVel()-comVel;
1260 +         thisMass = mol->getMass();
1261 +         // Compute moment of intertia coefficients.
1262 +         xx += thisq[0]*thisq[0]*thisMass;
1263 +         yy += thisq[1]*thisq[1]*thisMass;
1264 +         zz += thisq[2]*thisq[2]*thisMass;
1265 +        
1266 +         // compute products of intertia
1267 +         xy += thisq[0]*thisq[1]*thisMass;
1268 +         xz += thisq[0]*thisq[2]*thisMass;
1269 +         yz += thisq[1]*thisq[2]*thisMass;
1270 +            
1271 +         angularMomentum += cross( thisq, thisv ) * thisMass;
1272 +            
1273 +      }  
1274 +      
1275 +      
1276 +      inertiaTensor(0,0) = yy + zz;
1277 +      inertiaTensor(0,1) = -xy;
1278 +      inertiaTensor(0,2) = -xz;
1279 +      inertiaTensor(1,0) = -xy;
1280 +      inertiaTensor(1,1) = xx + zz;
1281 +      inertiaTensor(1,2) = -yz;
1282 +      inertiaTensor(2,0) = -xz;
1283 +      inertiaTensor(2,1) = -yz;
1284 +      inertiaTensor(2,2) = xx + yy;
1285 +      
1286 + #ifdef IS_MPI
1287 +      Mat3x3d tmpI(inertiaTensor);
1288 +      Vector3d tmpAngMom;
1289 +      MPI_Allreduce(tmpI.getArrayPointer(), inertiaTensor.getArrayPointer(),9,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1290 +      MPI_Allreduce(tmpAngMom.getArrayPointer(), angularMomentum.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1291 + #endif
1292 +              
1293 +      return;
1294 +   }
1295 +
1296 +   //Returns the angular momentum of the system
1297 +   Vector3d SimInfo::getAngularMomentum(){
1298 +      
1299 +      Vector3d com(0.0);
1300 +      Vector3d comVel(0.0);
1301 +      Vector3d angularMomentum(0.0);
1302 +      
1303 +      getComAll(com,comVel);
1304 +      
1305 +      SimInfo::MoleculeIterator i;
1306 +      Molecule* mol;
1307 +      
1308 +      Vector3d thisr(0.0);
1309 +      Vector3d thisp(0.0);
1310 +      
1311 +      RealType thisMass;
1312 +      
1313 +      for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {        
1314 +        thisMass = mol->getMass();
1315 +        thisr = mol->getCom()-com;
1316 +        thisp = (mol->getComVel()-comVel)*thisMass;
1317 +        
1318 +        angularMomentum += cross( thisr, thisp );
1319 +        
1320 +      }  
1321 +      
1322 + #ifdef IS_MPI
1323 +      Vector3d tmpAngMom;
1324 +      MPI_Allreduce(tmpAngMom.getArrayPointer(), angularMomentum.getArrayPointer(),3,MPI_REALTYPE,MPI_SUM, MPI_COMM_WORLD);
1325 + #endif
1326 +      
1327 +      return angularMomentum;
1328 +   }
1329 +  
1330 +  StuntDouble* SimInfo::getIOIndexToIntegrableObject(int index) {
1331 +    return IOIndexToIntegrableObject.at(index);
1332 +  }
1333 +  
1334 +  void SimInfo::setIOIndexToIntegrableObject(const vector<StuntDouble*>& v) {
1335 +    IOIndexToIntegrableObject= v;
1336 +  }
1337 +
1338 +  /* Returns the Volume of the simulation based on a ellipsoid with semi-axes
1339 +     based on the radius of gyration V=4/3*Pi*R_1*R_2*R_3
1340 +     where R_i are related to the principle inertia moments R_i = sqrt(C*I_i/N), this reduces to
1341 +     V = 4/3*Pi*(C/N)^3/2*sqrt(det(I)). See S.E. Baltazar et. al. Comp. Mat. Sci. 37 (2006) 526-536.
1342 +  */
1343 +  void SimInfo::getGyrationalVolume(RealType &volume){
1344 +    Mat3x3d intTensor;
1345 +    RealType det;
1346 +    Vector3d dummyAngMom;
1347 +    RealType sysconstants;
1348 +    RealType geomCnst;
1349 +
1350 +    geomCnst = 3.0/2.0;
1351 +    /* Get the inertial tensor and angular momentum for free*/
1352 +    getInertiaTensor(intTensor,dummyAngMom);
1353 +    
1354 +    det = intTensor.determinant();
1355 +    sysconstants = geomCnst/(RealType)nGlobalIntegrableObjects_;
1356 +    volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,3.0/2.0)*sqrt(det);
1357 +    return;
1358 +  }
1359 +
1360 +  void SimInfo::getGyrationalVolume(RealType &volume, RealType &detI){
1361 +    Mat3x3d intTensor;
1362 +    Vector3d dummyAngMom;
1363 +    RealType sysconstants;
1364 +    RealType geomCnst;
1365 +
1366 +    geomCnst = 3.0/2.0;
1367 +    /* Get the inertial tensor and angular momentum for free*/
1368 +    getInertiaTensor(intTensor,dummyAngMom);
1369 +    
1370 +    detI = intTensor.determinant();
1371 +    sysconstants = geomCnst/(RealType)nGlobalIntegrableObjects_;
1372 +    volume = 4.0/3.0*NumericConstant::PI*pow(sysconstants,3.0/2.0)*sqrt(detI);
1373 +    return;
1374 +  }
1375 + /*
1376 +   void SimInfo::setStuntDoubleFromGlobalIndex(vector<StuntDouble*> v) {
1377 +      assert( v.size() == nAtoms_ + nRigidBodies_);
1378 +      sdByGlobalIndex_ = v;
1379      }
1380 +
1381 +    StuntDouble* SimInfo::getStuntDoubleFromGlobalIndex(int index) {
1382 +      //assert(index < nAtoms_ + nRigidBodies_);
1383 +      return sdByGlobalIndex_.at(index);
1384 +    }  
1385 + */  
1386 +  int SimInfo::getNGlobalConstraints() {
1387 +    int nGlobalConstraints;
1388 + #ifdef IS_MPI
1389 +    MPI_Allreduce(&nConstraints_, &nGlobalConstraints, 1, MPI_INT, MPI_SUM,
1390 +                  MPI_COMM_WORLD);    
1391 + #else
1392 +    nGlobalConstraints =  nConstraints_;
1393 + #endif
1394 +    return nGlobalConstraints;
1395    }
1396  
1397 < }
1397 > }//end namespace OpenMD
1398 >

Comparing:
trunk/src/brains/SimInfo.cpp (property svn:keywords), Revision 143 by chrisfen, Fri Oct 22 22:54:01 2004 UTC vs.
branches/development/src/brains/SimInfo.cpp (property svn:keywords), Revision 1530 by gezelter, Tue Dec 28 21:47:55 2010 UTC

# Line 0 | Line 1
1 + Author Id Revision Date

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines