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

Comparing:
trunk/src/brains/SimInfo.cpp (property svn:keywords), Revision 2 by gezelter, Fri Sep 24 04:16:43 2004 UTC vs.
branches/development/src/brains/SimInfo.cpp (property svn:keywords), Revision 1534 by gezelter, Wed Dec 29 21:53:28 2010 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines