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 topdown_h 00023 #define topdown_h 00024 #include "tree.h" 00025 00026 //! Topdown tree constructor class 00027 template<Equation equation> 00028 class TopDown : public TreeStructure<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>::X0; //!< Center of root cell 00034 using Kernel<equation>::R0; //!< Radius of root cell 00035 00036 private: 00037 //! Nodes are primitive cells 00038 struct Node { 00039 int LEVEL; //!< Level of node 00040 int ICHILD; //!< Flag of empty child nodes 00041 int NLEAF; //!< Number of leafs in node 00042 bigint I; //!< Cell index 00043 bigint CHILD[8]; //!< Iterator offset of child nodes 00044 B_iter LEAF[NCRIT]; //!< Iterator for leafs 00045 vect X; //!< Node center 00046 real R; //!< Node radius 00047 }; 00048 std::vector<Node> nodes; //!< Nodes in the tree 00049 00050 //! Calculate octant from position 00051 int getOctant(const vect X, int i) { 00052 int octant = 0; // Initialize octant 00053 for( int d=0; d!=3; ++d ) { // Loop over dimensions 00054 octant += (X[d] > nodes[i].X[d]) << d; // interleave bits and accumulate octant 00055 } // End loop over dimensions 00056 return octant; // Return octant 00057 } 00058 00059 //! Add child node and link it 00060 void addChild(const int octant, int i) { 00061 bigint pOff = ((1 << 3* nodes[i].LEVEL ) - 1) / 7; // Parent cell index offset 00062 bigint cOff = ((1 << 3*(nodes[i].LEVEL+1)) - 1) / 7; // Current cell index offset 00063 vect x = nodes[i].X; // Initialize new center position with old center 00064 real r = nodes[i].R/2; // Initialize new size 00065 for( int d=0; d!=3; ++d ) { // Loop over dimensions 00066 x[d] += r * (((octant & 1 << d) >> d) * 2 - 1); // Calculate new center position 00067 } // End loop over dimensions 00068 Node node; // Node structure 00069 node.NLEAF = node.ICHILD = 0; // Initialize child node counters 00070 node.X = x; // Initialize child node center 00071 node.R = r; // Initialize child node radius 00072 node.LEVEL = nodes[i].LEVEL + 1; // Level of child node 00073 node.I = ((nodes[i].I-pOff) << 3) + octant + cOff; // Cell index of child node 00074 nodes[i].ICHILD |= (1 << octant); // Flip bit of octant 00075 nodes[i].CHILD[octant] = nodes.end()-nodes.begin(); // Link child node to its parent 00076 nodes.push_back(node); // Push child node into vector 00077 } 00078 00079 //! Add leaf to node 00080 void addLeaf(B_iter b, int i) { 00081 nodes[i].LEAF[nodes[i].NLEAF] = b; // Assign body iterator to leaf 00082 nodes[i].NLEAF++; // Increment leaf counter 00083 } 00084 00085 //! Split node and reassign leafs to child nodes 00086 void splitNode(int i) { 00087 for( int l=0; l!=NCRIT; ++l ) { // Loop over leafs in parent node 00088 int octant = getOctant(nodes[i].LEAF[l]->X,i); // Find the octant where the body belongs 00089 if( !(nodes[i].ICHILD & (1 << octant)) ) { // If child doesn't exist in this octant 00090 addChild(octant,i); // Add new child to list 00091 } // Endif for octant 00092 int c = nodes[i].CHILD[octant]; // Set counter for child node 00093 addLeaf(nodes[i].LEAF[l],c); // Add leaf to child 00094 if( nodes[c].NLEAF >= NCRIT ) { // If there are still too many leafs 00095 splitNode(c); // Split the node into smaller ones 00096 } // Endif for too many leafs 00097 } // End loop over leafs 00098 } 00099 00100 //! Traverse tree 00101 void traverse(typename std::vector<Node>::iterator N) { 00102 if( N->NLEAF >= NCRIT ) { // If node has children 00103 for( int i=0; i!=8; ++i ) { // Loop over children 00104 if( N->ICHILD & (1 << i) ) { // If child exists in this octant 00105 traverse(nodes.begin()+N->CHILD[i]); // Recursively search child node 00106 } // Endif for octant 00107 } // End loop over children 00108 } else { // If child doesn't exist 00109 for( int i=0; i!=N->NLEAF; ++i ) { // Loop over leafs 00110 N->LEAF[i]->ICELL = N->I; // Store cell index in bodies 00111 } // End loop over leafs 00112 } // Endif for child existence 00113 } 00114 00115 public: 00116 //! Constructor 00117 TopDown() : TreeStructure<equation>() {} 00118 //! Destructor 00119 ~TopDown() {} 00120 00121 //! Grow tree from root 00122 void grow(Bodies &bodies) { 00123 startTimer("Grow tree "); // Start timer 00124 int octant; // In which octant is the body located? 00125 Node node; // Node structure 00126 node.LEVEL = node.NLEAF = node.ICHILD = node.I = 0; // Initialize root node counters 00127 node.X = X0; // Initialize root node center 00128 node.R = R0; // Initialize root node radius 00129 nodes.push_back(node); // Push child node into vector 00130 for( B_iter B=bodies.begin(); B!=bodies.end(); ++B ) { // Loop over bodies 00131 int i = 0; // Reset node counter 00132 while( nodes[i].NLEAF >= NCRIT ) { // While the nodes have children 00133 nodes[i].NLEAF++; // Increment the cumulative leaf counter 00134 octant = getOctant(B->X,i); // Find the octant where the body belongs 00135 if( !(nodes[i].ICHILD & (1 << octant)) ) { // If child doesn't exist in this octant 00136 addChild(octant,i); // Add new child to list 00137 } // Endif for child existence 00138 i = nodes[i].CHILD[octant]; // Update node iterator to child 00139 } // End while loop 00140 addLeaf(B,i); // Add body to node as leaf 00141 if( nodes[i].NLEAF >= NCRIT ) { // If there are too many leafs 00142 splitNode(i); // Split the node into smaller ones 00143 } // Endif for splitting 00144 } // End loop over bodies 00145 stopTimer("Grow tree ",printNow); // Stop timer 00146 } 00147 00148 //! Store cell index of all bodies 00149 void setIndex() { 00150 startTimer("Set index "); // Start timer 00151 traverse(nodes.begin()); // Traverse tree 00152 stopTimer("Set index ",printNow); // Stop timer 00153 } 00154 }; 00155 00156 #endif