MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /** 00002 * \class ReadCGNS 00003 * \brief Template for writing a new reader in MOAB 00004 * 00005 */ 00006 00007 #include "ReadCGNS.hpp" 00008 #include "Internals.hpp" 00009 #include "moab/Interface.hpp" 00010 #include "moab/ReadUtilIface.hpp" 00011 #include "moab/Range.hpp" 00012 #include "moab/FileOptions.hpp" 00013 #include "MBTagConventions.hpp" 00014 #include "MBParallelConventions.h" 00015 #include "moab/CN.hpp" 00016 00017 #include <cstdio> 00018 #include <cassert> 00019 #include <cerrno> 00020 #include <map> 00021 #include <set> 00022 00023 #include <iostream> 00024 #include <cmath> 00025 00026 namespace moab 00027 { 00028 00029 ReaderIface* ReadCGNS::factory( Interface* iface ) 00030 { 00031 return new ReadCGNS( iface ); 00032 } 00033 00034 ReadCGNS::ReadCGNS( Interface* impl ) : fileName( NULL ), mesh_dim( 0 ), mbImpl( impl ), globalId( 0 ), boundary( 0 ) 00035 { 00036 mbImpl->query_interface( readMeshIface ); 00037 } 00038 00039 ReadCGNS::~ReadCGNS() 00040 { 00041 if( readMeshIface ) 00042 { 00043 mbImpl->release_interface( readMeshIface ); 00044 readMeshIface = 0; 00045 } 00046 } 00047 00048 ErrorCode ReadCGNS::read_tag_values( const char* /* file_name */, 00049 const char* /* tag_name */, 00050 const FileOptions& /* opts */, 00051 std::vector< int >& /* tag_values_out */, 00052 const SubsetList* /* subset_list */ ) 00053 { 00054 return MB_NOT_IMPLEMENTED; 00055 } 00056 00057 ErrorCode ReadCGNS::load_file( const char* filename, 00058 const EntityHandle* /*file_set*/, 00059 const FileOptions& opts, 00060 const ReaderIface::SubsetList* subset_list, 00061 const Tag* file_id_tag ) 00062 { 00063 int num_material_sets = 0; 00064 const int* material_set_list = 0; 00065 00066 if( subset_list ) 00067 { 00068 if( subset_list->tag_list_length > 1 && !strcmp( subset_list->tag_list[0].tag_name, MATERIAL_SET_TAG_NAME ) ) 00069 { 00070 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "CGNS supports subset read only by material ID" ); 00071 } 00072 material_set_list = subset_list->tag_list[0].tag_values; 00073 num_material_sets = subset_list->tag_list[0].num_tag_values; 00074 } 00075 00076 ErrorCode result; 00077 00078 geomSets.clear(); 00079 globalId = mbImpl->globalId_tag(); 00080 00081 // Create set for more convenient check for material set ids 00082 std::set< int > blocks; 00083 for( const int* mat_set_end = material_set_list + num_material_sets; material_set_list != mat_set_end; 00084 ++material_set_list ) 00085 blocks.insert( *material_set_list ); 00086 00087 // Map of ID->handle for nodes 00088 std::map< long, EntityHandle > node_id_map; 00089 00090 // Save filename to member variable so we don't need to pass as an argument 00091 // to called functions 00092 fileName = filename; 00093 00094 // Process options; see src/FileOptions.hpp for API for FileOptions class, and 00095 // doc/metadata_info.doc for a description of various options used by some of the readers in 00096 // MOAB 00097 result = process_options( opts );MB_CHK_SET_ERR( result, fileName << ": problem reading options" ); 00098 00099 // Open file 00100 int filePtr = 0; 00101 00102 cg_open( filename, CG_MODE_READ, &filePtr ); 00103 00104 if( filePtr <= 0 ) 00105 { 00106 MB_SET_ERR( MB_FILE_DOES_NOT_EXIST, fileName << ": fopen returned error" ); 00107 } 00108 00109 // Read number of verts, elements, sets 00110 long num_verts = 0, num_elems = 0, num_sets = 0; 00111 int num_bases = 0, num_zones = 0, num_sections = 0; 00112 00113 char zoneName[128]; 00114 cgsize_t size[3]; 00115 00116 mesh_dim = 3; // Default to 3D 00117 00118 // Read number of bases; 00119 cg_nbases( filePtr, &num_bases ); 00120 00121 if( num_bases > 1 ) 00122 { 00123 MB_SET_ERR( MB_NOT_IMPLEMENTED, fileName << ": support for number of bases > 1 not implemented" ); 00124 } 00125 00126 for( int indexBase = 1; indexBase <= num_bases; ++indexBase ) 00127 { 00128 // Get the number of zones/blocks in current base. 00129 cg_nzones( filePtr, indexBase, &num_zones ); 00130 00131 if( num_zones > 1 ) 00132 { 00133 MB_SET_ERR( MB_NOT_IMPLEMENTED, fileName << ": support for number of zones > 1 not implemented" ); 00134 } 00135 00136 for( int indexZone = 1; indexZone <= num_zones; ++indexZone ) 00137 { 00138 // Get zone name and size. 00139 cg_zone_read( filePtr, indexBase, indexZone, zoneName, size ); 00140 00141 // Read number of sections/Parts in current zone. 00142 cg_nsections( filePtr, indexBase, indexZone, &num_sections ); 00143 00144 num_verts = size[0]; 00145 num_elems = size[1]; 00146 num_sets = num_sections; 00147 00148 std::cout << "\nnumber of nodes = " << num_verts; 00149 std::cout << "\nnumber of elems = " << num_elems; 00150 std::cout << "\nnumber of parts = " << num_sets << std::endl; 00151 00152 // ////////////////////////////////// 00153 // Read Nodes 00154 00155 // Allocate nodes; these are allocated in one shot, get contiguous handles starting with 00156 // start_handle, and the reader is passed back double*'s pointing to MOAB's native 00157 // storage for vertex coordinates for those verts 00158 std::vector< double* > coord_arrays; 00159 EntityHandle handle = 0; 00160 result = readMeshIface->get_node_coords( 3, num_verts, MB_START_ID, handle, coord_arrays );MB_CHK_SET_ERR( result, fileName << ": Trouble reading vertices" ); 00161 00162 // Fill in vertex coordinate arrays 00163 cgsize_t beginPos = 1, endPos = num_verts; 00164 00165 // Read nodes coordinates. 00166 cg_coord_read( filePtr, indexBase, indexZone, "CoordinateX", RealDouble, &beginPos, &endPos, 00167 coord_arrays[0] ); 00168 cg_coord_read( filePtr, indexBase, indexZone, "CoordinateY", RealDouble, &beginPos, &endPos, 00169 coord_arrays[1] ); 00170 cg_coord_read( filePtr, indexBase, indexZone, "CoordinateZ", RealDouble, &beginPos, &endPos, 00171 coord_arrays[2] ); 00172 00173 // CGNS seems to always include the Z component, even if the mesh is 2D. 00174 // Check if Z is zero and determine mesh dimension. 00175 // Also create the node_id_map data. 00176 double sumZcoord = 0.0; 00177 double eps = 1.0e-12; 00178 for( long i = 0; i < num_verts; ++i, ++handle ) 00179 { 00180 int index = i + 1; 00181 00182 node_id_map.insert( std::pair< long, EntityHandle >( index, handle ) ).second; 00183 00184 sumZcoord += *( coord_arrays[2] + i ); 00185 } 00186 if( std::abs( sumZcoord ) <= eps ) mesh_dim = 2; 00187 00188 // Create reverse map from handle to id 00189 std::vector< int > ids( num_verts ); 00190 std::vector< int >::iterator id_iter = ids.begin(); 00191 std::vector< EntityHandle > handles( num_verts ); 00192 std::vector< EntityHandle >::iterator h_iter = handles.begin(); 00193 for( std::map< long, EntityHandle >::iterator i = node_id_map.begin(); i != node_id_map.end(); 00194 ++i, ++id_iter, ++h_iter ) 00195 { 00196 *id_iter = i->first; 00197 *h_iter = i->second; 00198 } 00199 // Store IDs in tags 00200 result = mbImpl->tag_set_data( globalId, &handles[0], num_verts, &ids[0] ); 00201 if( MB_SUCCESS != result ) return result; 00202 if( file_id_tag ) 00203 { 00204 result = mbImpl->tag_set_data( *file_id_tag, &handles[0], num_verts, &ids[0] ); 00205 if( MB_SUCCESS != result ) return result; 00206 } 00207 ids.clear(); 00208 handles.clear(); 00209 00210 // ////////////////////////////////// 00211 // Read elements data 00212 00213 EntityType ent_type; 00214 00215 long section_offset = 0; 00216 00217 // Define which mesh parts are volume families. 00218 // Mesh parts with volumeID[X] = 0 are boundary parts. 00219 std::vector< int > volumeID( num_sections, 0 ); 00220 00221 for( int section = 0; section < num_sections; ++section ) 00222 { 00223 ElementType_t elemsType; 00224 int iparent_flag, nbndry; 00225 char sectionName[128]; 00226 int verts_per_elem; 00227 00228 int cgSection = section + 1; 00229 00230 cg_section_read( filePtr, indexBase, indexZone, cgSection, sectionName, &elemsType, &beginPos, &endPos, 00231 &nbndry, &iparent_flag ); 00232 00233 size_t section_size = endPos - beginPos + 1; 00234 00235 // Read element description in current section 00236 00237 switch( elemsType ) 00238 { 00239 case BAR_2: 00240 ent_type = MBEDGE; 00241 verts_per_elem = 2; 00242 break; 00243 case TRI_3: 00244 ent_type = MBTRI; 00245 verts_per_elem = 3; 00246 if( mesh_dim == 2 ) volumeID[section] = 1; 00247 break; 00248 case QUAD_4: 00249 ent_type = MBQUAD; 00250 verts_per_elem = 4; 00251 if( mesh_dim == 2 ) volumeID[section] = 1; 00252 break; 00253 case TETRA_4: 00254 ent_type = MBTET; 00255 verts_per_elem = 4; 00256 if( mesh_dim == 3 ) volumeID[section] = 1; 00257 break; 00258 case PYRA_5: 00259 ent_type = MBPYRAMID; 00260 verts_per_elem = 5; 00261 if( mesh_dim == 3 ) volumeID[section] = 1; 00262 break; 00263 case PENTA_6: 00264 ent_type = MBPRISM; 00265 verts_per_elem = 6; 00266 if( mesh_dim == 3 ) volumeID[section] = 1; 00267 break; 00268 case HEXA_8: 00269 ent_type = MBHEX; 00270 verts_per_elem = 8; 00271 if( mesh_dim == 3 ) volumeID[section] = 1; 00272 break; 00273 case MIXED: 00274 ent_type = MBMAXTYPE; 00275 verts_per_elem = 0; 00276 break; 00277 default: 00278 MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" ); 00279 } 00280 00281 if( elemsType == TETRA_4 || elemsType == PYRA_5 || elemsType == PENTA_6 || elemsType == HEXA_8 || 00282 elemsType == TRI_3 || elemsType == QUAD_4 || ( ( elemsType == BAR_2 ) && mesh_dim == 2 ) ) 00283 { 00284 // Read connectivity into conn_array directly 00285 00286 cgsize_t iparentdata; 00287 cgsize_t connDataSize; 00288 00289 // Get number of entries on the connectivity list for this section 00290 cg_ElementDataSize( filePtr, indexBase, indexZone, cgSection, &connDataSize ); 00291 00292 // Need a temporary vector to later cast to conn_array. 00293 std::vector< cgsize_t > elemNodes( connDataSize ); 00294 00295 cg_elements_read( filePtr, indexBase, indexZone, cgSection, &elemNodes[0], &iparentdata ); 00296 00297 // ////////////////////////////////// 00298 // Create elements, sets and tags 00299 00300 create_elements( sectionName, file_id_tag, ent_type, verts_per_elem, section_offset, section_size, 00301 elemNodes ); 00302 } // Homogeneous mesh type 00303 else if( elemsType == MIXED ) 00304 { 00305 // We must first sort all elements connectivities into continuous vectors 00306 00307 cgsize_t connDataSize; 00308 cgsize_t iparentdata; 00309 00310 cg_ElementDataSize( filePtr, indexBase, indexZone, cgSection, &connDataSize ); 00311 00312 std::vector< cgsize_t > elemNodes( connDataSize ); 00313 00314 cg_elements_read( filePtr, indexBase, indexZone, cgSection, &elemNodes[0], &iparentdata ); 00315 00316 std::vector< cgsize_t > elemsConn_EDGE; 00317 std::vector< cgsize_t > elemsConn_TRI, elemsConn_QUAD; 00318 std::vector< cgsize_t > elemsConn_TET, elemsConn_PYRA, elemsConn_PRISM, elemsConn_HEX; 00319 cgsize_t count_EDGE, count_TRI, count_QUAD; 00320 cgsize_t count_TET, count_PYRA, count_PRISM, count_HEX; 00321 00322 // First, get elements count for current section 00323 00324 count_EDGE = count_TRI = count_QUAD = 0; 00325 count_TET = count_PYRA = count_PRISM = count_HEX = 0; 00326 00327 int connIndex = 0; 00328 for( int i = beginPos; i <= endPos; i++ ) 00329 { 00330 elemsType = ElementType_t( elemNodes[connIndex] ); 00331 00332 // Get current cell node count. 00333 cg_npe( elemsType, &verts_per_elem ); 00334 00335 switch( elemsType ) 00336 { 00337 case BAR_2: 00338 count_EDGE += 1; 00339 break; 00340 case TRI_3: 00341 count_TRI += 1; 00342 break; 00343 case QUAD_4: 00344 count_QUAD += 1; 00345 break; 00346 case TETRA_4: 00347 count_TET += 1; 00348 break; 00349 case PYRA_5: 00350 count_PYRA += 1; 00351 break; 00352 case PENTA_6: 00353 count_PRISM += 1; 00354 break; 00355 case HEXA_8: 00356 count_HEX += 1; 00357 break; 00358 default: 00359 MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" ); 00360 } 00361 00362 connIndex += ( verts_per_elem + 1 ); // Add one to skip next element descriptor 00363 } 00364 00365 if( count_EDGE > 0 ) elemsConn_EDGE.resize( count_EDGE * 2 ); 00366 if( count_TRI > 0 ) elemsConn_TRI.resize( count_TRI * 3 ); 00367 if( count_QUAD > 0 ) elemsConn_QUAD.resize( count_QUAD * 4 ); 00368 if( count_TET > 0 ) elemsConn_TET.resize( count_TET * 4 ); 00369 if( count_PYRA > 0 ) elemsConn_PYRA.resize( count_PYRA * 5 ); 00370 if( count_PRISM > 0 ) elemsConn_PRISM.resize( count_PRISM * 6 ); 00371 if( count_HEX > 0 ) elemsConn_HEX.resize( count_HEX * 8 ); 00372 00373 // Grab mixed section elements connectivity 00374 00375 int idx_edge, idx_tri, idx_quad; 00376 int idx_tet, idx_pyra, idx_prism, idx_hex; 00377 idx_edge = idx_tri = idx_quad = 0; 00378 idx_tet = idx_pyra = idx_prism = idx_hex = 0; 00379 00380 connIndex = 0; 00381 for( int i = beginPos; i <= endPos; i++ ) 00382 { 00383 elemsType = ElementType_t( elemNodes[connIndex] ); 00384 00385 // Get current cell node count. 00386 cg_npe( elemsType, &verts_per_elem ); 00387 00388 switch( elemsType ) 00389 { 00390 case BAR_2: 00391 for( int j = 0; j < 2; ++j ) 00392 elemsConn_EDGE[idx_edge + j] = elemNodes[connIndex + j + 1]; 00393 idx_edge += 2; 00394 break; 00395 case TRI_3: 00396 for( int j = 0; j < 3; ++j ) 00397 elemsConn_TRI[idx_tri + j] = elemNodes[connIndex + j + 1]; 00398 idx_tri += 3; 00399 break; 00400 case QUAD_4: 00401 for( int j = 0; j < 4; ++j ) 00402 elemsConn_QUAD[idx_quad + j] = elemNodes[connIndex + j + 1]; 00403 idx_quad += 4; 00404 break; 00405 case TETRA_4: 00406 for( int j = 0; j < 4; ++j ) 00407 elemsConn_TET[idx_tet + j] = elemNodes[connIndex + j + 1]; 00408 idx_tet += 4; 00409 break; 00410 case PYRA_5: 00411 for( int j = 0; j < 5; ++j ) 00412 elemsConn_PYRA[idx_pyra + j] = elemNodes[connIndex + j + 1]; 00413 idx_pyra += 5; 00414 break; 00415 case PENTA_6: 00416 for( int j = 0; j < 6; ++j ) 00417 elemsConn_PRISM[idx_prism + j] = elemNodes[connIndex + j + 1]; 00418 idx_prism += 6; 00419 break; 00420 case HEXA_8: 00421 for( int j = 0; j < 8; ++j ) 00422 elemsConn_HEX[idx_hex + j] = elemNodes[connIndex + j + 1]; 00423 idx_hex += 8; 00424 break; 00425 default: 00426 MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" ); 00427 } 00428 00429 connIndex += ( verts_per_elem + 1 ); // Add one to skip next element descriptor 00430 } 00431 00432 // ////////////////////////////////// 00433 // Create elements, sets and tags 00434 00435 if( count_EDGE > 0 ) 00436 create_elements( sectionName, file_id_tag, MBEDGE, 2, section_offset, count_EDGE, 00437 elemsConn_EDGE ); 00438 00439 if( count_TRI > 0 ) 00440 create_elements( sectionName, file_id_tag, MBTRI, 3, section_offset, count_TRI, elemsConn_TRI ); 00441 00442 if( count_QUAD > 0 ) 00443 create_elements( sectionName, file_id_tag, MBQUAD, 4, section_offset, count_QUAD, 00444 elemsConn_QUAD ); 00445 00446 if( count_TET > 0 ) 00447 create_elements( sectionName, file_id_tag, MBTET, 4, section_offset, count_TET, elemsConn_TET ); 00448 00449 if( count_PYRA > 0 ) 00450 create_elements( sectionName, file_id_tag, MBPYRAMID, 5, section_offset, count_PYRA, 00451 elemsConn_PYRA ); 00452 00453 if( count_PRISM > 0 ) 00454 create_elements( sectionName, file_id_tag, MBPRISM, 6, section_offset, count_PRISM, 00455 elemsConn_PRISM ); 00456 00457 if( count_HEX > 0 ) 00458 create_elements( sectionName, file_id_tag, MBHEX, 8, section_offset, count_HEX, elemsConn_HEX ); 00459 } // Mixed mesh type 00460 } // num_sections 00461 00462 cg_close( filePtr ); 00463 00464 return result; 00465 } // indexZone for 00466 } // indexBase for 00467 00468 return MB_SUCCESS; 00469 } 00470 00471 ErrorCode ReadCGNS::create_elements( char* sectionName, 00472 const Tag* file_id_tag, 00473 const EntityType& ent_type, 00474 const int& verts_per_elem, 00475 long& section_offset, 00476 int elems_count, 00477 const std::vector< cgsize_t >& elemsConn ) 00478 { 00479 ErrorCode result; 00480 00481 // Create the element sequence; passes back a pointer to the internal storage for connectivity 00482 // and the starting entity handle 00483 EntityHandle* conn_array; 00484 EntityHandle handle = 0; 00485 00486 result = readMeshIface->get_element_connect( elems_count, verts_per_elem, ent_type, 1, handle, conn_array );MB_CHK_SET_ERR( result, fileName << ": Trouble reading elements" ); 00487 00488 if( sizeof( EntityHandle ) == sizeof( cgsize_t ) ) 00489 { 00490 memcpy( conn_array, &elemsConn[0], elemsConn.size() * sizeof( EntityHandle ) ); 00491 } 00492 else 00493 { // if CGNS is compiled without 64bit enabled 00494 std::vector< EntityHandle > elemsConnTwin( elemsConn.size(), 0 ); 00495 for( int i = 0; i < elemsConn.size(); i++ ) 00496 { 00497 elemsConnTwin[i] = static_cast< EntityHandle >( elemsConn[i] ); 00498 } 00499 memcpy( conn_array, &elemsConnTwin[0], elemsConnTwin.size() * sizeof( EntityHandle ) ); 00500 } 00501 00502 // Notify MOAB of the new elements 00503 result = readMeshIface->update_adjacencies( handle, elems_count, verts_per_elem, conn_array ); 00504 if( MB_SUCCESS != result ) return result; 00505 00506 // ////////////////////////////////// 00507 // Create sets and tags 00508 00509 Range elements( handle, handle + elems_count - 1 ); 00510 00511 // Store element IDs 00512 00513 std::vector< int > id_list( elems_count ); 00514 00515 // Add 1 to offset id to 1-based numbering 00516 for( cgsize_t i = 0; i < elems_count; ++i ) 00517 id_list[i] = i + 1 + section_offset; 00518 section_offset += elems_count; 00519 00520 create_sets( sectionName, file_id_tag, ent_type, elements, id_list, 0 ); 00521 00522 return MB_SUCCESS; 00523 } 00524 00525 ErrorCode ReadCGNS::create_sets( char* sectionName, 00526 const Tag* file_id_tag, 00527 EntityType /*element_type*/, 00528 const Range& elements, 00529 const std::vector< int >& set_ids, 00530 int /*set_type*/ ) 00531 { 00532 ErrorCode result; 00533 00534 result = mbImpl->tag_set_data( globalId, elements, &set_ids[0] ); 00535 if( MB_SUCCESS != result ) return result; 00536 00537 if( file_id_tag ) 00538 { 00539 result = mbImpl->tag_set_data( *file_id_tag, elements, &set_ids[0] ); 00540 if( MB_SUCCESS != result ) return result; 00541 } 00542 00543 EntityHandle set_handle; 00544 00545 Tag tag_handle; 00546 00547 const char* setName = sectionName; 00548 00549 mbImpl->tag_get_handle( setName, 1, MB_TYPE_INTEGER, tag_handle, MB_TAG_SPARSE | MB_TAG_CREAT ); 00550 00551 // Create set 00552 result = mbImpl->create_meshset( MESHSET_SET, set_handle );MB_CHK_SET_ERR( result, fileName << ": Trouble creating set" ); 00553 00554 //// Add dummy values to current set 00555 // std::vector<int> tags(set_ids.size(), 1); 00556 // result = mbImpl->tag_set_data(tag_handle, elements, &tags[0]); 00557 // if (MB_SUCCESS != result) return result; 00558 00559 // Add them to the set 00560 result = mbImpl->add_entities( set_handle, elements );MB_CHK_SET_ERR( result, fileName << ": Trouble putting entities in set" ); 00561 00562 return MB_SUCCESS; 00563 } 00564 00565 ErrorCode ReadCGNS::process_options( const FileOptions& opts ) 00566 { 00567 // Mark all options seen, to avoid compile warning on unused variable 00568 opts.mark_all_seen(); 00569 00570 return MB_SUCCESS; 00571 } 00572 00573 } // namespace moab