MOAB: Mesh Oriented datABase  (version 5.5.0)
kd_tree_test.cpp
Go to the documentation of this file.
1 #include "moab/Core.hpp"
3 #include "moab/Range.hpp"
4 #include "moab/CartVect.hpp"
5 
6 #ifdef MOAB_HAVE_MPI
7 #include "moab_mpi.h"
8 #endif
9 
10 #include <cmath>
11 #include <cassert>
12 #include <cfloat>
13 #include <cstdio>
14 
15 #include "TestUtil.hpp"
16 
17 using namespace moab;
18 
19 const unsigned INTERVALS = 4;
20 const unsigned DEPTH = 7; // 3*log2(INTERVALS)+1
21 const char* TAG_NAME = "TEST_DATA";
22 
23 EntityHandle create_tree( AdaptiveKDTree& tool, unsigned depth, int intervals, Tag* tag_handle = 0 );
24 void validate_tree( AdaptiveKDTree& tool, EntityHandle root, int depth, double intervals );
25 
26 void test_tree_create();
27 void test_leaf_merge();
28 void test_tree_readwrite();
29 void test_tree_delete();
30 void test_iterator_back();
31 void test_point_search();
32 
33 int main( int argc, char** argv )
34 {
35 #ifdef MOAB_HAVE_MPI
36  int fail = MPI_Init( &argc, &argv );
37  if( fail ) return fail;
38 #else
39  // silence the warning of parameters not used, in serial; there should be a smarter way :(
40  argv[0] = argv[argc - argc];
41 #endif
42 
43  int err = RUN_TEST( test_tree_create );
44  if( err ) // can't run other tests if can't create tree
45  return 1;
46  err += RUN_TEST( test_leaf_merge );
47 #ifdef MOAB_HAVE_HDF5
48  err += RUN_TEST( test_tree_readwrite );
49 #endif
50  err += RUN_TEST( test_tree_delete );
51  err += RUN_TEST( test_iterator_back );
52  err += RUN_TEST( test_point_search );
53 
54 #ifdef MOAB_HAVE_MPI
55  fail = MPI_Finalize();
56  if( fail ) return fail;
57 #endif
58 
59  return err;
60 }
61 
62 EntityHandle create_tree( AdaptiveKDTree& tool, unsigned depth, int intervals, Tag* tag_handle )
63 {
64  // Create tree root
65  ErrorCode err;
66  EntityHandle root, leaf;
67  err = tool.create_root( CartVect( 0.0 ).array(), CartVect( intervals ).array(), root );
68  assert( !err );
69 
70  // Use iterator to create tree to fixed depth of DEPTH
71  AdaptiveKDTreeIter iter;
72  err = tool.get_tree_iterator( root, iter );CHECK_ERR( err );
73  while( err == MB_SUCCESS )
74  {
75  if( iter.depth() < depth )
76  {
77  // bisect leaves along alternating axes
79  split.norm = iter.depth() % 3; // alternate split axes;
80  split.coord = 0.5 * ( iter.box_min()[split.norm] + iter.box_max()[split.norm] );
81  err = tool.split_leaf( iter, split ); // advances iter to first new leaf
82  CHECK_ERR( err );
83  }
84  // if current leaf is at desired depth, advance to next one
85  else
86  {
87  err = iter.step();
88  }
89  }
90  CHECK( MB_ENTITY_NOT_FOUND == err );
91 
92  if( !tag_handle ) return root;
93 
94  // define a tag to use to store integer values on tree leaves
95  err = tool.moab()->tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, *tag_handle, MB_TAG_DENSE | MB_TAG_EXCL );CHECK_ERR( err );
96 
97  // iterate over tree setting data
98  int counter = 0;
99  for( err = tool.get_tree_iterator( root, iter ); !err; err = iter.step() )
100  {
101  // store integer value on leaf
102  ++counter;
103  leaf = iter.handle();
104  err = tool.moab()->tag_set_data( *tag_handle, &leaf, 1, &counter );CHECK_ERR( err );
105  }
106 
107  return root;
108 }
109 
110 void validate_tree( AdaptiveKDTree& tool, EntityHandle root, unsigned depth, int intervals, Tag data )
111 {
112  ErrorCode err;
113  const double VOL = 1.0; // all leaves should be 1x1x1 boxes
114  int val;
115 
116  // iterate over tree, verifying leaves
117  AdaptiveKDTreeIter iter;
118  int counter = 0;
119  for( err = tool.get_tree_iterator( root, iter ); !err; err = iter.step() )
120  {
121  // store integer value on leaf
122  ++counter;
123  EntityHandle leaf = iter.handle();
124  CHECK( leaf != 0 );
126 
127  // check size of leaf
128  const double* min = iter.box_min();
129  const double* max = iter.box_max();
130  double dims[] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
131  double volume = dims[0] * dims[1] * dims[2];
132  CHECK_REAL_EQUAL( VOL, volume, DBL_EPSILON );
133 
134  // check depth of leaf
135  CHECK_EQUAL( depth, iter.depth() );
136 
137  // check tag value on leaf
138  err = tool.moab()->tag_get_data( data, &leaf, 1, &val );CHECK_ERR( err );
139  CHECK_EQUAL( counter, val );
140  }
141  // check number of leaves
142  const int num_leaves = intervals * intervals * intervals;
143  CHECK_EQUAL( num_leaves, counter );
144 }
145 
147 {
148  Tag tag;
149  Core mb;
150  AdaptiveKDTree tool( &mb );
151  const EntityHandle root = create_tree( tool, DEPTH, INTERVALS, &tag );
152  validate_tree( tool, root, DEPTH, INTERVALS, tag );
153 }
154 
156 {
157  ErrorCode err;
158  Core mb;
159  AdaptiveKDTree tool( &mb );
160  Tag data;
161  const EntityHandle root = create_tree( tool, DEPTH, INTERVALS, &data );
162 
163  // reduce tree depth to DEPTH-1 by merging adjacent leaf pairs,
164  // make new "leaf" have smaller of two data values on original pair
165  AdaptiveKDTreeIter iter;
166  for( err = tool.get_tree_iterator( root, iter ); !err; err = iter.step() )
167  {
168  // get data for first leaf
169  int data1;
170  EntityHandle leaf = iter.handle();
171  err = mb.tag_get_data( data, &leaf, 1, &data1 );CHECK_ERR( err );
172  // tree traversal is always such that two leaves with same parent are consective
173  err = iter.step();CHECK_ERR( err );
174  // get data for sibling
175  int data2;
176  leaf = iter.handle();
177  err = mb.tag_get_data( data, &leaf, 1, &data2 );CHECK_ERR( err );
178  // as we stored increasing values, these had better be increasing
179  CHECK_EQUAL( 1, data2 - data1 );
180  // merge leaf pair (iter can be at either one)
181  err = tool.merge_leaf( iter ); // changes iter to be new "merged" leaf
182  CHECK_ERR( err );
183  // store smaller of two values on new leaf
184  leaf = iter.handle();
185  err = mb.tag_set_data( data, &leaf, 1, &data1 );CHECK_ERR( err );
186  }
187 
188  // Iterate over tree, verifying leaves and checking data
189  // Initial leaves had volume of 1 : merged pairs of leaves so volume should now be 2.
190  // Initial leaves were enumerated in order : merged pairs so new leaves should
191  // have data incrementing in steps of 2.
192  int counter = 1;
193  for( err = tool.get_tree_iterator( root, iter ); !err; err = iter.step() )
194  {
195  // store integer value on leaf
196  int data1;
197  EntityHandle leaf = iter.handle();
198  err = mb.tag_get_data( data, &leaf, 1, &data1 );CHECK_ERR( err );
199  CHECK_EQUAL( counter, data1 );
200  counter += 2;
201 
202  // check size of leaf
203  const double* min = iter.box_min();
204  const double* max = iter.box_max();
205  double dims[] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
206  double volume = dims[0] * dims[1] * dims[2];
207  CHECK_REAL_EQUAL( 2.0, volume, DBL_EPSILON );
208 
209  // check depth of leaf
210  CHECK_EQUAL( DEPTH - 1, iter.depth() );
211  }
212 }
213 
215 {
216  ErrorCode err;
217  Tag tag;
218  Core mb;
219  AdaptiveKDTree tool( &mb );
220  create_tree( tool, DEPTH, INTERVALS, &tag );
221 
222  // write to file
223  err = mb.write_file( "tree.h5m" );CHECK_ERR( err );
224 
225  // clear everything
226  mb.delete_mesh();
227 
228  // read tree from file
229  err = mb.load_file( "tree.h5m" );
230  remove( "tree.h5m" );CHECK_ERR( err );
231 
232  // get tag handle by name, because the handle may have changed
233  err = mb.tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag );CHECK_ERR( err );
234 
235  // get root handle for tree
236  Range range;
237  err = tool.find_all_trees( range );
238  assert( !err );
239  assert( range.size() == 1 );
240  EntityHandle root = range.front(); // first (only) handle
241 
242  validate_tree( tool, root, DEPTH, INTERVALS, tag );
243 }
244 
246 {
247  ErrorCode err;
248  Core mb;
249  AdaptiveKDTree tool( &mb );
250  Tag data;
251  create_tree( tool, DEPTH, INTERVALS, &data );
252 
253  err = tool.reset_tree();CHECK_ERR( err );
254 
255  Range ents;
256  err = mb.get_entities_by_type_and_tag( 0, MBENTITYSET, &data, 0, 1, ents );CHECK_ERR( err );
257  CHECK( ents.empty() );
258 }
259 
261 {
262  Core mb;
263  AdaptiveKDTree tool( &mb );
264  const EntityHandle root = create_tree( tool, DEPTH, INTERVALS );
265 
266  AdaptiveKDTreeIter iter;
267  ErrorCode rval = tool.get_tree_iterator( root, iter );CHECK_ERR( rval );
268 
269  CartVect min( iter.box_min() );
270  CartVect max( iter.box_max() );
271  EntityHandle leaf = iter.handle();
272 
273  // going back from first location should fail.
274  rval = iter.back();
276  rval = tool.get_tree_iterator( root, iter );CHECK_ERR( rval );
277 
278  // make sure iterator is valid
279  CHECK_REAL_EQUAL( min[0], iter.box_min()[0], DBL_EPSILON );
280  CHECK_REAL_EQUAL( min[1], iter.box_min()[1], DBL_EPSILON );
281  CHECK_REAL_EQUAL( min[2], iter.box_min()[2], DBL_EPSILON );
282  CHECK_REAL_EQUAL( max[0], iter.box_max()[0], DBL_EPSILON );
283  CHECK_REAL_EQUAL( max[1], iter.box_max()[1], DBL_EPSILON );
284  CHECK_REAL_EQUAL( max[2], iter.box_max()[2], DBL_EPSILON );
285  CHECK_EQUAL( leaf, iter.handle() );
286 
287  while( MB_SUCCESS == iter.step() )
288  {
289  // Get values at current iterator location
290  CartVect next_min( iter.box_min() );
291  CartVect next_max( iter.box_max() );
292  EntityHandle next_leaf = iter.handle();
293 
294  // step back to previous location
295  rval = iter.back();CHECK_ERR( rval );
296 
297  // check expected values for previous location
298  CHECK_REAL_EQUAL( min[0], iter.box_min()[0], DBL_EPSILON );
299  CHECK_REAL_EQUAL( min[1], iter.box_min()[1], DBL_EPSILON );
300  CHECK_REAL_EQUAL( min[2], iter.box_min()[2], DBL_EPSILON );
301  CHECK_REAL_EQUAL( max[0], iter.box_max()[0], DBL_EPSILON );
302  CHECK_REAL_EQUAL( max[1], iter.box_max()[1], DBL_EPSILON );
303  CHECK_REAL_EQUAL( max[2], iter.box_max()[2], DBL_EPSILON );
304  CHECK_EQUAL( leaf, iter.handle() );
305 
306  // advance iterator to 'current' location
307  rval = iter.step();CHECK_ERR( rval );
308 
309  // check that iterator values are correct
310  CHECK_REAL_EQUAL( next_min[0], iter.box_min()[0], DBL_EPSILON );
311  CHECK_REAL_EQUAL( next_min[1], iter.box_min()[1], DBL_EPSILON );
312  CHECK_REAL_EQUAL( next_min[2], iter.box_min()[2], DBL_EPSILON );
313  CHECK_REAL_EQUAL( next_max[0], iter.box_max()[0], DBL_EPSILON );
314  CHECK_REAL_EQUAL( next_max[1], iter.box_max()[1], DBL_EPSILON );
315  CHECK_REAL_EQUAL( next_max[2], iter.box_max()[2], DBL_EPSILON );
316  CHECK_EQUAL( next_leaf, iter.handle() );
317 
318  // store values for next iteration
319  min = next_min;
320  max = next_max;
321  leaf = next_leaf;
322  }
323 }
324 
326 {
327  Core mb;
328  AdaptiveKDTree tool( &mb );
329  const EntityHandle root = create_tree( tool, DEPTH, INTERVALS );
330 
331  ErrorCode rval;
333  AdaptiveKDTreeIter iter, iter2;
334 
335  // points to test
336  CartVect left( 0.5 );
337  CartVect right( CartVect( INTERVALS ) - left );
338 
339  // compare leaf search to iterator search
340  rval = tool.point_search( left.array(), leaf );CHECK_ERR( rval );
341  rval = tool.point_search( left.array(), iter );CHECK_ERR( rval );
342  CHECK_EQUAL( leaf, iter.handle() );
343 
344  // iterator should be at 'first' leaf
345  rval = tool.get_tree_iterator( root, iter2 );CHECK_ERR( rval );
346  for( ;; )
347  {
348  CHECK_EQUAL( iter.handle(), iter2.handle() );
349  CHECK_EQUAL( iter.depth(), iter2.depth() );
350  CHECK_REAL_EQUAL( iter.box_min()[0], iter2.box_min()[0], DBL_EPSILON );
351  CHECK_REAL_EQUAL( iter.box_min()[1], iter2.box_min()[1], DBL_EPSILON );
352  CHECK_REAL_EQUAL( iter.box_min()[2], iter2.box_min()[2], DBL_EPSILON );
353  CHECK_REAL_EQUAL( iter.box_max()[0], iter2.box_max()[0], DBL_EPSILON );
354  CHECK_REAL_EQUAL( iter.box_max()[1], iter2.box_max()[1], DBL_EPSILON );
355  CHECK_REAL_EQUAL( iter.box_max()[2], iter2.box_max()[2], DBL_EPSILON );
356 
357  rval = iter2.step();
358  if( MB_ENTITY_NOT_FOUND == rval ) break;CHECK_ERR( rval );
359  rval = iter.step();CHECK_ERR( rval );
360  }
361 
362  // compare leaf search to iterator search
363  rval = tool.point_search( right.array(), leaf, 0.0, 0.0, NULL, const_cast< EntityHandle* >( &root ) );CHECK_ERR( rval );
364  rval = tool.point_search( right.array(), iter, 0.0, 0.0, NULL, const_cast< EntityHandle* >( &root ) );CHECK_ERR( rval );
365  assert( iter.handle() == leaf );
366 
367  // iterator should be at 'last' leaf
368  rval = tool.get_last_iterator( root, iter2 );CHECK_ERR( rval );
369  for( ;; )
370  {
371  CHECK_EQUAL( iter.handle(), iter2.handle() );
372  CHECK_EQUAL( iter.depth(), iter2.depth() );
373  CHECK_REAL_EQUAL( iter.box_min()[0], iter2.box_min()[0], DBL_EPSILON );
374  CHECK_REAL_EQUAL( iter.box_min()[1], iter2.box_min()[1], DBL_EPSILON );
375  CHECK_REAL_EQUAL( iter.box_min()[2], iter2.box_min()[2], DBL_EPSILON );
376  CHECK_REAL_EQUAL( iter.box_max()[0], iter2.box_max()[0], DBL_EPSILON );
377  CHECK_REAL_EQUAL( iter.box_max()[1], iter2.box_max()[1], DBL_EPSILON );
378  CHECK_REAL_EQUAL( iter.box_max()[2], iter2.box_max()[2], DBL_EPSILON );
379 
380  rval = iter2.back();
381  if( MB_ENTITY_NOT_FOUND == rval ) break;CHECK_ERR( rval );
382  rval = iter.back();CHECK_ERR( rval );
383  }
384 }