ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-1.0/libmdtools/SimSetup.cpp
Revision: 1417
Committed: Tue Jul 27 15:41:17 2004 UTC (19 years, 11 months ago) by tim
File size: 60327 byte(s)
Log Message:
BASS eradication project (part 1)

File Contents

# Content
1 #include <algorithm>
2 #include <stdlib.h>
3 #include <iostream>
4 #include <math.h>
5 #include <string>
6 #include <sprng.h>
7 #include "SimSetup.hpp"
8 #include "ReadWrite.hpp"
9 #include "parse_me.h"
10 #include "Integrator.hpp"
11 #include "simError.h"
12 #include "RigidBody.hpp"
13 #include "OOPSEMinimizer.hpp"
14
15 #ifdef IS_MPI
16 #include "mpiBASS.h"
17 #include "mpiSimulation.hpp"
18 #endif
19
20 // some defines for ensemble and Forcefield cases
21
22 #define NVE_ENS 0
23 #define NVT_ENS 1
24 #define NPTi_ENS 2
25 #define NPTf_ENS 3
26 #define NPTxyz_ENS 4
27
28
29 #define FF_DUFF 0
30 #define FF_LJ 1
31 #define FF_EAM 2
32 #define FF_H2O 3
33
34 using namespace std;
35
36 /**
37 * Check whether dividend is divisble by divisor or not
38 */
39 bool isDivisible(double dividend, double divisor){
40 double tolerance = 0.000001;
41 double quotient;
42 double diff;
43 int intQuotient;
44
45 quotient = dividend / divisor;
46
47 if (quotient < 0)
48 quotient = -quotient;
49
50 intQuotient = int (quotient + tolerance);
51
52 diff = fabs(fabs(dividend) - intQuotient * fabs(divisor));
53
54 if (diff <= tolerance)
55 return true;
56 else
57 return false;
58 }
59
60 SimSetup::SimSetup(){
61
62 initSuspend = false;
63 isInfoArray = 0;
64 nInfo = 1;
65
66 stamps = new MakeStamps();
67 globals = new Globals();
68
69
70 #ifdef IS_MPI
71 strcpy(checkPointMsg, "SimSetup creation successful");
72 MPIcheckPoint();
73 #endif // IS_MPI
74 }
75
76 SimSetup::~SimSetup(){
77 delete stamps;
78 delete globals;
79 }
80
81 void SimSetup::setSimInfo(SimInfo* the_info, int theNinfo){
82 info = the_info;
83 nInfo = theNinfo;
84 isInfoArray = 1;
85 initSuspend = true;
86 }
87
88
89 void SimSetup::parseFile(char* fileName){
90 #ifdef IS_MPI
91 if (worldRank == 0){
92 #endif // is_mpi
93
94 inFileName = fileName;
95 set_interface_stamps(stamps, globals);
96
97 #ifdef IS_MPI
98 mpiEventInit();
99 #endif
100
101 yacc_BASS(fileName);
102
103 #ifdef IS_MPI
104 throwMPIEvent(NULL);
105 }
106 else{
107 receiveParse();
108 }
109 #endif
110
111 }
112
113 #ifdef IS_MPI
114 void SimSetup::receiveParse(void){
115 set_interface_stamps(stamps, globals);
116 mpiEventInit();
117 MPIcheckPoint();
118 mpiEventLoop();
119 }
120
121 #endif // is_mpi
122
123 void SimSetup::createSim(void){
124
125 // gather all of the information from the Bass file
126
127 gatherInfo();
128
129 // creation of complex system objects
130
131 sysObjectsCreation();
132
133 // check on the post processing info
134
135 finalInfoCheck();
136
137 // initialize the system coordinates
138
139 if ( !initSuspend ){
140 initSystemCoords();
141
142 if( !(globals->getUseInitTime()) )
143 info[0].currentTime = 0.0;
144 }
145
146 // make the output filenames
147
148 makeOutNames();
149
150 #ifdef IS_MPI
151 mpiSim->mpiRefresh();
152 #endif
153
154 // initialize the Fortran
155
156 initFortran();
157
158 if (globals->haveMinimizer())
159 // make minimizer
160 makeMinimizer();
161 else
162 // make the integrator
163 makeIntegrator();
164
165 }
166
167
168 void SimSetup::makeMolecules(void){
169 int i, j, k;
170 int exI, exJ, exK, exL, slI, slJ;
171 int tempI, tempJ, tempK, tempL;
172 int molI, globalID;
173 int stampID, atomOffset, rbOffset, groupOffset;
174 molInit molInfo;
175 DirectionalAtom* dAtom;
176 RigidBody* myRB;
177 StuntDouble* mySD;
178 LinkedAssign* extras;
179 LinkedAssign* current_extra;
180 AtomStamp* currentAtom;
181 BondStamp* currentBond;
182 BendStamp* currentBend;
183 TorsionStamp* currentTorsion;
184 RigidBodyStamp* currentRigidBody;
185 CutoffGroupStamp* currentCutoffGroup;
186 CutoffGroup* myCutoffGroup;
187 int nCutoffGroups;// number of cutoff group of a molecule defined in mdl file
188 set<int> cutoffAtomSet; //atoms belong to cutoffgroup defined at mdl file
189
190 bond_pair* theBonds;
191 bend_set* theBends;
192 torsion_set* theTorsions;
193
194 set<int> skipList;
195
196 double phi, theta, psi;
197 char* molName;
198 char rbName[100];
199
200 int whichRigidBody;
201 int consAtomIndex; //index of constraint atom in rigid body's atom array
202 double bondLength2;
203 //init the forceField paramters
204
205 the_ff->readParams();
206
207 // init the atoms
208
209 int nMembers, nNew, rb1, rb2;
210
211 for (k = 0; k < nInfo; k++){
212 the_ff->setSimInfo(&(info[k]));
213
214 #ifdef IS_MPI
215 info[k].globalGroupMembership = new int[mpiSim->getNAtomsGlobal()];
216 for (i = 0; i < mpiSim->getNAtomsGlobal(); i++)
217 info[k].globalGroupMembership[i] = 0;
218 #else
219 info[k].globalGroupMembership = new int[info[k].n_atoms];
220 for (i = 0; i < info[k].n_atoms; i++)
221 info[k].globalGroupMembership[i] = 0;
222 #endif
223
224 atomOffset = 0;
225 groupOffset = 0;
226
227 for (i = 0; i < info[k].n_mol; i++){
228 stampID = info[k].molecules[i].getStampID();
229 molName = comp_stamps[stampID]->getID();
230
231 molInfo.nAtoms = comp_stamps[stampID]->getNAtoms();
232 molInfo.nBonds = comp_stamps[stampID]->getNBonds();
233 molInfo.nBends = comp_stamps[stampID]->getNBends();
234 molInfo.nTorsions = comp_stamps[stampID]->getNTorsions();
235 molInfo.nRigidBodies = comp_stamps[stampID]->getNRigidBodies();
236
237 nCutoffGroups = comp_stamps[stampID]->getNCutoffGroups();
238
239 molInfo.myAtoms = &(info[k].atoms[atomOffset]);
240
241 if (molInfo.nBonds > 0)
242 molInfo.myBonds = new Bond*[molInfo.nBonds];
243 else
244 molInfo.myBonds = NULL;
245
246 if (molInfo.nBends > 0)
247 molInfo.myBends = new Bend*[molInfo.nBends];
248 else
249 molInfo.myBends = NULL;
250
251 if (molInfo.nTorsions > 0)
252 molInfo.myTorsions = new Torsion *[molInfo.nTorsions];
253 else
254 molInfo.myTorsions = NULL;
255
256 theBonds = new bond_pair[molInfo.nBonds];
257 theBends = new bend_set[molInfo.nBends];
258 theTorsions = new torsion_set[molInfo.nTorsions];
259
260 // make the Atoms
261
262 for (j = 0; j < molInfo.nAtoms; j++){
263 currentAtom = comp_stamps[stampID]->getAtom(j);
264
265 if (currentAtom->haveOrientation()){
266 dAtom = new DirectionalAtom((j + atomOffset),
267 info[k].getConfiguration());
268 info[k].n_oriented++;
269 molInfo.myAtoms[j] = dAtom;
270
271 // Directional Atoms have standard unit vectors which are oriented
272 // in space using the three Euler angles. We assume the standard
273 // unit vector was originally along the z axis below.
274
275 phi = currentAtom->getEulerPhi() * M_PI / 180.0;
276 theta = currentAtom->getEulerTheta() * M_PI / 180.0;
277 psi = currentAtom->getEulerPsi()* M_PI / 180.0;
278
279 dAtom->setUnitFrameFromEuler(phi, theta, psi);
280
281 }
282 else{
283
284 molInfo.myAtoms[j] = new Atom((j + atomOffset), info[k].getConfiguration());
285
286 }
287
288 molInfo.myAtoms[j]->setType(currentAtom->getType());
289 #ifdef IS_MPI
290 molInfo.myAtoms[j]->setGlobalIndex(globalAtomIndex[j + atomOffset]);
291 #endif // is_mpi
292 }
293
294 // make the bonds
295 for (j = 0; j < molInfo.nBonds; j++){
296 currentBond = comp_stamps[stampID]->getBond(j);
297 theBonds[j].a = currentBond->getA() + atomOffset;
298 theBonds[j].b = currentBond->getB() + atomOffset;
299
300 tempI = theBonds[j].a;
301 tempJ = theBonds[j].b;
302
303 #ifdef IS_MPI
304 exI = info[k].atoms[tempI]->getGlobalIndex() + 1;
305 exJ = info[k].atoms[tempJ]->getGlobalIndex() + 1;
306 #else
307 exI = tempI + 1;
308 exJ = tempJ + 1;
309 #endif
310
311 info[k].excludes->addPair(exI, exJ);
312 }
313
314 //make the bends
315 for (j = 0; j < molInfo.nBends; j++){
316 currentBend = comp_stamps[stampID]->getBend(j);
317 theBends[j].a = currentBend->getA() + atomOffset;
318 theBends[j].b = currentBend->getB() + atomOffset;
319 theBends[j].c = currentBend->getC() + atomOffset;
320
321 if (currentBend->haveExtras()){
322 extras = currentBend->getExtras();
323 current_extra = extras;
324
325 while (current_extra != NULL){
326 if (!strcmp(current_extra->getlhs(), "ghostVectorSource")){
327 switch (current_extra->getType()){
328 case 0:
329 theBends[j].ghost = current_extra->getInt() + atomOffset;
330 theBends[j].isGhost = 1;
331 break;
332
333 case 1:
334 theBends[j].ghost = (int) current_extra->getDouble() +
335 atomOffset;
336 theBends[j].isGhost = 1;
337 break;
338
339 default:
340 sprintf(painCave.errMsg,
341 "SimSetup Error: ghostVectorSource was neither a "
342 "double nor an int.\n"
343 "-->Bend[%d] in %s\n",
344 j, comp_stamps[stampID]->getID());
345 painCave.isFatal = 1;
346 simError();
347 }
348 }
349 else{
350 sprintf(painCave.errMsg,
351 "SimSetup Error: unhandled bend assignment:\n"
352 " -->%s in Bend[%d] in %s\n",
353 current_extra->getlhs(), j, comp_stamps[stampID]->getID());
354 painCave.isFatal = 1;
355 simError();
356 }
357
358 current_extra = current_extra->getNext();
359 }
360 }
361
362 if (theBends[j].isGhost) {
363
364 tempI = theBends[j].a;
365 tempJ = theBends[j].b;
366
367 #ifdef IS_MPI
368 exI = info[k].atoms[tempI]->getGlobalIndex() + 1;
369 exJ = info[k].atoms[tempJ]->getGlobalIndex() + 1;
370 #else
371 exI = tempI + 1;
372 exJ = tempJ + 1;
373 #endif
374 info[k].excludes->addPair(exI, exJ);
375
376 } else {
377
378 tempI = theBends[j].a;
379 tempJ = theBends[j].b;
380 tempK = theBends[j].c;
381
382 #ifdef IS_MPI
383 exI = info[k].atoms[tempI]->getGlobalIndex() + 1;
384 exJ = info[k].atoms[tempJ]->getGlobalIndex() + 1;
385 exK = info[k].atoms[tempK]->getGlobalIndex() + 1;
386 #else
387 exI = tempI + 1;
388 exJ = tempJ + 1;
389 exK = tempK + 1;
390 #endif
391
392 info[k].excludes->addPair(exI, exK);
393 info[k].excludes->addPair(exI, exJ);
394 info[k].excludes->addPair(exJ, exK);
395 }
396 }
397
398 for (j = 0; j < molInfo.nTorsions; j++){
399 currentTorsion = comp_stamps[stampID]->getTorsion(j);
400 theTorsions[j].a = currentTorsion->getA() + atomOffset;
401 theTorsions[j].b = currentTorsion->getB() + atomOffset;
402 theTorsions[j].c = currentTorsion->getC() + atomOffset;
403 theTorsions[j].d = currentTorsion->getD() + atomOffset;
404
405 tempI = theTorsions[j].a;
406 tempJ = theTorsions[j].b;
407 tempK = theTorsions[j].c;
408 tempL = theTorsions[j].d;
409
410 #ifdef IS_MPI
411 exI = info[k].atoms[tempI]->getGlobalIndex() + 1;
412 exJ = info[k].atoms[tempJ]->getGlobalIndex() + 1;
413 exK = info[k].atoms[tempK]->getGlobalIndex() + 1;
414 exL = info[k].atoms[tempL]->getGlobalIndex() + 1;
415 #else
416 exI = tempI + 1;
417 exJ = tempJ + 1;
418 exK = tempK + 1;
419 exL = tempL + 1;
420 #endif
421
422 info[k].excludes->addPair(exI, exJ);
423 info[k].excludes->addPair(exI, exK);
424 info[k].excludes->addPair(exI, exL);
425 info[k].excludes->addPair(exJ, exK);
426 info[k].excludes->addPair(exJ, exL);
427 info[k].excludes->addPair(exK, exL);
428 }
429
430
431 molInfo.myRigidBodies.clear();
432
433 for (j = 0; j < molInfo.nRigidBodies; j++){
434
435 currentRigidBody = comp_stamps[stampID]->getRigidBody(j);
436 nMembers = currentRigidBody->getNMembers();
437
438 // Create the Rigid Body:
439
440 myRB = new RigidBody();
441
442 sprintf(rbName,"%s_RB_%d", molName, j);
443 myRB->setType(rbName);
444
445 for (rb1 = 0; rb1 < nMembers; rb1++) {
446
447 // molI is atom numbering inside this molecule
448 molI = currentRigidBody->getMember(rb1);
449
450 // tempI is atom numbering on local processor
451 tempI = molI + atomOffset;
452
453 // currentAtom is the AtomStamp (which we need for
454 // rigid body reference positions)
455 currentAtom = comp_stamps[stampID]->getAtom(molI);
456
457 // When we add to the rigid body, add the atom itself and
458 // the stamp info:
459
460 myRB->addAtom(info[k].atoms[tempI], currentAtom);
461
462 // Add this atom to the Skip List for the integrators
463 #ifdef IS_MPI
464 slI = info[k].atoms[tempI]->getGlobalIndex();
465 #else
466 slI = tempI;
467 #endif
468 skipList.insert(slI);
469
470 }
471
472 for(rb1 = 0; rb1 < nMembers - 1; rb1++) {
473 for(rb2 = rb1+1; rb2 < nMembers; rb2++) {
474
475 tempI = currentRigidBody->getMember(rb1);
476 tempJ = currentRigidBody->getMember(rb2);
477
478 // Some explanation is required here.
479 // Fortran indexing starts at 1, while c indexing starts at 0
480 // Also, in parallel computations, the GlobalIndex is
481 // used for the exclude list:
482
483 #ifdef IS_MPI
484 exI = molInfo.myAtoms[tempI]->getGlobalIndex() + 1;
485 exJ = molInfo.myAtoms[tempJ]->getGlobalIndex() + 1;
486 #else
487 exI = molInfo.myAtoms[tempI]->getIndex() + 1;
488 exJ = molInfo.myAtoms[tempJ]->getIndex() + 1;
489 #endif
490
491 info[k].excludes->addPair(exI, exJ);
492
493 }
494 }
495
496 molInfo.myRigidBodies.push_back(myRB);
497 info[k].rigidBodies.push_back(myRB);
498 }
499
500
501 //create cutoff group for molecule
502
503 cutoffAtomSet.clear();
504 molInfo.myCutoffGroups.clear();
505
506 for (j = 0; j < nCutoffGroups; j++){
507
508 currentCutoffGroup = comp_stamps[stampID]->getCutoffGroup(j);
509 nMembers = currentCutoffGroup->getNMembers();
510
511 myCutoffGroup = new CutoffGroup();
512
513 #ifdef IS_MPI
514 myCutoffGroup->setGlobalIndex(globalGroupIndex[groupOffset]);
515 #else
516 myCutoffGroup->setGlobalIndex(groupOffset);
517 #endif
518
519 for (int cg = 0; cg < nMembers; cg++) {
520
521 // molI is atom numbering inside this molecule
522 molI = currentCutoffGroup->getMember(cg);
523
524 // tempI is atom numbering on local processor
525 tempI = molI + atomOffset;
526
527 #ifdef IS_MPI
528 globalID = info[k].atoms[tempI]->getGlobalIndex();
529 info[k].globalGroupMembership[globalID] = globalGroupIndex[groupOffset];
530 #else
531 globalID = info[k].atoms[tempI]->getIndex();
532 info[k].globalGroupMembership[globalID] = groupOffset;
533 #endif
534 myCutoffGroup->addAtom(info[k].atoms[tempI]);
535 cutoffAtomSet.insert(tempI);
536 }
537
538 molInfo.myCutoffGroups.push_back(myCutoffGroup);
539 groupOffset++;
540
541 }//end for (j = 0; j < molInfo.nCutoffGroups; j++)
542
543
544 // create a cutoff group for every atom in current molecule which
545 // does not belong to cutoffgroup defined at mdl file
546
547 for(j = 0; j < molInfo.nAtoms; j++){
548
549 if(cutoffAtomSet.find(molInfo.myAtoms[j]->getIndex()) == cutoffAtomSet.end()){
550 myCutoffGroup = new CutoffGroup();
551 myCutoffGroup->addAtom(molInfo.myAtoms[j]);
552
553 #ifdef IS_MPI
554 myCutoffGroup->setGlobalIndex(globalGroupIndex[groupOffset]);
555 globalID = info[k].atoms[atomOffset + j]->getGlobalIndex();
556 info[k].globalGroupMembership[globalID] = globalGroupIndex[groupOffset];
557 #else
558 myCutoffGroup->setGlobalIndex(groupOffset);
559 globalID = info[k].atoms[atomOffset + j]->getIndex();
560 info[k].globalGroupMembership[globalID] = groupOffset;
561 #endif
562 molInfo.myCutoffGroups.push_back(myCutoffGroup);
563 groupOffset++;
564 }
565 }
566
567 // After this is all set up, scan through the atoms to
568 // see if they can be added to the integrableObjects:
569
570 molInfo.myIntegrableObjects.clear();
571
572
573 for (j = 0; j < molInfo.nAtoms; j++){
574
575 #ifdef IS_MPI
576 slJ = molInfo.myAtoms[j]->getGlobalIndex();
577 #else
578 slJ = j+atomOffset;
579 #endif
580
581 // if they aren't on the skip list, then they can be integrated
582
583 if (skipList.find(slJ) == skipList.end()) {
584 mySD = (StuntDouble *) molInfo.myAtoms[j];
585 info[k].integrableObjects.push_back(mySD);
586 molInfo.myIntegrableObjects.push_back(mySD);
587 }
588 }
589
590 // all rigid bodies are integrated:
591
592 for (j = 0; j < molInfo.nRigidBodies; j++) {
593 mySD = (StuntDouble *) molInfo.myRigidBodies[j];
594 info[k].integrableObjects.push_back(mySD);
595 molInfo.myIntegrableObjects.push_back(mySD);
596 }
597
598 // send the arrays off to the forceField for init.
599
600 the_ff->initializeAtoms(molInfo.nAtoms, molInfo.myAtoms);
601 the_ff->initializeBonds(molInfo.nBonds, molInfo.myBonds, theBonds);
602 the_ff->initializeBends(molInfo.nBends, molInfo.myBends, theBends);
603 the_ff->initializeTorsions(molInfo.nTorsions, molInfo.myTorsions,
604 theTorsions);
605
606 info[k].molecules[i].initialize(molInfo);
607
608
609 atomOffset += molInfo.nAtoms;
610 delete[] theBonds;
611 delete[] theBends;
612 delete[] theTorsions;
613 }
614
615
616
617 #ifdef IS_MPI
618 // Since the globalGroupMembership has been zero filled and we've only
619 // poked values into the atoms we know, we can do an Allreduce
620 // to get the full globalGroupMembership array (We think).
621 // This would be prettier if we could use MPI_IN_PLACE like the MPI-2
622 // docs said we could.
623
624 int* ggMjunk = new int[mpiSim->getNAtomsGlobal()];
625
626 MPI_Allreduce(info[k].globalGroupMembership,
627 ggMjunk,
628 mpiSim->getNAtomsGlobal(),
629 MPI_INT, MPI_SUM, MPI_COMM_WORLD);
630
631 for (i = 0; i < mpiSim->getNAtomsGlobal(); i++)
632 info[k].globalGroupMembership[i] = ggMjunk[i];
633
634 delete[] ggMjunk;
635
636 #endif
637
638
639
640 }
641
642 #ifdef IS_MPI
643 sprintf(checkPointMsg, "all molecules initialized succesfully");
644 MPIcheckPoint();
645 #endif // is_mpi
646
647 }
648
649 void SimSetup::initFromBass(void){
650 int i, j, k;
651 int n_cells;
652 double cellx, celly, cellz;
653 double temp1, temp2, temp3;
654 int n_per_extra;
655 int n_extra;
656 int have_extra, done;
657
658 double vel[3];
659 vel[0] = 0.0;
660 vel[1] = 0.0;
661 vel[2] = 0.0;
662
663 temp1 = (double) tot_nmol / 4.0;
664 temp2 = pow(temp1, (1.0 / 3.0));
665 temp3 = ceil(temp2);
666
667 have_extra = 0;
668 if (temp2 < temp3){
669 // we have a non-complete lattice
670 have_extra = 1;
671
672 n_cells = (int) temp3 - 1;
673 cellx = info[0].boxL[0] / temp3;
674 celly = info[0].boxL[1] / temp3;
675 cellz = info[0].boxL[2] / temp3;
676 n_extra = tot_nmol - (4 * n_cells * n_cells * n_cells);
677 temp1 = ((double) n_extra) / (pow(temp3, 3.0) - pow(n_cells, 3.0));
678 n_per_extra = (int) ceil(temp1);
679
680 if (n_per_extra > 4){
681 sprintf(painCave.errMsg,
682 "SimSetup error. There has been an error in constructing"
683 " the non-complete lattice.\n");
684 painCave.isFatal = 1;
685 simError();
686 }
687 }
688 else{
689 n_cells = (int) temp3;
690 cellx = info[0].boxL[0] / temp3;
691 celly = info[0].boxL[1] / temp3;
692 cellz = info[0].boxL[2] / temp3;
693 }
694
695 current_mol = 0;
696 current_comp_mol = 0;
697 current_comp = 0;
698 current_atom_ndx = 0;
699
700 for (i = 0; i < n_cells ; i++){
701 for (j = 0; j < n_cells; j++){
702 for (k = 0; k < n_cells; k++){
703 makeElement(i * cellx, j * celly, k * cellz);
704
705 makeElement(i * cellx + 0.5 * cellx, j * celly + 0.5 * celly, k * cellz);
706
707 makeElement(i * cellx, j * celly + 0.5 * celly, k * cellz + 0.5 * cellz);
708
709 makeElement(i * cellx + 0.5 * cellx, j * celly, k * cellz + 0.5 * cellz);
710 }
711 }
712 }
713
714 if (have_extra){
715 done = 0;
716
717 int start_ndx;
718 for (i = 0; i < (n_cells + 1) && !done; i++){
719 for (j = 0; j < (n_cells + 1) && !done; j++){
720 if (i < n_cells){
721 if (j < n_cells){
722 start_ndx = n_cells;
723 }
724 else
725 start_ndx = 0;
726 }
727 else
728 start_ndx = 0;
729
730 for (k = start_ndx; k < (n_cells + 1) && !done; k++){
731 makeElement(i * cellx, j * celly, k * cellz);
732 done = (current_mol >= tot_nmol);
733
734 if (!done && n_per_extra > 1){
735 makeElement(i * cellx + 0.5 * cellx, j * celly + 0.5 * celly,
736 k * cellz);
737 done = (current_mol >= tot_nmol);
738 }
739
740 if (!done && n_per_extra > 2){
741 makeElement(i * cellx, j * celly + 0.5 * celly,
742 k * cellz + 0.5 * cellz);
743 done = (current_mol >= tot_nmol);
744 }
745
746 if (!done && n_per_extra > 3){
747 makeElement(i * cellx + 0.5 * cellx, j * celly,
748 k * cellz + 0.5 * cellz);
749 done = (current_mol >= tot_nmol);
750 }
751 }
752 }
753 }
754 }
755
756 for (i = 0; i < info[0].n_atoms; i++){
757 info[0].atoms[i]->setVel(vel);
758 }
759 }
760
761 void SimSetup::makeElement(double x, double y, double z){
762 int k;
763 AtomStamp* current_atom;
764 DirectionalAtom* dAtom;
765 double rotMat[3][3];
766 double pos[3];
767
768 for (k = 0; k < comp_stamps[current_comp]->getNAtoms(); k++){
769 current_atom = comp_stamps[current_comp]->getAtom(k);
770 if (!current_atom->havePosition()){
771 sprintf(painCave.errMsg,
772 "SimSetup:initFromBass error.\n"
773 "\tComponent %s, atom %s does not have a position specified.\n"
774 "\tThe initialization routine is unable to give a start"
775 " position.\n",
776 comp_stamps[current_comp]->getID(), current_atom->getType());
777 painCave.isFatal = 1;
778 simError();
779 }
780
781 pos[0] = x + current_atom->getPosX();
782 pos[1] = y + current_atom->getPosY();
783 pos[2] = z + current_atom->getPosZ();
784
785 info[0].atoms[current_atom_ndx]->setPos(pos);
786
787 if (info[0].atoms[current_atom_ndx]->isDirectional()){
788 dAtom = (DirectionalAtom *) info[0].atoms[current_atom_ndx];
789
790 rotMat[0][0] = 1.0;
791 rotMat[0][1] = 0.0;
792 rotMat[0][2] = 0.0;
793
794 rotMat[1][0] = 0.0;
795 rotMat[1][1] = 1.0;
796 rotMat[1][2] = 0.0;
797
798 rotMat[2][0] = 0.0;
799 rotMat[2][1] = 0.0;
800 rotMat[2][2] = 1.0;
801
802 dAtom->setA(rotMat);
803 }
804
805 current_atom_ndx++;
806 }
807
808 current_mol++;
809 current_comp_mol++;
810
811 if (current_comp_mol >= components_nmol[current_comp]){
812 current_comp_mol = 0;
813 current_comp++;
814 }
815 }
816
817
818 void SimSetup::gatherInfo(void){
819 int i;
820
821 ensembleCase = -1;
822 ffCase = -1;
823
824 // set the easy ones first
825
826 for (i = 0; i < nInfo; i++){
827 if (globals->haveTargetTemp()) {
828 info[i].target_temp = globals->getTargetTemp();
829 info[i].have_target_temp = 1;
830 } else {
831 info[i].have_target_temp = 0;
832 }
833 if (globals->haveDt()) {
834 info[i].dt = globals->getDt();
835 }
836 if (globals->haveRunTime()) {
837 info[i].run_time = globals->getRunTime();
838 }
839 }
840 n_components = globals->getNComponents();
841
842
843 // get the forceField
844
845 strcpy(force_field, globals->getForceField());
846
847 if (!strcasecmp(force_field, "DUFF")){
848 ffCase = FF_DUFF;
849 }
850 else if (!strcasecmp(force_field, "LJ")){
851 ffCase = FF_LJ;
852 }
853 else if (!strcasecmp(force_field, "EAM")){
854 ffCase = FF_EAM;
855 }
856 else if (!strcasecmp(force_field, "WATER")){
857 ffCase = FF_H2O;
858 }
859 else{
860 sprintf(painCave.errMsg, "SimSetup Error. Unrecognized force field -> %s\n",
861 force_field);
862 painCave.isFatal = 1;
863 simError();
864 }
865 if (globals->haveForceFieldVariant()) {
866 strcpy(forcefield_variant, globals->getForceFieldVariant());
867 has_forcefield_variant = 1;
868 }
869
870 // get the ensemble
871
872
873 if (globals->haveEnsemble()) {
874
875 strcpy(ensemble, globals->getEnsemble());
876
877 if (!strcasecmp(ensemble, "NVE")){
878 ensembleCase = NVE_ENS;
879 }
880 else if (!strcasecmp(ensemble, "NVT")){
881 ensembleCase = NVT_ENS;
882 }
883 else if (!strcasecmp(ensemble, "NPTi") || !strcasecmp(ensemble, "NPT")){
884 ensembleCase = NPTi_ENS;
885 }
886 else if (!strcasecmp(ensemble, "NPTf")){
887 ensembleCase = NPTf_ENS;
888 }
889 else if (!strcasecmp(ensemble, "NPTxyz")){
890 ensembleCase = NPTxyz_ENS;
891 }
892 else{
893 sprintf(painCave.errMsg,
894 "SimSetup Warning. Unrecognized Ensemble -> %s \n"
895 "\treverting to NVE for this simulation.\n",
896 ensemble);
897 painCave.isFatal = 0;
898 simError();
899 strcpy(ensemble, "NVE");
900 ensembleCase = NVE_ENS;
901 }
902
903 for (i = 0; i < nInfo; i++)
904 strcpy(info[i].ensemble, ensemble);
905
906
907 //check whether sample time, status time, thermal time and reset time are divisble by dt
908 if (globals->haveSampleTime() && !isDivisible(globals->getSampleTime(), globals->getDt())){
909 sprintf(painCave.errMsg,
910 "Sample time is not divisible by dt.\n"
911 "\tThis will result in samples that are not uniformly\n"
912 "\tdistributed in time. If this is a problem, change\n"
913 "\tyour sampleTime variable.\n");
914 painCave.isFatal = 0;
915 simError();
916 }
917
918 if (globals->haveStatusTime() && !isDivisible(globals->getStatusTime(), globals->getDt())){
919 sprintf(painCave.errMsg,
920 "Status time is not divisible by dt.\n"
921 "\tThis will result in status reports that are not uniformly\n"
922 "\tdistributed in time. If this is a problem, change \n"
923 "\tyour statusTime variable.\n");
924 painCave.isFatal = 0;
925 simError();
926 }
927
928 if (globals->haveThermalTime() && !isDivisible(globals->getThermalTime(), globals->getDt())){
929 sprintf(painCave.errMsg,
930 "Thermal time is not divisible by dt.\n"
931 "\tThis will result in thermalizations that are not uniformly\n"
932 "\tdistributed in time. If this is a problem, change \n"
933 "\tyour thermalTime variable.\n");
934 painCave.isFatal = 0;
935 simError();
936 }
937
938 if (globals->haveResetTime() && !isDivisible(globals->getResetTime(), globals->getDt())){
939 sprintf(painCave.errMsg,
940 "Reset time is not divisible by dt.\n"
941 "\tThis will result in integrator resets that are not uniformly\n"
942 "\tdistributed in time. If this is a problem, change\n"
943 "\tyour resetTime variable.\n");
944 painCave.isFatal = 0;
945 simError();
946 }
947
948 // set the status, sample, and thermal kick times
949
950 for (i = 0; i < nInfo; i++){
951 if (globals->haveSampleTime()){
952 info[i].sampleTime = globals->getSampleTime();
953 info[i].statusTime = info[i].sampleTime;
954 }
955 else{
956 info[i].sampleTime = globals->getRunTime();
957 info[i].statusTime = info[i].sampleTime;
958 }
959
960 if (globals->haveStatusTime()){
961 info[i].statusTime = globals->getStatusTime();
962 }
963
964 if (globals->haveThermalTime()){
965 info[i].thermalTime = globals->getThermalTime();
966 } else {
967 info[i].thermalTime = globals->getRunTime();
968 }
969
970 info[i].resetIntegrator = 0;
971 if( globals->haveResetTime() ){
972 info[i].resetTime = globals->getResetTime();
973 info[i].resetIntegrator = 1;
974 }
975 }
976
977
978 for (i=0; i < nInfo; i++) {
979
980 // check for the temperature set flag
981
982 if (globals->haveTempSet())
983 info[i].setTemp = globals->getTempSet();
984
985 // check for the extended State init
986
987 info[i].useInitXSstate = globals->getUseInitXSstate();
988 info[i].orthoTolerance = globals->getOrthoBoxTolerance();
989
990 // check for thermodynamic integration
991 if (globals->getUseSolidThermInt() && !globals->getUseLiquidThermInt()) {
992 if (globals->haveThermIntLambda() && globals->haveThermIntK()) {
993 info[i].useSolidThermInt = globals->getUseSolidThermInt();
994 info[i].thermIntLambda = globals->getThermIntLambda();
995 info[i].thermIntK = globals->getThermIntK();
996
997 Restraints *myRestraint = new Restraints(tot_nmol, info[i].thermIntLambda, info[i].thermIntK);
998 info[i].restraint = myRestraint;
999 }
1000 else {
1001 sprintf(painCave.errMsg,
1002 "SimSetup Error:\n"
1003 "\tKeyword useSolidThermInt was set to 'true' but\n"
1004 "\tthermodynamicIntegrationLambda (and/or\n"
1005 "\tthermodynamicIntegrationK) was not specified.\n"
1006 "\tPlease provide a lambda value and k value in your .md file.\n");
1007 painCave.isFatal = 1;
1008 simError();
1009 }
1010 }
1011 else if(globals->getUseLiquidThermInt()) {
1012 if (globals->getUseSolidThermInt()) {
1013 sprintf( painCave.errMsg,
1014 "SimSetup Warning: It appears that you have both solid and\n"
1015 "\tliquid thermodynamic integration activated in your .md\n"
1016 "\tfile. To avoid confusion, specify only one technique in\n"
1017 "\tyour .md file. Liquid-state thermodynamic integration\n"
1018 "\twill be assumed for the current simulation. If this is not\n"
1019 "\twhat you desire, set useSolidThermInt to 'true' and\n"
1020 "\tuseLiquidThermInt to 'false' in your .md file.\n");
1021 painCave.isFatal = 0;
1022 simError();
1023 }
1024 if (globals->haveThermIntLambda() && globals->haveThermIntK()) {
1025 info[i].useLiquidThermInt = globals->getUseLiquidThermInt();
1026 info[i].thermIntLambda = globals->getThermIntLambda();
1027 info[i].thermIntK = globals->getThermIntK();
1028 }
1029 else {
1030 sprintf(painCave.errMsg,
1031 "SimSetup Error:\n"
1032 "\tKeyword useLiquidThermInt was set to 'true' but\n"
1033 "\tthermodynamicIntegrationLambda (and/or\n"
1034 "\tthermodynamicIntegrationK) was not specified.\n"
1035 "\tPlease provide a lambda value and k value in your .md file.\n");
1036 painCave.isFatal = 1;
1037 simError();
1038 }
1039 }
1040 else if(globals->haveThermIntLambda() || globals->haveThermIntK()){
1041 sprintf(painCave.errMsg,
1042 "SimSetup Warning: If you want to use Thermodynamic\n"
1043 "\tIntegration, set useSolidThermInt or useLiquidThermInt to\n"
1044 "\t'true' in your .md file. These keywords are set to\n"
1045 "\t'false' by default, so your lambda and/or k values are\n"
1046 "\tbeing ignored.\n");
1047 painCave.isFatal = 0;
1048 simError();
1049 }
1050 }
1051 }
1052
1053 for (i = 0; i < nInfo; i++) {
1054 // get the mixing rule
1055
1056 strcpy(info[i].mixingRule, globals->getMixingRule());
1057 info[i].usePBC = globals->getPBC();
1058 }
1059
1060 // get the components and calculate the tot_nMol and indvidual n_mol
1061
1062 the_components = globals->getComponents();
1063 components_nmol = new int[n_components];
1064
1065 if (!globals->haveNMol()){
1066 // we don't have the total number of molecules, so we assume it is
1067 // given in each component
1068
1069 tot_nmol = 0;
1070 for (i = 0; i < n_components; i++){
1071 if (!the_components[i]->haveNMol()){
1072 // we have a problem
1073 sprintf(painCave.errMsg,
1074 "SimSetup Error. No global NMol or component NMol given.\n"
1075 "\tCannot calculate the number of atoms.\n");
1076 painCave.isFatal = 1;
1077 simError();
1078 }
1079
1080 tot_nmol += the_components[i]->getNMol();
1081 components_nmol[i] = the_components[i]->getNMol();
1082 }
1083 }
1084 else{
1085 sprintf(painCave.errMsg,
1086 "SimSetup error.\n"
1087 "\tSorry, the ability to specify total"
1088 " nMols and then give molfractions in the components\n"
1089 "\tis not currently supported."
1090 " Please give nMol in the components.\n");
1091 painCave.isFatal = 1;
1092 simError();
1093 }
1094
1095
1096
1097
1098 //setup seed for random number generator
1099 int seedValue;
1100
1101 if (globals->haveSeed()){
1102 seedValue = globals->getSeed();
1103
1104 if(seedValue / 1E9 == 0){
1105 sprintf(painCave.errMsg,
1106 "Seed for sprng library should contain at least 9 digits\n"
1107 "OOPSE will generate a seed for user\n");
1108 painCave.isFatal = 0;
1109 simError();
1110
1111 //using seed generated by system instead of invalid seed set by user
1112 #ifndef IS_MPI
1113 seedValue = make_sprng_seed();
1114 #else
1115 if (worldRank == 0){
1116 seedValue = make_sprng_seed();
1117 }
1118 MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
1119 #endif
1120 }
1121 }//end of if branch of globals->haveSeed()
1122 else{
1123
1124 #ifndef IS_MPI
1125 seedValue = make_sprng_seed();
1126 #else
1127 if (worldRank == 0){
1128 seedValue = make_sprng_seed();
1129 }
1130 MPI_Bcast(&seedValue, 1, MPI_INT, 0, MPI_COMM_WORLD);
1131 #endif
1132 }//end of globals->haveSeed()
1133
1134 for (int i = 0; i < nInfo; i++){
1135 info[i].setSeed(seedValue);
1136 }
1137
1138 #ifdef IS_MPI
1139 strcpy(checkPointMsg, "Successfully gathered all information from Bass\n");
1140 MPIcheckPoint();
1141 #endif // is_mpi
1142 }
1143
1144
1145 void SimSetup::finalInfoCheck(void){
1146 int index;
1147 int usesDipoles;
1148 int usesCharges;
1149 int i;
1150
1151 for (i = 0; i < nInfo; i++){
1152 // check electrostatic parameters
1153
1154 index = 0;
1155 usesDipoles = 0;
1156 while ((index < info[i].n_atoms) && !usesDipoles){
1157 usesDipoles = (info[i].atoms[index])->hasDipole();
1158 index++;
1159 }
1160 index = 0;
1161 usesCharges = 0;
1162 while ((index < info[i].n_atoms) && !usesCharges){
1163 usesCharges= (info[i].atoms[index])->hasCharge();
1164 index++;
1165 }
1166 #ifdef IS_MPI
1167 int myUse = usesDipoles;
1168 MPI_Allreduce(&myUse, &usesDipoles, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
1169 #endif //is_mpi
1170
1171 double theRcut, theRsw;
1172
1173 if (globals->haveRcut()) {
1174 theRcut = globals->getRcut();
1175
1176 if (globals->haveRsw())
1177 theRsw = globals->getRsw();
1178 else
1179 theRsw = theRcut;
1180
1181 info[i].setDefaultRcut(theRcut, theRsw);
1182
1183 } else {
1184
1185 the_ff->calcRcut();
1186 theRcut = info[i].getRcut();
1187
1188 if (globals->haveRsw())
1189 theRsw = globals->getRsw();
1190 else
1191 theRsw = theRcut;
1192
1193 info[i].setDefaultRcut(theRcut, theRsw);
1194 }
1195
1196 if (globals->getUseRF()){
1197 info[i].useReactionField = 1;
1198
1199 if (!globals->haveRcut()){
1200 sprintf(painCave.errMsg,
1201 "SimSetup Warning: No value was set for the cutoffRadius.\n"
1202 "\tOOPSE will use a default value of 15.0 angstroms"
1203 "\tfor the cutoffRadius.\n");
1204 painCave.isFatal = 0;
1205 simError();
1206 theRcut = 15.0;
1207 }
1208 else{
1209 theRcut = globals->getRcut();
1210 }
1211
1212 if (!globals->haveRsw()){
1213 sprintf(painCave.errMsg,
1214 "SimSetup Warning: No value was set for switchingRadius.\n"
1215 "\tOOPSE will use a default value of\n"
1216 "\t0.95 * cutoffRadius for the switchingRadius\n");
1217 painCave.isFatal = 0;
1218 simError();
1219 theRsw = 0.95 * theRcut;
1220 }
1221 else{
1222 theRsw = globals->getRsw();
1223 }
1224
1225 info[i].setDefaultRcut(theRcut, theRsw);
1226
1227 if (!globals->haveDielectric()){
1228 sprintf(painCave.errMsg,
1229 "SimSetup Error: No Dielectric constant was set.\n"
1230 "\tYou are trying to use Reaction Field without"
1231 "\tsetting a dielectric constant!\n");
1232 painCave.isFatal = 1;
1233 simError();
1234 }
1235 info[i].dielectric = globals->getDielectric();
1236 }
1237 else{
1238 if (usesDipoles || usesCharges){
1239
1240 if (!globals->haveRcut()){
1241 sprintf(painCave.errMsg,
1242 "SimSetup Warning: No value was set for the cutoffRadius.\n"
1243 "\tOOPSE will use a default value of 15.0 angstroms"
1244 "\tfor the cutoffRadius.\n");
1245 painCave.isFatal = 0;
1246 simError();
1247 theRcut = 15.0;
1248 }
1249 else{
1250 theRcut = globals->getRcut();
1251 }
1252
1253 if (!globals->haveRsw()){
1254 sprintf(painCave.errMsg,
1255 "SimSetup Warning: No value was set for switchingRadius.\n"
1256 "\tOOPSE will use a default value of\n"
1257 "\t0.95 * cutoffRadius for the switchingRadius\n");
1258 painCave.isFatal = 0;
1259 simError();
1260 theRsw = 0.95 * theRcut;
1261 }
1262 else{
1263 theRsw = globals->getRsw();
1264 }
1265
1266 info[i].setDefaultRcut(theRcut, theRsw);
1267
1268 }
1269 }
1270 }
1271 #ifdef IS_MPI
1272 strcpy(checkPointMsg, "post processing checks out");
1273 MPIcheckPoint();
1274 #endif // is_mpi
1275
1276 // clean up the forcefield
1277 the_ff->cleanMe();
1278 }
1279
1280 void SimSetup::initSystemCoords(void){
1281 int i;
1282
1283 char* inName;
1284
1285 (info[0].getConfiguration())->createArrays(info[0].n_atoms);
1286
1287 for (i = 0; i < info[0].n_atoms; i++)
1288 info[0].atoms[i]->setCoords();
1289
1290 if (globals->haveInitialConfig()){
1291 InitializeFromFile* fileInit;
1292 #ifdef IS_MPI // is_mpi
1293 if (worldRank == 0){
1294 #endif //is_mpi
1295 inName = globals->getInitialConfig();
1296 fileInit = new InitializeFromFile(inName);
1297 #ifdef IS_MPI
1298 }
1299 else
1300 fileInit = new InitializeFromFile(NULL);
1301 #endif
1302 fileInit->readInit(info); // default velocities on
1303
1304 delete fileInit;
1305 }
1306 else{
1307
1308 // no init from md file
1309
1310 sprintf(painCave.errMsg,
1311 "Cannot intialize a simulation without an initial configuration file.\n");
1312 painCave.isFatal = 1;;
1313 simError();
1314
1315 }
1316
1317 #ifdef IS_MPI
1318 strcpy(checkPointMsg, "Successfully read in the initial configuration");
1319 MPIcheckPoint();
1320 #endif // is_mpi
1321 }
1322
1323
1324 void SimSetup::makeOutNames(void){
1325 int k;
1326 string prefix;
1327
1328 for (k = 0; k < nInfo; k++){
1329 #ifdef IS_MPI
1330 if (worldRank == 0){
1331 #endif // is_mpi
1332
1333 if(globals->haveFinalConfig())
1334 prefix = getPrefix(globals->getFinalConfig());
1335 else
1336 prefix = getPrefix(info[k].finalName);
1337
1338 info[k].finalName = prefix + ".eor";
1339 info[k].sampleName = prefix + ".dump";
1340 info[k].statusName = prefix + ".stat";
1341
1342 #ifdef IS_MPI
1343
1344 }
1345 #endif // is_mpi
1346 }
1347 }
1348
1349
1350 void SimSetup::sysObjectsCreation(void){
1351 int i, k;
1352
1353 // create the forceField
1354
1355 createFF();
1356
1357 // extract componentList
1358
1359 compList();
1360
1361 // calc the number of atoms, bond, bends, and torsions
1362
1363 calcSysValues();
1364
1365 #ifdef IS_MPI
1366 // divide the molecules among the processors
1367
1368 mpiMolDivide();
1369 #endif //is_mpi
1370
1371 // create the atom and SRI arrays. Also initialize Molecule Stamp ID's
1372
1373 makeSysArrays();
1374
1375 // make and initialize the molecules (all but atomic coordinates)
1376
1377 makeMolecules();
1378
1379 for (k = 0; k < nInfo; k++){
1380 info[k].identArray = new int[info[k].n_atoms];
1381 for (i = 0; i < info[k].n_atoms; i++){
1382 info[k].identArray[i] = info[k].atoms[i]->getIdent();
1383 }
1384 }
1385 }
1386
1387
1388 void SimSetup::createFF(void){
1389 switch (ffCase){
1390 case FF_DUFF:
1391 the_ff = new DUFF();
1392 break;
1393
1394 case FF_LJ:
1395 the_ff = new LJFF();
1396 break;
1397
1398 case FF_EAM:
1399 if (has_forcefield_variant)
1400 the_ff = new EAM_FF(forcefield_variant);
1401 else
1402 the_ff = new EAM_FF();
1403 break;
1404
1405 case FF_H2O:
1406 the_ff = new WATER();
1407 break;
1408
1409 default:
1410 sprintf(painCave.errMsg,
1411 "SimSetup Error. Unrecognized force field in case statement.\n");
1412 painCave.isFatal = 1;
1413 simError();
1414 }
1415
1416
1417 #ifdef IS_MPI
1418 strcpy(checkPointMsg, "ForceField creation successful");
1419 MPIcheckPoint();
1420 #endif // is_mpi
1421 }
1422
1423
1424 void SimSetup::compList(void){
1425 int i;
1426 char* id;
1427 LinkedMolStamp* headStamp = new LinkedMolStamp();
1428 LinkedMolStamp* currentStamp = NULL;
1429 comp_stamps = new MoleculeStamp * [n_components];
1430 bool haveCutoffGroups;
1431
1432 haveCutoffGroups = false;
1433
1434 // make an array of molecule stamps that match the components used.
1435 // also extract the used stamps out into a separate linked list
1436
1437 for (i = 0; i < nInfo; i++){
1438 info[i].nComponents = n_components;
1439 info[i].componentsNmol = components_nmol;
1440 info[i].compStamps = comp_stamps;
1441 info[i].headStamp = headStamp;
1442 }
1443
1444
1445 for (i = 0; i < n_components; i++){
1446 id = the_components[i]->getType();
1447 comp_stamps[i] = NULL;
1448
1449 // check to make sure the component isn't already in the list
1450
1451 comp_stamps[i] = headStamp->match(id);
1452 if (comp_stamps[i] == NULL){
1453 // extract the component from the list;
1454
1455 currentStamp = stamps->extractMolStamp(id);
1456 if (currentStamp == NULL){
1457 sprintf(painCave.errMsg,
1458 "SimSetup error: Component \"%s\" was not found in the "
1459 "list of declared molecules\n",
1460 id);
1461 painCave.isFatal = 1;
1462 simError();
1463 }
1464
1465 headStamp->add(currentStamp);
1466 comp_stamps[i] = headStamp->match(id);
1467 }
1468
1469 if(comp_stamps[i]->getNCutoffGroups() > 0)
1470 haveCutoffGroups = true;
1471 }
1472
1473 for (i = 0; i < nInfo; i++)
1474 info[i].haveCutoffGroups = haveCutoffGroups;
1475
1476 #ifdef IS_MPI
1477 strcpy(checkPointMsg, "Component stamps successfully extracted\n");
1478 MPIcheckPoint();
1479 #endif // is_mpi
1480 }
1481
1482 void SimSetup::calcSysValues(void){
1483 int i, j;
1484 int ncutgroups, atomsingroups, ngroupsinstamp;
1485
1486 int* molMembershipArray;
1487 CutoffGroupStamp* cg;
1488
1489 tot_atoms = 0;
1490 tot_bonds = 0;
1491 tot_bends = 0;
1492 tot_torsions = 0;
1493 tot_rigid = 0;
1494 tot_groups = 0;
1495 for (i = 0; i < n_components; i++){
1496 tot_atoms += components_nmol[i] * comp_stamps[i]->getNAtoms();
1497 tot_bonds += components_nmol[i] * comp_stamps[i]->getNBonds();
1498 tot_bends += components_nmol[i] * comp_stamps[i]->getNBends();
1499 tot_torsions += components_nmol[i] * comp_stamps[i]->getNTorsions();
1500 tot_rigid += components_nmol[i] * comp_stamps[i]->getNRigidBodies();
1501
1502 ncutgroups = comp_stamps[i]->getNCutoffGroups();
1503 atomsingroups = 0;
1504 for (j=0; j < ncutgroups; j++) {
1505 cg = comp_stamps[i]->getCutoffGroup(j);
1506 atomsingroups += cg->getNMembers();
1507 }
1508 ngroupsinstamp = comp_stamps[i]->getNAtoms() - atomsingroups + ncutgroups;
1509 tot_groups += components_nmol[i] * ngroupsinstamp;
1510 }
1511
1512 tot_SRI = tot_bonds + tot_bends + tot_torsions;
1513 molMembershipArray = new int[tot_atoms];
1514
1515 for (i = 0; i < nInfo; i++){
1516 info[i].n_atoms = tot_atoms;
1517 info[i].n_bonds = tot_bonds;
1518 info[i].n_bends = tot_bends;
1519 info[i].n_torsions = tot_torsions;
1520 info[i].n_SRI = tot_SRI;
1521 info[i].n_mol = tot_nmol;
1522 info[i].ngroup = tot_groups;
1523 info[i].molMembershipArray = molMembershipArray;
1524 }
1525 }
1526
1527 #ifdef IS_MPI
1528
1529 void SimSetup::mpiMolDivide(void){
1530 int i, j, k;
1531 int localMol, allMol;
1532 int local_atoms, local_bonds, local_bends, local_torsions, local_SRI;
1533 int local_rigid, local_groups;
1534 vector<int> globalMolIndex;
1535 int ncutgroups, atomsingroups, ngroupsinstamp;
1536 CutoffGroupStamp* cg;
1537
1538 mpiSim = new mpiSimulation(info);
1539
1540 mpiSim->divideLabor();
1541 globalAtomIndex = mpiSim->getGlobalAtomIndex();
1542 globalGroupIndex = mpiSim->getGlobalGroupIndex();
1543 //globalMolIndex = mpiSim->getGlobalMolIndex();
1544
1545 // set up the local variables
1546
1547 mol2proc = mpiSim->getMolToProcMap();
1548 molCompType = mpiSim->getMolComponentType();
1549
1550 allMol = 0;
1551 localMol = 0;
1552 local_atoms = 0;
1553 local_bonds = 0;
1554 local_bends = 0;
1555 local_torsions = 0;
1556 local_rigid = 0;
1557 local_groups = 0;
1558 globalAtomCounter = 0;
1559
1560 for (i = 0; i < n_components; i++){
1561 for (j = 0; j < components_nmol[i]; j++){
1562 if (mol2proc[allMol] == worldRank){
1563 local_atoms += comp_stamps[i]->getNAtoms();
1564 local_bonds += comp_stamps[i]->getNBonds();
1565 local_bends += comp_stamps[i]->getNBends();
1566 local_torsions += comp_stamps[i]->getNTorsions();
1567 local_rigid += comp_stamps[i]->getNRigidBodies();
1568
1569 ncutgroups = comp_stamps[i]->getNCutoffGroups();
1570 atomsingroups = 0;
1571 for (k=0; k < ncutgroups; k++) {
1572 cg = comp_stamps[i]->getCutoffGroup(k);
1573 atomsingroups += cg->getNMembers();
1574 }
1575 ngroupsinstamp = comp_stamps[i]->getNAtoms() - atomsingroups +
1576 ncutgroups;
1577 local_groups += ngroupsinstamp;
1578
1579 localMol++;
1580 }
1581 for (k = 0; k < comp_stamps[i]->getNAtoms(); k++){
1582 info[0].molMembershipArray[globalAtomCounter] = allMol;
1583 globalAtomCounter++;
1584 }
1585
1586 allMol++;
1587 }
1588 }
1589 local_SRI = local_bonds + local_bends + local_torsions;
1590
1591 info[0].n_atoms = mpiSim->getNAtomsLocal();
1592
1593 if (local_atoms != info[0].n_atoms){
1594 sprintf(painCave.errMsg,
1595 "SimSetup error: mpiSim's localAtom (%d) and SimSetup's\n"
1596 "\tlocalAtom (%d) are not equal.\n",
1597 info[0].n_atoms, local_atoms);
1598 painCave.isFatal = 1;
1599 simError();
1600 }
1601
1602 info[0].ngroup = mpiSim->getNGroupsLocal();
1603 if (local_groups != info[0].ngroup){
1604 sprintf(painCave.errMsg,
1605 "SimSetup error: mpiSim's localGroups (%d) and SimSetup's\n"
1606 "\tlocalGroups (%d) are not equal.\n",
1607 info[0].ngroup, local_groups);
1608 painCave.isFatal = 1;
1609 simError();
1610 }
1611
1612 info[0].n_bonds = local_bonds;
1613 info[0].n_bends = local_bends;
1614 info[0].n_torsions = local_torsions;
1615 info[0].n_SRI = local_SRI;
1616 info[0].n_mol = localMol;
1617
1618 strcpy(checkPointMsg, "Passed nlocal consistency check.");
1619 MPIcheckPoint();
1620 }
1621
1622 #endif // is_mpi
1623
1624
1625 void SimSetup::makeSysArrays(void){
1626
1627 #ifndef IS_MPI
1628 int k, j;
1629 #endif // is_mpi
1630 int i, l;
1631
1632 Atom** the_atoms;
1633 Molecule* the_molecules;
1634
1635 for (l = 0; l < nInfo; l++){
1636 // create the atom and short range interaction arrays
1637
1638 the_atoms = new Atom * [info[l].n_atoms];
1639 the_molecules = new Molecule[info[l].n_mol];
1640 int molIndex;
1641
1642 // initialize the molecule's stampID's
1643
1644 #ifdef IS_MPI
1645
1646
1647 molIndex = 0;
1648 for (i = 0; i < mpiSim->getNMolGlobal(); i++){
1649 if (mol2proc[i] == worldRank){
1650 the_molecules[molIndex].setStampID(molCompType[i]);
1651 the_molecules[molIndex].setMyIndex(molIndex);
1652 the_molecules[molIndex].setGlobalIndex(i);
1653 molIndex++;
1654 }
1655 }
1656
1657 #else // is_mpi
1658
1659 molIndex = 0;
1660 globalAtomCounter = 0;
1661 for (i = 0; i < n_components; i++){
1662 for (j = 0; j < components_nmol[i]; j++){
1663 the_molecules[molIndex].setStampID(i);
1664 the_molecules[molIndex].setMyIndex(molIndex);
1665 the_molecules[molIndex].setGlobalIndex(molIndex);
1666 for (k = 0; k < comp_stamps[i]->getNAtoms(); k++){
1667 info[l].molMembershipArray[globalAtomCounter] = molIndex;
1668 globalAtomCounter++;
1669 }
1670 molIndex++;
1671 }
1672 }
1673
1674
1675 #endif // is_mpi
1676
1677 info[l].globalExcludes = new int;
1678 info[l].globalExcludes[0] = 0;
1679
1680 // set the arrays into the SimInfo object
1681
1682 info[l].atoms = the_atoms;
1683 info[l].molecules = the_molecules;
1684 info[l].nGlobalExcludes = 0;
1685
1686 the_ff->setSimInfo(info);
1687 }
1688 }
1689
1690 void SimSetup::makeIntegrator(void){
1691 int k;
1692
1693 NVE<Integrator<BaseIntegrator> >* myNVE = NULL;
1694 NVT<Integrator<BaseIntegrator> >* myNVT = NULL;
1695 NPTi<NPT<Integrator<BaseIntegrator> > >* myNPTi = NULL;
1696 NPTf<NPT<Integrator<BaseIntegrator> > >* myNPTf = NULL;
1697 NPTxyz<NPT<Integrator<BaseIntegrator> > >* myNPTxyz = NULL;
1698
1699 for (k = 0; k < nInfo; k++){
1700 switch (ensembleCase){
1701 case NVE_ENS:
1702 if (globals->haveZconstraints()){
1703 setupZConstraint(info[k]);
1704 myNVE = new ZConstraint<NVE<RealIntegrator> >(&(info[k]), the_ff);
1705 }
1706 else{
1707 myNVE = new NVE<RealIntegrator>(&(info[k]), the_ff);
1708 }
1709
1710 info->the_integrator = myNVE;
1711 break;
1712
1713 case NVT_ENS:
1714 if (globals->haveZconstraints()){
1715 setupZConstraint(info[k]);
1716 myNVT = new ZConstraint<NVT<RealIntegrator> >(&(info[k]), the_ff);
1717 }
1718 else
1719 myNVT = new NVT<RealIntegrator>(&(info[k]), the_ff);
1720
1721
1722 if (globals->haveTargetTemp())
1723 myNVT->setTargetTemp(globals->getTargetTemp());
1724 else{
1725 sprintf(painCave.errMsg,
1726 "SimSetup error: If you use the NVT\n"
1727 "\tensemble, you must set targetTemp.\n");
1728 painCave.isFatal = 1;
1729 simError();
1730 }
1731
1732 if (globals->haveTauThermostat())
1733 myNVT->setTauThermostat(globals->getTauThermostat());
1734 else{
1735 sprintf(painCave.errMsg,
1736 "SimSetup error: If you use the NVT\n"
1737 "\tensemble, you must set tauThermostat.\n");
1738 painCave.isFatal = 1;
1739 simError();
1740 }
1741
1742 info->the_integrator = myNVT;
1743 break;
1744
1745 case NPTi_ENS:
1746 if (globals->haveZconstraints()){
1747 setupZConstraint(info[k]);
1748 myNPTi = new ZConstraint<NPTi<NPT <RealIntegrator> > >(&(info[k]), the_ff);
1749 }
1750 else
1751 myNPTi = new NPTi<NPT<RealIntegrator> >(&(info[k]), the_ff);
1752
1753 if (globals->haveTargetTemp())
1754 myNPTi->setTargetTemp(globals->getTargetTemp());
1755 else{
1756 sprintf(painCave.errMsg,
1757 "SimSetup error: If you use a constant pressure\n"
1758 "\tensemble, you must set targetTemp.\n");
1759 painCave.isFatal = 1;
1760 simError();
1761 }
1762
1763 if (globals->haveTargetPressure())
1764 myNPTi->setTargetPressure(globals->getTargetPressure());
1765 else{
1766 sprintf(painCave.errMsg,
1767 "SimSetup error: If you use a constant pressure\n"
1768 "\tensemble, you must set targetPressure in the BASS file.\n");
1769 painCave.isFatal = 1;
1770 simError();
1771 }
1772
1773 if (globals->haveTauThermostat())
1774 myNPTi->setTauThermostat(globals->getTauThermostat());
1775 else{
1776 sprintf(painCave.errMsg,
1777 "SimSetup error: If you use an NPT\n"
1778 "\tensemble, you must set tauThermostat.\n");
1779 painCave.isFatal = 1;
1780 simError();
1781 }
1782
1783 if (globals->haveTauBarostat())
1784 myNPTi->setTauBarostat(globals->getTauBarostat());
1785 else{
1786 sprintf(painCave.errMsg,
1787 "SimSetup error: If you use an NPT\n"
1788 "\tensemble, you must set tauBarostat.\n");
1789 painCave.isFatal = 1;
1790 simError();
1791 }
1792
1793 info->the_integrator = myNPTi;
1794 break;
1795
1796 case NPTf_ENS:
1797 if (globals->haveZconstraints()){
1798 setupZConstraint(info[k]);
1799 myNPTf = new ZConstraint<NPTf<NPT <RealIntegrator> > >(&(info[k]), the_ff);
1800 }
1801 else
1802 myNPTf = new NPTf<NPT <RealIntegrator> >(&(info[k]), the_ff);
1803
1804 if (globals->haveTargetTemp())
1805 myNPTf->setTargetTemp(globals->getTargetTemp());
1806 else{
1807 sprintf(painCave.errMsg,
1808 "SimSetup error: If you use a constant pressure\n"
1809 "\tensemble, you must set targetTemp.\n");
1810 painCave.isFatal = 1;
1811 simError();
1812 }
1813
1814 if (globals->haveTargetPressure())
1815 myNPTf->setTargetPressure(globals->getTargetPressure());
1816 else{
1817 sprintf(painCave.errMsg,
1818 "SimSetup error: If you use a constant pressure\n"
1819 "\tensemble, you must set targetPressure in the BASS file.\n");
1820 painCave.isFatal = 1;
1821 simError();
1822 }
1823
1824 if (globals->haveTauThermostat())
1825 myNPTf->setTauThermostat(globals->getTauThermostat());
1826
1827 else{
1828 sprintf(painCave.errMsg,
1829 "SimSetup error: If you use an NPT\n"
1830 "\tensemble, you must set tauThermostat.\n");
1831 painCave.isFatal = 1;
1832 simError();
1833 }
1834
1835 if (globals->haveTauBarostat())
1836 myNPTf->setTauBarostat(globals->getTauBarostat());
1837
1838 else{
1839 sprintf(painCave.errMsg,
1840 "SimSetup error: If you use an NPT\n"
1841 "\tensemble, you must set tauBarostat.\n");
1842 painCave.isFatal = 1;
1843 simError();
1844 }
1845
1846 info->the_integrator = myNPTf;
1847 break;
1848
1849 case NPTxyz_ENS:
1850 if (globals->haveZconstraints()){
1851 setupZConstraint(info[k]);
1852 myNPTxyz = new ZConstraint<NPTxyz<NPT <RealIntegrator> > >(&(info[k]), the_ff);
1853 }
1854 else
1855 myNPTxyz = new NPTxyz<NPT <RealIntegrator> >(&(info[k]), the_ff);
1856
1857 if (globals->haveTargetTemp())
1858 myNPTxyz->setTargetTemp(globals->getTargetTemp());
1859 else{
1860 sprintf(painCave.errMsg,
1861 "SimSetup error: If you use a constant pressure\n"
1862 "\tensemble, you must set targetTemp.\n");
1863 painCave.isFatal = 1;
1864 simError();
1865 }
1866
1867 if (globals->haveTargetPressure())
1868 myNPTxyz->setTargetPressure(globals->getTargetPressure());
1869 else{
1870 sprintf(painCave.errMsg,
1871 "SimSetup error: If you use a constant pressure\n"
1872 "\tensemble, you must set targetPressure in the BASS file.\n");
1873 painCave.isFatal = 1;
1874 simError();
1875 }
1876
1877 if (globals->haveTauThermostat())
1878 myNPTxyz->setTauThermostat(globals->getTauThermostat());
1879 else{
1880 sprintf(painCave.errMsg,
1881 "SimSetup error: If you use an NPT\n"
1882 "\tensemble, you must set tauThermostat.\n");
1883 painCave.isFatal = 1;
1884 simError();
1885 }
1886
1887 if (globals->haveTauBarostat())
1888 myNPTxyz->setTauBarostat(globals->getTauBarostat());
1889 else{
1890 sprintf(painCave.errMsg,
1891 "SimSetup error: If you use an NPT\n"
1892 "\tensemble, you must set tauBarostat.\n");
1893 painCave.isFatal = 1;
1894 simError();
1895 }
1896
1897 info->the_integrator = myNPTxyz;
1898 break;
1899
1900 default:
1901 sprintf(painCave.errMsg,
1902 "SimSetup Error. Unrecognized ensemble in case statement.\n");
1903 painCave.isFatal = 1;
1904 simError();
1905 }
1906 }
1907 }
1908
1909 void SimSetup::initFortran(void){
1910 info[0].refreshSim();
1911
1912 if (!strcmp(info[0].mixingRule, "standard")){
1913 the_ff->initForceField(LB_MIXING_RULE);
1914 }
1915 else if (!strcmp(info[0].mixingRule, "explicit")){
1916 the_ff->initForceField(EXPLICIT_MIXING_RULE);
1917 }
1918 else{
1919 sprintf(painCave.errMsg, "SimSetup Error: unknown mixing rule -> \"%s\"\n",
1920 info[0].mixingRule);
1921 painCave.isFatal = 1;
1922 simError();
1923 }
1924
1925
1926 #ifdef IS_MPI
1927 strcpy(checkPointMsg, "Successfully intialized the mixingRule for Fortran.");
1928 MPIcheckPoint();
1929 #endif // is_mpi
1930 }
1931
1932 void SimSetup::setupZConstraint(SimInfo& theInfo){
1933 int nZConstraints;
1934 ZconStamp** zconStamp;
1935
1936 if (globals->haveZconstraintTime()){
1937 //add sample time of z-constraint into SimInfo's property list
1938 DoubleData* zconsTimeProp = new DoubleData();
1939 zconsTimeProp->setID(ZCONSTIME_ID);
1940 zconsTimeProp->setData(globals->getZconsTime());
1941 theInfo.addProperty(zconsTimeProp);
1942 }
1943 else{
1944 sprintf(painCave.errMsg,
1945 "ZConstraint error: If you use a ZConstraint,\n"
1946 "\tyou must set zconsTime.\n");
1947 painCave.isFatal = 1;
1948 simError();
1949 }
1950
1951 //push zconsTol into siminfo, if user does not specify
1952 //value for zconsTol, a default value will be used
1953 DoubleData* zconsTol = new DoubleData();
1954 zconsTol->setID(ZCONSTOL_ID);
1955 if (globals->haveZconsTol()){
1956 zconsTol->setData(globals->getZconsTol());
1957 }
1958 else{
1959 double defaultZConsTol = 0.01;
1960 sprintf(painCave.errMsg,
1961 "ZConstraint Warning: Tolerance for z-constraint method is not specified.\n"
1962 "\tOOPSE will use a default value of %f.\n"
1963 "\tTo set the tolerance, use the zconsTol variable.\n",
1964 defaultZConsTol);
1965 painCave.isFatal = 0;
1966 simError();
1967
1968 zconsTol->setData(defaultZConsTol);
1969 }
1970 theInfo.addProperty(zconsTol);
1971
1972 //set Force Subtraction Policy
1973 StringData* zconsForcePolicy = new StringData();
1974 zconsForcePolicy->setID(ZCONSFORCEPOLICY_ID);
1975
1976 if (globals->haveZconsForcePolicy()){
1977 zconsForcePolicy->setData(globals->getZconsForcePolicy());
1978 }
1979 else{
1980 sprintf(painCave.errMsg,
1981 "ZConstraint Warning: No force subtraction policy was set.\n"
1982 "\tOOPSE will use PolicyByMass.\n"
1983 "\tTo set the policy, use the zconsForcePolicy variable.\n");
1984 painCave.isFatal = 0;
1985 simError();
1986 zconsForcePolicy->setData("BYMASS");
1987 }
1988
1989 theInfo.addProperty(zconsForcePolicy);
1990
1991 //set zcons gap
1992 DoubleData* zconsGap = new DoubleData();
1993 zconsGap->setID(ZCONSGAP_ID);
1994
1995 if (globals->haveZConsGap()){
1996 zconsGap->setData(globals->getZconsGap());
1997 theInfo.addProperty(zconsGap);
1998 }
1999
2000 //set zcons fixtime
2001 DoubleData* zconsFixtime = new DoubleData();
2002 zconsFixtime->setID(ZCONSFIXTIME_ID);
2003
2004 if (globals->haveZConsFixTime()){
2005 zconsFixtime->setData(globals->getZconsFixtime());
2006 theInfo.addProperty(zconsFixtime);
2007 }
2008
2009 //set zconsUsingSMD
2010 IntData* zconsUsingSMD = new IntData();
2011 zconsUsingSMD->setID(ZCONSUSINGSMD_ID);
2012
2013 if (globals->haveZConsUsingSMD()){
2014 zconsUsingSMD->setData(globals->getZconsUsingSMD());
2015 theInfo.addProperty(zconsUsingSMD);
2016 }
2017
2018 //Determine the name of ouput file and add it into SimInfo's property list
2019 //Be careful, do not use inFileName, since it is a pointer which
2020 //point to a string at master node, and slave nodes do not contain that string
2021
2022 string zconsOutput(theInfo.finalName);
2023
2024 zconsOutput = zconsOutput.substr(0, zconsOutput.rfind(".")) + ".fz";
2025
2026 StringData* zconsFilename = new StringData();
2027 zconsFilename->setID(ZCONSFILENAME_ID);
2028 zconsFilename->setData(zconsOutput);
2029
2030 theInfo.addProperty(zconsFilename);
2031
2032 //setup index, pos and other parameters of z-constraint molecules
2033 nZConstraints = globals->getNzConstraints();
2034 theInfo.nZconstraints = nZConstraints;
2035
2036 zconStamp = globals->getZconStamp();
2037 ZConsParaItem tempParaItem;
2038
2039 ZConsParaData* zconsParaData = new ZConsParaData();
2040 zconsParaData->setID(ZCONSPARADATA_ID);
2041
2042 for (int i = 0; i < nZConstraints; i++){
2043 tempParaItem.havingZPos = zconStamp[i]->haveZpos();
2044 tempParaItem.zPos = zconStamp[i]->getZpos();
2045 tempParaItem.zconsIndex = zconStamp[i]->getMolIndex();
2046 tempParaItem.kRatio = zconStamp[i]->getKratio();
2047 tempParaItem.havingCantVel = zconStamp[i]->haveCantVel();
2048 tempParaItem.cantVel = zconStamp[i]->getCantVel();
2049 zconsParaData->addItem(tempParaItem);
2050 }
2051
2052 //check the uniqueness of index
2053 if(!zconsParaData->isIndexUnique()){
2054 sprintf(painCave.errMsg,
2055 "ZConstraint Error: molIndex is not unique!\n");
2056 painCave.isFatal = 1;
2057 simError();
2058 }
2059
2060 //sort the parameters by index of molecules
2061 zconsParaData->sortByIndex();
2062
2063 //push data into siminfo, therefore, we can retrieve later
2064 theInfo.addProperty(zconsParaData);
2065 }
2066
2067 void SimSetup::makeMinimizer(){
2068
2069 OOPSEMinimizer* myOOPSEMinimizer;
2070 MinimizerParameterSet* param;
2071 char minimizerName[100];
2072
2073 for (int i = 0; i < nInfo; i++){
2074
2075 //prepare parameter set for minimizer
2076 param = new MinimizerParameterSet();
2077 param->setDefaultParameter();
2078
2079 if (globals->haveMinimizer()){
2080 param->setFTol(globals->getMinFTol());
2081 }
2082
2083 if (globals->haveMinGTol()){
2084 param->setGTol(globals->getMinGTol());
2085 }
2086
2087 if (globals->haveMinMaxIter()){
2088 param->setMaxIteration(globals->getMinMaxIter());
2089 }
2090
2091 if (globals->haveMinWriteFrq()){
2092 param->setMaxIteration(globals->getMinMaxIter());
2093 }
2094
2095 if (globals->haveMinWriteFrq()){
2096 param->setWriteFrq(globals->getMinWriteFrq());
2097 }
2098
2099 if (globals->haveMinStepSize()){
2100 param->setStepSize(globals->getMinStepSize());
2101 }
2102
2103 if (globals->haveMinLSMaxIter()){
2104 param->setLineSearchMaxIteration(globals->getMinLSMaxIter());
2105 }
2106
2107 if (globals->haveMinLSTol()){
2108 param->setLineSearchTol(globals->getMinLSTol());
2109 }
2110
2111 strcpy(minimizerName, globals->getMinimizer());
2112
2113 if (!strcasecmp(minimizerName, "CG")){
2114 myOOPSEMinimizer = new PRCGMinimizer(&(info[i]), the_ff, param);
2115 }
2116 else if (!strcasecmp(minimizerName, "SD")){
2117 //myOOPSEMinimizer = MinimizerFactory.creatMinimizer("", &(info[i]), the_ff, param);
2118 myOOPSEMinimizer = new SDMinimizer(&(info[i]), the_ff, param);
2119 }
2120 else{
2121 sprintf(painCave.errMsg,
2122 "SimSetup error: Unrecognized Minimizer, use Conjugate Gradient \n");
2123 painCave.isFatal = 0;
2124 simError();
2125
2126 myOOPSEMinimizer = new PRCGMinimizer(&(info[i]), the_ff, param);
2127 }
2128 info[i].the_integrator = myOOPSEMinimizer;
2129
2130 //store the minimizer into simInfo
2131 info[i].the_minimizer = myOOPSEMinimizer;
2132 info[i].has_minimizer = true;
2133 }
2134
2135 }