moab
|
00001 00011 #include <vector> 00012 #include <set> 00013 #include <iostream> 00014 #include <map> 00015 #include <algorithm> 00016 #include <bitset> 00017 #include <numeric> 00018 #include <cmath> 00019 #include <tr1/unordered_map> 00020 #include <limits> 00021 00022 #include "common_tree.hpp" 00023 00024 #ifndef ELEMENT_TREE_HPP 00025 #define ELEMENT_TREE_HPP 00026 namespace moab { 00027 //forward declarations 00028 00029 template< typename _Entity_handles, 00030 typename _Box, 00031 typename _Moab, 00032 typename _Parametrizer> class Element_tree; 00033 00034 //non-exported functionality 00035 namespace { 00036 namespace _element_tree { 00037 template< typename Iterator> 00038 struct Iterator_comparator{ 00039 typedef typename Iterator::value_type Value; 00040 bool operator()(const Value & a, const Value & b){ 00041 return a->second.second.to_ulong() < b->second.second.to_ulong(); 00042 } 00043 }; //Iterator_comparator 00044 00045 template< typename Data> 00046 struct Split_comparator { 00047 //we minimizes ||left| - |right|| + |middle|^2 00048 double split_objective( const Data & a) const { 00049 if (a.second.sizes[ 2]==0 || a.second.sizes[ 0] == 0){ 00050 return std::numeric_limits< std::size_t>::max(); 00051 } 00052 const double total = a.second.sizes[ 0]+a.second.sizes[ 2]; 00053 const int max = 2*(a.second.sizes[ 2]>a.second.sizes[ 0]); 00054 00055 return (a.second.sizes[ max] -a.second.sizes[ 2*(1-(max==2))])/total; 00056 } 00057 bool operator()( const Data & a, const Data & b) const { 00058 return split_objective( a) < split_objective( b); 00059 } 00060 }; //Split_comparator 00061 00062 template< typename Partition_data, typename Box> 00063 void correct_bounding_box( const Partition_data & data, Box & box, 00064 const int child){ 00065 const int dim = data.dim; 00066 switch( child){ 00067 case 0: 00068 box.max[ dim] = data.left_rightline; 00069 break; 00070 case 1: 00071 box.max[ dim] = data.right_line; 00072 box.min[ dim] = data.left_line; 00073 break; 00074 case 2: 00075 box.min[ dim] = data.right_leftline; 00076 break; 00077 } 00078 #ifdef ELEMENT_TREE_DEBUG 00079 print_vector( data.bounding_box.max); 00080 print_vector( data.bounding_box.min); 00081 print_vector( box.max); 00082 print_vector( box.min); 00083 #endif 00084 } 00085 00086 template< typename Box> 00087 struct _Partition_data{ 00088 typedef _Partition_data< Box> Self; 00089 //default constructor 00090 _Partition_data():sizes(3,0),dim(0){} 00091 _Partition_data( const Self & f){ *this=f; } 00092 _Partition_data( const Box & _box, int _dim): sizes(3,0), 00093 bounding_box( _box), split((_box.max[ _dim] + _box.min[ _dim])/2.0), 00094 left_line( split), right_line( split), dim( _dim){} 00095 _Partition_data& operator=( const Self & f){ 00096 sizes = f.sizes; 00097 bounding_box = f.bounding_box; 00098 split = f.split; 00099 left_line = f.left_line; 00100 right_line = f.right_line; 00101 right_leftline=f.right_leftline; 00102 left_rightline=f.left_rightline; 00103 dim = f.dim; 00104 return *this; 00105 } 00106 std::vector< std::size_t> sizes; 00107 Box bounding_box; 00108 double split; 00109 double left_line; 00110 double right_line; 00111 double right_leftline; 00112 double left_rightline; 00113 int dim; 00114 std::size_t left() const { return sizes[ 0]; } 00115 std::size_t middle()const { return sizes[ 1]; } 00116 std::size_t right() const { return sizes[ 2]; } 00117 }; // Partition_data 00118 00119 template< typename _Entity_handles, typename _Entities> 00120 class _Node{ 00121 //public types: 00122 public: 00123 typedef _Entity_handles Entity_handles; 00124 typedef _Entities Entities; 00125 00126 //private types: 00127 private: 00128 typedef _Node< _Entity_handles, _Entities> Self; 00129 00130 //Constructors 00131 public: 00132 //Default constructor 00133 _Node(): children(3,-1), 00134 left_( children[ 0]), middle_( children[ 1]), 00135 right_( children[ 2]), 00136 dim( -1), split( 0), 00137 left_line( 0), right_line( 0), 00138 entities( 0) {} 00139 00140 //Copy constructor 00141 _Node( const Self & from): 00142 children( from.children), 00143 left_( children[ 0]), middle_( children[ 1]), 00144 right_( children[ 2]), 00145 dim( from.dim), split( from.split), 00146 left_line( from.left_line), right_line( from.right_line), 00147 entities( from.entities) {} 00148 00149 public: 00150 template< typename Iterator> 00151 void assign_entities(const Iterator & begin, const Iterator & end){ 00152 entities.reserve( std::distance( begin, end)); 00153 for( Iterator i = begin; i != end; ++i){ 00154 entities.push_back( std::make_pair((*i)->second.first, 00155 (*i)->first)); 00156 } 00157 } 00158 00159 // Functionality 00160 public: 00161 bool leaf() const { return children[ 0] == -1 && 00162 children[ 1] == -1 && 00163 children[ 2] == -1; } 00164 Self& operator=( const Self & from){ 00165 children=from.children; 00166 dim=from.dim; 00167 left_ = from.left_; 00168 middle_ = from.middle_; 00169 right_ = from.right_; 00170 split=from.split; 00171 left_line=from.left_line; 00172 right_line=from.right_line; 00173 entities=from.entities; 00174 return *this; 00175 } 00176 template< typename Box> 00177 Self& operator=( const _Partition_data< Box> & from){ 00178 dim=from.dim; 00179 split=from.split; 00180 left_line=from.left_line; 00181 right_line=from.right_line; 00182 return *this; 00183 } 00184 //private data members: 00185 private: 00186 //indices of children 00187 std::vector< int> children; 00188 int & left_, middle_, right_; 00189 int dim; //split dimension 00190 double split; //split position 00191 double left_line; 00192 double right_line; 00193 Entities entities; 00194 00195 //Element_tree can touch my privates. 00196 template< Entity_handles, typename B> friend class moab::Element_tree; 00197 }; //class Node 00198 00199 } //namespace _element_tree 00200 } // anon namespace 00201 00202 template< typename _Entity_handles, 00203 typename _Box, 00204 typename _Moab, 00205 typename _Parametrizer> 00206 class Element_tree { 00207 00208 //public types 00209 public: 00210 typedef _Entity_handles Entity_handles; 00211 typedef _Box Box; 00212 typedef _Moab Moab; 00213 typedef _Parametrizer Parametrizer; 00214 typedef typename Entity_handles::value_type Entity_handle; 00215 00216 //private types 00217 private: 00218 typedef Element_tree< _Entity_handles, 00219 _Box, 00220 _Moab, 00221 _Parametrizer> Self; 00222 typedef std::pair< Box, Entity_handle> Leaf_element; 00223 typedef _element_tree::_Node< Entity_handles, std::vector< Leaf_element> > Node; 00224 //int is because we only need to store 00225 #define MAX_ITERATIONS 2 00226 typedef common_tree::_Element_data< Box, std::bitset<NUM_DIM*MAX_ITERATIONS*2> > 00227 Element_data; 00228 typedef std::vector< Node> Nodes; 00229 //TODO: we really want an unordered map here, make sure this is kosher.. 00230 typedef std::tr1::unordered_map< Entity_handle, Element_data> 00231 Element_map; 00232 typedef typename std::vector< typename Element_map::iterator> 00233 Element_list; 00234 typedef _element_tree::_Partition_data< Box> Partition_data; 00235 //public methods 00236 public: 00237 //Constructor 00238 Element_tree( Entity_handles & _entities, Moab & _moab, Box & _bounding_box, 00239 Parametrizer & _entity_contains): 00240 entity_handles_( _entities), tree_(), moab( _moab), 00241 bounding_box( _bounding_box), entity_contains( _entity_contains){ 00242 tree_.reserve( _entities.size()); 00243 Element_map element_map( _entities.size()); 00244 Partition_data _data; 00245 common_tree::construct_element_map( entity_handles_, element_map, 00246 _data.bounding_box, moab); 00247 bounding_box = _data.bounding_box; 00248 _bounding_box = bounding_box; 00249 Element_list element_ordering( element_map.size()); 00250 std::size_t index = 0; 00251 for(typename Element_map::iterator i = element_map.begin(); 00252 i != element_map.end(); ++i, ++index){ 00253 element_ordering[ index] = i; 00254 } 00255 //We only build nonempty trees 00256 if( element_ordering.size()){ 00257 //initially all bits are set 00258 std::bitset< 3> directions( 7); 00259 tree_.push_back( Node()); 00260 int depth = 0; 00261 build_tree( element_ordering.begin(), 00262 element_ordering.end(), 00263 0, directions, _data, depth); 00264 std::cout << "depth: " << depth << std::endl; 00265 } 00266 } 00267 00268 //Copy constructor 00269 Element_tree( Self & s): entity_handles_( s.entity_handles_), 00270 tree_( s.tree_), moab( s.moab), 00271 bounding_box( s.bounding_box){} 00272 00273 //private functionality 00274 private: 00275 00276 template< typename Iterator, typename Split_data> 00277 void compute_split( Iterator & begin, Iterator & end, 00278 Split_data & split_data, bool iteration=false){ 00279 typedef typename Iterator::value_type::value_type Map_value_type; 00280 typedef typename Map_value_type::second_type::second_type Bitset; 00281 //we will update the left/right line 00282 double & left_line = split_data.left_line; 00283 double & right_line = split_data.right_line; 00284 double & split = split_data.split; 00285 const int & dim = split_data.dim; 00286 #ifdef ELEMENT_TREE_DEBUG 00287 std::cout << std::endl; 00288 std::cout << "-------------------" << std::endl; 00289 std::cout << "dim: " << dim << " split: " << split << std::endl; 00290 std::cout << "bounding_box min: "; 00291 print_vector( split_data.bounding_box.min); 00292 std::cout << "bounding_box max: "; 00293 print_vector( split_data.bounding_box.max); 00294 #endif 00295 //for each elt determine if left/middle/right 00296 for(Iterator i = begin; i != end; ++i){ 00297 const Box & box = (*i)->second.first; 00298 Bitset & bits = (*i)->second.second; 00299 //will be 0 if on left, will be 1 if in the middle 00300 //and 2 if on the right; 00301 const bool on_left = (box.max[ dim] < split); 00302 const bool on_right = (box.min[ dim] > split); 00303 const bool in_middle = !on_left && !on_right; 00304 //set the corresponding bits in the bit vector 00305 // looks like: [x_1 = 00 | x_2 = 00 | .. | z_1 = 00 | z_2 = 00] 00306 // two bits, left = 00, middle = 01, right = 10 00307 const int index = 4*dim + 2*iteration; 00308 if( on_left){ split_data.sizes[ 0]++; } 00309 else if(in_middle){ 00310 split_data.sizes[ 1]++; 00311 bits.set( index, 1); 00312 left_line = std::min( left_line, box.min[ dim]); 00313 right_line = std::max( right_line, box.max[ dim]); 00314 }else if( on_right){ 00315 bits.set( index+1, 1); 00316 split_data.sizes[ 2]++; 00317 } 00318 } 00319 #ifdef ELEMENT_TREE_DEBUG 00320 std::size_t _count = std::accumulate( split_data.sizes.begin(), 00321 split_data.sizes.end(), 0); 00322 std::size_t total = std::distance( begin, end); 00323 if( total != _count ){ 00324 std::cout << total << "vs. " << _count << std::endl; 00325 00326 } 00327 std::cout << " left_line: " << left_line; 00328 std::cout << " right_line: " << right_line << std::endl; 00329 std::cout << "co/mputed partition size: "; 00330 print_vector( split_data.sizes); 00331 std::cout << "-------------------" << std::endl; 00332 #endif 00333 } 00334 00335 template< typename Split_data> 00336 bool update_split_line( Split_data & data) const{ 00337 const int max = 2*(data.sizes[ 2]>data.sizes[ 0]); 00338 const int min = 2*(1-(max==2)); 00339 bool one_side_empty = data.sizes[ max]==0 || data.sizes[ min]==0; 00340 double balance_ratio = data.sizes[ max] - data.sizes[ min]; 00341 //if ( !one_side_empty && balance_ratio < .05*total){ return false; } 00342 if( !one_side_empty){ 00343 //if we have some imbalance on left/right 00344 //try to fix the situation 00345 balance_ratio /= data.sizes[ max]; 00346 data.split += (max-1)*balance_ratio*(data.split/2.0); 00347 }else{ 00348 //if the (left) side is empty move the split line just past the 00349 //extent of the (left) line of the middle box. 00350 //if middle encompasses everything then wiggle 00351 //the split line a bit and hope for the best.. 00352 const double left_distance = 00353 std::abs(data.left_line-data.split); 00354 const double right_distance = 00355 std::abs(data.right_line-data.split); 00356 if( (data.sizes[ 0] == 0) && (data.sizes[ 2] != 0)){ 00357 data.split += right_distance; 00358 }else if (data.sizes[ 2]==0 && data.sizes[ 0] != 0){ 00359 data.split -= left_distance; 00360 }else{ 00361 data.split *=1.05; 00362 } 00363 } 00364 data.left_line = data.right_line = data.split; 00365 data.sizes.assign( data.sizes.size(), 0); 00366 return true; 00367 } 00368 00369 template< typename Iterator, 00370 typename Split_data, 00371 typename Directions> 00372 void determine_split( Iterator & begin, 00373 Iterator & end, 00374 Split_data & data, 00375 const Directions & directions){ 00376 typedef typename Iterator::value_type Pair; 00377 typedef typename Pair::value_type Map_value_type; 00378 typedef typename Map_value_type::second_type::second_type Bitset; 00379 typedef typename Map_value_type::second_type::first_type Box; 00380 typedef typename std::map< std::size_t, Split_data> Splits; 00381 typedef typename Splits::value_type Split; 00382 typedef _element_tree::Split_comparator< Split> Comparator; 00383 Splits splits; 00384 for (std::size_t dir = 0; dir < directions.size(); ++dir){ 00385 if( directions.test( dir)){ 00386 Split_data split_data( data.bounding_box, dir); 00387 compute_split( begin, end, split_data); 00388 splits.insert( std::make_pair(2*dir, split_data)); 00389 if( update_split_line( split_data)){ 00390 compute_split( begin, end, split_data, true); 00391 splits.insert( std::make_pair( 2*dir+1, 00392 split_data) ); 00393 } 00394 } 00395 } 00396 Split best = *std::min_element( splits.begin(), splits.end(), 00397 Comparator()); 00398 #ifdef ELEMENT_TREE_DEBUG 00399 std::cout << "best: " << Comparator().split_objective( best) << " "; 00400 print_vector( best.second.sizes); 00401 #endif 00402 const int dir = best.first/2; 00403 const int iter = best.first%2; 00404 double & left_rightline = best.second.left_rightline= 00405 best.second.bounding_box.min[ dir]; 00406 double & right_leftline = best.second.right_leftline = 00407 best.second.bounding_box.max[ dir]; 00408 Bitset mask( 0); 00409 mask.flip( 4*dir+2*iter).flip( 4*dir+2*iter+1); 00410 for(Iterator i = begin; i != end; ++i){ 00411 Bitset & bits = (*i)->second.second; 00412 const Box & box = (*i)->second.first; 00413 //replace 12 bits with just two. 00414 bits &= mask; 00415 bits >>= 4*dir+2*iter; 00416 //if box is labeled left/right but properly contained 00417 //in the middle, move the element into the middle. 00418 //we can shrink the size of left/right 00419 switch( bits.to_ulong()){ 00420 case 0: 00421 if ( box.max[ dir] > best.second.left_line){ 00422 left_rightline = std::max( 00423 left_rightline, box.max[ dir]); 00424 } 00425 break; 00426 case 2: 00427 if ( box.min[ dir] < best.second.right_line){ 00428 right_leftline = std::min( 00429 right_leftline, box.max[ dir]); 00430 } 00431 break; 00432 } 00433 } 00434 data = best.second; 00435 } 00436 00437 //define here for now. 00438 #define ELEMENTS_PER_LEAF 30 00439 #define MAX_DEPTH 30 00440 #define EPSILON 1e-1 00441 template< typename Iterator, typename Node_index, 00442 typename Directions, typename Partition_data> 00443 void build_tree( Iterator begin, Iterator end, 00444 const Node_index node, 00445 const Directions & directions, 00446 Partition_data & _data, 00447 int & depth, 00448 const bool is_middle = false){ 00449 std::size_t number_elements = std::distance(begin, end); 00450 if ( depth < MAX_DEPTH && 00451 number_elements > ELEMENTS_PER_LEAF && 00452 (!is_middle || directions.any())){ 00453 determine_split( begin, end, _data, directions); 00454 //count_sort( begin, end, _data); 00455 std::sort( begin, end, 00456 _element_tree::Iterator_comparator< Iterator>()); 00457 //update the tree 00458 tree_[ node] = _data; 00459 Iterator middle_begin( begin+_data.left()); 00460 Iterator middle_end( middle_begin+_data.middle()); 00461 std::vector< int> depths(3, depth); 00462 //left subtree 00463 if( _data.left()>0){ 00464 Partition_data data( _data); 00465 tree_.push_back( Node()); 00466 tree_[ node].children[ 0] = tree_.size()-1; 00467 correct_bounding_box( _data, data.bounding_box, 0); 00468 Directions new_directions( directions); 00469 const bool axis_is_very_small = 00470 (data.bounding_box.max[ _data.dim] - 00471 data.bounding_box.min[ _data.dim] < EPSILON); 00472 new_directions.set( _data.dim, axis_is_very_small); 00473 build_tree( begin, middle_begin, 00474 tree_[ node].children[ 0], 00475 new_directions, data, ++depths[ 0], 00476 is_middle); 00477 } 00478 //middle subtree 00479 if( _data.middle()>0){ 00480 Partition_data data( _data); 00481 tree_.push_back( Node()); 00482 tree_[ node].children[ 1] = tree_.size()-1; 00483 correct_bounding_box( _data, data.bounding_box, 1); 00484 //force the middle subtree to split 00485 //in a different direction from this one 00486 Directions new_directions( directions); 00487 new_directions.flip( tree_[node].dim); 00488 bool axis_is_very_small = 00489 (data.bounding_box.max[ _data.dim] - 00490 data.bounding_box.min[ _data.dim] < EPSILON); 00491 new_directions.set( _data.dim, axis_is_very_small); 00492 build_tree( middle_begin, middle_end, 00493 tree_[ node].children[ 1], 00494 new_directions, data, 00495 ++depths[ 1], true); 00496 } 00497 //right subtree 00498 if( _data.right()>0){ 00499 Partition_data data( _data); 00500 tree_.push_back( Node()); 00501 tree_[ node].children[ 2] = tree_.size()-1; 00502 correct_bounding_box( _data, data.bounding_box, 2); 00503 Directions new_directions( directions); 00504 const bool axis_is_very_small = 00505 (data.bounding_box.max[ _data.dim] - 00506 data.bounding_box.min[ _data.dim] < EPSILON); 00507 new_directions.set( _data.dim, axis_is_very_small); 00508 00509 build_tree( middle_end, end, tree_[ node].children[ 2], 00510 directions, data, ++depths[ 2], is_middle); 00511 } 00512 depth = *std::max_element(depths.begin(), depths.end()); 00513 } 00514 if( tree_[ node].leaf()){ 00515 common_tree::assign_entities(tree_[ node].entities, begin, end); 00516 } 00517 } 00518 00519 template< typename Vector, typename Node_index, typename Result> 00520 Result& _find_point( const Vector & point, 00521 const Node_index & index, 00522 Result & result) const{ 00523 typedef typename Node::Entities::const_iterator Entity_iterator; 00524 typedef typename std::pair< bool, Vector> Return_type; 00525 const Node & node = tree_[ index]; 00526 if( node.leaf()){ 00527 //check each node 00528 for( Entity_iterator i = node.entities.begin(); 00529 i != node.entities.end(); ++i){ 00530 if( common_tree::box_contains_point( i->first, point)){ 00531 Return_type r = entity_contains( moab, 00532 i->second, 00533 point); 00534 if( r.first){ result = 00535 std::make_pair( i->second, r.second); 00536 } 00537 return result; 00538 } 00539 } 00540 return Result(0, point); 00541 } 00542 if( point[ node.dim] < node.left_line){ 00543 return _find_point( point, node.left_, result); 00544 }else if( point[ node.dim] > node.right_line){ 00545 return _find_point( point, node.right_, result); 00546 } else { 00547 Entity_handle middle = _find_point( point, 00548 node.middle_, result); 00549 if( middle != 0){ return result; } 00550 if( point[ node.dim] < node.split){ 00551 return _find_point( point, node.left_, result); 00552 } 00553 return _find_point( point, node.right_, result); 00554 } 00555 } 00556 00557 //public functionality 00558 public: 00559 template< typename Vector, typename Result> 00560 Result& find( const Vector & point, Result & result) const{ 00561 typedef typename Vector::const_iterator Point_iterator; 00562 typedef typename Box::Pair Pair; 00563 typedef typename Pair::first_type Box_iterator; 00564 return _find_point( point, 0, result); 00565 } 00566 00567 00568 //public accessor methods 00569 public: 00570 00571 //private data members 00572 private: 00573 const Entity_handles & entity_handles_; 00574 Nodes tree_; 00575 Moab & moab; 00576 Box bounding_box; 00577 Parametrizer entity_contains; 00578 00579 }; //class Element_tree 00580 00581 } // namespace moab 00582 00583 #endif //ELEMENT_TREE_HPP