MOAB: Mesh Oriented datABase  (version 5.5.0)
point_location.cpp File Reference
#include "moab/Core.hpp"
#include "moab/AdaptiveKDTree.hpp"
#include "moab/Range.hpp"
#include "moab/CartVect.hpp"
#include "moab/GeomUtil.hpp"
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cassert>
#include <sstream>
+ Include dependency graph for point_location.cpp:

Go to the source code of this file.

Macros

#define CHK(ErrorCode)
 

Enumerations

enum  TreeType { UseKDTree , UseNoTree , UseDefaultTree = UseKDTree }
 

Functions

static void fail (ErrorCode error_code, const char *file_name, int line_number)
 
const char * is_default_tree (TreeType type)
 
static void usage (char *argv0, bool help=false)
 
static void generate_random_points (Interface &mesh, size_t num_points, std::vector< CartVect > &points, std::vector< EntityHandle > &point_elems)
 
static void do_kdtree_test (Interface &mesh, int tree_depth, int elem_per_leaf, long num_test, const std::vector< CartVect > &points, std::vector< EntityHandle > &point_elems, clock_t &build_time, clock_t &test_time, size_t &depth)
 
static void do_linear_test (Interface &mesh, int tree_depth, int elem_per_leaf, long num_test, const std::vector< CartVect > &points, std::vector< EntityHandle > &point_elems, clock_t &build_time, clock_t &test_time, size_t &depth)
 
int main (int argc, char *argv[])
 
static CartVect random_point_in_hex (Interface &mb, EntityHandle hex)
 

Variables

const char * default_str = "(default)"
 
const char * empty_str = ""
 
const long DEFAULT_NUM_TEST = 100000
 
const long HARD_MAX_UNIQUE_POINTS = 100000
 
const long HARD_MIN_UNIQUE_POINTS = 1000
 
const long FRACTION_UNIQUE_POINTS = 100
 
const int HexSign [8][3]
 

Macro Definition Documentation

◆ CHK

#define CHK (   ErrorCode)
Value:
do \
{ \
if( MB_SUCCESS != ( ErrorCode ) ) fail( ( ErrorCode ), __FILE__, __LINE__ ); \
} while( false )

Definition at line 12 of file point_location.cpp.

Enumeration Type Documentation

◆ TreeType

enum TreeType
Enumerator
UseKDTree 
UseNoTree 
UseDefaultTree 

Definition at line 22 of file point_location.cpp.

23 {
24  UseKDTree,
25  UseNoTree,
27 };

Function Documentation

◆ do_kdtree_test()

void do_kdtree_test ( Interface mesh,
int  tree_depth,
int  elem_per_leaf,
long  num_test,
const std::vector< CartVect > &  points,
std::vector< EntityHandle > &  point_elems,
clock_t &  build_time,
clock_t &  test_time,
size_t &  depth 
)
static

Definition at line 310 of file point_location.cpp.

319 {
320  ErrorCode rval;
321  clock_t init = clock();
322  AdaptiveKDTree tool( &mb );
323  EntityHandle root;
324  std::ostringstream options;
325  if( tree_depth > 0 ) options << "MAX_DEPTH=" << tree_depth << ";";
326  if( elem_per_leaf > 0 ) options << "MAX_PER_LEAF=" << elem_per_leaf << ";";
327  Range all_hexes;
328  rval = mb.get_entities_by_type( 0, MBHEX, all_hexes );
329  CHK( rval );
330  FileOptions opt( options.str().c_str() );
331  rval = tool.build_tree( all_hexes, &root, &opt );
332  CHK( rval );
333  all_hexes.clear();
334  build_time = clock() - init;
335 
337  std::vector< EntityHandle > hexes;
338  std::vector< EntityHandle >::iterator j;
339  CartVect coords[8];
340  const EntityHandle* conn;
341  int len;
342  for( long i = 0; i < num_test; ++i )
343  {
344  const size_t idx = (size_t)i % points.size();
345  rval = tool.point_search( points[idx].array(), leaf, 1.0e-10, 1.0e-6, NULL, &root );
346  CHK( rval );
347  hexes.clear();
348  rval = mb.get_entities_by_handle( leaf, hexes );
349  CHK( rval );
350  for( j = hexes.begin(); j != hexes.end(); ++j )
351  {
352  rval = mb.get_connectivity( *j, conn, len, true );
353  CHK( rval );
354  rval = mb.get_coords( conn, 8, reinterpret_cast< double* >( coords ) );
355  CHK( rval );
356  if( GeomUtil::point_in_trilinear_hex( coords, points[idx], 1e-12 ) )
357  {
358  point_elems[idx] = *j;
359  break;
360  }
361  }
362  if( j == hexes.end() ) point_elems[idx] = 0;
363  }
364 
365  test_time = clock() - build_time;
366  double tmp_box[3];
367  unsigned max_d;
368  tool.get_info( root, tmp_box, tmp_box, max_d );
369  depth = max_d;
370 }

References build_time, moab::AdaptiveKDTree::build_tree(), CHK, moab::Range::clear(), ErrorCode, moab::Core::get_connectivity(), moab::Core::get_coords(), moab::Core::get_entities_by_handle(), moab::Core::get_entities_by_type(), moab::AdaptiveKDTree::get_info(), init(), leaf, mb, MBHEX, moab::GeomUtil::point_in_trilinear_hex(), and moab::AdaptiveKDTree::point_search().

Referenced by main().

◆ do_linear_test()

void do_linear_test ( Interface mesh,
int  tree_depth,
int  elem_per_leaf,
long  num_test,
const std::vector< CartVect > &  points,
std::vector< EntityHandle > &  point_elems,
clock_t &  build_time,
clock_t &  test_time,
size_t &  depth 
)
static

Definition at line 372 of file point_location.cpp.

381 {
382  clock_t init = clock();
383  Range hexes;
384  ErrorCode rval = mb.get_entities_by_type( 0, MBHEX, hexes );
385  CHK( rval );
386  depth = 0;
387  point_elems.resize( points.size() );
388  build_time = clock() - init;
389 
390  CartVect coords[8];
391  const EntityHandle* conn;
392  int len;
393  for( long i = 0; i < num_test; ++i )
394  {
395  const size_t idx = (size_t)i % points.size();
396  for( Range::iterator h = hexes.begin(); h != hexes.end(); ++h )
397  {
398  rval = mb.get_connectivity( *h, conn, len, true );
399  CHK( rval );
400  rval = mb.get_coords( conn, 8, reinterpret_cast< double* >( coords ) );
401  CHK( rval );
402  if( GeomUtil::point_in_trilinear_hex( coords, points[idx], 1e-12 ) )
403  {
404  point_elems[idx] = *h;
405  break;
406  }
407  }
408  }
409 
410  test_time = clock() - build_time;
411 }

References moab::Range::begin(), build_time, CHK, moab::Range::end(), ErrorCode, moab::Core::get_connectivity(), moab::Core::get_coords(), moab::Core::get_entities_by_type(), init(), mb, MBHEX, and moab::GeomUtil::point_in_trilinear_hex().

Referenced by main().

◆ fail()

void fail ( ErrorCode  error_code,
const char *  file_name,
int  line_number 
)
static

Definition at line 236 of file point_location.cpp.

237 {
238  std::cerr << "Internal error (error code " << error_code << ") at " << file << ":" << line << std::endl;
239  abort();
240 }

◆ generate_random_points()

void generate_random_points ( Interface mesh,
size_t  num_points,
std::vector< CartVect > &  points,
std::vector< EntityHandle > &  point_elems 
)
static

Definition at line 274 of file point_location.cpp.

278 {
279  Range elems;
280  ErrorCode rval;
281  rval = mb.get_entities_by_dimension( 0, 3, elems );
282  CHK( rval );
283  if( !elems.all_of_type( MBHEX ) )
284  {
285  std::cerr << "Warning: ignoring non-hexahedral elements." << std::endl;
286  std::pair< Range::iterator, Range::iterator > p = elems.equal_range( MBHEX );
287  elems.erase( p.second, elems.end() );
288  elems.erase( elems.begin(), p.first );
289  }
290  if( elems.empty() )
291  {
292  std::cerr << "Input file contains no hexahedral elements." << std::endl;
293  exit( 1 );
294  }
295 
296  points.resize( num_points );
297  point_elems.resize( num_points );
298  const size_t num_elem = elems.size();
299  for( size_t i = 0; i < num_points; ++i )
300  {
301  size_t offset = 0;
302  for( size_t x = num_elem; x > 0; x /= RAND_MAX )
303  offset += rand();
304  offset %= num_elem;
305  point_elems[i] = elems[offset];
306  points[i] = random_point_in_hex( mb, point_elems[i] );
307  }
308 }

References moab::Range::all_of_type(), moab::Range::begin(), CHK, moab::Range::empty(), moab::Range::end(), moab::Range::equal_range(), moab::Range::erase(), ErrorCode, moab::Core::get_entities_by_dimension(), mb, MBHEX, random_point_in_hex(), and moab::Range::size().

Referenced by main().

◆ is_default_tree()

const char* is_default_tree ( TreeType  type)
inline

Definition at line 31 of file point_location.cpp.

32 {
33  return type == UseDefaultTree ? default_str : empty_str;
34 }

References default_str, empty_str, and UseDefaultTree.

Referenced by usage().

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 87 of file point_location.cpp.

88 {
89 
90  const char* input_file = 0;
91  long tree_depth = -1;
92  long elem_per_leaf = -1;
93  long num_points = DEFAULT_NUM_TEST;
94  TreeType type = UseDefaultTree;
95  char* endptr;
96 
97  // PARSE ARGUMENTS
98 
99  long* valptr = 0;
100  for( int i = 1; i < argc; ++i )
101  {
102  if( valptr )
103  {
104  *valptr = strtol( argv[i], &endptr, 0 );
105  if( *valptr < 1 || *endptr )
106  {
107  std::cerr << "Invalid value for '" << argv[i - 1] << "' flag: " << argv[i] << std::endl;
108  exit( 1 );
109  }
110  valptr = 0;
111  }
112  else if( argv[i][0] == '-' && argv[i][1] && !argv[i][2] )
113  {
114  switch( argv[i][1] )
115  {
116  case 'h':
117  usage( argv[0], true );
118  break;
119  case 'k':
120  type = UseKDTree;
121  break;
122  case 'v':
123  type = UseNoTree;
124  break;
125  case 'd':
126  valptr = &tree_depth;
127  break;
128  case 'e':
129  valptr = &elem_per_leaf;
130  break;
131  case 'n':
132  valptr = &num_points;
133  break;
134  default:
135  std::cerr << "Invalid flag: " << argv[i] << std::endl;
136  usage( argv[0] );
137  break;
138  }
139  }
140  else if( !input_file )
141  {
142  input_file = argv[i];
143  }
144  else
145  {
146  std::cerr << "Unexpected argument: " << argv[i] << std::endl;
147  usage( argv[0] );
148  }
149  }
150  if( valptr )
151  {
152  std::cerr << "Expected value following '" << argv[argc - 1] << "' flag" << std::endl;
153  usage( argv[0] );
154  }
155  if( !input_file )
156  {
157  std::cerr << "No input file specified." << std::endl;
158  usage( argv[0] );
159  }
160 
161  // LOAD MESH
162 
163  Core moab;
164  Interface& mb = moab;
165  ErrorCode rval;
166  std::string init_msg, msg;
167  mb.get_last_error( init_msg );
168  rval = mb.load_file( input_file );
169  if( MB_SUCCESS != rval )
170  {
171  std::cerr << input_file << " : failed to read file." << std::endl;
172  mb.get_last_error( msg );
173  if( msg != init_msg ) std::cerr << "message : " << msg << std::endl;
174  }
175 
176  // GENERATE TEST POINTS
177 
178  int num_unique = num_points / FRACTION_UNIQUE_POINTS;
179  if( num_unique > HARD_MAX_UNIQUE_POINTS )
180  num_unique = HARD_MAX_UNIQUE_POINTS;
181  else if( num_unique < HARD_MIN_UNIQUE_POINTS )
182  num_unique = num_points;
183  std::vector< CartVect > points;
184  std::vector< EntityHandle > elems;
185  generate_random_points( mb, num_unique, points, elems );
186 
187  // GET MEMORY USE BEFORE BUILDING TREE
188 
189  unsigned long long init_total_storage;
190  mb.estimated_memory_use( 0, 0, &init_total_storage );
191 
192  // RUN TIMING TEST
193  clock_t build_time, test_time;
194  size_t actual_depth = 0;
195  std::vector< EntityHandle > results( points.size() );
196  switch( type )
197  {
198  default:
199  case UseKDTree:
200  do_kdtree_test( mb, tree_depth, elem_per_leaf, num_points, points, results, build_time, test_time,
201  actual_depth );
202  break;
203  case UseNoTree:
204  do_linear_test( mb, tree_depth, elem_per_leaf, num_points, points, results, build_time, test_time,
205  actual_depth );
206  break;
207  }
208 
209  unsigned long long fini_total_storage;
210  mb.estimated_memory_use( 0, 0, &fini_total_storage );
211 
212  // VALIDATE RESULTS
213  int fail = 0;
214  if( results != elems )
215  {
216  std::cout << "WARNING: Test produced invalid results" << std::endl;
217  fail = 1;
218  }
219 
220  // SUMMARIZE RESULTS
221  std::cout << "Number of test queries: " << num_points << std::endl;
222  std::cout << "Tree build time: " << ( (double)build_time ) / CLOCKS_PER_SEC << " seconds" << std::endl;
223  std::cout << "Total query time: " << ( (double)test_time ) / CLOCKS_PER_SEC << " seconds" << std::endl;
224  std::cout << "Time per query: " << ( (double)test_time ) / CLOCKS_PER_SEC / num_points << " seconds" << std::endl;
225  std::cout << "Tree depth: " << actual_depth << std::endl;
226  if( actual_depth )
227  std::cout << "Total query time/depth: " << ( (double)test_time ) / CLOCKS_PER_SEC / actual_depth << " seconds"
228  << std::endl;
229  std::cout << std::endl;
230  std::cout << "Bytes before tree construction: " << init_total_storage << std::endl;
231  std::cout << "Bytes after tree construction: " << fini_total_storage << std::endl;
232  std::cout << "Difference: " << fini_total_storage - init_total_storage << " bytes" << std::endl;
233  return fail;
234 }

References build_time, DEFAULT_NUM_TEST, do_kdtree_test(), do_linear_test(), ErrorCode, moab::Core::estimated_memory_use(), moab::fail(), FRACTION_UNIQUE_POINTS, generate_random_points(), moab::Core::get_last_error(), HARD_MAX_UNIQUE_POINTS, HARD_MIN_UNIQUE_POINTS, input_file, moab::Core::load_file(), mb, MB_SUCCESS, usage(), UseDefaultTree, UseKDTree, and UseNoTree.

◆ random_point_in_hex()

static CartVect random_point_in_hex ( Interface mb,
EntityHandle  hex 
)
static

Definition at line 245 of file point_location.cpp.

246 {
247  const double f = RAND_MAX / 2;
248  CartVect xi( ( (double)rand() - f ) / f, ( (double)rand() - f ) / f, ( (double)rand() - f ) / f );
249  CartVect coords[8];
250  const EntityHandle* conn;
251  int len;
252  ErrorCode rval = mb.get_connectivity( hex, conn, len, true );
253  if( len != 8 && MB_SUCCESS != rval )
254  {
255  std::cerr << "Invalid element" << std::endl;
256  assert( false );
257  abort();
258  }
259  rval = mb.get_coords( conn, 8, reinterpret_cast< double* >( coords ) );
260  CHK( rval );
261 
262  CartVect point( 0, 0, 0 );
263  for( unsigned i = 0; i < 8; ++i )
264  {
265  double coeff = 0.125;
266  for( unsigned j = 0; j < 3; ++j )
267  coeff *= 1 + HexSign[i][j] * xi[j];
268  point += coeff * coords[i];
269  }
270 
271  return point;
272 }

References CHK, ErrorCode, moab::Core::get_connectivity(), moab::Core::get_coords(), HexSign, mb, and MB_SUCCESS.

Referenced by generate_random_points().

◆ usage()

static void usage ( char *  argv0,
bool  help = false 
)
static

Definition at line 41 of file point_location.cpp.

42 {
43  const char* usage_str = "[-k|-v] [-n <N>] [-d <N>] [-e <N>] <input_mesh>";
44  if( !help )
45  {
46  std::cerr << "Usage: " << argv0 << " " << usage_str << std::endl;
47  std::cerr << " : " << argv0 << " -h" << std::endl;
48  exit( 1 );
49  }
50 
51  std::cout << "Usage: " << argv0 << " " << usage_str << std::endl
52  << " -k : Use kD Tree " << is_default_tree( UseKDTree ) << std::endl
53  << " -v : Use no tree" << is_default_tree( UseNoTree ) << std::endl
54  << " -n : Specify number of test points (default = " << DEFAULT_NUM_TEST << ")" << std::endl
55  << " -d : Specify maximum tree depth" << std::endl
56  << " -e : Specify maximum elements per leaf" << std::endl
57  << " <input_mesh> : Mesh to build and query." << std::endl
58  << std::endl;
59  exit( 0 );
60 }

References argv0, DEFAULT_NUM_TEST, help(), is_default_tree(), UseKDTree, and UseNoTree.

Referenced by main().

Variable Documentation

◆ DEFAULT_NUM_TEST

const long DEFAULT_NUM_TEST = 100000

Definition at line 36 of file point_location.cpp.

Referenced by main(), and usage().

◆ default_str

const char* default_str = "(default)"

Definition at line 29 of file point_location.cpp.

Referenced by is_default_tree().

◆ empty_str

const char* empty_str = ""

Definition at line 30 of file point_location.cpp.

Referenced by is_default_tree().

◆ FRACTION_UNIQUE_POINTS

const long FRACTION_UNIQUE_POINTS = 100

Definition at line 39 of file point_location.cpp.

Referenced by main().

◆ HARD_MAX_UNIQUE_POINTS

const long HARD_MAX_UNIQUE_POINTS = 100000

Definition at line 37 of file point_location.cpp.

Referenced by main().

◆ HARD_MIN_UNIQUE_POINTS

const long HARD_MIN_UNIQUE_POINTS = 1000

Definition at line 38 of file point_location.cpp.

Referenced by main().

◆ HexSign

const int HexSign[8][3]
Initial value:
= { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
{ -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } }

Definition at line 242 of file point_location.cpp.

Referenced by random_point_in_hex().