MOAB: Mesh Oriented datABase  (version 5.5.0)
obb_tree_tool.cpp
Go to the documentation of this file.
1 #define IS_BUILDING_MB
2 #include "moab/Core.hpp"
3 #include "moab/CartVect.hpp"
5 #include "moab/OrientedBox.hpp"
6 #include "Internals.hpp"
7 #include "moab/Range.hpp"
8 
9 #include <iostream>
10 #include <iomanip>
11 #include <cstdio>
12 #include <limits>
13 #include <cstdlib>
14 #include <ctime>
15 #if !defined( _MSC_VER ) && !defined( __MINGW32__ )
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #endif
20 
21 using namespace moab;
22 
23 std::string clock_to_string( clock_t t );
24 std::string mem_to_string( unsigned long mem );
25 
26 const int MAX_TAG_VALUE = 20;
27 const char* const TAG_NAME = "OBB_ID";
28 const char* const TREE_TAG = "OBB_ROOT";
29 const char* root_tag = TREE_TAG;
30 
33 void delete_existing_tree( Interface* interface );
34 void print_stats( Interface* interface );
35 void tag_triangles( Interface* interface );
36 void tag_vertices( Interface* interface );
37 void write_tree_blocks( Interface* interface, const char* file );
38 
39 static void usage( bool err = true )
40 {
41  std::ostream& s = err ? std::cerr : std::cout;
42  s << "obb_tree_tool [-s|-S] [-d <int>] [-n <int>] <input file> <output file>" << std::endl
43  << "obb_tree_tool [-h]" << std::endl;
44  if( !err )
45  {
47  s << "Tool to build adaptive kd-Tree from triangles" << std::endl;
48  s << " -s Use range-based sets for tree nodes" << std::endl
49  << " -S Use vector-based sets for tree nodes" << std::endl
50  << " -d <int> Specify maximum depth for tree. Default: " << st.max_depth << std::endl
51  << " -n <int> Specify maximum entities per leaf. Default: " << st.max_leaf_entities << std::endl
52  << " -m <real> Specify worst split ratio. Default: " << st.worst_split_ratio << std::endl
53  << " -M <real> Specify best split ratio. Default: " << st.best_split_ratio << std::endl
54  << " -t Tag triangles will tree cell number." << std::endl
55  << " -T Write tree boxes to file." << std::endl
56  << " -N Specify mesh tag containing tree root. Default: \"" << TREE_TAG << '"' << std::endl
57  << std::endl;
58  }
59  exit( err );
60 }
61 
62 #if defined( _MSC_VER ) || defined( __MINGW32__ )
63 static void memory_use( unsigned long long& vsize, unsigned long long& rss )
64 {
65  vsize = rss = 0;
66 }
67 #else
68 static void memory_use( unsigned long long& vsize, unsigned long long& rss )
69 {
70  char buffer[512];
71  unsigned long lvsize;
72  long lrss;
73  int filp = open( "/proc/self/stat", O_RDONLY );
74  ssize_t r = read( filp, buffer, sizeof( buffer ) - 1 );
75  close( filp );
76  if( r < 0 ) r = 0;
77  lvsize = lrss = 0;
78  buffer[r] = '\0';
79  sscanf( buffer,
80  "%*d %*s %*c " // pid command state
81  "%*d %*d " // ppid pgrp
82  "%*d %*d %*d " // session tty_nr tpgid
83  "%*u " // flags
84  "%*u %*u %*u %*u " // minflt cminflt majflt cmajflt
85  "%*u %*u %*d %*d " // utime stime cutime cstime
86  "%*d %*d %*d " // priority nice (unused)
87  "%*d %*u " // itrealval starttime
88  "%lu %ld",
89  &lvsize, &lrss );
90  rss = lrss * getpagesize();
91  vsize = lvsize;
92 }
93 #endif
94 
95 static int parseint( int& i, int argc, char* argv[] )
96 {
97  char* end;
98  ++i;
99  if( i == argc )
100  {
101  std::cerr << "Expected value following '" << argv[i - 1] << "'" << std::endl;
102  usage();
103  }
104 
105  int result = strtol( argv[i], &end, 0 );
106  if( result < 0 || *end )
107  {
108  std::cerr << "Expected positive integer following '" << argv[i - 1] << "'" << std::endl;
109  usage();
110  }
111 
112  return result;
113 }
114 
115 static double parsedouble( int& i, int argc, char* argv[] )
116 {
117  char* end;
118  ++i;
119  if( i == argc )
120  {
121  std::cerr << "Expected value following '" << argv[i - 1] << "'" << std::endl;
122  usage();
123  }
124 
125  double result = strtod( argv[i], &end );
126  if( result < 0 || *end )
127  {
128  std::cerr << "Expected positive real number following '" << argv[i - 1] << "'" << std::endl;
129  usage();
130  }
131 
132  return result;
133 }
134 
135 int main( int argc, char* argv[] )
136 {
137  const char* input_file = 0;
138  const char* output_file = 0;
139  const char* tree_file = 0;
141  bool tag_tris = false;
142  clock_t load_time, build_time, stat_time, tag_time, write_time, block_time;
143 
144  for( int i = 1; i < argc; ++i )
145  {
146  if( argv[i][0] != '-' )
147  {
148  if( !input_file )
149  input_file = argv[i];
150  else if( !output_file )
151  output_file = argv[i];
152  else
153  usage();
154  continue;
155  }
156 
157  if( !argv[i][1] || argv[i][2] ) usage();
158 
159  switch( argv[i][1] )
160  {
161  case 's':
163  break;
164  case 'S':
165  settings.set_options = MESHSET_ORDERED;
166  break;
167  case 'd':
168  settings.max_depth = parseint( i, argc, argv );
169  break;
170  case 'n':
171  settings.max_leaf_entities = parseint( i, argc, argv );
172  break;
173  case 'm':
174  settings.worst_split_ratio = parsedouble( i, argc, argv );
175  break;
176  case 'M':
177  settings.best_split_ratio = parsedouble( i, argc, argv );
178  break;
179  case 't':
180  tag_tris = true;
181  break;
182  case 'T':
183  if( ++i == argc ) usage();
184  tree_file = argv[i];
185  break;
186  case 'N':
187  if( ++i == argc ) usage();
188  root_tag = argv[i];
189  break;
190  case 'h':
191  usage( false );
192  break;
193  default:
194  usage();
195  }
196  }
197 
198  if( !output_file ) usage();
199 
200  ErrorCode rval;
201  Core moab_core;
202  Interface* interface = &moab_core;
203 
204  load_time = clock();
205  rval = interface->load_mesh( input_file );
206  if( MB_SUCCESS != rval )
207  {
208  std::cerr << "Error reading file: " << input_file << std::endl;
209  exit( 2 );
210  }
211  load_time = clock() - load_time;
212 
213  delete_existing_tree( interface );
214 
215  std::cout << "Building tree..." << std::endl;
216  build_time = clock();
217  build_tree( interface, settings );
218  build_time = clock() - build_time;
219 
220  std::cout << "Calculating stats..." << std::endl;
221  print_stats( interface );
222  stat_time = clock() - build_time;
223 
224  if( tag_tris )
225  {
226  std::cout << "Tagging tree..." << std::endl;
227  tag_triangles( interface );
228  tag_vertices( interface );
229  }
230  tag_time = clock() - stat_time;
231 
232  std::cout << "Writing file... ";
233  std::cout.flush();
234  rval = interface->write_mesh( output_file );
235  if( MB_SUCCESS != rval )
236  {
237  std::cerr << "Error writing file: " << output_file << std::endl;
238  exit( 3 );
239  }
240  write_time = clock() - tag_time;
241  std::cout << "Wrote " << output_file << std::endl;
242 
243  if( tree_file )
244  {
245  std::cout << "Writing tree block rep...";
246  std::cout.flush();
247  write_tree_blocks( interface, tree_file );
248  std::cout << "Wrote " << tree_file << std::endl;
249  }
250  block_time = clock() - write_time;
251 
252  std::cout << "Times: "
253  << " Load"
254  << " Build"
255  << " Stats"
256  << " Write";
257  if( tag_tris ) std::cout << "Tag Sets";
258  if( tree_file ) std::cout << "Block ";
259  std::cout << std::endl;
260 
261  std::cout << " " << std::setw( 8 ) << clock_to_string( load_time ) << std::setw( 8 )
262  << clock_to_string( build_time ) << std::setw( 8 ) << clock_to_string( stat_time ) << std::setw( 8 )
263  << clock_to_string( write_time );
264  if( tag_tris ) std::cout << std::setw( 8 ) << clock_to_string( tag_time );
265  if( tree_file ) std::cout << std::setw( 8 ) << clock_to_string( block_time );
266  std::cout << std::endl;
267 
268  return 0;
269 }
270 
272 {
273  Tag tag;
274  ErrorCode rval;
275 
276  rval = moab->tag_get_handle( root_tag, 1, MB_TYPE_HANDLE, tag );
277  if( MB_SUCCESS != rval ) return rval;
278 
279  const EntityHandle mesh = 0;
280  return moab->tag_get_data( tag, &mesh, 1, &root );
281 }
282 
283 void delete_existing_tree( Interface* interface )
284 {
285  EntityHandle root;
286  ErrorCode rval = get_root( interface, root );
287  if( MB_SUCCESS == rval )
288  {
289  OrientedBoxTreeTool tool( interface );
290  rval = tool.delete_tree( root );
291  if( MB_SUCCESS != rval )
292  {
293  std::cerr << "Failed to destroy existing trees. Aborting" << std::endl;
294  exit( 5 );
295  }
296  }
297 }
298 
300 {
301  ErrorCode rval;
302  EntityHandle root = 0;
303  Range triangles;
304 
305  rval = interface->get_entities_by_type( 0, MBTRI, triangles );
306  if( MB_SUCCESS != rval || triangles.empty() )
307  {
308  std::cerr << "No triangles from which to build tree." << std::endl;
309  exit( 4 );
310  }
311 
312  OrientedBoxTreeTool tool( interface );
313  rval = tool.build( triangles, root, &settings );
314  if( MB_SUCCESS != rval || !root )
315  {
316  std::cerr << "Tree construction failed." << std::endl;
317  exit( 4 );
318  }
319 
320  // store tree root
321  Tag roottag;
322  rval = interface->tag_get_handle( root_tag, 1, MB_TYPE_HANDLE, roottag, MB_TAG_CREAT | MB_TAG_SPARSE );
323  if( MB_SUCCESS != rval )
324  {
325  std::cout << "Failed to create root tag: \"" << root_tag << '"' << std::endl;
326  exit( 2 );
327  }
328  const EntityHandle mesh = 0;
329  rval = interface->tag_set_data( roottag, &mesh, 1, &root );
330  if( MB_SUCCESS != rval )
331  {
332  std::cout << "Failed to set root tag: \"" << root_tag << '"' << std::endl;
333  exit( 2 );
334  }
335 
336  return root;
337 }
338 
339 std::string clock_to_string( clock_t t )
340 {
341  char unit[5] = "s";
342  char buffer[256];
343  double dt = t / (double)CLOCKS_PER_SEC;
344  // if (dt > 300) {
345  // dt /= 60;
346  // strcpy( unit, "min" );
347  //}
348  // if (dt > 300) {
349  // dt /= 60;
350  // strcpy( unit, "hr" );
351  //}
352  // if (dt > 100) {
353  // dt /= 24;
354  // strcpy( unit, "days" );
355  //}
356  sprintf( buffer, "%0.2f%s", dt, unit );
357  return buffer;
358 }
359 
360 std::string mem_to_string( unsigned long mem )
361 {
362  char unit[3] = "B";
363  if( mem > 9 * 1024 )
364  {
365  mem = ( mem + 512 ) / 1024;
366  strcpy( unit, "kB" );
367  }
368  if( mem > 9 * 1024 )
369  {
370  mem = ( mem + 512 ) / 1024;
371  strcpy( unit, "MB" );
372  }
373  if( mem > 9 * 1024 )
374  {
375  mem = ( mem + 512 ) / 1024;
376  strcpy( unit, "GB" );
377  }
378  char buffer[256];
379  sprintf( buffer, "%lu %s", mem, unit );
380  return buffer;
381 }
382 
383 template < typename T >
385 {
387  size_t count;
389  void add( T value );
390  double avg() const
391  {
392  return (double)sum / count;
393  }
394  double rms() const
395  {
396  return sqrt( (double)sqr / count );
397  }
398  double dev() const
399  {
400  return sqrt( ( count * (double)sqr - (double)sum * (double)sum ) / ( (double)count * ( count - 1 ) ) );
401  }
402 };
403 
404 template < typename T >
406  : min( std::numeric_limits< T >::max() ), max( std::numeric_limits< T >::min() ), sum( 0 ), sqr( 0 ), count( 0 )
407 {
408 }
409 
410 void print_stats( Interface* interface )
411 {
412  EntityHandle root;
413  Range range;
414  ErrorCode rval;
415  rval = get_root( interface, root );
416  if( MB_SUCCESS != rval )
417  {
418  std::cerr << "Internal error: Failed to retrieve root." << std::endl;
419  exit( 5 );
420  }
421  OrientedBoxTreeTool tool( interface );
422 
423  Range tree_sets, triangles, verts;
424  // interface->get_child_meshsets( root, tree_sets, 0 );
425  interface->get_entities_by_type( 0, MBENTITYSET, tree_sets );
426  tree_sets.erase( tree_sets.begin(), Range::lower_bound( tree_sets.begin(), tree_sets.end(), root ) );
427  interface->get_entities_by_type( 0, MBTRI, triangles );
428  interface->get_entities_by_type( 0, MBVERTEX, verts );
429  triangles.merge( verts );
430  tree_sets.insert( root );
431  unsigned long long set_used, set_amortized, set_store_used, set_store_amortized, set_tag_used, set_tag_amortized,
432  tri_used, tri_amortized;
433  interface->estimated_memory_use( tree_sets, &set_used, &set_amortized, &set_store_used, &set_store_amortized, 0, 0,
434  0, 0, &set_tag_used, &set_tag_amortized );
435  interface->estimated_memory_use( triangles, &tri_used, &tri_amortized );
436 
437  int num_tri = 0;
438  interface->get_number_entities_by_type( 0, MBTRI, num_tri );
439 
440  tool.stats( root, std::cout );
441 
442  unsigned long long real_rss, real_vsize;
443  memory_use( real_vsize, real_rss );
444 
445  printf( "------------------------------------------------------------------\n" );
446  printf( "\nmemory: used amortized\n" );
447  printf( " ---------- ----------\n" );
448  printf( "triangles %10s %10s\n", mem_to_string( tri_used ).c_str(), mem_to_string( tri_amortized ).c_str() );
449  printf( "sets (total)%10s %10s\n", mem_to_string( set_used ).c_str(), mem_to_string( set_amortized ).c_str() );
450  printf( "sets %10s %10s\n", mem_to_string( set_store_used ).c_str(),
451  mem_to_string( set_store_amortized ).c_str() );
452  printf( "set tags %10s %10s\n", mem_to_string( set_tag_used ).c_str(),
453  mem_to_string( set_tag_amortized ).c_str() );
454  printf( "total real %10s %10s\n", mem_to_string( real_rss ).c_str(), mem_to_string( real_vsize ).c_str() );
455  printf( "------------------------------------------------------------------\n" );
456 }
457 
458 static int hash_handle( EntityHandle handle )
459 {
460  EntityID h = ID_FROM_HANDLE( handle );
461  return (int)( ( h * 13 + 7 ) % MAX_TAG_VALUE ) + 1;
462 }
463 
465 {
466  private:
469  std::vector< EntityHandle > mHandles;
470  std::vector< int > mTagData;
471 
472  public:
473  TriTagger( Tag tag, Interface* moab ) : mMB( moab ), mTag( tag ) {}
474 
475  ErrorCode visit( EntityHandle, int, bool& descent )
476  {
477  descent = true;
478  return MB_SUCCESS;
479  }
480 
482  {
483  mHandles.clear();
485  mTagData.clear();
486  mTagData.resize( mHandles.size(), hash_handle( node ) );
487  mMB->tag_set_data( mTag, &mHandles[0], mHandles.size(), &mTagData[0] );
488  return MB_SUCCESS;
489  }
490 };
491 
493 {
494  EntityHandle root;
495  ErrorCode rval = get_root( moab, root );
496  if( MB_SUCCESS != rval )
497  {
498  std::cerr << "Internal error: Failed to retrieve tree." << std::endl;
499  exit( 5 );
500  }
501 
502  Tag tag;
503  int zero = 0;
504  moab->tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero );
505  TriTagger op( tag, moab );
506 
507  OrientedBoxTreeTool tool( moab );
508  rval = tool.preorder_traverse( root, op );
509  if( MB_SUCCESS != rval )
510  {
511  std::cerr << "Internal error tagging triangles" << std::endl;
512  exit( 5 );
513  }
514 }
515 
517 {
518  private:
521  std::vector< EntityHandle > mHandles;
522  std::vector< EntityHandle > mConn;
523  std::vector< int > mTagData;
524 
525  public:
526  VtxTagger( Tag tag, Interface* moab ) : mMB( moab ), mTag( tag ) {}
527 
528  ErrorCode visit( EntityHandle, int, bool& descent )
529  {
530  descent = true;
531  return MB_SUCCESS;
532  }
533 
535  {
536  mHandles.clear();
538  mConn.clear();
539  mMB->get_connectivity( &mHandles[0], mHandles.size(), mConn );
540  mTagData.clear();
541  mTagData.resize( mConn.size(), hash_handle( node ) );
542  mMB->tag_set_data( mTag, &mConn[0], mConn.size(), &mTagData[0] );
543  return MB_SUCCESS;
544  }
545 };
546 
548 {
549  EntityHandle root;
550  ErrorCode rval = get_root( moab, root );
551  if( MB_SUCCESS != rval )
552  {
553  std::cerr << "Internal error: Failed to retrieve tree." << std::endl;
554  exit( 5 );
555  }
556 
557  Tag tag;
558  int zero = 0;
559  moab->tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero );
560  VtxTagger op( tag, moab );
561 
562  OrientedBoxTreeTool tool( moab );
563  rval = tool.preorder_traverse( root, op );
564  if( MB_SUCCESS != rval )
565  {
566  std::cerr << "Internal error tagging vertices" << std::endl;
567  exit( 5 );
568  }
569 }
570 
572 {
573  private:
577  std::vector< EntityHandle > mHandles;
578  std::vector< EntityHandle > mConn;
579  std::vector< int > mTagData;
580 
581  public:
582  LeafHexer( OrientedBoxTreeTool* tool, Interface* mb2, Tag tag ) : mTool( tool ), mOut( mb2 ), mTag( tag ) {}
583 
584  ErrorCode visit( EntityHandle, int, bool& descent )
585  {
586  descent = true;
587  return MB_SUCCESS;
588  }
589 
591  {
593  ErrorCode rval = mTool->box( node, box );
594  if( MB_SUCCESS != rval ) return rval;
595  EntityHandle h;
596  rval = box.make_hex( h, mOut );
597  if( MB_SUCCESS != rval ) return rval;
598  int i = hash_handle( node );
599  return mOut->tag_set_data( mTag, &h, 1, &i );
600  }
601 };
602 
603 void write_tree_blocks( Interface* interface, const char* file )
604 {
605  EntityHandle root;
606  ErrorCode rval = get_root( interface, root );
607  if( MB_SUCCESS != rval )
608  {
609  std::cerr << "Internal error: Failed to retrieve tree." << std::endl;
610  exit( 5 );
611  }
612 
613  Core moab2;
614  Tag tag;
615  int zero = 0;
617 
618  OrientedBoxTreeTool tool( interface );
619  LeafHexer op( &tool, &moab2, tag );
620  rval = tool.preorder_traverse( root, op );
621  if( MB_SUCCESS != rval )
622  {
623  std::cerr << "Internal error: failed to construct leaf hexes" << std::endl;
624  exit( 5 );
625  }
626 
627  moab2.write_mesh( file );
628 }