ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/branches/new_design/OOPSE-2.0/src/brains/SimInfo.cpp
(Generate patch)

Comparing branches/new_design/OOPSE-2.0/src/brains/SimInfo.cpp (file contents):
Revision 1701 by tim, Wed Nov 3 16:08:43 2004 UTC vs.
Revision 1735 by tim, Fri Nov 12 17:40:03 2004 UTC

# Line 1 | Line 1
1 < #include <stdlib.h>
2 < #include <string.h>
3 < #include <math.h>
1 > /*
2 > * Copyright (C) 2000-2004  Object Oriented Parallel Simulation Engine (OOPSE) project
3 > *
4 > * Contact: oopse@oopse.org
5 > *
6 > * This program is free software; you can redistribute it and/or
7 > * modify it under the terms of the GNU Lesser General Public License
8 > * as published by the Free Software Foundation; either version 2.1
9 > * of the License, or (at your option) any later version.
10 > * All we ask is that proper credit is given for our work, which includes
11 > * - but is not limited to - adding the above copyright notice to the beginning
12 > * of your source code files, and to any copyright notice that you may distribute
13 > * with programs based on this work.
14 > *
15 > * This program is distributed in the hope that it will be useful,
16 > * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 > * GNU Lesser General Public License for more details.
19 > *
20 > * You should have received a copy of the GNU Lesser General Public License
21 > * along with this program; if not, write to the Free Software
22 > * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 > *
24 > */
25  
26 < #include <iostream>
27 < using namespace std;
26 > /**
27 > * @file SimInfo.cpp
28 > * @author    tlin
29 > * @date  11/02/2004
30 > * @version 1.0
31 > */
32  
33 + #include <algorithm>
34 +
35   #include "brains/SimInfo.hpp"
36 < #define __C
10 < #include "brains/fSimulation.h"
11 < #include "utils/simError.h"
12 < #include "UseTheForce/DarkSide/simulation_interface.h"
13 < #include "UseTheForce/notifyCutoffs_interface.h"
36 > #include "utils/MemoryUtils.hpp"
37  
38 < //#include "UseTheForce/fortranWrappers.hpp"
38 > namespace oopse {
39  
40 < #include "math/MatVec3.h"
40 > SimInfo::SimInfo(const std::vector<std::pair<MoleculeStamp*, int> >& molStampPairs,
41 >                                ForceField* ff, Globals* globals) :
42 >                                forceField_(ff), globals_(globals), nAtoms_(0), nBonds_(0),
43 >                                nBends_(0), nTorsions_(0), nRigidBodies_(0), nIntegrableObjects_(0),
44 >                                nCutoffGroups_(0), nConstraints_(0), nZConstraint_(0), sman_(NULL) {
45  
46 < #ifdef IS_MPI
47 < #include "brains/mpiSimulation.hpp"
48 < #endif
46 >    std::vector<std::pair<MoleculeStamp*, int> >::iterator i;
47 >    int nCutoffAtoms; // number of atoms belong to cutoff groups
48 >    int ngroups;          //total cutoff groups defined in meta-data file
49 >    MoleculeStamp* molStamp;
50 >    int nMolWithSameStamp;
51 >    CutoffGroupStamp* cgStamp;
52 >    int nAtomsIngroups;
53 >    int nCutoffGroupsInStamp;    
54  
55 < inline double roundMe( double x ){
56 <  return ( x >= 0 ) ? floor( x + 0.5 ) : ceil( x - 0.5 );
57 < }
58 <          
59 < inline double min( double a, double b ){
60 <  return (a < b ) ? a : b;
61 < }
55 >    nGlobalAtoms_ =  0;
56 >    ngroups = 0;
57 >    
58 >    for (i = molStampPairs.begin(); i !=molStampPairs.end(); ++i) {
59 >        molStamp = i->first;
60 >        nMolWithSameStamp = i->second;
61 >        
62 >        addMoleculeStamp(molStamp, nMolWithSameStamp);
63 >        
64 >        nGlobalAtoms_ += molStamp->getNAtoms() *nMolWithSameStamp;  
65 >        
66 >        nAtomsIngroups = 0;
67 >        nCutoffGroupsInStamp = molStamp->getNCutoffGroups();
68 >        
69 >        for (int j=0; j < nCutoffGroupsInStamp; j++) {
70 >            cgStamp = molStamp->getCutoffGroup(j);
71 >            nAtomsIngroups += cgStamp->getNMembers();
72 >        }
73  
74 < SimInfo* currentInfo;
74 >        ngroups += *nMolWithSameStamp;
75 >        nCutoffAtoms += nAtomsIngroups * nMolWithSameStamp;                
76 >    }
77  
78 < SimInfo::SimInfo(){
78 >    //every free atom (atom does not belong to cutoff groups) is a cutoff group
79 >    //therefore the total number of cutoff groups in the system is equal to
80 >    //the total number of atoms minus number of atoms belong to cutoff group defined in meta-data
81 >    //file plus the number of cutoff groups defined in meta-data file
82 >    nGlobalCutoffGroups_ = nGlobalAtoms_ - nCutoffAtoms + ngroups;
83  
84 <  n_constraints = 0;
85 <  nZconstraints = 0;
37 <  n_oriented = 0;
38 <  n_dipoles = 0;
39 <  ndf = 0;
40 <  ndfRaw = 0;
41 <  nZconstraints = 0;
42 <  the_integrator = NULL;
43 <  setTemp = 0;
44 <  thermalTime = 0.0;
45 <  currentTime = 0.0;
46 <  rCut = 0.0;
47 <  rSw = 0.0;
84 >    //initialize globalGroupMembership_, every element of this array will be 0
85 >    globalGroupMembership_.insert(globalGroupMembership_.end(), nGlobalAtoms_, 0);
86  
87 <  haveRcut = 0;
50 <  haveRsw = 0;
51 <  boxIsInit = 0;
52 <  
53 <  resetTime = 1e99;
87 >    nGlobalMols_ = molStampIds_.size();
88  
89 <  orthoRhombic = 0;
90 <  orthoTolerance = 1E-6;
91 <  useInitXSstate = true;
89 > #ifdef IS_MPI    
90 >    molToProcMap_.resize(nGlobalMols_);
91 > #endif
92 >    
93 > }
94  
95 <  usePBC = 0;
96 <  useDirectionalAtoms = 0;
61 <  useLennardJones = 0;
62 <  useElectrostatics = 0;
63 <  useCharges = 0;
64 <  useDipoles = 0;
65 <  useSticky = 0;
66 <  useGayBerne = 0;
67 <  useEAM = 0;
68 <  useShapes = 0;
69 <  useFLARB = 0;
95 > SimInfo::~SimInfo() {
96 >    //MemoryUtils::deleteVectorOfPointer(molecules_);
97  
98 <  useSolidThermInt = 0;
99 <  useLiquidThermInt = 0;
98 >    MemoryUtils::deleteVectorOfPointer(moleculeStamps_);
99 >    
100 >    delete sman_;
101 >    delete globals_;
102 >    delete forceField_;
103  
104 <  haveCutoffGroups = false;
104 > }
105  
76  excludes = Exclude::Instance();
106  
107 <  myConfiguration = new SimState();
107 > bool SimInfo::addMolecule(Molecule* mol) {
108 >    MoleculeIterator i;
109  
110 <  has_minimizer = false;
111 <  the_minimizer =NULL;
110 >    i = molecules_.find(mol->getGlobalIndex());
111 >    if (i != molecules_.end() ) {
112  
113 <  ngroup = 0;
113 >        molecules_.insert(make_pair(mol->getGlobalIndex(), mol));
114 >        
115 >        nAtoms_ += mol->getNAtoms();
116 >        nBonds_ += mol->getNBonds();
117 >        nBends_ += mol->getNBends();
118 >        nTorsions_ += mol->getNTorsions();
119 >        nRigidBodies_ += mol->getNRigidBodies();
120 >        nIntegrableObjects_ += mol->getNIntegrableObjects();
121 >        nCutoffGroups_ += mol->getNCutoffGroups();
122 >        nConstraints_ += mol->getNConstraints();
123  
124 +        return true;
125 +    } else {
126 +        return false;
127 +    }
128   }
129  
130 + bool SimInfo::removeMolecule(Molecule* mol) {
131 +    MoleculeIterator i;
132 +    i = molecules_.find(mol->getGlobalIndex());
133  
134 < SimInfo::~SimInfo(){
134 >    if (i != molecules_.end() ) {
135  
136 <  delete myConfiguration;
136 >        assert(mol == i->second);
137 >        
138 >        nAtoms_ -= mol->getNAtoms();
139 >        nBonds_ -= mol->getNBonds();
140 >        nBends_ -= mol->getNBends();
141 >        nTorsions_ -= mol->getNTorsions();
142 >        nRigidBodies_ -= mol->getNRigidBodies();
143 >        nIntegrableObjects_ -= mol->getNIntegrableObjects();
144 >        nCutoffGroups_ -= mol->getNCutoffGroups();
145 >        nConstraints_ -= mol->getNConstraints();
146  
147 <  map<string, GenericData*>::iterator i;
93 <  
94 <  for(i = properties.begin(); i != properties.end(); i++)
95 <    delete (*i).second;
147 >        molecules_.erase(mol->getGlobalIndex());
148  
149 < }
149 >        delete mol;
150 >        
151 >        return true;
152 >    } else {
153 >        return false;
154 >    }
155  
99 void SimInfo::setBox(double newBox[3]) {
100  
101  int i, j;
102  double tempMat[3][3];
156  
157 <  for(i=0; i<3; i++)
105 <    for (j=0; j<3; j++) tempMat[i][j] = 0.0;;
157 > }    
158  
159 <  tempMat[0][0] = newBox[0];
160 <  tempMat[1][1] = newBox[1];
161 <  tempMat[2][2] = newBox[2];
159 >        
160 > Molecule* SimInfo::beginMolecule(MoleculeIterator& i) {
161 >    i = molecules_.begin();
162 >    return i == molecules_.end() ? NULL : *i;
163 > }    
164  
165 <  setBoxM( tempMat );
166 <
165 > Molecule* SimInfo::nextMolecule(MoleculeIterator& i) {
166 >    ++i;
167 >    return i == molecules_.end() ? NULL : *i;    
168   }
169  
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);
170  
171 <  if( !boxIsInit ) boxIsInit = 1;
171 > void SimInfo::calcNdf() {
172 >    int ndf_local;
173 >    MoleculeIterator i;
174 >    std::vector<StuntDouble*>::iterator j;
175 >    Molecule* mol;
176 >    StuntDouble* integrableObject;
177  
178 <  for(i=0; i < 3; i++)
179 <    for (j=0; j < 3; j++) Hmat[i][j] = theBox[i][j];
180 <  
181 <  calcBoxL();
182 <  calcHmatInv();
178 >    ndf_local = 0;
179 >    
180 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
181 >        for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
182 >               integrableObject = mol->nextIntegrableObject(j)) {
183  
184 <  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 <    }
138 <  }
184 >            ndf_local += 3;
185  
186 <  setFortranBox(FortranHmat, FortranHmatInv, &orthoRhombic);
187 <
188 < }
189 <
186 >            if (integrableObject->isDirectional()) {
187 >                if (integrableObject->isLinear()) {
188 >                    ndf_local += 2;
189 >                } else {
190 >                    ndf_local += 3;
191 >                }
192 >            }
193 >            
194 >        }//end for (integrableObject)
195 >    }// end for (mol)
196 >    
197 >    // n_constraints is local, so subtract them on each processor
198 >    ndf_local -= nConstraints_;
199  
200 < void SimInfo::getBoxM (double theBox[3][3]) {
200 > #ifdef IS_MPI
201 >    MPI_Allreduce(&ndf_local,&ndf_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
202 > #else
203 >    ndf_ = ndf_local;
204 > #endif
205  
206 <  int i, j;
207 <  for(i=0; i<3; i++)
208 <    for (j=0; j<3; j++) theBox[i][j] = Hmat[i][j];
206 >    // nZconstraints_ is global, as are the 3 COM translations for the
207 >    // entire system:
208 >    ndf_ = ndf_ - 3 - nZconstraints_;
209 >
210   }
211  
212 + void SimInfo::calcNdfRaw() {
213 +    int ndfRaw_local;
214  
215 < void SimInfo::scaleBox(double scale) {
216 <  double theBox[3][3];
217 <  int i, j;
215 >    MoleculeIterator i;
216 >    std::vector<StuntDouble*>::iterator j;
217 >    Molecule* mol;
218 >    StuntDouble* integrableObject;
219  
220 <  // cerr << "Scaling box by " << scale << "\n";
220 >    // Raw degrees of freedom that we have to set
221 >    ndfRaw_local = 0;
222 >    
223 >    for (mol = beginMolecule(i); mol != NULL; mol = nextMolecule(i)) {
224 >        for (integrableObject = mol->beginIntegrableObject(j); integrableObject != NULL;
225 >               integrableObject = mol->nextIntegrableObject(j)) {
226  
227 <  for(i=0; i<3; i++)
160 <    for (j=0; j<3; j++) theBox[i][j] = Hmat[i][j]*scale;
227 >            ndfRaw_local += 3;
228  
229 <  setBoxM(theBox);
230 <
229 >            if (integrableObject->isDirectional()) {
230 >                if (integrableObject->isLinear()) {
231 >                    ndfRaw_local += 2;
232 >                } else {
233 >                    ndfRaw_local += 3;
234 >                }
235 >            }
236 >            
237 >        }
238 >    }
239 >    
240 > #ifdef IS_MPI
241 >    MPI_Allreduce(&ndfRaw_local,&ndfRaw_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
242 > #else
243 >    ndfRaw_ = ndfRaw_local;
244 > #endif
245   }
246  
247 < void SimInfo::calcHmatInv( void ) {
248 <  
168 <  int oldOrtho;
169 <  int i,j;
170 <  double smallDiag;
171 <  double tol;
172 <  double sanity[3][3];
247 > void SimInfo::calcNdfTrans() {
248 >    int ndfTrans_local;
249  
250 <  invertMat3( Hmat, HmatInv );
250 >    ndfTrans_local = 3 * nIntegrableObjects_ - nConstraints_;
251  
176  // check to see if Hmat is orthorhombic
177  
178  oldOrtho = orthoRhombic;
252  
253 <  smallDiag = fabs(Hmat[0][0]);
254 <  if(smallDiag > fabs(Hmat[1][1])) smallDiag = fabs(Hmat[1][1]);
255 <  if(smallDiag > fabs(Hmat[2][2])) smallDiag = fabs(Hmat[2][2]);
256 <  tol = smallDiag * orthoTolerance;
253 > #ifdef IS_MPI
254 >    MPI_Allreduce(&ndfTrans_local,&ndfTrans_,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
255 > #else
256 >    ndfTrans_ = ndfTrans_local;
257 > #endif
258  
259 <  orthoRhombic = 1;
260 <  
261 <  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 <        }        
193 <      }
194 <    }
195 <  }
259 >    ndfTrans_ = ndfTrans_ - 3 - nZconstraints_;
260 >
261 > }
262  
263 <  if( oldOrtho != orthoRhombic ){
263 > void SimInfo::addExcludePairs(Molecule* mol) {
264 >    std::vector<Bond*>::iterator bondIter;
265 >    std::vector<Bend*>::iterator bendIter;
266 >    std::vector<Torsion*>::iterator torsionIter;
267 >    Bond* bond;
268 >    Bend* bend;
269 >    Torsion* torsion;
270 >    int a;
271 >    int b;
272 >    int c;
273 >    int d;
274      
275 <    if( orthoRhombic ) {
276 <      sprintf( painCave.errMsg,
277 <               "OOPSE is switching from the default Non-Orthorhombic\n"
278 <               "\tto the faster Orthorhombic periodic boundary computations.\n"
203 <               "\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();
275 >    for (bond= mol->beginBond(bondIter); bond != NULL; bond = mol->nextBond(bondIter)) {
276 >        a = bond->getAtomA()->getGlobalIndex();
277 >        b = bond->getAtomB()->getGlobalIndex();        
278 >        exclude_.addPair(a, b);
279      }
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    }
222  }
223 }
280  
281 < void SimInfo::calcBoxL( void ){
281 >    for (bend= mol->beginBend(bendIter); bend != NULL; bend = mol->nextBend(bendIter)) {
282 >        a = bend->getAtomA()->getGlobalIndex();
283 >        b = bend->getAtomB()->getGlobalIndex();        
284 >        c = bend->getAtomC()->getGlobalIndex();
285  
286 <  double dx, dy, dz, dsq;
286 >        exclude_.addPair(a, b);
287 >        exclude_.addPair(a, c);
288 >        exclude_.addPair(b, c);        
289 >    }
290  
291 <  // boxVol = Determinant of Hmat
291 >    for (torsion= mol->beginTorsion(torsionIter); torsion != NULL; torsion = mol->nextBond(torsionIter)) {
292 >        a = torsion->getAtomA()->getGlobalIndex();
293 >        b = torsion->getAtomB()->getGlobalIndex();        
294 >        c = torsion->getAtomC()->getGlobalIndex();        
295 >        d = torsion->getAtomD()->getGlobalIndex();        
296  
297 <  boxVol = matDet3( Hmat );
297 >        exclude_.addPair(a, b);
298 >        exclude_.addPair(a, c);
299 >        exclude_.addPair(a, d);
300 >        exclude_.addPair(b, c);
301 >        exclude_.addPair(b, d);
302 >        exclude_.addPair(c, d);        
303 >    }
304  
305 <  // boxLx
306 <  
235 <  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];
305 >    
306 > }
307  
308 <  // boxLy
309 <  
310 <  dx = Hmat[0][1]; dy = Hmat[1][1]; dz = Hmat[2][1];
311 <  dsq = dx*dx + dy*dy + dz*dz;
312 <  boxL[1] = sqrt( dsq );
313 <  //if( (0.5 * boxL[1]) < maxCutoff ) maxCutoff = 0.5 * boxL[1];
308 > void SimInfo::removeExcludePairs(Molecule* mol) {
309 >    std::vector<Bond*>::iterator bondIter;
310 >    std::vector<Bend*>::iterator bendIter;
311 >    std::vector<Torsion*>::iterator torsionIter;
312 >    Bond* bond;
313 >    Bend* bend;
314 >    Torsion* torsion;
315 >    int a;
316 >    int b;
317 >    int c;
318 >    int d;
319 >    
320 >    for (bond= mol->beginBond(bondIter); bond != NULL; bond = mol->nextBond(bondIter)) {
321 >        a = bond->getAtomA()->getGlobalIndex();
322 >        b = bond->getAtomB()->getGlobalIndex();        
323 >        exclude_.removePair(a, b);
324 >    }
325  
326 +    for (bend= mol->beginBend(bendIter); bend != NULL; bend = mol->nextBend(bendIter)) {
327 +        a = bend->getAtomA()->getGlobalIndex();
328 +        b = bend->getAtomB()->getGlobalIndex();        
329 +        c = bend->getAtomC()->getGlobalIndex();
330  
331 <  // boxLz
332 <  
333 <  dx = Hmat[0][2]; dy = Hmat[1][2]; dz = Hmat[2][2];
334 <  dsq = dx*dx + dy*dy + dz*dz;
252 <  boxL[2] = sqrt( dsq );
253 <  //if( (0.5 * boxL[2]) < maxCutoff ) maxCutoff = 0.5 * boxL[2];
331 >        exclude_.removePair(a, b);
332 >        exclude_.removePair(a, c);
333 >        exclude_.removePair(b, c);        
334 >    }
335  
336 <  //calculate the max cutoff
337 <  maxCutoff =  calcMaxCutOff();
338 <  
339 <  checkCutOffs();
336 >    for (torsion= mol->beginTorsion(torsionIter); torsion != NULL; torsion = mol->nextBond(torsionIter)) {
337 >        a = torsion->getAtomA()->getGlobalIndex();
338 >        b = torsion->getAtomB()->getGlobalIndex();        
339 >        c = torsion->getAtomC()->getGlobalIndex();        
340 >        d = torsion->getAtomD()->getGlobalIndex();        
341  
342 +        exclude_.removePair(a, b);
343 +        exclude_.removePair(a, c);
344 +        exclude_.removePair(a, d);
345 +        exclude_.removePair(b, c);
346 +        exclude_.removePair(b, d);
347 +        exclude_.removePair(c, d);        
348 +    }
349 +
350   }
351  
352  
353 < double SimInfo::calcMaxCutOff(){
353 > void SimInfo::addMoleculeStamp(MoleculeStamp* molStamp, int nmol) {
354 >    int curStampId;
355  
356 <  double ri[3], rj[3], rk[3];
357 <  double rij[3], rjk[3], rki[3];
267 <  double minDist;
356 >    //index from 0
357 >    curStampId = molStampIds_.size();
358  
359 <  ri[0] = Hmat[0][0];
360 <  ri[1] = Hmat[1][0];
361 <  ri[2] = Hmat[2][0];
359 >    moleculeStamps_.push_back(molStamp);
360 >    molStampIds_.insert(molStampIds_.end(), nmol, curStampId)
361 > }
362  
363 <  rj[0] = Hmat[0][1];
274 <  rj[1] = Hmat[1][1];
275 <  rj[2] = Hmat[2][1];
363 > void SimInfo::update() {
364  
365 <  rk[0] = Hmat[0][2];
366 <  rk[1] = Hmat[1][2];
367 <  rk[2] = Hmat[2][2];
280 <    
281 <  crossProduct3(ri, rj, rij);
282 <  distXY = dotProduct3(rk,rij) / norm3(rij);
365 > #ifdef IS_MPI
366 >    setupFortranParallel();
367 > #endif
368  
369 <  crossProduct3(rj,rk, rjk);
285 <  distYZ = dotProduct3(ri,rjk) / norm3(rjk);
369 >    setupFortranSim();
370  
371 <  crossProduct3(rk,ri, rki);
372 <  distZX = dotProduct3(rj,rki) / norm3(rki);
373 <
290 <  minDist = min(min(distXY, distYZ), distZX);
291 <  return minDist/2;
292 <  
371 >    calcNdf();
372 >    calcNdfRaw();
373 >    calcNdfTrans();
374   }
375  
376 < void SimInfo::wrapVector( double thePos[3] ){
376 > std::set<AtomType*> SimInfo::getUniqueAtomTypes() {
377 >    typename SimInfo::MoleculeIterator mi;
378 >    Molecule* mol;
379 >    typename Molecule::AtomIterator ai;
380 >    Atom* atom;
381 >    std::set<AtomType*> atomTypes;
382  
383 <  int i;
298 <  double scaled[3];
383 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {
384  
385 <  if( !orthoRhombic ){
386 <    // calc the scaled coordinates.
387 <  
385 >        for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
386 >            atomTypes.insert(atom->getAtomType());
387 >        }
388 >        
389 >    }
390  
391 <    matVecMul3(HmatInv, thePos, scaled);
392 <    
306 <    for(i=0; i<3; i++)
307 <      scaled[i] -= roundMe(scaled[i]);
308 <    
309 <    // calc the wrapped real coordinates from the wrapped scaled coordinates
310 <    
311 <    matVecMul3(Hmat, scaled, thePos);
391 >    return atomTypes;        
392 > }
393  
394 <  }
395 <  else{
396 <    // calc the scaled coordinates.
394 > void SimInfo::setupSimType() {
395 >    std::set<AtomType*>::iterator i;
396 >    std::set<AtomType*> atomTypes;
397 >    atomTypes = getUniqueAtomTypes();
398      
399 <    for(i=0; i<3; i++)
400 <      scaled[i] = thePos[i]*HmatInv[i][i];
401 <    
402 <    // wrap the scaled coordinates
403 <    
404 <    for(i=0; i<3; i++)
405 <      scaled[i] -= roundMe(scaled[i]);
406 <    
407 <    // calc the wrapped real coordinates from the wrapped scaled coordinates
408 <    
409 <    for(i=0; i<3; i++)
410 <      thePos[i] = scaled[i]*Hmat[i][i];
411 <  }
412 <    
413 < }
399 >    int useLennardJones = 0;
400 >    int useElectrostatic = 0;
401 >    int useEAM = 0;
402 >    int useCharge = 0;
403 >    int useDirectional = 0;
404 >    int useDipole = 0;
405 >    int useGayBerne = 0;
406 >    int useSticky = 0;
407 >    int useShape = 0;
408 >    int useFLARB = 0; //it is not in AtomType yet
409 >    int useDirectionalAtom = 0;    
410 >    int useElectrostatics = 0;
411 >    //usePBC and useRF are from globals
412 >    bool usePBC = globals_->getPBC();
413 >    bool useRF = globals_->getUseRF();
414  
415 +    //loop over all of the atom types
416 +    for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
417 +        useLennardJones |= i->isLennardJones();
418 +        useElectrostatic |= i->isElectrostatic();
419 +        useEAM |= i->isEAM();
420 +        useCharge |= i->isCharge();
421 +        useDirectional |= i->isDirectional();
422 +        useDipole |= i->isDipole();
423 +        useGayBerne |= i->isGayBerne();
424 +        useSticky |= i->isSticky();
425 +        useShape |= i->isShape();
426 +    }
427  
428 < int SimInfo::getNDF(){
429 <  int ndf_local;
428 >    if (useSticky || useDipole || useGayBerne || useShape) {
429 >        useDirectionalAtom = 1;
430 >    }
431  
432 <  ndf_local = 0;
433 <  
339 <  for(int i = 0; i < integrableObjects.size(); i++){
340 <    ndf_local += 3;
341 <    if (integrableObjects[i]->isDirectional()) {
342 <      if (integrableObjects[i]->isLinear())
343 <        ndf_local += 2;
344 <      else
345 <        ndf_local += 3;
432 >    if (useCharge || useDipole) {
433 >        useElectrostatics = 1;
434      }
347  }
435  
436 <  // n_constraints is local, so subtract them on each processor:
436 > #ifdef IS_MPI    
437 >    int temp;
438  
439 <  ndf_local -= n_constraints;
439 >    temp = usePBC;
440 >    MPI_Allreduce(&temp, &usePBC, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
441  
442 < #ifdef IS_MPI
443 <  MPI_Allreduce(&ndf_local,&ndf,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
355 < #else
356 <  ndf = ndf_local;
357 < #endif
442 >    temp = useDirectionalAtom;
443 >    MPI_Allreduce(&temp, &useDirectionalAtom, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
444  
445 <  // nZconstraints is global, as are the 3 COM translations for the
446 <  // entire system:
445 >    temp = useLennardJones;
446 >    MPI_Allreduce(&temp, &useLennardJones, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
447  
448 <  ndf = ndf - 3 - nZconstraints;
448 >    temp = useElectrostatics;
449 >    MPI_Allreduce(&temp, &useElectrostatics, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
450  
451 <  return ndf;
452 < }
451 >    temp = useCharge;
452 >    MPI_Allreduce(&temp, &useCharge, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
453  
454 < int SimInfo::getNDFraw() {
455 <  int ndfRaw_local;
454 >    temp = useDipole;
455 >    MPI_Allreduce(&temp, &useDipole, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
456  
457 <  // Raw degrees of freedom that we have to set
458 <  ndfRaw_local = 0;
457 >    temp = useSticky;
458 >    MPI_Allreduce(&temp, &useSticky, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
459  
460 <  for(int i = 0; i < integrableObjects.size(); i++){
461 <    ndfRaw_local += 3;
375 <    if (integrableObjects[i]->isDirectional()) {
376 <       if (integrableObjects[i]->isLinear())
377 <        ndfRaw_local += 2;
378 <      else
379 <        ndfRaw_local += 3;
380 <    }
381 <  }
382 <    
383 < #ifdef IS_MPI
384 <  MPI_Allreduce(&ndfRaw_local,&ndfRaw,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
385 < #else
386 <  ndfRaw = ndfRaw_local;
387 < #endif
460 >    temp = useGayBerne;
461 >    MPI_Allreduce(&temp, &useGayBerne, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
462  
463 <  return ndfRaw;
464 < }
463 >    temp = useEAM;
464 >    MPI_Allreduce(&temp, &useEAM, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
465  
466 < int SimInfo::getNDFtranslational() {
467 <  int ndfTrans_local;
466 >    temp = useShape;
467 >    MPI_Allreduce(&temp, &useShape, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);  
468  
469 <  ndfTrans_local = 3 * integrableObjects.size() - n_constraints;
469 >    temp = useFLARB;
470 >    MPI_Allreduce(&temp, &useFLARB, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
471  
472 <
473 < #ifdef IS_MPI
474 <  MPI_Allreduce(&ndfTrans_local,&ndfTrans,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
400 < #else
401 <  ndfTrans = ndfTrans_local;
472 >    temp = useRF;
473 >    MPI_Allreduce(&temp, &useRF, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);    
474 >    
475   #endif
476  
477 <  ndfTrans = ndfTrans - 3 - nZconstraints;
477 >    fInfo_.SIM_uses_PBC = usePBC;    
478 >    fInfo_.SIM_uses_DirectionalAtoms = useDirectionalAtom;
479 >    fInfo_.SIM_uses_LennardJones = useLennardJones;
480 >    fInfo_.SIM_uses_Electrostatics = useElectrostatics;    
481 >    fInfo_.SIM_uses_Charges = useCharge;
482 >    fInfo_.SIM_uses_Dipoles = useDipole;
483 >    fInfo_.SIM_uses_Sticky = useSticky;
484 >    fInfo_.SIM_uses_GayBerne = useGayBerne;
485 >    fInfo_.SIM_uses_EAM = useEAM;
486 >    fInfo_.SIM_uses_Shapes = useShape;
487 >    fInfo_.SIM_uses_FLARB = useFLARB;
488 >    fInfo_.SIM_uses_RF = useRF;
489  
490 <  return ndfTrans;
490 >    if( fInfo_.SIM_uses_Dipoles && fInfo_.SIM_uses_RF) {
491 >        fInfo_.dielect = dielectric;
492 >    } else {
493 >        fInfo_.dielect = 0.0;
494 >    }
495 >
496   }
497  
498 < int SimInfo::getTotIntegrableObjects() {
499 <  int nObjs_local;
500 <  int nObjs;
498 > void SimInfo::setupFortranSim() {
499 >    int isError;
500 >    int nExclude;
501 >    std::vector<int> fortranGlobalGroupMembership;
502 >    
503 >    nExclude = exclude_.getSize();
504 >    isError = 0;
505  
506 <  nObjs_local =  integrableObjects.size();
506 >    //globalGroupMembership_ is filled by SimCreator    
507 >    for (int i = 0; i < nGlobalAtoms_; i++) {
508 >        fortranGlobalGroupMembership.push_back(globalGroupMembership_[i] + 1);
509 >    }
510  
511 +    //calculate mass ratio of cutoff group
512 +    std::vector<double> mfact;
513 +    typename SimInfo::MoleculeIterator mi;
514 +    Molecule* mol;
515 +    typename Molecule::CutoffGroupIterator ci;
516 +    CutoffGroup* cg;
517 +    typename Molecule::AtomIterator ai;
518 +    Atom* atom;
519 +    double totalMass;
520  
521 < #ifdef IS_MPI
522 <  MPI_Allreduce(&nObjs_local,&nObjs,1,MPI_INT,MPI_SUM, MPI_COMM_WORLD);
523 < #else
524 <  nObjs = nObjs_local;
525 < #endif
521 >    //to avoid memory reallocation, reserve enough space for mfact
522 >    mfact.reserve(getNCutoffGroups());
523 >    
524 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {        
525 >        for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
526  
527 +            totalMass = cg->getMass();
528 +            for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
529 +                        mfact.push_back(atom->getMass()/totalMass);
530 +            }
531  
532 <  return nObjs;
533 < }
532 >        }      
533 >    }
534  
535 < void SimInfo::refreshSim(){
535 >    //fill ident array of local atoms (it is actually ident of AtomType, it is so confusing !!!)
536 >    std::vector<int> identArray;
537  
538 <  simtype fInfo;
539 <  int isError;
540 <  int n_global;
541 <  int* excl;
538 >    //to avoid memory reallocation, reserve enough space identArray
539 >    identArray.reserve(getNAtoms());
540 >    
541 >    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {        
542 >        for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
543 >            identArray.push_back(atom->getIdent());
544 >        }
545 >    }    
546  
547 <  fInfo.dielect = 0.0;
547 >    //fill molMembershipArray
548 >    //molMembershipArray is filled by SimCreator    
549 >    std::vector<int> molMembershipArray(nGlobalAtoms_);
550 >    for (int i = 0; i < nGlobalAtoms_; i++) {
551 >        molMembershipArray.push_back(globalMolMembership_[i] + 1);
552 >    }
553 >    
554 >    //setup fortran simulation
555 >    //gloalExcludes and molMembershipArray should go away (They are never used)
556 >    //why the hell fortran need to know molecule?
557 >    //OOPSE = Object-Obfuscated Parallel Simulation Engine
558 >    
559 >    setFortranSim( &fInfo_, &nGlobalAtoms_, &nAtoms_, &identArray[0], &nExclude, exclude_->getExcludeList(),
560 >                  &nGlobalExcludes, globalExcludes, molMembershipArray,
561 >                  &mfact[0], &nCutoffGroups_, &fortranGlobalGroupMembership[0], &isError);
562  
563 <  if( useDipoles ){
436 <    if( useReactionField )fInfo.dielect = dielectric;
437 <  }
563 >    if( isError ){
564  
565 <  fInfo.SIM_uses_PBC = usePBC;
565 >        sprintf( painCave.errMsg,
566 >                 "There was an error setting the simulation information in fortran.\n" );
567 >        painCave.isFatal = 1;
568 >        painCave.severity = OOPSE_ERROR;
569 >        simError();
570 >    }
571  
572 <  if (useSticky || useDipoles || useGayBerne || useShapes) {
573 <    useDirectionalAtoms = 1;
574 <    fInfo.SIM_uses_DirectionalAtoms = useDirectionalAtoms;
575 <  }
572 > #ifdef IS_MPI
573 >    sprintf( checkPointMsg,
574 >       "succesfully sent the simulation information to fortran.\n");
575 >    MPIcheckPoint();
576 > #endif // is_mpi
577 > }
578  
446  fInfo.SIM_uses_LennardJones = useLennardJones;
579  
448  if (useCharges || useDipoles) {
449    useElectrostatics = 1;
450    fInfo.SIM_uses_Electrostatics = useElectrostatics;
451  }
452
453  fInfo.SIM_uses_Charges = useCharges;
454  fInfo.SIM_uses_Dipoles = useDipoles;
455  fInfo.SIM_uses_Sticky = useSticky;
456  fInfo.SIM_uses_GayBerne = useGayBerne;
457  fInfo.SIM_uses_EAM = useEAM;
458  fInfo.SIM_uses_Shapes = useShapes;
459  fInfo.SIM_uses_FLARB = useFLARB;
460  fInfo.SIM_uses_RF = useReactionField;
461
462  n_exclude = excludes->getSize();
463  excl = excludes->getFortranArray();
464  
580   #ifdef IS_MPI
581 <  n_global = mpiSim->getNAtomsGlobal();
582 < #else
583 <  n_global = n_atoms;
584 < #endif
585 <  
586 <  isError = 0;
587 <  
588 <  getFortranGroupArrays(this, FglobalGroupMembership, mfact);
589 <  //it may not be a good idea to pass the address of first element in vector
590 <  //since c++ standard does not require vector to be stored continuously in meomory
591 <  //Most of the compilers will organize the memory of vector continuously
592 <  setFortranSim( &fInfo, &n_global, &n_atoms, identArray, &n_exclude, excl,
593 <                  &nGlobalExcludes, globalExcludes, molMembershipArray,
479 <                  &mfact[0], &ngroup, &FglobalGroupMembership[0], &isError);
581 > void SimInfo::setupFortranParallel() {
582 >    
583 >    //SimInfo is responsible for creating localToGlobalAtomIndex and localToGlobalGroupIndex
584 >    std::vector<int> localToGlobalAtomIndex(getNAtoms(), 0);
585 >    std::vector<int> localToGlobalCutoffGroupIndex;
586 >    typename SimInfo::MoleculeIterator mi;
587 >    typename Molecule::AtomIterator ai;
588 >    typename Molecule::CutoffGroupIterator ci;
589 >    Molecule* mol;
590 >    Atom* atom;
591 >    CutoffGroup* cg;
592 >    mpiSimData parallelData;
593 >    int isError;
594  
595 <  if( isError ){
482 <    
483 <    sprintf( painCave.errMsg,
484 <             "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 < }
595 >    for (mol = beginMolecule(mi); mol != NULL; mol  = nextMolecule(mi)) {
596  
597 < void SimInfo::setDefaultRcut( double theRcut ){
598 <  
599 <  haveRcut = 1;
600 <  rCut = theRcut;
505 <  rList = rCut + 1.0;
506 <  
507 <  notifyFortranCutoffs( &rCut, &rSw, &rList );
508 < }
597 >        //local index(index in DataStorge) of atom is important
598 >        for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
599 >            localToGlobalAtomIndex[atom->getLocalIndex()] = atom->getGlobalIndex() + 1;
600 >        }
601  
602 < void SimInfo::setDefaultRcut( double theRcut, double theRsw ){
602 >        //local index of cutoff group is trivial, it only depends on the order of travesing
603 >        for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
604 >            localToGlobalCutoffGroupIndex.push_back(cg->getGlobalIndex() + 1);
605 >        }        
606 >        
607 >    }
608  
609 <  rSw = theRsw;
610 <  setDefaultRcut( theRcut );
611 < }
609 >    //fill up mpiSimData struct
610 >    parallelData.nMolGlobal = getNGlobalMolecules();
611 >    parallelData.nMolLocal = getNMolecules();
612 >    parallelData.nAtomsGlobal = getNGlobalAtoms();
613 >    parallelData.nAtomsLocal = getNAtoms();
614 >    parallelData.nGroupsGlobal = getNGlobalCutoffGroups();
615 >    parallelData.nGroupsLocal = getNCutoffGroups();
616 >    parallelData.myNode = worldRank;
617 >    MPI_Comm_size(MPI_COMM_WORLD, &(parallelData->nProcessors));
618  
619 +    //pass mpiSimData struct and index arrays to fortran
620 +    setFsimParallel(parallelData, &(parallelData->nAtomsLocal),
621 +                    &localToGlobalAtomIndex[0],  &(parallelData->nGroupsLocal),
622 +                    &localToGlobalCutoffGroupIndex[0], &isError);
623  
624 < void SimInfo::checkCutOffs( void ){
625 <  
626 <  if( boxIsInit ){
627 <    
628 <    //we need to check cutOffs against the box
629 <    
523 <    if( rCut > maxCutoff ){
524 <      sprintf( painCave.errMsg,
525 <               "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;
538 <      painCave.isFatal = 1;
539 <      simError();
540 <    }    
541 <  } else {
542 <    // initialize this stuff before using it, OK?
543 <    sprintf( painCave.errMsg,
544 <             "Trying to check cutoffs without a box.\n"
545 <             "\tOOPSE should have better programmers than that.\n" );
546 <    painCave.severity = OOPSE_ERROR;
547 <    painCave.isFatal = 1;
548 <    simError();      
549 <  }
550 <  
551 < }
624 >    if (isError) {
625 >        sprintf(painCave.errMsg,
626 >                "mpiRefresh errror: fortran didn't like something we gave it.\n");
627 >        painCave.isFatal = 1;
628 >        simError();
629 >    }
630  
631 < void SimInfo::addProperty(GenericData* prop){
631 >    sprintf(checkPointMsg, " mpiRefresh successful.\n");
632 >    MPIcheckPoint();
633  
555  map<string, GenericData*>::iterator result;
556  result = properties.find(prop->getID());
557  
558  //we can't simply use  properties[prop->getID()] = prop,
559  //it will cause memory leak if we already contain a propery which has the same name of prop
560  
561  if(result != properties.end()){
562    
563    delete (*result).second;
564    (*result).second = prop;
565      
566  }
567  else{
634  
569    properties[prop->getID()] = prop;
570
571  }
572    
635   }
636  
637 < GenericData* SimInfo::getPropertyByName(const string& propName){
576 <
577 <  map<string, GenericData*>::iterator result;
578 <  
579 <  //string lowerCaseName = ();
580 <  
581 <  result = properties.find(propName);
582 <  
583 <  if(result != properties.end())
584 <    return (*result).second;  
585 <  else  
586 <    return NULL;  
587 < }
637 > #endif
638  
639 + double SimInfo::calcMaxCutoffRadius() {
640  
590 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  
641  
642 <  // Fix the silly fortran indexing problem
642 >    std::vector<AtomType*> atomTypes;
643 >    std::vector<AtomType*>::iterator i;
644 >    std::vector<double> cutoffRadius;
645 >
646 >    //get the unique atom types
647 >    atomTypes = getUniqueAtomTypes();
648 >
649 >    //query the max cutoff radius among these atom types
650 >    for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
651 >        cutoffRadius.push_back(forceField_->getRcutFromAtomType(*i));
652 >    }
653 >
654 >    double maxCutoffRadius = std::max_element(cutoffRadius.begin(), cutoffRadius.end());
655   #ifdef IS_MPI
656 <  numAtom = mpiSim->getNAtomsGlobal();
614 < #else
615 <  numAtom = n_atoms;
656 >    //pick the max cutoff radius among the processors
657   #endif
617  for (int i = 0; i < numAtom; i++)
618    FglobalGroupMembership.push_back(globalGroupMembership[i] + 1);
619  
658  
659 <  myMols = info->molecules;
660 <  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)){
659 >    return maxCutoffRadius;
660 > }
661  
662 <      totalMass = myCutoffGroup->getMass();
662 > void SimInfo::addProperty(GenericData* genData) {
663 >    properties_.addProperty(genData);  
664 > }
665 >
666 > void SimInfo::removeProperty(const std::string& propName) {
667 >    properties_.removeProperty(propName);  
668 > }
669 >
670 > void SimInfo::clearProperties() {
671 >    properties_.clearProperties();
672 > }
673 >
674 > std::vector<std::string> SimInfo::getPropertyNames() {
675 >    return properties_.getPropertyNames();  
676 > }
677        
678 <      for(cutoffAtom = myCutoffGroup->beginAtom(iterAtom);
679 <          cutoffAtom != NULL;
680 <          cutoffAtom = myCutoffGroup->nextAtom(iterAtom)){
634 <        mfact.push_back(cutoffAtom->getMass()/totalMass);
635 <      }  
636 <    }
637 <  }
678 > std::vector<GenericData*> SimInfo::getProperties() {
679 >    return properties_.getProperties();
680 > }
681  
682 + GenericData* SimInfo::getPropertyByName(const std::string& propName) {
683 +    return properties_.getPropertyByName(propName);
684   }
685 +
686 +
687 + std::ostream& operator <<(ostream& o, SimInfo& info) {
688 +
689 +    return o;
690 + }
691 +
692 + }//end namespace oopse

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines