src/Particle/ParticleUniformLayout.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/ParticleUniformLayout.h"
00028 #include "Utility/IpplInfo.h"
00029 #include "Message/Communicate.h"
00030 #include "Message/Message.h"
00031 #include "Profile/Profiler.h"
00032 #include <stddef.h>
00033 
00034 
00036 // constructor
00037 // create storage for per-node data
00038 template<class T, unsigned Dim>
00039 ParticleUniformLayout<T, Dim>::ParticleUniformLayout() {
00040   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00041   TAU_PROFILE("ParticleUniformLayout::ParticleUniformLayout()", taustr, 
00042     TAU_PARTICLE);
00043   
00044   int N = Ippl::getNodes();
00045   LocalSize = new int[N];
00046   Change = new int[N];
00047   MsgCount = new int[N];
00048 }
00049 
00050 
00052 // destructor
00053 template<class T, unsigned Dim>
00054 ParticleUniformLayout<T, Dim>::~ParticleUniformLayout() {
00055   TAU_TYPE_STRING(taustr, CT(*this) + " void ()"); 
00056   TAU_PROFILE("ParticleUniformLayout::~ParticleUniformLayout()", taustr, 
00057     TAU_PARTICLE);
00058 
00059   delete [] LocalSize;
00060   delete [] Change;
00061   delete [] MsgCount;
00062 }
00063 
00064 
00066 // Update the location and indices of all atoms in the given ParticleBase
00067 // object.  This handles swapping particles among processors if
00068 // needed, and handles create and destroy requests.  When complete,
00069 // all nodes have correct layout information.
00070 template<class T, unsigned Dim>
00071 void ParticleUniformLayout<T, Dim>::update(
00072   ParticleBase< ParticleUniformLayout<T, Dim> >& PData,
00073   const ParticleAttrib<char>* canSwap) {
00074   TAU_TYPE_STRING(taustr, " void (" + CT(PData) + "ParticleAttrib<char>* )"); 
00075   TAU_PROFILE("ParticleUniformLayout::update()", taustr, 
00076     TAU_PARTICLE);
00077 
00078   int i, j;                     // loop variables
00079   int N = Ippl::getNodes();
00080   int myN = Ippl::myNode();
00081   size_t TotalNum   = PData.getTotalNum();
00082   size_t LocalNum   = PData.getLocalNum();
00083   size_t DestroyNum = PData.getDestroyNum();
00084   float Weight = 1.0 / (float)N;  // the fraction of the total particles
00085                                   // to go on each node
00086   // create Inform object for printing
00087   //Inform dbgmsg("UniformLayout", INFORM_ALL_NODES);
00088   //dbgmsg << "At start on node " << myN << ": local=" << LocalNum;
00089   //dbgmsg << ", total=" << TotalNum << ", destroy=" << DestroyNum << endl;
00090 
00091   // if we just have one node, this is simple: just create and destroy
00092   // particles we need to.
00093   if (N == 1) {
00094     // delete unsightly particles
00095     PData.performDestroy();
00096 
00097     // adjust local num
00098     LocalNum -= DestroyNum;
00099 
00100     // update particle counts
00101     PData.setTotalNum(LocalNum);
00102     PData.setLocalNum(LocalNum);
00103 
00104     return;
00105   }
00106 
00107   // data and tags for send/receive's
00108   int tag1 = Ippl::Comm->next_tag(P_WEIGHTED_LAYOUT_TAG, P_LAYOUT_CYCLE);
00109   int tag2 = Ippl::Comm->next_tag(P_WEIGHTED_RETURN_TAG, P_LAYOUT_CYCLE);
00110   int tag3 = Ippl::Comm->next_tag(P_WEIGHTED_TRANSFER_TAG, P_LAYOUT_CYCLE);
00111   int node, sendnum, recnum;
00112   int nodedata[3];
00113   Message *msg = 0;
00114 
00115   // perform tasks on client nodes
00116   if (myN != 0) {
00117     // step 1: forward our current size and delete requests
00118     // to master node
00119     nodedata[0] = LocalNum;
00120     nodedata[1] = DestroyNum;
00121     msg = new Message;
00122     msg->put(nodedata, nodedata + 2);
00123     //dbgmsg << "Sending to parent: LocalNum=" << nodedata[0];
00124     //dbgmsg << ", DestroyNum=" << nodedata[1] << endl;
00125     Ippl::Comm->send(msg, 0, tag1);
00126 
00127   } else {                      // do update tasks particular to node 0
00128 
00129     //
00130     // step 1: get info on requests from client nodes
00131     //
00132 
00133     // fill in data on the size, etc. of node 0
00134     LocalSize[0] = LocalNum - DestroyNum;
00135     TotalNum = LocalSize[0];
00136     //dbgmsg << "Master initially has TotalNum = " << TotalNum << endl;
00137 
00138     // receive messages from other nodes describing what they have
00139     int notrecvd = N - 1;       // do not need to receive from node 0
00140     while (notrecvd > 0) {
00141       // receive a message from another node.  After recv, node == sender.
00142       node = Communicate::COMM_ANY_NODE;
00143       msg = Ippl::Comm->receive_block(node, tag1);
00144       msg->get(nodedata);
00145       delete msg;
00146 
00147       // fill in data on the size, etc. of other nodes
00148       LocalSize[node] = nodedata[0] - nodedata[1];
00149       TotalNum += LocalSize[node];
00150       //dbgmsg << "Master received local[" << node << "] = " << LocalSize[node];
00151       //dbgmsg << ", new TotalNum = " << TotalNum << endl;
00152       notrecvd--;
00153     }
00154 
00155     // now calculate how many particles go on each node
00156     if (getUpdateFlag(ParticleLayout<T,Dim>::SWAP)) {
00157       int accounted = 0;
00158       for (i = 0; i < N; i++) {
00159         Change[i] = (int)((float)TotalNum * Weight);
00160         accounted += Change[i];
00161       }
00162       accounted -= TotalNum;
00163       if (accounted < 0) {
00164         while (accounted != 0) {
00165           Change[(-accounted) % N]++;
00166           accounted++;
00167         }
00168       } else {
00169         int whichnode = 0;
00170         while (accounted != 0) {
00171           if (Change[whichnode] > 0) {
00172             Change[whichnode]--;
00173             accounted--;
00174           }
00175           whichnode = (whichnode + 1) % N;
00176         }
00177       }
00178       for (i = 0; i < N; i++) {
00179         Change[i] = Change[i] - LocalSize[i];
00180         MsgCount[i] = Change[i];
00181       }
00182     } else {
00183       for (i = 0; i < N; i++) {
00184         Change[i] = MsgCount[i] = 0;
00185       }
00186     }
00187 
00188     // send out instructions to all nodes, while calculating what goes where
00189     for (i = 0; i < N; i++) {
00190       // put header info into the message
00191       nodedata[0] = TotalNum;     // new total number of particles
00192       if (Change[i] <= 0) {       // if the change is < 0, send out particles
00193         nodedata[1] = -Change[i]; // number of particles to send
00194         nodedata[2] = 0;          // number of particles to receive
00195       }
00196       else {                      // if the change is > 0, receive particles
00197         nodedata[1] = 0;          // number of particles to send
00198         nodedata[2] = Change[i];  // number of particles to receive
00199       }
00200       msg = new Message;
00201       msg->put(nodedata, nodedata + 3);
00202 
00203       // if we must send out particles to other nodes
00204       // put info on where to send into the message
00205       if (Change[i] <= 0) {
00206         for (j = 0; j < N && MsgCount[i] < 0; j++) {
00207           if (j != i && MsgCount[j] > 0) {
00208             nodedata[0] = j;
00209             if ((-MsgCount[i]) > MsgCount[j])
00210               nodedata[1] = MsgCount[j];
00211             else
00212               nodedata[1] = -MsgCount[i];
00213             MsgCount[i] += nodedata[1];
00214             MsgCount[j] -= nodedata[1];
00215             msg->put(nodedata, nodedata + 2);
00216           }
00217         }
00218       }
00219 
00220       Ippl::Comm->send(msg, i, tag2);
00221     }
00222   }
00223 
00224   // step 2: retrieve instructions on what to create, and what to send/rec
00225   node = Communicate::COMM_ANY_NODE;
00226   // dbgmsg << "Receiving instructions ..." << endl;
00227   msg = Ippl::Comm->receive_block(node, tag2);
00228   msg->get(nodedata);
00229   TotalNum = nodedata[0];       // new total number of particles
00230   sendnum = nodedata[1];        // how many particles to send out
00231   recnum = nodedata[2];         // how many particles to receive
00232   //dbgmsg << "Received new TotalNum=" << TotalNum << ", sendnum=" << sendnum;
00233   //dbgmsg << ", recnum=" << recnum << endl;
00234 
00235   // step 3: delete unwanted particles, update local num
00236   PData.performDestroy();
00237   LocalNum -= DestroyNum;
00238 
00239   // step 4: send out particles which need to be sent.  In this case,
00240   // we just respond to the instructions from the master node, and
00241   // take particles from the end of our list
00242   if (canSwap==0) {
00243     while (sendnum > 0) {
00244       // get number of particles to send, and where
00245       msg->get(nodedata);       // node, number of particles
00246       LocalNum -= nodedata[1];
00247       sendnum -= nodedata[1];
00248 
00249       //dbgmsg << "Sending " << nodedata[1] << " particles to node ";
00250       //dbgmsg << nodedata[0] << endl;
00251 
00252       // put the particles in a new message
00253       Message *sendmsg = new Message;
00254       PData.putMessage(*sendmsg, nodedata[1], LocalNum);
00255       Ippl::Comm->send(sendmsg, nodedata[0], tag3);
00256 
00257       // After putting particles in the message, we can delete them.
00258       PData.destroy(nodedata[1], LocalNum, true);
00259     }
00260   }
00261   else {
00262     while (sendnum > 0) {
00263       // get number of particles to send, and where
00264       msg->get(nodedata);       // node, number of particles
00265 
00266       // put the particles in a new message
00267       Message *sendmsg = new Message;
00268       int delpart = LocalNum-1;
00269       for (int ip=0; ip<nodedata[1]; ip++) {
00270         while ( !(bool((*canSwap)[delpart])) ) { --delpart; }
00271         PData.putMessage(*sendmsg, 1, delpart);
00272         // After putting particles in the message, we can delete them.
00273         PData.destroy(1, delpart, true);
00274       }
00275       LocalNum -= nodedata[1];
00276       sendnum -= nodedata[1];
00277 
00278       //dbgmsg << "Sending " << nodedata[1] << " particles to node ";
00279       //dbgmsg << nodedata[0] << endl;
00280 
00281       Ippl::Comm->send(sendmsg, nodedata[0], tag3);
00282     }
00283   }
00284 
00285   // we no longer need the message from node 0 telling us what to do
00286   delete msg;
00287 
00288   // step 5: receive particles, add them to our list
00289   while (recnum > 0) {
00290     // receive next message with particle data for us
00291     node = Communicate::COMM_ANY_NODE;
00292     // dbgmsg<< "Receiving particles (" << recnum << " yet to arrive)" << endl;
00293     msg = Ippl::Comm->receive_block(node, tag3);
00294     int recvamt = PData.getMessage(*msg);
00295     delete msg;
00296 
00297     //dbgmsg << "Received " << recvamt << " particles" << endl;
00298     LocalNum += recvamt;
00299     recnum -= recvamt;
00300   }
00301 
00302   // finally, update our particle number counts
00303   PData.setTotalNum(TotalNum);  // set the total atom count
00304   PData.setLocalNum(LocalNum);  // set the number of local atoms
00305 }
00306 
00307 
00309 // print it out
00310 template<class T, unsigned Dim>
00311 inline
00312 ostream& operator<<(ostream& out, const ParticleUniformLayout<T,Dim>& L) {
00313   TAU_TYPE_STRING(taustr, "ostream (ostream, " + CT(L) + " )"); 
00314   TAU_PROFILE("ParticleBase::singleInitNode()", taustr, 
00315     TAU_PARTICLE | TAU_IO);
00316   out << "ParticleUniformLayout" << endl;
00317   return out;
00318 }
00319 
00320 
00322 // print out debugging information
00323 template<class T, unsigned Dim>
00324 void ParticleUniformLayout<T, Dim>::printDebug(Inform& o) {
00325   TAU_PROFILE("ParticleUniformLayout::printDebug()", "void (Inform)", 
00326     TAU_PARTICLE | TAU_IO);
00327 
00328   o << "ParticleUniformLayout";
00329 }
00330 
00331 
00332 /***************************************************************************
00333  * $RCSfile: addheaderfooter,v $   $Author: adelmann $
00334  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:17 $
00335  * IPPL_VERSION_ID: $Id: addheaderfooter,v 1.1.1.1 2003/01/23 07:40:17 adelmann Exp $ 
00336  ***************************************************************************/
00337 

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