MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 #define IS_BUILDING_MB 00002 #include "moab/Core.hpp" 00003 #include "moab/CartVect.hpp" 00004 #include "moab/OrientedBoxTreeTool.hpp" 00005 #include "moab/OrientedBox.hpp" 00006 #include "Internals.hpp" 00007 #include "moab/Range.hpp" 00008 00009 #include <iostream> 00010 #include <iomanip> 00011 #include <cstdio> 00012 #include <limits> 00013 #include <cstdlib> 00014 #include <ctime> 00015 #if !defined( _MSC_VER ) && !defined( __MINGW32__ ) 00016 #include <unistd.h> 00017 #include <sys/stat.h> 00018 #include <fcntl.h> 00019 #endif 00020 00021 using namespace moab; 00022 00023 std::string clock_to_string( clock_t t ); 00024 std::string mem_to_string( unsigned long mem ); 00025 00026 const int MAX_TAG_VALUE = 20; 00027 const char* const TAG_NAME = "OBB_ID"; 00028 const char* const TREE_TAG = "OBB_ROOT"; 00029 const char* root_tag = TREE_TAG; 00030 00031 ErrorCode get_root( Interface* moab, EntityHandle& root ); 00032 EntityHandle build_tree( Interface* interface, OrientedBoxTreeTool::Settings settings ); 00033 void delete_existing_tree( Interface* interface ); 00034 void print_stats( Interface* interface ); 00035 void tag_triangles( Interface* interface ); 00036 void tag_vertices( Interface* interface ); 00037 void write_tree_blocks( Interface* interface, const char* file ); 00038 00039 static void usage( bool err = true ) 00040 { 00041 std::ostream& s = err ? std::cerr : std::cout; 00042 s << "obb_tree_tool [-s|-S] [-d <int>] [-n <int>] <input file> <output file>" << std::endl 00043 << "obb_tree_tool [-h]" << std::endl; 00044 if( !err ) 00045 { 00046 OrientedBoxTreeTool::Settings st; 00047 s << "Tool to build adaptive kd-Tree from triangles" << std::endl; 00048 s << " -s Use range-based sets for tree nodes" << std::endl 00049 << " -S Use vector-based sets for tree nodes" << std::endl 00050 << " -d <int> Specify maximum depth for tree. Default: " << st.max_depth << std::endl 00051 << " -n <int> Specify maximum entities per leaf. Default: " << st.max_leaf_entities << std::endl 00052 << " -m <real> Specify worst split ratio. Default: " << st.worst_split_ratio << std::endl 00053 << " -M <real> Specify best split ratio. Default: " << st.best_split_ratio << std::endl 00054 << " -t Tag triangles will tree cell number." << std::endl 00055 << " -T Write tree boxes to file." << std::endl 00056 << " -N Specify mesh tag containing tree root. Default: \"" << TREE_TAG << '"' << std::endl 00057 << std::endl; 00058 } 00059 exit( err ); 00060 } 00061 00062 #if defined( _MSC_VER ) || defined( __MINGW32__ ) 00063 static void memory_use( unsigned long long& vsize, unsigned long long& rss ) 00064 { 00065 vsize = rss = 0; 00066 } 00067 #else 00068 static void memory_use( unsigned long long& vsize, unsigned long long& rss ) 00069 { 00070 char buffer[512]; 00071 unsigned long lvsize; 00072 long lrss; 00073 int filp = open( "/proc/self/stat", O_RDONLY ); 00074 ssize_t r = read( filp, buffer, sizeof( buffer ) - 1 ); 00075 close( filp ); 00076 if( r < 0 ) r = 0; 00077 lvsize = lrss = 0; 00078 buffer[r] = '\0'; 00079 sscanf( buffer, 00080 "%*d %*s %*c " // pid command state 00081 "%*d %*d " // ppid pgrp 00082 "%*d %*d %*d " // session tty_nr tpgid 00083 "%*u " // flags 00084 "%*u %*u %*u %*u " // minflt cminflt majflt cmajflt 00085 "%*u %*u %*d %*d " // utime stime cutime cstime 00086 "%*d %*d %*d " // priority nice (unused) 00087 "%*d %*u " // itrealval starttime 00088 "%lu %ld", 00089 &lvsize, &lrss ); 00090 rss = lrss * getpagesize(); 00091 vsize = lvsize; 00092 } 00093 #endif 00094 00095 static int parseint( int& i, int argc, char* argv[] ) 00096 { 00097 char* end; 00098 ++i; 00099 if( i == argc ) 00100 { 00101 std::cerr << "Expected value following '" << argv[i - 1] << "'" << std::endl; 00102 usage(); 00103 } 00104 00105 int result = strtol( argv[i], &end, 0 ); 00106 if( result < 0 || *end ) 00107 { 00108 std::cerr << "Expected positive integer following '" << argv[i - 1] << "'" << std::endl; 00109 usage(); 00110 } 00111 00112 return result; 00113 } 00114 00115 static double parsedouble( int& i, int argc, char* argv[] ) 00116 { 00117 char* end; 00118 ++i; 00119 if( i == argc ) 00120 { 00121 std::cerr << "Expected value following '" << argv[i - 1] << "'" << std::endl; 00122 usage(); 00123 } 00124 00125 double result = strtod( argv[i], &end ); 00126 if( result < 0 || *end ) 00127 { 00128 std::cerr << "Expected positive real number following '" << argv[i - 1] << "'" << std::endl; 00129 usage(); 00130 } 00131 00132 return result; 00133 } 00134 00135 int main( int argc, char* argv[] ) 00136 { 00137 const char* input_file = 0; 00138 const char* output_file = 0; 00139 const char* tree_file = 0; 00140 OrientedBoxTreeTool::Settings settings; 00141 bool tag_tris = false; 00142 clock_t load_time, build_time, stat_time, tag_time, write_time, block_time; 00143 00144 for( int i = 1; i < argc; ++i ) 00145 { 00146 if( argv[i][0] != '-' ) 00147 { 00148 if( !input_file ) 00149 input_file = argv[i]; 00150 else if( !output_file ) 00151 output_file = argv[i]; 00152 else 00153 usage(); 00154 continue; 00155 } 00156 00157 if( !argv[i][1] || argv[i][2] ) usage(); 00158 00159 switch( argv[i][1] ) 00160 { 00161 case 's': 00162 settings.set_options = MESHSET_SET; 00163 break; 00164 case 'S': 00165 settings.set_options = MESHSET_ORDERED; 00166 break; 00167 case 'd': 00168 settings.max_depth = parseint( i, argc, argv ); 00169 break; 00170 case 'n': 00171 settings.max_leaf_entities = parseint( i, argc, argv ); 00172 break; 00173 case 'm': 00174 settings.worst_split_ratio = parsedouble( i, argc, argv ); 00175 break; 00176 case 'M': 00177 settings.best_split_ratio = parsedouble( i, argc, argv ); 00178 break; 00179 case 't': 00180 tag_tris = true; 00181 break; 00182 case 'T': 00183 if( ++i == argc ) usage(); 00184 tree_file = argv[i]; 00185 break; 00186 case 'N': 00187 if( ++i == argc ) usage(); 00188 root_tag = argv[i]; 00189 break; 00190 case 'h': 00191 usage( false ); 00192 break; 00193 default: 00194 usage(); 00195 } 00196 } 00197 00198 if( !output_file ) usage(); 00199 00200 ErrorCode rval; 00201 Core moab_core; 00202 Interface* interface = &moab_core; 00203 00204 load_time = clock(); 00205 rval = interface->load_mesh( input_file ); 00206 if( MB_SUCCESS != rval ) 00207 { 00208 std::cerr << "Error reading file: " << input_file << std::endl; 00209 exit( 2 ); 00210 } 00211 load_time = clock() - load_time; 00212 00213 delete_existing_tree( interface ); 00214 00215 std::cout << "Building tree..." << std::endl; 00216 build_time = clock(); 00217 build_tree( interface, settings ); 00218 build_time = clock() - build_time; 00219 00220 std::cout << "Calculating stats..." << std::endl; 00221 print_stats( interface ); 00222 stat_time = clock() - build_time; 00223 00224 if( tag_tris ) 00225 { 00226 std::cout << "Tagging tree..." << std::endl; 00227 tag_triangles( interface ); 00228 tag_vertices( interface ); 00229 } 00230 tag_time = clock() - stat_time; 00231 00232 std::cout << "Writing file... "; 00233 std::cout.flush(); 00234 rval = interface->write_mesh( output_file ); 00235 if( MB_SUCCESS != rval ) 00236 { 00237 std::cerr << "Error writing file: " << output_file << std::endl; 00238 exit( 3 ); 00239 } 00240 write_time = clock() - tag_time; 00241 std::cout << "Wrote " << output_file << std::endl; 00242 00243 if( tree_file ) 00244 { 00245 std::cout << "Writing tree block rep..."; 00246 std::cout.flush(); 00247 write_tree_blocks( interface, tree_file ); 00248 std::cout << "Wrote " << tree_file << std::endl; 00249 } 00250 block_time = clock() - write_time; 00251 00252 std::cout << "Times: " 00253 << " Load" 00254 << " Build" 00255 << " Stats" 00256 << " Write"; 00257 if( tag_tris ) std::cout << "Tag Sets"; 00258 if( tree_file ) std::cout << "Block "; 00259 std::cout << std::endl; 00260 00261 std::cout << " " << std::setw( 8 ) << clock_to_string( load_time ) << std::setw( 8 ) 00262 << clock_to_string( build_time ) << std::setw( 8 ) << clock_to_string( stat_time ) << std::setw( 8 ) 00263 << clock_to_string( write_time ); 00264 if( tag_tris ) std::cout << std::setw( 8 ) << clock_to_string( tag_time ); 00265 if( tree_file ) std::cout << std::setw( 8 ) << clock_to_string( block_time ); 00266 std::cout << std::endl; 00267 00268 return 0; 00269 } 00270 00271 ErrorCode get_root( Interface* moab, EntityHandle& root ) 00272 { 00273 Tag tag; 00274 ErrorCode rval; 00275 00276 rval = moab->tag_get_handle( root_tag, 1, MB_TYPE_HANDLE, tag ); 00277 if( MB_SUCCESS != rval ) return rval; 00278 00279 const EntityHandle mesh = 0; 00280 return moab->tag_get_data( tag, &mesh, 1, &root ); 00281 } 00282 00283 void delete_existing_tree( Interface* interface ) 00284 { 00285 EntityHandle root; 00286 ErrorCode rval = get_root( interface, root ); 00287 if( MB_SUCCESS == rval ) 00288 { 00289 OrientedBoxTreeTool tool( interface ); 00290 rval = tool.delete_tree( root ); 00291 if( MB_SUCCESS != rval ) 00292 { 00293 std::cerr << "Failed to destroy existing trees. Aborting" << std::endl; 00294 exit( 5 ); 00295 } 00296 } 00297 } 00298 00299 EntityHandle build_tree( Interface* interface, OrientedBoxTreeTool::Settings settings ) 00300 { 00301 ErrorCode rval; 00302 EntityHandle root = 0; 00303 Range triangles; 00304 00305 rval = interface->get_entities_by_type( 0, MBTRI, triangles ); 00306 if( MB_SUCCESS != rval || triangles.empty() ) 00307 { 00308 std::cerr << "No triangles from which to build tree." << std::endl; 00309 exit( 4 ); 00310 } 00311 00312 OrientedBoxTreeTool tool( interface ); 00313 rval = tool.build( triangles, root, &settings ); 00314 if( MB_SUCCESS != rval || !root ) 00315 { 00316 std::cerr << "Tree construction failed." << std::endl; 00317 exit( 4 ); 00318 } 00319 00320 // store tree root 00321 Tag roottag; 00322 rval = interface->tag_get_handle( root_tag, 1, MB_TYPE_HANDLE, roottag, MB_TAG_CREAT | MB_TAG_SPARSE ); 00323 if( MB_SUCCESS != rval ) 00324 { 00325 std::cout << "Failed to create root tag: \"" << root_tag << '"' << std::endl; 00326 exit( 2 ); 00327 } 00328 const EntityHandle mesh = 0; 00329 rval = interface->tag_set_data( roottag, &mesh, 1, &root ); 00330 if( MB_SUCCESS != rval ) 00331 { 00332 std::cout << "Failed to set root tag: \"" << root_tag << '"' << std::endl; 00333 exit( 2 ); 00334 } 00335 00336 return root; 00337 } 00338 00339 std::string clock_to_string( clock_t t ) 00340 { 00341 char unit[5] = "s"; 00342 char buffer[256]; 00343 double dt = t / (double)CLOCKS_PER_SEC; 00344 // if (dt > 300) { 00345 // dt /= 60; 00346 // strcpy( unit, "min" ); 00347 //} 00348 // if (dt > 300) { 00349 // dt /= 60; 00350 // strcpy( unit, "hr" ); 00351 //} 00352 // if (dt > 100) { 00353 // dt /= 24; 00354 // strcpy( unit, "days" ); 00355 //} 00356 sprintf( buffer, "%0.2f%s", dt, unit ); 00357 return buffer; 00358 } 00359 00360 std::string mem_to_string( unsigned long mem ) 00361 { 00362 char unit[3] = "B"; 00363 if( mem > 9 * 1024 ) 00364 { 00365 mem = ( mem + 512 ) / 1024; 00366 strcpy( unit, "kB" ); 00367 } 00368 if( mem > 9 * 1024 ) 00369 { 00370 mem = ( mem + 512 ) / 1024; 00371 strcpy( unit, "MB" ); 00372 } 00373 if( mem > 9 * 1024 ) 00374 { 00375 mem = ( mem + 512 ) / 1024; 00376 strcpy( unit, "GB" ); 00377 } 00378 char buffer[256]; 00379 sprintf( buffer, "%lu %s", mem, unit ); 00380 return buffer; 00381 } 00382 00383 template < typename T > 00384 struct SimpleStat 00385 { 00386 T min, max, sum, sqr; 00387 size_t count; 00388 SimpleStat(); 00389 void add( T value ); 00390 double avg() const 00391 { 00392 return (double)sum / count; 00393 } 00394 double rms() const 00395 { 00396 return sqrt( (double)sqr / count ); 00397 } 00398 double dev() const 00399 { 00400 return sqrt( ( count * (double)sqr - (double)sum * (double)sum ) / ( (double)count * ( count - 1 ) ) ); 00401 } 00402 }; 00403 00404 template < typename T > 00405 SimpleStat< T >::SimpleStat() 00406 : min( std::numeric_limits< T >::max() ), max( std::numeric_limits< T >::min() ), sum( 0 ), sqr( 0 ), count( 0 ) 00407 { 00408 } 00409 00410 void print_stats( Interface* interface ) 00411 { 00412 EntityHandle root; 00413 Range range; 00414 ErrorCode rval; 00415 rval = get_root( interface, root ); 00416 if( MB_SUCCESS != rval ) 00417 { 00418 std::cerr << "Internal error: Failed to retrieve root." << std::endl; 00419 exit( 5 ); 00420 } 00421 OrientedBoxTreeTool tool( interface ); 00422 00423 Range tree_sets, triangles, verts; 00424 // interface->get_child_meshsets( root, tree_sets, 0 ); 00425 interface->get_entities_by_type( 0, MBENTITYSET, tree_sets ); 00426 tree_sets.erase( tree_sets.begin(), Range::lower_bound( tree_sets.begin(), tree_sets.end(), root ) ); 00427 interface->get_entities_by_type( 0, MBTRI, triangles ); 00428 interface->get_entities_by_type( 0, MBVERTEX, verts ); 00429 triangles.merge( verts ); 00430 tree_sets.insert( root ); 00431 unsigned long long set_used, set_amortized, set_store_used, set_store_amortized, set_tag_used, set_tag_amortized, 00432 tri_used, tri_amortized; 00433 interface->estimated_memory_use( tree_sets, &set_used, &set_amortized, &set_store_used, &set_store_amortized, 0, 0, 00434 0, 0, &set_tag_used, &set_tag_amortized ); 00435 interface->estimated_memory_use( triangles, &tri_used, &tri_amortized ); 00436 00437 int num_tri = 0; 00438 interface->get_number_entities_by_type( 0, MBTRI, num_tri ); 00439 00440 tool.stats( root, std::cout ); 00441 00442 unsigned long long real_rss, real_vsize; 00443 memory_use( real_vsize, real_rss ); 00444 00445 printf( "------------------------------------------------------------------\n" ); 00446 printf( "\nmemory: used amortized\n" ); 00447 printf( " ---------- ----------\n" ); 00448 printf( "triangles %10s %10s\n", mem_to_string( tri_used ).c_str(), mem_to_string( tri_amortized ).c_str() ); 00449 printf( "sets (total)%10s %10s\n", mem_to_string( set_used ).c_str(), mem_to_string( set_amortized ).c_str() ); 00450 printf( "sets %10s %10s\n", mem_to_string( set_store_used ).c_str(), 00451 mem_to_string( set_store_amortized ).c_str() ); 00452 printf( "set tags %10s %10s\n", mem_to_string( set_tag_used ).c_str(), 00453 mem_to_string( set_tag_amortized ).c_str() ); 00454 printf( "total real %10s %10s\n", mem_to_string( real_rss ).c_str(), mem_to_string( real_vsize ).c_str() ); 00455 printf( "------------------------------------------------------------------\n" ); 00456 } 00457 00458 static int hash_handle( EntityHandle handle ) 00459 { 00460 EntityID h = ID_FROM_HANDLE( handle ); 00461 return (int)( ( h * 13 + 7 ) % MAX_TAG_VALUE ) + 1; 00462 } 00463 00464 class TriTagger : public OrientedBoxTreeTool::Op 00465 { 00466 private: 00467 Interface* mMB; 00468 Tag mTag; 00469 std::vector< EntityHandle > mHandles; 00470 std::vector< int > mTagData; 00471 00472 public: 00473 TriTagger( Tag tag, Interface* moab ) : mMB( moab ), mTag( tag ) {} 00474 00475 ErrorCode visit( EntityHandle, int, bool& descent ) 00476 { 00477 descent = true; 00478 return MB_SUCCESS; 00479 } 00480 00481 ErrorCode leaf( EntityHandle node ) 00482 { 00483 mHandles.clear(); 00484 mMB->get_entities_by_handle( node, mHandles ); 00485 mTagData.clear(); 00486 mTagData.resize( mHandles.size(), hash_handle( node ) ); 00487 mMB->tag_set_data( mTag, &mHandles[0], mHandles.size(), &mTagData[0] ); 00488 return MB_SUCCESS; 00489 } 00490 }; 00491 00492 void tag_triangles( Interface* moab ) 00493 { 00494 EntityHandle root; 00495 ErrorCode rval = get_root( moab, root ); 00496 if( MB_SUCCESS != rval ) 00497 { 00498 std::cerr << "Internal error: Failed to retrieve tree." << std::endl; 00499 exit( 5 ); 00500 } 00501 00502 Tag tag; 00503 int zero = 0; 00504 moab->tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero ); 00505 TriTagger op( tag, moab ); 00506 00507 OrientedBoxTreeTool tool( moab ); 00508 rval = tool.preorder_traverse( root, op ); 00509 if( MB_SUCCESS != rval ) 00510 { 00511 std::cerr << "Internal error tagging triangles" << std::endl; 00512 exit( 5 ); 00513 } 00514 } 00515 00516 class VtxTagger : public OrientedBoxTreeTool::Op 00517 { 00518 private: 00519 Interface* mMB; 00520 Tag mTag; 00521 std::vector< EntityHandle > mHandles; 00522 std::vector< EntityHandle > mConn; 00523 std::vector< int > mTagData; 00524 00525 public: 00526 VtxTagger( Tag tag, Interface* moab ) : mMB( moab ), mTag( tag ) {} 00527 00528 ErrorCode visit( EntityHandle, int, bool& descent ) 00529 { 00530 descent = true; 00531 return MB_SUCCESS; 00532 } 00533 00534 ErrorCode leaf( EntityHandle node ) 00535 { 00536 mHandles.clear(); 00537 mMB->get_entities_by_handle( node, mHandles ); 00538 mConn.clear(); 00539 mMB->get_connectivity( &mHandles[0], mHandles.size(), mConn ); 00540 mTagData.clear(); 00541 mTagData.resize( mConn.size(), hash_handle( node ) ); 00542 mMB->tag_set_data( mTag, &mConn[0], mConn.size(), &mTagData[0] ); 00543 return MB_SUCCESS; 00544 } 00545 }; 00546 00547 void tag_vertices( Interface* moab ) 00548 { 00549 EntityHandle root; 00550 ErrorCode rval = get_root( moab, root ); 00551 if( MB_SUCCESS != rval ) 00552 { 00553 std::cerr << "Internal error: Failed to retrieve tree." << std::endl; 00554 exit( 5 ); 00555 } 00556 00557 Tag tag; 00558 int zero = 0; 00559 moab->tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero ); 00560 VtxTagger op( tag, moab ); 00561 00562 OrientedBoxTreeTool tool( moab ); 00563 rval = tool.preorder_traverse( root, op ); 00564 if( MB_SUCCESS != rval ) 00565 { 00566 std::cerr << "Internal error tagging vertices" << std::endl; 00567 exit( 5 ); 00568 } 00569 } 00570 00571 class LeafHexer : public OrientedBoxTreeTool::Op 00572 { 00573 private: 00574 OrientedBoxTreeTool* mTool; 00575 Interface* mOut; 00576 Tag mTag; 00577 std::vector< EntityHandle > mHandles; 00578 std::vector< EntityHandle > mConn; 00579 std::vector< int > mTagData; 00580 00581 public: 00582 LeafHexer( OrientedBoxTreeTool* tool, Interface* mb2, Tag tag ) : mTool( tool ), mOut( mb2 ), mTag( tag ) {} 00583 00584 ErrorCode visit( EntityHandle, int, bool& descent ) 00585 { 00586 descent = true; 00587 return MB_SUCCESS; 00588 } 00589 00590 ErrorCode leaf( EntityHandle node ) 00591 { 00592 OrientedBox box; 00593 ErrorCode rval = mTool->box( node, box ); 00594 if( MB_SUCCESS != rval ) return rval; 00595 EntityHandle h; 00596 rval = box.make_hex( h, mOut ); 00597 if( MB_SUCCESS != rval ) return rval; 00598 int i = hash_handle( node ); 00599 return mOut->tag_set_data( mTag, &h, 1, &i ); 00600 } 00601 }; 00602 00603 void write_tree_blocks( Interface* interface, const char* file ) 00604 { 00605 EntityHandle root; 00606 ErrorCode rval = get_root( interface, root ); 00607 if( MB_SUCCESS != rval ) 00608 { 00609 std::cerr << "Internal error: Failed to retrieve tree." << std::endl; 00610 exit( 5 ); 00611 } 00612 00613 Core moab2; 00614 Tag tag; 00615 int zero = 0; 00616 moab2.tag_get_handle( TAG_NAME, 1, MB_TYPE_INTEGER, tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero ); 00617 00618 OrientedBoxTreeTool tool( interface ); 00619 LeafHexer op( &tool, &moab2, tag ); 00620 rval = tool.preorder_traverse( root, op ); 00621 if( MB_SUCCESS != rval ) 00622 { 00623 std::cerr << "Internal error: failed to construct leaf hexes" << std::endl; 00624 exit( 5 ); 00625 } 00626 00627 moab2.write_mesh( file ); 00628 }