src/Utility/DiscParticle.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef DISC_PARTICLE_H
00012 #define DISC_PARTICLE_H
00013 
00014 // debugging macros
00015 #ifdef IPPL_PRINTDEBUG
00016 #define DPCTLDBG(x) x
00017 #else
00018 #define DPCTLDBG(x)
00019 #endif
00020 
00021 // include files
00022 #include "Utility/DiscConfig.h"
00023 #include "Utility/Pstring.h"
00024 #include "Utility/IpplInfo.h"
00025 #include "Message/Message.h"
00026 
00027 
00028 
00029 #ifdef IPPL_STDSTL
00030 #include <vector>
00031 using std::vector;
00032 #else
00033 #include <vector.h>
00034 #endif // IPPL_STDSTL
00035 
00036 #ifdef IPPL_USE_STANDARD_HEADERS
00037 #include <iostream>
00038 using namespace std;
00039 #else
00040 #include <iostream.h>
00041 #endif
00042 
00043 #include <stdio.h>
00044 
00045 // forward declarations
00046 template<class T> class ParticleBase;
00047 template<class T> class ParticleAttrib;
00048 class Message;
00049 
00050 class DiscParticle {
00051 
00052 public:
00053   // an enumeration used to indicate whether the file is for reading (INPUT)
00054   // or writing (OUTPUT), or for appending (APPEND)
00055   enum DPMode1 { INPUT, OUTPUT, APPEND };
00056 
00057   // an enumeration used to indicate whether we should read/write just a
00058   // single attribute, or the whole set of particle attributes
00059   enum DPMode2 { ALL, ATTRIB };
00060 
00061 public:
00062   // Constructor: make a DiscParticle for reading or writing.
00063   // fname = name of file (without extensions)
00064   // config = name of configuration file
00065   // I/O mode (INPUT, OUTPUT, or APPEND)
00066   // typestr = string describing the 'type' of the Particles to be written
00067   //           (this is ignored if the data is being read).  The string can
00068   //           be anything the user prefers.
00069   DiscParticle(const char *fname, const char *config, int iomode,
00070                const char *typestr = 0);
00071 
00072   // Constructor: same as above, but without a config file specified.  The
00073   // default config file entry that will be used is "*  .", which means, for
00074   // each SMP machine, assume the directory to put data files in is "."
00075   DiscParticle(const char *fname, int iomode, const char * = 0);
00076 
00077   // Destructor.
00078   ~DiscParticle();
00079 
00080   //
00081   // accessor functions
00082   //
00083 
00084   // Query for whether everything is OK so far.
00085   bool get_OK() const { return ConfigOK; }
00086 
00087   // Query for the number of records in the file.  If all attributes in a
00088   // Particle object are being written out, this is the number of sets of
00089   // attribute collections; if only single attributes are being written out,
00090   // this is the number of attributes which were written.
00091   unsigned int get_NumRecords() const { return RecordList.size(); }
00092 
00093   // Query for the mode of the Nth record, which can be either ALL (meaning
00094   // an entire ParticleBase's list of attributes was written out), or
00095   // ATTRIB (meaning only one specific attribute was written out).
00096   int get_DataMode(unsigned int record=0) const {
00097     return (RecordList[record]->attributes > 0 ? ALL : ATTRIB);
00098   }
00099 
00100   // Query for how this DiscParticle is operationg, either INPUT, OUTPUT, or
00101   // APPEND.
00102   int get_IOMode() const { return IOMode; }
00103 
00104   // Query for how many individual particles are stored in the Nth record,
00105   // for just the local filesets
00106   unsigned int get_NumLocalParticles(unsigned int record=0) const;
00107 
00108   // Query for how many individual particles are stored in the Nth record,
00109   // for the entire particle object (sum of all local particle counts)
00110   unsigned int get_NumGlobalParticles(unsigned int record=0) const {
00111     return RecordList[record]->globalparticles;
00112   }
00113 
00114   // Query for the number of attributes in the Nth record
00115   unsigned int get_NumAttributes(unsigned int record=0) const {
00116     return (get_DataMode(record)==ALL ? RecordList[record]->attributes : 1);
00117   }
00118 
00119   // Query for the number of bytes/elem in the Mth attribute in the Nth record
00120   unsigned int get_ElemByteSize(unsigned int record=0,
00121                                 unsigned int attrib=0) const {
00122     return RecordList[record]->bytesize[attrib];
00123   }
00124 
00125   // Query for the user-specified type string
00126   const char *get_TypeString() const { return TypeString.c_str(); }
00127 
00128   // Query for the DiscType string for the Mth attribute in the Nth record.
00129   // If there not one available, return 0.
00130   const char *get_DiscType(unsigned int record=0,
00131                            unsigned int attrib=0) const;
00132 
00133   //
00134   // read methods
00135   //
00136   // read the specifed record in the file into the given ParticleBase or
00137   // ParticleAttrib object.
00138   // If the method is to read all the ParticleBase, this will delete all the
00139   // existing particles in the given object, create new ones and store the
00140   // values, and then do an update.  If an attribute is being read, this
00141   // will only work if the number of particles in the attribute already
00142   // matches the number in the file.
00143 
00144   // a templated read for ParticleBase objects.  This should only be called
00145   // if the object was opened with iomode == INPUT
00146   //   pbase = ParticleBase object to read into
00147   //   record = which record to read.  DiscParticle does not keep a 'current
00148   //          file position' pointer, instead you explicitly request which
00149   //          record you wish to read.
00150   // Return success of operation.
00151   //mwerks  template<class T>
00152   //mwerks  bool read(ParticleBase<T> &pbase, unsigned int record=0);
00154   // a templated read for ParticleBase objects.  This should only be called
00155   // if the object was opened with iomode == INPUT, datamode == ALL.
00156   //   pbase = ParticleBase object to read into
00157   //   record = which record to read.  DiscParticle does not keep a 'current
00158   //          file position' pointer, instead you explicitly request which
00159   //          record you wish to read.
00160   // Return success of operation.
00161   template<class T>
00162   bool read(ParticleBase<T> &pbase, unsigned int record) {
00163     TAU_TYPE_STRING(taustr, CT(*this) +  " bool (ParticleBase<" + CT(T) +
00164                     ">, unsigned int)");
00165     TAU_PROFILE("DiscParticle::read()", taustr, 
00166                 TAU_UTILITY | TAU_PARTICLE | TAU_IO);
00167 
00168     // re-read the meta file since it might have changed
00169     ConfigOK = read_meta(); 
00170 
00171     // do some sanity checking first
00172     if (!ConfigOK) {
00173       ERRORMSG("Bad config or meta file in DiscParticle::read." << endl);
00174       return false;
00175     } else if (IOMode != INPUT) {
00176       ERRORMSG("Trying to read for DiscParticle created for output." << endl);
00177       return false;
00178     } else if (record >= get_NumRecords()) {
00179       ERRORMSG("Illegal record number in DiscParticle::read." << endl);
00180       return false;
00181     } else if (get_DataMode(record) != ALL) {
00182       ERRORMSG("Record " << record << " does not contain information for an ");
00183       ERRORMSG("entire ParticleBase." << endl);
00184       return false;
00185     } else if (get_NumAttributes(record) != pbase.numAttributes()) {
00186       ERRORMSG("Record " << record <<" has a different number of attributes ");
00187       ERRORMSG("than in the given ParticleBase." << endl);
00188       return false;
00189     }
00190 
00191 // ada:  incDiscReads is not found  INCIPPLSTAT(incDiscReads);
00192 
00193     // make sure all the attribute sizes match
00194     for (int ca=0; ca < get_NumAttributes(record); ++ca) {
00195       if (get_ElemByteSize(record, ca)!=pbase.getAttribute(ca).elementSize()) {
00196         ERRORMSG("Mismatched data type size for attribute " << ca << " in ");
00197         ERRORMSG("DiscParticle::read." << endl);
00198         return false;
00199       }
00200     }
00201 
00202     DPCTLDBG(string dbgmsgname("DiscParticle::read(ParticleBase) "));
00203     DPCTLDBG(dbgmsgname += Config->getConfigFile());
00204     DPCTLDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00205 
00206     // since we're reading in data for the entire ParticleBase, delete all the
00207     // existing particles, and do an update, before reading in new particles
00208     DPCTLDBG(dbgmsg << "Deleting existing " << pbase.getLocalNum());
00209     DPCTLDBG(dbgmsg << " particles." << endl);
00210     pbase.destroy(pbase.getLocalNum(), 0);
00211     pbase.update();
00212 
00213     // if we're on a box0 node, read in the data for the attributes
00214     if (Ippl::myNode() == Config->getSMPBox0()) {
00215 
00216       // loop over all the files on this Box0 node
00217       for (int sf=0; sf < Config->getNumFiles(); ++sf) {
00218 
00219         // only need to process this file if there are particles in the file
00220         int localnum = RecordList[record]->localparticles[sf];
00221         if (localnum > 0) {
00222 
00223           // open the data file
00224           string filename = Config->getFilename(sf) + ".data";
00225           DPCTLDBG(dbgmsg<<"Opening data file '" << filename << "' ..."<<endl);
00226           FILE *datafile = open_file(filename, string("r"));
00227 
00228           // if the file is available, read it
00229           if (datafile != 0) {
00230             // read the data for each attribute into a buffer, then put
00231             // these buffers in a message.
00232             Message *msg = new Message;
00233             msg->put(localnum);
00234 
00235             // read in the data for all the attributes
00236             for (int a=0; a < get_NumAttributes(record); ++a) {
00237               // read the data
00238               void *buf = read_data(datafile, a, record, sf);
00239               PAssert(buf != 0);
00240 
00241               // put it in the Message
00242               msg->setCopy(false).setDelete(true);
00243               msg->putmsg(buf, get_ElemByteSize(record, a), localnum);
00244             }
00245 
00246             // create new particles, by getting them from the message
00247             DPCTLDBG(dbgmsg<<"Creating "<<localnum << " new particles."<<endl);
00248             pbase.getMessageAndCreate(*msg);
00249 
00250             // we're done with the message now
00251             delete msg;
00252           }
00253         }
00254       }
00255     }
00256 
00257     // at the end, do an update to get everything where it is supposed to be
00258     DPCTLDBG(dbgmsg << "Doing final update after reading in particles ...");
00259     DPCTLDBG(dbgmsg << endl);
00260     pbase.update();
00261     DPCTLDBG(dbgmsg << "This node now has " << pbase.getLocalNum());
00262     DPCTLDBG(dbgmsg << " local particles." << endl);
00263     return true;
00264   }
00265 
00266   // a templated read for ParticleAttrib objects.  This should only be
00267   // called if the object was opened with iomode == INPUT
00268   //   pattr = ParticleAttrib object to read into
00269   //   record = which record to read.  DiscParticle does not keep a 'current
00270   //          file position' pointer, instead you explicitly request which
00271   //          record you wish to read.
00272   // Return success of operation.
00273   //mwerks  template<class T>
00274   //mwerks  bool read(ParticleAttrib<T> &pattr, unsigned int record=0);
00276   // a templated read for ParticleAttrib objects.  This should only be called
00277   // if the object was opened with iomode == INPUT, datamode == ATTRIB.  When
00278   // reading just a single attribute, the particles simply replace the existing
00279   // particles in the attribute.
00280   //   pbase = ParticleAttrib object to read into
00281   //   record = which record to read.  DiscParticle does not keep a 'current
00282   //          file position' pointer, instead you explicitly request which
00283   //          record you wish to read.
00284   // Return success of operation.
00285   template<class T>
00286   bool read(ParticleAttrib<T> &pattr, unsigned int record) {
00287     TAU_TYPE_STRING(taustr, CT(*this) +  " bool (ParticleAttrib<" + CT(T) +
00288                     ">, unsigned int)");
00289     TAU_PROFILE("DiscParticle::read()", taustr,
00290                 TAU_UTILITY | TAU_PARTICLE | TAU_IO);
00291 
00292     // re-read the meta file since it might have changed
00293     ConfigOK = read_meta();
00294 
00295     // do some sanity checking first
00296     if (!ConfigOK) {
00297       ERRORMSG("Bad config or meta file in DiscParticle::read." << endl);
00298       return false;
00299     } else if (IOMode != INPUT) {
00300       ERRORMSG("Trying to read for a DiscParticle created for output."<<endl);
00301       return false;
00302     } else if (record >= get_NumRecords()) {
00303       ERRORMSG("Illegal record number in DiscParticle::read." << endl);
00304       return false;
00305     } else if (get_DataMode(record) != ATTRIB) {
00306       ERRORMSG("Record " << record << " does not contain information for a ");
00307       ERRORMSG("single ParticleAttrib." << endl);
00308       return false;
00309     } else if (get_ElemByteSize(record, 0) != pattr.elementSize()) {
00310       ERRORMSG("Mismatched attribute data type size in ");
00311       ERRORMSG("DiscParticle::read." << endl);
00312       return false;
00313     }
00314 
00315 // ada:  incDiscReads is not found   INCIPPLSTAT(incDiscReads);
00316 
00317     DPCTLDBG(string dbgmsgname("DiscParticle::read(ParticleAttrib) "));
00318     DPCTLDBG(dbgmsgname += Config->getConfigFile());
00319     DPCTLDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00320 
00321     // delete all the existing particles before reading in new particles
00322     DPCTLDBG(dbgmsg << "Deleting existing " << pattr.size());
00323     DPCTLDBG(dbgmsg << " particles." << endl);
00324     pattr.destroy(pattr.size(), 0);
00325 
00326     // if we're on a box0 node, read in the data for the attributes
00327     if (Ippl::myNode() == Config->getSMPBox0()) {
00328 
00329       // loop over all the files on this Box0 node
00330       for (int sf=0; sf < Config->getNumFiles(); ++sf) {
00331 
00332         // only need to process this file if there are particles in the file
00333         int localnum = RecordList[record]->localparticles[sf];
00334         if (localnum > 0) {
00335 
00336           // open the data file
00337           string filename = Config->getFilename(sf) + ".data";
00338           DPCTLDBG(dbgmsg<<"Opening data file '"<<filename << "' ..." << endl);
00339           FILE *datafile = open_file(filename, string("r"));
00340 
00341           // if the file is available, read it
00342           if (datafile != 0) {
00343             // read the data for each attribute into a buffer, then put
00344             // these buffers in a message.
00345             Message *msg = new Message;
00346 
00347             // read in the data for the attribute
00348             void *buf = read_data(datafile, 0, record, sf);
00349             PAssert(buf != 0);
00350 
00351             // put it in the Message
00352             msg->setCopy(false).setDelete(true);
00353             msg->putmsg(buf, get_ElemByteSize(record, 0), localnum);
00354 
00355             // create new particles, by getting them from the message
00356             DPCTLDBG(dbgmsg<<"Creating "<<localnum<<" new particles." << endl);
00357             pattr.getMessage(*msg, localnum);
00358 
00359             // we're done with the message now
00360             delete msg;
00361           }
00362         }
00363       }
00364     }
00365 
00366     DPCTLDBG(dbgmsg << "This node now has " << pattr.size());
00367     DPCTLDBG(dbgmsg << " local particles." << endl);
00368     return true;
00369   }
00370 
00371   //
00372   // write methods
00373   //
00374   // write the data from the given ParticleBase or ParticleAttrib into the
00375   // file.  Data is appended as a new record.
00376 
00377   // a templated write for ParticleBase objects.  All attributes in the
00378   // ParticleBase are written as a single record.  This should only be
00379   // called if the object was opened with iomode == OUTPUT or APPEND.
00380   //   pbase = ParticleBase object to read from.
00381   // Return success of operation.
00382   //mwerks  template<class T>
00383   //mwerks  bool write(ParticleBase<T> &pbase);
00385   // a templated write for ParticleBase objects.  All attributes in the
00386   // ParticleBase are written as a single record.  This should only be
00387   // called if the object was opened with iomode == OUTPUT or APPEND.
00388   //   pbase = ParticleBase object to read into
00389   // Return success of operation.
00390   template<class T>
00391   bool write(ParticleBase<T> &pbase) {
00392     TAU_TYPE_STRING(taustr, CT(*this) +  " bool (ParticleBase<" + CT(T)+">)");
00393     TAU_PROFILE("DiscParticle::write()", taustr, 
00394                 TAU_UTILITY | TAU_PARTICLE | TAU_IO);
00395 
00396     // generate a tag to use for communication
00397     int tag = Ippl::Comm->next_tag(FB_WRITE_TAG, FB_TAG_CYCLE);
00398 
00399     // if the file already has some records, re-read the meta file in case it
00400     // has changed.  If we do not have any record info, and we've opened
00401     // for OUTPUT, we do NOT read any possible meta file since we want to start
00402     // a new file.
00403     if (get_NumRecords() > 0 || IOMode == APPEND)
00404       ConfigOK = read_meta();
00405 
00406     // do some sanity checking first
00407     if (!ConfigOK) {
00408       ERRORMSG("Bad config or meta file in DiscParticle::write." << endl);
00409       return false;
00410     } else if (IOMode == INPUT) {
00411       ERRORMSG("Trying to write for a DiscParticle created for input."<<endl);
00412       return false;
00413     }
00414 
00415 //   ada:  incDiscWrites is not found  INCIPPLSTAT(incDiscWrites);
00416 
00417     DPCTLDBG(string dbgmsgname("DiscParticle::write(ParticleBase) "));
00418     DPCTLDBG(dbgmsgname += Config->getConfigFile());
00419     DPCTLDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00420 
00421     // create a new record entry, and set it to the proper values
00422     RecordInfo *info = new RecordInfo;
00423     info->attributes = pbase.numAttributes();
00424     info->globalparticles = pbase.getTotalNum();
00425     for (int a=0; a < info->attributes; ++a) {
00426       info->bytesize.push_back(pbase.getAttribute(a).elementSize());
00427       info->disctypes.push_back(pbase.getAttribute(a).typeString());
00428     }
00429 
00430     // Create a message with our local particles, which will then be used
00431     // to write out the data
00432     DPCTLDBG(dbgmsg << "Putting local " << pbase.getLocalNum());
00433     DPCTLDBG(dbgmsg << " particles into a message." << endl);
00434     Message *msg = new Message;
00435     pbase.putMessage(*msg, pbase.getLocalNum(), 0);
00436 
00437     // on Box0 nodes, first write out your own particles, then write out
00438     // all the other node's particles
00439     if (Ippl::myNode() == Config->getSMPBox0()) {
00440       // create the data file, if it does not yet exist; otherwise, open
00441       // it for append
00442       string openmode = "a";
00443       if (get_NumRecords() == 0)
00444         openmode = "w";
00445       string filename = Config->getFilename(0) + ".data";
00446       DPCTLDBG(dbgmsg << "Opening data file '" << filename << "' ..." << endl);
00447       FILE *datafile = open_file(filename, openmode);
00448       if (datafile == 0) {
00449         delete info;
00450         delete msg;
00451         return false;
00452       }
00453 
00454       // create a vector of Messages, which will hold the info to be written
00455       // out.  We do not write until we have all the messages from the
00456       // different nodes writing to the Box0 file.
00457       vector<Message *> msgvec;
00458       msgvec.push_back(msg);
00459 
00460       // write out our local attribute data, saving where we started to write
00461       // determine how many other SMP nodes we expect to receive data from
00462       int notreceived = (Config->getNumSMPNodes() - 1);
00463       for (int s=0; s < Config->getNumOtherSMP(); ++s)
00464         notreceived += Config->getNumSMPNodes(Config->getOtherSMP(s));
00465 
00466       // now wait for messages from all the other nodes with their particle
00467       // data, and save the messages
00468       DPCTLDBG(dbgmsg << "Box0 node waiting to receive " << notreceived);
00469       DPCTLDBG(dbgmsg << " messages, from this SMP and ");
00470       DPCTLDBG(dbgmsg << Config->getNumOtherSMP() << " other SMPs." << endl);
00471       while (notreceived > 0) {
00472         // receive the message
00473         int any_node = COMM_ANY_NODE;
00474         Message *recmsg = Ippl::Comm->receive_block(any_node, tag);
00475         PAssert(recmsg != 0);
00476         notreceived--;
00477 
00478         DPCTLDBG(dbgmsg<<"Received msg from node " << any_node << " w tag ");
00479         DPCTLDBG(dbgmsg<< tag << "; still waiting for " << notreceived);
00480         DPCTLDBG(dbgmsg<< " messages." << endl);
00481 
00482         // get the number of particles and save the info
00483         // write the info out to disk
00484         msgvec.push_back(recmsg);
00485       }
00486 
00487       // we have all the messages, so write the data to disk.  This will
00488       // delete all the messages and save the offset information, as well as
00489       // the particle count.
00490       if (!write_data(datafile, msgvec, info)) {
00491         delete info;
00492         return false;
00493       }
00494 
00495       // done writing; close the file and save the particle count
00496       fclose(datafile);
00497 
00498     } else {
00499       // just send out the message with our local particles now
00500       DPCTLDBG(dbgmsg<<"Sending " << pbase.getLocalNum()<<" ptcls to node ");
00501       DPCTLDBG(dbgmsg<< Config->getSMPBox0() << " with tag " << tag << endl);
00502       Ippl::Comm->send(msg, Config->getSMPBox0(), tag);
00503 
00504       // and save extra necessary info into RecordInfo struct
00505       info->localparticles.push_back(0);
00506       info->offset.push_back(vector<Offset_t>());
00507     }
00508 
00509     // add this new record information to our list
00510     DPCTLDBG(dbgmsg << "Finished writing; saving RecordInfo record ..."<<endl);
00511     RecordList.push_back(info);
00512 
00513     // rewrite the meta file, if we're on a box0 node
00514     if (Ippl::myNode() == Config->getSMPBox0()) {
00515       DPCTLDBG(dbgmsg << "Doing final re-write of .meta file ..." << endl);
00516       if (!write_meta())
00517         return false;
00518     }
00519 
00520     // to be safe, do a barrier here, since some nodes could have had very
00521     // little to do
00522     DPCTLDBG(dbgmsg << "At final barrier at end of write ..." << endl);
00523     Ippl::Comm->barrier();
00524 
00525     // return success
00526     return true;
00527   }
00528 
00529   // a templated write for ParticleAttrib objects.  The single attribute
00530   // data is written as a single record.  This should only be
00531   // called if the object was opened with iomode == OUTPUT or APPEND.
00532   //   pattr = ParticleAttrib object to read from.
00533   // Return success of operation.
00534   //mwerks  template<class T>
00535   //mwerks  bool write(ParticleAttrib<T> &pattr);
00537   // a templated write for ParticleAttrib objects.  This should only be
00538   // called if the object was opened with iomode == OUTPUT or APPEND.
00539   //   pattr = ParticleAttrib object to read from
00540   // Return success of operation.
00541   template<class T>
00542   bool write(ParticleAttrib<T> &pattr) {
00543     TAU_TYPE_STRING(taustr, CT(*this) + " bool (ParticleAttrib<" + CT(T)+">)");
00544     TAU_PROFILE("DiscParticle::write()", taustr,
00545                 TAU_UTILITY | TAU_PARTICLE | TAU_IO);
00546 
00547     // generate a tag to use for communication
00548     int tag = Ippl::Comm->next_tag(FB_WRITE_TAG, FB_TAG_CYCLE);
00549 
00550     // if the file already has some records, re-read the meta file in case it
00551     // has changed.  If we do not have any record info, and we've opened
00552     // for OUTPUT, we do NOT ready any possible meta file since we want to
00553     // start a new file
00554     if (get_NumRecords() > 0 || IOMode == APPEND)
00555       ConfigOK = read_meta();
00556 
00557     // do some sanity checking first
00558     if (!ConfigOK) {
00559       ERRORMSG("Bad config or meta file in DiscParticle::write." << endl);
00560       return false;
00561     } else if (IOMode == INPUT) {
00562       ERRORMSG("Trying to write for a DiscParticle created for input."<<endl);
00563       return false;
00564     }
00565 
00566 // ada:  incDiscWrites is not found    INCIPPLSTAT(incDiscWrites);
00567 
00568     DPCTLDBG(string dbgmsgname("DiscParticle::write(ParticleAttrib) "));
00569     DPCTLDBG(dbgmsgname += Config->getConfigFile());
00570     DPCTLDBG(Inform dbgmsg(dbgmsgname.c_str(), INFORM_ALL_NODES));
00571 
00572     // create a new record entry, and set it to the proper values
00573     RecordInfo *info = new RecordInfo;
00574     info->attributes = 0;
00575     info->globalparticles = 0;
00576     info->bytesize.push_back(pattr.elementSize());
00577     info->disctypes.push_back(pattr.typeString());
00578 
00579     // Create a message with our local particles, which will then be used
00580     // to write out the data
00581     DPCTLDBG(dbgmsg << "Putting local " << pattr.size());
00582     DPCTLDBG(dbgmsg << " particles into a message." << endl);
00583     Message *msg = new Message;
00584     msg->put(pattr.size());
00585     pattr.putMessage(*msg, pattr.size(), 0);
00586 
00587     // on Box0 nodes, first write out your own particles, then write out
00588     // all the other node's particles
00589     if (Ippl::myNode() == Config->getSMPBox0()) {
00590       // create the data file, if it does not yet exist; otherwise, open
00591       // it for append
00592       string openmode = "a";
00593       if (get_NumRecords() == 0)
00594         openmode = "w";
00595       string filename = Config->getFilename(0) + ".data";
00596       DPCTLDBG(dbgmsg << "Opening data file '" << filename << "' ..." << endl);
00597       FILE *datafile = open_file(filename, openmode);
00598       if (datafile == 0) {
00599         delete info;
00600         delete msg;
00601         return false;
00602       }
00603 
00604       // create a vector of Messages, which will hold the info to be written
00605       // out.  We do not write until we have all the messages from the
00606       // different nodes writing to the Box0 file.
00607       vector<Message *> msgvec;
00608       msgvec.push_back(msg);
00609 
00610       // write out our local attribute data, saving where we started to write
00611       // determine how many other SMP nodes we expect to receive data from
00612       int notreceived = (Config->getNumSMPNodes() - 1);
00613       for (int s=0; s < Config->getNumOtherSMP(); ++s)
00614         notreceived += Config->getNumSMPNodes(Config->getOtherSMP(s));
00615 
00616       // now wait for messages from all the other nodes with their particle
00617       // data, and save the messages
00618       DPCTLDBG(dbgmsg << "Box0 node waiting to receive " << notreceived);
00619       DPCTLDBG(dbgmsg << " messages, from this SMP and ");
00620       DPCTLDBG(dbgmsg << Config->getNumOtherSMP() << " other SMPs." << endl);
00621       while (notreceived > 0) {
00622         // receive the message
00623         int any_node = COMM_ANY_NODE;
00624         Message *recmsg = Ippl::Comm->receive_block(any_node, tag);
00625         PAssert(recmsg != 0);
00626         notreceived--;
00627 
00628         DPCTLDBG(dbgmsg<< "Received msg from node " << any_node << " w tag ");
00629         DPCTLDBG(dbgmsg<< tag << "; still waiting for " << notreceived);
00630         DPCTLDBG(dbgmsg<< " messages." << endl);
00631 
00632         // get the number of particles and save the info
00633         // write the info out to disk
00634         msgvec.push_back(recmsg);
00635       }
00636 
00637       // we have all the messages, so write the data to disk.  This will
00638       // delete all the messages and save the offset information, as well as
00639       // the particle count.
00640       if (!write_data(datafile, msgvec, info)) {
00641         delete info;
00642         return false;
00643       }
00644 
00645       // done writing; close the file and save the particle count
00646       fclose(datafile);
00647 
00648     } else {
00649       // just send out the message with our local particles now
00650       DPCTLDBG(dbgmsg << "Sending " << pattr.size() << " particles to node ");
00651       DPCTLDBG(dbgmsg << Config->getSMPBox0() << " with tag " << tag << endl);
00652       Ippl::Comm->send(msg, Config->getSMPBox0(), tag);
00653 
00654       // and save extra necessary info into RecordInfo struct
00655       info->localparticles.push_back(0);
00656       info->offset.push_back(vector<Offset_t>());
00657     }
00658 
00659     // add this new record information to our list
00660     DPCTLDBG(dbgmsg << "Finished writing; saving RecordInfo record ..."<<endl);
00661     RecordList.push_back(info);
00662 
00663     // rewrite the meta file, if we're on a box0 node
00664     if (Ippl::myNode() == Config->getSMPBox0()) {
00665       DPCTLDBG(dbgmsg << "Doing final re-write of .meta file ..." << endl);
00666       if (!write_meta())
00667         return false;
00668     }
00669 
00670     // to be safe, do a barrier here, since some nodes could have had very
00671     // little to do
00672     DPCTLDBG(dbgmsg << "At final barrier at end of write ..." << endl);
00673     Ippl::Comm->barrier();
00674 
00675     // return success
00676     return true;
00677   }
00678 
00679   //
00680   // console printing methods
00681   //
00682 
00683   // print out debugging info to the given stream
00684   void printDebug(ostream&);
00685   void printDebug();
00686 
00687 private:
00688   // a typedef used to select the data type for file offsets
00689   typedef long  Offset_t; 
00690 
00691   // the configuration file mechanism
00692   DiscConfig *Config;
00693   bool ConfigOK;
00694 
00695   // I/O mode (INPUT or OUTPUT)
00696   int IOMode;
00697 
00698   // the base name for the output file, and the descriptive type string
00699   string BaseFile;
00700   string TypeString;
00701 
00702   // a simple struct which stores information about each record, for each
00703   // file set
00704   struct RecordInfo {
00705     // a typedef used to select the data type for file offsets
00706     typedef long  Offset_t; 
00707 
00708     int attributes;              // number of attributes; 0 == just writing
00709                                  // one attribute, > 0 == writing a whole
00710                                  // ParticleBase's worth of particles
00711     int globalparticles;         // total number of particles in whole system
00712     vector<int> localparticles;  // number of particles in this fileset's files
00713     vector<int> bytesize;        // how many bytes/attrib elem in each attrib
00714     vector<vector<Offset_t> > offset; // starting offset for attrib in .data
00715     vector<string> disctypes;    // attribute types determined by DiscType
00716     RecordInfo() : globalparticles(0), attributes(0) { }
00717   };
00718 
00719   // the list of information for each record
00720   vector<RecordInfo *> RecordList;
00721 
00722   // this keeps track of where in the .data file writing is occuring
00723   Offset_t CurrentOffset;
00724 
00725   //
00726   // functions used to build/query information about the processors, etc.
00727   //
00728 
00729   // perform initialization based on the constuctor arguments
00730   void initialize(const char *base, const char *config,
00731                   const char *typestr, int iomode);
00732 
00733   // open a file in the given mode.  If an error occurs, print a message (but
00734   // only if the last argument is true).
00735   // fnm = complete name of file (can include a path)
00736   // mode = open method ("r" == read, "rw" == read/write, etc.
00737   FILE *open_file(const string& fnm, const string& mode,
00738                   bool reporterr = true);
00739 
00740   //
00741   // read/write functions for individual components
00742   //
00743 
00744   // read or write .meta data file information.  Return success.
00745   bool read_meta();
00746   bool write_meta();
00747 
00748   // read the data for the Nth attribute of record R, in the Fth fileset,
00749   // and return the newly allocated buffer (or 0 if an error occurs).
00750   void *read_data(FILE *outputData, unsigned int attrib,
00751                   unsigned int record, unsigned int fileset);
00752 
00753   // write the data for a block of particles to the given file.  The
00754   // data is just appended to the end.  Return success of write.
00755   bool write_data(FILE *outputData, vector<Message *> &, RecordInfo *);
00756 
00757   //
00758   // don't allow copy or assign ... this are declared but never defined,
00759   // if something tries to use them it will generate a missing symbol error
00760   //
00761 
00762   DiscParticle(const DiscParticle&);
00763   DiscParticle& operator=(const DiscParticle&);
00764 };
00765 
00766 #include "Utility/DiscParticle.cpp"
00767 
00768 #endif // DISC_PARTICLE_H
00769 
00770 /***************************************************************************
00771  * $RCSfile: DiscParticle.h,v $   $Author: adelmann $
00772  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:33 $
00773  * IPPL_VERSION_ID: $Id: DiscParticle.h,v 1.1.1.1 2003/01/23 07:40:33 adelmann Exp $ 
00774  ***************************************************************************/

Generated on Mon Jan 16 13:23:58 2006 for IPPL by  doxygen 1.4.6