moab
obb_analysis.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 #include <fstream>
00003 #include <sstream>
00004 
00005 #include "dagmc_preproc.hpp"
00006 #include "DagMC.hpp"
00007 #include "moab/Core.hpp"
00008 #include "moab/Interface.hpp"
00009 #include "moab/OrientedBoxTreeTool.hpp"
00010 #include "moab/CartVect.hpp"
00011 
00012 #include "OrientedBox.hpp"
00013 
00014 using namespace moab;
00015 
00016 class TriCounter : public OrientedBoxTreeTool::Op { 
00017 
00018 
00019 public:   
00020   int count;
00021   Interface* mbi;
00022   OrientedBoxTreeTool* tool;
00023   const CartVect& pt;
00024 
00025   TriCounter( Interface* mbi_p, OrientedBoxTreeTool *tool_p, const CartVect& p ):
00026     OrientedBoxTreeTool::Op(), count(0), mbi(mbi_p), tool(tool_p), pt(p)
00027   {}
00028 
00029   virtual ErrorCode visit( EntityHandle node,int , bool& descend ){
00030     OrientedBox box;
00031     ErrorCode rval = tool->box( node, box );
00032     
00033     descend = box.contained( pt, 1e-6 );
00034 
00035     return rval;
00036   }
00037   
00038   virtual ErrorCode leaf( EntityHandle node ){
00039 
00040     int numtris;
00041     ErrorCode rval = tool->get_moab_instance()->get_number_entities_by_type( node, MBTRI, numtris );
00042     count += numtris;
00043     return rval;
00044   }
00045 
00046 };
00047 
00048 ErrorCode obbvis_create( DagMC& dag, std::vector<int> &volumes, int grid, std::string& filename ){
00049 
00050   ErrorCode rval = MB_SUCCESS;
00051   OrientedBoxTreeTool& obbtool = *dag.obb_tree();
00052   
00053   CartVect min, max;
00054   EntityHandle vol = dag.entity_by_id( 3, volumes.front() );
00055   rval = dag.getobb( vol, min.array(), max.array() );
00056   CHECKERR(dag, rval);
00057 
00058   /* Compute an axis-aligned bounding box of all the requested volumes */
00059   for( std::vector<int>::iterator i = volumes.begin()+1; i!=volumes.end(); ++i ){
00060     CartVect i_min, i_max; 
00061     vol = dag.entity_by_id( 3, *i );
00062     rval = dag.getobb( vol, i_min.array(), i_max.array() );
00063     for( int j = 0; j < 3; ++j ){ 
00064       min[j] = std::min( min[j], i_min[j] );
00065       max[j] = std::max( max[j], i_max[j] );
00066     }
00067   }
00068 
00069   // These vectors could be repurposed to describe an OBB without changing the loops below
00070   CartVect center = (min+max) / 2.0;
00071   CartVect v1(max[0]-min[0]/2,0,0);
00072   CartVect v2(0,max[1]-min[1]/2,0);
00073   CartVect v3(0,0,max[2]-min[2]/2);
00074   
00075   /* Compute the vertices of the visualization grid.  Calculation points are at the center 
00076      of each cell in this grid, so make grid+1 vertices in each direction. */
00077   int numpoints = pow((double)(grid+1),3);
00078   double* pgrid = new double[ numpoints * 3 ];
00079   int idx = 0;
00080 
00081 
00082   for( int i = 0; i <= grid; ++i ){
00083     CartVect x = -v1 + ((v1*2.0) * (i/(double)grid));
00084 
00085     for( int j = 0; j <= grid; ++j ){
00086       CartVect y = -v2 + ((v2*2.0) * (j/(double)grid));
00087 
00088       for( int k = 0; k <= grid; ++k ){        
00089         CartVect z = -v3 + ((v3*2.0) * (k/(double)grid));
00090         
00091         CartVect p = center + x + y + z;
00092         for( int d = 0; d<3; ++d ){ pgrid[idx++] = p[d]; }
00093       }
00094     }
00095   }
00096 
00097   /* Create a new MOAB to use for output, and build the vertex grid */
00098   Core mb2;
00099   Range r;
00100   rval = mb2.create_vertices( pgrid, numpoints, r);
00101   CHECKERR( mb2, rval );
00102   
00103   Tag lttag;
00104   rval = mb2.tag_get_handle( "LEAFTRIS", sizeof(int), MB_TYPE_INTEGER, lttag,
00105                              MB_TAG_EXCL|MB_TAG_CREAT|MB_TAG_BYTES|MB_TAG_DENSE, 0);
00106   CHECKERR( mb2, rval );
00107 
00108   int row = grid + 1;
00109   int side = row * row;
00110   EntityHandle connect[8];
00111   EntityHandle hex;
00112 
00113   // offset from grid corner to grid center 
00114   CartVect grid_hex_center_offset = (v1+v2+v3) * 2 * (1.0 / grid);
00115 
00116 
00117   // collect all the surfaces from the requested volumes to iterate over --
00118   // this prevents checking a shared surface more than once.
00119   Range surfs;
00120   for(  std::vector<int>::iterator it = volumes.begin(); it!=volumes.end(); ++it ){
00121     
00122     vol = dag.entity_by_id(3,*it);
00123     Range it_surfs;
00124     rval = dag.moab_instance()->get_child_meshsets( vol, it_surfs );
00125     CHECKERR(dag,rval);
00126     surfs.merge(it_surfs);
00127 
00128   }
00129   std::cout << "visualizing " << surfs.size() << " surfaces." << std::endl;
00130 
00131   /* Build hexes for any point with 1 or more leaftris */
00132   for( int i = 0; i < grid; ++i ){
00133     for( int j = 0; j < grid; ++j ){
00134       for( int k = 0; k < grid; ++k ){
00135 
00136         idx = (side * k) + (row * j) + i;
00137     assert( idx + 1 + row + side > numpoints - 1 );
00138 
00139         CartVect loc = CartVect((pgrid+(idx*3)) ) + grid_hex_center_offset ;
00140         TriCounter tc(dag.moab_instance(), &obbtool, loc );
00141 
00142     for( Range::iterator it = surfs.begin(); it!=surfs.end(); ++it ){
00143       
00144       EntityHandle surf_tree;
00145       rval = dag.get_root( *it, surf_tree );
00146       CHECKERR(dag,rval);
00147 
00148       rval = obbtool.preorder_traverse( surf_tree, tc );
00149       CHECKERR(dag,rval);
00150 
00151     }
00152 
00153     if( tc.count == 0 ) continue; 
00154 
00155         connect[0] = r[ idx ];
00156         connect[1] = r[ idx + 1       ];
00157         connect[2] = r[ idx + 1 + row ];
00158         connect[3] = r[ idx +     row ];
00159         connect[4] = r[ idx +           side ];
00160         connect[5] = r[ idx + 1 +       side ];
00161         connect[6] = r[ idx + 1 + row + side ];
00162         connect[7] = r[ idx +     row + side ];
00163 
00164         rval = mb2.create_element( MBHEX, connect, 8, hex );
00165         CHECKERR(mb2,rval);
00166 
00167         rval = mb2.tag_set_data( lttag, &hex, 1, &(tc.count) );
00168         CHECKERR(mb2,rval);
00169 
00170       }
00171     }
00172   }
00173 
00174   if( verbose ){ std::cout << "Writing " << filename << std::endl; }
00175   rval = mb2.write_file( filename.c_str() );
00176   CHECKERR(mb2,rval);
00177 
00178   return rval;
00179 }
00180 
00181 // stats code borrowed from OrientedBoxTreeTool.cpp
00182 static inline double std_dev( double sqr, double sum, double count )
00183 {
00184   sum /= count;
00185   sqr /= count;
00186   return sqrt( sqr - sum*sum );
00187 }
00188 
00189 class TriStats : public OrientedBoxTreeTool::Op { 
00190 
00191 
00192 public:   
00193   unsigned min, max, sum, leaves;
00194   double sqr;
00195 
00196   const static unsigned ten_buckets_max = 5;
00197   unsigned ten_buckets[ ten_buckets_max ];
00198   double ten_buckets_vol[ ten_buckets_max ];
00199 
00200   Interface* mbi;
00201   OrientedBoxTreeTool* tool;
00202 
00203   double tot_vol; 
00204   
00205   TriStats( Interface* mbi_p, OrientedBoxTreeTool *tool_p, EntityHandle root):
00206     OrientedBoxTreeTool::Op(), sum(0), leaves(0), sqr(0), mbi(mbi_p), tool(tool_p)
00207   {
00208     min = std::numeric_limits<unsigned>::max();
00209     max = std::numeric_limits<unsigned>::min();
00210     
00211     for( unsigned i = 0; i < ten_buckets_max; ++i ){ 
00212       ten_buckets[i] = 0; 
00213       ten_buckets_vol[i] = 0.;
00214     }
00215 
00216     OrientedBox box;
00217     ErrorCode rval = tool->box( root, box );
00218     CHECKERR( mbi, rval );
00219     tot_vol = box.volume();
00220 
00221   }
00222 
00223   virtual ErrorCode visit( EntityHandle ,int , bool& descend ){
00224     
00225     descend = true;
00226     return MB_SUCCESS;
00227 
00228   }
00229   
00230   virtual ErrorCode leaf( EntityHandle node ){
00231 
00232      Range tris;
00233      ErrorCode rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
00234      unsigned count = tris.size();
00235 
00236      sum += count;
00237      sqr += (count * count);
00238      if( min > count ) min = count;
00239      if( max < count ) max = count;
00240      
00241      for( unsigned i = 0; i < ten_buckets_max; ++i ){
00242        if( count > std::pow((double)10,(int)(i+1)) ){ 
00243      ten_buckets[i] += 1; 
00244      OrientedBox box;
00245      rval = tool->box( node, box );
00246      CHECKERR( mbi, rval );
00247      ten_buckets_vol[i] += box.volume();
00248        } 
00249      }
00250 
00251      leaves++;
00252 
00253      return rval;
00254   }
00255 
00256   std::string commafy( int num ){
00257     std::stringstream str;
00258     str << num;
00259     std::string s = str.str();
00260     
00261     int n = s.size();
00262     for( int i = n-3; i >= 1; i -= 3 ){
00263       s.insert(i, 1, ',');
00264       n++;
00265     }
00266 
00267     return s;
00268 
00269   }
00270   
00271   void write_results( std::ostream& out ){
00272 
00273     out << commafy(sum) << " triangles in " << commafy(leaves) << " leaves." << std::endl;
00274 
00275     double avg = sum / (double)leaves; 
00276     double stddev = std_dev( sqr, sum, leaves );
00277 
00278     out << "Tris per leaf: Min " << min << ", Max " << max << ", avg " << avg << ", stddev " << stddev << std::endl;
00279 
00280     for (unsigned i = 0; i < ten_buckets_max; ++i ){
00281       if( ten_buckets[i] ){
00282         out << "Leaves exceeding " << std::pow((double)10,(int)(i+1)) << " triangles: " << ten_buckets[i];
00283     
00284     double frac_total_vol =  ten_buckets_vol[i]/tot_vol;
00285     double avg_ftv = frac_total_vol / ten_buckets[i];
00286 
00287     out << " (avg " << avg_ftv * 100.0 << "% of OBB volume)" << std::endl;
00288       }
00289     }
00290   }
00291 
00292 };
00293 
00294 static std::string make_property_string( DagMC& dag, EntityHandle eh, std::vector<std::string> &properties )
00295 {
00296   ErrorCode ret;
00297   std::string propstring;
00298   for( std::vector<std::string>::iterator p = properties.begin();
00299     p != properties.end(); ++p )
00300   {
00301     if( dag.has_prop( eh, *p ) ){
00302       std::vector< std::string> vals;
00303       ret = dag.prop_values( eh, *p, vals );
00304       CHECKERR(dag,ret);
00305       propstring += *p;
00306       if( vals.size() == 1 ){
00307         propstring += "=";
00308         propstring += vals[0];
00309       }
00310       else if( vals.size() > 1 ){
00311         // this property has multiple values, list within brackets
00312         propstring += "=[";
00313         for( std::vector<std::string>::iterator i = vals.begin();
00314              i != vals.end(); ++i )
00315         {
00316             propstring += *i;
00317             propstring += ",";
00318         }
00319         // replace the last trailing comma with a close braket
00320         propstring[ propstring.length()-1 ] = ']';
00321       }
00322       propstring += ", ";
00323     }
00324   }
00325   if( propstring.length() ){
00326     propstring.resize( propstring.length() - 2 ); // drop trailing comma
00327   }
00328   return propstring;
00329 }
00330 
00331 ErrorCode obbstat_write( DagMC& dag, std::vector<int> &volumes, 
00332                          std::vector<std::string> &properties, std::ostream& out ){
00333 
00334   ErrorCode ret = MB_SUCCESS;
00335   OrientedBoxTreeTool& obbtool = *dag.obb_tree();
00336 
00337   // can assume that volume numbers are valid.
00338   for( std::vector<int>::iterator i = volumes.begin(); i!=volumes.end(); ++i){
00339     EntityHandle vol_root;
00340     EntityHandle vol = dag.entity_by_id(3,*i);
00341     CHECKERR(dag,ret);
00342 
00343     if( vol == 0 ){
00344       std::cerr << "ERROR: volume " << *i << " has no entity." << std::endl;
00345       continue;
00346     }
00347 
00348     ret = dag.get_root( vol, vol_root );
00349     CHECKERR(dag,ret);
00350 
00351     out << "\nVolume " << *i << " " << std::flush;
00352 
00353     if( dag.is_implicit_complement(vol) ) out << "(implicit complement) ";
00354     out << std::endl;
00355 
00356     std::string propstring = make_property_string( dag, vol, properties );
00357     if( propstring.length() ) out << "Properties: " << propstring << std::endl;
00358 
00359     // get all surfaces in volume
00360     Range surfs;
00361     ret = dag.moab_instance()->get_child_meshsets( vol, surfs );
00362     CHECKERR(dag,ret);
00363 
00364     out << "   with " << surfs.size() << " surfaces" << std::endl;
00365     
00366     TriStats ts( dag.moab_instance(), &obbtool, vol_root );
00367     ret = obbtool.preorder_traverse( vol_root, ts );
00368     CHECKERR(dag,ret);
00369     ts.write_results( out );
00370 
00371     if( verbose ){
00372       out << "Surface list: " << std::flush;
00373       for( Range::iterator j = surfs.begin(); j!=surfs.end(); ++j){
00374         out << dag.get_entity_id(*j);
00375         std::string props = make_property_string( dag, *j, properties );
00376         if( props.length() ) out << "(" << props << ")";
00377         if( j+1 != surfs.end() ) out << ",";
00378       }
00379       out << std::endl;
00380       ret = obbtool.stats( vol_root, out ); 
00381       CHECKERR(dag,ret);
00382     }
00383 
00384     out << "\n    ------------ " << std::endl;
00385 
00386   }
00387 
00388   return ret;
00389 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines