ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/io/RestReader.cpp
Revision: 2101
Committed: Thu Mar 10 15:10:24 2005 UTC (19 years, 4 months ago) by chrisfen
File size: 26064 byte(s)
Log Message:
First commit of the new restraints code

File Contents

# User Rev Content
1 chrisfen 2101 /*
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. Acknowledgement of the program authors must be made in any
10     * publication of scientific results based in part on use of the
11     * program. An acceptable form of acknowledgement is citation of
12     * the article in which the program was described (Matthew
13     * A. Meineke, Charles F. Vardeman II, Teng Lin, Christopher
14     * J. Fennell and J. Daniel Gezelter, "OOPSE: An Object-Oriented
15     * Parallel Simulation Engine for Molecular Dynamics,"
16     * J. Comput. Chem. 26, pp. 252-271 (2005))
17     *
18     * 2. Redistributions of source code must retain the above copyright
19     * notice, this list of conditions and the following disclaimer.
20     *
21     * 3. Redistributions in binary form must reproduce the above copyright
22     * notice, this list of conditions and the following disclaimer in the
23     * documentation and/or other materials provided with the
24     * distribution.
25     *
26     * This software is provided "AS IS," without a warranty of any
27     * kind. All express or implied conditions, representations and
28     * warranties, including any implied warranty of merchantability,
29     * fitness for a particular purpose or non-infringement, are hereby
30     * excluded. The University of Notre Dame and its licensors shall not
31     * be liable for any damages suffered by licensee as a result of
32     * using, modifying or distributing the software or its
33     * derivatives. In no event will the University of Notre Dame or its
34     * licensors be liable for any lost revenue, profit or data, or for
35     * direct, indirect, special, consequential, incidental or punitive
36     * damages, however caused and regardless of the theory of liability,
37     * arising out of the use of or inability to use software, even if the
38     * University of Notre Dame has been advised of the possibility of
39     * such damages.
40     */
41    
42     #define _LARGEFILE_SOURCE64
43     #define _FILE_OFFSET_BITS 64
44    
45     #include <sys/types.h>
46     #include <sys/stat.h>
47    
48     #include <iostream>
49     #include <math.h>
50    
51     #include <stdio.h>
52     #include <stdlib.h>
53     #include <string.h>
54    
55     #include "primitives/Molecule.hpp"
56     #include "utils/MemoryUtils.hpp"
57     #include "utils/StringTokenizer.hpp"
58     #include "io/RestReader.hpp"
59     #include "utils/simError.h"
60    
61     #ifdef IS_MPI
62     #include <mpi.h>
63     #include "brains/mpiSimulation.hpp"
64     #define TAKE_THIS_TAG_CHAR 0
65     #define TAKE_THIS_TAG_INT 1
66     #define TAKE_THIS_TAG_DOUBLE 2
67     #endif // is_mpi
68    
69     namespace oopse {
70    
71     RestReader::RestReader( SimInfo* info ) : info_(info){
72    
73     idealName = "idealCrystal.in";
74    
75     isScanned = false;
76    
77     #ifdef IS_MPI
78     if (worldRank == 0) {
79     #endif
80    
81     inIdealFile = fopen(idealName, "r");
82     if(inIdealFile == NULL){
83     sprintf(painCave.errMsg,
84     "RestReader: Cannot open file: %s\n", idealName);
85     painCave.isFatal = 1;
86     simError();
87     }
88    
89     inIdealFileName = idealName;
90     #ifdef IS_MPI
91     }
92     strcpy( checkPointMsg,
93     "File \"idealCrystal.in\" opened successfully for reading." );
94     MPIcheckPoint();
95     #endif
96     return;
97     }
98    
99     RestReader :: ~RestReader( ){
100     #ifdef IS_MPI
101     if (worldRank == 0) {
102     #endif
103     int error;
104     error = fclose( inIdealFile );
105    
106     if( error ){
107     sprintf( painCave.errMsg,
108     "Error closing %s\n", inIdealFileName.c_str());
109     simError();
110     }
111    
112     MemoryUtils::deletePointers(framePos);
113    
114     #ifdef IS_MPI
115     }
116     strcpy( checkPointMsg, "Restraint file closed successfully." );
117     MPIcheckPoint();
118     #endif
119    
120     return;
121     }
122    
123    
124     void RestReader :: readIdealCrystal(){
125    
126     int i;
127     unsigned int j;
128    
129     #ifdef IS_MPI
130     int done, which_node, which_atom; // loop counter
131     #endif //is_mpi
132    
133     const int BUFFERSIZE = 2000; // size of the read buffer
134     int nTotObjs; // the number of atoms
135     char read_buffer[BUFFERSIZE]; //the line buffer for reading
136    
137     char *eof_test; // ptr to see when we reach the end of the file
138     char *parseErr;
139    
140     std::vector<StuntDouble*> integrableObjects;
141    
142     Molecule* mol;
143     StuntDouble* integrableObject;
144     SimInfo::MoleculeIterator mi;
145     Molecule::IntegrableObjectIterator ii;
146    
147     #ifndef IS_MPI
148    
149     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
150     if( eof_test == NULL ){
151     sprintf( painCave.errMsg,
152     "RestraintReader error: error reading 1st line of \"%s\"\n",
153     inIdealFileName.c_str() );
154     painCave.isFatal = 1;
155     simError();
156     }
157    
158     nTotObjs = atoi( read_buffer );
159    
160     if( nTotObjs != info_->getNGlobalIntegrableObjects() ){
161     sprintf( painCave.errMsg,
162     "RestraintReader error. %s nIntegrable, %d, "
163     "does not match the meta-data file's nIntegrable, %d.\n",
164     inIdealFileName.c_str(), nTotObjs,
165     info_->getNGlobalIntegrableObjects());
166     painCave.isFatal = 1;
167     simError();
168     }
169    
170     // skip over the comment line
171     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
172     if(eof_test == NULL){
173     sprintf( painCave.errMsg,
174     "error in reading commment in %s\n", inIdealFileName.c_str());
175     painCave.isFatal = 1;
176     simError();
177     }
178    
179     // parse the ideal crystal lines
180     /*
181     * Note: we assume that there is a one-to-one correspondence between
182     * integrable objects and lines in the idealCrystal.in file. Thermodynamic
183     * integration is only supported for simple rigid bodies.
184     */
185     for (mol = info_->beginMolecule(mi); mol != NULL;
186     mol = info_->nextMolecule(mi)) {
187    
188     for (integrableObject = mol->beginIntegrableObject(ii);
189     integrableObject != NULL;
190     integrableObject = mol->nextIntegrableObject(ii)) {
191    
192     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
193     if(eof_test == NULL){
194     sprintf(painCave.errMsg,
195     "RestReader Error: error in reading file %s\n"
196     "natoms = %d; index = %d\n"
197     "error reading the line from the file.\n",
198     inIdealFileName.c_str(), nTotObjs,
199     integrableObject->getGlobalIndex() );
200     painCave.isFatal = 1;
201     simError();
202     }
203    
204     parseErr = parseIdealLine( read_buffer, integrableObject);
205     if( parseErr != NULL ){
206     strcpy( painCave.errMsg, parseErr );
207     painCave.isFatal = 1;
208     simError();
209     }
210     }
211     }
212    
213     // MPI Section of code..........
214     #else //IS_MPI
215    
216     // first thing first, suspend fatalities.
217     painCave.isEventLoop = 1;
218    
219     int masterNode = 0;
220     int myStatus; // 1 = wakeup & success; 0 = error; -1 = AllDone
221    
222     MPI_Status istatus;
223     int localIndex;
224     int nCurObj;
225     int nitems;
226    
227     nTotObjs = info_->getTotIntegrableObjects();
228     haveError = 0;
229    
230     if (worldRank == masterNode) {
231     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
232     if( eof_test == NULL ){
233     sprintf( painCave.errMsg,
234     "Error reading 1st line of %s \n ",inIdealFileName.c_str());
235     painCave.isFatal = 1;
236     simError();
237     }
238    
239     nitems = atoi( read_buffer );
240    
241     // Check to see that the number of integrable objects in the
242     // intial configuration file is the same as derived from the
243     // meta-data file.
244     if( nTotObjs != nitems){
245     sprintf( painCave.errMsg,
246     "RestraintReader Error. %s nIntegrable, %d, "
247     "does not match the meta-data file's nIntegrable, %d.\n",
248     inIdealFileName.c_str(), nTotObjs,
249     info_->getNGlobalIntegrableObjects());
250     painCave.isFatal = 1;
251     simError();
252     }
253    
254     // skip over the comment line
255     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
256     if(eof_test == NULL){
257     sprintf( painCave.errMsg,
258     "error in reading commment in %s\n", inIdealFileName.c_str());
259     painCave.isFatal = 1;
260     simError();
261     }
262    
263     for (i=0 ; i < info_->getNGlobalMolecules(); i++) {
264     int which_node = info_->getMolToProc(i);
265    
266     if(which_node == masterNode){
267     //molecules belong to master node
268    
269     localIndex = info_->getMoleculeByGlobalIndex(i);
270    
271     if(localIndex == NULL) {
272     strcpy(painCave.errMsg,
273     "RestReader Error: Molecule not found on node %d!",
274     worldRank);
275     painCave.isFatal = 1;
276     simError();
277     }
278    
279     for (integrableObject = mol->beginIntegrableObject(ii);
280     integrableObject != NULL;
281     integrableObject = mol->nextIntegrableObject(ii)){
282    
283     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
284    
285     if(eof_test == NULL){
286     sprintf(painCave.errMsg,
287     "RestReader Error: error in reading file %s\n"
288     "natoms = %d; index = %d\n"
289     "error reading the line from the file.\n",
290     inIdealFileName.c_str(), nTotObjs, i );
291     painCave.isFatal = 1;
292     simError();
293     }
294    
295     parseIdealLine(read_buffer, integrableObjects[j]);
296     }
297     } else {
298     //molecule belongs to slave nodes
299    
300     MPI_Recv(&nCurObj, 1, MPI_INT, which_node,
301     TAKE_THIS_TAG_INT, MPI_COMM_WORLD, &istatus);
302    
303     for(j=0; j < nCurObj; j++){
304    
305     eof_test = fgets(read_buffer, sizeof(read_buffer), inIdealFile);
306     if(eof_test == NULL){
307     sprintf(painCave.errMsg,
308     "RestReader Error: error in reading file %s\n"
309     "natoms = %d; index = %d\n"
310     "error reading the line from the file.\n",
311     inIdealFileName.c_str(), nTotObjs, i );
312     painCave.isFatal = 1;
313     simError();
314     }
315    
316     if(haveError) nodeZeroError();
317    
318     MPI_Send(read_buffer, BUFFERSIZE, MPI_CHAR, which_node,
319     TAKE_THIS_TAG_CHAR, MPI_COMM_WORLD);
320     }
321     }
322     }
323     } else {
324     //actions taken at slave nodes
325     for (i=0 ; i < info_->getNGlobalMolecules(); i++) {
326     int which_node = info_->getMolToProc(i);
327    
328     if(which_node == worldRank){
329     //molecule with global index i belongs to this processor
330    
331     localIndex = info_->getMoleculeByGlobalIndex(i);
332    
333     if(localIndex == NULL) {
334     sprintf(painCave.errMsg,
335     "RestReader Error: molecule not found on node %d\n",
336     worldRank);
337     painCave.isFatal = 1;
338     simError();
339     }
340    
341     nCurObj = localIndex->getNIntegrableObjects();
342    
343     MPI_Send(&nCurObj, 1, MPI_INT, masterNode,
344     TAKE_THIS_TAG_INT, MPI_COMM_WORLD);
345    
346     for (integrableObject = mol->beginIntegrableObject(ii);
347     integrableObject != NULL;
348     integrableObject = mol->nextIntegrableObject(ii)){
349    
350     MPI_Recv(read_buffer, BUFFERSIZE, MPI_CHAR, masterNode,
351     TAKE_THIS_TAG_CHAR, MPI_COMM_WORLD, &istatus);
352    
353     parseErr = parseIdealLine(read_buffer, integrableObject);
354    
355     if( parseErr != NULL ){
356     strcpy( painCave.errMsg, parseErr );
357     simError();
358     }
359     }
360     }
361     }
362     }
363     #endif
364     }
365    
366     char* RestReader::parseIdealLine(char* readLine, StuntDouble* sd){
367    
368     char *foo; // the pointer to the current string token
369    
370     double pos[3]; // position place holders
371     double q[4]; // the quaternions
372     double RfromQ[3][3]; // the rotation matrix
373     double normalize; // to normalize the reference unit vector
374     double uX, uY, uZ; // reference unit vector place holders
375     double uselessToken;
376     StringTokenizer tokenizer(readLine);
377     int nTokens;
378    
379     nTokens = tokenizer.countTokens();
380    
381     if (nTokens < 14) {
382     sprintf(painCave.errMsg,
383     "RestReader Error: Not enough Tokens.\n");
384     painCave.isFatal = 1;
385     simError();
386     }
387    
388     std::string name = tokenizer.nextToken();
389    
390     if (name != sd->getType()) {
391    
392     sprintf(painCave.errMsg,
393     "RestReader Error: Atom type [%s] in %s does not "
394     "match Atom Type [%s] in .md file.\n",
395     name.c_str(), inIdealFileName.c_str(),
396     sd->getType().c_str());
397     painCave.isFatal = 1;
398     simError();
399     }
400    
401     pos[0] = tokenizer.nextTokenAsDouble();
402     pos[1] = tokenizer.nextTokenAsDouble();
403     pos[2] = tokenizer.nextTokenAsDouble();
404    
405     // store the positions in the stuntdouble as generic data doubles
406     DoubleGenericData* refPosX = new DoubleGenericData();
407     refPosX->setID("refPosX");
408     refPosX->setData(pos[0]);
409     sd->addProperty(refPosX);
410    
411     DoubleGenericData* refPosY = new DoubleGenericData();
412     refPosY->setID("refPosY");
413     refPosY->setData(pos[1]);
414     sd->addProperty(refPosY);
415    
416     DoubleGenericData* refPosZ = new DoubleGenericData();
417     refPosZ->setID("refPosZ");
418     refPosZ->setData(pos[2]);
419     sd->addProperty(refPosZ);
420    
421     // we don't need the velocities
422     uselessToken = tokenizer.nextTokenAsDouble();
423     uselessToken = tokenizer.nextTokenAsDouble();
424     uselessToken = tokenizer.nextTokenAsDouble();
425    
426     if (sd->isDirectional()) {
427    
428     q[0] = tokenizer.nextTokenAsDouble();
429     q[1] = tokenizer.nextTokenAsDouble();
430     q[2] = tokenizer.nextTokenAsDouble();
431     q[3] = tokenizer.nextTokenAsDouble();
432    
433     // now build the rotation matrix and find the unit vectors
434     RfromQ[0][0] = q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3];
435     RfromQ[0][1] = 2*(q[1]*q[2] + q[0]*q[3]);
436     RfromQ[0][2] = 2*(q[1]*q[3] - q[0]*q[2]);
437     RfromQ[1][0] = 2*(q[1]*q[2] - q[0]*q[3]);
438     RfromQ[1][1] = q[0]*q[0] - q[1]*q[1] + q[2]*q[2] - q[3]*q[3];
439     RfromQ[1][2] = 2*(q[2]*q[3] + q[0]*q[1]);
440     RfromQ[2][0] = 2*(q[1]*q[3] + q[0]*q[2]);
441     RfromQ[2][1] = 2*(q[2]*q[3] - q[0]*q[1]);
442     RfromQ[2][2] = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
443    
444     normalize = sqrt(RfromQ[2][0]*RfromQ[2][0] + RfromQ[2][1]*RfromQ[2][1]
445     + RfromQ[2][2]*RfromQ[2][2]);
446     uX = RfromQ[2][0]/normalize;
447     uY = RfromQ[2][1]/normalize;
448     uZ = RfromQ[2][2]/normalize;
449    
450     // store reference unit vectors as generic data in the stuntdouble
451     DoubleGenericData* refVectorX = new DoubleGenericData();
452     refVectorX->setID("refVectorX");
453     refVectorX->setData(uX);
454     sd->addProperty(refVectorX);
455    
456     DoubleGenericData* refVectorY = new DoubleGenericData();
457     refVectorY->setID("refVectorY");
458     refVectorY->setData(uY);
459     sd->addProperty(refVectorY);
460    
461     DoubleGenericData* refVectorZ = new DoubleGenericData();
462     refVectorZ->setID("refVectorZ");
463     refVectorZ->setData(uZ);
464     sd->addProperty(refVectorZ);
465     }
466    
467     // we don't need the angular velocities, so let's exit the line
468     return NULL;
469     }
470    
471     void RestReader::readZangle(){
472    
473     int i;
474     unsigned int j;
475     int isPresent;
476    
477     Molecule* mol;
478     StuntDouble* integrableObject;
479     SimInfo::MoleculeIterator mi;
480     Molecule::IntegrableObjectIterator ii;
481    
482     #ifdef IS_MPI
483     int done, which_node, which_atom; // loop counter
484     int nProc;
485     MPI_Status istatus;
486     #endif //is_mpi
487    
488     const int BUFFERSIZE = 2000; // size of the read buffer
489     int nTotObjs; // the number of atoms
490     char read_buffer[BUFFERSIZE]; //the line buffer for reading
491    
492     char *eof_test; // ptr to see when we reach the end of the file
493     char *parseErr;
494    
495     std::vector<StuntDouble*> vecParticles;
496     std::vector<double> tempZangs;
497    
498     inAngFileName = info_->getRestFileName();
499    
500     inAngFileName += "0";
501    
502     // open the omega value file for reading
503     #ifdef IS_MPI
504     if (worldRank == 0) {
505     #endif
506     isPresent = 1;
507     inAngFile = fopen(inAngFileName.c_str(), "r");
508     if(!inAngFile){
509     sprintf(painCave.errMsg,
510     "Restraints Warning: %s file is not present\n"
511     "\tAll omega values will be initialized to zero. If the\n"
512     "\tsimulation is starting from the idealCrystal.in reference\n"
513     "\tconfiguration, this is the desired action. If this is not\n"
514     "\tthe case, the energy calculations will be incorrect.\n",
515     inAngFileName.c_str());
516     painCave.severity = OOPSE_WARNING;
517     painCave.isFatal = 0;
518     simError();
519     isPresent = 0;
520     }
521    
522     #ifdef IS_MPI
523     // let the other nodes know the status of the file search
524     MPI_Bcast(&isPresent, 1, MPI_INT, 0, MPI_COMM_WORLD);
525     #endif // is_mpi
526    
527     if (!isPresent) {
528     zeroZangle();
529     return;
530     }
531    
532     #ifdef IS_MPI
533     }
534    
535     // listen to node 0 to see if we should exit this function
536     if (worldRank != 0) {
537     MPI_Bcast(&isPresent, 1, MPI_INT, 0, MPI_COMM_WORLD);
538     if (!isPresent) {
539     zeroZangle();
540     return;
541     }
542     }
543    
544     strcpy( checkPointMsg, "zAngle file opened successfully for reading." );
545     MPIcheckPoint();
546     #endif
547    
548     #ifndef IS_MPI
549    
550     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
551     if( eof_test == NULL ){
552     sprintf( painCave.errMsg,
553     "RestraintReader error: error reading 1st line of \"%s\"\n",
554     inAngFileName.c_str() );
555     painCave.isFatal = 1;
556     simError();
557     }
558    
559     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
560     while ( eof_test != NULL ) {
561     // check for and ignore blank lines
562     if ( read_buffer != NULL )
563     tempZangs.push_back( atof(read_buffer) );
564     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
565     }
566    
567     nTotObjs = info_->getNGlobalIntegrableObjects();
568    
569     if( nTotObjs != tempZangs.size() ){
570     sprintf( painCave.errMsg,
571     "RestraintReader zAngle reading error. %s nIntegrable, %d, "
572     "does not match the meta-data file's nIntegrable, %d.\n",
573     inAngFileName.c_str(), tempZangs.size(), nTotObjs );
574     painCave.isFatal = 1;
575     simError();
576     }
577    
578     // load the zAngles into the integrable objects
579     i = 0;
580     for (mol = info_->beginMolecule(mi); mol != NULL;
581     mol = info_->nextMolecule(mi)) {
582    
583     for (integrableObject = mol->beginIntegrableObject(ii);
584     integrableObject != NULL;
585     integrableObject = mol->nextIntegrableObject(ii)) {
586    
587     integrableObject->setZangle(tempZangs[i]);
588     i++;
589     }
590     }
591    
592     // MPI Section of code..........
593     #else //IS_MPI
594    
595     // first thing first, suspend fatalities.
596     painCave.isEventLoop = 1;
597    
598     int myStatus; // 1 = wakeup & success; 0 = error; -1 = AllDone
599     int haveError, index;
600    
601     int *MolToProcMap = mpiSim->getMolToProcMap();
602     int localIndex;
603     int nCurObj;
604     double angleTranfer;
605    
606     nTotObjs = info_->getTotIntegrableObjects();
607     haveError = 0;
608     if (worldRank == 0) {
609    
610     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
611     if( eof_test == NULL ){
612     sprintf( painCave.errMsg,
613     "Error reading 1st line of %s \n ",inAngFileName.c_str());
614     haveError = 1;
615     simError();
616     }
617    
618     // let node 0 load the temporary angle vector
619     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
620     while ( eof_test != NULL ) {
621     // check for and ignore blank lines
622     if ( read_buffer != NULL )
623     tempZangs.push_back( atof(read_buffer) );
624     eof_test = fgets(read_buffer, sizeof(read_buffer), inAngFile);
625     }
626    
627     // Check to see that the number of integrable objects in the
628     // intial configuration file is the same as derived from the
629     // meta-data file.
630     if( nTotObjs != tempZangs.size() ){
631     sprintf( painCave.errMsg,
632     "RestraintReader zAngle reading Error. %s nIntegrable, %d, "
633     "does not match the meta-data file's nIntegrable, %d.\n",
634     inAngFileName.c_str(), tempZangs.size(), nTotObjs);
635     haveError= 1;
636     simError();
637     }
638    
639     }
640     // At this point, node 0 has a tempZangs vector completed, and
641     // everyone else has nada
642     index = 0;
643    
644     for (i=0 ; i < mpiSim->getNMolGlobal(); i++) {
645     // Get the Node number which has this atom
646     which_node = MolToProcMap[i];
647    
648     if (worldRank == 0) {
649     if (which_node == 0) {
650     localIndex = mpiSim->getGlobalToLocalMol(i);
651    
652     if(localIndex == -1) {
653     strcpy(painCave.errMsg, "Molecule not found on node 0!");
654     haveError = 1;
655     simError();
656     }
657    
658     vecParticles = (info_->molecules[localIndex]).getIntegrableObjects();
659     for(j = 0; j < vecParticles.size(); j++){
660     vecParticles[j]->setZangle(tempZangs[index]);
661     index++;
662     }
663    
664     } else {
665     // I am MASTER OF THE UNIVERSE, but I don't own this molecule
666    
667     MPI_Recv(&nCurObj, 1, MPI_INT, which_node,
668     TAKE_THIS_TAG_INT, MPI_COMM_WORLD, &istatus);
669    
670     for(j=0; j < nCurObj; j++){
671     angleTransfer = tempZangs[index];
672     MPI_Send(&angleTransfer, 1, MPI_DOUBLE, which_node,
673     TAKE_THIS_TAG_DOUBLE, MPI_COMM_WORLD);
674     index++;
675     }
676    
677     }
678    
679     } else {
680     // I am SLAVE TO THE MASTER
681    
682     if (which_node == worldRank) {
683    
684     // BUT I OWN THIS MOLECULE!!!
685    
686     localIndex = mpiSim->getGlobalToLocalMol(i);
687     vecParticles = (info_->molecules[localIndex]).getIntegrableObjects();
688     nCurObj = vecParticles.size();
689    
690     MPI_Send(&nCurObj, 1, MPI_INT, 0,
691     TAKE_THIS_TAG_INT, MPI_COMM_WORLD);
692    
693     for(j = 0; j < vecParticles.size(); j++){
694    
695     MPI_Recv(&angleTransfer, 1, MPI_DOUBLE, 0,
696     TAKE_THIS_TAG_DOUBLE, MPI_COMM_WORLD, &istatus);
697     vecParticles[j]->setZangle(angleTransfer);
698     }
699     }
700     }
701     }
702     #endif
703     }
704    
705     void RestReader :: zeroZangle(){
706    
707     int i;
708     unsigned int j;
709     int nTotObjs; // the number of atoms
710    
711     Molecule* mol;
712     StuntDouble* integrableObject;
713     SimInfo::MoleculeIterator mi;
714     Molecule::IntegrableObjectIterator ii;
715    
716     std::vector<StuntDouble*> vecParticles;
717    
718     #ifndef IS_MPI
719     // set all zAngles to 0.0
720     for (mol = info_->beginMolecule(mi); mol != NULL;
721     mol = info_->nextMolecule(mi))
722    
723     for (integrableObject = mol->beginIntegrableObject(ii);
724     integrableObject != NULL;
725     integrableObject = mol->nextIntegrableObject(ii))
726     integrableObject->setZangle( 0.0 );
727    
728    
729     // MPI Section of code..........
730     #else //IS_MPI
731    
732     // first thing first, suspend fatalities.
733     painCave.isEventLoop = 1;
734    
735     int myStatus; // 1 = wakeup & success; 0 = error; -1 = AllDone
736     int haveError, index;
737     int which_node;
738    
739     MPI_Status istatus;
740     int *MolToProcMap = mpiSim->getMolToProcMap();
741     int localIndex;
742     int nCurObj;
743     double angleTranfer;
744    
745     nTotObjs = info_->getTotIntegrableObjects();
746     haveError = 0;
747    
748     for (i=0 ; i < mpiSim->getNMolGlobal(); i++) {
749     // Get the Node number which has this atom
750     which_node = MolToProcMap[i];
751    
752     // let's let node 0 pass out constant values to all the processors
753     if (worldRank == 0) {
754     if (which_node == 0) {
755     localIndex = mpiSim->getGlobalToLocalMol(i);
756    
757     if(localIndex == -1) {
758     strcpy(painCave.errMsg, "Molecule not found on node 0!");
759     haveError = 1;
760     simError();
761     }
762    
763     vecParticles = (info_->molecules[localIndex]).getIntegrableObjects();
764     for(j = 0; j < vecParticles.size(); j++){
765     vecParticles[j]->setZangle( 0.0 );
766     }
767    
768     } else {
769     // I am MASTER OF THE UNIVERSE, but I don't own this molecule
770    
771     MPI_Recv(&nCurObj, 1, MPI_INT, which_node,
772     TAKE_THIS_TAG_INT, MPI_COMM_WORLD, &istatus);
773    
774     for(j=0; j < nCurObj; j++){
775     angleTransfer = 0.0;
776     MPI_Send(&angleTransfer, 1, MPI_DOUBLE, which_node,
777     TAKE_THIS_TAG_DOUBLE, MPI_COMM_WORLD);
778     index++;
779     }
780     }
781     } else {
782     // I am SLAVE TO THE MASTER
783    
784     if (which_node == worldRank) {
785    
786     // BUT I OWN THIS MOLECULE!!!
787    
788     localIndex = mpiSim->getGlobalToLocalMol(i);
789     vecParticles = (info_->molecules[localIndex]).getIntegrableObjects();
790     nCurObj = vecParticles.size();
791    
792     MPI_Send(&nCurObj, 1, MPI_INT, 0,
793     TAKE_THIS_TAG_INT, MPI_COMM_WORLD);
794    
795     for(j = 0; j < vecParticles.size(); j++){
796    
797     MPI_Recv(&angleTransfer, 1, MPI_DOUBLE, 0,
798     TAKE_THIS_TAG_DOUBLE, MPI_COMM_WORLD, &istatus);
799     vecParticles[j]->setZangle(angleTransfer);
800     }
801     }
802     }
803     }
804     #endif
805     }
806    
807     } // end namespace oopse