moab
|
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 }