Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
WriteHDF5.hpp
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 2004 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 #ifndef WRITE_HDF5_HPP
17 #define WRITE_HDF5_HPP
18 
19 #include <list>
20 #include "moab/MOABConfig.h"
21 #ifdef MOAB_HAVE_MPI // include this before HDF5 headers to avoid conflicts
22 #include "moab_mpi.h"
23 #endif
24 #include "moab_mpe.h"
25 #include "mhdf.h"
26 #include "moab/Forward.hpp"
27 #include "moab/Range.hpp"
28 #include "moab/WriterIface.hpp"
29 #include "moab/RangeMap.hpp"
30 #include "moab/WriteUtilIface.hpp"
31 #include "DebugOutput.hpp"
32 #include "HDF5Common.hpp"
33 
34 namespace moab
35 {
36 
37 class IODebugTrack;
38 
39 /* If this define is not set, node->entity adjacencies will not be written */
40 #undef MB_H5M_WRITE_NODE_ADJACENCIES
41 
42 /**
43  * \brief Write mesh database to MOAB's native HDF5-based file format.
44  * \author Jason Kraftcheck
45  * \date 01 April 2004
46  */
47 class WriteHDF5 : public WriterIface
48 {
49 
50  public:
51  static WriterIface* factory( Interface* );
52 
54 
55  virtual ~WriteHDF5();
56 
57  /** Export specified meshsets to file
58  * \param filename The filename to export.
59  * \param export_sets Array of handles to sets to export, or NULL to export all.
60  * \param export_set_count Length of <code>export_sets</code> array.
61  */
62  ErrorCode write_file( const char* filename,
63  const bool overwrite,
64  const FileOptions& opts,
65  const EntityHandle* export_sets,
66  const int export_set_count,
67  const std::vector< std::string >& qa_records,
68  const Tag* tag_list = NULL,
69  int num_tags = 0,
70  int user_dimension = 3 );
71 
72  /** The type to use for entity IDs w/in the file.
73  *
74  * NOTE: If this is changed, the value of id_type
75  * MUST be changed accordingly.
76  */
77  typedef EntityHandle wid_t; // change the name,
78  // to avoid conflicts to /usr/include/x86_64-linux-gnu/bits/types.h : id_t , which is unsigned
79  // int
80 
81  /** HDF5 type corresponding to type of wid_t */
82  static const hid_t id_type;
83 
84  struct ExportType
85  {
86  //! The type of the entities in the range
87  EntityType type;
88  //! The number of nodes per entity - not used for nodes and sets
89  int num_nodes;
90 
91  virtual ~ExportType() {}
92 
93  bool operator==( const ExportType& t ) const
94  {
95  return t.type == type && t.num_nodes == num_nodes;
96  }
97  bool operator!=( const ExportType& t ) const
98  {
99  return t.type != type || t.num_nodes != num_nodes;
100  }
101  bool operator<( const ExportType& t ) const
102  {
103  return type < t.type || ( type == t.type && num_nodes < t.num_nodes );
104  }
105  };
106 
107  //! Range of entities, grouped by type, to export
108  struct ExportSet : public ExportType
109  {
110  //! The range of entities.
112  //! The first Id allocated by the mhdf library. Entities in range have sequential IDs.
114  //! The offset at which to begin writing this processor's data.
115  //! Always zero except for parallel IO.
116  long offset;
117  //! Offset for adjacency data. Always zero except for parallel IO
119  //! If doing parallel IO, largest number of entities to write
120  //! for any processor (needed to do collective IO). Zero if unused.
122  //! The total number of entities that will be written to the file
123  //! for this group. For serial IO, this should always be range.size().
124  //! For parallel IO, it will be the sum of range size over all processors.
125  //! For parallel IO, this value is undefined except for on the root
126  //! processor.
128 
129  bool operator<( const ExportType& other ) const
130  {
131  return type < other.type || ( type == other.type && num_nodes < other.num_nodes );
132  }
133 
134  bool operator<( std::pair< int, int > other ) const
135  {
136  return type < other.first || ( type == other.first && num_nodes < other.second );
137  }
138 
139  bool operator==( const ExportType& other ) const
140  {
141  return ( type == other.type && num_nodes == other.num_nodes );
142  }
143 
144  bool operator==( std::pair< int, int > other ) const
145  {
146  return ( type == other.first && num_nodes == other.second );
147  }
148 
149  const char* name() const;
150  };
151 
152  //! Tag to write to file.
153  struct TagDesc
154  {
155  //! The tag handle
157  //! The offset at which to begin writting this processor's data.
158  //! Always zero except for parallel IO.
160  //! For variable-length tags, a second offset for the tag data table,
161  //! separate from the offset used for the ID and Index tables.
162  //! Always zero except for parallel IO.
164  //! Write sparse tag data (for serial, is always equal to !range.empty())
166  //! If doing parallel IO, largest number, over all processes, of entities
167  //! for which to write tag data. Zero if unused.
168  unsigned long max_num_ents;
169  //! For variable-length tags during parallel IO: the largest number
170  //! of tag values to be written on by any process, used to calculate
171  //! the total number of collective writes that all processes must do.
172  //! Zero for fixed-length tags or if not doing parallel IO.
173  unsigned long max_num_vals;
174 
175  //! List of entity groups for which to write tag data in
176  //! dense format
177  std::vector< ExportType > dense_list;
178 
179  bool have_dense( const ExportType& type ) const
180  {
181  return std::find( dense_list.begin(), dense_list.end(), type ) != dense_list.end();
182  }
183 
184  bool operator<( const TagDesc& ) const;
185  };
186 
187  /** Create attributes holding the HDF5 type handle for the
188  * type of a bunch of the default tags.
189  */
190  // static ErrorCode register_known_tag_types( Interface* );
191 
192  //! Store old HDF5 error handling function
194  {
196  void* data;
197  };
198 
200  {
201  return filePtr;
202  }
203 
205  {
206  return writeUtil;
207  }
208 
209  protected:
210  //! Store old HDF5 error handling function
212 
213  /** Function to create the file. Virtual to allow override
214  * for parallel version.
215  */
216  virtual ErrorCode parallel_create_file( const char* filename,
217  bool overwrite,
218  const std::vector< std::string >& qa_records,
219  const FileOptions& opts,
220  const Tag* tag_list,
221  int num_tags,
222  int dimension = 3,
223  double* times = 0 );
224  virtual ErrorCode write_finished();
225  virtual void debug_barrier_line( int lineno );
226 
227  //! Gather tags
228  ErrorCode gather_tags( const Tag* user_tag_list, int user_tag_list_length );
229 
230  /** Check if tag values for a given ExportSet should be written in dense format
231  *
232  *\param ents ExportSet to consider
233  *\param all_tagged Range containing all the entities in ents.range for
234  * which an explicit tag value is stored. Range may
235  * also contain entities not in ents.range, but may
236  * not contain entities in ents.range for which no tag
237  * value is stored.
238  *\param prefer_dense If true, will return true if at least 2/3 of the
239  * entities are tagged. This should not be passed as
240  * true if the tag does not have a default value, as
241  * tag values must be stored for all entities in the
242  * ExportSet for dense-formatted data.
243  */
244  bool check_dense_format_tag( const ExportSet& ents, const Range& all_tagged, bool prefer_dense );
245 
246  /** Helper function for create-file
247  *
248  * Calculate the sum of the number of non-set adjacencies
249  * of all entities in the passed range.
250  */
251  ErrorCode count_adjacencies( const Range& elements, wid_t& result );
252 
253  public: // make these public so helper classes in WriteHDF5Parallel can use them
254  /** Helper function for create-file
255  *
256  * Create zero-ed tables where element connectivity and
257  * adjacency data will be stored.
258  */
259  ErrorCode create_elem_table( const ExportSet& block, long num_ents, long& first_id_out );
260 
261  /** Helper function for create-file
262  *
263  * Create zero-ed table where set descriptions will be written
264  */
265  ErrorCode create_set_meta( long num_sets, long& first_id_out );
266 
267  protected:
268  /** Helper function for create-file
269  *
270  * Calculate total length of set contents and child tables.
271  */
272  ErrorCode count_set_size( const Range& sets,
273  long& contents_length_out,
274  long& children_length_out,
275  long& parents_length_out );
276 
277  //! Get information about a meshset
279  long& num_entities,
280  long& num_children,
281  long& num_parents,
282  unsigned long& flags );
283 
284  /** Helper function for create-file
285  *
286  * Create zero-ed tables where set data will be written.
287  */
288  ErrorCode create_set_tables( long contents_length, long children_length, long parents_length );
289 
290  //! Write exodus-type QA info
291  ErrorCode write_qa( const std::vector< std::string >& list );
292 
293  //!\brief Get tagged entities for which to write tag values
294  ErrorCode get_num_sparse_tagged_entities( const TagDesc& tag, size_t& count );
295  //!\brief Get tagged entities for which to write tag values
296  ErrorCode get_sparse_tagged_entities( const TagDesc& tag, Range& range );
297  //!\brief Get entities that will be written to file
298  void get_write_entities( Range& range );
299 
300  //! The size of the data buffer (<code>dataBuffer</code>).
301  size_t bufferSize;
302  //! A memory buffer to use for all I/O operations.
303  char* dataBuffer;
304 
305  //! Interface pointer passed to constructor
307  //! Cached pointer to writeUtil interface.
309 
310  //! The file handle from the mhdf library
312 
313  //! Map from entity handles to file IDs
315 
316  //! The list elements to export.
317  std::list< ExportSet > exportList;
318  //! The list of nodes to export
320  //! The list of sets to export
322 
323  const ExportSet* find( const ExportType& type ) const
324  {
325  if( type.type == MBVERTEX )
326  return &nodeSet;
327  else if( type.type == MBENTITYSET )
328  return &setSet;
329  else
330  {
331  std::list< ExportSet >::const_iterator it;
332  it = std::find( exportList.begin(), exportList.end(), type );
333  return it == exportList.end() ? 0 : &*it;
334  }
335  }
336 
337  //! Offset into set contents table (zero except for parallel)
338  unsigned long setContentsOffset;
339  //! Offset into set children table (zero except for parallel)
341  //! The largest number of values to write
342  //! for any processor (needed to do collective IO).
344  //! Flags idicating if set data should be written.
345  //! For the normal (non-parallel) case, these values
346  //! will depend only on whether or not there is any
347  //! data to be written. For parallel-meshes, opening
348  //! the data table is collective so the values must
349  //! depend on whether or not any processor has meshsets
350  //! to be written.
352 
353  //! Struct describing a set for which the contained and linked entity
354  //! lists are something other than the local values. Used to store
355  //! data for shared sets owned by this process when writing in parallel.
357  {
359  unsigned setFlags;
360  std::vector< wid_t > contentIds;
361  std::vector< wid_t > childIds;
362  std::vector< wid_t > parentIds;
363  };
364  struct SpecSetLess
365  {
366  bool operator()( const SpecialSetData& a, SpecialSetData b ) const
367  {
368  return a.setHandle < b.setHandle;
369  }
370  };
371 
372  //! Array of special/shared sets, in order of handle value.
373  std::vector< SpecialSetData > specialSets;
375  {
376  return const_cast< WriteHDF5* >( this )->find_set_data( h );
377  }
378  SpecialSetData* find_set_data( EntityHandle h );
379 
380  //! The list of tags to export
381  std::list< TagDesc > tagList;
382 
383  //! True if doing parallel write
385  //! True if using collective IO calls for parallel write
387  //! True if writing dense-formatted tag data
389 
390  //! Property set to pass to H5Dwrite calls.
391  //! For serial, should be H5P_DEFAULTS.
392  //! For parallel, may request collective IO.
393  hid_t writeProp;
394 
395  //! Utility to log debug output
397 
398  static MPEState topState;
399  static MPEState subState;
400 
401  //! Look for overlapping and/or missing writes
403 
404  void print_id_map() const;
405  void print_id_map( std::ostream& str, const char* prefix = "" ) const;
406 
407  /** Helper function for create-file
408  *
409  * Write tag meta-info and create zero-ed table where
410  * tag values will be written.
411  *\param num_entities Number of entities for which to write tag data.
412  *\param var_len_total For variable-length tags, the total number of values
413  * in the data table.
414  */
415  ErrorCode create_tag( const TagDesc& tag_data, unsigned long num_entities, unsigned long var_len_total );
416 
417  /**\brief add entities to idMap */
418  ErrorCode assign_ids( const Range& entities, wid_t first_id );
419 
420  /** Get possibly compacted list of IDs for passed entities
421  *
422  * For the passed range of entities, determine if IDs
423  * can be compacted and write IDs to passed list.
424  *
425  * If the IDs are not compacted, the output list will contain
426  * a simple ordered list of IDs.
427  *
428  * If IDs are compacted, the output list will contain
429  * {start,count} pairs.
430  *
431  * If the ID list is compacted, ranged_list will be 'true'.
432  * Otherwise it will be 'false'.
433  */
434  ErrorCode range_to_blocked_list( const Range& input_range,
435  std::vector< wid_t >& output_id_list,
436  bool& ranged_list );
437 
438  /** Get possibly compacted list of IDs for passed entities
439  *
440  * For the passed range of entities, determine if IDs
441  * can be compacted and write IDs to passed list.
442  *
443  * If the IDs are not compacted, the output list will contain
444  * a simple ordered list of IDs.
445  *
446  * If IDs are compacted, the output list will contain
447  * {start,count} pairs.
448  *
449  * If the ID list is compacted, ranged_list will be 'true'.
450  * Otherwise it will be 'false'.
451  */
452  ErrorCode range_to_blocked_list( const EntityHandle* input_ranges,
453  size_t num_input_ranges,
454  std::vector< wid_t >& output_id_list,
455  bool& ranged_list );
456 
457  ErrorCode range_to_id_list( const Range& input_range, wid_t* array );
458  //! Get IDs for entities
459  ErrorCode vector_to_id_list( const std::vector< EntityHandle >& input,
460  std::vector< wid_t >& output,
461  bool remove_non_written = false );
462  //! Get IDs for entities
463  ErrorCode vector_to_id_list( const EntityHandle* input, wid_t* output, size_t num_entities );
464  //! Get IDs for entities
466  size_t input_len,
467  wid_t* output,
468  size_t& output_len,
469  bool remove_non_written );
470 
471  /** When writing tags containing EntityHandles to file, need to convert tag
472  * data from EntityHandles to file IDs. This function does that.
473  *
474  * If the handle is not valid or does not correspond to an entity that will
475  * be written to the file, the file ID is set to zero.
476  *\param data The data buffer. As input, an array of EntityHandles. As
477  * output an array of file IDS, where the size of each integral
478  * file ID is the same as the size of EntityHandle.
479  *\param count The number of handles in the buffer.
480  *\return true if at least one of the handles is valid and will be written to
481  * the file or at least one of the handles is NULL (zero). false
482  * otherwise
483  */
484  bool convert_handle_tag( EntityHandle* data, size_t count ) const;
485  bool convert_handle_tag( const EntityHandle* source, EntityHandle* dest, size_t count ) const;
486 
487  /** Get IDs of adjacent entities.
488  *
489  * For all entities adjacent to the passed entity, if the
490  * adjacent entity is to be exported (ID is not zero), append
491  * the ID to the passed list.
492  */
493  ErrorCode get_adjacencies( EntityHandle entity, std::vector< wid_t >& adj );
494 
495  //! get sum of lengths of tag values (as number of type) for
496  //! variable length tag data.
497  ErrorCode get_tag_data_length( const TagDesc& tag_info, const Range& range, unsigned long& result );
498 
499  private:
500  //! Do the actual work of write_file. Separated from write_file
501  //! for easier resource cleanup.
502  ErrorCode write_file_impl( const char* filename,
503  const bool overwrite,
504  const FileOptions& opts,
505  const EntityHandle* export_sets,
506  const int export_set_count,
507  const std::vector< std::string >& qa_records,
508  const Tag* tag_list,
509  int num_tags,
510  int user_dimension = 3 );
511 
512  ErrorCode init();
513 
514  ErrorCode serial_create_file( const char* filename,
515  bool overwrite,
516  const std::vector< std::string >& qa_records,
517  const Tag* tag_list,
518  int num_tags,
519  int dimension = 3 );
520 
521  /** Get all mesh to export from given list of sets.
522  *
523  * Populate exportSets, nodeSet and setSet with lists of
524  * entities to write.
525  *
526  * \param export_sets The list of meshsets to export
527  */
528  ErrorCode gather_mesh_info( const std::vector< EntityHandle >& export_sets );
529 
530  //! Same as gather_mesh_info, except for entire mesh
532 
533  //! Initialize internal data structures from gathered mesh
534  ErrorCode initialize_mesh( const Range entities_by_dim[5] );
535 
536  /** Write out the nodes.
537  *
538  * Note: Assigns IDs to nodes.
539  */
541 
542  /** Write out element connectivity.
543  *
544  * Write connectivity for passed set of elements.
545  *
546  * Note: Assigns element IDs.
547  * Note: Must do write_nodes first so node IDs get assigned.
548  */
549  ErrorCode write_elems( ExportSet& elemset );
550 
551  /** Write out meshsets
552  *
553  * Write passed set of meshsets, including parent/child relations.
554  *
555  * Note: Must have written nodes and element connectivity
556  * so entities have assigned IDs.
557  */
558  ErrorCode write_sets( double* times );
559 
560  /** Write set contents/parents/children lists
561  *
562  *\param which_data Which set data to write (contents, parents, or children)
563  *\param handle HDF5 handle for data set in which to write data
564  *\param track Debugging tool
565  *\param ranged Will be populated with handles of sets for which
566  * contents were written in a range-compacted format.
567  * (mhdf_SET_RANGE_BIT). Should be null for parents/children.
568  *\param null_stripped Will be populated with handles of sets for which
569  * invalid or null handles were stripped from the contents
570  * list. This is only done for unordered sets. This argument
571  * should be null if writing parents/children because those
572  * lists are always ordered.
573  *\param set_sizes Will be populated with the length of the data written
574  * for those sets for which the handles were added to
575  * either \c ranged or \c null_stripped. Values are
576  * in handle order.
577  */
579  const hid_t handle,
580  IODebugTrack& track,
581  Range* ranged = 0,
582  Range* null_stripped = 0,
583  std::vector< long >* set_sizes = 0 );
584 
585  /** Write adjacency info for passed set of elements
586  *
587  * Note: Must have written element connectivity so elements
588  * have IDs assigned.
589  */
590  ErrorCode write_adjacencies( const ExportSet& export_set );
591 
592  /** Write tag information and data.
593  *
594  * Note: Must have already written nodes, elem connectivity and
595  * sets so that entities have IDs assigned.
596  */
597 
598  //! Write tag for all entities.
599  ErrorCode write_tag( const TagDesc& tag_data, double* times );
600 
601  //! Get element connectivity
604  int nodes_per_element,
605  wid_t* id_data_out );
606 
607  //! Get size data for tag
608  //!\param tag MOAB tag ID
609  //!\param moab_type Output: DataType for tag
610  //!\param num_bytes Output: MOAB tag size (bits for bit tags).
611  //! MB_VARIABLE_LENGTH for variable-length tags.
612  //!\param elem_size Output: Size of of the base data type of the
613  //! tag data (e.g. sizeof(double) if
614  //! moab_type == MB_TYPE_DOUBLE).
615  //! One for bit and opaque tags.
616  //!\param array_size Output: The number of valeus of size elem_size
617  //! for each tag. Always 1 for opaque data.
618  //! Nubmer of bits for bit tags.
619  //!\param file_type Output: mhdf type enumeration
620  //!\param hdf_type Output: Handle to HDF5 type object. Caller is
621  //! responsible for releasing this object
622  //! (calling H5Tclose).
624  DataType& moab_type,
625  int& num_bytes,
626  int& elem_size,
627  int& file_size,
628  mhdf_TagDataType& file_type,
629  hid_t& hdf_type );
630 
631  //! Write ID table for sparse tag
632  ErrorCode write_sparse_ids( const TagDesc& tag_data,
633  const Range& range,
634  hid_t table_handle,
635  size_t table_size,
636  const char* name = 0 );
637 
638  //! Write fixed-length tag data in sparse format
639  ErrorCode write_sparse_tag( const TagDesc& tag_data,
640  const std::string& tag_name,
641  DataType tag_data_type,
642  hid_t hdf5_data_type,
643  int hdf5_type_size );
644 
645  //! Write end index data_set for a variable-length tag
646  ErrorCode write_var_len_indices( const TagDesc& tag_data,
647  const Range& range,
648  hid_t idx_table,
649  size_t table_size,
650  int type_size,
651  const char* name = 0 );
652 
653  //! Write tag value data_set for a variable-length tag
654  ErrorCode write_var_len_data( const TagDesc& tag_data,
655  const Range& range,
656  hid_t table,
657  size_t table_size,
658  bool handle_tag,
659  hid_t hdf_type,
660  int type_size,
661  const char* name = 0 );
662 
663  //! Write varialbe-length tag data
664  ErrorCode write_var_len_tag( const TagDesc& tag_info,
665  const std::string& tag_name,
666  DataType tag_data_type,
667  hid_t hdf5_type,
668  int hdf5_type_size );
669 
670  //! Write dense-formatted tag data
671  ErrorCode write_dense_tag( const TagDesc& tag_data,
672  const ExportSet& elem_data,
673  const std::string& tag_name,
674  DataType tag_data_type,
675  hid_t hdf5_data_type,
676  int hdf5_type_size );
677 
678  //! Write data for fixed-size tag
680  hid_t data_table,
681  unsigned long data_offset,
682  const Range& range,
683  DataType tag_data_type,
684  hid_t hdf5_data_type,
685  int hdf5_type_size,
686  unsigned long max_num_ents,
687  IODebugTrack& debug_track );
688 
689  protected:
691  {
717  NUM_TIMES
718  };
719 
720  virtual void print_times( const double times[NUM_TIMES] ) const;
721 };
722 
723 } // namespace moab
724 
725 #endif