ExaFMM 1
Fast-multipole Method for exascale systems
include/topdown.h
Go to the documentation of this file.
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
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines