Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /** 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2006 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 */ 00015 00016 /* Example file for using mhdf interface for reading MOAB native file foramt 00017 * 00018 * Requires libmhdf from MOAB source and HDF5 library 00019 * 00020 * Reads: 00021 * - all node coordinates 00022 * - a single group of hexahedral elements 00023 * - GLOBAL_ID tag if present 00024 * and writes as Gmsh file version 1.0. 00025 * 00026 * Does not contain examples for reading meshsets or 00027 * reading polygon or polyhedron elements. 00028 * 00029 * A simple exorcise: 00030 * Clean up handling of variable number of dimensions by reading 00031 * node coordinate data one dimension at a time using 00032 * mhdf_readNodeCoord 00033 * 00034 * A more complex exorcise: 00035 * Read meshsets with MATERIAL_SET tag, which MOAB uses to 00036 * represent element blocks, and assign appropriate element 00037 * block for each hex in Gmsh file. 00038 * Hint: look for and read MATERIAL_SET tag first to get list of entities 00039 * then read set contents for sets with that tag 00040 * then match hex file ids to lists of set contents 00041 * Be careful of the mhdf_SET_RANGE_BIT for each set when reading set 00042 * contents. 00043 */ 00044 00045 #include <stdlib.h> 00046 #include <stdio.h> 00047 #include <assert.h> 00048 #include <string.h> 00049 00050 /* mhdf API */ 00051 #include "mhdf.h" 00052 /* need constants for native types (e.g. H5T_NATIVE_UINT)*/ 00053 #include <H5Tpublic.h> 00054 00055 /* Macro to check return status from mhdf calls. Exit on error. */ 00056 #define CHK_ERR( A ) \ 00057 do \ 00058 { \ 00059 if( mhdf_isError( A ) ) \ 00060 { \ 00061 fprintf( stderr, "Error: %s\n", mhdf_message( A ) ); \ 00062 exit( 2 ); \ 00063 } \ 00064 } while( 0 ) 00065 00066 int main( int argc, char* argv[] ) 00067 { 00068 /* input file */ 00069 const char* filename; 00070 mhdf_FileHandle file; 00071 mhdf_Status status; 00072 mhdf_Status* const sptr = &status; 00073 hid_t handle; /* generic handle used to refer to any data block in file */ 00074 00075 /* output file */ 00076 const char* gmsh_filename; 00077 FILE* gmsh; 00078 unsigned gmsh_type; /* hexahedral element type number */ 00079 double x, y, z; /* temp storage of node coordinates */ 00080 unsigned node_offset, node_id; /* temporary values */ 00081 unsigned* connectivity; /* temporary value */ 00082 00083 /* node data */ 00084 long numnode; /* total number of nodes */ 00085 long nodestart; /* file id of first node in list */ 00086 int dimension; /* coordinate values per node */ 00087 double* nodecoords; /* interleaved node coordinates */ 00088 unsigned* nodeids; /* GLOBAL_ID value for nodes */ 00089 int have_nodeids = 0; 00090 00091 /* hex data */ 00092 char* hexgroup = NULL; /* name of element group containing hexes */ 00093 long numhex; /* total number of hexahedral elements */ 00094 long hexstart; /* file id of first hex in group */ 00095 int nodes_per_hex; /* length of connectivity list for a hex */ 00096 unsigned* hexconnectivity; /* hex connectivity data */ 00097 unsigned* hexids; /* GLOBAL_ID value for hexes */ 00098 int have_hexids = 0; 00099 00100 /* list of element groups in file */ 00101 char** elem_groups; 00102 unsigned num_elem_groups; 00103 char namebuffer[64]; 00104 00105 /* tag data for accessing GLOBAL_ID */ 00106 int tagsize; /* number of values for each entity */ 00107 int ts, td, tg; /* unused tag properties */ 00108 int havesparse, havedense; /* Boolean values */ 00109 enum mhdf_TagDataType tagtype; /* base data type of tag */ 00110 hid_t sparse_handle[2]; /* handle pair for sparse tag data */ 00111 unsigned* sparse_entities; /* temp storage of sparse tag file ids */ 00112 unsigned* sparse_ids; /* temp storage of GLOBAL_ID values in spasre tag */ 00113 long junk, numtag; /* number of entities for which tag data is available */ 00114 long fileid, globalid; /* temporary values */ 00115 long ncount = 0, hcount = 0; /* temporary count of number of tag values */ 00116 00117 /* iteration */ 00118 long i; 00119 int j; 00120 unsigned k; 00121 00122 /* process CL args (expect input .h5m file and output .gmsh file name) */ 00123 if( argc != 3 ) 00124 { 00125 fprintf( stderr, "Usage: %s <input_file> <output_file>\n", argv[0] ); 00126 return 1; 00127 } 00128 filename = argv[1]; 00129 gmsh_filename = argv[2]; 00130 00131 /* Open the file */ 00132 file = mhdf_openFile( filename, 0, 0, sptr );CHK_ERR( sptr ); 00133 00134 /* Read node coordinates. */ 00135 handle = mhdf_openNodeCoords( file, &numnode, &dimension, &nodestart, sptr );CHK_ERR( sptr ); 00136 nodecoords = (double*)malloc( dimension * numnode * sizeof( double ) ); 00137 mhdf_readNodeCoords( handle, 0, numnode, nodecoords, sptr );CHK_ERR( sptr ); 00138 mhdf_closeData( file, handle, sptr );CHK_ERR( sptr ); 00139 00140 /* Find first element group containing hexahedra */ 00141 elem_groups = mhdf_getElemHandles( file, &num_elem_groups, sptr );CHK_ERR( sptr ); 00142 for( k = 0; k < num_elem_groups; ++k ) 00143 { 00144 mhdf_getElemTypeName( file, elem_groups[k], namebuffer, sizeof( namebuffer ), sptr );CHK_ERR( sptr ); 00145 if( !hexgroup && !strcmp( mdhf_HEX_TYPE_NAME, namebuffer ) ) 00146 hexgroup = strdup( elem_groups[k] ); 00147 else 00148 printf( "Skipping element group '%s' containing element of type '%s'\n", elem_groups[k], namebuffer ); 00149 } 00150 free( elem_groups ); 00151 00152 if( !hexgroup ) 00153 { 00154 fprintf( stderr, "No Hexahedra defined in file\n" ); 00155 return 4; 00156 } 00157 00158 /* Read Hexahedron connectivity */ 00159 handle = mhdf_openConnectivity( file, hexgroup, &nodes_per_hex, &numhex, &hexstart, sptr );CHK_ERR( sptr ); 00160 hexconnectivity = (unsigned*)malloc( numhex * nodes_per_hex * sizeof( unsigned ) ); 00161 mhdf_readConnectivity( handle, 0, numhex, H5T_NATIVE_UINT, hexconnectivity, sptr );CHK_ERR( sptr ); 00162 mhdf_closeData( file, handle, sptr );CHK_ERR( sptr ); 00163 /* Note: hex connectivity list contains file-space node IDs, which are 00164 the nodes in the sequence they are read from the file, with 00165 the first node having an ID of 'nodestart' */ 00166 00167 /* Check for "GLOBAL_ID" tag */ 00168 nodeids = (unsigned*)malloc( numnode * sizeof( unsigned ) ); 00169 hexids = (unsigned*)malloc( numhex * sizeof( unsigned ) ); 00170 mhdf_getTagInfo( file, "GLOBAL_ID", &tagtype, &tagsize, &ts, &td, &tg, &havesparse, sptr ); 00171 00172 /* If have GLOBAL_ID tag, try to read values for nodes and hexes */ 00173 if( !mhdf_isError( sptr ) ) 00174 { 00175 /* Check that the tag contains what we expect */ 00176 if( tagtype != mhdf_INTEGER || tagsize != 1 ) 00177 { 00178 fprintf( stderr, "ERROR: Invalid data type for 'GLOBAL_ID' tag.\n" ); 00179 exit( 3 ); 00180 } 00181 00182 /* Check for and read dense-format tag data for nodes */ 00183 havedense = mhdf_haveDenseTag( file, "GLOBAL_ID", mhdf_node_type_handle(), sptr );CHK_ERR( sptr ); 00184 if( havedense ) 00185 { 00186 handle = mhdf_openDenseTagData( file, "GLOBAL_ID", mhdf_node_type_handle(), &numtag, sptr );CHK_ERR( sptr ); 00187 assert( numtag == numnode ); 00188 mhdf_readDenseTag( handle, 0, numtag, H5T_NATIVE_UINT, nodeids, sptr );CHK_ERR( sptr ); 00189 mhdf_closeData( file, handle, sptr );CHK_ERR( sptr ); 00190 have_nodeids = 1; 00191 } 00192 /* Check for and read dense-format tag data for hexes */ 00193 havedense = mhdf_haveDenseTag( file, "GLOBAL_ID", hexgroup, sptr );CHK_ERR( sptr ); 00194 if( havedense ) 00195 { 00196 handle = mhdf_openDenseTagData( file, "GLOBAL_ID", hexgroup, &numtag, sptr );CHK_ERR( sptr ); 00197 assert( numtag == numhex ); 00198 mhdf_readDenseTag( handle, 0, numtag, H5T_NATIVE_UINT, hexids, sptr );CHK_ERR( sptr ); 00199 mhdf_closeData( file, handle, sptr );CHK_ERR( sptr ); 00200 have_hexids = 1; 00201 } 00202 /* Check for and read sparse-format tag data */ 00203 if( havesparse ) 00204 { 00205 mhdf_openSparseTagData( file, "GLOBAL_ID", &numtag, &junk, sparse_handle, sptr );CHK_ERR( sptr ); 00206 sparse_entities = (unsigned*)malloc( numtag * sizeof( unsigned ) ); 00207 mhdf_readSparseTagEntities( sparse_handle[0], 0, numtag, H5T_NATIVE_UINT, sparse_entities, sptr );CHK_ERR( sptr ); 00208 sparse_ids = (unsigned*)malloc( numtag * sizeof( unsigned ) ); 00209 mhdf_readSparseTagValues( sparse_handle[1], 0, numtag, H5T_NATIVE_UINT, sparse_ids, sptr );CHK_ERR( sptr ); 00210 mhdf_closeData( file, sparse_handle[0], sptr );CHK_ERR( sptr ); 00211 mhdf_closeData( file, sparse_handle[1], sptr );CHK_ERR( sptr ); 00212 00213 /* Set hex and node ids from sparse tag data */ 00214 for( i = 0; i < numtag; ++i ) 00215 { 00216 fileid = sparse_entities[i]; 00217 globalid = sparse_ids[i]; 00218 if( fileid >= nodestart && fileid - nodestart < numnode ) 00219 { 00220 nodeids[fileid - nodestart] = globalid; 00221 ++ncount; 00222 } 00223 else if( fileid >= hexstart && fileid - hexstart < numhex ) 00224 { 00225 hexids[fileid - hexstart] = globalid; 00226 ++hcount; 00227 } 00228 } 00229 free( sparse_ids ); 00230 free( sparse_entities ); 00231 00232 /* make sure there was an ID for each node and each hex */ 00233 if( ncount == numnode ) have_nodeids = 1; 00234 if( hcount == numhex ) have_hexids = 1; 00235 00236 } /* end have sparse tag for GLOBAL_ID */ 00237 } /* end have GLOBAL_ID tag */ 00238 00239 /* done with input file */ 00240 free( hexgroup ); 00241 mhdf_closeFile( file, sptr );CHK_ERR( sptr ); 00242 00243 /* if no GLOBAL_ID, just use incrementing values */ 00244 if( !have_nodeids ) 00245 for( i = 0; i < numnode; ++i ) 00246 nodeids[i] = i + 1; 00247 if( !have_hexids ) 00248 for( i = 0; i < numhex; ++i ) 00249 hexids[i] = i + 1; 00250 00251 /* write out as gmesh file version 1.0 */ 00252 00253 /* get gmsh type for hexahedrons */ 00254 if( nodes_per_hex == 8 ) 00255 gmsh_type = 5; 00256 else if( nodes_per_hex == 27 ) 00257 gmsh_type = 12; 00258 else 00259 { 00260 fprintf( stderr, "Cannot store %d node hex in gmsh file.\n", nodes_per_hex ); 00261 exit( 4 ); 00262 } 00263 00264 /* open file */ 00265 gmsh = fopen( gmsh_filename, "w" ); 00266 00267 /* Write node data. If dimension is less than 3, 00268 write zero for other coordinate values. In the 00269 (highly unlikely) case that dimension is greater 00270 than three, disregard higher-dimension coordinate 00271 values. */ 00272 fprintf( gmsh, "$NOD\n" ); 00273 fprintf( gmsh, "%lu\n", numnode ); 00274 for( i = 0; i < numnode; ++i ) 00275 { 00276 x = nodecoords[dimension * i]; 00277 y = z = 0.0; 00278 if( dimension > 1 ) 00279 { 00280 y = nodecoords[dimension * i + 1]; 00281 if( dimension > 2 ) 00282 { 00283 z = nodecoords[dimension * i + 2]; 00284 } 00285 } 00286 fprintf( gmsh, "%u %f %f %f\n", nodeids[i], x, y, z ); 00287 } 00288 00289 /* Write element connectivity data */ 00290 fprintf( gmsh, "$ENDNOD\n$ELM\n" ); 00291 fprintf( gmsh, "%lu\n", numhex ); 00292 for( i = 0; i < numhex; ++i ) 00293 { 00294 fprintf( gmsh, "%u %u 1 1 %d", hexids[i], gmsh_type, nodes_per_hex ); 00295 /* connectivity list for this hex */ 00296 connectivity = hexconnectivity + i * nodes_per_hex; 00297 for( j = 0; j < nodes_per_hex; ++j ) 00298 { 00299 /* get offset in node list from file id */ 00300 node_offset = connectivity[j] - nodestart; 00301 /* get node id from ID list */ 00302 node_id = nodeids[node_offset]; 00303 fprintf( gmsh, " %u", node_id ); 00304 } 00305 fprintf( gmsh, "\n" ); 00306 } 00307 fprintf( gmsh, "$ENDELM\n" ); 00308 fclose( gmsh ); 00309 return 0; 00310 }