00001 /* _______ __
00002 / ___/ / ___ __ _ / / ___
00003 / /__/ _ \/ _ \/ V \/ _ \/ _ \
00004 \___/_//_/\___/_/_/_/_.__/\___/
00005 */
00006 // CHOMBO Copyright (c) 2000-2004, The Regents of the University of
00007 // California, through Lawrence Berkeley National Laboratory (subject to
00008 // receipt of any required approvals from U.S. Dept. of Energy). All
00009 // rights reserved.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are met:
00013 //
00014 // (1) Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 // (2) Redistributions in binary form must reproduce the above copyright
00017 // notice, this list of conditions and the following disclaimer in the
00018 // documentation and/or other materials provided with the distribution.
00019 // (3) Neither the name of Lawrence Berkeley National Laboratory, U.S.
00020 // Dept. of Energy nor the names of its contributors may be used to endorse
00021 // or promote products derived from this software without specific prior
00022 // written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00026 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00027 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00028 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00029 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00030 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00031 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00032 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00033 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00034 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035 //
00036 // You are under no obligation whatsoever to provide any bug fixes,
00037 // patches, or upgrades to the features, functionality or performance of
00038 // the source code ("Enhancements") to anyone; however, if you choose to
00039 // make your Enhancements available either publicly, or directly to
00040 // Lawrence Berkeley National Laboratory, without imposing a separate
00041 // written license agreement for such Enhancements, then you hereby grant
00042 // the following license: a non-exclusive, royalty-free perpetual license
00043 // to install, use, modify, prepare derivative works, incorporate into
00044 // other computer software, distribute, and sublicense such Enhancements or
00045 // derivative works thereof, in binary and source code form.
00046 //
00047 // TRADEMARKS. Product and company names mentioned herein may be the
00048 // trademarks of their respective owners. Any rights not expressly granted
00049 // herein are reserved.
00050 //
00051
00052 #ifndef _BINFABIMPLEM_H_
00053 #define _BINFABIMPLEM_H_
00054
00055 #include <cmath>
00056
00057 #include "BoxIterator.H"
00058 #include "parstream.H"
00059
00060 //
00061 // Implementation.=====================================
00062 //
00063
00064 template <class T>
00065 BinFab<T>::BinFab()
00066 : BaseFab<List<T> >(),
00067 //[NOTE: dont use RealVect::Zero because of unreliable order of static initializations. <dbs>]
00068 m_origin(D_DECL(0,0,0)),
00069 m_mesh_spacing(D_DECL(0,0,0))
00070 {
00071 }
00072
00073 template <class T>
00074 BinFab<T>::BinFab(const Box& a_domain,
00075 const RealVect& a_meshSpacing,
00076 const RealVect& a_origin)
00077 {
00078 define(a_domain, a_meshSpacing, a_origin);
00079 }
00080
00081 template <class T>
00082 BinFab<T>::BinFab(const BinFab<T>& a_binfab)
00083 {
00084 define(a_binfab.m_domain, a_binfab.m_mesh_spacing, a_binfab.m_origin);
00085 BaseFab<List<T> >::copy(a_binfab);
00086 }
00087
00088 template <class T>
00089 BinFab<T>::~BinFab()
00090 {
00091 this->undefine();
00092 }
00093
00094 template <class T>
00095 void BinFab<T>::define(const Box& a_domain,
00096 const RealVect& a_meshSpacing,
00097 const RealVect& a_origin)
00098 {
00099 // BaseFab vars
00100 this->m_domain = a_domain;
00101 this->m_nvar = 1;
00102 this->m_numpts = this->m_domain.numPts();
00103 BaseFab<List<T> >::define();
00104 // BinFab vars
00105 m_mesh_spacing = a_meshSpacing;
00106 m_origin = a_origin;
00107 }
00108
00109 // set the mesh spacing
00110 //[NOTE: this is a vector even though Chombo doesn't support isotropic grids yet.]
00111 template <class T>
00112 void BinFab<T>::meshSpacing(const RealVect & a_meshSpacing)
00113 {
00114 m_mesh_spacing = a_meshSpacing;
00115 }
00116
00117 // retrieve a copy of the mesh spacing
00118 template <class T>
00119 RealVect BinFab<T>::meshSpacing() const
00120 {
00121 return m_mesh_spacing;
00122 }
00123
00124 // set the coordinate origin;
00125 // i.e. the physical location of the lower corner of cell IntVect::Zero
00126 template <class T>
00127 void BinFab<T>::origin(const RealVect& a_origin)
00128 {
00129 m_origin = a_origin;
00130 }
00131
00132 // retrieve a copy of the coordinate origin
00133 template <class T>
00134 RealVect BinFab<T>::origin() const
00135 {
00136 return m_origin;
00137 }
00138
00140
00142 template <class T>
00143 void BinFab<T>::addItem(const T& a_item)
00144 {
00145 int comp = 0;
00146 IntVect binLoc = locateBin(a_item);
00147 if (this->m_domain.contains(binLoc))
00148 {
00149 this->operator()(binLoc,comp).append(a_item);
00150 }
00151 }
00152
00154 template <class T>
00155 void BinFab<T>::addItem(const T& a_item, const IntVect& a_binLoc)
00156 {
00157 int comp = 0;
00158 if (this->m_domain.contains(a_binLoc))
00159 {
00160 this->operator()(a_binLoc,comp).append(a_item);
00161 }
00162 }
00163
00165 template <class T>
00166 void BinFab<T>::addItems(const List<T>& a_List)
00167 {
00168 if (a_List.isNotEmpty())
00169 {
00170 // loop through items in List, and add to appropriate locations
00171 ListIterator<T> lit(a_List);
00172 int comp = 0;
00173 IntVect binLoc;
00174
00175 for (lit.rewind(); lit; ++lit)
00176 {
00177 const T& thisItem = a_List[lit];
00178 binLoc = locateBin(thisItem);
00179
00180 if (this->m_domain.contains(binLoc))
00181 {
00182 this->operator()(binLoc,comp).append(thisItem);
00183 }
00184 }
00185 }
00186 }
00187
00189
00191 // [NOTE: this is mostly the same as the previous version, except for the inner loop]
00192 template <class T>
00193 void BinFab<T>::addItemsDestructive(List<T>& a_List)
00194 {
00195 if (a_List.isNotEmpty())
00196 {
00197 // loop through items in List, add to appropriate bins,
00198 // and remove from List
00199 ListIterator<T> lit(a_List);
00200 int comp = 0;
00201 IntVect binLoc;
00202
00203 for (lit.rewind(); lit; )
00204 {
00205 const T& thisItem = a_List[lit];
00206 binLoc = locateBin(thisItem);
00207 if (this->m_domain.contains(binLoc)) //[NOTE: BaseFab domain, not problem domain]
00208 {
00209 //this->operator()(binLoc,comp).append(thisItem);
00210 //a_List.remove(lit);
00211 this->operator()(binLoc,comp).transfer(lit);
00212 }
00213 else
00214 {
00215 // removing a list element has the side-effect of moving the
00216 // iterator forward, so only increment explicitly if not removed
00217 ++lit ;
00218 }
00219 }
00220 }
00221 }
00222
00224 // [NOTE: this is mostly the same as the previous version, except for the inner loop]
00225 template <class T>
00226 void BinFab<T>::addItemsDestructive(List<T>& a_List, const Box& a_valid ,bool a_in)
00227 {
00228 assert( a_valid.cellCentered() );
00229 if (a_List.isNotEmpty())
00230 {
00231 // loop through items in List, add to appropriate bins,
00232 // and remove from List
00233 ListIterator<T> lit(a_List);
00234 int comp = 0;
00235 IntVect binLoc;
00236
00237 for (lit.rewind(); lit; )
00238 {
00239 const T& thisItem = a_List[lit];
00240 binLoc = locateBin(thisItem);
00241 if (this->m_domain.contains(binLoc)) //[NOTE: BaseFab domain, not problem domain]
00242 {
00243
00244 // If the a_in flag is true, then delete the particle from the
00245 // List if it is in the valid Box; if the a_in flag is false,
00246 // delete the particle if it is NOT in the Box.
00247 // Transfering a list element has the side-effect of moving the
00248 // iterator forward, so explicitly increment the iterator only
00249 // if the particle was not transfered. Wish C++ have a nice XOR function.
00250 if( a_valid.contains(binLoc) )
00251 {
00252 if( a_in )
00253 {
00254 //this->operator()(binLoc,comp).append(thisItem);
00255 //a_List.remove(lit);
00256 this->operator()(binLoc,comp).transfer(lit);
00257 }
00258 else
00259 {
00260 this->operator()(binLoc,comp).append(thisItem);
00261 ++lit ;
00262 }
00263 }
00264 else
00265 {
00266 if( a_in )
00267 {
00268 this->operator()(binLoc,comp).append(thisItem);
00269 ++lit;
00270 }
00271 else
00272 {
00273 //this->operator()(binLoc,comp).append(thisItem);
00274 //a_List.remove(lit);
00275 this->operator()(binLoc,comp).transfer(lit);
00276 }
00277 }
00278
00279 }
00280 else
00281 {
00282 // not added, so just increment the iterator
00283 ++lit ;
00284 }
00285 }
00286 }
00287 }
00288
00290
00291 // Look at every item in the BinFab and move to a different cell
00292 // if it is in the wrong one. Useful after computing new physical
00293 // locations of particles, e.g. moving in time.
00294 template <class T>
00295 void BinFab<T>::reBin()
00296 {
00297 // loop through each bin and determine if each binItem is
00298 // in the correct bin.
00299 BoxIterator bit(this->m_domain);
00300 int comp = 0;
00301 IntVect binLoc;
00302 // int lost = 0;
00303
00304 for (BoxIterator bit(this->m_domain); bit.ok(); ++bit)
00305 {
00306 const IntVect thisIV = bit();
00307 List<T>& thisList = this->operator()(thisIV,comp);
00308
00309 if (thisList.isNotEmpty())
00310 {
00311 // now index through the List and figure out which bin each
00312 // particle should be in
00313 for (ListIterator<T> thisLit(thisList); thisLit;)
00314 {
00315 T& thisItem = thisList[thisLit];
00316 binLoc = locateBin(thisItem);
00317
00318 if (binLoc != thisIV)
00319 {
00320 // binItem needs to be moved.
00321 // note that if binItem moves outside of domain, it is lost
00322 if (this->m_domain.contains(binLoc))
00323 {
00324 // this->operator()(binLoc,comp).append(thisItem);
00325 // thisList.remove(thisLit);
00326 this->operator()(binLoc,comp).transfer(thisLit);
00327 }
00328 else
00329 {
00330 // ++lost ;
00331 thisList.remove(thisLit);
00332 }
00333 }
00334 else
00335 {
00336 // if this list element is not moved, increment the iterator
00337 ++thisLit;
00338 }
00339 } // end loop over items in this List of binItems
00340 } // end if this list has items
00341 } // end loop over bins
00342 // return lost;
00343 }
00344
00345 // Sort all the items into the appropriate bins and return items that are in (or not in) the \p Box.
00346 // The returned items are appended to the list, so the caller should clear() first if apprpriate.
00347 // Same as reBin(void) except it keeps track of the lost items.
00348 //[NOTE: items that are moved forward in the box wil be looked at twice. <dbs>]
00349 template <class T>
00350 void BinFab<T>::reBin(List<T>& a_lost, const Box & a_valid, bool a_in)
00351 {
00352 //XXX What to do if a_valid is not contained in m_domain?? <dbs>
00353 int comp = 0; //assume only one component
00354 IntVect binLoc;
00355 Box valid = a_valid.isEmpty() ? this->m_domain : a_valid ;
00356
00357 // Loop through _all_ the bins in this BinFab, regardless of the valid Box
00358 for (BoxIterator bit(this->m_domain); bit.ok(); ++bit)
00359 {
00360 const IntVect thisIV = bit();
00361 List<T>& thisList = this->operator()(thisIV,comp);
00362 if (thisList.isNotEmpty())
00363 {
00364 // Compute the proper cell for each element in this list
00365 for (ListIterator<T> thisLit(thisList); thisLit;) //[NOTE: no auto-increment operation]
00366 {
00367 T& thisItem = thisList[thisLit];
00368 binLoc = locateBin(thisItem);
00369 if (binLoc != thisIV)
00370 {
00371 // move it or return it, as appropriate
00372 if (valid.contains(binLoc))
00373 { // new location is in the arg box
00374 if (a_in) a_lost.transfer(thisLit) ;//return it
00375 else this->operator()(binLoc,comp).transfer(thisLit); //move it
00376 }
00377 else if (this->m_domain.contains(binLoc))
00378 { // new location not in the arg box but in the domain
00379 this->operator()(binLoc,comp).transfer(thisLit); //move it
00380 }
00381 else
00382 { // new location is not in the domain
00383 if (!a_in) a_lost.transfer(thisLit); //return it
00384 else thisList.remove(thisLit); // and not in the box, so throw it away
00385 }
00386 //
00387 }
00388 else
00389 {
00390 // increment the iterator only if the item stays in place
00391 ++thisLit;
00392 }
00393 } // end loop over items in this List of binItems
00394 } // end if this list has items
00395 } // end loop over bins
00396 }
00397
00399
00400 // Move items from a_srcBox in the source BinFab to a_destBox in *this.
00401 // This is what ::copy() would do if it allowed a non-const source.
00402 //[NOTE: if the boxes are different, the items will end up in cells with
00403 // different IntVects from the ones they started in. <dbs>]
00404 template <class T>
00405 void BinFab<T>::transfer(BinFab<T>& a_src,
00406 const Box& a_srcBox,
00407 const Box& a_destBox)
00408 {
00409 assert(a_src.box().contains(a_srcBox));
00410 assert(a_destBox.sameSize(a_srcBox));
00411 // Ignore components; BinFab assumes only one.
00412 const int comp = 0, ncomps = 1;
00413 //XXX stupid lack of operator==
00414 //XXX assert( a_comps == Interval(0,0) );
00415 // loop through the cells in the intersection of the two boxes
00416 ForAllThisBNNXCBN(List<T>,a_destBox,comp,ncomps,a_src,a_srcBox,comp)
00417 {
00418 if(a_srcR.isNotEmpty())
00419 {
00420 // cast away const-ness that is assumed by the ForAll...
00421 List<T>& src = (List<T>&)a_srcR ;
00422 //XXX debug
00423 //XXX pout() << "dbg: transfer: i=" << iR << " has " << a_srcR.length() << endl ;
00424 thisR.catenate(src);
00425 }
00426 } EndForTX
00427 }
00428
00430
00431 // Deletes all items from this BinFab and resets it to the undefined state.
00432 template <class T>
00433 void BinFab<T>::clear()
00434 {
00435 this->undefine();
00436 this->m_domain = Box();
00437 this->m_nvar = 0;
00438 this->m_numpts = 0;
00439 m_origin = RealVect::Zero;
00440 m_mesh_spacing = RealVect::Zero;
00441 }
00442
00444
00445 // Counts the number of items in the cells of a_box.
00446 template <class T>
00447 int BinFab<T>::numItems(const Box& a_box) const
00448 {
00449 // Ignore components; BinFab assumes only one.
00450 const int comp = 0 ;
00451 // default is an empty box, so use this BinFab's box instead
00452 // [NOTE: this leaves the caller no way to ask for an empty box;
00453 // it must avoid calling this routine in that case. Sorry.]
00454 Box ibox = a_box;
00455 if (ibox.isEmpty())
00456 {
00457 ibox = this->box();
00458 }
00459 // Loop over all bins in the BinFab
00460 int totalSize = 0;
00461 for (BoxIterator bi(ibox); bi.ok(); ++bi)
00462 {
00463 totalSize += this->operator()(bi(),comp).length();
00464 }
00465 //XXX -- debug
00466 //XXX pout() << "dbg: BinFab::numItems is " << totalSize << " for box " << ibox << endl ;
00467 return totalSize;
00468 }
00469
00471
00472 // Computes the linear size (in bytes) of the items in the cells of a_box.
00473 template <class T>
00474 int BinFab<T>::size(const Box& a_box, const Interval& a_comps) const
00475 {
00476 // Ignore components; BinFab assumes only one.
00477 const int ncomps = 1 ;
00478 //XXX stupid lack of operator==
00479 //XXX assert( a_comps == Interval(0,0) );
00480 // Count the number of items in the specified Box.
00481 int totalSize = numItems(a_box);
00482 // Compute size as the number of items times the size of the items
00483 {
00484 // Compute the size of an item, assuming all are the same size.
00485 int sizeOfT;
00486 T tmp;
00487 sizeOfT = tmp.size();
00488 // totalSize has total number of items, so now compute total size
00489 totalSize *= sizeOfT;
00490 }
00491 // Will also need to include an integer for each list to specify how
00492 // many items are in each list.
00493 //[NOTE: Is this the right thing to do? An alternate approach would be to
00494 // simply unpack one List<T> for all the items and then call addItems()
00495 // with that list. But that probably will be slower. <dfmartin>]
00496 int numBins = a_box.numPts() * ncomps ;
00497 totalSize += numBins*sizeof(int);
00498 return totalSize;
00499 }
00500
00502
00503 // Linearizes the items in the cells of a_box into a_buf.
00504 template <class T>
00505 void BinFab<T>::linearOut(void* a_buf, const Box& a_box, const Interval& a_comps) const
00506 {
00507 // Ignore components; BinFab assumes only one.
00508 const int comp = 0 ;
00509 //XXX stupid lack of operator==
00510 //XXX assert( a_comps == Interval(0,0) );
00511 // make a usable pointer to the buffer
00512 char* buf_ch = (char*)a_buf;
00513 // All we do in this function is loop over the Box
00514 // and call linearOut() on the List elements.
00515 for (BoxIterator bit(a_box); bit.ok(); ++bit)
00516 {
00517 const List<T>& thisList = this->operator()(bit(), comp);
00518 // write the number of list items first
00519 int *intBuffer = (int*)buf_ch;
00520 *intBuffer = thisList.length();
00521 buf_ch += sizeof(int);
00522 // now loop over the items in the list and write each one
00523 for (ListIterator<T> lit(thisList); lit.ok(); ++lit)
00524 {
00525 thisList[lit].linearOut(buf_ch);
00526 buf_ch += thisList[lit].size();
00527 }
00528 }
00529 }
00530
00532
00533 // Same as linearOut() except it clear()s the List after writing it.
00534 template <class T>
00535 void
00536 BinFab<T>::linearOutDestructive(void* a_buf, const Box& a_box, const Interval& a_comps)
00537 {
00538 const int comp = 0 ;
00539 //XXX stupid lack of operator==
00540 //XXX assert( a_comps == Interval(0,0) );
00541 char* buf_ch = (char*)a_buf;
00542 for (BoxIterator bit(a_box); bit.ok(); ++bit)
00543 {
00544 List<T>& thisList = this->operator()(bit(), comp);
00545 int *intBuffer = (int*)buf_ch;
00546 *intBuffer = thisList.length();
00547 buf_ch += sizeof(int);
00548 for (ListIterator<T> lit(thisList); lit.ok(); ++lit)
00549 {
00550 thisList[lit].linearOut(buf_ch);
00551 buf_ch += thisList[lit].size();
00552 }
00553 thisList.clear();
00554 }
00555 }
00556
00558
00559 // Fills this BinFab from the linearization in a_buf of the cells in a_box.
00560 template <class T>
00561 void
00562 BinFab<T>::linearIn(void* a_buf, const Box& a_box, const Interval& a_comps)
00563 {
00564 // Should be just the inverse of linearOut().
00565 // Ignore components; BinFab assumes only one.
00566 const int comp = 0 ;
00567 //XXX stupid lack of operator==
00568 //XXX assert( a_comps == Interval(0,0) );
00569 // make a usable pointer to the buffer
00570 char *buf_ch = (char*)a_buf;
00571 // All we do in this function is loop over the Box
00572 // and call linearOut() on the List elements.
00573 for (BoxIterator bit(a_box); bit.ok(); ++bit)
00574 {
00575 List<T>& thisList = this->operator()(bit(), comp);
00576 // clear the list to prevent accumulation of binItems
00577 thisList.clear();
00578
00579 // first extract the length of the list
00580 int numItems = *((int*)buf_ch);
00581 buf_ch += sizeof(int);
00582 // loop over the list items and make the list
00583 for (int n=0; n<numItems; ++n)
00584 {
00585 T thisBinItem;
00586 thisBinItem.linearIn( buf_ch );
00587 thisList.append(thisBinItem);
00588 buf_ch += thisBinItem.size();
00589 }
00590 }
00591 }
00592
00593 //X /*******************************************************************************
00594 //X This is an example that I want to keep here to remind that the loops over boxes
00595 //X should be unrolled through the BaseFabMacro. <fm>
00596 //X *******************************************************************************
00597 //X template <class T>
00598 //X inline
00599 //X void
00600 //X BaseFab<T>::linearIn(void* buf, const Box& R, const Interval& comps)
00601 //X {
00602 //X T* buffer = (T*)buf;
00603 //X ForAllThisBNN(T,R,comps.begin(), comps.size())
00604 //X {
00605 //X thisR = *buffer;
00606 //X ++buffer;
00607 //X } EndFor;
00608 //X }
00609 //X */
00610
00612
00613 // Compute the IntVect of the cell containing a_binItem.
00614 template <class T>
00615 inline
00616 IntVect
00617 BinFab<T>::locateBin(const T& a_binItem) const
00618 {
00619 IntVect binLoc;
00620 RealVect thisPos = a_binItem.position();
00621 thisPos -= m_origin;
00622 thisPos /= m_mesh_spacing;
00623
00624 for( int d=0 ; d<SpaceDim ; ++d )
00625 {
00626 binLoc[d] = (int)floor(thisPos[d]);
00627 }
00628 return binLoc;
00629 }
00630
00631 #endif
1.2.16