![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "moab/GeomQueryTool.hpp"
00002 #include "moab/GeomTopoTool.hpp"
00003 #include "InitCGMA.hpp"
00004 #include "CGMApp.hpp"
00005 #include "moab/CN.hpp"
00006 #include "moab/Core.hpp"
00007 #include "moab/CartVect.hpp"
00008 #include "moab/FileOptions.hpp"
00009 #include "moab/Skinner.hpp"
00010 #include "quads_to_tris.hpp"
00011 #include
00012 #include
00013 #include
00014 #include
00015
00016 #define GF_CUBIT_FILE_TYPE "CUBIT"
00017 #define GF_STEP_FILE_TYPE "STEP"
00018 #define GF_IGES_FILE_TYPE "IGES"
00019 #define GF_ACIS_TXT_FILE_TYPE "ACIS_SAT"
00020 #define GF_ACIS_BIN_FILE_TYPE "ACIS_SAB"
00021 #define GF_OCC_BREP_FILE_TYPE "OCC"
00022
00023 using namespace moab;
00024
00025 void tokenize( const std::string& str, std::vector< std::string >& tokens, const char* delimiters )
00026 {
00027 std::string::size_type last = str.find_first_not_of( delimiters, 0 );
00028 std::string::size_type pos = str.find_first_of( delimiters, last );
00029 if( std::string::npos == pos )
00030 tokens.push_back( str );
00031 else
00032 while( std::string::npos != pos && std::string::npos != last )
00033 {
00034 tokens.push_back( str.substr( last, pos - last ) );
00035 last = str.find_first_not_of( delimiters, pos );
00036 pos = str.find_first_of( delimiters, last );
00037 if( std::string::npos == pos ) pos = str.size();
00038 }
00039 }
00040
00041 ErrorCode get_group_names( Interface* MBI,
00042 const EntityHandle group_set,
00043 const Tag nameTag,
00044 std::vector< std::string >& grp_names )
00045 {
00046 // get names
00047 char name0[NAME_TAG_SIZE];
00048 std::fill( name0, name0 + NAME_TAG_SIZE, '\0' );
00049 ErrorCode result = MBI->tag_get_data( nameTag, &group_set, 1, &name0 );
00050 if( MB_SUCCESS != result && MB_TAG_NOT_FOUND != result ) return MB_FAILURE;
00051
00052 if( MB_TAG_NOT_FOUND != result ) grp_names.push_back( std::string( name0 ) );
00053
00054 return MB_SUCCESS;
00055 }
00056
00057 // For each material, sum the volume. If the coordinates were updated for
00058 // deformation, summarize the volume change.
00059 ErrorCode summarize_cell_volume_change( Interface* MBI,
00060 const EntityHandle cgm_file_set,
00061 const Tag categoryTag,
00062 const Tag dimTag,
00063 const Tag sizeTag,
00064 const Tag nameTag,
00065 const Tag idTag,
00066 const bool conserve_mass,
00067 const bool debug )
00068 {
00069 // get groups
00070 ErrorCode rval;
00071 const char group_category[CATEGORY_TAG_SIZE] = { "Group\0" };
00072 const void* const group_val[] = { &group_category };
00073 Range groups;
00074 rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &categoryTag, group_val, 1, groups );
00075 if( MB_SUCCESS != rval ) return rval;
00076
00077 // Get the maximum group id. This is so that new groups do not have
00078 // duplicate ids.
00079 int max_grp_id = -1;
00080 for( Range::const_iterator i = groups.begin(); i != groups.end(); ++i )
00081 {
00082 int grp_id;
00083 rval = MBI->tag_get_data( idTag, &( *i ), 1, &grp_id );
00084 if( MB_SUCCESS != rval ) return rval;
00085 if( max_grp_id < grp_id ) max_grp_id = grp_id;
00086 }
00087 if( conserve_mass )
00088 {
00089 std::cout << " Altering group densities to conserve mass for each volume." << std::endl;
00090 std::cout << " maximum group id=" << max_grp_id << std::endl;
00091 }
00092
00093 for( Range::const_iterator i = groups.begin(); i != groups.end(); ++i )
00094 {
00095 // get group names
00096 std::vector< std::string > grp_names;
00097 rval = get_group_names( MBI, *i, nameTag, grp_names );
00098 if( MB_SUCCESS != rval ) return MB_FAILURE;
00099
00100 // determine if it is a material group
00101 bool material_grp = false;
00102 int mat_id = -1;
00103 double rho = 0;
00104 for( std::vector< std::string >::const_iterator j = grp_names.begin(); j != grp_names.end(); ++j )
00105 {
00106 if( std::string::npos != ( *j ).find( "mat" ) && std::string::npos != ( *j ).find( "rho" ) )
00107 {
00108 material_grp = true;
00109 std::cout << " material group: " << *j << std::endl;
00110
00111 // get the density and material id
00112 std::vector< std::string > tokens;
00113 tokenize( *j, tokens, "_" );
00114 mat_id = atoi( tokens[1].c_str() );
00115 rho = atof( tokens[3].c_str() );
00116 }
00117 }
00118 if( !material_grp ) continue;
00119
00120 // get the volume sets of the material group
00121 const int three = 3;
00122 const void* const three_val[] = { &three };
00123 Range vols;
00124 rval = MBI->get_entities_by_type_and_tag( *i, MBENTITYSET, &dimTag, three_val, 1, vols );
00125 if( MB_SUCCESS != rval ) return rval;
00126
00127 // for each volume, sum predeformed and deformed volume
00128 double orig_grp_volume = 0, defo_grp_volume = 0;
00129
00130 moab::GeomTopoTool gtt = moab::GeomTopoTool( MBI, false );
00131 moab::GeomQueryTool gqt = moab::GeomQueryTool( >t );
00132 for( Range::const_iterator j = vols.begin(); j != vols.end(); ++j )
00133 {
00134 double defo_size = 0, orig_size = 0;
00135 rval = gqt.measure_volume( *j, defo_size );
00136 if( MB_SUCCESS != rval ) return rval;
00137 defo_grp_volume += defo_size;
00138 rval = MBI->tag_get_data( sizeTag, &( *j ), 1, &orig_size );
00139 if( MB_SUCCESS != rval ) return rval;
00140 orig_grp_volume += orig_size;
00141
00142 // calculate a new density to conserve mass through the deformation
00143 if( !conserve_mass ) continue;
00144 double new_rho = rho * orig_size / defo_size;
00145
00146 // create a group for the volume with modified density
00147 EntityHandle new_grp;
00148 rval = MBI->create_meshset( MESHSET_SET, new_grp );
00149 if( MB_SUCCESS != rval ) return rval;
00150 std::stringstream new_name_ss;
00151 new_name_ss << "mat_" << mat_id << "_rho_" << new_rho << "\0";
00152 std::string new_name;
00153 new_name_ss >> new_name;
00154 rval = MBI->tag_set_data( nameTag, &new_grp, 1, new_name.c_str() );
00155 if( MB_SUCCESS != rval ) return rval;
00156 max_grp_id++;
00157 rval = MBI->tag_set_data( idTag, &new_grp, 1, &max_grp_id );
00158 if( MB_SUCCESS != rval ) return rval;
00159 const char group_category2[CATEGORY_TAG_SIZE] = "Group\0";
00160 rval = MBI->tag_set_data( categoryTag, &new_grp, 1, group_category2 );
00161 if( MB_SUCCESS != rval ) return rval;
00162
00163 // add the volume to the new group
00164 rval = MBI->add_entities( new_grp, &( *j ), 1 );
00165 if( MB_SUCCESS != rval ) return rval;
00166
00167 // add the new grp to the cgm_file_set
00168 rval = MBI->add_entities( cgm_file_set, &new_grp, 1 );
00169 if( MB_SUCCESS != rval ) return rval;
00170
00171 // remove the volume from the old group
00172 rval = MBI->remove_entities( *i, &( *j ), 1 );
00173 if( MB_SUCCESS != rval ) return rval;
00174 if( debug ) std::cout << " new group: " << new_name << " id=" << max_grp_id << std::endl;
00175 }
00176
00177 std::cout << " orig_volume=" << orig_grp_volume << " defo_volume=" << defo_grp_volume
00178 << " defo/orig=" << defo_grp_volume / orig_grp_volume << std::endl;
00179 }
00180
00181 return MB_SUCCESS;
00182 }
00183
00184 // We cannot build an OBB tree if all of a volume's surfaces have no facets.
00185 // To prevent this, remove the cgm surface set if the cub surface set exists,
00186 // but had its faced removed (due to dead elements). Remember that the cgm_file_set
00187 // is not TRACKING.
00188 ErrorCode remove_empty_cgm_surfs_and_vols( Interface* MBI,
00189 const EntityHandle cgm_file_set,
00190 const Tag idTag,
00191 const Tag dimTag,
00192 const bool /*debug */ )
00193 {
00194
00195 ErrorCode result;
00196 const int two = 2;
00197 const void* const two_val[] = { &two };
00198 Range cgm_surfs;
00199 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, two_val, 1, cgm_surfs );
00200 if( MB_SUCCESS != result ) return result;
00201
00202 for( Range::iterator i = cgm_surfs.begin(); i != cgm_surfs.end(); ++i )
00203 {
00204 int n_tris;
00205 result = MBI->get_number_entities_by_type( *i, MBTRI, n_tris );
00206 if( MB_SUCCESS != result ) return result;
00207
00208 if( 0 == n_tris )
00209 {
00210 int surf_id;
00211 result = MBI->tag_get_data( idTag, &( *i ), 1, &surf_id );
00212 assert( MB_SUCCESS == result );
00213
00214 Range parent_vols;
00215 result = MBI->get_parent_meshsets( *i, parent_vols );
00216 assert( MB_SUCCESS == result );
00217 for( Range::iterator j = parent_vols.begin(); j != parent_vols.end(); ++j )
00218 {
00219 result = MBI->remove_parent_child( *j, *i );
00220 assert( MB_SUCCESS == result );
00221 }
00222 Range child_curves;
00223 result = MBI->get_child_meshsets( *i, child_curves );
00224 assert( MB_SUCCESS == result );
00225 for( Range::iterator j = child_curves.begin(); j != child_curves.end(); ++j )
00226 {
00227 result = MBI->remove_parent_child( *i, *j );
00228 assert( MB_SUCCESS == result );
00229 }
00230 result = MBI->remove_entities( cgm_file_set, &( *i ), 1 );
00231 assert( MB_SUCCESS == result );
00232
00233 // Is the set contained anywhere else? If the surface is in a CUBIT group,
00234 // such as "unmerged_surfs" it will cause write_mesh to fail. This should
00235 // be a MOAB bug.
00236 Range all_sets;
00237 result = MBI->get_entities_by_type( 0, MBENTITYSET, all_sets );
00238 assert( MB_SUCCESS == result );
00239 for( Range::iterator j = all_sets.begin(); j != all_sets.end(); ++j )
00240 {
00241 if( MBI->contains_entities( *j, &( *i ), 1 ) )
00242 {
00243 result = MBI->remove_entities( *j, &( *i ), 1 );
00244 assert( MB_SUCCESS == result );
00245 }
00246 }
00247
00248 result = MBI->delete_entities( &( *i ), 1 );
00249 assert( MB_SUCCESS == result );
00250 std::cout << " Surface " << surf_id << ": removed because all of its mesh faces have been removed"
00251 << std::endl;
00252 }
00253 }
00254
00255 // get all volumes
00256 const int three = 3;
00257 const void* const three_val[] = { &three };
00258 Range cgm_vols;
00259 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, three_val, 1, cgm_vols );
00260 if( MB_SUCCESS != result ) return result;
00261
00262 for( Range::iterator i = cgm_vols.begin(); i != cgm_vols.end(); ++i )
00263 {
00264 // get the volume's number of surfaces
00265 int n_surfs;
00266 result = MBI->num_child_meshsets( *i, &n_surfs );
00267 assert( MB_SUCCESS == result );
00268
00269 // if no surfaces remain, remove the volume
00270 if( 0 == n_surfs )
00271 {
00272 int vol_id;
00273 result = MBI->tag_get_data( idTag, &( *i ), 1, &vol_id );
00274 assert( MB_SUCCESS == result );
00275 // Is the set contained anywhere else? If the surface is in a CUBIT group,
00276 // such as "unmerged_surfs" it will cause write_mesh to fail. This should
00277 // be a MOAB bug.
00278 Range all_sets;
00279 result = MBI->get_entities_by_type( 0, MBENTITYSET, all_sets );
00280 assert( MB_SUCCESS == result );
00281 for( Range::iterator j = all_sets.begin(); j != all_sets.end(); ++j )
00282 {
00283 if( MBI->contains_entities( *j, &( *i ), 1 ) )
00284 {
00285 result = MBI->remove_entities( *j, &( *i ), 1 );
00286 assert( MB_SUCCESS == result );
00287 }
00288 }
00289 result = MBI->delete_entities( &( *i ), 1 );
00290 assert( MB_SUCCESS == result );
00291 std::cout << " Volume " << vol_id << ": removed because all of its surfaces have been removed"
00292 << std::endl;
00293 }
00294 }
00295 return MB_SUCCESS;
00296 }
00297
00298 // Given parent volume senses, an id, and a set handle, this function creates a
00299 // new surface set with dimension, geometry category, id, and sense tags.
00300 ErrorCode build_new_surface( Interface* MBI,
00301 EntityHandle& new_surf,
00302 const EntityHandle forward_parent_vol,
00303 const EntityHandle reverse_parent_vol,
00304 const int new_surf_id,
00305 const Tag dimTag,
00306 const Tag idTag,
00307 const Tag categoryTag,
00308 const Tag senseTag )
00309 {
00310
00311 ErrorCode result;
00312 result = MBI->create_meshset( 0, new_surf );
00313 if( MB_SUCCESS != result ) return result;
00314 if( 0 != forward_parent_vol )
00315 {
00316 result = MBI->add_parent_child( forward_parent_vol, new_surf );
00317 if( MB_SUCCESS != result ) return result;
00318 }
00319 if( 0 != reverse_parent_vol )
00320 {
00321 result = MBI->add_parent_child( reverse_parent_vol, new_surf );
00322 if( MB_SUCCESS != result ) return result;
00323 }
00324 const int two = 2;
00325 result = MBI->tag_set_data( dimTag, &new_surf, 1, &two );
00326 if( MB_SUCCESS != result ) return result;
00327 result = MBI->tag_set_data( idTag, &new_surf, 1, &new_surf_id );
00328 if( MB_SUCCESS != result ) return result;
00329 const char geom_category[CATEGORY_TAG_SIZE] = { "Surface\0" };
00330 result = MBI->tag_set_data( categoryTag, &new_surf, 1, &geom_category );
00331 if( MB_SUCCESS != result ) return result;
00332 EntityHandle vols[2] = { forward_parent_vol, reverse_parent_vol };
00333 result = MBI->tag_set_data( senseTag, &new_surf, 1, vols );
00334 if( MB_SUCCESS != result ) return result;
00335
00336 return MB_SUCCESS;
00337 }
00338
00339 // Given a face, orient it outward wrt its adjacent mesh element.
00340 // Each face must be adjacent to exactly one mesh element.
00341 ErrorCode orient_faces_outward( Interface* MBI, const Range& faces, const bool /*debug*/ )
00342 {
00343
00344 ErrorCode result;
00345 for( Range::const_iterator i = faces.begin(); i != faces.end(); ++i )
00346 {
00347 Range adj_elem;
00348 result = MBI->get_adjacencies( &( *i ), 1, 3, false, adj_elem );
00349 if( MB_SUCCESS != result ) return result;
00350 if( 1 != adj_elem.size() ) return MB_INVALID_SIZE;
00351
00352 // get connectivity for element and face
00353 const EntityHandle* elem_conn;
00354 int elem_n_nodes;
00355 result = MBI->get_connectivity( adj_elem.front(), elem_conn, elem_n_nodes );
00356 if( MB_SUCCESS != result ) return result;
00357 const EntityHandle* face_conn;
00358 int face_n_nodes;
00359 result = MBI->get_connectivity( *i, face_conn, face_n_nodes );
00360 if( MB_SUCCESS != result ) return result;
00361
00362 // Get the sense of the face wrt the element
00363 EntityType elem_type = MBI->type_from_handle( adj_elem.front() );
00364 EntityType face_type = MBI->type_from_handle( *i );
00365 int face_num, offset;
00366 int sense = 0;
00367 const int face_dim = CN::Dimension( face_type );
00368 int rval = CN::SideNumber( elem_type, elem_conn, face_conn, face_n_nodes, face_dim, face_num, sense, offset );
00369 if( 0 != rval ) return MB_FAILURE;
00370
00371 // If the face is not oriented outward wrt the element, reverse it
00372 if( -1 == sense )
00373 {
00374 EntityHandle new_face_conn[4] = { face_conn[3], face_conn[2], face_conn[1], face_conn[0] };
00375 result = MBI->set_connectivity( *i, new_face_conn, 4 );
00376 if( MB_SUCCESS != result ) return result;
00377 }
00378 }
00379 return MB_SUCCESS;
00380 }
00381
00382 /* Isolate dead code in a preproc-killed block - sjackson 11/22/10 */
00383 #if 0
00384
00385 /* qsort int comparison function */
00386 int handle_compare(const void *a, const void *b)
00387 {
00388 const EntityHandle *ia = (const EntityHandle *)a; // casting pointer types
00389 const EntityHandle *ib = (const EntityHandle *)b;
00390 return *ia - *ib;
00391 /* integer comparison: returns negative if b > a
00392 and positive if a > b */
00393 }
00394
00395 // qsort face comparison function. assume each face has 4 nodes
00396 int compare_face(const void *a, const void *b)
00397 {
00398 EntityHandle *ia = (EntityHandle *)a;
00399 EntityHandle *ib = (EntityHandle *)b;
00400 if(*ia == *ib)
00401 {
00402 if(*(ia+1) == *(ib+1))
00403 {
00404 if(*(ia+2) == *(ib+2))
00405 {
00406 return (int)(*(ia+3) - *(ib+3));
00407 }
00408 else
00409 {
00410 return (int)(*(ia+2) - *(ib+2));
00411 }
00412 }
00413 else
00414 {
00415 return (int)(*(ia+1) - *(ib+1));
00416 }
00417 }
00418 else
00419 {
00420 return (int)(*ia - *ib);
00421 }
00422 }
00423
00424 // Use this to get quad faces from hex elems.
00425 ErrorCode skin_hex_elems(Interface *MBI, Range elems, const int dim,
00426 Range &faces )
00427 {
00428 // get faces of each hex
00429 const int nodes_per_face = 4;
00430 const unsigned int faces_per_elem = 6;
00431 unsigned int n_faces = faces_per_elem*elems.size();
00432 EntityHandle f[n_faces][nodes_per_face];
00433 ErrorCode result;
00434 int counter = 0;
00435 for(Range::iterator i=elems.begin(); i!=elems.end(); ++i)
00436 {
00437 Range elem_faces;
00438 result = MBI->get_adjacencies( &(*i), 1, 2, true, elem_faces );
00439 if(MB_SUCCESS != result) return result;
00440 if(faces_per_elem != elem_faces.size()) return MB_INVALID_SIZE;
00441 for(Range::iterator j=elem_faces.begin(); j!=elem_faces.end(); ++j)
00442 {
00443 const EntityHandle *conn;
00444 int n_nodes;
00445 ErrorCode result = MBI->get_connectivity( *j, conn, n_nodes );
00446 if(MB_SUCCESS != result) return result;
00447 if(nodes_per_face != n_nodes) return MB_INVALID_SIZE;
00448 // Sort the node handles of the face
00449 for(int k=0; kget_adjacencies( &(f[i][0]), nodes_per_face, 2, false, face_handle );
00467 if(MB_SUCCESS != result) return result;
00468 if(1 != face_handle.size()) return MB_INVALID_SIZE;
00469 faces.insert( face_handle.front() );
00470 // Due to sort, if a duplicate exists it must be next
00471 }
00472 else if( f[i][0]==f[i+1][0] && f[i][1]==f[i+1][1] &&
00473 f[i][2]==f[i+1][2] && f[i][3]==f[i+1][3] )
00474 {
00475 ++i;
00476 while( f[i][0]==f[i+1][0] && f[i][1]==f[i+1][1] &&
00477 f[i][2]==f[i+1][2] && f[i][3]==f[i+1][3] )
00478 {
00479 std::cout << " skin WARNING: non-manifold face" << std::endl;
00480 ++i;
00481 }
00482 // otherwise it is on the skin
00483 }
00484 else
00485 {
00486 Range face_handle;
00487 result = MBI->get_adjacencies( &(f[i][0]), nodes_per_face, 2, false, face_handle );
00488 if(MB_SUCCESS != result) return result;
00489 if(1 != face_handle.size()) return MB_INVALID_SIZE;
00490 faces.insert( face_handle.front() );
00491 }
00492 }
00493
00494 return MB_SUCCESS;
00495 }
00496
00497 #endif // dead code isolation
00498 // Given a 1D array of data, axis labels, title, and number of bins, create a
00499 // histogram.
00500 void plot_histogram( const std::string& title,
00501 const std::string& x_axis_label,
00502 const std::string& y_axis_label,
00503 const int n_bins,
00504 const double data[],
00505 const int n_data )
00506 {
00507 // find max and min
00508 double min = std::numeric_limits< double >::max();
00509 double max = -std::numeric_limits< double >::max();
00510 for( int i = 0; i < n_data; ++i )
00511 {
00512 if( min > data[i] ) min = data[i];
00513 if( max < data[i] ) max = data[i];
00514 }
00515
00516 // make bins for histogram
00517 double bin_width = ( max - min ) / n_bins;
00518 std::vector< int > bins( n_bins );
00519 for( int i = 0; i < n_bins; ++i )
00520 bins[i] = 0;
00521
00522 // fill the bins
00523 for( int i = 0; i < n_data; ++i )
00524 {
00525 double diff = data[i] - min;
00526 int bin = diff / bin_width;
00527 if( 9 < bin ) bin = 9; // cheap fix for numerical precision error
00528 if( 0 > bin ) bin = 0; // cheap fix for numerical precision error
00529 ++bins[bin];
00530 }
00531
00532 // create bars
00533 int max_bin = 0;
00534 for( int i = 0; i < n_bins; ++i )
00535 if( max_bin < bins[i] ) max_bin = bins[i];
00536 int bar_height;
00537 int max_bar_chars = 72;
00538 std::vector< std::string > bars( n_bins );
00539 for( int i = 0; i < n_bins; ++i )
00540 {
00541 bar_height = ( max_bar_chars * bins[i] ) / max_bin;
00542 for( int j = 0; j < bar_height; ++j )
00543 bars[i] += "*";
00544 }
00545
00546 // print histogram header
00547 std::cout << std::endl;
00548 std::cout << " " << title << std::endl;
00549
00550 // print results
00551 std::cout.width( 15 );
00552 std::cout << min << std::endl;
00553 for( int i = 0; i < n_bins; ++i )
00554 {
00555 std::cout.width( 15 );
00556 std::cout << min + ( ( i + 1 ) * bin_width );
00557 std::cout.width( max_bar_chars );
00558 std::cout << bars[i] << bins[i] << std::endl;
00559 }
00560
00561 // print histogram footer
00562 std::cout.width( 15 );
00563 std::cout << y_axis_label;
00564 std::cout.width( max_bar_chars );
00565 std::cout << " " << x_axis_label << std::endl;
00566 std::cout << std::endl;
00567 }
00568
00569 // This is a helper function that creates data and labels for histograms.
00570 void generate_plots( const double orig[], const double defo[], const int n_elems, const std::string& time_step )
00571 {
00572
00573 // find volume ratio then max and min
00574 double* ratio = new double[n_elems];
00575 for( int i = 0; i < n_elems; ++i )
00576 ratio[i] = ( defo[i] - orig[i] ) / orig[i];
00577
00578 plot_histogram( "Predeformed Element Volume", "Num_Elems", "Volume [cc]", 10, orig, n_elems );
00579 std::string title = "Element Volume Change Ratio at Time Step " + time_step;
00580 plot_histogram( title, "Num_Elems", "Volume Ratio", 10, ratio, n_elems );
00581 delete[] ratio;
00582 }
00583
00584 // Given four nodes, calculate the tet volume.
00585 inline static double tet_volume( const CartVect& v0, const CartVect& v1, const CartVect& v2, const CartVect& v3 )
00586 {
00587 return 1. / 6. * ( ( ( v1 - v0 ) * ( v2 - v0 ) ) % ( v3 - v0 ) );
00588 }
00589
00590 // Measure and tet volume are taken from measure.cpp
00591 double measure( Interface* MBI, const EntityHandle element )
00592 {
00593 EntityType type = MBI->type_from_handle( element );
00594
00595 const EntityHandle* conn;
00596 int num_vertices;
00597 ErrorCode result = MBI->get_connectivity( element, conn, num_vertices );
00598 if( MB_SUCCESS != result ) return result;
00599
00600 std::vector< CartVect > coords( num_vertices );
00601 result = MBI->get_coords( conn, num_vertices, coords[0].array() );
00602 if( MB_SUCCESS != result ) return result;
00603
00604 switch( type )
00605 {
00606 case MBEDGE:
00607 return ( coords[0] - coords[1] ).length();
00608 case MBTRI:
00609 return 0.5 * ( ( coords[1] - coords[0] ) * ( coords[2] - coords[0] ) ).length();
00610 case MBQUAD:
00611 num_vertices = 4;
00612 case MBPOLYGON: {
00613 CartVect mid( 0, 0, 0 );
00614 for( int i = 0; i < num_vertices; ++i )
00615 mid += coords[i];
00616 mid /= num_vertices;
00617
00618 double sum = 0.0;
00619 for( int i = 0; i < num_vertices; ++i )
00620 {
00621 int j = ( i + 1 ) % num_vertices;
00622 sum += ( ( mid - coords[i] ) * ( mid - coords[j] ) ).length();
00623 }
00624 return 0.5 * sum;
00625 }
00626 case MBTET:
00627 return tet_volume( coords[0], coords[1], coords[2], coords[3] );
00628 case MBPYRAMID:
00629 return tet_volume( coords[0], coords[1], coords[2], coords[4] ) +
00630 tet_volume( coords[0], coords[2], coords[3], coords[4] );
00631 case MBPRISM:
00632 return tet_volume( coords[0], coords[1], coords[2], coords[5] ) +
00633 tet_volume( coords[3], coords[5], coords[4], coords[0] ) +
00634 tet_volume( coords[1], coords[4], coords[5], coords[0] );
00635 case MBHEX:
00636 return tet_volume( coords[0], coords[1], coords[3], coords[4] ) +
00637 tet_volume( coords[7], coords[3], coords[6], coords[4] ) +
00638 tet_volume( coords[4], coords[5], coords[1], coords[6] ) +
00639 tet_volume( coords[1], coords[6], coords[3], coords[4] ) +
00640 tet_volume( coords[2], coords[6], coords[3], coords[1] );
00641 default:
00642 return 0.0;
00643 }
00644 }
00645
00646 /* Calculate the signed volumes beneath the surface (x 6.0). Use the triangle's
00647 canonical sense. Do not take sense tags into account. Code taken from
00648 DagMC::measure_volume.
00649
00650 Special Case: If the surface is planar, and the plane includes the origin,
00651 the signed volume will be ~0. If the signed volume is ~0 then offset everything
00652 by a random amount and try again. */
00653 ErrorCode get_signed_volume( Interface* MBI,
00654 const EntityHandle surf_set,
00655 const CartVect& offset,
00656 double& signed_volume )
00657 {
00658 ErrorCode rval;
00659 Range tris;
00660 rval = MBI->get_entities_by_type( surf_set, MBTRI, tris );
00661 if( MB_SUCCESS != rval ) return rval;
00662 signed_volume = 0.0;
00663 const EntityHandle* conn;
00664 int len;
00665 CartVect coords[3];
00666 for( Range::iterator j = tris.begin(); j != tris.end(); ++j )
00667 {
00668 rval = MBI->get_connectivity( *j, conn, len, true );
00669 if( MB_SUCCESS != rval ) return rval;
00670 if( 3 != len ) return MB_INVALID_SIZE;
00671 rval = MBI->get_coords( conn, 3, coords[0].array() );
00672 if( MB_SUCCESS != rval ) return rval;
00673
00674 // Apply offset to avoid calculating 0 for cases when the origin is in the
00675 // plane of the surface.
00676 for( unsigned int k = 0; k < 3; ++k )
00677 {
00678 coords[k][0] += offset[0];
00679 coords[k][1] += offset[1];
00680 coords[k][2] += offset[2];
00681 }
00682
00683 coords[1] -= coords[0];
00684 coords[2] -= coords[0];
00685 signed_volume += ( coords[0] % ( coords[1] * coords[2] ) );
00686 }
00687 return MB_SUCCESS;
00688 }
00689
00690 // The cgm and cub surfaces may not have the same sense. Create triangles that
00691 // represent the quads in the cub surface. Calculate the signed volume of both
00692 // the cgm and cub surface. If they are different, change the cgm sense so that
00693 // it matches the sense of the cub surface.
00694 ErrorCode fix_surface_senses( Interface* MBI,
00695 const EntityHandle cgm_file_set,
00696 const EntityHandle cub_file_set,
00697 const Tag idTag,
00698 const Tag dimTag,
00699 const Tag senseTag,
00700 const bool debug )
00701 {
00702 ErrorCode result;
00703 const int two = 2;
00704 const void* const two_val[] = { &two };
00705 Range cgm_surfs;
00706 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, two_val, 1, cgm_surfs );
00707 if( MB_SUCCESS != result ) return result;
00708 for( Range::iterator i = cgm_surfs.begin(); i != cgm_surfs.end(); ++i )
00709 {
00710 int surf_id;
00711 result = MBI->tag_get_data( idTag, &( *i ), 1, &surf_id );
00712 if( MB_SUCCESS != result ) return result;
00713
00714 // Find the meshed surface set with the same id
00715 Range cub_surf;
00716 const Tag tags[] = { idTag, dimTag };
00717 const void* const tag_vals[] = { &surf_id, &two };
00718 result = MBI->get_entities_by_type_and_tag( cub_file_set, MBENTITYSET, tags, tag_vals, 2, cub_surf );
00719 if( MB_SUCCESS != result ) return result;
00720 if( 1 != cub_surf.size() )
00721 {
00722 std::cout << " Surface " << surf_id << ": no meshed representation found, using CAD representation instead"
00723 << std::endl;
00724 continue;
00725 }
00726
00727 // Get tris that represent the quads of the cub surf
00728 Range quads;
00729 result = MBI->get_entities_by_type( cub_surf.front(), MBQUAD, quads );
00730 if( MB_SUCCESS != result ) return result;
00731 Range cub_tris;
00732 result = make_tris_from_quads( MBI, quads, cub_tris );
00733 if( MB_SUCCESS != result ) return result;
00734
00735 // Add the tris to the same surface meshset as the quads are inside.
00736 result = MBI->add_entities( cub_surf.front(), cub_tris );
00737 if( MB_SUCCESS != result ) return result;
00738
00739 // get the signed volume for each surface representation. Keep trying until
00740 // The signed volumes are much greater than numerical precision. Planar
00741 // surfaces will have a signed volume of zero if the plane goes through the
00742 // origin, unless we apply an offset.
00743 const int n_attempts = 100;
00744 const int max_random = 10;
00745 const double min_signed_vol = 0.1;
00746 double cgm_signed_vol, cub_signed_vol;
00747 for( int j = 0; j < n_attempts; ++j )
00748 {
00749 cgm_signed_vol = 0;
00750 cub_signed_vol = 0;
00751 CartVect offset( std::rand() % max_random, std::rand() % max_random, std::rand() % max_random );
00752 result = get_signed_volume( MBI, *i, offset, cgm_signed_vol );
00753 if( MB_SUCCESS != result ) return result;
00754 result = get_signed_volume( MBI, cub_surf.front(), offset, cub_signed_vol );
00755 if( MB_SUCCESS != result ) return result;
00756 if( debug )
00757 std::cout << " surf_id=" << surf_id << " cgm_signed_vol=" << cgm_signed_vol
00758 << " cub_signed_vol=" << cub_signed_vol << std::endl;
00759 if( fabs( cgm_signed_vol ) > min_signed_vol && fabs( cub_signed_vol ) > min_signed_vol ) break;
00760 if( n_attempts == j + 1 )
00761 {
00762 std::cout << "error: signed volume could not be calculated unambiguously" << std::endl;
00763 return MB_FAILURE;
00764 }
00765 }
00766
00767 // If the sign is different, reverse the cgm senses so that both
00768 // representations have the same signed volume.
00769 if( ( cgm_signed_vol < 0 && cub_signed_vol > 0 ) || ( cgm_signed_vol > 0 && cub_signed_vol < 0 ) )
00770 {
00771 EntityHandle cgm_surf_volumes[2], reversed_cgm_surf_volumes[2];
00772 result = MBI->tag_get_data( senseTag, &( *i ), 1, cgm_surf_volumes );
00773 if( MB_SUCCESS != result ) return result;
00774 if( MB_SUCCESS != result ) return result;
00775
00776 reversed_cgm_surf_volumes[0] = cgm_surf_volumes[1];
00777 reversed_cgm_surf_volumes[1] = cgm_surf_volumes[0];
00778
00779 result = MBI->tag_set_data( senseTag, &( *i ), 1, reversed_cgm_surf_volumes );
00780 if( MB_SUCCESS != result ) return result;
00781 }
00782 }
00783
00784 return MB_SUCCESS;
00785 }
00786
00787 // The quads in the cub_file_set have been updated for dead elements. For each
00788 // cgm_surf, if there exists a cub_surf with the same id, replace the cgm tris
00789 // with cub_tris (created from the quads). Note the a surface that is not
00790 // meshed (in cub file) will not be effected.
00791 ErrorCode replace_faceted_cgm_surfs( Interface* MBI,
00792 const EntityHandle cgm_file_set,
00793 const EntityHandle cub_file_set,
00794 const Tag idTag,
00795 const Tag dimTag,
00796 const bool debug )
00797 {
00798 ErrorCode result;
00799 const int two = 2;
00800 const void* const two_val[] = { &two };
00801 Range cgm_surfs;
00802 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, two_val, 1, cgm_surfs );
00803 if( MB_SUCCESS != result ) return result;
00804
00805 for( Range::iterator i = cgm_surfs.begin(); i != cgm_surfs.end(); ++i )
00806 {
00807 int surf_id;
00808 result = MBI->tag_get_data( idTag, &( *i ), 1, &surf_id );
00809 if( MB_SUCCESS != result ) return result;
00810 if( debug ) std::cout << "surf_id=" << surf_id << std::endl;
00811
00812 // Find the meshed surface set with the same id
00813 Range cub_surf;
00814 const Tag tags[] = { idTag, dimTag };
00815 const void* const tag_vals[] = { &surf_id, &two };
00816 result = MBI->get_entities_by_type_and_tag( cub_file_set, MBENTITYSET, tags, tag_vals, 2, cub_surf );
00817 if( MB_SUCCESS != result ) return result;
00818 if( 1 != cub_surf.size() )
00819 {
00820 std::cout << " Surface " << surf_id << ": no meshed representation found, using CAD representation instead"
00821 << std::endl;
00822 continue;
00823 }
00824
00825 // Get tris that represent the quads of the cub surf
00826 Range quads;
00827 result = MBI->get_entities_by_type( cub_surf.front(), MBQUAD, quads );
00828 if( MB_SUCCESS != result ) return result;
00829
00830 Range cub_tris;
00831 result = make_tris_from_quads( MBI, quads, cub_tris );
00832 if( MB_SUCCESS != result ) return result;
00833
00834 // Remove the tris from the cgm surf. Don't forget to remove them from the
00835 // cgm_file_set because it is not TRACKING.
00836 Range cgm_tris;
00837 result = MBI->get_entities_by_type( *i, MBTRI, cgm_tris );
00838 if( MB_SUCCESS != result ) return result;
00839 result = MBI->remove_entities( *i, cgm_tris );
00840 if( MB_SUCCESS != result ) return result;
00841 result = MBI->remove_entities( cgm_file_set, cgm_tris );
00842 if( MB_SUCCESS != result ) return result;
00843 result = MBI->delete_entities( cgm_tris );
00844 if( MB_SUCCESS != result ) return result;
00845
00846 // Add the cub_tris to the cgm_surf
00847 result = MBI->add_entities( *i, cub_tris );
00848 if( MB_SUCCESS != result ) return result;
00849 }
00850
00851 return MB_SUCCESS;
00852 }
00853
00854 // Dead elements need removed from the simulation. This is done by removing them
00855 // from their volume set and adding them to the implicit complement. New surfaces
00856 // must be created for this.
00857 // IF MODIFYING THIS CODE, BE AWARE THAT DEAD ELEMENTS CAN BE ADJACENT TO MORE
00858 // THAN ONE SURFACE, MAKING THE ASSOCIATION BETWEEN NEWLY EXPOSED AND EXISTING
00859 // SURFACES AMBIGUOUS.
00860 ErrorCode add_dead_elems_to_impl_compl( Interface* MBI,
00861 const EntityHandle cgm_file_set,
00862 const EntityHandle cub_file_set,
00863 const Tag idTag,
00864 const Tag dimTag,
00865 const Tag categoryTag,
00866 const Tag senseTag,
00867 const bool debug )
00868 {
00869
00870 // Get the cgm surfaces
00871 ErrorCode result;
00872 const int two = 2;
00873 const void* const two_val[] = { &two };
00874 Range cgm_surfs;
00875 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, two_val, 1, cgm_surfs );
00876 if( MB_SUCCESS != result ) return result;
00877
00878 // Get the maximum surface id. This is so that new surfaces do not have
00879 // duplicate ids.
00880 int max_surf_id = -1;
00881 for( Range::const_iterator i = cgm_surfs.begin(); i != cgm_surfs.end(); ++i )
00882 {
00883 int surf_id;
00884 result = MBI->tag_get_data( idTag, &( *i ), 1, &surf_id );
00885 if( MB_SUCCESS != result ) return result;
00886 if( max_surf_id < surf_id ) max_surf_id = surf_id;
00887 }
00888 std::cout << " Maximum surface id=" << max_surf_id << std::endl;
00889
00890 // For each cgm volume, does a cub volume with the same id exist?
00891 const int three = 3;
00892 const void* const three_val[] = { &three };
00893 Range cgm_vols;
00894 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, three_val, 1, cgm_vols );
00895 if( MB_SUCCESS != result ) return result;
00896
00897 // get the corresponding cub volume
00898 for( Range::iterator i = cgm_vols.begin(); i != cgm_vols.end(); ++i )
00899 {
00900 int vol_id;
00901 result = MBI->tag_get_data( idTag, &( *i ), 1, &vol_id );
00902 assert( MB_SUCCESS == result );
00903 if( MB_SUCCESS != result ) return result;
00904 std::cout << " Volume " << vol_id;
00905
00906 // Find the meshed vol set with the same id
00907 Range cub_vol;
00908 const Tag tags[] = { idTag, dimTag };
00909 const void* const tag_vals[] = { &vol_id, &three };
00910 result = MBI->get_entities_by_type_and_tag( cub_file_set, MBENTITYSET, tags, tag_vals, 2, cub_vol );
00911 assert( MB_SUCCESS == result );
00912 if( MB_SUCCESS != result ) return result;
00913 if( 1 != cub_vol.size() )
00914 {
00915 std::cout << ": no meshed representation found" << std::endl;
00916 continue;
00917 }
00918 else
00919 {
00920 std::cout << std::endl;
00921 }
00922
00923 // get the mesh elements of the volume.
00924 Range elems;
00925 result = MBI->get_entities_by_type( cub_vol.front(), MBHEX, elems );
00926 assert( MB_SUCCESS == result );
00927 if( MB_SUCCESS != result ) return result;
00928 if( debug ) std::cout << " found " << elems.size() << " hex elems" << std::endl;
00929
00930 // skin the volumes
00931 Skinner tool( MBI );
00932 Range skin_faces;
00933 result = tool.find_skin( 0, elems, 2, skin_faces, true );
00934 assert( MB_SUCCESS == result );
00935 if( MB_SUCCESS != result ) return result;
00936
00937 // Reconcile the difference between faces of the cub file surfaces and skin
00938 // faces of the 3D mesh. The difference exists because dead elements have been
00939 // removed. Faces are divided into:
00940 // cub_faces (in) - the faces in the cub file surface
00941 // skin_faces (in) - the faces of the 3D mesh elements
00942 // common_faces (out)- the faces common to both the cub file surface and 3D mesh
00943 // they are still adjacent to this volume
00944 // old_faces (out)- the faces of the cub surface not on the 3D mesh skin
00945 // they are no longer adjacent to this vol
00946 // new_faces (out)- the faces of the 3D mesh skin not on the cub surface
00947 // they are now adjacent to this volume
00948
00949 // get cub child surfaces.
00950 Range cub_surfs;
00951 result = MBI->get_child_meshsets( cub_vol.front(), cub_surfs );
00952 assert( MB_SUCCESS == result );
00953 if( MB_SUCCESS != result ) return result;
00954 for( Range::iterator j = cub_surfs.begin(); j != cub_surfs.end(); ++j )
00955 {
00956 int surf_id;
00957 result = MBI->tag_get_data( idTag, &( *j ), 1, &surf_id );
00958 assert( MB_SUCCESS == result );
00959 if( MB_SUCCESS != result ) return result;
00960 // get the quads on each surface
00961 Range cub_faces;
00962 result = MBI->get_entities_by_type( *j, MBQUAD, cub_faces );
00963 assert( MB_SUCCESS == result );
00964 if( MB_SUCCESS != result ) return result;
00965 // Meshed volumes must have meshed surfaces
00966 if( cub_faces.empty() )
00967 {
00968 std::cout << " Surface " << surf_id << ": contains no meshed faces" << std::endl;
00969 // return MB_ENTITY_NOT_FOUND;
00970 }
00971 // get the faces common to both the skin and this surface
00972 Range common_faces = intersect( cub_faces, skin_faces );
00973 // find the surface faces not on the skin - these are old and need removed
00974 Range old_faces = subtract( cub_faces, common_faces );
00975 result = MBI->remove_entities( *j, old_faces );
00976 assert( MB_SUCCESS == result );
00977 if( MB_SUCCESS != result ) return result;
00978
00979 // remove the common faces from the skin faces
00980 skin_faces = subtract( skin_faces, common_faces );
00981 // If no old faces exist we are done
00982 if( old_faces.empty() ) continue;
00983 std::cout << " Surface " << surf_id << ": " << old_faces.size() << " old faces removed" << std::endl;
00984 // Place the old faces in a new surface, because they may still be adjacent
00985 // to 3D mesh in another volume. Get the parent vols of the surface.
00986 Range cgm_surf;
00987 const Tag tags2[] = { idTag, dimTag };
00988 const void* const tag_vals2[] = { &surf_id, &two };
00989 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, tags2, tag_vals2, 2, cgm_surf );
00990 assert( MB_SUCCESS == result );
00991 if( MB_SUCCESS != result ) return result;
00992 if( 1 != cgm_surf.size() )
00993 {
00994 std::cout << "invalid size" << std::endl;
00995 return MB_INVALID_SIZE;
00996 }
00997 EntityHandle cgm_vols2[2], cub_vols[2];
00998 result = MBI->tag_get_data( senseTag, cgm_surf, &cgm_vols2 );
00999 assert( MB_SUCCESS == result );
01000 if( MB_SUCCESS != result ) return result;
01001 result = MBI->tag_get_data( senseTag, &( *j ), 1, &cub_vols );
01002 assert( MB_SUCCESS == result );
01003 if( MB_SUCCESS != result ) return result;
01004 // for the new surf, replace the current volume with the impl compl vol.
01005 // This is because the faces that no longer exist will become adjacent to
01006 // the impl compl
01007 if( *i == cgm_vols2[0] )
01008 {
01009 cgm_vols2[0] = 0;
01010 cub_vols[0] = 0;
01011 }
01012 if( *i == cgm_vols2[1] )
01013 {
01014 cgm_vols2[1] = 0;
01015 cub_vols[1] = 0;
01016 }
01017 // If both sides of the surface are the impl comp, do not create the surface.
01018 if( 0 == cgm_vols2[0] && 0 == cgm_vols2[1] )
01019 {
01020 std::cout << " New surface was not created for old faces because both parents "
01021 "are impl_compl volume "
01022 << std::endl;
01023 continue;
01024 }
01025 // build the new surface.
01026 EntityHandle new_cgm_surf, new_cub_surf;
01027 ++max_surf_id;
01028 result = build_new_surface( MBI, new_cgm_surf, cgm_vols2[0], cgm_vols2[1], max_surf_id, dimTag, idTag,
01029 categoryTag, senseTag );
01030 assert( MB_SUCCESS == result );
01031 if( MB_SUCCESS != result ) return result;
01032 result = build_new_surface( MBI, new_cub_surf, cub_vols[0], cub_vols[1], max_surf_id, dimTag, idTag,
01033 categoryTag, senseTag );
01034 assert( MB_SUCCESS == result );
01035 if( MB_SUCCESS != result ) return result;
01036 // add the new surface to the file set and populate it with the old faces
01037 result = MBI->add_entities( cgm_file_set, &new_cgm_surf, 1 );
01038 assert( MB_SUCCESS == result );
01039 if( MB_SUCCESS != result ) return result;
01040 assert( MB_SUCCESS == result );
01041 result = MBI->add_entities( cub_file_set, &new_cub_surf, 1 );
01042 if( MB_SUCCESS != result ) return result;
01043 assert( MB_SUCCESS == result );
01044 result = MBI->add_entities( new_cub_surf, old_faces );
01045 assert( MB_SUCCESS == result );
01046 if( MB_SUCCESS != result ) return result;
01047
01048 std::cout << " Surface " << max_surf_id << ": created for " << old_faces.size() << " old faces"
01049 << std::endl;
01050 }
01051
01052 // the remaining skin faces are newly exposed faces
01053 Range new_faces = skin_faces;
01054
01055 // new skin faces must be assigned to a surface
01056 if( new_faces.empty() ) continue;
01057 std::cout << " Surface " << max_surf_id + 1 << ": created for " << new_faces.size() << " new faces"
01058 << std::endl;
01059
01060 // Ensure that faces are oriented outwards
01061 result = orient_faces_outward( MBI, new_faces, debug );
01062 assert( MB_SUCCESS == result );
01063 if( MB_SUCCESS != result ) return result;
01064
01065 // Create the new surface.
01066 EntityHandle new_cgm_surf, new_cub_surf;
01067 ++max_surf_id;
01068 result = build_new_surface( MBI, new_cgm_surf, *i, 0, max_surf_id, dimTag, idTag, categoryTag, senseTag );
01069 assert( MB_SUCCESS == result );
01070 if( MB_SUCCESS != result ) return result;
01071 result = build_new_surface( MBI, new_cub_surf, cub_vol.front(), 0, max_surf_id, dimTag, idTag, categoryTag,
01072 senseTag );
01073 assert( MB_SUCCESS == result );
01074 if( MB_SUCCESS != result ) return result;
01075 // Insert the new surf into file sets and populate it with faces.
01076 result = MBI->add_entities( cgm_file_set, &new_cgm_surf, 1 );
01077 assert( MB_SUCCESS == result );
01078 if( MB_SUCCESS != result ) return result;
01079 result = MBI->add_entities( cub_file_set, &new_cub_surf, 1 );
01080 assert( MB_SUCCESS == result );
01081 if( MB_SUCCESS != result ) return result;
01082 result = MBI->add_entities( new_cub_surf, new_faces );
01083 assert( MB_SUCCESS == result );
01084 if( MB_SUCCESS != result ) return result;
01085 }
01086
01087 return MB_SUCCESS;
01088 }
01089
01090 /* Get the type of a file.
01091 Return value is one of the above constants
01092 */
01093 const char* get_geom_file_type( const char* filename );
01094 const char* get_geom_fptr_type( FILE* file );
01095
01096 int is_cubit_file( FILE* file );
01097 int is_step_file( FILE* file );
01098 int is_iges_file( FILE* file );
01099 int is_acis_txt_file( FILE* file );
01100 int is_acis_bin_file( FILE* file );
01101 int is_occ_brep_file( FILE* file );
01102
01103 double DEFAULT_DISTANCE = 0.001;
01104 double DEFAULT_LEN = 0.0;
01105 int DEFAULT_NORM = 5;
01106
01107 // load cub file
01108 // load cgm file
01109 // for each surface
01110 // convert cub surf quads to tris
01111 // get signed volume from cgm and cub surf MUST COME BEFORE COORD UPDATE, NEEDS MBTRIS
01112 // reverse cgm surface sense if needed
01113 // replace cgm surf tris with cub surf tris
01114 // measure volume of predeformed cub elements
01115 // convert cub volumes sets to tracking so that dead elems are removed from vol sets
01116 // update coordinates and delete dead elems
01117 // measure volume of deformed cub elems
01118 // print histogram of volume change
01119 // for each cub volume
01120 // skin volume elems to get faces
01121 // for each child cub surface
01122 // assign old skin faces to a new surface in case they are adjacent to another volume
01123 // orient each skin face outward
01124 // assign new skin faces to a new surface
01125 // for each surface
01126 // remove existing tris (from before the update)
01127 // convert quads to tris
01128 // remove empty surfaces and volumes due to dead elements
01129 int main( int argc, char* argv[] )
01130 {
01131 clock_t start_time = clock();
01132
01133 const bool debug = false;
01134 const char* file_type = NULL;
01135
01136 const char* cub_name = 0;
01137 const char* exo_name = 0;
01138 const char* out_name = 0;
01139 const char* time_step = 0;
01140 const char* sat_name = 0;
01141 double dist_tol = 0.001, len_tol = 0.0;
01142 int norm_tol = 5;
01143
01144 if( 6 != argc && 9 != argc )
01145 {
01146 std::cerr << "To read meshed geometry for MOAB:" << std::endl;
01147 std::cerr << "$> conserve_mass" << std::endl;
01148 std::cerr << "To read meshed geometry for MOAB and update node coordinates:" << std::endl;
01149 std::cerr << "$> "
01150 " time_step check_vol_change conserve_mass"
01151 << std::endl;
01152 exit( 4 );
01153 }
01154
01155 // check filenames for proper suffix
01156 std::string temp;
01157 cub_name = argv[1];
01158 temp.assign( cub_name );
01159 if( std::string::npos == temp.find( ".cub" ) )
01160 {
01161 std::cerr << "cub_file does not have correct suffix" << std::endl;
01162 return 1;
01163 }
01164 sat_name = argv[2]; // needed because the cub file's embedded sat file does not have groups
01165 temp.assign( sat_name );
01166 if( std::string::npos == temp.find( ".sat" ) )
01167 {
01168 std::cerr << "sat_file does not have correct suffix" << std::endl;
01169 return 1;
01170 }
01171 out_name = argv[4];
01172 temp.assign( out_name );
01173 if( std::string::npos == temp.find( ".h5m" ) )
01174 {
01175 std::cerr << "out_file does not have correct suffix" << std::endl;
01176 return 1;
01177 }
01178
01179 // get the facet tolerance
01180 dist_tol = atof( argv[3] );
01181 if( 0 > dist_tol || 1 < dist_tol )
01182 {
01183 std::cout << "error: facet_tolerance=" << dist_tol << std::endl;
01184 return 1;
01185 }
01186
01187 // Should the nodes be updated?
01188 bool update_coords = false;
01189 if( 9 == argc )
01190 {
01191 exo_name = argv[5];
01192 temp.assign( exo_name );
01193 if( std::string::npos == temp.find( ".e" ) )
01194 {
01195 std::cerr << "e_file does not have correct suffix" << std::endl;
01196 return 1;
01197 }
01198 time_step = argv[6];
01199 update_coords = true;
01200 }
01201
01202 // Should the volume change be determined?
01203 bool determine_volume_change = false;
01204 if( 9 == argc )
01205 {
01206 temp.assign( argv[7] );
01207 if( std::string::npos != temp.find( "true" ) ) determine_volume_change = true;
01208 }
01209
01210 // Should densities be changed to conserve mass?
01211 bool conserve_mass = false;
01212 if( 9 == argc )
01213 {
01214 temp.assign( argv[8] );
01215 if( std::string::npos != temp.find( "true" ) ) conserve_mass = true;
01216 }
01217 else if( 6 == argc )
01218 {
01219 temp.assign( argv[5] );
01220 if( std::string::npos != temp.find( "true" ) ) conserve_mass = true;
01221 }
01222
01223 // Get CGM file type
01224 if( !file_type )
01225 {
01226 file_type = get_geom_file_type( cub_name );
01227 if( !file_type )
01228 {
01229 std::cerr << cub_name << " : unknown file type, try '-t'" << std::endl;
01230 exit( 1 );
01231 }
01232 }
01233
01234 // Read the mesh from the cub file with Tqcdfr
01235 Core* MBI = new Core();
01236 ErrorCode result;
01237 EntityHandle cub_file_set;
01238 result = MBI->create_meshset( 0, cub_file_set );
01239 if( MB_SUCCESS != result ) return result;
01240 // Do not ignore the Cubit file version. In testing, a cub file from Cubit12
01241 // did not work.
01242 // char cub_options[256] = "120";
01243 // char cub_options[256] = "IGNORE_VERSION";
01244 // result = MBI->load_file(cub_name, &cub_file_set, cub_options, NULL, 0, 0);
01245 result = MBI->load_file( cub_name, &cub_file_set, 0, NULL, 0, 0 );
01246 if( MB_SUCCESS != result )
01247 {
01248 std::cout << "error: problem reading cub file" << std::endl;
01249 return result;
01250 }
01251 std::cout << "Mesh file read." << std::endl;
01252
01253 // Read the ACIS file with ReadCGM
01254 char cgm_options[256];
01255 std::cout << " facet tolerance=" << dist_tol << std::endl;
01256 sprintf( cgm_options,
01257 "CGM_ATTRIBS=yes;FACET_DISTANCE_TOLERANCE=%g;FACET_NORMAL_TOLERANCE=%d;MAX_FACET_EDGE_"
01258 "LENGTH=%g;",
01259 dist_tol, norm_tol, len_tol );
01260 EntityHandle cgm_file_set;
01261 result = MBI->create_meshset( 0, cgm_file_set );
01262 if( MB_SUCCESS != result ) return result;
01263 result = MBI->load_file( sat_name, &cgm_file_set, cgm_options, NULL, 0, 0 );
01264 if( MB_SUCCESS != result )
01265 {
01266 std::cout << "error: problem reading sat file" << std::endl;
01267 return result;
01268 }
01269 std::cout << "CAD file read." << std::endl;
01270
01271 // Create tags
01272 Tag dimTag, idTag, categoryTag, senseTag, sizeTag, nameTag;
01273 result = MBI->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, dimTag, MB_TAG_SPARSE | MB_TAG_CREAT );
01274 if( MB_SUCCESS != result ) return result;
01275 idTag = MBI->globalId_tag();
01276 result = MBI->tag_get_handle( CATEGORY_TAG_NAME, CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE, categoryTag,
01277 MB_TAG_SPARSE | MB_TAG_CREAT );
01278 if( MB_SUCCESS != result ) return result;
01279 result = MBI->tag_get_handle( "GEOM_SENSE_2", 2, MB_TYPE_HANDLE, senseTag, MB_TAG_SPARSE | MB_TAG_CREAT );
01280 if( MB_SUCCESS != result ) return result;
01281 result = MBI->tag_get_handle( "GEOM_SIZE", 1, MB_TYPE_DOUBLE, sizeTag, MB_TAG_DENSE | MB_TAG_CREAT );
01282 if( MB_SUCCESS != result ) return result;
01283 result = MBI->tag_get_handle( NAME_TAG_NAME, NAME_TAG_SIZE, MB_TYPE_OPAQUE, nameTag, MB_TAG_SPARSE | MB_TAG_CREAT );
01284 if( MB_SUCCESS != result ) return result;
01285
01286 // Create triangles from the quads of the cub surface sets and add them to the
01287 // cub surface sets. Get the signed volume of each surface for both cgm and
01288 // cub representations. Change the sense of the cgm representation to match
01289 // the cub representation.
01290 result = fix_surface_senses( MBI, cgm_file_set, cub_file_set, idTag, dimTag, senseTag, debug );
01291 if( MB_SUCCESS != result ) return result;
01292 std::cout << "Fixed CAD surface senses to match meshed surface senses." << std::endl;
01293
01294 // Get the 3D elements in the cub file and measure their volume.
01295 Range orig_elems;
01296 std::vector< double > orig_size;
01297 if( determine_volume_change )
01298 {
01299 result = MBI->get_entities_by_dimension( 0, 3, orig_elems );
01300 if( MB_SUCCESS != result ) return result;
01301 orig_size.resize( orig_elems.size() );
01302 for( unsigned int i = 0; i < orig_elems.size(); ++i )
01303 {
01304 orig_size[i] = measure( MBI, orig_elems[i] );
01305 }
01306 }
01307
01308 // Before updating the nodes and removing dead elements, force the cub volume
01309 // sets to track ownership so that dead elements will be deleted from the sets.
01310 const int three = 3;
01311 const void* const three_val[] = { &three };
01312 Range cub_vols;
01313 result = MBI->get_entities_by_type_and_tag( cub_file_set, MBENTITYSET, &dimTag, three_val, 1, cub_vols );
01314 if( MB_SUCCESS != result ) return result;
01315 for( Range::const_iterator i = cub_vols.begin(); i != cub_vols.end(); ++i )
01316 {
01317 result = MBI->set_meshset_options( *i, MESHSET_TRACK_OWNER );
01318 if( MB_SUCCESS != result ) return result;
01319 }
01320
01321 // Tag volume sets with the undeformed size of each volume.
01322 Range vol_sets;
01323 result = MBI->get_entities_by_type_and_tag( cgm_file_set, MBENTITYSET, &dimTag, three_val, 1, vol_sets );
01324 if( MB_SUCCESS != result ) return result;
01325
01326 moab::GeomTopoTool gtt = moab::GeomTopoTool( MBI, false );
01327 moab::GeomQueryTool gqt = moab::GeomQueryTool( >t );
01328
01329 for( Range::const_iterator i = vol_sets.begin(); i != vol_sets.end(); ++i )
01330 {
01331 double size;
01332 result = gqt.measure_volume( *i, size );
01333 if( MB_SUCCESS != result ) return result;
01334 result = MBI->tag_set_data( sizeTag, &( *i ), 1, &size );
01335 if( MB_SUCCESS != result ) return result;
01336 }
01337
01338 // Update the coordinates if needed. Do not do this before checking surface
01339 // sense, because the coordinate update could deform the surfaces too much
01340 // to make an accurate comparison.
01341 // The cub node ids are unique because cgm vertex ids are tagged on the vertex
01342 // meshset and not the vertex itself.
01343 // result = MBI->delete_entities( &cub_file_set, 1 );
01344 // if(MB_SUCCESS != result) return result;
01345 // Assume dead elements exist until I think of something better.
01346 bool dead_elements_exist = true;
01347 if( update_coords )
01348 {
01349 // ReadNCDF my_ex_reader(MBI);
01350 char exo_options[120] = "tdata=coord,";
01351 strcat( exo_options, time_step );
01352 strcat( exo_options, ",set" );
01353 // FileOptions exo_opts(exo_options) ;
01354 // opts = "tdata=coord, 100, sum, temp.exo";
01355 // result = my_ex_reader.load_file(exo_name, cgm_file_set, exo_opts, NULL, 0 , 0);
01356 // result = my_ex_reader.load_file(exo_name, cub_file_set, exo_opts, NULL, 0 , 0);
01357 // result = my_ex_reader.load_file(exo_name, &cub_file_set, exo_opts, NULL, 0 , 0);
01358 MBI->load_file( exo_name, &cub_file_set, exo_options );
01359 if( MB_SUCCESS != result )
01360 {
01361 std::string last_error;
01362 MBI->get_last_error( last_error );
01363 std::cout << "coordinate update failed, " << last_error << std::endl;
01364 return result;
01365 }
01366 std::cout << "Updated mesh nodes with deformed coordinates from exodus file." << std::endl;
01367 }
01368
01369 if( determine_volume_change )
01370 {
01371 // Dead elements have been removed by the deformation. Get the elements that
01372 // still exist.
01373 Range defo_elems;
01374 result = MBI->get_entities_by_dimension( 0, 3, defo_elems );
01375 if( MB_SUCCESS != result ) return result;
01376
01377 // Determine the volume of the elements now that a deformation has been
01378 // applied. Condense the original array by removing dead elements.
01379 double* orig_size_condensed = new double[defo_elems.size()];
01380 double* defo_size_condensed = new double[defo_elems.size()];
01381 int j = 0;
01382 for( unsigned int i = 0; i < orig_elems.size(); ++i )
01383 {
01384 if( orig_elems[i] == defo_elems[j] )
01385 {
01386 orig_size_condensed[j] = orig_size[i];
01387 defo_size_condensed[j] = measure( MBI, defo_elems[j] );
01388 ++j;
01389 }
01390 }
01391 generate_plots( orig_size_condensed, defo_size_condensed, defo_elems.size(), std::string( time_step ) );
01392 delete[] orig_size_condensed; // can't use the same delete[] for both
01393 delete[] defo_size_condensed;
01394 }
01395
01396 // Deal with dead elements. For now, add them to the impl_compl volume.
01397 // Extra surfaces are created to do this.
01398 if( update_coords && dead_elements_exist )
01399 {
01400 result = add_dead_elems_to_impl_compl( MBI, cgm_file_set, cub_file_set, idTag, dimTag, categoryTag, senseTag,
01401 debug );
01402 if( MB_SUCCESS != result ) return result;
01403 std::cout << "Placed dead elements in implicit complement volume and added required surfaces." << std::endl;
01404 }
01405
01406 // The quads in the cub_file_set have been updated for dead elements. For each
01407 // cgm_surf, if there exists a cub_surf with the same id, replace the cgm tris
01408 // with cub_tris (created from the quads). Note the a surface that is not
01409 // meshed (in cub file) will not be effected.
01410 result = replace_faceted_cgm_surfs( MBI, cgm_file_set, cub_file_set, idTag, dimTag, debug );
01411 if( MB_SUCCESS != result ) return result;
01412 std::cout << "Replaced faceted CAD surfaces with meshed surfaces of triangles." << std::endl;
01413
01414 result = remove_empty_cgm_surfs_and_vols( MBI, cgm_file_set, idTag, dimTag, debug );
01415 if( MB_SUCCESS != result ) return result;
01416 std::cout << "Removed surfaces and volumes that no longer have any triangles." << std::endl;
01417
01418 // For each material, sum the volume. If the coordinates were updated for
01419 // deformation, summarize the volume change.
01420 result = summarize_cell_volume_change( MBI, cgm_file_set, categoryTag, dimTag, sizeTag, nameTag, idTag,
01421 conserve_mass, debug );
01422 if( MB_SUCCESS != result ) return result;
01423 std::cout << "Summarized the volume change of each material, with respect to the solid model." << std::endl;
01424
01425 result = MBI->write_mesh( out_name, &cgm_file_set, 1 );
01426 if( MB_SUCCESS != result )
01427 {
01428 std::cout << "write mesh failed" << std::endl;
01429 return result;
01430 }
01431 std::cout << "Saved output file for mesh-based analysis." << std::endl;
01432
01433 clock_t end_time = clock();
01434 std::cout << " " << (double)( end_time - start_time ) / CLOCKS_PER_SEC << " seconds" << std::endl;
01435 std::cout << std::endl;
01436
01437 return 0;
01438 }
01439
01440 const char* get_geom_file_type( const char* name )
01441 {
01442 FILE* file;
01443 const char* result = 0;
01444
01445 file = fopen( name, "r" );
01446 if( file )
01447 {
01448 result = get_geom_fptr_type( file );
01449 fclose( file );
01450 }
01451
01452 return result;
01453 }
01454
01455 const char* get_geom_fptr_type( FILE* file )
01456 {
01457 static const char* CUBIT_NAME = GF_CUBIT_FILE_TYPE;
01458 static const char* STEP_NAME = GF_STEP_FILE_TYPE;
01459 static const char* IGES_NAME = GF_IGES_FILE_TYPE;
01460 static const char* SAT_NAME = GF_ACIS_TXT_FILE_TYPE;
01461 static const char* SAB_NAME = GF_ACIS_BIN_FILE_TYPE;
01462 static const char* BREP_NAME = GF_OCC_BREP_FILE_TYPE;
01463
01464 if( is_cubit_file( file ) )
01465 return CUBIT_NAME;
01466 else if( is_step_file( file ) )
01467 return STEP_NAME;
01468 else if( is_iges_file( file ) )
01469 return IGES_NAME;
01470 else if( is_acis_bin_file( file ) )
01471 return SAB_NAME;
01472 else if( is_acis_txt_file( file ) )
01473 return SAT_NAME;
01474 else if( is_occ_brep_file( file ) )
01475 return BREP_NAME;
01476 else
01477 return 0;
01478 }
01479
01480 int is_cubit_file( FILE* file )
01481 {
01482 unsigned char buffer[4];
01483 return !fseek( file, 0, SEEK_SET ) && fread( buffer, 4, 1, file ) && !memcmp( buffer, "CUBE", 4 );
01484 }
01485
01486 int is_step_file( FILE* file )
01487 {
01488 unsigned char buffer[9];
01489 return !fseek( file, 0, SEEK_SET ) && fread( buffer, 9, 1, file ) && !memcmp( buffer, "ISO-10303", 9 );
01490 }
01491
01492 int is_iges_file( FILE* file )
01493 {
01494 unsigned char buffer[10];
01495 return !fseek( file, 72, SEEK_SET ) && fread( buffer, 10, 1, file ) && !memcmp( buffer, "S 1\r\n", 10 );
01496 }
01497
01498 int is_acis_bin_file( FILE* file )
01499 {
01500 char buffer[15];
01501 return !fseek( file, 0, SEEK_SET ) && fread( buffer, 15, 1, file ) && !memcmp( buffer, "ACIS BinaryFile", 9 );
01502 }
01503
01504 int is_acis_txt_file( FILE* file )
01505 {
01506 char buffer[5];
01507 int version, length;
01508
01509 if( fseek( file, 0, SEEK_SET ) || 2 != fscanf( file, "%d %*d %*d %*d %d ", &version, &length ) ) return 0;
01510
01511 if( version < 1 || version > 0xFFFF ) return 0;
01512
01513 // Skip application name
01514 if( fseek( file, length, SEEK_CUR ) ) return 0;
01515
01516 // Read length of version string followed by first 5 characters
01517 if( 2 != fscanf( file, "%d %4s", &length, buffer ) ) return 0;
01518
01519 return !strcmp( buffer, "ACIS" );
01520 }
01521
01522 int is_occ_brep_file( FILE* file )
01523 {
01524 unsigned char buffer[6];
01525 return !fseek( file, 0, SEEK_SET ) && fread( buffer, 6, 1, file ) && !memcmp( buffer, "DBRep_", 6 );
01526 }