Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

LevelDataI.H

Go to the documentation of this file.
00001 /*   _______              __
00002     / ___/ /  ___  __ _  / /  ___
00003    / /__/ _ \/ _ \/  ' \/ _ \/ _ \
00004    \___/_//_/\___/_/_/_/_.__/\___/ 
00005 */
00006 //
00007 // This software is copyright (C) by the Lawrence Berkeley
00008 // National Laboratory.  Permission is granted to reproduce
00009 // this software for non-commercial purposes provided that
00010 // this notice is left intact.
00011 // 
00012 // It is acknowledged that the U.S. Government has rights to
00013 // this software under Contract DE-AC03-765F00098 between
00014 // the U.S.  Department of Energy and the University of
00015 // California.
00016 //
00017 // This software is provided as a professional and academic
00018 // contribution for joint exchange. Thus it is experimental,
00019 // is provided ``as is'', with no warranties of any kind
00020 // whatsoever, no support, no promise of updates, or printed
00021 // documentation. By using this software, you acknowledge
00022 // that the Lawrence Berkeley National Laboratory and
00023 // Regents of the University of California shall have no
00024 // liability with respect to the infringement of other
00025 // copyrights by any part of this software.
00026 //
00027 
00028 #include <cstdlib>
00029 #include <algorithm>
00030 #include "parstream.H"
00031 #include "memtrack.H"
00032 
00033 using std::sort;
00034 
00035 template<class T> 
00036 LevelData<T>::LevelData()
00037   :m_sendbuffer(NULL), m_sendcapacity(0),
00038    m_recbuffer(NULL), m_reccapacity(0)
00039 {
00040 #ifdef MPI
00041   numSends = 0;
00042   numReceives = 0;
00043 #endif
00044 }
00045 
00046 template<class T> 
00047 LevelData<T>::LevelData(const DisjointBoxLayout& dp, int comps, const IntVect& ghost,
00048                         const DataFactory<T>& a_factory)
00049   : m_disjointBoxLayout(dp), m_ghost(ghost), m_sendbuffer(NULL),
00050     m_sendcapacity(0),  m_recbuffer(NULL),m_reccapacity(0)
00051 { 
00052 #ifdef MPI
00053   numSends = 0;
00054   numReceives = 0;
00055 #endif
00056   this->m_boxLayout = dp; 
00057   this->m_comps = comps;
00058   this->m_isdefined = true;
00059 
00060   if(!dp.isClosed())
00061     {
00062       MayDay::Error("non-disjoint DisjointBoxLayout: LevelData<T>::LevelData(const DisjointBoxLayout& dp, int comps)");
00063     }
00064 
00065   Interval interval(0, comps-1);
00066   allocateGhostVector(a_factory, ghost);
00067   setVector(*this, interval, interval);
00068   
00069  
00070 }
00071 
00072 
00073 
00074 // Since I need to thwart the user from invoking the
00075 // 'define' methods that use a general BoxLayout, I cannot
00076 // get at said functions myself now. Ha!  So, I have to recode
00077 // them here.
00078 
00079 template<class T> 
00080 void LevelData<T>::define(const DisjointBoxLayout& dp, int comps, const IntVect& ghost,
00081                           const DataFactory<T> & a_factory)
00082 {
00083   this->m_isdefined = true;
00084   if(!dp.isClosed())
00085     {
00086       MayDay::Error("non-disjoint DisjointBoxLayout: LevelData<T>::define(const DisjointBoxLayout& dp,....)");
00087     }
00088   if(comps<=0)
00089     {
00090       MayDay::Error("LevelData::LevelData(const BoxLayout& dp, int comps)  comps<=0");
00091     }
00092   this->m_comps = comps;
00093   this->m_boxLayout = dp;
00094 
00095   m_disjointBoxLayout = dp;
00096   m_ghost = ghost;
00097 
00098   // Interval interval(0, comps-1);
00099   allocateGhostVector(a_factory, ghost);
00100   //  setVector(*this, interval, interval);
00101   
00102   m_ghost = ghost; 
00103 
00104 #ifdef MPI  
00105   m_fromMe.resize(0);
00106   m_toMe.resize(0);
00107 #endif
00108 
00109 }
00110 
00111 
00112 template<class T> 
00113 void LevelData<T>::define(const LevelData<T>& da,  const DataFactory<T> & a_factory)
00114 {
00115   this->m_isdefined = true;
00116   if(this == &da) return;
00117   m_disjointBoxLayout = da.m_disjointBoxLayout;
00118   this->m_boxLayout  = da.m_disjointBoxLayout;
00119   this->m_comps     = da.m_comps;
00120   m_ghost     = da.m_ghost;
00121 
00122   Interval srcAnddest(0, this->m_comps-1);
00123 
00124   allocateGhostVector(a_factory, m_ghost);
00125   setVector(da, srcAnddest, srcAnddest);
00126 
00127 #ifdef MPI
00128   m_fromMe.resize(0);
00129   m_toMe.resize(0);
00130 #endif
00131 }
00132 
00133 
00134 template<class T> 
00135 void LevelData<T>::define(const LevelData<T>& da, const Interval& comps,
00136                           const DataFactory<T>& a_factory)
00137 {
00138   this->m_isdefined = true;
00139   if(this == &da){
00140     MayDay::Error(" LevelData<T>::define(const LevelData<T>& da, const Interval& comps) called with 'this'");
00141   }
00142   assert(comps.size()>0);
00143   // this line doesn't make any sense!
00144   //assert(comps.end()<=this->m_comps);
00145   assert(comps.begin()>=0);
00146 
00147   m_disjointBoxLayout = da.m_disjointBoxLayout;
00148   this->m_boxLayout  = da.m_disjointBoxLayout;
00149 
00150   this->m_comps = comps.size();
00151 
00152   m_ghost = da.m_ghost;
00153 
00154   Interval dest(0, this->m_comps-1);
00155 
00156   allocateGhostVector(a_factory, m_ghost);
00157 
00158   setVector(da, comps, dest);
00159 
00160 #ifdef MPI
00161   m_fromMe.resize(0);
00162   m_toMe.resize(0);
00163 #endif
00164 }
00165 
00166 template<class T> 
00167 void LevelData<T>::copyTo(const Interval& srcComps, 
00168                           BoxLayoutData<T>& dest,
00169                           const Interval& destComps) const
00170 {
00171   if((BoxLayoutData<T>*)this == &dest) return;
00172 
00173   if(this->boxLayout() == dest.boxLayout())
00174     {
00175       // parallel direct copy here, no communication issues
00176       for(DataIterator it(this->dataIterator()); it.ok(); ++it)
00177         {
00178           dest[it()].copy(this->box(it()), 
00179                           destComps,
00180                           this->box(it()),
00181                           this->operator[](it()),
00182                           srcComps);
00183         }
00184       return;
00185     }
00186 
00187   Copier copier(m_disjointBoxLayout, dest.boxLayout());
00188   copyTo(srcComps, dest, destComps, copier);
00189 }
00190 
00191 template<class T> 
00192 void LevelData<T>::copyTo(const Interval& srcComps, 
00193                           LevelData<T>& dest,
00194                           const Interval& destComps) const
00195 {
00196   if(this == &dest){
00197     MayDay::Error("src == dest in copyTo function. Perhaps you want exchange ?");
00198   }
00199 
00200   if(this->boxLayout() == dest.boxLayout()  && dest.ghostVect() == IntVect::Zero)
00201     {
00202       // parallel direct copy here, no communication issues
00203       for(DataIterator it(this->dataIterator()); it.ok(); ++it)
00204         {
00205           dest[it()].copy(this->box(it()), 
00206                           destComps,
00207                           this->box(it()),
00208                           this->operator[](it()),
00209                           srcComps);
00210         }
00211       return;
00212     }
00213 
00214   Copier copier(m_disjointBoxLayout, dest.getBoxes(), dest.m_ghost);
00215   copyTo(srcComps, dest, destComps, copier);
00216 }
00217 
00218 
00219 template<class T> 
00220 void LevelData<T>::copyTo(const Interval& srcComps, 
00221                           BoxLayoutData<T>& dest,
00222                           const Interval& destComps,
00223                           const Copier& copier) const
00224 {
00225 
00226   makeItSo(srcComps, *this, dest, destComps, copier);
00227 
00228 }
00229 
00230 template<class T> 
00231 void LevelData<T>::copyTo(const Interval& srcComps, 
00232                           LevelData<T>& dest,
00233                           const Interval& destComps,
00234                           const Copier& copier,
00235                           const LDOperator<T>& a_op) const
00236 {
00237 
00238   makeItSo(srcComps, *this, dest, destComps, copier, a_op);
00239 
00240 }
00241 
00242 template<class T>  
00243 void LevelData<T>::exchange(const Interval& comps)
00244 {
00245   // later on we can code this part as a direct algorithm
00246   // by copying and pasting the code from the Copier::define code
00247   // for now, just do the easy to debug approach.
00248   Copier copier(m_disjointBoxLayout, m_disjointBoxLayout, m_ghost, true);
00249   exchange(comps, copier);
00250 
00251   // if there aren't any ghost cells, there isn't really anything
00252   // to do here (also, if m_ghost == Zero, m_exchangeCopier
00253   // wasn't defined!
00254   //if (m_ghost != IntVect::Zero)
00255   //makeItSo(comps, *this, *this, comps, m_exchangeCopier);
00256 }
00257 
00258 template<class T> 
00259 void LevelData<T>::exchange(const Interval& comps,
00260                             const Copier& copier)
00261 {
00262   makeItSo(comps, *this, *this, comps, copier);
00263 
00264 }
00265 
00266 template<class T> 
00267 void LevelData<T>::makeItSo(const Interval&   a_srcComps, 
00268                             const LevelData<T>& a_src,
00269                             BoxLayoutData<T>& a_dest,
00270                             const Interval&   a_destComps,
00271                             const Copier&     a_copier,
00272                             const LDOperator<T>& a_op) const
00273 {
00274   // The following five functions are nullOps in uniprocessor mode
00275 
00276   // Instead of doing this here, do it an end of makeItSo (ndk)
00277   //completePendingSends(); // wait for sends from possible previous operation
00278 
00279   // new evil logic to determine under what conditions we can just
00280   // re-use our messaging pattern and buffers from the last call to
00281   // makeItSo.  pretty elaborate, I know.  bvs
00282 #ifdef MPI
00283   static Copier* lastCopier=NULL;
00284   
00285 
00286   
00287 #ifndef NDEBUG
00288   //verifyCommunications();
00289 #endif
00290 
00291   if(T::preAllocatable() == 2 || !a_copier.bufferAllocated() || 
00292      (m_fromMe.size() + m_toMe.size() == 0) ||lastCopier != &a_copier){
00293     allocateBuffers(a_src,  a_srcComps,
00294                     a_dest, a_destComps,
00295                     a_copier,
00296                     a_op);  //monkey with buffers, set up 'fromMe' and 'toMe' queues
00297     a_copier.setBufferAllocated(true);
00298   }
00299   lastCopier = (Copier*)(&a_copier);
00300 
00301 #endif
00302 
00303   writeSendDataFromMeIntoBuffers(a_src, a_srcComps, a_op);
00304 
00305 
00306   // If there is nothing to recv/send, don't go into these functions 
00307   // and allocate memory that will not be freed later.  (ndk)
00308   // The #ifdef MPI is for the m_toMe and m_fromMe
00309 #ifdef MPI
00310   if (m_toMe.size() > 0) {
00311     postReceivesToMe(); // all non-blocking
00312   }
00313 
00314   if (m_fromMe.size() > 0) {
00315     postSendsFromMe();  // all non-blocking
00316   }
00317 #endif
00318 
00319   //  computation that could occur during communication should really
00320   //  go here somehow.  while all the non-blocking sending and receiving is
00321   //  going on.  
00322   //
00323   //  my thought is to return from this function at this point an object
00324   //  that encapsulates the argument list above.  
00325   //  a "ChomboMessaging" object.
00326   //  The user can keep a reference
00327   //  to this object and do computations.  When they reach the limit of what
00328   //  they can compute without this communication completing, they call the
00329   //  "finalize()" function of their ChomboMessaging object and the rest of this
00330   //  code below gets executed.
00331   //  a real question though is: is there really enough computation to do while
00332   //  messaging is going on to justify the effort, and what machines really have
00333   //  good asynchronous messaging to make the work worthwhile.
00334   //  
00335   //  the other approach is to more finely decompose the overlapping of
00336   //  messaging and computation by using the ChomboMessaging object in the
00337   //  DataIterator construction.  The DataIterator returns T objects as they
00338   //  are completed from messaging.  This preserves almost all of the Chombo
00339   //  code as is but would be mucho tricky to actually implement and might only
00340   //  gain little.  This would not be a thing to try unitl Chombo is
00341   //  heavily instrumented for performance measuring.  in this design, unpackRecievesToMe()
00342   //  would become a complicated process interwoven with a DataIterator.
00343 
00344   //  postReceivesToMe();
00345 
00346   // perform local copy
00347   for(CopyIterator it(a_copier, CopyIterator::LOCAL); it.ok(); ++it)
00348     {
00349       const MotionItem& item = it();
00350       a_op.op(a_dest[item.toIndex], item.fromRegion, 
00351               a_destComps,
00352               item.toRegion,
00353               a_src[item.fromIndex],
00354               a_srcComps);
00355     }
00356 
00357   // Uncomment and Move this out of unpackReceivesToMe()  (ndk)
00358   completePendingSends(); // wait for sends from possible previous operation
00359 
00360   unpackReceivesToMe(a_dest, a_destComps, a_op); // nullOp in uniprocessor mode
00361 
00362 }
00363 
00364 template<class T> 
00365 void LevelData<T>::define(const BoxLayout& dp, int comps,  const DataFactory<T>& a_factory)
00366 {
00367   MayDay::Error("LevelData<T>::define called with BoxLayout input");
00368 }
00369 
00370 template<class T> 
00371 void LevelData<T>::define(const BoxLayout& dp)
00372 {
00373   MayDay::Error("LevelData<T>::define called with BoxLayout input");
00374 }
00375 
00376 template<class T> 
00377 void LevelData<T>::define(const BoxLayoutData<T>& da, const DataFactory<T>& a_factory )
00378 {
00379   MayDay::Error("LevelData<T>::define called with BoxLayout input");
00380 }
00381 
00382 template<class T> 
00383 void LevelData<T>::define(const BoxLayoutData<T>& da, const Interval& comps,
00384                           const DataFactory<T>& a_factory)
00385 {
00386   MayDay::Error("LevelData<T>::define called with BoxLayout input");
00387 }
00388 
00389 template<class T> 
00390 LevelData<T>::~LevelData()
00391 {
00392   completePendingSends();
00393   free(m_sendbuffer);
00394   free(m_recbuffer);
00395 }
00396 
00397 template<class T>
00398 void LevelData<T>::apply(void (*a_func)(const Box& box, int comps, T& t))
00399 {
00400   for(DataIterator it(this->dataIterator()); it.ok(); ++it)
00401     {
00402       unsigned int index = this->m_boxLayout.index(it());
00403       a_func(m_disjointBoxLayout.get(it()), this->m_comps, *(this->m_vector[index]));
00404     }
00405 }
00406 #ifndef MPI
00407 // uniprocessor version of all these nullop functions.
00408 template<class T> 
00409 void LevelData<T>::completePendingSends() const
00410 {;}
00411 
00412 template<class T> 
00413 void LevelData<T>::allocateBuffers(const LevelData<T>& a_src, 
00414                                    const Interval& a_srcComps,
00415                                    const BoxLayoutData<T>& a_dest,
00416                                    const Interval& a_destComps,
00417                                    const Copier&   a_copier,
00418                                    const LDOperator<T>& a_op
00419                                    ) const
00420 {;}  
00421 
00422 template<class T> 
00423 void LevelData<T>::writeSendDataFromMeIntoBuffers(const LevelData<T>& a_src, 
00424                                                   const Interval&     a_srcComps,
00425                                                   const LDOperator<T>& a_op) const
00426 {;}
00427 
00428 template<class T> 
00429 void LevelData<T>::postSendsFromMe() const
00430 {;}
00431 
00432 template<class T> 
00433 void LevelData<T>::postReceivesToMe() const
00434 {;}
00435 
00436 template<class T> 
00437 void LevelData<T>::unpackReceivesToMe(BoxLayoutData<T>& a_dest, 
00438                                       const Interval&   a_destComps,
00439                                       const LDOperator<T>& a_op) const
00440 {;}
00441 
00442 #else
00443 
00444 // MPI versions of the above codes.
00445 
00446 template<class T> 
00447 void LevelData<T>::completePendingSends() const
00448 {
00449   if(numSends > 0){
00450     int result = MPI_Waitall(numSends, m_sendRequests, m_sendStatus);
00451     if(result != MPI_SUCCESS)
00452       {
00453         //hell if I know what to do about failed messaging here
00454       }
00455 
00456     delete[] m_sendRequests;
00457     delete[] m_sendStatus;
00458   }
00459   numSends = 0;
00460 }
00461 
00462 template<class T> 
00463 void LevelData<T>::allocateBuffers(const LevelData<T>& a_src, 
00464                                    const Interval& a_srcComps,
00465                                    const BoxLayoutData<T>& a_dest,
00466                                    const Interval& a_destComps,
00467                                    const Copier&   a_copier,
00468                                    const LDOperator<T>& a_op) const
00469 {
00470   m_fromMe.resize(0);
00471   m_toMe.resize(0);
00472   size_t sendBufferSize = 0;
00473   size_t recBufferSize  = 0;
00474   // two versions of code here.  one for preAllocatable T, one not.
00475 
00476   //  T dummy;
00477   for(CopyIterator it(a_copier, CopyIterator::FROM); it.ok(); ++it)
00478     {
00479       const MotionItem& item = it();
00480       bufEntry b;
00481       b.item = &item;
00482       b.size = a_op.size(a_src[item.fromIndex], item.fromRegion, a_srcComps);
00483       sendBufferSize+=b.size;
00484       b.procID = item.procID;
00485       m_fromMe.push_back(b);
00486     }
00487   sort(m_fromMe.begin(), m_fromMe.end());
00488   for(CopyIterator it(a_copier, CopyIterator::TO); it.ok(); ++it)
00489     {
00490       const MotionItem& item = it();
00491       bufEntry b;
00492       b.item = &item;
00493       if (!(T::preAllocatable() == 2))
00494         {
00495           b.size = a_op.size(a_dest[item.toIndex], item.toRegion, a_destComps);
00496           recBufferSize+=b.size;
00497         }
00498       b.procID = item.procID;
00499       m_toMe.push_back(b);
00500     }
00501   sort(m_toMe.begin(), m_toMe.end());
00502 
00503   if(T::preAllocatable() == 2) // dynamic allocatable, need two pass
00504     {
00505       // in the non-preallocatable case, I need to message the
00506       // values for the m_toMe[*].size 
00507       if(m_fromMe.size() > 0)
00508         {
00509           MPI_Request nullrequest;
00510 
00511           int lastProc = -1;
00512           int messageIndex = 0;
00513           for(int i=0; i<m_fromMe.size(); ++i)
00514             {
00515               bufEntry& b = m_fromMe[i];
00516               if(b.procID == lastProc) messageIndex++;
00517               else                     messageIndex = 0;
00518               lastProc = b.procID;
00519               MPI_Isend(&(b.size), 1, MPI_UNSIGNED_LONG, b.procID, 
00520                         messageIndex, Chombo_MPI::comm, &(nullrequest));
00521               MPI_Request_free(&(nullrequest));  // we don't wait on these sends, assume
00522               //    this memory really doesn't go anywhere.  Most MPI systems will fast message
00523               //    a single integer message
00524             }
00525         }
00526       if(m_toMe.size() > 0)
00527         {
00528           m_receiveRequests = new MPI_Request[m_toMe.size()];
00529           m_receiveStatus   = new MPI_Status[m_toMe.size()];
00530           int lastProc = -1;
00531           int messageIndex = 0;
00532           for(int i=0; i<m_toMe.size(); ++i)
00533             {
00534               bufEntry& b = m_toMe[i];
00535               if(b.procID == lastProc) messageIndex++;
00536               else                     messageIndex = 0;
00537               lastProc = b.procID;
00538               MPI_Irecv(&(b.size), 1, MPI_UNSIGNED_LONG, b.procID, 
00539                         messageIndex, Chombo_MPI::comm, m_receiveRequests+i);
00540             }
00541 
00542           int result = MPI_Waitall(m_toMe.size(), m_receiveRequests, m_receiveStatus);
00543           if(result != MPI_SUCCESS)
00544             {
00545               MayDay::Error("First pass of two-phase communication failed");
00546             }
00547           for(int i=0; i<m_toMe.size(); ++i)  recBufferSize+= m_toMe[i].size;
00548           delete[] m_receiveRequests;
00549           delete[] m_receiveStatus;
00550         }
00551     }
00552 
00553   // allocate send and receveive buffer space.
00554 
00555   if(sendBufferSize > m_sendcapacity)
00556     {
00557       free(m_sendbuffer);
00558       m_sendbuffer = malloc(sendBufferSize);
00559       if(m_sendbuffer == NULL)
00560         {
00561           MayDay::Error("Out of memory in LevelData::allocatebuffers");
00562         }
00563       m_sendcapacity = sendBufferSize;
00564     }
00565 
00566   if(recBufferSize > m_reccapacity)
00567     {
00568       free(m_recbuffer);
00569       m_recbuffer = malloc(recBufferSize);
00570       if(m_recbuffer == NULL)
00571         {
00572           MayDay::Error("Out of memory in LevelData::allocatebuffers");
00573         }
00574       m_reccapacity = recBufferSize;
00575     }
00576 
00577 
00578   /*
00579     pout()<<"\n";
00580     for(int i=0; i<m_fromMe.size(); i++) 
00581     pout()<<m_fromMe[i].item->region<<"{"<<m_fromMe[i].procID<<"}"<<" ";
00582     pout() <<"::::";
00583     for(int i=0; i<m_toMe.size(); i++) 
00584     pout()<<m_toMe[i].item->region<<"{"<<m_toMe[i].procID<<"}"<<" ";
00585     pout() << endl;
00586   */
00587 
00588   char* nextFree = (char*)m_sendbuffer;
00589   if(m_fromMe.size() > 0)
00590     {
00591       for(unsigned int i=0; i<m_fromMe.size(); ++i)
00592         {
00593           m_fromMe[i].bufPtr = nextFree;
00594           nextFree += m_fromMe[i].size;
00595         }
00596     }
00597 
00598   nextFree = (char*)m_recbuffer;
00599   if(m_toMe.size() > 0)
00600     {
00601       for(unsigned int i=0; i<m_toMe.size(); ++i)
00602         {
00603           m_toMe[i].bufPtr = nextFree;
00604           nextFree += m_toMe[i].size;
00605         }
00606     }
00607 
00608   // since fromMe and toMe are sorted based on procID, messages can now be grouped
00609   // together on a per-processor basis.
00610 
00611 }
00612 
00613 
00614 
00615 template<class T> 
00616 void LevelData<T>::writeSendDataFromMeIntoBuffers(const LevelData<T>& a_src, 
00617                                                   const Interval&     a_srcComps,
00618                                                   const LDOperator<T>& a_op) const
00619 {
00620 
00621 
00622   for(unsigned int i=0; i<m_fromMe.size(); ++i)
00623     {
00624       const bufEntry& entry = m_fromMe[i];
00625       a_op.linearOut(a_src[entry.item->fromIndex], entry.bufPtr, 
00626                      entry.item->fromRegion, a_srcComps);
00627     }
00628 
00629 }
00630 
00631 template<class T> 
00632 void LevelData<T>::postSendsFromMe() const
00633 {
00634 
00635   // now we get the magic of message coalescence
00636   // fromMe has already been sorted in the allocateBuffers() step.
00637 
00638   numSends = m_fromMe.size();
00639   if(numSends > 1){
00640     for(unsigned int i=m_fromMe.size()-1; i>0; --i)
00641       {
00642         if(m_fromMe[i].procID == m_fromMe[i-1].procID) 
00643           {
00644             numSends--;
00645             m_fromMe[i-1].size+=m_fromMe[i].size;
00646             m_fromMe[i].size = 0;
00647           }
00648       }
00649   }
00650   m_sendRequests = new MPI_Request[numSends];
00651   m_sendStatus = new MPI_Status[numSends];
00652 
00653 
00654   unsigned int next=0;
00655   for(int i=0; i<numSends; ++i)
00656     {
00657       const bufEntry& entry = m_fromMe[next];
00658       // cout<<procID()<< ": sending message of "<<entry.size;
00659       // cout<<" to proc "<<  entry.procID<<endl;
00660       MPI_Isend(entry.bufPtr, entry.size, MPI_BYTE, entry.procID, 
00661                 0, Chombo_MPI::comm, m_sendRequests+i);
00662       ++next;
00663       while(next < m_fromMe.size() && m_fromMe[next].size == 0) ++next;
00664     }
00665 
00666 
00667 }
00668 
00669 template<class T> 
00670 void LevelData<T>::postReceivesToMe() const
00671 {
00672   numReceives = m_toMe.size();
00673 
00674   if(numReceives > 1){
00675     for(unsigned int i=m_toMe.size()-1; i>0; --i)
00676       {
00677         if(m_toMe[i].procID == m_toMe[i-1].procID) 
00678           {
00679             numReceives--;
00680             m_toMe[i-1].size+=m_toMe[i].size;
00681             m_toMe[i].size = 0;
00682           }
00683       }
00684   }
00685   m_receiveRequests = new MPI_Request[numReceives];
00686   m_receiveStatus = new MPI_Status[numReceives];
00687 
00688 
00689   unsigned int next=0;
00690   for(int i=0; i<numReceives; ++i)
00691     {
00692       const bufEntry& entry = m_toMe[next];
00693       //cout<<procID()<< ": receiving message of "<<entry.size;
00694       //cout<<" from proc "<<  entry.procID<<endl;
00695       MPI_Irecv(entry.bufPtr, entry.size, MPI_BYTE, entry.procID, 
00696                 0, Chombo_MPI::comm, m_receiveRequests+i);
00697       ++next;
00698       while(next < m_toMe.size() && m_toMe[next].size == 0) ++next;
00699     }
00700 
00701 }
00702 
00703 
00704 template<class T> 
00705 void LevelData<T>::unpackReceivesToMe(BoxLayoutData<T>& a_dest, 
00706                                       const Interval&   a_destComps,
00707                                       const LDOperator<T>& a_op) const
00708 {
00709 
00710   if(numReceives > 0){
00711     int result = MPI_Waitall(numReceives, m_receiveRequests, m_receiveStatus);
00712     if(result != MPI_SUCCESS)
00713       {
00714         //hell if I know what to do about failed messaging here
00715       }
00716 
00717     for(unsigned int i=0; i<m_toMe.size(); ++i)
00718       {
00719         const bufEntry& entry = m_toMe[i];
00720         a_op.linearIn(a_dest[entry.item->toIndex], entry.bufPtr, entry.item->toRegion, a_destComps);
00721       }
00722 
00723     delete[] m_receiveRequests;
00724     delete[] m_receiveStatus;
00725   }
00726   numReceives = 0;
00727 }
00728 
00729 
00730 
00731 #endif
00732 
00733 
00734 
00735 
00736 
00737 
00738 

Generated on Wed Jun 2 13:53:33 2004 for Chombo&INSwithParticles by doxygen 1.3.2