src/Particle/ParticleLayoutFromGrid.cpp

Go to the documentation of this file.
00001 //
00002 // C++ Implementation: ParticleLayoutFromGrid
00003 //
00004 // Description: 
00005 //
00006 //
00007 //
00008 // Author: Roman Geus <geus@maxwell>, (C) 2005
00009 //
00010 // Copyright: See COPYING file that comes with this distribution
00011 //
00012 #include <cassert>
00013 #include "ParticleLayoutFromGrid.h"
00014 
00015 void ParticleLayoutFromGrid::update(ParticleBase< ParticleLayoutFromGrid >& particles) {
00016     unsigned num_procs = Ippl::getNodes();
00017     unsigned my_id = Ippl::myNode();
00018     size_t num_my_particles   = particles.getLocalNum();
00019 
00020     // Delete particles in destroy list, update local num
00021     size_t num_destroyed_particles = particles.getDestroyNum();
00022     particles.performDestroy();
00023     num_my_particles -= num_destroyed_particles;
00024     
00025     // FIXME: This should be done in ParticleBase::performDestroy()
00026     particles.setLocalNum(num_my_particles);
00027 
00028     // Apply boundary conditions to the particle positions
00029     // apply_bconds(particles.R);
00030     
00031     // Redistribute particles, such that particles that have moved outside the 
00032     // local domain are moved to the corresponding processor.
00033     unsigned num_active_procs = grid_->give_number_of_active_processes();
00034     if (num_active_procs > 1)
00035         num_my_particles = redistribute_particles(particles);
00036         
00037     // Update total number of particles in particle container
00038     size_t num_total_particles;
00039     reduce(num_my_particles, num_total_particles, OpAddAssign());
00040     particles.setTotalNum(num_total_particles);
00041 }
00042 
00043 void ParticleLayoutFromGrid::apply_bconds(ParticlePos_t& R)
00044 {
00045     Inform msg("update");
00046     size_t num_my_particles = R.size();
00047     
00048     for (size_t ip = 0; ip < num_my_particles; ++ ip) {
00049         D3vector pos(R[ip](0), R[ip](1), R[ip](2));
00050         if (!geom_domain_->point_in_domain(pos)) {
00051             msg << "Particle " << ip << " moved outside domain." << endl;
00052         }
00053     }    
00054 }
00055 
00056 size_t ParticleLayoutFromGrid::redistribute_particles(ParticleBase< ParticleLayoutFromGrid >& particles) 
00057 {
00058     unsigned num_procs = Ippl::getNodes();
00059     unsigned my_id = Ippl::myNode();
00060     size_t num_my_particles = particles.getLocalNum();
00061     
00062     // FIXME: How do I test if I am an active processor?
00063     // FIXME: Assume that active processors are assigned the ids 0..num_active_procs-1.
00064     unsigned num_active_procs = grid_->give_number_of_active_processes();
00065 
00066     // Non-active processors return here!
00067     if (my_id >= num_active_procs)
00068         return num_my_particles;
00069     
00070     std::vector<D3vector> bb_min;
00071     std::vector<D3vector> bb_max;
00072     for (int p = 0; p < num_active_procs; ++ p) {
00073         double xmin[3], xmax[3];
00074         grid_->localbox(xmin, xmax, p);
00075         bb_min.push_back(D3vector(xmin[0], xmin[1], xmin[2]));
00076         bb_max.push_back(D3vector(xmax[0], xmax[1], xmax[2]));
00077     }
00078     // FIXME: Bounding boxes could be sorted, such that neighbors are close the beginning.
00079     // FIXME: Should the local bounding box be removed from this list?
00080     
00081     // num_active_procs Message objects
00082     std::vector<Message> messages(num_active_procs);
00083     // List of particles for each message
00084     std::vector<size_t>* put_list = new std::vector<size_t>[num_active_procs];
00085     
00086     for (size_t ip = 0; ip < num_my_particles; ++ ip) {
00087         D3vector pos(particles.R[ip][0], particles.R[ip][1], particles.R[ip][2]);
00088         
00089         if (!is_local_pos(pos)) 
00090         {
00091             // Particle has moved outside the local domain
00092             
00093             // Identify processor which should receive the particle (linear search)
00094             unsigned target_id = num_active_procs;
00095             for (unsigned p = 0; p < num_active_procs; ++ p) {
00096                 if (is_inside_box(bb_min[p], bb_max[p], pos)) {
00097                     target_id = p;
00098                     break;
00099                 }
00100             }
00101             assert(target_id != num_active_procs && target_id != my_id);
00102             put_list[target_id].push_back(ip);
00103             
00104             // Mark particle for deletion
00105             particles.destroy(1, ip);
00106         }      
00107     }
00108     
00109     // Send particles to their destination nodes
00110     int tag = Ippl::Comm->next_tag(P_SPATIAL_TRANSFER_TAG, P_LAYOUT_CYCLE);
00111     for (int p = 0; p < num_active_procs; ++ p) {
00112         if (p != my_id) {
00113             // Put data for particles on this put list into message and add sentinel
00114             particles.putMessage(messages[p], put_list[p]);
00115             particles.putMessage(messages[p], (size_t) 0, (size_t) 0);
00116             // Send message
00117             // Note: The last parameter is set to false, to prevent send() from destroying the Message object
00118             Ippl::Comm->send(&messages[p], p, tag, false);
00119         }
00120         put_list[p].clear();
00121     }
00122 
00123     // Delete sent particles.
00124     num_my_particles -= particles.getDestroyNum();
00125     particles.performDestroy();
00126     
00127     // FIXME: This should be done in ParticleBase::performDestroy()
00128     particles.setLocalNum(num_my_particles);
00129     
00130     // Receive particles
00131     unsigned sendnum = num_active_procs - 1;
00132     while (sendnum-- > 0) {
00133         int node = Communicate::COMM_ANY_NODE;
00134         Message *recmsg = Ippl::Comm->receive_block(node, tag);
00135         size_t recvd;
00136         size_t total_recvd = 0;
00137         while ((recvd = particles.getMessage(*recmsg)) > 0)
00138             total_recvd += recvd;
00139         num_my_particles += total_recvd;
00140         delete recmsg;
00141     }
00142     
00143     // FIXME: This should be done in ParticleBase::getMessage()
00144     particles.setLocalNum(num_my_particles);
00145     
00146     delete[] put_list;
00147     return num_my_particles;
00148 }

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