MOAB: Mesh Oriented datABase  (version 5.4.1)
obb_tree_tool.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines