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 READ_HDF5_HPP
17 #define READ_HDF5_HPP
18
19 #include <cstdlib>
20 #include <list>
21 #include "mhdf.h"
22 #include "moab/Forward.hpp"
23 #include "moab/ReadUtilIface.hpp"
24 #include "moab/Range.hpp"
25 #include "moab/ReaderIface.hpp"
26 #include "moab/RangeMap.hpp"
27 #include "DebugOutput.hpp"
28 #include "HDF5Common.hpp"
29
30 #ifdef MOAB_HAVE_MPI
31 #include <moab_mpi.h>
32 #endif
33
34 namespace moab
35 {
36
37 class ParallelComm;
38 class ReadHDF5Dataset;
39 class CpuTimer;
40
41 /**
42 * \brief Read mesh from MOAB HDF5 (.h5m) file.
43 * \author Jason Kraftcheck
44 * \date 18 April 2004
45 */
46 class ReadHDF5 : public ReaderIface
47 {
48 public:
49 #ifdef MOAB_HAVE_MPI
50 typedef MPI_Comm Comm;
51 #else
52 typedef int Comm;
53 #endif
54
55 static ReaderIface* factory( Interface* );
56
57 ReadHDF5( Interface* iface );
58
59 virtual ~ReadHDF5();
60
61 /** Export specified meshsets to file
62 * \param filename The filename to export. Must end in <em>.mhdf</em>
63 * \param export_sets Array of handles to sets to export, or NULL to export all.
64 * \param export_set_count Length of <code>export_sets</code> array.
65 */
66 ErrorCode load_file( const char* file_name,
67 const EntityHandle* file_set,
68 const FileOptions& opts,
69 const SubsetList* subset_list = 0,
70 const Tag* file_id_tag = 0 );
71
72 ErrorCode read_tag_values( const char* file_name,
73 const char* tag_name,
74 const FileOptions& opts,
75 std::vector< int >& tag_values_out,
76 const SubsetList* subset_list = 0 );
77 Interface* moab() const
78 {
79 return iFace;
80 }
81
82 //! Store old HDF5 error handling function
83 struct HDF5ErrorHandler
84 {
85 HDF5_Error_Func_Type func;
86 void* data;
87 };
88
89 protected:
90 ErrorCode load_file_impl( const FileOptions& opts );
91
92 ErrorCode load_file_partial( const ReaderIface::IDTag* subset_list,
93 int subset_list_length,
94 int num_parts,
95 int part_number,
96 const FileOptions& opts );
97
98 ErrorCode read_tag_values_all( int tag_index, std::vector< int >& results );
99 ErrorCode read_tag_values_partial( int tag_index, const Range& file_ids, std::vector< int >& results );
100
101 enum ReadTimingValues
102 {
103 TOTAL_TIME = 0,
104 SET_META_TIME,
105 SUBSET_IDS_TIME,
106 GET_PARTITION_TIME,
107 GET_SET_IDS_TIME,
108 GET_SET_CONTENTS_TIME,
109 GET_POLYHEDRA_TIME,
110 GET_ELEMENTS_TIME,
111 GET_NODES_TIME,
112 GET_NODEADJ_TIME,
113 GET_SIDEELEM_TIME,
114 UPDATECONN_TIME,
115 ADJACENCY_TIME,
116 DELETE_NON_SIDEELEM_TIME,
117 READ_SET_IDS_RECURS_TIME,
118 FIND_SETS_CONTAINING_TIME,
119 READ_SETS_TIME,
120 READ_TAGS_TIME,
121 STORE_FILE_IDS_TIME,
122 READ_QA_TIME,
123 NUM_TIMES
124 };
125
126 void print_times();
127
128 private:
129 ErrorCode init();
130
131 inline int is_error( mhdf_Status& status )
132 {
133 int i;
134 if( ( i = mhdf_isError( &status ) ) ) MB_SET_ERR_CONT( mhdf_message( &status ) );
135 return i;
136 }
137
138 //! The size of the data buffer (<code>dataBuffer</code>).
139 int bufferSize;
140 //! A memory buffer to use for all I/O operations.
141 char* dataBuffer;
142
143 //! Interface pointer passed to constructor
144 Interface* iFace;
145
146 //! The file handle from the mhdf library
147 mhdf_FileHandle filePtr;
148
149 //! File summary
150 mhdf_FileDesc* fileInfo;
151
152 //! Map from File ID to MOAB handle
153 typedef RangeMap< long, EntityHandle > IDMap;
154 IDMap idMap;
155
156 //! Cache pointer to read util
157 ReadUtilIface* readUtil;
158
159 //! The type of an EntityHandle
160 hid_t handleType;
161
162 //! List of connectivity arrays for which conversion from file ID
163 //! to handle was deferred until later.
164 struct IDConnectivity
165 {
166 EntityHandle handle; // Start_handle
167 size_t count; // Num entities
168 int nodes_per_elem; // Per-element connectivity length
169 EntityHandle* array; // Connectivity array
170 };
171 //! List of connectivity arrays for which conversion from file ID
172 //! to handle was deferred until later.
173 std::vector< IDConnectivity > idConnectivityList;
174
175 //! Read/write property handle
176 //! indepIO -> independent IO during true parallel read
177 //! collIO -> collective IO during true parallel read
178 //! Both are H5P_DEFAULT for serial IO and collective
179 //! when reading the entire file on all processors.
180 hid_t indepIO, collIO;
181
182 ParallelComm* myPcomm;
183
184 //! Use IODebugTrack instances to verify reads.
185 //! Enable with the DEBUG_OVERLAPS option.
186 bool debugTrack;
187 //! Debug output. Verbosity controlled with DEBUG_FORMAT option.
188 DebugOutput dbgOut;
189 //! Doing true parallel read (PARALLEL=READ_PART)
190 bool nativeParallel;
191 //! MPI_Comm value (unused if \c !nativeParallel)
192 Comm* mpiComm;
193
194 //! Flags for some behavior that can be changed through
195 //! reader options
196 bool blockedCoordinateIO;
197 bool bcastSummary;
198 bool bcastDuplicateReads;
199
200 //! Store old HDF5 error handling function
201 HDF5ErrorHandler errorHandler;
202
203 long ( *setMeta )[4];
204
205 double _times[NUM_TIMES];
206 CpuTimer* timer;
207 bool cputime;
208 ErrorCode read_all_set_meta();
209
210 ErrorCode set_up_read( const char* file_name, const FileOptions& opts );
211 ErrorCode clean_up_read( const FileOptions& opts );
212
213 //! Given a list of tags and values, get the file ids for the
214 //! corresponding entities in the file.
215 ErrorCode get_subset_ids( const ReaderIface::IDTag* subset_list, int subset_list_length, Range& file_ids_out );
216
217 /**\brief Remove all but the specified fraction of sets from the passed range
218 *
219 * Select a subset of the gathered set of file ids to read in based on
220 * communicator size and rank.
221 *\param tmp_file_ids As input: sets to be read on all procs.
222 * As output: sets to read on this proc.
223 *\param num_parts communicator size
224 *\param part_number communicator rank
225 */
226 ErrorCode get_partition( Range& tmp_file_ids, int num_parts, int part_number );
227
228 ErrorCode read_nodes( const Range& node_file_ids );
229
230 // Read elements in fileInfo->elems[index]
231 ErrorCode read_elems( int index );
232
233 // Read subset of elements in fileInfo->elems[index]
234 ErrorCode read_elems( int index, const Range& file_ids, Range* node_ids = 0 );
235
236 //! Read element connectivity.
237 //!
238 //!\param node_ids If this is non-null, the union of the connectivity list
239 //! for all elements is passed back as FILE IDS in this
240 //! range AND the connectivity list is left in the form
241 //! of file IDs (NOT NODE HANDLES).
242 ErrorCode read_elems( const mhdf_ElemDesc& elems, const Range& file_ids, Range* node_ids = 0 );
243
244 //! Update connectivity data for all element groups for which read_elems
245 //! was called with a non-null \c node_ids argument.
246 ErrorCode update_connectivity();
247
248 // Read connectivity data for a list of element file ids.
249 // passing back the file IDs for the element connectivity
250 // w/out actually creating any elements in MOAB.
251 ErrorCode read_elems( int index, const Range& element_file_ids, Range& node_file_ids );
252
253 // Scan all elements in group. For each element for which all vertices
254 // are contained in idMap (class member), read the element. All new
255 // elements are added to idMap.
256 //
257 // NOTE: Collective IO calls in parallel.
258 ErrorCode read_node_adj_elems( const mhdf_ElemDesc& group, Range* read_entities = 0 );
259
260 // Scan all elements in specified file table. For each element for
261 // which all vertices are contained in idMap (class member), read the
262 // element. All new elements are added to idMap.
263 //
264 // NOTE: Collective IO calls in parallel.
265 ErrorCode read_node_adj_elems( const mhdf_ElemDesc& group, hid_t connectivity_handle, Range* read_entities = 0 );
266
267 //! Read poly(gons|hedra)
268 ErrorCode read_poly( const mhdf_ElemDesc& elems, const Range& file_ids );
269
270 //! Clean up elements that were a) read because we had read all of the
271 //! nodes and b) weren't actually sides of the top-dimension elements
272 //! we were trying to read.
273 ErrorCode delete_non_side_elements( const Range& side_ents );
274
275 //! Read sets
276 ErrorCode read_sets( const Range& set_file_ids );
277
278 ErrorCode read_adjacencies( hid_t adjacency_table, long table_length );
279
280 //! Create tag and read all data.
281 ErrorCode read_tag( int index );
282
283 //! Create new tag or verify type matches existing tag
284 ErrorCode create_tag( const mhdf_TagDesc& info, Tag& handle, hid_t& type );
285
286 //! Read dense tag for all entities
287 ErrorCode read_dense_tag( Tag tag_handle,
288 const char* ent_name,
289 hid_t hdf_read_type,
290 hid_t data_table,
291 long start_id,
292 long count );
293
294 //! Read sparse tag for all entities.
295 ErrorCode read_sparse_tag( Tag tag_handle,
296 hid_t hdf_read_type,
297 hid_t ent_table,
298 hid_t val_table,
299 long num_entities );
300
301 //! Read variable-length tag for all entities.
302 ErrorCode read_var_len_tag( Tag tag_handle,
303 hid_t hdf_read_type,
304 hid_t ent_table,
305 hid_t val_table,
306 hid_t off_table,
307 long num_entities,
308 long num_values );
309
310 /**\brief Read index table for sparse tag.
311 *
312 * Read ID table for a sparse or variable-length tag, returning
313 * the handles and offsets within the table for each file ID
314 * that corresponds to an entity we've read from the file (an
315 * entity that is in \c idMap).
316 *
317 * \param id_table The MOAB handle for the tag
318 * \param start_offset Some non-zero value because ranges (in this case
319 * the offset_range) cannot contain zeros.
320 * \param offset_range Output: The offsets in the id table for which IDs
321 * that occur in \c idMap were found. All values
322 * are increased by \c start_offset to avoid
323 * putting zeros in the range.
324 * \param handle_range Output: For each valid ID read from the table,
325 * the corresponding entity handle. Note: if
326 * the IDs did not occur in handle order, then
327 * this will be empty. Use \c handle_vect instead.
328 * \param handle_vect Output: For each valid ID read from the table,
329 * the corresponding entity handle. Note: if
330 * the IDs occurred in handle order, then
331 * this will be empty. Use \c handle_range instead.
332 */
333 ErrorCode read_sparse_tag_indices( const char* name,
334 hid_t id_table,
335 EntityHandle start_offset,
336 Range& offset_range,
337 Range& handle_range,
338 std::vector< EntityHandle >& handle_vect );
339
340 ErrorCode read_qa( EntityHandle file_set );
341
342 public:
343 ErrorCode convert_id_to_handle( EntityHandle* in_out_array, size_t array_length );
344
345 void convert_id_to_handle( EntityHandle* in_out_array, size_t array_length, size_t& array_length_out ) const
346 {
347 return convert_id_to_handle( in_out_array, array_length, array_length_out, idMap );
348 }
349
350 ErrorCode convert_range_to_handle( const EntityHandle* ranges, size_t num_ranges, Range& merge );
351
352 static void convert_id_to_handle( EntityHandle* in_out_array,
353 size_t array_length,
354 const RangeMap< long, EntityHandle >& id_map );
355
356 static void convert_id_to_handle( EntityHandle* in_out_array,
357 size_t array_length,
358 size_t& array_length_out,
359 const RangeMap< long, EntityHandle >& id_map );
360
361 static void convert_range_to_handle( const EntityHandle* ranges,
362 size_t num_ranges,
363 const RangeMap< long, EntityHandle >& id_map,
364 Range& merge );
365
366 ErrorCode insert_in_id_map( const Range& file_ids, EntityHandle start_id );
367
368 ErrorCode insert_in_id_map( long file_id, EntityHandle handle );
369
370 private:
371 /**\brief Search for entities with specified tag values
372 *
373 *\NOTE For parallel reads, this function does collective IO.
374 *
375 *\param tag_index Index into info->tags specifying which tag to search.
376 *\param sorted_values List of tag values to check for, in ascending sorted
377 * order.
378 *\param file_ids_out File IDs for entities with specified tag values.
379 */
380 ErrorCode search_tag_values( int tag_index,
381 const std::vector< int >& sorted_values,
382 Range& file_ids_out,
383 bool sets_only = false );
384
385 /**\brief Search for entities with specified tag
386 *
387 *\NOTE For parallel reads, this function does collective IO.
388 *
389 *\param tag_index Index into info->tags specifying which tag to search.
390 *\param file_ids_out File IDs for entities with specified tag values.
391 */
392 ErrorCode get_tagged_entities( int tag_index, Range& file_ids_out );
393
394 /**\brief Search a table of tag data for a specified set of values.
395 *
396 * Search a table of tag values, returning the indices into the table
397 * at which matches were found.
398 *\NOTE For parallel reads, this function does collective IO.
399 *
400 *\param info Summary of data contained in file.
401 *\param tag_table HDF5/mhdf handle for tag values
402 *\param table_size Number of values in table
403 *\param sorted_values Sorted list of values to search for.
404 *\param value_indices Output: Offsets into the table of data at which
405 * matching values were found.
406 */
407 ErrorCode search_tag_values( hid_t tag_table,
408 unsigned long table_size,
409 const std::vector< int >& sorted_values,
410 std::vector< EntityHandle >& value_indices );
411
412 /**\brief Get the file IDs for nodes and elements contained in sets.
413 *
414 * Read the contents for the specified sets and return the file IDs
415 * of all nodes and elements contained within those sets.
416 *\param sets Container of file IDs designating entity sets.
417 *\param file_ids Output: File IDs of entities contained in sets.
418 */
419 ErrorCode get_set_contents( const Range& sets, Range& file_ids );
420
421 /** Given a list of file IDs for entity sets, find all contained
422 * or child sets (at any depth) and append them to the Range
423 * of file IDs.
424 */
425 ErrorCode read_set_ids_recursive( Range& sets_in_out, bool containted_sets, bool child_sets );
426
427 /** Find all sets containing one or more entities read from the file
428 * and added to idMap
429 */
430 ErrorCode find_sets_containing( Range& sets_out, bool read_set_containing_parents );
431
432 /**\brief Read sets from file into MOAB for partial read of file.
433 *
434 * Given the file IDs for entity sets (sets_in) and elements and
435 * nodes (id_map), read in all sets containing any of the elements
436 * or nodes and all sets that are (recursively) children of any
437 * other set to be read (those in sets_in or those containing any
438 * already-read element or node.)
439 *\param sets_in File IDs for sets to read (unconditionally)
440 */
441 ErrorCode read_sets_partial( const Range& sets_in );
442
443 /** Find file IDs of sets containing any entities in the passed id_map */
444 ErrorCode find_sets_containing( hid_t content_handle,
445 hid_t content_type,
446 long content_len,
447 bool read_set_containing_parents,
448 Range& file_ids );
449
450 public:
451 enum SetMode
452 {
453 CONTENT = 0,
454 CHILD = 1,
455 PARENT = 2
456 };
457
458 private:
459 // Read the set data specified by by which_data.
460 // Update set data in MOAB according to which_data,
461 // unless file_ids_out is non-null. If file_ids_out is
462 // non-null, then return the file IDs in the passed
463 // range and do not make any changes to MOAB data
464 // structures. If file_ids_out is NULL, then set_start_handle
465 // is ignored.
466 ErrorCode read_set_data( const Range& set_file_ids,
467 EntityHandle set_start_handle,
468 ReadHDF5Dataset& set_data_set,
469 SetMode which_data,
470 Range* file_ids_out = 0 );
471
472 /**\brief Store file IDS in tag values
473 *
474 * Copy file ID from IDMap for each entity read from file
475 * into a tag value on the entity.
476 */
477 ErrorCode store_file_ids( Tag tag );
478
479 /**\brief Store sets file IDS in a custom tag
480 *
481 * Copy sets file ID from IDMap for each set read from file
482 * into a custom tag on the sets
483 * needed now for the VisIt plugin, to identify sets read
484 */
485 ErrorCode store_sets_file_ids();
486
487 /**\brief Find index in mhdf_FileDesc* fileInfo for specified tag name
488 *
489 * Given a tag name, find its index in fileInfo and verify that
490 * each tag value is a single integer.
491 */
492 ErrorCode find_int_tag( const char* name, int& index_out );
493
494 void debug_barrier_line( int lineno );
495 };
496
497 } // namespace moab
498
499 #endif