src/Particle/ParticleSpatialLayout.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/ParticleSpatialLayout.h"
00028 #include "Particle/ParticleBConds.h"
00029 #include "Index/NDIndex.h"
00030 #include "Region/RegionLayout.h"
00031 #include "Message/Communicate.h"
00032 #include "Message/Message.h"
00033 #include "Utility/IpplInfo.h"
00034 #include "Utility/IpplStats.h"
00035 #include "Profile/Profiler.h"
00036 
00037 // forward declarations
00038 template <unsigned Dim> class FieldLayout;
00039 class UserList;
00040 
00042 // constructor, from a FieldLayout
00043 template < class T, unsigned Dim, class Mesh >
00044 ParticleSpatialLayout<T,Dim,Mesh>::ParticleSpatialLayout(FieldLayout<Dim>& fl)
00045   : RLayout(fl) {
00046   TAU_TYPE_STRING(taustr, CT(*this) + " void (" + CT(fl) + " )" ); 
00047   TAU_PROFILE("ParticleSpatialLayout::ParticleSpatialLayout()", taustr, 
00048     TAU_PARTICLE);
00049 
00050   setup();                      // perform necessary setup 
00051 }
00052 
00053 
00055 // constructor, from a FieldLayout
00056 template < class T, unsigned Dim, class Mesh >
00057 ParticleSpatialLayout<T,Dim,Mesh>::ParticleSpatialLayout(FieldLayout<Dim>& fl,
00058   Mesh& mesh)
00059   : RLayout(fl,mesh) {
00060   TAU_TYPE_STRING(taustr, "void (" + CT(fl) + ", " + CT(mesh) + " )" ); 
00061   TAU_PROFILE("ParticleSpatialLayout::ParticleSpatialLayout()", taustr, 
00062     TAU_PARTICLE);
00063   setup();                      // perform necessary setup 
00064 }
00065 
00066 
00068 // constructor, from a RegionLayout
00069 template < class T, unsigned Dim, class Mesh >
00070 ParticleSpatialLayout<T,Dim,Mesh>::ParticleSpatialLayout(const
00071   RegionLayout<T,Dim,Mesh>& rl) : RLayout(rl) {
00072   TAU_TYPE_STRING(taustr, "void (" + CT(rl) + " )" ); 
00073   TAU_PROFILE("ParticleSpatialLayout::ParticleSpatialLayout()", taustr, 
00074     TAU_PARTICLE);
00075 
00076   setup();                      // perform necessary setup 
00077 }
00078 
00079 
00081 // default constructor ... this does not initialize the RegionLayout,
00082 // it will be instead initialized during the first update.
00083 template < class T, unsigned Dim, class Mesh >
00084 ParticleSpatialLayout<T,Dim,Mesh>::ParticleSpatialLayout() : RLayout() {
00085   TAU_TYPE_STRING(taustr, CT(*this) + " void ()");
00086   TAU_PROFILE("ParticleSpatialLayout::ParticleSpatialLayout()", taustr, 
00087     TAU_PARTICLE);
00088 
00089   setup();                      // perform necessary setup 
00090 }
00091 
00092 
00094 // perform common constructor tasks
00095 template < class T, unsigned Dim, class Mesh >
00096 void ParticleSpatialLayout<T,Dim,Mesh>::setup() {
00097   TAU_TYPE_STRING(taustr, CT(*this) + " void ()");
00098   TAU_PROFILE("ParticleSpatialLayout::setup()", taustr, TAU_PARTICLE);
00099 
00100   unsigned i;                   // loop variable
00101 
00102   // check ourselves in as a user of the RegionLayout
00103   RLayout.checkin(*this);
00104 
00105   // create storage for message pointers used in swapping particles
00106   unsigned N = Ippl::getNodes();
00107   SwapMsgList = new Message*[N];
00108   for (i = 0; i < Dim; ++i)
00109     SwapNodeList[i] = new bool[N];
00110   PutList = new vector<size_t>[N];
00111 
00112   // create storage for the number of particles on each node
00113   // and flag for empty node domain
00114   NodeCount = new size_t[N];
00115   EmptyNode = new bool[N];
00116   for (i = 0; i < N; ++i) {
00117     NodeCount[i] = 0;
00118     EmptyNode[i] = false;
00119   }
00120 
00121   // recalculate which nodes are our neighbors in each dimension
00122   if (RLayout.initialized())
00123     rebuild_neighbor_data();
00124 }
00125 
00126 
00128 // destructor
00129 template < class T, unsigned Dim, class Mesh >
00130 ParticleSpatialLayout<T,Dim,Mesh>::~ParticleSpatialLayout() {
00131   TAU_TYPE_STRING(taustr, CT(*this) + " void ()");
00132   TAU_PROFILE("ParticleSpatialLayout::~ParticleSpatialLayout()", taustr,
00133     TAU_PARTICLE);
00134 
00135   int i;
00136 
00137   delete [] NodeCount;
00138   delete [] EmptyNode;
00139   delete [] SwapMsgList;
00140   for (i=0; i < Dim; i++)
00141     delete [] (SwapNodeList[i]);
00142   delete [] PutList;
00143 
00144   // check ourselves out as a user of the RegionLayout
00145   RLayout.checkout(*this);
00146 }
00147 
00148 
00149 
00150 
00152 // for each dimension, calculate where neighboring Vnodes and physical
00153 // nodes are located, and create a list of this data.  This need only
00154 // be updated when the layout changes.
00155 template < class T, unsigned Dim, class Mesh >
00156 void ParticleSpatialLayout<T,Dim,Mesh>::rebuild_neighbor_data() {
00157   TAU_TYPE_STRING(taustr, CT(*this) + " void ()" );
00158   TAU_PROFILE("ParticleSpatialLayout::rebuild_neighbor_data()", taustr, 
00159     TAU_PARTICLE);
00160 
00161   int d, j;                     // loop variables
00162   unsigned N = Ippl::getNodes();
00163   unsigned myN = Ippl::myNode();
00164 
00165 
00166   // initialize the message list and initial node count
00167   for (d = 0; d < Dim; ++d) {
00168     NeighborNodes[d] = 0;
00169     for (j = 0; j < N; j++)
00170       SwapNodeList[d][j] = false;
00171   }
00172 
00173   // local Rnode iterators
00174   typename RegionLayout<T,Dim,Mesh>::iterator_iv localVN, endLocalVN = RLayout.end_iv();
00175 
00176   // check for no local Rnodes
00177   if (RLayout.begin_iv() == endLocalVN) {
00178     EmptyNode[myN] = true;
00179   }      
00180   else {
00181     // we need to consider each spatial dimension separately
00182     for (d = 0; d < Dim; ++d) {
00183       // determine number of neighbor nodes in this spatial dimension
00184       for (localVN = RLayout.begin_iv(); localVN != endLocalVN; ++localVN) {
00185         // for each local Vnode, the domain to check equals the local Vnode dom
00186         // except for current dimension, which is the total Field domain size
00187         NDRegion<T,Dim> chkDom((*localVN).second->getDomain());
00188         chkDom[d] = (RLayout.getDomain())[d];
00189 
00190         // use the RegionLayout to find all remote Vnodes which touch the
00191         // domain being checked here
00192         typename RegionLayout<T,Dim,Mesh>::touch_range_dv touchingVN =
00193           RLayout.touch_range_rdv(chkDom);
00194         typename RegionLayout<T,Dim,Mesh>::touch_iterator_dv tVN = touchingVN.first;
00195         for ( ; tVN != touchingVN.second; ++tVN) {
00196           // note that we need to send a message to the node which contains
00197           // this remote Vnode
00198           unsigned vn = ((*tVN).second)->getNode();
00199           if ( ! SwapNodeList[d][vn] ) {
00200             SwapNodeList[d][vn] = true;
00201             NeighborNodes[d]++;
00202           }
00203         }
00204       }
00205     }
00206   }
00207 
00208   // there is extra work to do if there are multipple nodes, to distribute
00209   // the particle layout data to all nodes
00210   if (N > 1) {
00211     // At this point, we can send our domain status to node 0, and
00212     // receive back the complete domain status.
00213     int tag1 = Ippl::Comm->next_tag(P_SPATIAL_LAYOUT_TAG, P_LAYOUT_CYCLE);
00214     int tag2 = Ippl::Comm->next_tag(P_SPATIAL_RETURN_TAG, P_LAYOUT_CYCLE);
00215     Message *msg1, *msg2;
00216     if (myN != 0) {
00217       msg1 = new Message;
00218       // put local domain status in the message
00219       msg1->put(EmptyNode[myN]);
00220       // send this info to node 0
00221       int node = 0;
00222       Ippl::Comm->send(msg1, node, tag1);
00223 
00224       // receive back the complete domain status
00225       msg2 = Ippl::Comm->receive_block(node, tag2);
00226       msg2->get(EmptyNode);
00227       delete msg2;
00228     }
00229     else {                      // do update tasks particular to node 0
00230       // receive messages from other nodes describing their domain status
00231       int notrecvd = N - 1;     // do not need to receive from node 0
00232       while (notrecvd > 0) {
00233         // receive a message from another node.  After recv, node == sender.
00234         int node = Communicate::COMM_ANY_NODE;
00235         msg1 = Ippl::Comm->receive_block(node, tag1);
00236         msg1->get(EmptyNode[node]);
00237         delete msg1;
00238         notrecvd--;
00239       }
00240 
00241       // send info back to all the client nodes
00242       msg2 = new Message;
00243       msg2->put(EmptyNode, EmptyNode+N);
00244       Ippl::Comm->broadcast_others(msg2, tag2);
00245     }
00246   }
00247 
00248   // fix-up for empty nodes
00249   if (EmptyNode[myN]) {
00250     // node with empty domain treats all non-empty nodes as neighbor
00251     // nodes along dimension 0
00252     for (j = 0; j < N; ++j) {
00253       if (!EmptyNode[j]) {
00254         SwapNodeList[0][j] = true;
00255         NeighborNodes[0]++;
00256       }
00257     }
00258   }
00259 
00260   return;
00261 }
00262 
00263 
00265 // Update the location and indices of all atoms in the given ParticleBase
00266 // object.  This handles swapping particles among processors if
00267 // needed, and handles create and destroy requests.  When complete,
00268 // all nodes have correct layout information.
00269 template <class T, unsigned Dim, class Mesh>
00270 void ParticleSpatialLayout<T,Dim,Mesh>::update(
00271        ParticleBase< ParticleSpatialLayout<T,Dim,Mesh> >& PData,
00272        const ParticleAttrib<char>* canSwap) {
00273 
00274   TAU_TYPE_STRING(taustr, "void (" + CT(PData) + ", ParticleAttrib<char>* )"); 
00275   TAU_PROFILE("ParticleSpatialLayout::update()", taustr, TAU_PARTICLE);
00276 
00277   unsigned N = Ippl::getNodes();
00278   unsigned myN = Ippl::myNode();
00279   size_t LocalNum   = PData.getLocalNum();
00280   size_t DestroyNum = PData.getDestroyNum();
00281   size_t TotalNum;
00282   int node;
00283 
00284 //  Inform dbgmsg("SpatialLayout::update", INFORM_ALL_NODES);
00285   //dbgmsg << "At start of update:" << endl;
00286   //PData.printDebug(dbgmsg);
00287 
00288   // delete particles in destroy list, update local num
00289   PData.performDestroy();
00290   LocalNum -= DestroyNum;
00291 
00292   // set up our layout, if not already done ... we could also do this if
00293   // we needed to expand our spatial region.
00294   if ( ! RLayout.initialized())
00295     rebuild_layout(LocalNum,PData);
00296 
00297   // apply boundary conditions to the particle positions
00298   if (getUpdateFlag(ParticleLayout<T,Dim>::BCONDS))
00299     apply_bconds(LocalNum, PData.R, this->getBConds(), RLayout.getDomain());
00300 
00301   // swap particles, if necessary
00302   if (N > 1 && getUpdateFlag(ParticleLayout<T,Dim>::SWAP)) {
00303     // Now we can swap particles that have moved outside the region of
00304     // local field space.  This is done in several passes, one for each
00305     // spatial dimension.  The NodeCount values are updated by this routine.
00306     if (canSwap==0) 
00307       LocalNum = swap_particles(LocalNum, PData);
00308     else
00309       LocalNum = swap_particles(LocalNum, PData, *canSwap);
00310   }
00311 
00312   // Save how many local particles we have.
00313   TotalNum = NodeCount[myN] = LocalNum;
00314 
00315   // there is extra work to do if there are multipple nodes, to distribute
00316   // the particle layout data to all nodes
00317   if (N > 1) {
00318     // At this point, we can send our particle count updates to node 0, and
00319     // receive back the particle layout.
00320     int tag1 = Ippl::Comm->next_tag(P_SPATIAL_LAYOUT_TAG, P_LAYOUT_CYCLE);
00321     int tag2 = Ippl::Comm->next_tag(P_SPATIAL_RETURN_TAG, P_LAYOUT_CYCLE);
00322     if (myN != 0) {
00323       Message *msg = new Message;
00324 
00325       // put local particle count in the message
00326       msg->put(LocalNum);
00327       // send this info to node 0
00328       Ippl::Comm->send(msg, 0, tag1);
00329 
00330       // receive back the number of particles on each node
00331       node = 0;
00332       Message* recmsg = Ippl::Comm->receive_block(node, tag2);
00333       recmsg->get(NodeCount);
00334       recmsg->get(TotalNum);
00335       delete recmsg;
00336     }
00337     else {                      // do update tasks particular to node 0
00338       // receive messages from other nodes describing what they have
00339       int notrecvd = N - 1;     // do not need to receive from node 0
00340       TotalNum = LocalNum;
00341       while (notrecvd > 0) {
00342         // receive a message from another node.  After recv, node == sender.
00343         node = Communicate::COMM_ANY_NODE;
00344         Message *recmsg = Ippl::Comm->receive_block(node, tag1);
00345         size_t remNodeCount = 0;
00346         recmsg->get(remNodeCount);
00347         delete recmsg;
00348         notrecvd--;
00349 
00350         // update values based on data from remote node
00351         TotalNum += remNodeCount;
00352         NodeCount[node] = remNodeCount;
00353       }
00354 
00355       // send info back to all the client nodes
00356       Message *msg = new Message;
00357       msg->put(NodeCount, NodeCount + N);
00358       msg->put(TotalNum);
00359       Ippl::Comm->broadcast_others(msg, tag2);
00360     }
00361   }
00362 
00363   // update our particle number counts
00364   PData.setTotalNum(TotalNum);  // set the total atom count
00365   PData.setLocalNum(LocalNum);  // set the number of local atoms
00366 
00367   //dbgmsg << endl << "At end of update:" << endl;
00368   //PData.printDebug(dbgmsg);
00369 }
00370 
00371 
00372 
00373 
00374 
00376 // print it out
00377 template < class T, unsigned Dim, class Mesh >
00378 ostream& operator<<(ostream& out, const ParticleSpatialLayout<T,Dim,Mesh>& L) {
00379   TAU_TYPE_STRING(taustr, "ostream& (ostream&, " + CT(L) + " )"); 
00380   TAU_PROFILE("ParticleSpatialLayout::operator<<()", taustr, 
00381     TAU_PARTICLE | TAU_IO);
00382 
00383   out << "ParticleSpatialLayout, with particle distribution:\n    ";
00384   for (unsigned int i=0; i < Ippl::getNodes(); ++i)
00385     out << "Number of particles " << L.getNodeCount(i) << "  ";
00386   out << "\nSpatialLayout decomposition = " << L.getLayout();
00387   return out;
00388 }
00389 
00390 
00392 // Print out information for debugging purposes.
00393 template < class T, unsigned Dim, class Mesh >
00394 void ParticleSpatialLayout<T,Dim,Mesh>::printDebug(Inform& o) {
00395   TAU_PROFILE("ParticleSpatialLayout::printDebug()", "void (Inform)", 
00396     TAU_PARTICLE | TAU_IO);
00397 
00398   o << "PSpatial: distrib = ";
00399   for (int i=0; i < Ippl::getNodes(); ++i)
00400     o << NodeCount[i] << "  ";
00401 }
00402 
00403 
00405 // Repartition onto a new layout, if the layout changes ... this is a
00406 // virtual function called by a UserList, as opposed to the RepartitionLayout
00407 // function used by the particle load balancing mechanism.
00408 template < class T, unsigned Dim, class Mesh >
00409 void ParticleSpatialLayout<T,Dim,Mesh>::Repartition(UserList* userlist) {
00410   TAU_TYPE_STRING(taustr, "void (UserList *)");
00411   TAU_PROFILE("ParticleSpatialLayout::Repartition()", taustr, TAU_PARTICLE);
00412 
00413   // perform actions to restructure our data due to a change in the
00414   // RegionLayout
00415   if (userlist->getUserListID() == RLayout.get_Id()) {
00416     //Inform dbgmsg("ParticleSpatialLayout::Repartition", INFORM_ALL_NODES);
00417     //dbgmsg << "Repartitioning due to change in RegionLayout ..." << endl;
00418 
00419     // recalculate which nodes are our neighbors in each dimension
00420     rebuild_neighbor_data();
00421   }
00422 }
00423 
00424 
00426 // Tell the subclass that the FieldLayoutBase is being deleted, so
00427 // don't use it anymore
00428 template < class T, unsigned Dim, class Mesh >
00429 void ParticleSpatialLayout<T,Dim,Mesh>::notifyUserOfDelete(UserList*) {
00430   TAU_TYPE_STRING(taustr, "void (UserList *)");
00431   TAU_PROFILE("ParticleSpatialLayout::notifyUserOfDelete()", taustr,
00432               TAU_PARTICLE);
00433 
00434   // really, nothing to do, since the RegionLayout we use only gets
00435   // deleted when we are deleted ourselves.
00436   return;
00437 }
00438 
00439 
00440 /***************************************************************************
00441  * $RCSfile: ParticleSpatialLayout.cpp,v $   $Author: adelmann $
00442  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:29 $
00443  * IPPL_VERSION_ID: $Id: ParticleSpatialLayout.cpp,v 1.1.1.1 2003/01/23 07:40:29 adelmann Exp $ 
00444  ***************************************************************************/

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