src/Particle/ParticleAttrib.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/ParticleAttrib.h"
00028 #include "Field/Field.h"
00029 #include "Field/LField.h"
00030 #include "Message/Message.h"
00031 #include "Utility/IpplInfo.h"
00032 #include "Utility/PAssert.h"
00033 #include "Utility/IpplStats.h"
00034 #include "AppTypes/AppTypeTraits.h"
00035 #include "Profile/Profiler.h"
00036 
00037 
00039 // Create a ParticleAttribElem to allow the user to access just the Nth
00040 // element of the attribute stored here.
00041 template <class T>
00042 ParticleAttribElem<T,1U>
00043 ParticleAttrib<T>::operator()(unsigned i) {
00044   PInsist(AppTypeTraits<T>::ElemDim > 0,
00045           "No operator()(unsigned) for this element type!!");
00046   return ParticleAttribElem<T,1U>(*this, vec<unsigned,1U>(i));
00047 }
00048 
00049 
00051 // Same as above, but specifying two indices
00052 template <class T>
00053 ParticleAttribElem<T,2U>
00054 ParticleAttrib<T>::operator()(unsigned i, unsigned j) {
00055   PInsist(AppTypeTraits<T>::ElemDim > 1,
00056           "No operator()(unsigned,unsigned) for this element type!!");
00057   return ParticleAttribElem<T,2U>(*this, vec<unsigned,2U>(i,j));
00058 }
00059 
00060 
00062 // Same as above, but specifying three indices
00063 template <class T>
00064 ParticleAttribElem<T,3U>
00065 ParticleAttrib<T>::operator()(unsigned i, unsigned j, unsigned k) {
00066   PInsist(AppTypeTraits<T>::ElemDim > 2,
00067           "No operator()(unsigned,unsigned,unsigned) for this element type!!");
00068   return ParticleAttribElem<T,3U>(*this, vec<unsigned,3U>(i,j,k));
00069 }
00070 
00071 
00073 // Create storage for M particle attributes.  The storage is uninitialized.
00074 // New items are appended to the end of the array.
00075 template<class T>
00076 void ParticleAttrib<T>::create(size_t M) {
00077   TAU_PROFILE("ParticleAttrib::create()", "void (unsigned)", TAU_PARTICLE);
00078   // make sure we have storage for M more items
00079   // and push back M items, using default value
00080   if (M > 0)
00081     ParticleList.insert(ParticleList.end(), M, T());
00082 }
00083 
00084 
00086 // Delete the attribute storage for M particle attributes, starting at
00087 // the position I.  Boolean flag indicates whether to use optimized 
00088 // destroy method.  This function really erases the data, which will
00089 // change local indices of the data.  The optimized method just copies
00090 // data from the end of the storage into the selected block.  Otherwise,
00091 // we use the std::vector erase method, which preserves data ordering.
00092 
00093 template<class T>
00094 void ParticleAttrib<T>::destroy(size_t M, size_t I, bool optDestroy) {
00095   TAU_PROFILE("ParticleAttrib::destroy()", "void (unsigned, unsigned, bool)", TAU_PARTICLE);
00096 
00097   if (M == 0) return;
00098   if (optDestroy) {
00099     // get iterators for where the data to be deleted begins, and where
00100     // the data we copy from the end begins
00101     typename ParticleList_t::iterator putloc = ParticleList.begin() + I;
00102     typename ParticleList_t::iterator getloc = ParticleList.end() - M;
00103     typename ParticleList_t::iterator endloc = ParticleList.end();
00104 
00105     // make sure we do not copy too much
00106     if ((I + M) > (ParticleList.size() - M))
00107       getloc = putloc + M;
00108 
00109     // copy over the data
00110     while (getloc != endloc)
00111       *putloc++ = *getloc++;
00112     // delete the last M items
00113     ParticleList.erase(endloc - M, endloc);
00114   }
00115   else {
00116     // just use the erase method
00117     typename ParticleList_t::iterator loc = ParticleList.begin() + I;
00118     ParticleList.erase(loc, loc + M);
00119   }
00120   return;
00121 }
00122 
00123 
00125 // Delete the attribute storage for a list of particle destroy events
00126 // This really erases the data, which will change local indices
00127 // of the data.  If we are using the optimized destroy method,
00128 // this just copies data from the end of the storage into the selected
00129 // block.  Otherwise, we use a leading/trailing iterator semantic to
00130 // copy data from below and  preserve data ordering.
00131 
00132 template <class T>
00133 void ParticleAttrib<T>::destroy(const vector< pair<size_t,size_t> >& dlist,
00134                                 bool optDestroy)
00135 {
00136   TAU_PROFILE("ParticleAttrib::destroy()", "void (vector< pair<unsigned,unsigned> >, bool)", TAU_PARTICLE); 
00137 
00138   if (dlist.empty()) return;
00139   typedef vector< pair<size_t,size_t> > dlist_t;
00140   if (optDestroy) {
00141     // process list in reverse order, since we are backfilling
00142     dlist_t::const_reverse_iterator rbeg, rend = dlist.rend();
00143     // find point to copy data from
00144     typename ParticleList_t::iterator putloc, saveloc;
00145     typename ParticleList_t::iterator getloc = ParticleList.end();
00146     typename ParticleList_t::iterator endloc = ParticleList.end();
00147     // loop over destroy list and copy data from end of particle list
00148     size_t I, M, numParts=0;
00149     for (rbeg = dlist.rbegin(); rbeg != rend; ++rbeg) {
00150       I = (*rbeg).first;   // index number to begin destroy
00151       M = (*rbeg).second;  // number of particles to destroy
00152       numParts += M;       // running total of number of particles destroyed
00153       // set iterators for data copy
00154       putloc = ParticleList.begin() + I;
00155       // make sure we do not copy too much
00156       if ((I + M) > ((getloc - ParticleList.begin()) - M)) {
00157         // we cannot fill all M slots
00158         saveloc = getloc;  // save endpoint of valid particle data
00159         getloc = putloc + M;  // move to just past end of section to delete
00160         // copy over the data
00161         while (getloc != saveloc) {
00162           *putloc++ = *getloc++;
00163         }
00164         // reset getloc for next copy
00165         getloc = putloc;  // set to end of last copy
00166       }
00167       else {
00168         // fill all M slots using data from end of particle list
00169         getloc = getloc - M;
00170         saveloc = getloc;  // save new endpoint of valid particle data
00171         // copy over the data
00172         for (size_t m=0; m<M; ++m)
00173           *putloc++ = *getloc++;
00174         // reset getloc for next copy
00175         getloc = saveloc;  // set to new endpoint of valid particle data
00176       }
00177     }
00178     // delete storage at end of particle list
00179     ParticleList.erase( endloc - numParts, endloc );
00180   }
00181   else {
00182     // just process destroy list using leading/trailing iterators
00183     dlist_t::const_iterator dnext = dlist.begin(), dend = dlist.end();
00184     size_t putIndex, getIndex, endIndex = ParticleList.size();
00185     putIndex = (*dnext).first;  // first index to delete
00186     getIndex = putIndex + (*dnext).second;  // move past end of destroy event
00187     ++dnext;  // move to next destroy event
00188     // make sure getIndex is not pointing to a deleted particle
00189     while (dnext != dend && getIndex == (*dnext).first) {
00190       getIndex += (*dnext).second;  // move past end of destroy event
00191       ++dnext;                      // move to next destroy event
00192     }
00193     while (dnext != dend) {
00194       // copy into deleted slot
00195       ParticleList[putIndex++] = ParticleList[getIndex++];
00196       // make sure getIndex points to next non-deleted particle
00197       while (dnext != dend && getIndex == (*dnext).first) {
00198         getIndex += (*dnext).second;  // move past end of destroy event
00199         ++dnext;                      // move to next destroy event
00200       }
00201     }
00202     // one more loop to do any remaining data copying beyond last destroy
00203     while (getIndex < endIndex) {
00204       // copy into deleted slot
00205       ParticleList[putIndex++] = ParticleList[getIndex++];
00206     }
00207     // now erase any data below last copy
00208     typename ParticleList_t::iterator loc = ParticleList.begin() + putIndex;
00209     ParticleList.erase(loc, ParticleList.end());
00210   }
00211   return;
00212 }
00213 
00214 
00216 // put the data for M particles into a message, starting from index I.
00217 // This will either put in local or ghost particle data, but not both.
00218 template<class T>
00219 size_t
00220 ParticleAttrib<T>::putMessage(Message& msg, size_t M, size_t I)
00221 {
00222   TAU_PROFILE("ParticleAttrib::putMessage()", 
00223               "unsigned (Message, unsigned, unsigned)", TAU_PARTICLE);
00224 
00225   if (M > 0) {
00226     if (isTemporary()) {
00227       ::putMessage(msg, M);
00228     }
00229     else {
00230       typename ParticleList_t::iterator currp = ParticleList.begin() + I;
00231       typename ParticleList_t::iterator endp = currp + M;
00232       ::putMessage(msg, currp, endp);
00233     }
00234   }
00235 
00236   return M;
00237 }
00238 
00239 
00241 // put the data for particles in a list into a Message
00242 // This will only work for local particle data right now.
00243 template<class T>
00244 size_t
00245 ParticleAttrib<T>::putMessage(Message& msg,
00246                               const vector<size_t>& putList)
00247 {  
00248   TAU_PROFILE("ParticleAttrib::putMessage()", 
00249     "unsigned (Message, vector<unsigned>)", TAU_PARTICLE); 
00250 
00251   vector<size_t>::size_type M = putList.size();
00252 
00253   if (M > 0) {
00254     if (isTemporary()) {
00255       ::putMessage(msg, M);
00256     }
00257     else {
00258       ::putMessage(msg, putList, ParticleList.begin());
00259     }
00260   }
00261 
00262   return M;
00263 }
00264 
00265 
00267 // Get data out of a Message containing M particle's attribute data,
00268 // and store it here.  Data is appended to the end of the list.  Return
00269 // the number of particles retrieved.
00270 template<class T>
00271 size_t
00272 ParticleAttrib<T>::getMessage(Message& msg, size_t M)
00273 {
00274   TAU_PROFILE("ParticleAttrib::getMessage()", 
00275     "unsigned (Message, unsigned)", TAU_PARTICLE); 
00276 
00277   if (M > 0) {
00278     if (isTemporary()) {
00279       size_t checksize;
00280       ::getMessage(msg, checksize);
00281       PAssert(checksize == M);
00282       create(M);
00283     }
00284     else {
00285       size_t currsize = size();
00286       create(M);
00287       ::getMessage_iter(msg, ParticleList.begin() + currsize);
00288     }
00289   }
00290 
00291   return M;
00292 }
00293 
00294 
00296 // Print out information for debugging purposes.  This version just
00297 // prints out static information, so it is static
00298 template<class T>
00299 void ParticleAttrib<T>::printDebug(Inform& o)
00300 {
00301   TAU_PROFILE("ParticleAttrib::printDebug()", 
00302     "void (Inform)", TAU_PARTICLE | TAU_IO); 
00303 
00304   o << "PAttr: size = " << ParticleList.size()
00305     << ", capacity = " << ParticleList.capacity()
00306     << ", temporary = " << isTemporary();
00307 }
00308 
00309 
00310 template<class T>
00311 struct PASortCompare
00312 {
00313   static bool compare(const T &, const T &, bool)
00314   {
00315     // by default, just return false indicating "no change"
00316     return false;
00317   }
00318 };
00319 
00320 #define PA_SORT_COMPARE_SCALAR(SCALAR)                                  \
00321 template<>                                                              \
00322 struct PASortCompare<SCALAR>                                            \
00323 {                                                                       \
00324   static bool compare(const SCALAR &a, const SCALAR &b, bool ascending) \
00325   {                                                                     \
00326     return (ascending ? (a < b) : (a > b));                             \
00327   }                                                                     \
00328 };
00329 
00330 PA_SORT_COMPARE_SCALAR(char)
00331 PA_SORT_COMPARE_SCALAR(unsigned char)
00332 PA_SORT_COMPARE_SCALAR(short)
00333 PA_SORT_COMPARE_SCALAR(unsigned short)
00334 PA_SORT_COMPARE_SCALAR(int)
00335 PA_SORT_COMPARE_SCALAR(unsigned int)
00336 PA_SORT_COMPARE_SCALAR(long)
00337 PA_SORT_COMPARE_SCALAR(unsigned long)
00338 PA_SORT_COMPARE_SCALAR(float)
00339 PA_SORT_COMPARE_SCALAR(double)
00340 
00341 
00343 // Calculate a "sort list", which is an array of data of the same
00344 // length as this attribute, with each element indicating the
00345 // (local) index wherethe ith particle shoulkd go.  For example, 
00346 // if there are four particles, and the sort-list is {3,1,0,2}, that
00347 // means the particle currently with index=0 should be moved to the third
00348 // position, the one with index=1 should stay where it is, etc.
00349 // The optional second argument indicates if the sort should be ascending
00350 // (true, the default) or descending (false).
00351 template<class T>
00352 void ParticleAttrib<T>::calcSortList(SortList_t &slist, bool ascending)
00353 {
00354   int i, j;
00355 
00356   //Inform dbgmsg("PA<T>::calcSortList");
00357 
00358   // Resize the sort list, if necessary, to our own size
00359   SortList_t::size_type slsize = slist.size();
00360   size_t mysize = size();
00361   if (slsize < mysize) {
00362     // dbgmsg << "Resizing provided sort-list: new size = ";
00363     slist.insert(slist.end(), mysize - slsize, (SortList_t::value_type) 0);
00364     // dbgmsg << slist.size() << ", attrib size = " << mysize << endl;
00365   }
00366 
00367   // Initialize the sort-list with a negative value, since we check
00368   // it later when determing what items to consider in the sort.  This
00369   // is done to avoid changing the attribute values.
00370   for (i=0; i < mysize; ++i)
00371     slist[i] = (-1);
00372 
00373   // OK, this is a VERY simple sort routine, O(N^2): Find min or max
00374   // of all elems, store where it goes, then for N-1 elems, etc.  I
00375   // am sure there is a better way.
00376   int firstindx = 0;
00377   int lastindx = (mysize - 1);
00378   for (i=0; i < mysize; ++i) {
00379     int currindx = firstindx;
00380     T currval = ParticleList[currindx];
00381 
00382     for (j=(firstindx + 1); j <= lastindx; ++j) {
00383       // skip looking at this item if we already know where it goes
00384       if (slist[j] < 0) {
00385         // compare current to jth item, if the new one is different
00386         // in the right way, save that index
00387         if (PASortCompare<T>::compare(ParticleList[j], currval, ascending)) {
00388           currindx = j;
00389           currval = ParticleList[currindx];
00390         }
00391       }
00392     }
00393 
00394     // We've found the min or max element, it has index = currindx.
00395     // So the currindx's item in the sort-list should say "this will be
00396     // the ith item".
00397     slist[currindx] = i;
00398     // dbgmsg << "Found min/max value " << i << " at position " << currindx;
00399     // dbgmsg << " with value = " << currval << endl;
00400 
00401     // Adjust the min/max index range to look at next time, if necessary
00402     while (slist[firstindx] >= 0 && firstindx < lastindx)
00403       firstindx++;
00404     while (slist[lastindx] >= 0 && firstindx < lastindx)
00405       lastindx--;
00406     // dbgmsg << " firstindx = " << firstindx << ", lastindx = " << lastindx;
00407     // dbgmsg << endl;
00408   }
00409 }
00410 
00411 
00413 // Process a sort-list, as described for "calcSortList", to reorder
00414 // the elements in this attribute.  All indices in the sort list are
00415 // considered "local", so they should be in the range 0 ... localnum-1.
00416 // The sort-list does not have to have been calcualted by calcSortList,
00417 // it could be calculated by some other means, but it does have to
00418 // be in the same format.  Note that the routine may need to modify
00419 // the sort-list temporarily, but it will return it in the same state.
00420 template<class T>
00421 void ParticleAttrib<T>::sort(SortList_t &slist)
00422 {
00423   // Make sure the sort-list has the proper length.
00424   PAssert(slist.size() >= size());
00425 
00426   // Inform dbgmsg("PA<T>::sort");
00427   // dbgmsg << "Sorting " << size() << " items." << endl;
00428 
00429   // Go through the sort-list instructions, and move items around.
00430   int i, mysize = size();
00431   for (i=0; i < mysize; ++i) {
00432     PAssert(slist[i] < mysize);
00433 
00434     // skip this swap if the swap-list value is negative.  This
00435     // happens when we've already put the item in the proper place.
00436     if (slist[i] >= 0 && slist[i] != i) {
00437       // We should not have a negative slist value for the destination
00438       PAssert(slist[slist[i]] >= 0);
00439 
00440       // OK, swap the items
00441       T tmpval = ParticleList[i];
00442       ParticleList[i] = ParticleList[slist[i]];
00443       ParticleList[slist[i]] = tmpval;
00444       //dbgmsg << "Swapping item " << i << " to position " << slist[i] << endl;
00445 
00446       // then indicate that we've put this
00447       // item in the proper location.
00448       slist[slist[i]] -= mysize;
00449       // } else {
00450       //  dbgmsg << "Skipping item " << i << " in sort: slist[" << i << "] = ";
00451       //  dbgmsg << slist[i] << endl;
00452     }
00453   }
00454 
00455   // Restore the sort-list
00456   for (i=0; i < mysize; ++i) {
00457     if (slist[i] < 0)
00458       slist[i] += mysize;
00459     // dbgmsg << "At end of sort: restored slist[" << i << "] = " << slist[i];
00460     // dbgmsg << ", data[" << i << "] = " << ParticleList[i] << endl;
00461   }
00462 }
00463 
00464 
00466 // scatter functions
00468 //mwerks Moved into class definition (.h file).
00469 
00470 
00472 // gather functions
00474 //mwerks Moved into class definition (.h file).
00475 
00477 // Global function templates
00479 
00480 
00482 // scatter functions for number density
00484 
00485 template <class FT, unsigned Dim, class M, class C, class PT, class IntOp>
00486 void
00487 scatter(Field<FT,Dim,M,C>& f, const ParticleAttrib< Vektor<PT,Dim> >& pp,
00488         const IntOp& intop, FT val) {
00489   TAU_TYPE_STRING(taustr, "void (" + CT(f) + ", " + CT(pp) + ", " 
00490     + CT(intop)  + ", " + CT(val)  + " )" );
00491   TAU_PROFILE("scatter()", taustr, TAU_PARTICLE);
00492 
00493   // make sure field is uncompressed and guard cells are zeroed
00494   f.Uncompress();
00495   FT zero = 0;
00496   f.setGuardCells(zero);
00497 
00498   const M& mesh = f.get_mesh();
00499   // iterate through particles and call scatter operation
00500   typename ParticleAttrib< Vektor<PT,Dim> >::iterator ppiter, ppend=pp.end();
00501   for (ppiter = pp.begin(); ppiter != ppend; ++ppiter)
00502     IntOp::scatter(val,f,*ppiter,mesh);
00503 
00504   // accumulate values in guard cells
00505   f.accumGuardCells();
00506 
00507   INCIPPLSTAT(incParticleScatters);
00508   return;
00509 }
00510 
00511 template <class FT, unsigned Dim, class M, class C, class PT,
00512           class IntOp, class CacheData>
00513 void
00514 scatter(Field<FT,Dim,M,C>& f, const ParticleAttrib< Vektor<PT,Dim> >& pp,
00515   const IntOp& intop, ParticleAttrib<CacheData>& cache, FT val) {
00516 
00517   TAU_TYPE_STRING(taustr, "void (" + CT(f) + ", " + CT(pp) + ", " 
00518     + CT(intop)  + ", " + CT(cache)  + ", " + CT(val)  + " )" );
00519   TAU_PROFILE("scatter()", taustr, TAU_PARTICLE);
00520 
00521   // make sure field is uncompressed and guard cells are zeroed
00522   f.Uncompress();
00523   FT zero = 0;
00524   f.setGuardCells(zero);
00525 
00526   const M& mesh = f.get_mesh();
00527   // iterate through particles and call scatter operation
00528   typename ParticleAttrib< Vektor<PT,Dim> >::iterator ppiter, ppend=pp.end();
00529   typename ParticleAttrib<CacheData>::iterator citer=cache.begin();
00530   for (ppiter = pp.begin(); ppiter != ppend; ++ppiter, ++citer)
00531     IntOp::scatter(val,f,*ppiter,mesh,*citer);
00532 
00533   // accumulate values in guard cells
00534   f.accumGuardCells();
00535 
00536   INCIPPLSTAT(incParticleScatters);
00537   return;
00538 }
00539 
00540 template <class FT, unsigned Dim, class M, class C,
00541           class CacheData, class IntOp>
00542 void
00543 scatter(Field<FT,Dim,M,C>& f, const IntOp& intop,
00544         const ParticleAttrib<CacheData>& cache, FT val) {
00545 
00546   TAU_TYPE_STRING(taustr, "void (" + CT(f) + ", " + CT(intop) + ", " 
00547     + CT(cache)  + ", " + CT(val)  + " )" );
00548   TAU_PROFILE("scatter()", taustr, TAU_PARTICLE);
00549 
00550   // make sure field is uncompressed and guard cells are zeroed
00551   f.Uncompress();
00552   FT zero = 0;
00553   f.setGuardCells(zero);
00554 
00555   // iterate through particles and call scatter operation
00556   typename ParticleAttrib<CacheData>::iterator citer, cend=cache.end();
00557   for (citer = cache.begin(); citer != cend; ++citer)
00558     IntOp::scatter(val,f,*citer);
00559 
00560   // accumulate values in guard cells
00561   f.accumGuardCells();
00562 
00563   INCIPPLSTAT(incParticleScatters);
00564   return;
00565 }
00566 
00567 
00568 /***************************************************************************
00569  * $RCSfile: ParticleAttrib.cpp,v $   $Author: adelmann $
00570  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:28 $
00571  * IPPL_VERSION_ID: $Id: ParticleAttrib.cpp,v 1.1.1.1 2003/01/23 07:40:28 adelmann Exp $ 
00572  ***************************************************************************/

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