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
53 WriteHDF5( Interface* iface );
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.
111 Range range;
112 //! The first Id allocated by the mhdf library. Entities in range have sequential IDs.
113 wid_t first_id;
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
118 long adj_offset;
119 //! If doing parallel IO, largest number of entities to write
120 //! for any processor (needed to do collective IO). Zero if unused.
121 long max_num_ents, max_num_adjs;
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.
127 long total_num_ents;
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
156 Tag tag_id;
157 //! The offset at which to begin writting this processor's data.
158 //! Always zero except for parallel IO.
159 wid_t sparse_offset;
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.
163 wid_t var_data_offset;
164 //! Write sparse tag data (for serial, is always equal to !range.empty())
165 bool write_sparse;
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
193 struct HDF5ErrorHandler
194 {
195 HDF5_Error_Func_Type func;
196 void* data;
197 };
198
199 mhdf_FileHandle file_ptr()
200 {
201 return filePtr;
202 }
203
204 WriteUtilIface* write_util()
205 {
206 return writeUtil;
207 }
208
209 protected:
210 //! Store old HDF5 error handling function
211 HDF5ErrorHandler errorHandler;
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
278 ErrorCode get_set_info( EntityHandle set,
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
306 Interface* iFace;
307 //! Cached pointer to writeUtil interface.
308 WriteUtilIface* writeUtil;
309
310 //! The file handle from the mhdf library
311 mhdf_FileHandle filePtr;
312
313 //! Map from entity handles to file IDs
314 RangeMap< EntityHandle, wid_t > idMap;
315
316 //! The list elements to export.
317 std::list< ExportSet > exportList;
318 //! The list of nodes to export
319 ExportSet nodeSet;
320 //! The list of sets to export
321 ExportSet setSet;
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)
340 unsigned long setChildrenOffset, setParentsOffset;
341 //! The largest number of values to write
342 //! for any processor (needed to do collective IO).
343 long maxNumSetContents, maxNumSetChildren, maxNumSetParents;
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.
351 bool writeSets, writeSetContents, writeSetChildren, writeSetParents;
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.
356 struct SpecialSetData
357 {
358 EntityHandle setHandle;
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;
374 const SpecialSetData* find_set_data( EntityHandle h ) const
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
384 bool parallelWrite;
385 //! True if using collective IO calls for parallel write
386 bool collectiveIO;
387 //! True if writing dense-formatted tag data
388 bool writeTagDense;
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
396 DebugOutput dbgOut;
397
398 static MPEState topState;
399 static MPEState subState;
400
401 //! Look for overlapping and/or missing writes
402 bool debugTrack;
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
465 ErrorCode vector_to_id_list( const EntityHandle* input,
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
531 ErrorCode gather_all_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 */
540 ErrorCode write_nodes();
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 */
578 ErrorCode write_set_data( const WriteUtilIface::EntityListType which_data,
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
602 ErrorCode get_connectivity( Range::const_iterator begin,
603 Range::const_iterator end,
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).
623 ErrorCode get_tag_size( Tag tag,
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
679 ErrorCode write_tag_values( Tag tag_id,
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:
690 enum TimingValues
691 {
692 TOTAL_TIME = 0,
693 GATHER_TIME,
694 CREATE_TIME,
695 CREATE_NODE_TIME,
696 NEGOTIATE_TYPES_TIME,
697 CREATE_ELEM_TIME,
698 FILEID_EXCHANGE_TIME,
699 CREATE_ADJ_TIME,
700 CREATE_SET_TIME,
701 SHARED_SET_IDS,
702 SHARED_SET_CONTENTS,
703 SET_OFFSET_TIME,
704 CREATE_TAG_TIME,
705 COORD_TIME,
706 CONN_TIME,
707 SET_TIME,
708 SET_META,
709 SET_CONTENT,
710 SET_PARENT,
711 SET_CHILD,
712 ADJ_TIME,
713 TAG_TIME,
714 DENSE_TAG_TIME,
715 SPARSE_TAG_TIME,
716 VARLEN_TAG_TIME,
717 NUM_TIMES
718 };
719
720 virtual void print_times( const double times[NUM_TIMES] ) const;
721 };
722
723 } // namespace moab
724
725 #endif