src/Particle/ParticleBase.cpp

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  * This program was prepared by PSI. 
00007  * All rights in the program are reserved by PSI.
00008  * Neither PSI nor the author(s)
00009  * makes any warranty, express or implied, or assumes any liability or
00010  * responsibility for the use of this software
00011  *
00012  * Visit http://www.acl.lanl.gov/POOMS for more details
00013  *
00014  ***************************************************************************/
00015 
00016 // -*- C++ -*-
00017 /***************************************************************************
00018  *
00019  * The IPPL Framework
00020  * 
00021  *
00022  * Visit http://people.web.psi.ch/adelmann/ for more details
00023  *
00024  ***************************************************************************/
00025 
00026 // include files
00027 #include "Particle/ParticleBase.h"
00028 #include "Particle/ParticleLayout.h"
00029 #include "Particle/ParticleAttrib.h"
00030 #include "Message/Message.h"
00031 #include "Message/Communicate.h"
00032 #include "Utility/Inform.h"
00033 #include "Utility/PAssert.h"
00034 #include "Utility/IpplInfo.h"
00035 #include "Utility/IpplStats.h"
00036 #include "Profile/Profiler.h"
00037 
00038 #ifdef IPPL_STDSTL
00039 #include <algorithm>
00040 using namespace std;
00041 #else
00042 #include <algo.h>
00043 #endif // IPPL_STDSTL
00044 
00045 
00047 // For a ParticleBase that was created with the default constructor,
00048 // initialize performs the same actions as are done in the non-default
00049 // constructor.  If this object has already been initialized, it is
00050 // an error.  For initialize, you must supply a layout instance.
00051 template<class PLayout>
00052 void ParticleBase<PLayout>::initialize(PLayout *layout) {
00053   TAU_TYPE_STRING(taustr, CT(*this) + " void (" + CT(*layout) + ")"); 
00054   TAU_PROFILE("ParticleBase::initialize()", taustr, TAU_PARTICLE);
00055 
00056   // make sure we have not already been initialized, and that we have
00057   // been given a good layout
00058   PAssert(Layout == 0);
00059   PAssert(layout != 0);
00060 
00061   // save the layout, and perform setup tasks
00062   Layout = layout;
00063   setup();
00064 }
00065 
00066 
00068 // set up this new object:  add attributes and check in to the layout
00069 template<class PLayout>
00070 void ParticleBase<PLayout>::setup() {
00071   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00072   TAU_PROFILE("ParticleBase::setup()", taustr, TAU_PARTICLE);
00073 
00074   TotalNum = 0;
00075   LocalNum = 0;
00076   DestroyNum = 0;
00077   GhostNum = 0;
00078 
00079   // shift ID back so that first ID retrieved is myNode
00080   NextID = Ippl::Comm->myNode() - Ippl::Comm->getNodes();
00081 
00082   // Create position R and index ID attributes for the particles,
00083   // and add them to our list of attributes.
00084   addAttribute(R);
00085   addAttribute(ID);
00086 
00087   // indicate we have created a new ParticleBase object
00088   INCIPPLSTAT(incParticleBases);
00089 }
00090 
00091 
00093 // Return a boolean value indicating if we are on a processor which can
00094 // be used for single-node particle creation and initialization
00095 template<class PLayout>
00096 bool ParticleBase<PLayout>::singleInitNode() const {
00097   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00098   TAU_PROFILE("ParticleBase::singleInitNode()", taustr, TAU_PARTICLE);
00099   
00100   return (Ippl::Comm->myNode() == 0);
00101 }
00102 
00103 
00105 // Return a new unique ID value for use by new particles.
00106 // The ID number = (i * numprocs) + myproc, i = 0, 1, 2, ...
00107 template<class PLayout>
00108 unsigned ParticleBase<PLayout>::getNextID() {
00109   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00110   TAU_PROFILE("ParticleBase::getNextID()", taustr, TAU_PARTICLE);
00111 
00112   return (NextID += Ippl::Comm->getNodes());
00113 }
00114 
00116 // Reset the particle ID's to be globally consecutive, 0 thru TotalNum.
00117 template <class PLayout>
00118 void ParticleBase<PLayout>::resetID(void) {
00119   TAU_TYPE_STRING(taustr, CT(*this) + " void ()");
00120   TAU_PROFILE("ParticleBase::resetID()", taustr, TAU_PARTICLE);
00121 
00122   unsigned int nodes = Ippl::getNodes();
00123   unsigned int myNode = Ippl::myNode();
00124   size_t localNum = this->getLocalNum();
00125   size_t ip;
00126   int master = 0;
00127   if (myNode == master) {
00128     // Node 0 can immediately set its ID's to 0 thru LocalNum-1
00129     for (ip=0; ip<localNum; ++ip) 
00130       this->ID[ip] = ip;
00131     // if there is only one processor, we are done
00132     if (nodes == 1) return;
00133     // parallel case: must find out how many particles each processor has
00134     // Node 0 gathers this information into an array
00135     size_t *lp;
00136     lp = new size_t[nodes];
00137     lp[0] = localNum;  // enter our own number of particles
00138     // get next message tag and receive messages
00139     int tag1 = Ippl::Comm->next_tag(P_RESET_ID_TAG,P_LAYOUT_CYCLE);
00140     Message* msg1;
00141     for (ip=1; ip<nodes; ++ip) {
00142       int rnode = COMM_ANY_NODE;
00143       msg1 = Ippl::Comm->receive_block(rnode,tag1);
00144       PAssert(msg1);
00145       msg1->get(lp[rnode]);
00146       delete msg1;
00147     }
00148     // now we should have all the localnum values.
00149     // figure out starting ID for each processor and send back
00150     size_t current, sum = 0;
00151     for (ip=0; ip<nodes; ++ip) {
00152       current = lp[ip];
00153       lp[ip] = sum;
00154       sum += current;
00155     }
00156     // send initial ID values back out
00157     int tag2 = Ippl::Comm->next_tag(P_RESET_ID_TAG,P_LAYOUT_CYCLE);
00158     for (ip=1; ip<nodes; ++ip) {
00159       Message* msg2 = new Message;
00160       msg2->put(lp[ip]);
00161       bool success = Ippl::Comm->send(msg2,ip,tag2);
00162       PAssert(success);
00163     }
00164     // we are done
00165     return;
00166   }
00167   else {
00168     // first send number of local particles to Node 0
00169     int tag1 = Ippl::Comm->next_tag(P_RESET_ID_TAG,P_LAYOUT_CYCLE);
00170     Message* msg1 = new Message;
00171     msg1->put(localNum);
00172     bool success = Ippl::Comm->send(msg1,master,tag1);
00173     PAssert(success);
00174     // now receive back our initial ID number
00175     size_t initialID;
00176     int tag2 = Ippl::Comm->next_tag(P_RESET_ID_TAG,P_LAYOUT_CYCLE);
00177     Message* msg2 = Ippl::Comm->receive_block(master,tag2);
00178     PAssert(msg2);
00179     msg2->get(initialID);
00180     delete msg2;
00181     // now reset our particle ID's using this initial value
00182     for (ip=0; ip<localNum; ++ip) 
00183       this->ID[ip] = ip + initialID;
00184     // we are done
00185     return;
00186   }
00187 }
00188 
00189 
00191 // put the data for M particles starting from local index I in a Message
00192 template<class PLayout>
00193 size_t
00194 ParticleBase<PLayout>::putMessage(Message& msg, size_t M, size_t I) {
00195   TAU_PROFILE("ParticleBase::putMessage()", 
00196     "unsigned (Message, unsigned, unsigned)", TAU_PARTICLE);
00197 
00198   // make sure we've been initialized
00199   PAssert(Layout != 0);
00200 
00201   // put into message the number of items in the message
00202   msg.put(M);
00203 
00204   // go through all the attributes and put their data in the message
00205   if (M > 0) {
00206     // this routine should only be called for local particles; call
00207     // ghostPutMessage to put in particles which might be ghost particles
00208     PAssert(I < R.size() && (I+M) <= R.size());
00209 
00210     attrib_container_t::iterator abeg = AttribList.begin();
00211     attrib_container_t::iterator aend = AttribList.end();
00212     for ( ; abeg != aend; abeg++ )
00213       (*abeg)->putMessage(msg, M, I);
00214   }
00215 
00216   return M;
00217 }
00218 
00219 
00221 // put the data for a list of particles in a Message
00222 template<class PLayout>
00223 size_t
00224 ParticleBase<PLayout>::putMessage(Message& msg,
00225                                   const vector<size_t>& putList)
00226 {
00227   TAU_PROFILE("ParticleBase::putMessage()", 
00228     "unsigned (Message, vector<unsigned>)", TAU_PARTICLE);
00229 
00230   // make sure we've been initialized
00231   PAssert(Layout != 0);
00232 
00233   vector<size_t>::size_type M = putList.size();  
00234   msg.put(M);
00235 
00236   // go through all the attributes and put their data in the message
00237   if (M > 0) {
00238     attrib_container_t::iterator abeg = AttribList.begin();
00239     attrib_container_t::iterator aend = AttribList.end();
00240     for ( ; abeg != aend; ++abeg )
00241       (*abeg)->putMessage(msg, putList);
00242   }
00243 
00244   return M;
00245 }
00246 
00247 
00249 // retrieve particles from the given message and store them
00250 template<class PLayout>
00251 size_t ParticleBase<PLayout>::getMessage(Message& msg) {
00252   TAU_PROFILE("ParticleBase::getMessage()", "unsigned (Message)",
00253               TAU_PARTICLE);
00254 
00255   // make sure we've been initialized
00256   PAssert(Layout != 0);
00257 
00258   // get the number of items in the message
00259   size_t numitems;
00260   msg.get(numitems);
00261 
00262   // go through all the attributes and get their data from the message
00263   if (numitems > 0) {
00264     attrib_container_t::iterator abeg = AttribList.begin();
00265     attrib_container_t::iterator aend = AttribList.end();
00266     for ( ; abeg != aend; abeg++ )
00267       (*abeg)->getMessage(msg, numitems);
00268   }
00269 
00270   return numitems;
00271 }
00272 
00273 
00275 // retrieve particles from the given message and store them, also 
00276 // signaling we are creating the given number of particles.  Return the
00277 // number of particles created.
00278 template<class PLayout>
00279 size_t ParticleBase<PLayout>::getMessageAndCreate(Message& msg) {
00280   TAU_PROFILE("ParticleBase::getMessageAndCreate()", "unsigned (Message)",
00281               TAU_PARTICLE);
00282 
00283   // make sure we've been initialized
00284   PAssert(Layout != 0);
00285 
00286   // call the regular create, and add in the particles to our LocalNum
00287   size_t numcreate = getMessage(msg);
00288   LocalNum += numcreate;
00289   ADDIPPLSTAT(incParticlesCreated,numcreate);
00290   return numcreate;
00291 }
00292 
00293 
00295 // create M new particles on this processor
00296 template<class PLayout>
00297 void ParticleBase<PLayout>::create(size_t M) {
00298   TAU_PROFILE("ParticleBase::create()", "void (unsigned)", TAU_PARTICLE);
00299 
00300   // make sure we've been initialized
00301   PAssert(Layout != 0);
00302 
00303   // go through all the attributes, and allocate space for M new particles
00304   attrib_container_t::iterator abeg = AttribList.begin();
00305   attrib_container_t::iterator aend = AttribList.end();
00306   for ( ; abeg != aend; abeg++ )
00307     (*abeg)->create(M);
00308 
00309   // set the unique ID value for these new particles
00310   size_t i1 = LocalNum;
00311   size_t i2 = i1 + M;
00312   while (i1 < i2)
00313     ID[i1++] = getNextID();
00314 
00315   // remember that we're creating these new particles
00316   LocalNum += M;
00317   ADDIPPLSTAT(incParticlesCreated,M);
00318 }
00319 
00320 
00322 // create np new particles globally, equally distributed among all processors
00323 template<class PLayout>
00324 void ParticleBase<PLayout>::globalCreate(size_t np) {
00325   TAU_PROFILE("ParticleBase::globalCreate()", "void (unsigned)", TAU_PARTICLE);
00326 
00327   // make sure we've been initialized
00328   PAssert(Layout != 0);
00329 
00330   // Compute the number of particles local to each processor:
00331   unsigned nPE = IpplInfo::getNodes();
00332   unsigned npLocal = np/nPE;
00333 
00334   // Handle the case where np/nPE is not an integer:
00335   unsigned myPE = IpplInfo::myNode();
00336   unsigned rem = np - npLocal * nPE;
00337   if (myPE < rem) ++npLocal;
00338 
00339   // Now each PE calls the local ParticleBase::create() function to create it's
00340   // local number of particles:
00341   create(npLocal);
00342 }
00343 
00344 
00346 // delete M particles, starting with the Ith particle.  If the last argument
00347 // is true, the destroy will be done immediately, otherwise the request
00348 // will be cached.
00349 template<class PLayout>
00350 void ParticleBase<PLayout>::destroy(size_t M, size_t I, bool doNow) {
00351   TAU_PROFILE("ParticleBase::destroy()", 
00352     "void (unsigned, unsigned, bool)", TAU_PARTICLE);
00353 
00354   // make sure we've been initialized
00355   PAssert(Layout != 0);
00356 
00357   if (M > 0) {
00358     if (doNow) {
00359       // find out if we are using optimized destroy method
00360       bool optDestroy = getUpdateFlag(PLayout::OPTDESTROY);
00361       // loop over attributes and carry out the destroy request
00362       attrib_container_t::iterator abeg, aend = AttribList.end();
00363       for (abeg = AttribList.begin(); abeg != aend; ++abeg)
00364         (*abeg)->destroy(M,I,optDestroy);
00365       LocalNum -= M;
00366     }
00367     else {
00368       // add this group of particle indices to our list of items to destroy
00369       pair<size_t,size_t> destroyEvent(I,M);
00370       DestroyList.push_back(destroyEvent);
00371       DestroyNum += M;
00372     }
00373 
00374     // remember we have this many more items to destroy (or have destroyed)
00375     ADDIPPLSTAT(incParticlesDestroyed,M);
00376   }
00377 }
00378 
00379 
00381 // Update the particle object after a timestep.  This routine will change
00382 // our local, total, create particle counts properly.
00383 template<class PLayout>
00384 void ParticleBase<PLayout>::update() {
00385   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00386   TAU_PROFILE("ParticleBase::update()", taustr, TAU_PARTICLE);
00387 
00388   // make sure we've been initialized
00389   PAssert(Layout != 0);
00390 
00391   // ask the layout manager to update our atoms, etc.
00392   Layout->update(*this);
00393   INCIPPLSTAT(incParticleUpdates);
00394 }
00395 
00396 
00398 // Update the particle object after a timestep.  This routine will change
00399 // our local, total, create particle counts properly.
00400 template<class PLayout>
00401 void ParticleBase<PLayout>::update(const ParticleAttrib<char>& canSwap) {
00402   TAU_TYPE_STRING(taustr, CT(*this) + " void (ParticleAttrib<char>)"); 
00403   TAU_PROFILE("ParticleBase::update()", taustr, TAU_PARTICLE);
00404 
00405   // make sure we've been initialized
00406   PAssert(Layout != 0);
00407 
00408   // ask the layout manager to update our atoms, etc.
00409   Layout->update(*this, &canSwap);
00410   INCIPPLSTAT(incParticleUpdates);
00411 }
00412 
00413 
00414 // Actually perform the delete atoms action for all the attributes; the
00415 // calls to destroy() only stored a list of what to do.  This actually
00416 // does it.  This should in most cases only be called by the layout manager.
00417 template<class PLayout>
00418 void ParticleBase<PLayout>::performDestroy() {
00419   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00420   TAU_PROFILE("ParticleBase::performDestroy()", taustr, TAU_PARTICLE);
00421 
00422   // make sure we've been initialized
00423   PAssert(Layout != 0);
00424 
00425   // nothing to do if destroy list is empty
00426   if (DestroyList.empty()) return;
00427 
00428   // before processing the list, we should make sure it is sorted
00429   bool isSorted = true;
00430   typedef vector< pair<size_t,size_t> > dlist_t;
00431   dlist_t::const_iterator curr = DestroyList.begin(),
00432                           last = DestroyList.end();
00433   dlist_t::const_iterator next = curr + 1;
00434   while (next != last && isSorted) {
00435     if (*next++ < *curr++) isSorted = false;
00436   }
00437   if (!isSorted)
00438      ::sort(DestroyList.begin(),DestroyList.end());
00439  
00440   // find out if we are using optimized destroy method
00441   bool optDestroy = getUpdateFlag(PLayout::OPTDESTROY);
00442 
00443   // loop over attributes and process destroy list
00444   attrib_container_t::iterator abeg, aend = AttribList.end();
00445   for (abeg = AttribList.begin(); abeg != aend; ++abeg)
00446     (*abeg)->destroy(DestroyList,optDestroy);
00447 
00448   // clear destroy list and update destroy num counter
00449   DestroyList.erase(DestroyList.begin(),DestroyList.end());
00450   DestroyNum = 0;
00451 }
00452 
00453 
00455 // delete M ghost particles, starting with the Ith particle.
00456 // This is done immediately.
00457 template<class PLayout>
00458 void ParticleBase<PLayout>::ghostDestroy(size_t M, size_t I) {
00459   TAU_TYPE_STRING(taustr, CT(*this) + " void (unsigned, unsigned)"); 
00460   TAU_PROFILE("ParticleBase::ghostDestroy()", taustr, TAU_PARTICLE);
00461 
00462   // make sure we've been initialized
00463   PAssert(Layout != 0);
00464 
00465   if (M > 0) {
00466     // delete the data from the attribute containers
00467     size_t dnum = 0;
00468     attrib_container_t::iterator abeg = AttribList.begin();
00469     attrib_container_t::iterator aend = AttribList.end();
00470     for ( ; abeg != aend; ++abeg )
00471       dnum = (*abeg)->ghostDestroy(M, I);
00472     GhostNum -= dnum;
00473   }
00474 }
00475 
00476 
00478 // Put the data for M particles starting from local index I in a Message.
00479 // Return the number of particles put in the Message.  This is for building
00480 // ghost particle interaction lists.
00481 template<class PLayout>
00482 size_t
00483 ParticleBase<PLayout>::ghostPutMessage(Message &msg, size_t M, size_t I) {
00484   TAU_PROFILE("ParticleBase::ghostPutMessage()", 
00485               "unsigned (Message, unsigned, unsigned)", TAU_PARTICLE);
00486 
00487   // make sure we've been initialized
00488   PAssert(Layout != 0);
00489 
00490   // put into message the number of items in the message
00491   if (I >= R.size()) {
00492     // we're putting in ghost particles ...
00493     if ((I + M) > (R.size() + GhostNum))
00494       M = (R.size() + GhostNum) - I;
00495   } else {
00496     // we're putting in local particles ...
00497     if ((I + M) > R.size())
00498       M = R.size() - I;
00499   }
00500   msg.put(M);
00501 
00502   // go through all the attributes and put their data in the message
00503   if (M > 0) {
00504     attrib_container_t::iterator abeg = AttribList.begin();
00505     attrib_container_t::iterator aend = AttribList.end();
00506     for ( ; abeg != aend; abeg++ )
00507       (*abeg)->ghostPutMessage(msg, M, I);
00508   }
00509 
00510   return M;
00511 }
00512 
00513 
00515 // put the data for particles on a list into a Message, given list of indices
00516 // Return the number of particles put in the Message.  This is for building
00517 // ghost particle interaction lists.
00518 template<class PLayout>
00519 size_t
00520 ParticleBase<PLayout>::ghostPutMessage(Message &msg,
00521                                        const vector<size_t>& pl) {
00522   TAU_PROFILE("ParticleBase::ghostPutMessage()", 
00523               "unsigned (Message, vector<unsigned>)", TAU_PARTICLE);
00524 
00525   // make sure we've been initialized
00526   PAssert(Layout != 0);
00527 
00528   vector<size_t>::size_type M = pl.size();  
00529   msg.put(M);
00530 
00531   // go through all the attributes and put their data in the message
00532   if (M > 0) {
00533     attrib_container_t::iterator abeg = AttribList.begin();
00534     attrib_container_t::iterator aend = AttribList.end();
00535     for ( ; abeg != aend; ++abeg )
00536       (*abeg)->ghostPutMessage(msg, pl);
00537   }
00538 
00539   return M;
00540 }
00541 
00542 
00544 // retrieve particles from the given message and sending node and store them
00545 template<class PLayout>
00546 size_t
00547 ParticleBase<PLayout>::ghostGetMessage(Message& msg, int node) {
00548   TAU_TYPE_STRING(taustr, CT(*this) + " unsigned (Message, int)"); 
00549   TAU_PROFILE("ParticleBase::ghostGetMessage()", taustr, TAU_PARTICLE);
00550 
00551   // make sure we've been initialized
00552   PAssert(Layout != 0);
00553 
00554   // get the number of items in the message
00555   size_t numitems;
00556   msg.get(numitems);
00557   GhostNum += numitems;
00558 
00559   // go through all the attributes and get their data from the message
00560   if (numitems > 0) {
00561     attrib_container_t::iterator abeg = AttribList.begin();
00562     attrib_container_t::iterator aend = AttribList.end();
00563     for ( ; abeg != aend; abeg++ )
00564       (*abeg)->ghostGetMessage(msg, numitems);
00565   }
00566 
00567   return numitems;
00568 }
00569 
00570 
00572 // Apply the given sort-list to all the attributes.  The sort-list
00573 // may be temporarily modified, thus it must be passed by non-const ref.
00574 template<class PLayout>
00575 void ParticleBase<PLayout>::sort(SortList_t &sortlist) {
00576   attrib_container_t::iterator abeg = AttribList.begin();
00577   attrib_container_t::iterator aend = AttribList.end();
00578   for ( ; abeg != aend; ++abeg )
00579     (*abeg)->sort(sortlist);
00580 }
00581 
00582 
00584 // print it out
00585 template<class PLayout>
00586 ostream& operator<<(ostream& out, const ParticleBase<PLayout>& P) {
00587   TAU_TYPE_STRING(taustr, "ostream (ostream, " + CT(P) + " )" ); 
00588   TAU_PROFILE("operator<<()", taustr, TAU_PARTICLE | TAU_IO);
00589   out << "Particle object contents:";
00590   out << "\n  Total particles: " << P.getTotalNum();
00591   out << "\n  Local particles: " << P.getLocalNum();
00592   out << "\n  Attributes (including R and ID): " << P.numAttributes();
00593   out << "\n  Layout = " << P.getLayout();
00594   return out;
00595 }
00596 
00597 
00599 // print out debugging information
00600 template<class PLayout>
00601 void ParticleBase<PLayout>::printDebug(Inform& o) {
00602   TAU_PROFILE("printDebug()", "void (Inform)", TAU_PARTICLE | TAU_IO);
00603   o << "PBase: total = " << getTotalNum() << ", local = " << getLocalNum();
00604   o << ", attributes = " << AttribList.size() << endl;
00605   for (attrib_container_t::size_type i=0; i < AttribList.size(); ++i) {
00606     o << "    ";
00607     AttribList[i]->printDebug(o);
00608     o << endl;
00609   }
00610   o << "    ";
00611   Layout->printDebug(o);
00612 }
00613 
00614 
00615 /***************************************************************************
00616  * $RCSfile: ParticleBase.cpp,v $   $Author: adelmann $
00617  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:28 $
00618  * IPPL_VERSION_ID: $Id: ParticleBase.cpp,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $ 
00619  ***************************************************************************/

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