ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/branches/new_design/OOPSE-2.0/src/brains/SimCreator.cpp
Revision: 1727
Committed: Thu Nov 11 16:41:58 2004 UTC (19 years, 8 months ago) by tim
File size: 16172 byte(s)
Log Message:
add Snapshot.cpp, remove useless mpiSimulation

File Contents

# Content
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 /**
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 namespace oopse {
36
37 void SimSetup::parseFile(char* mdfile, MakeStamps* stamps, Globals* globals){
38 #ifdef IS_MPI
39 if (worldRank == 0){
40 #endif // is_mpi
41
42
43 globals->initalize();
44 set_interface_stamps(stamps, globals);
45
46 #ifdef IS_MPI
47 mpiEventInit();
48 #endif
49
50 yacc_BASS(mdfile);
51
52 #ifdef IS_MPI
53 throwMPIEvent(NULL);
54 }
55 else{
56 set_interface_stamps(stamps, globals);
57 mpiEventInit();
58 MPIcheckPoint();
59 mpiEventLoop();
60 }
61 #endif
62
63 }
64
65
66 SimInfo* SimCreator::createSim(const std::string& mdfile) {
67 MakeStamps* stamps = new MakeStamps();
68
69 Globals* globals = new Globals();
70
71 //parse meta-data file
72 parseFile(mdfile, stamps, globals);
73
74 //create the force field
75 ForceFiled* ff = ForceFieldFactory::getInstance()->createObject(globals->getForceField());
76
77 //create SimInfo
78 SimInfo* info = new SimInfo();
79 info->setGlobals(globals);
80 info->setForceField(ff);
81
82 //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)
87 gatherParameters(info);
88
89 //divide the molecules and determine the global index of molecules
90
91 //create the molecules
92 createMolecules(info);
93
94 //set the global index of atoms, rigidbodies and cutoffgroups (only need to be set once, the
95 //global index will never change again). Local indices of atoms and rigidbodies are already set by
96 //MoleculeCreator class which actually delegates the responsibility to LocalIndexManager.
97 setGlobalIndices(info);
98
99 //allocate memory for DataStorage(circular reference, need to break it)
100 info->setSnapshotManager(new SimSnapshotManager(info);
101
102 //load initial coordinates, some extra information are pushed into SimInfo's property map ( such as
103 //eta, chi for NPT integrator)
104 DumpReader reader(info->getInitFilename());
105 int nframes = reader->getNframes();
106
107 if (nframes > 0) {
108 reader.readFrame(info, nframes - 1);
109 } else {
110 //invalid initial coordinate file
111
112 }
113
114
115 //initialize fortran
116
117 return info;
118 }
119
120 void SimCreator::gatherParameters(SimInfo* info) {
121 //model->addProperty(new StringGenericData("Ensemble", globals->getForceFiled()));
122 //model->addProperty(new DoubleGenericData("dt"), globals->getDt());
123
124 //setup seed for random number generator
125 int seedValue;
126 Globals* globals = info->getGlobals();
127
128 if (globals->haveSeed()){
129 seedValue = globals->getSeed();
130
131 if(seedValue / 1000000000 == 0){
132 sprintf(painCave.errMsg,
133 "Seed for sprng library should contain at least 9 digits\n"
134 "OOPSE will generate a seed for user\n");
135 painCave.isFatal = 0;
136 simError();
137
138 //using seed generated by system instead of invalid seed set by user
139 #ifndef IS_MPI
140 seedValue = make_sprng_seed();
141 #else
142 if (worldRank == 0){
143 seedValue = make_sprng_seed();
144 }
145 MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
146 #endif
147 } //end if (seedValue /1000000000 == 0)
148 } else{
149
150 #ifndef IS_MPI
151 seedValue = make_sprng_seed();
152 #else
153 if (worldRank == 0){
154 seedValue = make_sprng_seed();
155 }
156 MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
157 #endif
158 }//end of globals->haveSeed()
159 info->setSeed(seedValue);
160
161 //
162 std::string prefix;
163 #ifdef IS_MPI
164 if (worldRank == 0){
165 #endif // is_mpi
166
167 if(globals->haveFinalConfig()) {
168 prefix = getPrefix(globals->getFinalConfig());
169 } else {
170 prefix = getPrefix(mdfile_);
171 }
172
173 info->setFinalConfFileName(prefix + ".eor");
174 info->setDumpFileName(prefix + ".dump");
175 info->setStatFileName(prefix + ".stat");
176
177 #ifdef IS_MPI
178 }
179 #endif
180
181
182
183 }
184
185 #ifdef IS_MPI
186 void SimCreator::divideMolecules(SimInfo* info){
187 int nComponents;
188 MoleculeStamp ** compStamps;
189 randomSPRNG * myRandom;
190 int * componentsNmol;
191 int * AtomsPerProc;
192
193 double numerator;
194 double denominator;
195 double precast;
196 double x;
197 double y;
198 double a;
199 int old_atoms;
200 int add_atoms;
201 int new_atoms;
202
203 int nTarget;
204 int molIndex;
205 int atomIndex;
206 int done;
207 int i;
208 int j;
209 int loops;
210 int which_proc;
211 int nmol_global,
212 nmol_local;
213 int natoms_global,
214
215 int baseSeed = info->getSeed();
216 CutoffGroupStamp * cg;
217
218 nComponents = info->nComponents;
219 compStamps = info->compStamps;
220 componentsNmol = info->componentsNmol;
221 AtomsPerProc = new int[parallelData->nProcessors];
222
223 parallelData->nMolGlobal = info->n_mol;
224
225 if (parallelData->nProcessors > parallelData->nMolGlobal) {
226 sprintf(painCave.errMsg,
227 "nProcessors (%d) > nMol (%d)\n"
228 "\tThe number of processors is larger than\n"
229 "\tthe number of molecules. This will not result in a \n"
230 "\tusable division of atoms for force decomposition.\n"
231 "\tEither try a smaller number of processors, or run the\n"
232 "\tsingle-processor version of OOPSE.\n",
233 parallelData->nProcessors,
234 parallelData->nMolGlobal);
235
236 painCave.isFatal = 1;
237 simError();
238 }
239
240 myRandom = new randomSPRNG(baseSeed);
241
242 a = 3.0 * parallelData->nMolGlobal / parallelData->nAtomsGlobal;
243
244 // Initialize things that we'll send out later:
245 for( i = 0; i < parallelData->nProcessors; i++ ) {
246 AtomsPerProc[i] = 0;
247 }
248
249 for( i = 0; i < parallelData->nMolGlobal; i++ ) {
250 // default to an error condition:
251 MolToProcMap[i] = -1;
252 }
253
254 if (parallelData->myNode == 0) {
255 numerator = info->n_atoms;
256 denominator = parallelData->nProcessors;
257 precast = numerator / denominator;
258 nTarget = (int)(precast + 0.5);
259
260 // Build the array of molecule component types first
261 molIndex = 0;
262
263 for( i = 0; i < nComponents; i++ ) {
264 for( j = 0; j < componentsNmol[i]; j++ ) {
265 molIndex++;
266 }
267 }
268
269 for( i = 0; i < molIndex; i++ ) {
270 done = 0;
271 loops = 0;
272
273 while (!done) {
274 loops++;
275
276 // Pick a processor at random
277
278 which_proc
279
280 = (int) (myRandom->getRandom() * parallelData->nProcessors);
281
282 // How many atoms does this processor have?
283
284 old_atoms = AtomsPerProc[which_proc];
285 add_atoms = compStamps[MolComponentType[i]]->getNAtoms();
286 new_atoms = old_atoms + add_atoms;
287
288 // If we've been through this loop too many times, we need
289 // to just give up and assign the molecule to this processor
290 // and be done with it.
291
292 if (loops > 100) {
293 sprintf(
294 painCave.errMsg,
295 "I've tried 100 times to assign molecule %d to a "
296 " processor, but can't find a good spot.\n"
297 "I'm assigning it at random to processor %d.\n",
298 i,
299 which_proc);
300
301 painCave.isFatal = 0;
302 simError();
303
304 MolToProcMap[i] = which_proc;
305 AtomsPerProc[which_proc] += add_atoms;
306
307 done = 1;
308 continue;
309 }
310
311 // If we can add this molecule to this processor without sending
312 // it above nTarget, then go ahead and do it:
313
314 if (new_atoms <= nTarget) {
315 MolToProcMap[i] = which_proc;
316 AtomsPerProc[which_proc] += add_atoms;
317
318 done = 1;
319 continue;
320 }
321
322 // The only situation left is when new_atoms > nTarget. We
323 // want to accept this with some probability that dies off the
324 // farther we are from nTarget
325
326 // roughly: x = new_atoms - nTarget
327 // Pacc(x) = exp(- a * x)
328 // where a = penalty / (average atoms per molecule)
329
330 x = (double)(new_atoms - nTarget);
331 y = myRandom->getRandom();
332
333 if (y < exp(- a * x)) {
334 MolToProcMap[i] = which_proc;
335 AtomsPerProc[which_proc] += add_atoms;
336
337 done = 1;
338 continue;
339 } else { continue; }
340 }
341 }
342
343 // Spray out this nonsense to all other processors:
344
345 MPI_Bcast(MolToProcMap, parallelData->nMolGlobal, MPI_INT, 0,
346 MPI_COMM_WORLD);
347 } else {
348
349 // Listen to your marching orders from processor 0:
350
351 MPI_Bcast(MolToProcMap, parallelData->nMolGlobal, MPI_INT, 0,
352 MPI_COMM_WORLD); }
353
354 // Let's all check for sanity:
355
356 nmol_local = 0;
357
358 for( i = 0; i < parallelData->nMolGlobal; i++ ) {
359 if (MolToProcMap[i] == parallelData->myNode) {
360 nmol_local++;
361 }
362 }
363
364 MPI_Allreduce(&nmol_local, &nmol_global, 1, MPI_INT, MPI_SUM,
365 MPI_COMM_WORLD);
366
367 if (nmol_global != info->n_mol) {
368 sprintf(painCave.errMsg,
369 "The sum of all nmol_local, %d, did not equal the "
370 "total number of molecules, %d.\n",
371 nmol_global,
372 info->n_mol);
373
374 painCave.isFatal = 1;
375 simError();
376 }
377
378 sprintf(checkPointMsg,
379 "Successfully divided the molecules among the processors.\n");
380 MPIcheckPoint();
381
382 }
383 #endif
384
385 Molecule* SimCreator::createMolecules(SimInfo* info) {
386 MoleculeCreator molCreator;
387 int stampId;
388
389
390 for (int i = 0; i < info->getNGlobalMolecules(); i++){
391 if (info->getMolToProc(i) == worldRank){
392
393 stampId = info->getMoleculeStampId(i);
394 Molecule* mol = molCreator.createMolecule(info->getForceField(),
395 info->getMoleculeStamp(stampId), stampId, i);
396
397 info->addMolecule(mol);
398 }
399 }
400
401 }
402
403 void SimSetup::compList(MakeStamps* stamps,SimInfo* info) {
404 int i;
405 char* id;
406 MoleculeStamp* currentStamp;
407 Component* the_components = info->getGlobals()->getComponents();
408 int n_components = info->getGlobals()->getNComponents();
409
410 if (!globals->haveNMol()){
411 // we don't have the total number of molecules, so we assume it is
412 // given in each component
413
414 for (i = 0; i < n_components; i++){
415 if (!the_components[i]->haveNMol()){
416 // we have a problem
417 sprintf(painCave.errMsg,
418 "SimSetup Error. No global NMol or component NMol given.\n"
419 "\tCannot calculate the number of atoms.\n");
420 painCave.isFatal = 1;
421 simError();
422 }
423
424 id = the_components[i]->getType();
425 currentStamp = stamps->extractMolStamp(id);
426 if (currentStamp == NULL){
427 sprintf(painCave.errMsg,
428 "SimSetup error: Component \"%s\" was not found in the "
429 "list of declared molecules\n",
430 id);
431 painCave.isFatal = 1;
432 simError();
433 }
434
435 info->addMoleculeStamp(currentStamp, the_components[i]->getNMol);
436
437 } //end for (i = 0; i < n_components; i++)
438
439 } else{
440 sprintf(painCave.errMsg,
441 "SimSetup error.\n"
442 "\tSorry, the ability to specify total"
443 " nMols and then give molfractions in the components\n"
444 "\tis not currently supported."
445 " Please give nMol in the components.\n");
446 painCave.isFatal = 1;
447 simError();
448 }
449
450 #ifdef IS_MPI
451 strcpy(checkPointMsg, "Component stamps successfully extracted\n");
452 MPIcheckPoint();
453 #endif // is_mpi
454 }
455
456 void SimCreator::setGlobalIndices(SimInfo* info) {
457 typename SimInfo::MoleculeIterator mi;
458 typename Molecule::AtomIterator ai;
459 typename Molecule::RigidBodyIterator ri;
460 typename Molecule::CutoffGroupIterator ci;
461 Molecule* mol;
462 Atom* atom;
463 RigidBody* rb;
464 CutoffGroup* cg;
465 int beginAtomIndex;
466 int beginRigidBodyIndex;
467 int beginCutoffGroupIndex;
468
469 #ifdef IS_MPI
470 beginAtomIndex = 0;
471 beginRigidBodyIndex = 0;
472 beginCutoffGroupIndex = 0;
473 #else
474 int nproc;
475 int myNode;
476
477 myNode = worldRank;
478 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
479
480 std::vector<int> tmpAtomsInProc(nproc, 0);
481 std::vector<int> tmpRigidBodiesInProc(nproc, 0);
482 std::vector<int> tmpCutoffGroupsInProc(nproc, 0);
483 std::vector<int> NumAtomsInProc(nproc, 0);
484 std::vector<int> NumRigidBodiesInProc(nproc, 0);
485 std::vector<int> NumCutoffGroupsInProc(nproc, 0);
486
487 tmpAtomInProc[myNode] = info->getNAtoms();
488 tmpRigidBodiesInProc[myNode] = info->getNRigidBodiess();
489 tmpCutoffGroupsInProc[myNode] = info->getNCutoffGroupss();
490
491 //do MPI_ALLREDUCE to exchange the total number of atoms, rigidbodies and cutoff groups
492 MPI_Allreduce(&tmpAtomsInProc[0], &NumAtomsInProc[0], nproc, MPI_INT,MPI_SUM, MPI_COMM_WORLD);
493 MPI_Allreduce(&tmpRigidBodiesInProc[0], &NumRigidBodiesInProc[0], nproc, MPI_INT,MPI_SUM, MPI_COMM_WORLD);
494 MPI_Allreduce(&tmpCutoffGroupsInProc[0], &NumCutoffGroupsInProc[0], nproc, MPI_INT,MPI_SUM, MPI_COMM_WORLD);
495
496 beginAtomIndex = 0;
497 beginRigidBodyIndex = 0;
498 beginCutoffGroupIndex = 0;
499
500 for (int i = 0; i < nproc; i++) {
501 beginAtomIndex += NumAtomsInProc[i];
502 beginRigidBodyIndex += NumRigidBodiesInProc[i];
503 beginCutoffGroupIndex += NumCutoffGroupsInProc[i];
504 }
505
506 #endif
507
508 for (mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
509
510 //local index(index in DataStorge) of atom is important
511 for (atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
512 atom->setGlobalIndex(beginAtomIndex++);
513 }
514
515 for (rb = mol->beginRigidBody(ri); rb != NULL; rb = mol->nextRigidBody(ri)) {
516 rb->setGlobalIndex(beginRigidBodyIndex++);
517 }
518
519 //local index of cutoff group is trivial, it only depends on the order of travesing
520 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
521 cg->setGlobalIndex(beginCutoffGroupIndex++);
522 }
523
524 }
525 }
526
527 } //end namespace oopse