ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/brains/SimCreator.cpp
Revision: 1725
Committed: Sat May 26 18:13:43 2012 UTC (12 years, 11 months ago) by gezelter
File size: 31096 byte(s)
Log Message:
Individual ForceField classes have been removed (they were essentially
all duplicates anyway).  

ForceField has moved to brains, and since only one force field is in
play at any time, the ForceFieldFactory and Register methods have been
removed.  


File Contents

# Content
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] Kuang & Gezelter, J. Chem. Phys. 133, 164101 (2010).
40 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
41 */
42
43 /**
44 * @file SimCreator.cpp
45 * @author tlin
46 * @date 11/03/2004
47 * @time 13:51am
48 * @version 1.0
49 */
50 #include <exception>
51 #include <iostream>
52 #include <sstream>
53 #include <string>
54
55 #include "brains/MoleculeCreator.hpp"
56 #include "brains/SimCreator.hpp"
57 #include "brains/SimSnapshotManager.hpp"
58 #include "io/DumpReader.hpp"
59 #include "brains/ForceField.hpp"
60 #include "utils/simError.h"
61 #include "utils/StringUtils.hpp"
62 #include "math/SeqRandNumGen.hpp"
63 #include "mdParser/MDLexer.hpp"
64 #include "mdParser/MDParser.hpp"
65 #include "mdParser/MDTreeParser.hpp"
66 #include "mdParser/SimplePreprocessor.hpp"
67 #include "antlr/ANTLRException.hpp"
68 #include "antlr/TokenStreamRecognitionException.hpp"
69 #include "antlr/TokenStreamIOException.hpp"
70 #include "antlr/TokenStreamException.hpp"
71 #include "antlr/RecognitionException.hpp"
72 #include "antlr/CharStreamException.hpp"
73
74 #include "antlr/MismatchedCharException.hpp"
75 #include "antlr/MismatchedTokenException.hpp"
76 #include "antlr/NoViableAltForCharException.hpp"
77 #include "antlr/NoViableAltException.hpp"
78
79 #include "types/DirectionalAdapter.hpp"
80 #include "types/MultipoleAdapter.hpp"
81 #include "types/EAMAdapter.hpp"
82 #include "types/SuttonChenAdapter.hpp"
83 #include "types/PolarizableAdapter.hpp"
84 #include "types/FixedChargeAdapter.hpp"
85 #include "types/FluctuatingChargeAdapter.hpp"
86
87 #ifdef IS_MPI
88 #include "mpi.h"
89 #include "math/ParallelRandNumGen.hpp"
90 #endif
91
92 namespace OpenMD {
93
94 Globals* SimCreator::parseFile(std::istream& rawMetaDataStream, const std::string& filename, int mdFileVersion, int startOfMetaDataBlock ){
95 Globals* simParams = NULL;
96 try {
97
98 // Create a preprocessor that preprocesses md file into an ostringstream
99 std::stringstream ppStream;
100 #ifdef IS_MPI
101 int streamSize;
102 const int masterNode = 0;
103 int commStatus;
104 if (worldRank == masterNode) {
105 commStatus = MPI_Bcast(&mdFileVersion, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
106 #endif
107 SimplePreprocessor preprocessor;
108 preprocessor.preprocess(rawMetaDataStream, filename, startOfMetaDataBlock, ppStream);
109
110 #ifdef IS_MPI
111 //brocasting the stream size
112 streamSize = ppStream.str().size() +1;
113 commStatus = MPI_Bcast(&streamSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
114
115 commStatus = MPI_Bcast(static_cast<void*>(const_cast<char*>(ppStream.str().c_str())), streamSize, MPI_CHAR, masterNode, MPI_COMM_WORLD);
116
117
118 } else {
119
120 commStatus = MPI_Bcast(&mdFileVersion, 1, MPI_INT, masterNode, MPI_COMM_WORLD);
121
122 //get stream size
123 commStatus = MPI_Bcast(&streamSize, 1, MPI_LONG, masterNode, MPI_COMM_WORLD);
124
125 char* buf = new char[streamSize];
126 assert(buf);
127
128 //receive file content
129 commStatus = MPI_Bcast(buf, streamSize, MPI_CHAR, masterNode, MPI_COMM_WORLD);
130
131 ppStream.str(buf);
132 delete [] buf;
133
134 }
135 #endif
136 // Create a scanner that reads from the input stream
137 MDLexer lexer(ppStream);
138 lexer.setFilename(filename);
139 lexer.initDeferredLineCount();
140
141 // Create a parser that reads from the scanner
142 MDParser parser(lexer);
143 parser.setFilename(filename);
144
145 // Create an observer that synchorizes file name change
146 FilenameObserver observer;
147 observer.setLexer(&lexer);
148 observer.setParser(&parser);
149 lexer.setObserver(&observer);
150
151 antlr::ASTFactory factory;
152 parser.initializeASTFactory(factory);
153 parser.setASTFactory(&factory);
154 parser.mdfile();
155
156 // Create a tree parser that reads information into Globals
157 MDTreeParser treeParser;
158 treeParser.initializeASTFactory(factory);
159 treeParser.setASTFactory(&factory);
160 simParams = treeParser.walkTree(parser.getAST());
161 }
162
163
164 catch(antlr::MismatchedCharException& e) {
165 sprintf(painCave.errMsg,
166 "parser exception: %s %s:%d:%d\n",
167 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
168 painCave.isFatal = 1;
169 simError();
170 }
171 catch(antlr::MismatchedTokenException &e) {
172 sprintf(painCave.errMsg,
173 "parser exception: %s %s:%d:%d\n",
174 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
175 painCave.isFatal = 1;
176 simError();
177 }
178 catch(antlr::NoViableAltForCharException &e) {
179 sprintf(painCave.errMsg,
180 "parser exception: %s %s:%d:%d\n",
181 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
182 painCave.isFatal = 1;
183 simError();
184 }
185 catch(antlr::NoViableAltException &e) {
186 sprintf(painCave.errMsg,
187 "parser exception: %s %s:%d:%d\n",
188 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
189 painCave.isFatal = 1;
190 simError();
191 }
192
193 catch(antlr::TokenStreamRecognitionException& e) {
194 sprintf(painCave.errMsg,
195 "parser exception: %s %s:%d:%d\n",
196 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
197 painCave.isFatal = 1;
198 simError();
199 }
200
201 catch(antlr::TokenStreamIOException& e) {
202 sprintf(painCave.errMsg,
203 "parser exception: %s\n",
204 e.getMessage().c_str());
205 painCave.isFatal = 1;
206 simError();
207 }
208
209 catch(antlr::TokenStreamException& e) {
210 sprintf(painCave.errMsg,
211 "parser exception: %s\n",
212 e.getMessage().c_str());
213 painCave.isFatal = 1;
214 simError();
215 }
216 catch (antlr::RecognitionException& e) {
217 sprintf(painCave.errMsg,
218 "parser exception: %s %s:%d:%d\n",
219 e.getMessage().c_str(),e.getFilename().c_str(), e.getLine(), e.getColumn());
220 painCave.isFatal = 1;
221 simError();
222 }
223 catch (antlr::CharStreamException& e) {
224 sprintf(painCave.errMsg,
225 "parser exception: %s\n",
226 e.getMessage().c_str());
227 painCave.isFatal = 1;
228 simError();
229 }
230 catch (OpenMDException& e) {
231 sprintf(painCave.errMsg,
232 "%s\n",
233 e.getMessage().c_str());
234 painCave.isFatal = 1;
235 simError();
236 }
237 catch (std::exception& e) {
238 sprintf(painCave.errMsg,
239 "parser exception: %s\n",
240 e.what());
241 painCave.isFatal = 1;
242 simError();
243 }
244
245 simParams->setMDfileVersion(mdFileVersion);
246 return simParams;
247 }
248
249 SimInfo* SimCreator::createSim(const std::string & mdFileName,
250 bool loadInitCoords) {
251
252 const int bufferSize = 65535;
253 char buffer[bufferSize];
254 int lineNo = 0;
255 std::string mdRawData;
256 int metaDataBlockStart = -1;
257 int metaDataBlockEnd = -1;
258 int i;
259 int mdOffset;
260 int mdFileVersion;
261
262 #ifdef IS_MPI
263 const int masterNode = 0;
264 if (worldRank == masterNode) {
265 #endif
266
267 std::ifstream mdFile_(mdFileName.c_str());
268
269 if (mdFile_.fail()) {
270 sprintf(painCave.errMsg,
271 "SimCreator: Cannot open file: %s\n",
272 mdFileName.c_str());
273 painCave.isFatal = 1;
274 simError();
275 }
276
277 mdFile_.getline(buffer, bufferSize);
278 ++lineNo;
279 std::string line = trimLeftCopy(buffer);
280 i = CaseInsensitiveFind(line, "<OpenMD");
281 if (static_cast<size_t>(i) == string::npos) {
282 // try the older file strings to see if that works:
283 i = CaseInsensitiveFind(line, "<OOPSE");
284 }
285
286 if (static_cast<size_t>(i) == string::npos) {
287 // still no luck!
288 sprintf(painCave.errMsg,
289 "SimCreator: File: %s is not a valid OpenMD file!\n",
290 mdFileName.c_str());
291 painCave.isFatal = 1;
292 simError();
293 }
294
295 // found the correct opening string, now try to get the file
296 // format version number.
297
298 StringTokenizer tokenizer(line, "=<> \t\n\r");
299 std::string fileType = tokenizer.nextToken();
300 toUpper(fileType);
301
302 mdFileVersion = 0;
303
304 if (fileType == "OPENMD") {
305 while (tokenizer.hasMoreTokens()) {
306 std::string token(tokenizer.nextToken());
307 toUpper(token);
308 if (token == "VERSION") {
309 mdFileVersion = tokenizer.nextTokenAsInt();
310 break;
311 }
312 }
313 }
314
315 //scan through the input stream and find MetaData tag
316 while(mdFile_.getline(buffer, bufferSize)) {
317 ++lineNo;
318
319 std::string line = trimLeftCopy(buffer);
320 if (metaDataBlockStart == -1) {
321 i = CaseInsensitiveFind(line, "<MetaData>");
322 if (i != string::npos) {
323 metaDataBlockStart = lineNo;
324 mdOffset = mdFile_.tellg();
325 }
326 } else {
327 i = CaseInsensitiveFind(line, "</MetaData>");
328 if (i != string::npos) {
329 metaDataBlockEnd = lineNo;
330 }
331 }
332 }
333
334 if (metaDataBlockStart == -1) {
335 sprintf(painCave.errMsg,
336 "SimCreator: File: %s did not contain a <MetaData> tag!\n",
337 mdFileName.c_str());
338 painCave.isFatal = 1;
339 simError();
340 }
341 if (metaDataBlockEnd == -1) {
342 sprintf(painCave.errMsg,
343 "SimCreator: File: %s did not contain a closed MetaData block!\n",
344 mdFileName.c_str());
345 painCave.isFatal = 1;
346 simError();
347 }
348
349 mdFile_.clear();
350 mdFile_.seekg(0);
351 mdFile_.seekg(mdOffset);
352
353 mdRawData.clear();
354
355 for (int i = 0; i < metaDataBlockEnd - metaDataBlockStart - 1; ++i) {
356 mdFile_.getline(buffer, bufferSize);
357 mdRawData += buffer;
358 mdRawData += "\n";
359 }
360
361 mdFile_.close();
362
363 #ifdef IS_MPI
364 }
365 #endif
366
367 std::stringstream rawMetaDataStream(mdRawData);
368
369 //parse meta-data file
370 Globals* simParams = parseFile(rawMetaDataStream, mdFileName, mdFileVersion,
371 metaDataBlockStart + 1);
372
373 //create the force field
374 ForceField * ff = new ForceField(simParams->getForceField());
375
376 if (ff == NULL) {
377 sprintf(painCave.errMsg,
378 "ForceField Factory can not create %s force field\n",
379 simParams->getForceField().c_str());
380 painCave.isFatal = 1;
381 simError();
382 }
383
384 if (simParams->haveForceFieldFileName()) {
385 ff->setForceFieldFileName(simParams->getForceFieldFileName());
386 }
387
388 std::string forcefieldFileName;
389 forcefieldFileName = ff->getForceFieldFileName();
390
391 if (simParams->haveForceFieldVariant()) {
392 //If the force field has variant, the variant force field name will be
393 //Base.variant.frc. For exampel EAM.u6.frc
394
395 std::string variant = simParams->getForceFieldVariant();
396
397 std::string::size_type pos = forcefieldFileName.rfind(".frc");
398 variant = "." + variant;
399 if (pos != std::string::npos) {
400 forcefieldFileName.insert(pos, variant);
401 } else {
402 //If the default force field file name does not containt .frc suffix, just append the .variant
403 forcefieldFileName.append(variant);
404 }
405 }
406
407 ff->parse(forcefieldFileName);
408 //create SimInfo
409 SimInfo * info = new SimInfo(ff, simParams);
410
411 info->setRawMetaData(mdRawData);
412
413 //gather parameters (SimCreator only retrieves part of the
414 //parameters)
415 gatherParameters(info, mdFileName);
416
417 //divide the molecules and determine the global index of molecules
418 #ifdef IS_MPI
419 divideMolecules(info);
420 #endif
421
422 //create the molecules
423 createMolecules(info);
424
425 //find the storage layout
426
427 int storageLayout = computeStorageLayout(info);
428
429 //allocate memory for DataStorage(circular reference, need to
430 //break it)
431 info->setSnapshotManager(new SimSnapshotManager(info, storageLayout));
432
433 //set the global index of atoms, rigidbodies and cutoffgroups
434 //(only need to be set once, the global index will never change
435 //again). Local indices of atoms and rigidbodies are already set
436 //by MoleculeCreator class which actually delegates the
437 //responsibility to LocalIndexManager.
438 setGlobalIndex(info);
439
440 //Although addInteractionPairs is called inside SimInfo's addMolecule
441 //method, at that point atoms don't have the global index yet
442 //(their global index are all initialized to -1). Therefore we
443 //have to call addInteractionPairs explicitly here. A way to work
444 //around is that we can determine the beginning global indices of
445 //atoms before they get created.
446 SimInfo::MoleculeIterator mi;
447 Molecule* mol;
448 for (mol= info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
449 info->addInteractionPairs(mol);
450 }
451
452 if (loadInitCoords)
453 loadCoordinates(info, mdFileName);
454 return info;
455 }
456
457 void SimCreator::gatherParameters(SimInfo *info, const std::string& mdfile) {
458
459 //figure out the output file names
460 std::string prefix;
461
462 #ifdef IS_MPI
463
464 if (worldRank == 0) {
465 #endif // is_mpi
466 Globals * simParams = info->getSimParams();
467 if (simParams->haveFinalConfig()) {
468 prefix = getPrefix(simParams->getFinalConfig());
469 } else {
470 prefix = getPrefix(mdfile);
471 }
472
473 info->setFinalConfigFileName(prefix + ".eor");
474 info->setDumpFileName(prefix + ".dump");
475 info->setStatFileName(prefix + ".stat");
476 info->setRestFileName(prefix + ".zang");
477
478 #ifdef IS_MPI
479
480 }
481
482 #endif
483
484 }
485
486 #ifdef IS_MPI
487 void SimCreator::divideMolecules(SimInfo *info) {
488 RealType numerator;
489 RealType denominator;
490 RealType precast;
491 RealType x;
492 RealType y;
493 RealType a;
494 int old_atoms;
495 int add_atoms;
496 int new_atoms;
497 int nTarget;
498 int done;
499 int i;
500 int j;
501 int loops;
502 int which_proc;
503 int nProcessors;
504 std::vector<int> atomsPerProc;
505 int nGlobalMols = info->getNGlobalMolecules();
506 std::vector<int> molToProcMap(nGlobalMols, -1); // default to an error condition:
507
508 MPI_Comm_size(MPI_COMM_WORLD, &nProcessors);
509
510 if (nProcessors > nGlobalMols) {
511 sprintf(painCave.errMsg,
512 "nProcessors (%d) > nMol (%d)\n"
513 "\tThe number of processors is larger than\n"
514 "\tthe number of molecules. This will not result in a \n"
515 "\tusable division of atoms for force decomposition.\n"
516 "\tEither try a smaller number of processors, or run the\n"
517 "\tsingle-processor version of OpenMD.\n", nProcessors, nGlobalMols);
518
519 painCave.isFatal = 1;
520 simError();
521 }
522
523 int seedValue;
524 Globals * simParams = info->getSimParams();
525 SeqRandNumGen* myRandom; //divide labor does not need Parallel random number generator
526 if (simParams->haveSeed()) {
527 seedValue = simParams->getSeed();
528 myRandom = new SeqRandNumGen(seedValue);
529 }else {
530 myRandom = new SeqRandNumGen();
531 }
532
533
534 a = 3.0 * nGlobalMols / info->getNGlobalAtoms();
535
536 //initialize atomsPerProc
537 atomsPerProc.insert(atomsPerProc.end(), nProcessors, 0);
538
539 if (worldRank == 0) {
540 numerator = info->getNGlobalAtoms();
541 denominator = nProcessors;
542 precast = numerator / denominator;
543 nTarget = (int)(precast + 0.5);
544
545 for(i = 0; i < nGlobalMols; i++) {
546 done = 0;
547 loops = 0;
548
549 while (!done) {
550 loops++;
551
552 // Pick a processor at random
553
554 which_proc = (int) (myRandom->rand() * nProcessors);
555
556 //get the molecule stamp first
557 int stampId = info->getMoleculeStampId(i);
558 MoleculeStamp * moleculeStamp = info->getMoleculeStamp(stampId);
559
560 // How many atoms does this processor have so far?
561 old_atoms = atomsPerProc[which_proc];
562 add_atoms = moleculeStamp->getNAtoms();
563 new_atoms = old_atoms + add_atoms;
564
565 // If we've been through this loop too many times, we need
566 // to just give up and assign the molecule to this processor
567 // and be done with it.
568
569 if (loops > 100) {
570 sprintf(painCave.errMsg,
571 "I've tried 100 times to assign molecule %d to a "
572 " processor, but can't find a good spot.\n"
573 "I'm assigning it at random to processor %d.\n",
574 i, which_proc);
575
576 painCave.isFatal = 0;
577 simError();
578
579 molToProcMap[i] = which_proc;
580 atomsPerProc[which_proc] += add_atoms;
581
582 done = 1;
583 continue;
584 }
585
586 // If we can add this molecule to this processor without sending
587 // it above nTarget, then go ahead and do it:
588
589 if (new_atoms <= nTarget) {
590 molToProcMap[i] = which_proc;
591 atomsPerProc[which_proc] += add_atoms;
592
593 done = 1;
594 continue;
595 }
596
597 // The only situation left is when new_atoms > nTarget. We
598 // want to accept this with some probability that dies off the
599 // farther we are from nTarget
600
601 // roughly: x = new_atoms - nTarget
602 // Pacc(x) = exp(- a * x)
603 // where a = penalty / (average atoms per molecule)
604
605 x = (RealType)(new_atoms - nTarget);
606 y = myRandom->rand();
607
608 if (y < exp(- a * x)) {
609 molToProcMap[i] = which_proc;
610 atomsPerProc[which_proc] += add_atoms;
611
612 done = 1;
613 continue;
614 } else {
615 continue;
616 }
617 }
618 }
619
620 delete myRandom;
621
622 // Spray out this nonsense to all other processors:
623
624 MPI_Bcast(&molToProcMap[0], nGlobalMols, MPI_INT, 0, MPI_COMM_WORLD);
625 } else {
626
627 // Listen to your marching orders from processor 0:
628
629 MPI_Bcast(&molToProcMap[0], nGlobalMols, MPI_INT, 0, MPI_COMM_WORLD);
630 }
631
632 info->setMolToProcMap(molToProcMap);
633 sprintf(checkPointMsg,
634 "Successfully divided the molecules among the processors.\n");
635 errorCheckPoint();
636 }
637
638 #endif
639
640 void SimCreator::createMolecules(SimInfo *info) {
641 MoleculeCreator molCreator;
642 int stampId;
643
644 for(int i = 0; i < info->getNGlobalMolecules(); i++) {
645
646 #ifdef IS_MPI
647
648 if (info->getMolToProc(i) == worldRank) {
649 #endif
650
651 stampId = info->getMoleculeStampId(i);
652 Molecule * mol = molCreator.createMolecule(info->getForceField(),
653 info->getMoleculeStamp(stampId),
654 stampId, i,
655 info->getLocalIndexManager());
656
657 info->addMolecule(mol);
658
659 #ifdef IS_MPI
660
661 }
662
663 #endif
664
665 } //end for(int i=0)
666 }
667
668 int SimCreator::computeStorageLayout(SimInfo* info) {
669
670 Globals* simParams = info->getSimParams();
671 int nRigidBodies = info->getNGlobalRigidBodies();
672 set<AtomType*> atomTypes = info->getSimulatedAtomTypes();
673 set<AtomType*>::iterator i;
674 bool hasDirectionalAtoms = false;
675 bool hasFixedCharge = false;
676 bool hasMultipoles = false;
677 bool hasPolarizable = false;
678 bool hasFluctuatingCharge = false;
679 bool hasMetallic = false;
680 int storageLayout = 0;
681 storageLayout |= DataStorage::dslPosition;
682 storageLayout |= DataStorage::dslVelocity;
683 storageLayout |= DataStorage::dslForce;
684
685 for (i = atomTypes.begin(); i != atomTypes.end(); ++i) {
686
687 DirectionalAdapter da = DirectionalAdapter( (*i) );
688 MultipoleAdapter ma = MultipoleAdapter( (*i) );
689 EAMAdapter ea = EAMAdapter( (*i) );
690 SuttonChenAdapter sca = SuttonChenAdapter( (*i) );
691 PolarizableAdapter pa = PolarizableAdapter( (*i) );
692 FixedChargeAdapter fca = FixedChargeAdapter( (*i) );
693 FluctuatingChargeAdapter fqa = FluctuatingChargeAdapter( (*i) );
694
695 if (da.isDirectional()){
696 hasDirectionalAtoms = true;
697 }
698 if (ma.isMultipole()){
699 hasMultipoles = true;
700 }
701 if (ea.isEAM() || sca.isSuttonChen()){
702 hasMetallic = true;
703 }
704 if ( fca.isFixedCharge() ){
705 hasFixedCharge = true;
706 }
707 if ( fqa.isFluctuatingCharge() ){
708 hasFluctuatingCharge = true;
709 }
710 if ( pa.isPolarizable() ){
711 hasPolarizable = true;
712 }
713 }
714
715 if (nRigidBodies > 0 || hasDirectionalAtoms) {
716 storageLayout |= DataStorage::dslAmat;
717 if(storageLayout & DataStorage::dslVelocity) {
718 storageLayout |= DataStorage::dslAngularMomentum;
719 }
720 if (storageLayout & DataStorage::dslForce) {
721 storageLayout |= DataStorage::dslTorque;
722 }
723 }
724 if (hasMultipoles) {
725 storageLayout |= DataStorage::dslElectroFrame;
726 }
727 if (hasFixedCharge || hasFluctuatingCharge) {
728 storageLayout |= DataStorage::dslSkippedCharge;
729 }
730 if (hasMetallic) {
731 storageLayout |= DataStorage::dslDensity;
732 storageLayout |= DataStorage::dslFunctional;
733 storageLayout |= DataStorage::dslFunctionalDerivative;
734 }
735 if (hasPolarizable) {
736 storageLayout |= DataStorage::dslElectricField;
737 }
738 if (hasFluctuatingCharge){
739 storageLayout |= DataStorage::dslFlucQPosition;
740 if(storageLayout & DataStorage::dslVelocity) {
741 storageLayout |= DataStorage::dslFlucQVelocity;
742 }
743 if (storageLayout & DataStorage::dslForce) {
744 storageLayout |= DataStorage::dslFlucQForce;
745 }
746 }
747
748 // if the user has asked for them, make sure we've got the memory for the
749 // objects defined.
750
751 if (simParams->getOutputParticlePotential()) {
752 storageLayout |= DataStorage::dslParticlePot;
753 }
754
755 if (simParams->havePrintHeatFlux()) {
756 if (simParams->getPrintHeatFlux()) {
757 storageLayout |= DataStorage::dslParticlePot;
758 }
759 }
760
761 if (simParams->getOutputElectricField()) {
762 storageLayout |= DataStorage::dslElectricField;
763 }
764 if (simParams->getOutputFluctuatingCharges()) {
765 storageLayout |= DataStorage::dslFlucQPosition;
766 storageLayout |= DataStorage::dslFlucQVelocity;
767 storageLayout |= DataStorage::dslFlucQForce;
768 }
769
770 return storageLayout;
771 }
772
773 void SimCreator::setGlobalIndex(SimInfo *info) {
774 SimInfo::MoleculeIterator mi;
775 Molecule::AtomIterator ai;
776 Molecule::RigidBodyIterator ri;
777 Molecule::CutoffGroupIterator ci;
778 Molecule::IntegrableObjectIterator ioi;
779 Molecule * mol;
780 Atom * atom;
781 RigidBody * rb;
782 CutoffGroup * cg;
783 int beginAtomIndex;
784 int beginRigidBodyIndex;
785 int beginCutoffGroupIndex;
786 int nGlobalAtoms = info->getNGlobalAtoms();
787
788 beginAtomIndex = 0;
789 beginRigidBodyIndex = 0;
790 beginCutoffGroupIndex = 0;
791
792 for(int i = 0; i < info->getNGlobalMolecules(); i++) {
793
794 #ifdef IS_MPI
795 if (info->getMolToProc(i) == worldRank) {
796 #endif
797 // stuff to do if I own this molecule
798 mol = info->getMoleculeByGlobalIndex(i);
799
800 //local index(index in DataStorge) of atom is important
801 for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
802 atom->setGlobalIndex(beginAtomIndex++);
803 }
804
805 for(rb = mol->beginRigidBody(ri); rb != NULL;
806 rb = mol->nextRigidBody(ri)) {
807 rb->setGlobalIndex(beginRigidBodyIndex++);
808 }
809
810 //local index of cutoff group is trivial, it only depends on
811 //the order of travesing
812 for(cg = mol->beginCutoffGroup(ci); cg != NULL;
813 cg = mol->nextCutoffGroup(ci)) {
814 cg->setGlobalIndex(beginCutoffGroupIndex++);
815 }
816
817 #ifdef IS_MPI
818 } else {
819
820 // stuff to do if I don't own this molecule
821
822 int stampId = info->getMoleculeStampId(i);
823 MoleculeStamp* stamp = info->getMoleculeStamp(stampId);
824
825 beginAtomIndex += stamp->getNAtoms();
826 beginRigidBodyIndex += stamp->getNRigidBodies();
827 beginCutoffGroupIndex += stamp->getNCutoffGroups() + stamp->getNFreeAtoms();
828 }
829 #endif
830
831 } //end for(int i=0)
832
833 //fill globalGroupMembership
834 std::vector<int> globalGroupMembership(info->getNGlobalAtoms(), 0);
835 for(mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
836 for (cg = mol->beginCutoffGroup(ci); cg != NULL; cg = mol->nextCutoffGroup(ci)) {
837
838 for(atom = cg->beginAtom(ai); atom != NULL; atom = cg->nextAtom(ai)) {
839 globalGroupMembership[atom->getGlobalIndex()] = cg->getGlobalIndex();
840 }
841
842 }
843 }
844
845 #ifdef IS_MPI
846 // Since the globalGroupMembership has been zero filled and we've only
847 // poked values into the atoms we know, we can do an Allreduce
848 // to get the full globalGroupMembership array (We think).
849 // This would be prettier if we could use MPI_IN_PLACE like the MPI-2
850 // docs said we could.
851 std::vector<int> tmpGroupMembership(info->getNGlobalAtoms(), 0);
852 MPI_Allreduce(&globalGroupMembership[0], &tmpGroupMembership[0], nGlobalAtoms,
853 MPI_INT, MPI_SUM, MPI_COMM_WORLD);
854 info->setGlobalGroupMembership(tmpGroupMembership);
855 #else
856 info->setGlobalGroupMembership(globalGroupMembership);
857 #endif
858
859 //fill molMembership
860 std::vector<int> globalMolMembership(info->getNGlobalAtoms(), 0);
861
862 for(mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
863 for(atom = mol->beginAtom(ai); atom != NULL; atom = mol->nextAtom(ai)) {
864 globalMolMembership[atom->getGlobalIndex()] = mol->getGlobalIndex();
865 }
866 }
867
868 #ifdef IS_MPI
869 std::vector<int> tmpMolMembership(info->getNGlobalAtoms(), 0);
870
871 MPI_Allreduce(&globalMolMembership[0], &tmpMolMembership[0], nGlobalAtoms,
872 MPI_INT, MPI_SUM, MPI_COMM_WORLD);
873
874 info->setGlobalMolMembership(tmpMolMembership);
875 #else
876 info->setGlobalMolMembership(globalMolMembership);
877 #endif
878
879 // nIOPerMol holds the number of integrable objects per molecule
880 // here the molecules are listed by their global indices.
881
882 std::vector<int> nIOPerMol(info->getNGlobalMolecules(), 0);
883 for (mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
884 nIOPerMol[mol->getGlobalIndex()] = mol->getNIntegrableObjects();
885 }
886
887 #ifdef IS_MPI
888 std::vector<int> numIntegrableObjectsPerMol(info->getNGlobalMolecules(), 0);
889 MPI_Allreduce(&nIOPerMol[0], &numIntegrableObjectsPerMol[0],
890 info->getNGlobalMolecules(), MPI_INT, MPI_SUM, MPI_COMM_WORLD);
891 #else
892 std::vector<int> numIntegrableObjectsPerMol = nIOPerMol;
893 #endif
894
895 std::vector<int> startingIOIndexForMol(info->getNGlobalMolecules());
896
897 int startingIndex = 0;
898 for (int i = 0; i < info->getNGlobalMolecules(); i++) {
899 startingIOIndexForMol[i] = startingIndex;
900 startingIndex += numIntegrableObjectsPerMol[i];
901 }
902
903 std::vector<StuntDouble*> IOIndexToIntegrableObject(info->getNGlobalIntegrableObjects(), (StuntDouble*)NULL);
904 for (mol = info->beginMolecule(mi); mol != NULL; mol = info->nextMolecule(mi)) {
905 int myGlobalIndex = mol->getGlobalIndex();
906 int globalIO = startingIOIndexForMol[myGlobalIndex];
907 for (StuntDouble* integrableObject = mol->beginIntegrableObject(ioi); integrableObject != NULL;
908 integrableObject = mol->nextIntegrableObject(ioi)) {
909 integrableObject->setGlobalIntegrableObjectIndex(globalIO);
910 IOIndexToIntegrableObject[globalIO] = integrableObject;
911 globalIO++;
912 }
913 }
914
915 info->setIOIndexToIntegrableObject(IOIndexToIntegrableObject);
916
917 }
918
919 void SimCreator::loadCoordinates(SimInfo* info, const std::string& mdFileName) {
920 Globals* simParams;
921
922 simParams = info->getSimParams();
923
924 DumpReader reader(info, mdFileName);
925 int nframes = reader.getNFrames();
926
927 if (nframes > 0) {
928 reader.readFrame(nframes - 1);
929 } else {
930 //invalid initial coordinate file
931 sprintf(painCave.errMsg,
932 "Initial configuration file %s should at least contain one frame\n",
933 mdFileName.c_str());
934 painCave.isFatal = 1;
935 simError();
936 }
937 //copy the current snapshot to previous snapshot
938 info->getSnapshotManager()->advance();
939 }
940
941 } //end namespace OpenMD
942
943

Properties

Name Value
svn:keywords Author Id Revision Date