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

Comparing branches/new_design/OOPSE-3.0/src/brains/SimCreator.cpp (file contents):
Revision 1719 by tim, Fri Nov 5 23:38:27 2004 UTC vs.
Revision 1738 by tim, Sat Nov 13 05:08:12 2004 UTC

# Line 22 | Line 22
22   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23   *
24   */
25
26 /**
27  * @file SimCreator.cpp
28  * @author tlin
29  * @date 11/03/2004
30  * @time 13:51am
31  * @version 1.0
32  */
25  
26 < #include "brains/SimCreator.hpp"  
26 > /**
27 > * @file SimCreator.cpp
28 > * @author tlin
29 > * @date 11/03/2004
30 > * @time 13:51am
31 > * @version 1.0
32 > */
33 >
34 > #include "brains/SimCreator.hpp"
35 >
36   namespace oopse {
37  
38 < void SimSetup::parseFile(char* mdfile,  MakeStamps* stamps, Globals* globals){
38 > void SimSetup::parseFile(const std::string& mdFileName, MakeStamps *stamps, Globals *globals) {
39 >
40   #ifdef IS_MPI
41 <  if (worldRank == 0){
41 >
42 >    if (worldRank == 0) {
43   #endif // is_mpi
44  
45 +        globals->initalize();
46 +        set_interface_stamps(stamps, globals);
47  
43    globals->initalize();
44    set_interface_stamps(stamps, globals);
45
48   #ifdef IS_MPI
49 <    mpiEventInit();
49 >
50 >        mpiEventInit();
51 >
52   #endif
53  
54 <    yacc_BASS(mdfile);
54 >        yacc_BASS(mdFileName.c_str());
55  
56   #ifdef IS_MPI
57 <    throwMPIEvent(NULL);
58 <  }
59 <  else{
60 <  set_interface_stamps(stamps, globals);
61 <  mpiEventInit();
62 <  MPIcheckPoint();
63 <  mpiEventLoop();
64 <  }
57 >
58 >        throwMPIEvent(NULL);
59 >    } else {
60 >        set_interface_stamps(stamps, globals);
61 >        mpiEventInit();
62 >        MPIcheckPoint();
63 >        mpiEventLoop();
64 >    }
65 >
66   #endif
67  
68   }
69  
70 + SimInfo*  SimCreator::createSim(const std::string & mdFileName) {
71  
72 < SimInfo* SimCreator::createSim(const std::string& mdfile) {
67 <    MakeStamps* stamps = new MakeStamps();
72 >    mdFileName_ = mdFileName;
73      
74 <    Globals* globals = new Globals();
74 >    MakeStamps * stamps = new MakeStamps();
75  
76 +    Globals * globals = new Globals();
77 +
78      //parse meta-data file
79 <    parseFile(mdfile, stamps, globals);
79 >    parseFile(mdFileName_, stamps, globals);
80  
81      //create the force field
82 <    ForceFiled* ff = ForceFieldFactory::getInstance()->createForceField(globals->getForceField());
83 <    
82 >    ForceFiled * ff = ForceFieldFactory::getInstance()->createObject(
83 >                          globals->getForceField());
84 >
85 >    if (ff == NULL) {
86 >        sprintf(painCave.errMsg, "ForceFiled Factory can not create %s force field\n",
87 >                globals->getForceField());
88 >        painCave.isFatal = 1;
89 >        simError();
90 >    }
91 >
92 >    //extract the molecule stamps
93 >    std::vector < std::pair<MoleculeStamp *, int> > moleculeStampPairs;
94 >    compList(stamps, globals, moleculeStampPairs);
95 >
96      //create SimInfo
97 <    SimInfo* info = new SimInfo();
79 <    info->setGlobals(globals);
80 <    info->setForceField(ff);
97 >    SimInfo * info = new SimInfo(moleculeStampPairs, ff, globals);
98  
99 <    //extract the molecule stamps and add them into SimInfo
83 <    compList(stamps, info);
84 <    
85 <    //gather parameters (SimCreator only retrieves the parameters which will be used to create
86 <    // the simulation)
99 >    //gather parameters (SimCreator only retrieves part of the parameters)
100      gatherParameters(info);
101 <    
101 >
102      //divide the molecules and determine the global index of molecules
103 <    
103 >    divideMolecules(info);
104 >
105      //create the molecules
106      createMolecules(info);
107  
108 +    //set the global index of atoms, rigidbodies and cutoffgroups (only need to be set once, the
109 +    //global index will never change again). Local indices of atoms and rigidbodies are already set by
110 +    //MoleculeCreator class which actually delegates the responsibility to LocalIndexManager.
111 +    setGlobalIndices(info);
112 +
113      //allocate memory for DataStorage(circular reference, need to break it)
114 <    info->setSnapshotManager(new SimSnapshotManager(info);
96 <    
97 <    //load initial coordinates
98 <    DumpReader reader(info->getInitFilename());
99 <    int nframes = reader->getNframes();
114 >    info->setSnapshotManager(new SimSnapshotManager(info));
115  
116 <    if (nframes > 0) {
117 <        reader.readFrame(info, nframes - 1);
116 >    //initialize fortran -- setup the cutoff
117 >    initFortran(info);
118 >
119 >    //load initial coordinates, some extra information are pushed into SimInfo's property map ( such as
120 >    //eta, chi for NPT integrator)
121 >    loadCoordinates(info);    
122 >    return info;
123 > }
124 >
125 > void SimCreator::gatherParameters(SimInfo *info) {
126 >
127 >    //setup seed for random number generator
128 >    int seedValue;
129 >    Globals * globals = info->getGlobals();
130 >
131 >    if (globals->haveSeed()) {
132 >        seedValue = globals->getSeed();
133 >
134 >        if (seedValue / 1000000000 == 0) {
135 >            sprintf(painCave.errMsg,
136 >                    "Seed for sprng library should contain at least 9 digits\n"
137 >                        "OOPSE will generate a seed for user\n");
138 >
139 >            painCave.isFatal = 0;
140 >            simError();
141 >
142 >            //using seed generated by system instead of invalid seed set by user
143 >
144 > #ifndef IS_MPI
145 >
146 >            seedValue = make_sprng_seed();
147 >
148 > #else
149 >
150 >            if (worldRank == 0) {
151 >                seedValue = make_sprng_seed();
152 >            }
153 >
154 >            MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
155 >
156 > #endif
157 >
158 >        } //end if (seedValue /1000000000 == 0)
159      } else {
160 <        //invalid initial coordinate file
161 <        
160 >
161 > #ifndef IS_MPI
162 >
163 >        seedValue = make_sprng_seed();
164 >
165 > #else
166 >
167 >        if (worldRank == 0) {
168 >            seedValue = make_sprng_seed();
169 >        }
170 >
171 >        MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
172 >
173 > #endif
174 >
175 >    } //end of globals->haveSeed()
176 >
177 >    info->setSeed(seedValue);
178 >
179 >
180 >    //figure out the ouput file names
181 >    std::string prefix;
182 >
183 > #ifdef IS_MPI
184 >
185 >    if (worldRank == 0) {
186 > #endif // is_mpi
187 >
188 >        if (globals->haveFinalConfig()) {
189 >            prefix = StringUtils::getPrefix(globals->getFinalConfig());
190 >        } else {
191 >            prefix = StringUtils::getPrefix(mdfile_);
192 >        }
193 >
194 >        info->setFinalConfigFileName(prefix + ".eor");
195 >        info->setDumpFileName(prefix + ".dump");
196 >        info->setStatFileName(prefix + ".stat");
197 >
198 > #ifdef IS_MPI
199 >
200      }
201  
202 <    
109 <    //initialize fortran    
110 <    
111 <    return info;
112 < }    
202 > #endif
203  
114 void SimCreator::gatherParameters(SimModel* model) {
115    model->addProperty(new StringGenericData("Ensemble", globals->getForceFiled()));
116    model->addProperty(new DoubleGenericData("dt"), globals->getDt());
204   }
205  
206   #ifdef IS_MPI
120 void SimCreator::mpiMolDivide(){
121
122    mpiSim = new mpiSimulation(info);
207  
208 <    mpiSim->divideLabor();
208 > void SimCreator::divideMolecules(SimInfo *info) {
209 >    double numerator;
210 >    double denominator;
211 >    double precast;
212 >    double x;
213 >    double y;
214 >    double a;
215 >    int old_atoms;
216 >    int add_atoms;
217 >    int new_atoms;
218 >    int nTarget;
219 >    int done;
220 >    int i;
221 >    int j;
222 >    int loops;
223 >    int which_proc;
224 >    int nProcessors;
225 >    int nGlobalMols;
226 >    std::vector < int > atomsPerProc;
227 >    randomSPRNG myRandom(info->getSeed());
228 >    int * molToProcMap = info->getMolToProcMapPointer();
229  
230 <    strcpy(checkPointMsg, "Passed nlocal consistency check.");
231 <    MPIcheckPoint();
128 < }
129 < #endif
230 >    MPI_Comm_size(MPI_COMM_WORLD, &nProcessors);
231 >    nGlobalMols = info->getNGlobalMolecules();
232  
233 < Molecule* SimCreator::createMolecules(SimInfo* info) {
233 >    if (nProcessors > nGlobalMols) {
234 >        sprintf(painCave.errMsg,
235 >                "nProcessors (%d) > nMol (%d)\n"
236 >                    "\tThe number of processors is larger than\n"
237 >                    "\tthe number of molecules.  This will not result in a \n"
238 >                    "\tusable division of atoms for force decomposition.\n"
239 >                    "\tEither try a smaller number of processors, or run the\n"
240 >                    "\tsingle-processor version of OOPSE.\n", nProcessors, nGlobalMols);
241  
242 +        painCave.isFatal = 1;
243 +        simError();
244 +    }
245  
246 <    
135 <    for (i = 0; i < mpiSim->getNMolGlobal(); i++){
136 <        if (mol2proc[i] == worldRank){
246 >    a = 3.0 * nGlobalMols / info->getNGlobalAtoms();
247  
248 <            Molecule* mol = MoleculeCreator.createMolecule(molStamp, stampID, globalIndex);
249 <                        
250 <            info->addMolecule(mol);
248 >    //initialize atomsPerProc
249 >    atomsPerProc.insert(atomsPerProc.end(), nProcessors, 0);
250 >
251 >    for(i = 0; i < nGlobalMols; i++) {
252 >        // default to an error condition:
253 >        molToProcMap[i] = -1;
254 >    }
255 >
256 >    if (worldRank == 0) {
257 >        numerator = info->getNGlobalAtoms();
258 >        denominator = nProcessors;
259 >        precast = numerator / denominator;
260 >        nTarget = (int)(precast + 0.5);
261 >
262 >        for(i = 0; i < nGlobalMols; i++) {
263 >            done = 0;
264 >            loops = 0;
265 >
266 >            while (!done) {
267 >                loops++;
268 >
269 >                // Pick a processor at random
270 >
271 >                which_proc = (int) (myRandom.getRandom() * nProcessors);
272 >
273 >                //get the molecule stamp first
274 >                int stampId = info->getMoleculeStampId(i);
275 >                MoleculeStamp * moleculeStamp = info->getMoleculeStamp(stampId);
276 >
277 >                // How many atoms does this processor have so far?
278 >                old_atoms = atomsPerProc[which_proc];
279 >                add_atoms = moleculeStamp->getNAtoms();
280 >                new_atoms = old_atoms + add_atoms;
281 >
282 >                // If we've been through this loop too many times, we need
283 >                // to just give up and assign the molecule to this processor
284 >                // and be done with it.
285 >
286 >                if (loops > 100) {
287 >                    sprintf(painCave.errMsg,
288 >                            "I've tried 100 times to assign molecule %d to a "
289 >                                " processor, but can't find a good spot.\n"
290 >                                "I'm assigning it at random to processor %d.\n",
291 >                            i, which_proc);
292 >
293 >                    painCave.isFatal = 0;
294 >                    simError();
295 >
296 >                    molToProcMap[i] = which_proc;
297 >                    atomsPerProc[which_proc] += add_atoms;
298 >
299 >                    done = 1;
300 >                    continue;
301 >                }
302 >
303 >                // If we can add this molecule to this processor without sending
304 >                // it above nTarget, then go ahead and do it:
305 >
306 >                if (new_atoms <= nTarget) {
307 >                    molToProcMap[i] = which_proc;
308 >                    atomsPerProc[which_proc] += add_atoms;
309 >
310 >                    done = 1;
311 >                    continue;
312 >                }
313 >
314 >                // The only situation left is when new_atoms > nTarget.  We
315 >                // want to accept this with some probability that dies off the
316 >                // farther we are from nTarget
317 >
318 >                // roughly:  x = new_atoms - nTarget
319 >                //           Pacc(x) = exp(- a * x)
320 >                // where a = penalty / (average atoms per molecule)
321 >
322 >                x = (double)(new_atoms - nTarget);
323 >                y = myRandom.getRandom();
324 >
325 >                if (y < exp(- a * x)) {
326 >                    molToProcMap[i] = which_proc;
327 >                    atomsPerProc[which_proc] += add_atoms;
328 >
329 >                    done = 1;
330 >                    continue;
331 >                } else {
332 >                    continue;
333 >                }
334 >            }
335          }
336 <    }        
337 <      
336 >
337 >        // Spray out this nonsense to all other processors:
338 >
339 >        MPI_Bcast(molToProcMap, nGlobalMols, MPI_INT, 0, MPI_COMM_WORLD);
340 >    } else {
341 >
342 >        // Listen to your marching orders from processor 0:
343 >
344 >        MPI_Bcast(molToProcMap, nGlobalMols, MPI_INT, 0, MPI_COMM_WORLD);
345 >    }
346 >
347 >    sprintf(checkPointMsg,
348 >            "Successfully divided the molecules among the processors.\n");
349 >    MPIcheckPoint();
350   }
351  
352 + #endif
353  
354 < void SimSetup::compList(MakeStamps* stamps,SimInfo* info) {
354 > void SimCreator::createMolecules(SimInfo *info) {
355 >    MoleculeCreator molCreator;
356 >    int stampId;
357 >
358 >    for(int i = 0; i < info->getNGlobalMolecules(); i++) {
359 >
360 > #ifdef IS_MPI
361 >
362 >        if (info->getMolToProc(i) == worldRank) {
363 > #endif
364 >
365 >            stampId = info->getMoleculeStampId(i);
366 >            Molecule * mol = molCreator.createMolecule(info->getForceField(),
367 >                                                info->getMoleculeStamp(stampId), stampId, i);
368 >
369 >            info->addMolecule(mol);
370 >
371 > #ifdef IS_MPI
372 >
373 >        }
374 >
375 > #endif
376 >
377 >    } //end for(int i=0)  
378 > }
379 >
380 > void SimSetup::compList(MakeStamps *stamps, Globals* globals,
381 >                        std::vector < std::pair<MoleculeStamp *, int> > &moleculeStampPairs) {
382      int i;
383 <    char* id;
384 <    MoleculeStamp* currentStamp;
385 <    Component* the_components = info->getGlobals()->getComponents();
386 <    int n_components = info->getGlobals()->getNComponents();
383 >    char * id;
384 >    MoleculeStamp * currentStamp;
385 >    Component * the_components = globals->getComponents();
386 >    int n_components = globals->getNComponents();
387  
388 <    if (!globals->haveNMol()){
388 >    if (!globals->haveNMol()) {
389          // we don't have the total number of molecules, so we assume it is
390          // given in each component
391  
392 <        for (i = 0; i < n_components; i++){
393 <            if (!the_components[i]->haveNMol()){
392 >        for(i = 0; i < n_components; i++) {
393 >            if (!the_components[i]->haveNMol()) {
394                  // we have a problem
395                  sprintf(painCave.errMsg,
396 <                    "SimSetup Error. No global NMol or component NMol given.\n"
397 <                    "\tCannot calculate the number of atoms.\n");
396 >                        "SimSetup Error. No global NMol or component NMol given.\n"
397 >                            "\tCannot calculate the number of atoms.\n");
398 >
399                  painCave.isFatal = 1;
400                  simError();
401              }
402  
403              id = the_components[i]->getType();
404              currentStamp = stamps->extractMolStamp(id);
405 <            if (currentStamp == NULL){
405 >
406 >            if (currentStamp == NULL) {
407                  sprintf(painCave.errMsg,
408 <                    "SimSetup error: Component \"%s\" was not found in the "
409 <                    "list of declared molecules\n",
410 <                    id);
408 >                        "SimSetup error: Component \"%s\" was not found in the "
409 >                            "list of declared molecules\n", id);
410 >
411                  painCave.isFatal = 1;
412                  simError();
413 <            }      
413 >            }
414  
415 <            info.moleculeStamps.push_back(make_pair(currentStamp, the_components[i]->getNMol()));
416 <          
415 >            moleculeStampPairs.push_back(
416 >                make_pair(currentStamp, the_components[i]->getNMol));
417          } //end for (i = 0; i < n_components; i++)
418 <        
419 <    } else{
420 <        sprintf(painCave.errMsg,
421 <                "SimSetup error.\n"
422 <                "\tSorry, the ability to specify total"
423 <                " nMols and then give molfractions in the components\n"
424 <                "\tis not currently supported."
189 <                " Please give nMol in the components.\n");
418 >    } else {
419 >        sprintf(painCave.errMsg, "SimSetup error.\n"
420 >                                     "\tSorry, the ability to specify total"
421 >                                     " nMols and then give molfractions in the components\n"
422 >                                     "\tis not currently supported."
423 >                                     " Please give nMol in the components.\n");
424 >
425          painCave.isFatal = 1;
426          simError();
427      }
428 <  
428 >
429   #ifdef IS_MPI
430 <  strcpy(checkPointMsg, "Component stamps successfully extracted\n");
431 <  MPIcheckPoint();
430 >
431 >    strcpy(checkPointMsg, "Component stamps successfully extracted\n");
432 >    MPIcheckPoint();
433 >
434   #endif // is_mpi
435 +
436   }
437  
438 + void SimCreator::setGlobalIndex(SimInfo *info) {
439 +    typename SimInfo::MoleculeIterator mi;
440 +    typename Molecule::AtomIterator ai;
441 +    typename Molecule::RigidBodyIterator ri;
442 +    typename Molecule::CutoffGroupIterator ci;
443 +    Molecule * mol;
444 +    Atom * atom;
445 +    RigidBody * rb;
446 +    CutoffGroup * cg;
447 +    int beginAtomIndex;
448 +    int beginRigidBodyIndex;
449 +    int beginCutoffGroupIndex;
450  
451 + #ifndef IS_MPI
452 +
453 +    beginAtomIndex = 0;
454 +    beginRigidBodyIndex = 0;
455 +    beginCutoffGroupIndex = 0;
456 +
457 + #else
458 +
459 +    int nproc;
460 +    int myNode;
461 +
462 +    myNode = worldRank;
463 +    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
464 +
465 +    std::vector < int > tmpAtomsInProc(nproc, 0);
466 +    std::vector < int > tmpRigidBodiesInProc(nproc, 0);
467 +    std::vector < int > tmpCutoffGroupsInProc(nproc, 0);
468 +    std::vector < int > NumAtomsInProc(nproc, 0);
469 +    std::vector < int > NumRigidBodiesInProc(nproc, 0);
470 +    std::vector < int > NumCutoffGroupsInProc(nproc, 0);
471 +
472 +    tmpAtomsInProc[myNode] = info->getNAtoms();
473 +    tmpRigidBodiesInProc[myNode] = info->getNRigidBodies();
474 +    tmpCutoffGroupsInProc[myNode] = info->getNCutoffGroups();
475 +
476 +    //do MPI_ALLREDUCE to exchange the total number of atoms, rigidbodies and cutoff groups
477 +    MPI_Allreduce(&tmpAtomsInProc[0], &NumAtomsInProc[0], nproc, MPI_INT,
478 +                  MPI_SUM, MPI_COMM_WORLD);
479 +    MPI_Allreduce(&tmpRigidBodiesInProc[0], &NumRigidBodiesInProc[0], nproc,
480 +                  MPI_INT, MPI_SUM, MPI_COMM_WORLD);
481 +    MPI_Allreduce(&tmpCutoffGroupsInProc[0], &NumCutoffGroupsInProc[0], nproc,
482 +                  MPI_INT, MPI_SUM, MPI_COMM_WORLD);
483 +
484 +    beginAtomIndex = 0;
485 +    beginRigidBodyIndex = 0;
486 +    beginCutoffGroupIndex = 0;
487 +
488 +    for(int i = 0; i < nproc; i++) {
489 +        beginAtomIndex += NumAtomsInProc[i];
490 +        beginRigidBodyIndex += NumRigidBodiesInProc[i];
491 +        beginCutoffGroupIndex += NumCutoffGroupsInProc[i];
492 +    }
493 +
494 + #endif
495 +
496 +    for(mol = info->beginMolecule(mi); mol != NULL;
497 +        mol = info->nextMolecule(mi)) {
498 +
499 +        //local index(index in DataStorge) of atom is important
500 +        for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
501 +            atom->setGlobalIndex(beginAtomIndex++);
502 +        }
503 +
504 +        for(rb = mol->beginRigidBody(ri); rb != NULL;
505 +            rb = mol->nextRigidBody(ri)) {
506 +            rb->setGlobalIndex(beginRigidBodyIndex++);
507 +        }
508 +
509 +        //local index of cutoff group is trivial, it only depends on the order of travesing
510 +        for(cg = mol->beginCutoffGroup(ci); cg != NULL;
511 +            cg = mol->nextCutoffGroup(ci)) {
512 +            cg->setGlobalIndex(beginCutoffGroupIndex++);
513 +        }
514 +    }
515 +
516 +    //fill globalGroupMembership
517 +    std::vector<int> globalGroupMembership(info->getNGlobalAtoms(), 0);
518 +    for(mol = beginMolecule(mi); mol != NULL; mol = nextMolecule(mi)) {        
519 +        for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
520 +
521 +            for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
522 +                globalGroupMembership[atom->getGlobalIndex()] = cg->getGlobalIndex();
523 +            }
524 +
525 +        }      
526 +    }
527 +
528 + #ifdef IS_MPI    
529 +    // Since the globalGroupMembership has been zero filled and we've only
530 +    // poked values into the atoms we know, we can do an Allreduce
531 +    // to get the full globalGroupMembership array (We think).
532 +    // This would be prettier if we could use MPI_IN_PLACE like the MPI-2
533 +    // docs said we could.
534 +
535 +    MPI_Allreduce(&globalGroupMembership[0],
536 +                  info->getGlobalGroupMembershipPointer(),
537 +                  info->getNGlobalAtoms(),
538 +                  MPI_INT, MPI_SUM, MPI_COMM_WORLD);
539 + #else
540 +    std::copy(globalGroupMembership.begin(), globalGroupMembership.end(),
541 +        info->getGlobalGroupMembershipPointer());
542 + #endif
543 +
544 +    //fill molMembership
545 +    std::vector<int> globalMolMembership(info->getNGlobalAtoms(), 0);
546 +    
547 +    for(mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
548 +
549 +        for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
550 +            globalMolMembership[atom->getGlobalIndex()] = mol->getGlobalIndex();
551 +        }
552 +
553 + #ifdef IS_MPI
554 +    MPI_Allreduce(&globalMolMembership[0],
555 +                  info->getGlobalMolMembershipPointer(),
556 +                  info->getNGlobalAtoms(),
557 +                  MPI_INT, MPI_SUM, MPI_COMM_WORLD);
558 + #else
559 +    std::copy(globalMolMembership.begin(), globalMolMembership.end(),
560 +        info->getGlobalMolMembershipPointer());
561 + #endif
562 +
563 + }
564 +
565 + void SimCreator::loadCoordinates(SimInfo* info) {
566 +    Globals* globals;
567 +    globals = info->getGlobals();
568 +    
569 +    if (!globals->haveInitialConfig()) {
570 +        sprintf(painCave.errMsg,
571 +                "Cannot intialize a simulation without an initial configuration file.\n");
572 +        painCave.isFatal = 1;;
573 +        simError();
574 +    }
575 +        
576 +    DumpReader reader(globals->getInitialConfig());
577 +    int nframes = reader->getNframes();
578 +
579 +    if (nframes > 0) {
580 +        reader.readFrame(info, nframes - 1);
581 +    } else {
582 +        //invalid initial coordinate file
583 +        sprintf(painCave.errMsg, "Initial configuration file %s should at least contain one frame\n",
584 +                globals->getInitialConfig());
585 +        painCave.isFatal = 1;
586 +        simError();
587 +    }
588 +
589 + }
590 +
591   } //end namespace oopse

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines