Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ReadCGNS.cpp
Go to the documentation of this file.
1 /**
2  * \class ReadCGNS
3  * \brief Template for writing a new reader in MOAB
4  *
5  */
6 
7 #include "ReadCGNS.hpp"
8 #include "Internals.hpp"
9 #include "moab/Interface.hpp"
10 #include "moab/ReadUtilIface.hpp"
11 #include "moab/Range.hpp"
12 #include "moab/FileOptions.hpp"
13 #include "MBTagConventions.hpp"
14 #include "MBParallelConventions.h"
15 #include "moab/CN.hpp"
16 
17 #include <cstdio>
18 #include <cassert>
19 #include <cerrno>
20 #include <map>
21 #include <set>
22 
23 #include <iostream>
24 #include <cmath>
25 
26 namespace moab
27 {
28 
30 {
31  return new ReadCGNS( iface );
32 }
33 
34 ReadCGNS::ReadCGNS( Interface* impl ) : fileName( NULL ), mesh_dim( 0 ), mbImpl( impl ), globalId( 0 ), boundary( 0 )
35 {
37 }
38 
40 {
41  if( readMeshIface )
42  {
44  readMeshIface = 0;
45  }
46 }
47 
48 ErrorCode ReadCGNS::read_tag_values( const char* /* file_name */,
49  const char* /* tag_name */,
50  const FileOptions& /* opts */,
51  std::vector< int >& /* tag_values_out */,
52  const SubsetList* /* subset_list */ )
53 {
54  return MB_NOT_IMPLEMENTED;
55 }
56 
57 ErrorCode ReadCGNS::load_file( const char* filename,
58  const EntityHandle* /*file_set*/,
59  const FileOptions& opts,
60  const ReaderIface::SubsetList* subset_list,
61  const Tag* file_id_tag )
62 {
63  int num_material_sets = 0;
64  const int* material_set_list = 0;
65 
66  if( subset_list )
67  {
68  if( subset_list->tag_list_length > 1 && !strcmp( subset_list->tag_list[0].tag_name, MATERIAL_SET_TAG_NAME ) )
69  {
70  MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "CGNS supports subset read only by material ID" );
71  }
72  material_set_list = subset_list->tag_list[0].tag_values;
73  num_material_sets = subset_list->tag_list[0].num_tag_values;
74  }
75 
76  ErrorCode result;
77 
78  geomSets.clear();
80 
81  // Create set for more convenient check for material set ids
82  std::set< int > blocks;
83  for( const int* mat_set_end = material_set_list + num_material_sets; material_set_list != mat_set_end;
84  ++material_set_list )
85  blocks.insert( *material_set_list );
86 
87  // Map of ID->handle for nodes
88  std::map< long, EntityHandle > node_id_map;
89 
90  // Save filename to member variable so we don't need to pass as an argument
91  // to called functions
92  fileName = filename;
93 
94  // Process options; see src/FileOptions.hpp for API for FileOptions class, and
95  // doc/metadata_info.doc for a description of various options used by some of the readers in
96  // MOAB
97  result = process_options( opts );
98  MB_CHK_SET_ERR( result, fileName << ": problem reading options" );
99 
100  // Open file
101  int filePtr = 0;
102 
103  cg_open( filename, CG_MODE_READ, &filePtr );
104 
105  if( filePtr <= 0 )
106  {
107  MB_SET_ERR( MB_FILE_DOES_NOT_EXIST, fileName << ": fopen returned error" );
108  }
109 
110  // Read number of verts, elements, sets
111  long num_verts = 0, num_elems = 0, num_sets = 0;
112  int num_bases = 0, num_zones = 0, num_sections = 0;
113 
114  char zoneName[128];
115  cgsize_t size[3];
116 
117  mesh_dim = 3; // Default to 3D
118 
119  // Read number of bases;
120  cg_nbases( filePtr, &num_bases );
121 
122  if( num_bases > 1 )
123  {
124  MB_SET_ERR( MB_NOT_IMPLEMENTED, fileName << ": support for number of bases > 1 not implemented" );
125  }
126 
127  for( int indexBase = 1; indexBase <= num_bases; ++indexBase )
128  {
129  // Get the number of zones/blocks in current base.
130  cg_nzones( filePtr, indexBase, &num_zones );
131 
132  if( num_zones > 1 )
133  {
134  MB_SET_ERR( MB_NOT_IMPLEMENTED, fileName << ": support for number of zones > 1 not implemented" );
135  }
136 
137  for( int indexZone = 1; indexZone <= num_zones; ++indexZone )
138  {
139  // Get zone name and size.
140  cg_zone_read( filePtr, indexBase, indexZone, zoneName, size );
141 
142  // Read number of sections/Parts in current zone.
143  cg_nsections( filePtr, indexBase, indexZone, &num_sections );
144 
145  num_verts = size[0];
146  num_elems = size[1];
147  num_sets = num_sections;
148 
149  std::cout << "\nnumber of nodes = " << num_verts;
150  std::cout << "\nnumber of elems = " << num_elems;
151  std::cout << "\nnumber of parts = " << num_sets << std::endl;
152 
153  // //////////////////////////////////
154  // Read Nodes
155 
156  // Allocate nodes; these are allocated in one shot, get contiguous handles starting with
157  // start_handle, and the reader is passed back double*'s pointing to MOAB's native
158  // storage for vertex coordinates for those verts
159  std::vector< double* > coord_arrays;
160  EntityHandle handle = 0;
161  result = readMeshIface->get_node_coords( 3, num_verts, MB_START_ID, handle, coord_arrays );
162  MB_CHK_SET_ERR( result, fileName << ": Trouble reading vertices" );
163 
164  // Fill in vertex coordinate arrays
165  cgsize_t beginPos = 1, endPos = num_verts;
166 
167  // Read nodes coordinates.
168  cg_coord_read( filePtr, indexBase, indexZone, "CoordinateX", RealDouble, &beginPos, &endPos,
169  coord_arrays[0] );
170  cg_coord_read( filePtr, indexBase, indexZone, "CoordinateY", RealDouble, &beginPos, &endPos,
171  coord_arrays[1] );
172  cg_coord_read( filePtr, indexBase, indexZone, "CoordinateZ", RealDouble, &beginPos, &endPos,
173  coord_arrays[2] );
174 
175  // CGNS seems to always include the Z component, even if the mesh is 2D.
176  // Check if Z is zero and determine mesh dimension.
177  // Also create the node_id_map data.
178  double sumZcoord = 0.0;
179  double eps = 1.0e-12;
180  for( long i = 0; i < num_verts; ++i, ++handle )
181  {
182  int index = i + 1;
183 
184  node_id_map.insert( std::pair< long, EntityHandle >( index, handle ) ).second;
185 
186  sumZcoord += *( coord_arrays[2] + i );
187  }
188  if( std::abs( sumZcoord ) <= eps ) mesh_dim = 2;
189 
190  // Create reverse map from handle to id
191  std::vector< int > ids( num_verts );
192  std::vector< int >::iterator id_iter = ids.begin();
193  std::vector< EntityHandle > handles( num_verts );
194  std::vector< EntityHandle >::iterator h_iter = handles.begin();
195  for( std::map< long, EntityHandle >::iterator i = node_id_map.begin(); i != node_id_map.end();
196  ++i, ++id_iter, ++h_iter )
197  {
198  *id_iter = i->first;
199  *h_iter = i->second;
200  }
201  // Store IDs in tags
202  result = mbImpl->tag_set_data( globalId, &handles[0], num_verts, &ids[0] );
203  if( MB_SUCCESS != result ) return result;
204  if( file_id_tag )
205  {
206  result = mbImpl->tag_set_data( *file_id_tag, &handles[0], num_verts, &ids[0] );
207  if( MB_SUCCESS != result ) return result;
208  }
209  ids.clear();
210  handles.clear();
211 
212  // //////////////////////////////////
213  // Read elements data
214 
215  EntityType ent_type;
216 
217  long section_offset = 0;
218 
219  // Define which mesh parts are volume families.
220  // Mesh parts with volumeID[X] = 0 are boundary parts.
221  std::vector< int > volumeID( num_sections, 0 );
222 
223  for( int section = 0; section < num_sections; ++section )
224  {
225  ElementType_t elemsType;
226  int iparent_flag, nbndry;
227  char sectionName[128];
228  int verts_per_elem;
229 
230  int cgSection = section + 1;
231 
232  cg_section_read( filePtr, indexBase, indexZone, cgSection, sectionName, &elemsType, &beginPos, &endPos,
233  &nbndry, &iparent_flag );
234 
235  size_t section_size = endPos - beginPos + 1;
236 
237  // Read element description in current section
238 
239  switch( elemsType )
240  {
241  case BAR_2:
242  ent_type = MBEDGE;
243  verts_per_elem = 2;
244  break;
245  case TRI_3:
246  ent_type = MBTRI;
247  verts_per_elem = 3;
248  if( mesh_dim == 2 ) volumeID[section] = 1;
249  break;
250  case QUAD_4:
251  ent_type = MBQUAD;
252  verts_per_elem = 4;
253  if( mesh_dim == 2 ) volumeID[section] = 1;
254  break;
255  case TETRA_4:
256  ent_type = MBTET;
257  verts_per_elem = 4;
258  if( mesh_dim == 3 ) volumeID[section] = 1;
259  break;
260  case PYRA_5:
261  ent_type = MBPYRAMID;
262  verts_per_elem = 5;
263  if( mesh_dim == 3 ) volumeID[section] = 1;
264  break;
265  case PENTA_6:
266  ent_type = MBPRISM;
267  verts_per_elem = 6;
268  if( mesh_dim == 3 ) volumeID[section] = 1;
269  break;
270  case HEXA_8:
271  ent_type = MBHEX;
272  verts_per_elem = 8;
273  if( mesh_dim == 3 ) volumeID[section] = 1;
274  break;
275  case MIXED:
276  ent_type = MBMAXTYPE;
277  verts_per_elem = 0;
278  break;
279  default:
280  MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" );
281  }
282 
283  if( elemsType == TETRA_4 || elemsType == PYRA_5 || elemsType == PENTA_6 || elemsType == HEXA_8 ||
284  elemsType == TRI_3 || elemsType == QUAD_4 || ( ( elemsType == BAR_2 ) && mesh_dim == 2 ) )
285  {
286  // Read connectivity into conn_array directly
287 
288  cgsize_t iparentdata;
289  cgsize_t connDataSize;
290 
291  // Get number of entries on the connectivity list for this section
292  cg_ElementDataSize( filePtr, indexBase, indexZone, cgSection, &connDataSize );
293 
294  // Need a temporary vector to later cast to conn_array.
295  std::vector< cgsize_t > elemNodes( connDataSize );
296 
297  cg_elements_read( filePtr, indexBase, indexZone, cgSection, &elemNodes[0], &iparentdata );
298 
299  // //////////////////////////////////
300  // Create elements, sets and tags
301 
302  create_elements( sectionName, file_id_tag, ent_type, verts_per_elem, section_offset, section_size,
303  elemNodes );
304  } // Homogeneous mesh type
305  else if( elemsType == MIXED )
306  {
307  // We must first sort all elements connectivities into continuous vectors
308 
309  cgsize_t connDataSize;
310  cgsize_t iparentdata;
311 
312  cg_ElementDataSize( filePtr, indexBase, indexZone, cgSection, &connDataSize );
313 
314  std::vector< cgsize_t > elemNodes( connDataSize );
315 
316  cg_elements_read( filePtr, indexBase, indexZone, cgSection, &elemNodes[0], &iparentdata );
317 
318  std::vector< cgsize_t > elemsConn_EDGE;
319  std::vector< cgsize_t > elemsConn_TRI, elemsConn_QUAD;
320  std::vector< cgsize_t > elemsConn_TET, elemsConn_PYRA, elemsConn_PRISM, elemsConn_HEX;
321  cgsize_t count_EDGE, count_TRI, count_QUAD;
322  cgsize_t count_TET, count_PYRA, count_PRISM, count_HEX;
323 
324  // First, get elements count for current section
325 
326  count_EDGE = count_TRI = count_QUAD = 0;
327  count_TET = count_PYRA = count_PRISM = count_HEX = 0;
328 
329  int connIndex = 0;
330  for( int i = beginPos; i <= endPos; i++ )
331  {
332  elemsType = ElementType_t( elemNodes[connIndex] );
333 
334  // Get current cell node count.
335  cg_npe( elemsType, &verts_per_elem );
336 
337  switch( elemsType )
338  {
339  case BAR_2:
340  count_EDGE += 1;
341  break;
342  case TRI_3:
343  count_TRI += 1;
344  break;
345  case QUAD_4:
346  count_QUAD += 1;
347  break;
348  case TETRA_4:
349  count_TET += 1;
350  break;
351  case PYRA_5:
352  count_PYRA += 1;
353  break;
354  case PENTA_6:
355  count_PRISM += 1;
356  break;
357  case HEXA_8:
358  count_HEX += 1;
359  break;
360  default:
361  MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" );
362  }
363 
364  connIndex += ( verts_per_elem + 1 ); // Add one to skip next element descriptor
365  }
366 
367  if( count_EDGE > 0 ) elemsConn_EDGE.resize( count_EDGE * 2 );
368  if( count_TRI > 0 ) elemsConn_TRI.resize( count_TRI * 3 );
369  if( count_QUAD > 0 ) elemsConn_QUAD.resize( count_QUAD * 4 );
370  if( count_TET > 0 ) elemsConn_TET.resize( count_TET * 4 );
371  if( count_PYRA > 0 ) elemsConn_PYRA.resize( count_PYRA * 5 );
372  if( count_PRISM > 0 ) elemsConn_PRISM.resize( count_PRISM * 6 );
373  if( count_HEX > 0 ) elemsConn_HEX.resize( count_HEX * 8 );
374 
375  // Grab mixed section elements connectivity
376 
377  int idx_edge, idx_tri, idx_quad;
378  int idx_tet, idx_pyra, idx_prism, idx_hex;
379  idx_edge = idx_tri = idx_quad = 0;
380  idx_tet = idx_pyra = idx_prism = idx_hex = 0;
381 
382  connIndex = 0;
383  for( int i = beginPos; i <= endPos; i++ )
384  {
385  elemsType = ElementType_t( elemNodes[connIndex] );
386 
387  // Get current cell node count.
388  cg_npe( elemsType, &verts_per_elem );
389 
390  switch( elemsType )
391  {
392  case BAR_2:
393  for( int j = 0; j < 2; ++j )
394  elemsConn_EDGE[idx_edge + j] = elemNodes[connIndex + j + 1];
395  idx_edge += 2;
396  break;
397  case TRI_3:
398  for( int j = 0; j < 3; ++j )
399  elemsConn_TRI[idx_tri + j] = elemNodes[connIndex + j + 1];
400  idx_tri += 3;
401  break;
402  case QUAD_4:
403  for( int j = 0; j < 4; ++j )
404  elemsConn_QUAD[idx_quad + j] = elemNodes[connIndex + j + 1];
405  idx_quad += 4;
406  break;
407  case TETRA_4:
408  for( int j = 0; j < 4; ++j )
409  elemsConn_TET[idx_tet + j] = elemNodes[connIndex + j + 1];
410  idx_tet += 4;
411  break;
412  case PYRA_5:
413  for( int j = 0; j < 5; ++j )
414  elemsConn_PYRA[idx_pyra + j] = elemNodes[connIndex + j + 1];
415  idx_pyra += 5;
416  break;
417  case PENTA_6:
418  for( int j = 0; j < 6; ++j )
419  elemsConn_PRISM[idx_prism + j] = elemNodes[connIndex + j + 1];
420  idx_prism += 6;
421  break;
422  case HEXA_8:
423  for( int j = 0; j < 8; ++j )
424  elemsConn_HEX[idx_hex + j] = elemNodes[connIndex + j + 1];
425  idx_hex += 8;
426  break;
427  default:
428  MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, fileName << ": Trouble determining element type" );
429  }
430 
431  connIndex += ( verts_per_elem + 1 ); // Add one to skip next element descriptor
432  }
433 
434  // //////////////////////////////////
435  // Create elements, sets and tags
436 
437  if( count_EDGE > 0 )
438  create_elements( sectionName, file_id_tag, MBEDGE, 2, section_offset, count_EDGE,
439  elemsConn_EDGE );
440 
441  if( count_TRI > 0 )
442  create_elements( sectionName, file_id_tag, MBTRI, 3, section_offset, count_TRI, elemsConn_TRI );
443 
444  if( count_QUAD > 0 )
445  create_elements( sectionName, file_id_tag, MBQUAD, 4, section_offset, count_QUAD,
446  elemsConn_QUAD );
447 
448  if( count_TET > 0 )
449  create_elements( sectionName, file_id_tag, MBTET, 4, section_offset, count_TET, elemsConn_TET );
450 
451  if( count_PYRA > 0 )
452  create_elements( sectionName, file_id_tag, MBPYRAMID, 5, section_offset, count_PYRA,
453  elemsConn_PYRA );
454 
455  if( count_PRISM > 0 )
456  create_elements( sectionName, file_id_tag, MBPRISM, 6, section_offset, count_PRISM,
457  elemsConn_PRISM );
458 
459  if( count_HEX > 0 )
460  create_elements( sectionName, file_id_tag, MBHEX, 8, section_offset, count_HEX, elemsConn_HEX );
461  } // Mixed mesh type
462  } // num_sections
463 
464  cg_close( filePtr );
465 
466  return result;
467  } // indexZone for
468  } // indexBase for
469 
470  return MB_SUCCESS;
471 }
472 
474  const Tag* file_id_tag,
475  const EntityType& ent_type,
476  const int& verts_per_elem,
477  long& section_offset,
478  int elems_count,
479  const std::vector< cgsize_t >& elemsConn )
480 {
481  ErrorCode result;
482 
483  // Create the element sequence; passes back a pointer to the internal storage for connectivity
484  // and the starting entity handle
485  EntityHandle* conn_array;
486  EntityHandle handle = 0;
487 
488  result = readMeshIface->get_element_connect( elems_count, verts_per_elem, ent_type, 1, handle, conn_array );
489  MB_CHK_SET_ERR( result, fileName << ": Trouble reading elements" );
490 
491  if( sizeof( EntityHandle ) == sizeof( cgsize_t ) )
492  {
493  memcpy( conn_array, &elemsConn[0], elemsConn.size() * sizeof( EntityHandle ) );
494  }
495  else
496  { // if CGNS is compiled without 64bit enabled
497  std::vector< EntityHandle > elemsConnTwin( elemsConn.size(), 0 );
498  for( int i = 0; i < elemsConn.size(); i++ )
499  {
500  elemsConnTwin[i] = static_cast< EntityHandle >( elemsConn[i] );
501  }
502  memcpy( conn_array, &elemsConnTwin[0], elemsConnTwin.size() * sizeof( EntityHandle ) );
503  }
504 
505  // Notify MOAB of the new elements
506  result = readMeshIface->update_adjacencies( handle, elems_count, verts_per_elem, conn_array );
507  if( MB_SUCCESS != result ) return result;
508 
509  // //////////////////////////////////
510  // Create sets and tags
511 
512  Range elements( handle, handle + elems_count - 1 );
513 
514  // Store element IDs
515 
516  std::vector< int > id_list( elems_count );
517 
518  // Add 1 to offset id to 1-based numbering
519  for( cgsize_t i = 0; i < elems_count; ++i )
520  id_list[i] = i + 1 + section_offset;
521  section_offset += elems_count;
522 
523  create_sets( sectionName, file_id_tag, ent_type, elements, id_list, 0 );
524 
525  return MB_SUCCESS;
526 }
527 
528 ErrorCode ReadCGNS::create_sets( char* sectionName,
529  const Tag* file_id_tag,
530  EntityType /*element_type*/,
531  const Range& elements,
532  const std::vector< int >& set_ids,
533  int /*set_type*/ )
534 {
535  ErrorCode result;
536 
537  result = mbImpl->tag_set_data( globalId, elements, &set_ids[0] );
538  if( MB_SUCCESS != result ) return result;
539 
540  if( file_id_tag )
541  {
542  result = mbImpl->tag_set_data( *file_id_tag, elements, &set_ids[0] );
543  if( MB_SUCCESS != result ) return result;
544  }
545 
546  EntityHandle set_handle;
547 
548  Tag tag_handle;
549 
550  const char* setName = sectionName;
551 
552  mbImpl->tag_get_handle( setName, 1, MB_TYPE_INTEGER, tag_handle, MB_TAG_SPARSE | MB_TAG_CREAT );
553 
554  // Create set
555  result = mbImpl->create_meshset( MESHSET_SET, set_handle );
556  MB_CHK_SET_ERR( result, fileName << ": Trouble creating set" );
557 
558  //// Add dummy values to current set
559  // std::vector<int> tags(set_ids.size(), 1);
560  // result = mbImpl->tag_set_data(tag_handle, elements, &tags[0]);
561  // if (MB_SUCCESS != result) return result;
562 
563  // Add them to the set
564  result = mbImpl->add_entities( set_handle, elements );
565  MB_CHK_SET_ERR( result, fileName << ": Trouble putting entities in set" );
566 
567  return MB_SUCCESS;
568 }
569 
571 {
572  // Mark all options seen, to avoid compile warning on unused variable
573  opts.mark_all_seen();
574 
575  return MB_SUCCESS;
576 }
577 
578 } // namespace moab