Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
hexes_to_gmsh.c
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2006 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 /* Example file for using mhdf interface for reading MOAB native file foramt
17  *
18  * Requires libmhdf from MOAB source and HDF5 library
19  *
20  * Reads:
21  * - all node coordinates
22  * - a single group of hexahedral elements
23  * - GLOBAL_ID tag if present
24  * and writes as Gmsh file version 1.0.
25  *
26  * Does not contain examples for reading meshsets or
27  * reading polygon or polyhedron elements.
28  *
29  * A simple exorcise:
30  * Clean up handling of variable number of dimensions by reading
31  * node coordinate data one dimension at a time using
32  * mhdf_readNodeCoord
33  *
34  * A more complex exorcise:
35  * Read meshsets with MATERIAL_SET tag, which MOAB uses to
36  * represent element blocks, and assign appropriate element
37  * block for each hex in Gmsh file.
38  * Hint: look for and read MATERIAL_SET tag first to get list of entities
39  * then read set contents for sets with that tag
40  * then match hex file ids to lists of set contents
41  * Be careful of the mhdf_SET_RANGE_BIT for each set when reading set
42  * contents.
43  */
44 
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <assert.h>
48 #include <string.h>
49 
50 /* mhdf API */
51 #include "mhdf.h"
52 /* need constants for native types (e.g. H5T_NATIVE_UINT)*/
53 #include <H5Tpublic.h>
54 
55 /* Macro to check return status from mhdf calls. Exit on error. */
56 #define CHK_ERR( A ) \
57  do \
58  { \
59  if( mhdf_isError( A ) ) \
60  { \
61  fprintf( stderr, "Error: %s\n", mhdf_message( A ) ); \
62  exit( 2 ); \
63  } \
64  } while( 0 )
65 
66 int main( int argc, char* argv[] )
67 {
68  /* input file */
69  const char* filename;
70  mhdf_FileHandle file;
71  mhdf_Status status;
72  mhdf_Status* const sptr = &status;
73  hid_t handle; /* generic handle used to refer to any data block in file */
74 
75  /* output file */
76  const char* gmsh_filename;
77  FILE* gmsh;
78  unsigned gmsh_type; /* hexahedral element type number */
79  double x, y, z; /* temp storage of node coordinates */
80  unsigned node_offset, node_id; /* temporary values */
81  unsigned* connectivity; /* temporary value */
82 
83  /* node data */
84  long numnode; /* total number of nodes */
85  long nodestart; /* file id of first node in list */
86  int dimension; /* coordinate values per node */
87  double* nodecoords; /* interleaved node coordinates */
88  unsigned* nodeids; /* GLOBAL_ID value for nodes */
89  int have_nodeids = 0;
90 
91  /* hex data */
92  char* hexgroup = NULL; /* name of element group containing hexes */
93  long numhex; /* total number of hexahedral elements */
94  long hexstart; /* file id of first hex in group */
95  int nodes_per_hex; /* length of connectivity list for a hex */
96  unsigned* hexconnectivity; /* hex connectivity data */
97  unsigned* hexids; /* GLOBAL_ID value for hexes */
98  int have_hexids = 0;
99 
100  /* list of element groups in file */
101  char** elem_groups;
102  unsigned num_elem_groups;
103  char namebuffer[64];
104 
105  /* tag data for accessing GLOBAL_ID */
106  int tagsize; /* number of values for each entity */
107  int ts, td, tg; /* unused tag properties */
108  int havesparse, havedense; /* Boolean values */
109  enum mhdf_TagDataType tagtype; /* base data type of tag */
110  hid_t sparse_handle[2]; /* handle pair for sparse tag data */
111  unsigned* sparse_entities; /* temp storage of sparse tag file ids */
112  unsigned* sparse_ids; /* temp storage of GLOBAL_ID values in spasre tag */
113  long junk, numtag; /* number of entities for which tag data is available */
114  long fileid, globalid; /* temporary values */
115  long ncount = 0, hcount = 0; /* temporary count of number of tag values */
116 
117  /* iteration */
118  long i;
119  int j;
120  unsigned k;
121 
122  /* process CL args (expect input .h5m file and output .gmsh file name) */
123  if( argc != 3 )
124  {
125  fprintf( stderr, "Usage: %s <input_file> <output_file>\n", argv[0] );
126  return 1;
127  }
128  filename = argv[1];
129  gmsh_filename = argv[2];
130 
131  /* Open the file */
132  file = mhdf_openFile( filename, 0, 0, sptr );CHK_ERR( sptr );
133 
134  /* Read node coordinates. */
135  handle = mhdf_openNodeCoords( file, &numnode, &dimension, &nodestart, sptr );CHK_ERR( sptr );
136  nodecoords = (double*)malloc( dimension * numnode * sizeof( double ) );
137  mhdf_readNodeCoords( handle, 0, numnode, nodecoords, sptr );CHK_ERR( sptr );
138  mhdf_closeData( file, handle, sptr );CHK_ERR( sptr );
139 
140  /* Find first element group containing hexahedra */
141  elem_groups = mhdf_getElemHandles( file, &num_elem_groups, sptr );CHK_ERR( sptr );
142  for( k = 0; k < num_elem_groups; ++k )
143  {
144  mhdf_getElemTypeName( file, elem_groups[k], namebuffer, sizeof( namebuffer ), sptr );CHK_ERR( sptr );
145  if( !hexgroup && !strcmp( mdhf_HEX_TYPE_NAME, namebuffer ) )
146  hexgroup = strdup( elem_groups[k] );
147  else
148  printf( "Skipping element group '%s' containing element of type '%s'\n", elem_groups[k], namebuffer );
149  }
150  free( elem_groups );
151 
152  if( !hexgroup )
153  {
154  fprintf( stderr, "No Hexahedra defined in file\n" );
155  return 4;
156  }
157 
158  /* Read Hexahedron connectivity */
159  handle = mhdf_openConnectivity( file, hexgroup, &nodes_per_hex, &numhex, &hexstart, sptr );CHK_ERR( sptr );
160  hexconnectivity = (unsigned*)malloc( numhex * nodes_per_hex * sizeof( unsigned ) );
161  mhdf_readConnectivity( handle, 0, numhex, H5T_NATIVE_UINT, hexconnectivity, sptr );CHK_ERR( sptr );
162  mhdf_closeData( file, handle, sptr );CHK_ERR( sptr );
163  /* Note: hex connectivity list contains file-space node IDs, which are
164  the nodes in the sequence they are read from the file, with
165  the first node having an ID of 'nodestart' */
166 
167  /* Check for "GLOBAL_ID" tag */
168  nodeids = (unsigned*)malloc( numnode * sizeof( unsigned ) );
169  hexids = (unsigned*)malloc( numhex * sizeof( unsigned ) );
170  mhdf_getTagInfo( file, "GLOBAL_ID", &tagtype, &tagsize, &ts, &td, &tg, &havesparse, sptr );
171 
172  /* If have GLOBAL_ID tag, try to read values for nodes and hexes */
173  if( !mhdf_isError( sptr ) )
174  {
175  /* Check that the tag contains what we expect */
176  if( tagtype != mhdf_INTEGER || tagsize != 1 )
177  {
178  fprintf( stderr, "ERROR: Invalid data type for 'GLOBAL_ID' tag.\n" );
179  exit( 3 );
180  }
181 
182  /* Check for and read dense-format tag data for nodes */
183  havedense = mhdf_haveDenseTag( file, "GLOBAL_ID", mhdf_node_type_handle(), sptr );CHK_ERR( sptr );
184  if( havedense )
185  {
186  handle = mhdf_openDenseTagData( file, "GLOBAL_ID", mhdf_node_type_handle(), &numtag, sptr );CHK_ERR( sptr );
187  assert( numtag == numnode );
188  mhdf_readDenseTag( handle, 0, numtag, H5T_NATIVE_UINT, nodeids, sptr );CHK_ERR( sptr );
189  mhdf_closeData( file, handle, sptr );CHK_ERR( sptr );
190  have_nodeids = 1;
191  }
192  /* Check for and read dense-format tag data for hexes */
193  havedense = mhdf_haveDenseTag( file, "GLOBAL_ID", hexgroup, sptr );CHK_ERR( sptr );
194  if( havedense )
195  {
196  handle = mhdf_openDenseTagData( file, "GLOBAL_ID", hexgroup, &numtag, sptr );CHK_ERR( sptr );
197  assert( numtag == numhex );
198  mhdf_readDenseTag( handle, 0, numtag, H5T_NATIVE_UINT, hexids, sptr );CHK_ERR( sptr );
199  mhdf_closeData( file, handle, sptr );CHK_ERR( sptr );
200  have_hexids = 1;
201  }
202  /* Check for and read sparse-format tag data */
203  if( havesparse )
204  {
205  mhdf_openSparseTagData( file, "GLOBAL_ID", &numtag, &junk, sparse_handle, sptr );CHK_ERR( sptr );
206  sparse_entities = (unsigned*)malloc( numtag * sizeof( unsigned ) );
207  mhdf_readSparseTagEntities( sparse_handle[0], 0, numtag, H5T_NATIVE_UINT, sparse_entities, sptr );CHK_ERR( sptr );
208  sparse_ids = (unsigned*)malloc( numtag * sizeof( unsigned ) );
209  mhdf_readSparseTagValues( sparse_handle[1], 0, numtag, H5T_NATIVE_UINT, sparse_ids, sptr );CHK_ERR( sptr );
210  mhdf_closeData( file, sparse_handle[0], sptr );CHK_ERR( sptr );
211  mhdf_closeData( file, sparse_handle[1], sptr );CHK_ERR( sptr );
212 
213  /* Set hex and node ids from sparse tag data */
214  for( i = 0; i < numtag; ++i )
215  {
216  fileid = sparse_entities[i];
217  globalid = sparse_ids[i];
218  if( fileid >= nodestart && fileid - nodestart < numnode )
219  {
220  nodeids[fileid - nodestart] = globalid;
221  ++ncount;
222  }
223  else if( fileid >= hexstart && fileid - hexstart < numhex )
224  {
225  hexids[fileid - hexstart] = globalid;
226  ++hcount;
227  }
228  }
229  free( sparse_ids );
230  free( sparse_entities );
231 
232  /* make sure there was an ID for each node and each hex */
233  if( ncount == numnode ) have_nodeids = 1;
234  if( hcount == numhex ) have_hexids = 1;
235 
236  } /* end have sparse tag for GLOBAL_ID */
237  } /* end have GLOBAL_ID tag */
238 
239  /* done with input file */
240  free( hexgroup );
241  mhdf_closeFile( file, sptr );CHK_ERR( sptr );
242 
243  /* if no GLOBAL_ID, just use incrementing values */
244  if( !have_nodeids )
245  for( i = 0; i < numnode; ++i )
246  nodeids[i] = i + 1;
247  if( !have_hexids )
248  for( i = 0; i < numhex; ++i )
249  hexids[i] = i + 1;
250 
251  /* write out as gmesh file version 1.0 */
252 
253  /* get gmsh type for hexahedrons */
254  if( nodes_per_hex == 8 )
255  gmsh_type = 5;
256  else if( nodes_per_hex == 27 )
257  gmsh_type = 12;
258  else
259  {
260  fprintf( stderr, "Cannot store %d node hex in gmsh file.\n", nodes_per_hex );
261  exit( 4 );
262  }
263 
264  /* open file */
265  gmsh = fopen( gmsh_filename, "w" );
266 
267  /* Write node data. If dimension is less than 3,
268  write zero for other coordinate values. In the
269  (highly unlikely) case that dimension is greater
270  than three, disregard higher-dimension coordinate
271  values. */
272  fprintf( gmsh, "$NOD\n" );
273  fprintf( gmsh, "%lu\n", numnode );
274  for( i = 0; i < numnode; ++i )
275  {
276  x = nodecoords[dimension * i];
277  y = z = 0.0;
278  if( dimension > 1 )
279  {
280  y = nodecoords[dimension * i + 1];
281  if( dimension > 2 )
282  {
283  z = nodecoords[dimension * i + 2];
284  }
285  }
286  fprintf( gmsh, "%u %f %f %f\n", nodeids[i], x, y, z );
287  }
288 
289  /* Write element connectivity data */
290  fprintf( gmsh, "$ENDNOD\n$ELM\n" );
291  fprintf( gmsh, "%lu\n", numhex );
292  for( i = 0; i < numhex; ++i )
293  {
294  fprintf( gmsh, "%u %u 1 1 %d", hexids[i], gmsh_type, nodes_per_hex );
295  /* connectivity list for this hex */
296  connectivity = hexconnectivity + i * nodes_per_hex;
297  for( j = 0; j < nodes_per_hex; ++j )
298  {
299  /* get offset in node list from file id */
300  node_offset = connectivity[j] - nodestart;
301  /* get node id from ID list */
302  node_id = nodeids[node_offset];
303  fprintf( gmsh, " %u", node_id );
304  }
305  fprintf( gmsh, "\n" );
306  }
307  fprintf( gmsh, "$ENDELM\n" );
308  fclose( gmsh );
309  return 0;
310 }