ExaFMM 1
Fast-multipole Method for exascale systems
|
00001 /* 00002 Copyright (C) 2011 by Rio Yokota, Simon Layton, Lorena Barba 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00020 THE SOFTWARE. 00021 */ 00022 #ifndef bottomup_h 00023 #define bottomup_h 00024 #include "topdown.h" 00025 00026 //! Bottomup tree constructor 00027 template<Equation equation> 00028 class BottomUp : public TopDown<equation> { 00029 public: 00030 using Kernel<equation>::printNow; //!< Switch to print timings 00031 using Kernel<equation>::startTimer; //!< Start timer for given event 00032 using Kernel<equation>::stopTimer; //!< Stop timer for given event 00033 using Kernel<equation>::sortBodies; //!< Sort bodies according to cell index 00034 using Kernel<equation>::X0; //!< Center of root cell 00035 using Kernel<equation>::R0; //!< Radius of root cell 00036 using TreeStructure<equation>::buffer; //!< Buffer for MPI communication & sorting 00037 using TreeStructure<equation>::getLevel; //!< Get level from cell index 00038 00039 protected: 00040 //! Max level for bottom up tree build 00041 int getMaxLevel(Bodies &bodies) { 00042 const long N = bodies.size() * MPISIZE; // Number of bodies 00043 int level; // Max level 00044 level = N >= NCRIT ? 1 + int(log(N / NCRIT)/M_LN2/3) : 0; // Decide max level from N/Ncrit 00045 int MPIlevel = int(log(MPISIZE-1) / M_LN2 / 3) + 1; // Level of local root cell 00046 if( MPISIZE == 1 ) MPIlevel = 0; // For serial execution local root cell is root cell 00047 if( MPIlevel > level ) { // If process hierarchy is deeper than tree 00048 // std::cout << "Process hierarchy is deeper than tree @ rank" << MPIRANK << std::endl; 00049 level = MPIlevel; 00050 } 00051 return level; // Return max level 00052 } 00053 00054 public: 00055 //! Constructor 00056 BottomUp() : TopDown<equation>() {} 00057 //! Destructor 00058 ~BottomUp() {} 00059 00060 //! Set cell index of all bodies 00061 void setIndex(Bodies &bodies, int level=-1, int begin=0, int end=0, bool update=false) { 00062 startTimer("Set index "); // Start timer 00063 bigint i; // Levelwise cell index 00064 if( level == -1 ) level = getMaxLevel(bodies); // Decide max level 00065 bigint off = ((1 << 3*level) - 1) / 7; // Offset for each level 00066 real r = R0 / (1 << (level-1)); // Radius at finest level 00067 vec<3,int> nx; // 3-D cell index 00068 if( end == 0 ) end = bodies.size(); // Default size is all bodies 00069 for( int b=begin; b!=end; ++b ) { // Loop over bodies 00070 for( int d=0; d!=3; ++d ) { // Loop over dimension 00071 nx[d] = int( ( bodies[b].X[d] - (X0[d]-R0) ) / r ); // 3-D cell index 00072 } // End loop over dimension 00073 i = 0; // Initialize cell index 00074 for( int l=0; l!=level; ++l ) { // Loop over levels of tree 00075 for( int d=0; d!=3; ++d ) { // Loop over dimension 00076 i += nx[d] % 2 << (3 * l + d); // Accumulate cell index 00077 nx[d] >>= 1; // Bitshift 3-D cell index 00078 } // End loop over dimension 00079 } // End loop over levels 00080 if( !update ) { // If this not an update 00081 bodies[b].ICELL = i+off; // Store index in bodies 00082 } else if( i+off > bodies[b].ICELL ) { // If the new cell index is larger 00083 bodies[b].ICELL = i+off; // Store index in bodies 00084 } // Endif for update 00085 } // End loop over bodies 00086 stopTimer("Set index ",printNow); // Stop timer 00087 } 00088 00089 //! Prune tree by merging cells 00090 void prune(Bodies &bodies) { 00091 startTimer("Prune tree "); // Start timer 00092 int maxLevel = getMaxLevel(bodies); // Max level for bottom up tree build 00093 for( int l=maxLevel; l>0; --l ) { // Loop upwards from bottom level 00094 int level = getLevel(bodies[0].ICELL); // Current level 00095 bigint cOff = ((1 << 3 * level) - 1) / 7; // Current ce;; index offset 00096 bigint pOff = ((1 << 3 * (l-1)) - 1) / 7; // Parent cell index offset 00097 bigint index = ((bodies[0].ICELL-cOff) >> 3*(level-l+1)) + pOff;// Current cell index 00098 int begin = 0; // Begin cell index for bodies in cell 00099 int size = 0; // Number of bodies in cell 00100 int b = 0; // Current body index 00101 for( B_iter B=bodies.begin(); B!=bodies.end(); ++B,++b ) {// Loop over bodies 00102 level = getLevel(B->ICELL); // Level of twig 00103 cOff = ((1 << 3*level) - 1) / 7; // Offset of twig 00104 bigint p = ((B->ICELL-cOff) >> 3*(level-l+1)) + pOff; // Cell index of parent cell 00105 if( p != index ) { // If it's a new parent cell 00106 if( size < NCRIT ) { // If parent cell has few enough bodies 00107 for( int i=begin; i!=begin+size; ++i ) { // Loop over bodies in that cell 00108 bodies[i].ICELL = index; // Renumber cell index to parent cell 00109 } // End loop over bodies in cell 00110 } // Endif for merging 00111 begin = b; // Set new begin index 00112 size = 0; // Reset number of bodies 00113 index = p; // Set new parent cell 00114 } // Endif for new cell 00115 size++; // Increment body counter 00116 } // End loop over bodies 00117 if( size < NCRIT ) { // If last parent cell has few enough bodies 00118 for( int i=begin; i!=begin+size; ++i ) { // Loop over bodies in that cell 00119 bodies[i].ICELL = index; // Renumber cell index to parent cell 00120 } // End loop over bodies in cell 00121 } // Endif for merging 00122 } // End loop over levels 00123 stopTimer("Prune tree ",printNow); // Stop timer 00124 } 00125 00126 //! Grow tree by splitting cells 00127 void grow(Bodies &bodies, int level=0, int begin=0, int end=0) { 00128 bigint index = bodies[begin].ICELL; // Initialize cell index 00129 int off=begin, size=0; // Initialize offset, and size 00130 if( level == 0 ) level = getMaxLevel(bodies); // Max level for bottom up tree build 00131 if( end == 0 ) end = bodies.size(); // Default size is all bodies 00132 for( int b=begin; b!=end; ++b ) { // Loop over bodies under consideration 00133 if( bodies[b].ICELL != index ) { // If it's a new cell 00134 if( size >= NCRIT ) { // If the cell has too many bodies 00135 level++; // Increment level 00136 setIndex(bodies,level,off,off+size); // Set new cell index considering new level 00137 sortBodies(bodies,buffer,false,off,off+size); // Sort new cell index 00138 grow(bodies,level,off,off+size); // Recursively grow tree 00139 level--; // Go back to previous level 00140 } // Endif for splitting 00141 off = b; // Set new offset 00142 size = 0; // Reset number of bodies 00143 index = bodies[b].ICELL; // Set new cell 00144 } // Endif for new cell 00145 size++; // Increment body counter 00146 } // End loop over bodies 00147 if( size >= NCRIT ) { // If last cell has too many bodies 00148 level++; // Increment level 00149 setIndex(bodies,level,off,off+size); // Set new cell index considering new level 00150 sortBodies(bodies,buffer,false,off,off+size); // Sort new cell index 00151 grow(bodies,level,off,off+size); // Recursively grow tree 00152 level--; // Go back to previous level 00153 } // Endif for splitting 00154 } 00155 }; 00156 00157 #endif