1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/**
 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
 * storing and accessing finite element mesh data.
 *
 * Copyright 2004 Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
 * retains certain rights in this software.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 */

#ifndef READ_HDF5_HPP
#define READ_HDF5_HPP

#include <cstdlib>
#include <list>
#include "mhdf.h"
#include "moab/Forward.hpp"
#include "moab/ReadUtilIface.hpp"
#include "moab/Range.hpp"
#include "moab/ReaderIface.hpp"
#include "moab/RangeMap.hpp"
#include "DebugOutput.hpp"
#include "HDF5Common.hpp"

#ifdef MOAB_HAVE_MPI
#include <moab_mpi.h>
#endif

namespace moab
{

class ParallelComm;
class ReadHDF5Dataset;
class CpuTimer;

/**
 * \brief  Read mesh from MOAB HDF5 (.h5m) file.
 * \author Jason Kraftcheck
 * \date   18 April 2004
 */
class ReadHDF5 : public ReaderIface
{
  public:
#ifdef MOAB_HAVE_MPI
    typedef MPI_Comm Comm;
#else
    typedef int Comm;
#endif

    static ReaderIface* factory( Interface* );

    ReadHDF5( Interface* iface );

    virtual ~ReadHDF5();

    /** Export specified meshsets to file
     * \param filename     The filename to export. Must end in <em>.mhdf</em>
     * \param export_sets  Array of handles to sets to export, or NULL to export all.
     * \param export_set_count Length of <code>export_sets</code> array.
     */
    ErrorCode load_file( const char* file_name,
                         const EntityHandle* file_set,
                         const FileOptions& opts,
                         const SubsetList* subset_list = 0,
                         const Tag* file_id_tag        = 0 );

    ErrorCode read_tag_values( const char* file_name,
                               const char* tag_name,
                               const FileOptions& opts,
                               std::vector< int >& tag_values_out,
                               const SubsetList* subset_list = 0 );
    Interface* moab() const
    {
        return iFace;
    }

    //! Store old HDF5 error handling function
    struct HDF5ErrorHandler
    {
        HDF5_Error_Func_Type func;
        void* data;
    };

  protected:
    ErrorCode load_file_impl( const FileOptions& opts );

    ErrorCode load_file_partial( const ReaderIface::IDTag* subset_list,
                                 int subset_list_length,
                                 int num_parts,
                                 int part_number,
                                 const FileOptions& opts );

    ErrorCode read_tag_values_all( int tag_index, std::vector< int >& results );
    ErrorCode read_tag_values_partial( int tag_index, const Range& file_ids, std::vector< int >& results );

    enum ReadTimingValues
    {
        TOTAL_TIME = 0,
        SET_META_TIME,
        SUBSET_IDS_TIME,
        GET_PARTITION_TIME,
        GET_SET_IDS_TIME,
        GET_SET_CONTENTS_TIME,
        GET_POLYHEDRA_TIME,
        GET_ELEMENTS_TIME,
        GET_NODES_TIME,
        GET_NODEADJ_TIME,
        GET_SIDEELEM_TIME,
        UPDATECONN_TIME,
        ADJACENCY_TIME,
        DELETE_NON_SIDEELEM_TIME,
        READ_SET_IDS_RECURS_TIME,
        FIND_SETS_CONTAINING_TIME,
        READ_SETS_TIME,
        READ_TAGS_TIME,
        STORE_FILE_IDS_TIME,
        READ_QA_TIME,
        NUM_TIMES
    };

    void print_times();

  private:
    ErrorCode init();

    inline int is_error( mhdf_Status& status )
    {
        int i;
        if( ( i = mhdf_isError( &status ) ) ) MB_SET_ERR_CONT( mhdf_message( &status ) );
        return i;
    }

    //! The size of the data buffer (<code>dataBuffer</code>).
    int bufferSize;
    //! A memory buffer to use for all I/O operations.
    char* dataBuffer;

    //! Interface pointer passed to constructor
    Interface* iFace;

    //! The file handle from the mhdf library
    mhdf_FileHandle filePtr;

    //! File summary
    mhdf_FileDesc* fileInfo;

    //! Map from File ID to MOAB handle
    typedef RangeMap< long, EntityHandle > IDMap;
    IDMap idMap;

    //! Cache pointer to read util
    ReadUtilIface* readUtil;

    //! The type of an EntityHandle
    hid_t handleType;

    //! List of connectivity arrays for which conversion from file ID
    //! to handle was deferred until later.
    struct IDConnectivity
    {
        EntityHandle handle;  // Start_handle
        size_t count;         // Num entities
        int nodes_per_elem;   // Per-element connectivity length
        EntityHandle* array;  // Connectivity array
    };
    //! List of connectivity arrays for which conversion from file ID
    //! to handle was deferred until later.
    std::vector< IDConnectivity > idConnectivityList;

    //! Read/write property handle
    //! indepIO -> independent IO during true parallel read
    //! collIO  -> collective IO during true parallel read
    //! Both are H5P_DEFAULT for serial IO and collective
    //! when reading the entire file on all processors.
    hid_t indepIO, collIO;

    ParallelComm* myPcomm;

    //! Use IODebugTrack instances to verify reads.
    //! Enable with the DEBUG_OVERLAPS option.
    bool debugTrack;
    //! Debug output. Verbosity controlled with DEBUG_FORMAT option.
    DebugOutput dbgOut;
    //! Doing true parallel read (PARALLEL=READ_PART)
    bool nativeParallel;
    //! MPI_Comm value (unused if \c !nativeParallel)
    Comm* mpiComm;

    //! Flags for some behavior that can be changed through
    //! reader options
    bool blockedCoordinateIO;
    bool bcastSummary;
    bool bcastDuplicateReads;

    //! Store old HDF5 error handling function
    HDF5ErrorHandler errorHandler;

    long ( *setMeta )[4];

    double _times[NUM_TIMES];
    CpuTimer* timer;
    bool cputime;
    ErrorCode read_all_set_meta();

    ErrorCode set_up_read( const char* file_name, const FileOptions& opts );
    ErrorCode clean_up_read( const FileOptions& opts );

    //! Given a list of tags and values, get the file ids for the
    //! corresponding entities in the file.
    ErrorCode get_subset_ids( const ReaderIface::IDTag* subset_list, int subset_list_length, Range& file_ids_out );

    /**\brief Remove all but the specified fraction of sets from the passed range
     *
     * Select a subset of the gathered set of file ids to read in based on
     * communicator size and rank.
     *\param tmp_file_ids As input: sets to be read on all procs.
     *                    As output: sets to read on this proc.
     *\param num_parts    communicator size
     *\param part_number  communicator rank
     */
    ErrorCode get_partition( Range& tmp_file_ids, int num_parts, int part_number );

    ErrorCode read_nodes( const Range& node_file_ids );

    // Read elements in fileInfo->elems[index]
    ErrorCode read_elems( int index );

    // Read subset of elements in fileInfo->elems[index]
    ErrorCode read_elems( int index, const Range& file_ids, Range* node_ids = 0 );

    //! Read element connectivity.
    //!
    //!\param node_ids  If this is non-null, the union of the connectivity list
    //!                 for all elements is passed back as FILE IDS in this
    //!                 range AND the connectivity list is left in the form
    //!                 of file IDs (NOT NODE HANDLES).
    ErrorCode read_elems( const mhdf_ElemDesc& elems, const Range& file_ids, Range* node_ids = 0 );

    //! Update connectivity data for all element groups for which read_elems
    //! was called with a non-null \c node_ids argument.
    ErrorCode update_connectivity();

    // Read connectivity data for a list of element file ids.
    // passing back the file IDs for the element connectivity
    // w/out actually creating any elements in MOAB.
    ErrorCode read_elems( int index, const Range& element_file_ids, Range& node_file_ids );

    // Scan all elements in group. For each element for which all vertices
    // are contained in idMap (class member), read the element. All new
    // elements are added to idMap.
    //
    // NOTE: Collective IO calls in parallel.
    ErrorCode read_node_adj_elems( const mhdf_ElemDesc& group, Range* read_entities = 0 );

    // Scan all elements in specified file table. For each element for
    // which all vertices are contained in idMap (class member), read the
    // element. All new elements are added to idMap.
    //
    // NOTE: Collective IO calls in parallel.
    ErrorCode read_node_adj_elems( const mhdf_ElemDesc& group, hid_t connectivity_handle, Range* read_entities = 0 );

    //! Read poly(gons|hedra)
    ErrorCode read_poly( const mhdf_ElemDesc& elems, const Range& file_ids );

    //! Clean up elements that were a) read because we had read all of the
    //! nodes and b) weren't actually sides of the top-dimension elements
    //! we were trying to read.
    ErrorCode delete_non_side_elements( const Range& side_ents );

    //! Read sets
    ErrorCode read_sets( const Range& set_file_ids );

    ErrorCode read_adjacencies( hid_t adjacency_table, long table_length );

    //! Create tag and read all data.
    ErrorCode read_tag( int index );

    //! Create new tag or verify type matches existing tag
    ErrorCode create_tag( const mhdf_TagDesc& info, Tag& handle, hid_t& type );

    //! Read dense tag for all entities
    ErrorCode read_dense_tag( Tag tag_handle,
                              const char* ent_name,
                              hid_t hdf_read_type,
                              hid_t data_table,
                              long start_id,
                              long count );

    //! Read sparse tag for all entities.
    ErrorCode read_sparse_tag( Tag tag_handle,
                               hid_t hdf_read_type,
                               hid_t ent_table,
                               hid_t val_table,
                               long num_entities );

    //! Read variable-length tag for all entities.
    ErrorCode read_var_len_tag( Tag tag_handle,
                                hid_t hdf_read_type,
                                hid_t ent_table,
                                hid_t val_table,
                                hid_t off_table,
                                long num_entities,
                                long num_values );

    /**\brief Read index table for sparse tag.
     *
     * Read ID table for a sparse or variable-length tag, returning
     * the handles and offsets within the table for each file ID
     * that corresponds to an entity we've read from the file (an
     * entity that is in \c idMap).
     *
     * \param id_table     The MOAB handle for the tag
     * \param start_offset Some non-zero value because ranges (in this case
     *                     the offset_range) cannot contain zeros.
     * \param offset_range Output: The offsets in the id table for which IDs
     *                     that occur in \c idMap were found. All values
     *                     are increased by \c start_offset to avoid
     *                     putting zeros in the range.
     * \param handle_range Output: For each valid ID read from the table,
     *                     the corresponding entity handle. Note: if
     *                     the IDs did not occur in handle order, then
     *                     this will be empty. Use \c handle_vect instead.
     * \param handle_vect  Output: For each valid ID read from the table,
     *                     the corresponding entity handle. Note: if
     *                     the IDs occurred in handle order, then
     *                     this will be empty. Use \c handle_range instead.
     */
    ErrorCode read_sparse_tag_indices( const char* name,
                                       hid_t id_table,
                                       EntityHandle start_offset,
                                       Range& offset_range,
                                       Range& handle_range,
                                       std::vector< EntityHandle >& handle_vect );

    ErrorCode read_qa( EntityHandle file_set );

  public:
    ErrorCode convert_id_to_handle( EntityHandle* in_out_array, size_t array_length );

    void convert_id_to_handle( EntityHandle* in_out_array, size_t array_length, size_t& array_length_out ) const
    {
        return convert_id_to_handle( in_out_array, array_length, array_length_out, idMap );
    }

    ErrorCode convert_range_to_handle( const EntityHandle* ranges, size_t num_ranges, Range& merge );

    static void convert_id_to_handle( EntityHandle* in_out_array,
                                      size_t array_length,
                                      const RangeMap< long, EntityHandle >& id_map );

    static void convert_id_to_handle( EntityHandle* in_out_array,
                                      size_t array_length,
                                      size_t& array_length_out,
                                      const RangeMap< long, EntityHandle >& id_map );

    static void convert_range_to_handle( const EntityHandle* ranges,
                                         size_t num_ranges,
                                         const RangeMap< long, EntityHandle >& id_map,
                                         Range& merge );

    ErrorCode insert_in_id_map( const Range& file_ids, EntityHandle start_id );

    ErrorCode insert_in_id_map( long file_id, EntityHandle handle );

  private:
    /**\brief Search for entities with specified tag values
     *
     *\NOTE For parallel reads, this function does collective IO.
     *
     *\param tag_index  Index into info->tags specifying which tag to search.
     *\param sorted_values  List of tag values to check for, in ascending sorted
     *                  order.
     *\param file_ids_out  File IDs for entities with specified tag values.
     */
    ErrorCode search_tag_values( int tag_index,
                                 const std::vector< int >& sorted_values,
                                 Range& file_ids_out,
                                 bool sets_only = false );

    /**\brief Search for entities with specified tag
     *
     *\NOTE For parallel reads, this function does collective IO.
     *
     *\param tag_index  Index into info->tags specifying which tag to search.
     *\param file_ids_out  File IDs for entities with specified tag values.
     */
    ErrorCode get_tagged_entities( int tag_index, Range& file_ids_out );

    /**\brief Search a table of tag data for a specified set of values.
     *
     * Search a table of tag values, returning the indices into the table
     * at which matches were found.
     *\NOTE For parallel reads, this function does collective IO.
     *
     *\param info       Summary of data contained in file.
     *\param tag_table     HDF5/mhdf handle for tag values
     *\param table_size    Number of values in table
     *\param sorted_values Sorted list of values to search for.
     *\param value_indices Output: Offsets into the table of data at which
     *                       matching values were found.
     */
    ErrorCode search_tag_values( hid_t tag_table,
                                 unsigned long table_size,
                                 const std::vector< int >& sorted_values,
                                 std::vector< EntityHandle >& value_indices );

    /**\brief Get the file IDs for nodes and elements contained in sets.
     *
     * Read the contents for the specified sets and return the file IDs
     * of all nodes and elements contained within those sets.
     *\param sets       Container of file IDs designating entity sets.
     *\param file_ids   Output: File IDs of entities contained in sets.
     */
    ErrorCode get_set_contents( const Range& sets, Range& file_ids );

    /** Given a list of file IDs for entity sets, find all contained
     *  or child sets (at any depth) and append them to the Range
     *  of file IDs.
     */
    ErrorCode read_set_ids_recursive( Range& sets_in_out, bool containted_sets, bool child_sets );

    /** Find all sets containing one or more entities read from the file
     *  and added to idMap
     */
    ErrorCode find_sets_containing( Range& sets_out, bool read_set_containing_parents );

    /**\brief Read sets from file into MOAB for partial read of file.
     *
     * Given the file IDs for entity sets (sets_in) and elements and
     * nodes (id_map), read in all sets containing any of the elements
     * or nodes and all sets that are (recursively) children of any
     * other set to be read (those in sets_in or those containing any
     * already-read element or node.)
     *\param sets_in    File IDs for sets to read (unconditionally)
     */
    ErrorCode read_sets_partial( const Range& sets_in );

    /** Find file IDs of sets containing any entities in the passed id_map */
    ErrorCode find_sets_containing( hid_t content_handle,
                                    hid_t content_type,
                                    long content_len,
                                    bool read_set_containing_parents,
                                    Range& file_ids );

  public:
    enum SetMode
    {
        CONTENT = 0,
        CHILD   = 1,
        PARENT  = 2
    };

  private:
    // Read the set data specified by by which_data.
    // Update set data in MOAB according to which_data,
    // unless file_ids_out is non-null. If file_ids_out is
    // non-null, then return the file IDs in the passed
    // range and do not make any changes to MOAB data
    // structures. If file_ids_out is NULL, then set_start_handle
    // is ignored.
    ErrorCode read_set_data( const Range& set_file_ids,
                             EntityHandle set_start_handle,
                             ReadHDF5Dataset& set_data_set,
                             SetMode which_data,
                             Range* file_ids_out = 0 );

    /**\brief Store file IDS in tag values
     *
     * Copy file ID from IDMap for each entity read from file
     * into a tag value on the entity.
     */
    ErrorCode store_file_ids( Tag tag );

    /**\brief Store sets file IDS in a custom tag
     *
     * Copy sets file ID from IDMap for each set read from file
     *  into a custom tag on the sets
     *  needed now for the VisIt plugin, to identify sets read
     */
    ErrorCode store_sets_file_ids();

    /**\brief Find index in mhdf_FileDesc* fileInfo for specified tag name
     *
     * Given a tag name, find its index in fileInfo and verify that
     * each tag value is a single integer.
     */
    ErrorCode find_int_tag( const char* name, int& index_out );

    void debug_barrier_line( int lineno );
};

}  // namespace moab

#endif