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 //-------------------------------------------------------------------------
17 // Filename      : ReadHDF5.cpp
18 //
19 // Purpose       : HDF5 Writer
20 //
21 // Creator       : Jason Kraftcheck
22 //
23 // Creation Date : 04/18/04
24 //-------------------------------------------------------------------------
25 
26 #include <assert.h>
27 #include "moab/MOABConfig.h"
28 /* Include our MPI header before any HDF5 because otherwise
29    it will get included indirectly by HDF5 */
30 #ifdef MOAB_HAVE_MPI
31 #  include "moab_mpi.h"
32 #  include "moab/ParallelComm.hpp"
33 #endif
34 #include <H5Tpublic.h>
35 #include <H5Ppublic.h>
36 #include <H5Epublic.h>
37 #include "moab/Interface.hpp"
38 #include "Internals.hpp"
39 #include "MBTagConventions.hpp"
40 #include "ReadHDF5.hpp"
41 #include "moab/CN.hpp"
42 #include "moab/FileOptions.hpp"
43 #include "moab/CpuTimer.hpp"
44 #ifdef MOAB_HAVE_HDF5_PARALLEL
45 #include <H5FDmpi.h>
46 #include <H5FDmpio.h>
47 #endif
48 //#include "WriteHDF5.hpp"
49 
50 #include <stdlib.h>
51 #include <string.h>
52 #include <limits>
53 #include <functional>
54 #include <iostream>
55 
56 #include "IODebugTrack.hpp"
57 #include "ReadHDF5Dataset.hpp"
58 #include "ReadHDF5VarLen.hpp"
59 #include "moab_mpe.h"
60 
61 namespace moab {
62 
63 /* If true, coordinates are read in blocked format (all X values before
64  * Y values before Z values.) If undefined, then all coordinates for a
65  * given vertex are read at the same time.
66  */
67 const bool DEFAULT_BLOCKED_COORDINATE_IO = false;
68 
69 /* If true, file is opened first by root node only to read summary,
70  * file is the closed and the summary is broadcast to all nodes, after
71  * which all nodes open file in parallel to read data. If undefined,
72  * file is opened once in parallel and all nodes read summary data.
73  */
74 const bool DEFAULT_BCAST_SUMMARY = true;
75 
76 /* If true and all processors are to read the same block of data,
77  * read it on one and broadcast to others rather than using collective
78  * io
79  */
80 const bool DEFAULT_BCAST_DUPLICATE_READS = true;
81 
82 #define READ_HDF5_BUFFER_SIZE (128 * 1024 * 1024)
83 
84 #define assert_range(PTR, CNT) \
85   assert((PTR) >= (void*)dataBuffer); assert(((PTR) + (CNT)) <= (void*)(dataBuffer + bufferSize));
86 
87 // Call \c error function during HDF5 library errors to make
88 // it easier to trap such errors in the debugger. This function
89 // gets registered with the HDF5 library as a callback. It
90 // works the same as the default (H5Eprint), except that it
91 // also calls the \c error function as a no-op.
92 #if defined(H5E_auto_t_vers) && H5E_auto_t_vers > 1
handle_hdf5_error(hid_t stack,void * data)93 static herr_t handle_hdf5_error(hid_t stack, void* data)
94 {
95   ReadHDF5::HDF5ErrorHandler* h = reinterpret_cast<ReadHDF5::HDF5ErrorHandler*>(data);
96   herr_t result = 0;
97   if (h->func)
98     result = (*h->func)(stack, h->data);
99   MB_CHK_ERR_CONT(MB_FAILURE);
100   return result;
101 }
102 #else
handle_hdf5_error(void * data)103 static herr_t handle_hdf5_error(void* data)
104 {
105   ReadHDF5::HDF5ErrorHandler* h = reinterpret_cast<ReadHDF5::HDF5ErrorHandler*>(data);
106   herr_t result = 0;
107   if (h->func)
108     result = (*h->func)(h->data);
109   MB_CHK_ERR_CONT(MB_FAILURE);
110   return result;
111 }
112 #endif
113 
copy_sorted_file_ids(const EntityHandle * sorted_ids,long num_ids,Range & results)114 static void copy_sorted_file_ids(const EntityHandle* sorted_ids,
115                                  long num_ids,
116                                  Range& results)
117 {
118   Range::iterator hint = results.begin();
119   long i = 0;
120   while (i < num_ids) {
121     EntityHandle start = sorted_ids[i];
122     for (++i; i < num_ids && sorted_ids[i] == 1 + sorted_ids[i - 1]; ++i);
123     hint = results.insert(hint, start, sorted_ids[i - 1]);
124   }
125 }
126 
intersect(const mhdf_EntDesc & group,const Range & range,Range & result)127 static void intersect(const mhdf_EntDesc& group, const Range& range, Range& result)
128 {
129   Range::const_iterator s, e;
130   s = Range::lower_bound(range.begin(), range.end(), group.start_id);
131   e = Range::lower_bound(s, range.end(), group.start_id + group.count);
132   result.merge(s, e);
133 }
134 
135 #define debug_barrier() debug_barrier_line(__LINE__)
debug_barrier_line(int lineno)136 void ReadHDF5::debug_barrier_line(int lineno)
137 {
138 #ifdef MOAB_HAVE_MPI
139   if (mpiComm) {
140     const unsigned threshold = 2;
141     static unsigned long count = 0;
142     if (dbgOut.get_verbosity() >= threshold) {
143       dbgOut.printf(threshold, "*********** Debug Barrier %lu (@%d)***********\n", ++count, lineno);
144       MPI_Barrier(*mpiComm);
145     }
146   }
147 #else
148   if (lineno) {}
149 #endif
150 }
151 
152 class CheckOpenReadHDF5Handles
153 {
154   int fileline;
155   mhdf_FileHandle handle;
156   int enter_count;
157 public:
CheckOpenReadHDF5Handles(mhdf_FileHandle file,int line)158   CheckOpenReadHDF5Handles(mhdf_FileHandle file, int line)
159     : fileline(line), handle(file),
160       enter_count(mhdf_countOpenHandles(file))
161   {}
~CheckOpenReadHDF5Handles()162   ~CheckOpenReadHDF5Handles()
163   {
164     int new_count = mhdf_countOpenHandles(handle);
165     if (new_count != enter_count) {
166       std::cout << "Leaked HDF5 object handle in function at "
167                 << __FILE__ << ":" << fileline << std::endl
168                 << "Open at entrance: " << enter_count << std::endl
169                 << "Open at exit:     " << new_count << std::endl;
170     }
171   }
172 };
173 
174 #ifdef NDEBUG
175 #define CHECK_OPEN_HANDLES
176 #else
177 #define CHECK_OPEN_HANDLES \
178   CheckOpenReadHDF5Handles check_open_handles_(filePtr, __LINE__)
179 #endif
180 
factory(Interface * iface)181 ReaderIface* ReadHDF5::factory(Interface* iface)
182 {
183   return new ReadHDF5(iface);
184 }
185 
ReadHDF5(Interface * iface)186 ReadHDF5::ReadHDF5(Interface* iface)
187   : bufferSize(READ_HDF5_BUFFER_SIZE),
188     dataBuffer(NULL),
189     iFace(iface),
190     filePtr(0),
191     fileInfo(NULL),
192     readUtil(NULL),
193     handleType(0),
194     indepIO(H5P_DEFAULT),
195     collIO(H5P_DEFAULT),
196     myPcomm(NULL),
197     debugTrack(false),
198     dbgOut(stderr),
199     nativeParallel(false),
200     mpiComm(NULL),
201     blockedCoordinateIO(DEFAULT_BLOCKED_COORDINATE_IO),
202     bcastSummary(DEFAULT_BCAST_SUMMARY),
203     bcastDuplicateReads(DEFAULT_BCAST_DUPLICATE_READS),
204     setMeta(0),
205     timer(NULL),
206     cputime(false)
207 {
208 }
209 
init()210 ErrorCode ReadHDF5::init()
211 {
212   ErrorCode rval;
213 
214   if (readUtil)
215     return MB_SUCCESS;
216 
217   indepIO = collIO = H5P_DEFAULT;
218   //WriteHDF5::register_known_tag_types(iFace);
219 
220   handleType = H5Tcopy(H5T_NATIVE_ULONG);
221   if (handleType < 0)
222     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
223 
224   if (H5Tset_size(handleType, sizeof(EntityHandle)) < 0) {
225     H5Tclose(handleType);
226     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
227   }
228 
229   rval = iFace->query_interface(readUtil);
230   if (MB_SUCCESS != rval) {
231     H5Tclose(handleType);
232     MB_SET_ERR(rval, "ReadHDF5 Failure");
233   }
234 
235   idMap.clear();
236   fileInfo = 0;
237   debugTrack = false;
238   myPcomm = 0;
239 
240   return MB_SUCCESS;
241 }
242 
~ReadHDF5()243 ReadHDF5::~ReadHDF5()
244 {
245   if (!readUtil) // init() failed.
246     return;
247 
248   delete [] setMeta;
249   setMeta = 0;
250   iFace->release_interface(readUtil);
251   H5Tclose(handleType);
252 }
253 
set_up_read(const char * filename,const FileOptions & opts)254 ErrorCode ReadHDF5::set_up_read(const char* filename,
255                                 const FileOptions& opts)
256 {
257   ErrorCode rval;
258   mhdf_Status status;
259   indepIO = collIO = H5P_DEFAULT;
260   mpiComm = 0;
261 
262   if (MB_SUCCESS != init())
263     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
264 
265 #if defined(H5Eget_auto_vers) && H5Eget_auto_vers > 1
266   herr_t err = H5Eget_auto(H5E_DEFAULT, &errorHandler.func, &errorHandler.data);
267 #else
268   herr_t err = H5Eget_auto(&errorHandler.func, &errorHandler.data);
269 #endif
270   if (err < 0) {
271     errorHandler.func = 0;
272     errorHandler.data = 0;
273   }
274   else {
275 #if defined(H5Eset_auto_vers) && H5Eset_auto_vers > 1
276     err = H5Eset_auto(H5E_DEFAULT, &handle_hdf5_error, &errorHandler);
277 #else
278     err = H5Eset_auto(&handle_hdf5_error, &errorHandler);
279 #endif
280     if (err < 0) {
281       errorHandler.func = 0;
282       errorHandler.data = 0;
283     }
284   }
285 
286   // Set up debug output
287   int tmpval;
288   if (MB_SUCCESS == opts.get_int_option("DEBUG_IO", 1, tmpval)) {
289     dbgOut.set_verbosity(tmpval);
290     dbgOut.set_prefix("H5M ");
291   }
292   dbgOut.limit_output_to_first_N_procs(32);
293 
294   // Enable some extra checks for reads. Note: amongst other things this
295   // will print errors if the entire file is not read, so if doing a
296   // partial read that is not a parallel read, this should be disabled.
297   debugTrack = (MB_SUCCESS == opts.get_null_option("DEBUG_BINIO"));
298 
299   opts.get_toggle_option("BLOCKED_COORDINATE_IO", DEFAULT_BLOCKED_COORDINATE_IO, blockedCoordinateIO);
300   opts.get_toggle_option("BCAST_SUMMARY",         DEFAULT_BCAST_SUMMARY,         bcastSummary);
301   opts.get_toggle_option("BCAST_DUPLICATE_READS", DEFAULT_BCAST_DUPLICATE_READS, bcastDuplicateReads);
302 
303   // Handle parallel options
304   bool use_mpio = (MB_SUCCESS == opts.get_null_option("USE_MPIO"));
305   rval = opts.match_option("PARALLEL", "READ_PART");
306   bool parallel = (rval != MB_ENTITY_NOT_FOUND);
307   nativeParallel = (rval == MB_SUCCESS);
308   if (use_mpio && !parallel) {
309     MB_SET_ERR(MB_NOT_IMPLEMENTED, "'USE_MPIO' option specified w/out 'PARALLEL' option");
310   }
311 
312   // This option is intended for testing purposes only, and thus
313   // is not documented anywhere.  Decreasing the buffer size can
314   // expose bugs that would otherwise only be seen when reading
315   // very large files.
316   rval = opts.get_int_option("BUFFER_SIZE", bufferSize);
317   if (MB_SUCCESS != rval) {
318     bufferSize = READ_HDF5_BUFFER_SIZE;
319   }
320   else if (bufferSize < (int)std::max(sizeof(EntityHandle), sizeof(void*))) {
321     MB_CHK_ERR(MB_INVALID_SIZE);
322   }
323 
324   dataBuffer = (char*)malloc(bufferSize);
325   if (!dataBuffer)
326     MB_CHK_ERR(MB_MEMORY_ALLOCATION_FAILED);
327 
328   if (use_mpio || nativeParallel) {
329 
330 #ifndef MOAB_HAVE_HDF5_PARALLEL
331     free(dataBuffer);
332     dataBuffer = NULL;
333     MB_SET_ERR(MB_NOT_IMPLEMENTED, "MOAB not configured with parallel HDF5 support");
334 #else
335     MPI_Info info = MPI_INFO_NULL;
336     std::string cb_size;
337     rval = opts.get_str_option("CB_BUFFER_SIZE", cb_size);
338     if (MB_SUCCESS == rval) {
339       MPI_Info_create (&info);
340       MPI_Info_set (info, const_cast<char*>("cb_buffer_size"), const_cast<char*>(cb_size.c_str()));
341     }
342 
343     int pcomm_no = 0;
344     rval = opts.get_int_option("PARALLEL_COMM", pcomm_no);
345     if (rval == MB_TYPE_OUT_OF_RANGE) {
346       MB_SET_ERR(rval, "Invalid value for PARALLEL_COMM option");
347     }
348     myPcomm = ParallelComm::get_pcomm(iFace, pcomm_no);
349     if (0 == myPcomm) {
350       myPcomm = new ParallelComm(iFace, MPI_COMM_WORLD);
351     }
352     const int rank = myPcomm->proc_config().proc_rank();
353     dbgOut.set_rank(rank);
354     dbgOut.limit_output_to_first_N_procs(32);
355     mpiComm = new MPI_Comm(myPcomm->proc_config().proc_comm());
356 
357 #ifndef H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS
358     dbgOut.print(1, "H5_MPI_COMPLEX_DERIVED_DATATYPE_WORKS is not defined\n");
359 #endif
360 
361     // Open the file in serial on root to read summary
362     dbgOut.tprint(1, "Getting file summary\n");
363     fileInfo = 0;
364 
365     hid_t file_prop;
366     if (bcastSummary) {
367       unsigned long size = 0;
368       if (rank == 0) {
369         file_prop = H5Pcreate(H5P_FILE_ACCESS);
370         err = H5Pset_fapl_mpio(file_prop, MPI_COMM_SELF, MPI_INFO_NULL);
371         assert(file_prop >= 0);
372         assert(err >= 0);
373         filePtr = mhdf_openFileWithOpt(filename, 0, NULL, handleType, file_prop, &status);
374         H5Pclose(file_prop);
375 
376         if (filePtr) {
377           fileInfo = mhdf_getFileSummary(filePtr, handleType, &status, 0); // no extra set info
378           if (!is_error(status)) {
379             size = fileInfo->total_size;
380             fileInfo->offset = (unsigned char*)fileInfo;
381           }
382         }
383         mhdf_closeFile(filePtr, &status);
384         if (fileInfo && mhdf_isError(&status)) {
385           free(fileInfo);
386           fileInfo = NULL;
387         }
388       }
389 
390       dbgOut.tprint(1, "Communicating file summary\n");
391       int mpi_err = MPI_Bcast(&size, 1, MPI_UNSIGNED_LONG, 0, myPcomm->proc_config().proc_comm());
392       if (mpi_err || !size)
393         return MB_FAILURE;
394 
395       if (rank != 0)
396         fileInfo = reinterpret_cast<mhdf_FileDesc*>(malloc(size));
397 
398       MPI_Bcast(fileInfo, size, MPI_BYTE, 0, myPcomm->proc_config().proc_comm());
399 
400       if (rank != 0)
401         mhdf_fixFileDesc(fileInfo, reinterpret_cast<mhdf_FileDesc*>(fileInfo->offset));
402     }
403 
404     file_prop = H5Pcreate(H5P_FILE_ACCESS);
405     err = H5Pset_fapl_mpio(file_prop, myPcomm->proc_config().proc_comm(), info);
406     assert(file_prop >= 0);
407     assert(err >= 0);
408 
409     collIO = H5Pcreate(H5P_DATASET_XFER);
410     assert(collIO > 0);
411     err = H5Pset_dxpl_mpio(collIO, H5FD_MPIO_COLLECTIVE);
412     assert(err >= 0);
413     indepIO = nativeParallel ? H5P_DEFAULT : collIO;
414 
415     // Re-open file in parallel
416     dbgOut.tprintf(1, "Opening \"%s\" for parallel IO\n", filename);
417     filePtr = mhdf_openFileWithOpt(filename, 0, NULL, handleType, file_prop, &status);
418 
419     H5Pclose(file_prop);
420     if (!filePtr) {
421       free(dataBuffer);
422       dataBuffer = NULL;
423       H5Pclose(indepIO);
424       if (collIO != indepIO)
425         H5Pclose(collIO);
426       collIO = indepIO = H5P_DEFAULT;
427       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
428     }
429 
430     if (!bcastSummary) {
431       fileInfo = mhdf_getFileSummary(filePtr, handleType, &status, 0);
432       if (is_error(status)) {
433         free(dataBuffer);
434         dataBuffer = NULL;
435         mhdf_closeFile(filePtr, &status);
436         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
437       }
438     }
439 #endif // HDF5_PARALLEL
440   }
441   else {
442     // Open the file
443     filePtr = mhdf_openFile(filename, 0, NULL, handleType, &status);
444     if (!filePtr) {
445       free(dataBuffer);
446       dataBuffer = NULL;
447       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
448     }
449 
450     // Get file info
451     fileInfo = mhdf_getFileSummary(filePtr, handleType, &status, 0);
452     if (is_error(status)) {
453       free(dataBuffer);
454       dataBuffer = NULL;
455       mhdf_closeFile(filePtr, &status);
456       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
457     }
458   }
459 
460   ReadHDF5Dataset::default_hyperslab_selection_limit();
461   int hslimit;
462   rval = opts.get_int_option("HYPERSLAB_SELECT_LIMIT", hslimit);
463   if (MB_SUCCESS == rval && hslimit > 0)
464     ReadHDF5Dataset::set_hyperslab_selection_limit(hslimit);
465   else
466     ReadHDF5Dataset::default_hyperslab_selection_limit();
467   if (MB_SUCCESS != opts.get_null_option("HYPERSLAB_OR") &&
468      (MB_SUCCESS == opts.get_null_option("HYPERSLAB_APPEND")
469       || HDF5_can_append_hyperslabs())) {
470     ReadHDF5Dataset::append_hyperslabs();
471     if (MB_SUCCESS != opts.get_int_option("HYPERSLAB_SELECT_LIMIT", hslimit))
472       ReadHDF5Dataset::set_hyperslab_selection_limit(std::numeric_limits<int>::max());
473     dbgOut.print(1, "Using H5S_APPEND for hyperslab selection\n");
474   }
475 
476   return MB_SUCCESS;
477 }
478 
clean_up_read(const FileOptions &)479 ErrorCode ReadHDF5::clean_up_read(const FileOptions&)
480 {
481   HDF5ErrorHandler handler;
482 #if defined(H5Eget_auto_vers) && H5Eget_auto_vers > 1
483   herr_t err = H5Eget_auto(H5E_DEFAULT, &handler.func, &handler.data);
484 #else
485   herr_t err = H5Eget_auto(&handler.func, &handler.data);
486 #endif
487   if (err >= 0 && handler.func == &handle_hdf5_error) {
488     assert(handler.data == &errorHandler);
489 #if defined(H5Eget_auto_vers) && H5Eget_auto_vers > 1
490     H5Eset_auto(H5E_DEFAULT, errorHandler.func, errorHandler.data);
491 #else
492     H5Eset_auto(errorHandler.func, errorHandler.data);
493 #endif
494   }
495 
496   free(dataBuffer);
497   dataBuffer = NULL;
498   free(fileInfo);
499   fileInfo = NULL;
500   delete mpiComm;
501   mpiComm = 0;
502 
503   if (indepIO != H5P_DEFAULT)
504     H5Pclose(indepIO);
505   if (collIO != indepIO)
506     H5Pclose(collIO);
507   collIO = indepIO = H5P_DEFAULT;
508 
509   delete [] setMeta;
510   setMeta = 0;
511 
512   mhdf_Status status;
513   mhdf_closeFile(filePtr, &status);
514   filePtr = 0;
515   return is_error(status) ? MB_FAILURE : MB_SUCCESS;
516 }
517 
load_file(const char * filename,const EntityHandle * file_set,const FileOptions & opts,const ReaderIface::SubsetList * subset_list,const Tag * file_id_tag)518 ErrorCode ReadHDF5::load_file(const char* filename,
519                               const EntityHandle* file_set,
520                               const FileOptions& opts,
521                               const ReaderIface::SubsetList* subset_list,
522                               const Tag* file_id_tag)
523 {
524   ErrorCode rval;
525 
526   rval = set_up_read(filename, opts);
527   if (MB_SUCCESS != rval) {
528     clean_up_read(opts);
529     return rval;
530   }
531   // See if we need to report times
532 
533   rval = opts.get_null_option("CPUTIME");
534   if (MB_SUCCESS == rval)
535   {
536     cputime = true;
537     timer = new CpuTimer;
538     for (int i=0; i<NUM_TIMES; i++)
539       _times[i]=0;
540   }
541 
542   // We read the entire set description table regardless of partial
543   // or complete reads or serial vs parallel reads
544   rval = read_all_set_meta();
545 
546   if (cputime)
547     _times[SET_META_TIME]=timer->time_elapsed();
548   if (subset_list && MB_SUCCESS == rval)
549     rval = load_file_partial(subset_list->tag_list,
550                              subset_list->tag_list_length,
551                              subset_list->num_parts,
552                              subset_list->part_number,
553                              opts);
554   else
555     rval = load_file_impl(opts);
556 
557   if (MB_SUCCESS == rval && file_id_tag) {
558     dbgOut.tprint(1, "Storing file IDs in tag\n");
559     rval = store_file_ids(*file_id_tag);
560   }
561   ErrorCode rval3 = opts.get_null_option("STORE_SETS_FILEIDS");
562   if (MB_SUCCESS == rval3)
563   {
564     rval = store_sets_file_ids();
565     if (MB_SUCCESS != rval) return rval;
566   }
567 
568   if (cputime)
569     _times[STORE_FILE_IDS_TIME]=timer->time_elapsed();
570 
571   if (MB_SUCCESS == rval && 0 != file_set) {
572     dbgOut.tprint(1, "Reading QA records\n");
573     rval = read_qa(*file_set);
574   }
575 
576   if (cputime)
577     _times[READ_QA_TIME]=timer->time_elapsed();
578   dbgOut.tprint(1, "Cleaning up\n");
579   ErrorCode rval2 = clean_up_read(opts);
580   if (rval == MB_SUCCESS && rval2 != MB_SUCCESS)
581     rval = rval2;
582 
583   if (MB_SUCCESS == rval)
584     dbgOut.tprint(1, "Read finished.\n");
585   else {
586     std::string msg;
587     iFace->get_last_error(msg);
588     dbgOut.tprintf(1, "READ FAILED (ERROR CODE %s): %s\n", ErrorCodeStr[rval], msg.c_str());
589   }
590 
591   if (cputime) {
592     _times[TOTAL_TIME] = timer->time_since_birth();
593     print_times();
594     delete timer;
595   }
596   if (H5P_DEFAULT != collIO)
597     H5Pclose(collIO);
598   if (H5P_DEFAULT != indepIO)
599     H5Pclose(indepIO);
600   collIO = indepIO = H5P_DEFAULT;
601 
602   return rval;
603 }
604 
load_file_impl(const FileOptions &)605 ErrorCode ReadHDF5::load_file_impl(const FileOptions&)
606 {
607   ErrorCode rval;
608   mhdf_Status status;
609   int i;
610 
611   CHECK_OPEN_HANDLES;
612 
613   dbgOut.tprint(1, "Reading all nodes...\n");
614   Range ids;
615   if (fileInfo->nodes.count) {
616     ids.insert(fileInfo->nodes.start_id,
617                fileInfo->nodes.start_id + fileInfo->nodes.count - 1);
618     rval = read_nodes(ids);
619     if (MB_SUCCESS != rval)
620       MB_SET_ERR(rval, "ReadHDF5 Failure");
621   }
622 
623   dbgOut.tprint(1, "Reading all element connectivity...\n");
624   std::vector<int> polyhedra; // Need to do these last so that faces are loaded
625   for (i = 0; i < fileInfo->num_elem_desc; ++i) {
626     if (CN::EntityTypeFromName(fileInfo->elems[i].type) == MBPOLYHEDRON) {
627       polyhedra.push_back(i);
628       continue;
629     }
630 
631     rval = read_elems(i);
632     if (MB_SUCCESS != rval)
633       MB_SET_ERR(rval, "ReadHDF5 Failure");
634   }
635   for (std::vector<int>::iterator it = polyhedra.begin();
636        it != polyhedra.end(); ++it) {
637     rval = read_elems(*it);
638     if (MB_SUCCESS != rval)
639       MB_SET_ERR(rval, "ReadHDF5 Failure");
640   }
641 
642   dbgOut.tprint(1, "Reading all sets...\n");
643   ids.clear();
644   if (fileInfo->sets.count) {
645     ids.insert(fileInfo->sets.start_id,
646                fileInfo->sets.start_id + fileInfo->sets.count - 1);
647     rval = read_sets(ids);
648     if (rval != MB_SUCCESS) {
649       MB_SET_ERR(rval, "ReadHDF5 Failure");
650     }
651   }
652 
653   dbgOut.tprint(1, "Reading all adjacencies...\n");
654   for (i = 0; i < fileInfo->num_elem_desc; ++i) {
655     if (!fileInfo->elems[i].have_adj)
656       continue;
657 
658     long table_len;
659     hid_t table = mhdf_openAdjacency(filePtr,
660                                      fileInfo->elems[i].handle,
661                                      &table_len,
662                                      &status);
663     if (is_error(status))
664       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
665 
666     rval = read_adjacencies(table, table_len);
667     mhdf_closeData(filePtr, table, &status);
668     if (MB_SUCCESS != rval)
669       MB_SET_ERR(rval, "ReadHDF5 Failure");
670     if (is_error(status))
671       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
672   }
673 
674   dbgOut.tprint(1, "Reading all tags...\n");
675   for (i = 0; i < fileInfo->num_tag_desc; ++i) {
676     rval = read_tag(i);
677     if (MB_SUCCESS != rval)
678       MB_SET_ERR(rval, "ReadHDF5 Failure");
679   }
680 
681   dbgOut.tprint(1, "Core read finished.  Cleaning up...\n");
682   return MB_SUCCESS;
683 }
684 
find_int_tag(const char * name,int & index)685 ErrorCode ReadHDF5::find_int_tag(const char* name, int& index)
686 {
687   for (index = 0; index < fileInfo->num_tag_desc; ++index)
688     if (!strcmp(name, fileInfo->tags[index].name))
689       break;
690 
691   if (index == fileInfo->num_tag_desc) {
692     MB_SET_ERR(MB_TAG_NOT_FOUND, "File does not contain subset tag '" << name << "'");
693   }
694 
695   if (fileInfo->tags[index].type != mhdf_INTEGER ||
696       fileInfo->tags[index].size != 1) {
697     MB_SET_ERR(MB_TAG_NOT_FOUND, "Tag ' " << name << "' does not contain single integer value");
698   }
699 
700   return MB_SUCCESS;
701 }
702 
get_subset_ids(const ReaderIface::IDTag * subset_list,int subset_list_length,Range & file_ids)703 ErrorCode ReadHDF5::get_subset_ids(const ReaderIface::IDTag* subset_list,
704                                    int subset_list_length,
705                                    Range& file_ids)
706 {
707   ErrorCode rval;
708 
709   for (int i = 0; i < subset_list_length; ++i) {
710     int tag_index;
711     rval = find_int_tag(subset_list[i].tag_name, tag_index);
712     if (MB_SUCCESS != rval)
713       MB_SET_ERR(rval, "ReadHDF5 Failure");
714 
715     Range tmp_file_ids;
716     if (!subset_list[i].num_tag_values) {
717       rval = get_tagged_entities(tag_index, tmp_file_ids);
718     }
719     else {
720       std::vector<int> ids(subset_list[i].tag_values,
721                            subset_list[i].tag_values + subset_list[i].num_tag_values);
722       std::sort(ids.begin(), ids.end());
723       rval = search_tag_values(tag_index, ids, tmp_file_ids);
724       if (MB_SUCCESS != rval)
725         MB_SET_ERR(rval, "ReadHDF5 Failure");
726     }
727 
728     if (tmp_file_ids.empty())
729       MB_CHK_ERR(MB_ENTITY_NOT_FOUND);
730 
731     if (i == 0)
732       file_ids.swap(tmp_file_ids);
733     else
734       file_ids = intersect(tmp_file_ids, file_ids);
735   }
736 
737   return MB_SUCCESS;
738 }
739 
get_partition(Range & tmp_file_ids,int num_parts,int part_number)740 ErrorCode ReadHDF5::get_partition(Range& tmp_file_ids, int num_parts, int part_number)
741 {
742   CHECK_OPEN_HANDLES;
743 
744    // Check that the tag only identified sets
745    if ((unsigned long)fileInfo->sets.start_id > tmp_file_ids.front()) {
746      dbgOut.print(2, "Ignoring non-set entities with partition set tag\n");
747      tmp_file_ids.erase(tmp_file_ids.begin(),
748                         tmp_file_ids.lower_bound(
749                         (EntityHandle)fileInfo->sets.start_id));
750    }
751    unsigned long set_end = (unsigned long)fileInfo->sets.start_id + fileInfo->sets.count;
752    if (tmp_file_ids.back() >= set_end) {
753      dbgOut.print(2, "Ignoring non-set entities with partition set tag\n");
754      tmp_file_ids.erase(tmp_file_ids.upper_bound((EntityHandle)set_end),
755                         tmp_file_ids.end());
756    }
757 
758   Range::iterator s = tmp_file_ids.begin();
759   size_t num_per_proc = tmp_file_ids.size() / num_parts;
760   size_t num_extra = tmp_file_ids.size() % num_parts;
761   Range::iterator e;
762   if (part_number < (long)num_extra) {
763     s += (num_per_proc + 1) * part_number;
764     e = s;
765     e += (num_per_proc + 1);
766   }
767   else {
768     s += num_per_proc * part_number + num_extra;
769     e = s;
770     e += num_per_proc;
771   }
772   tmp_file_ids.erase(e, tmp_file_ids.end());
773   tmp_file_ids.erase(tmp_file_ids.begin(), s);
774 
775   return MB_SUCCESS;
776 }
777 
load_file_partial(const ReaderIface::IDTag * subset_list,int subset_list_length,int num_parts,int part_number,const FileOptions & opts)778 ErrorCode ReadHDF5::load_file_partial(const ReaderIface::IDTag* subset_list,
779                                       int subset_list_length,
780                                       int num_parts,
781                                       int part_number,
782                                       const FileOptions& opts)
783 {
784   mhdf_Status status;
785 
786   static MPEState mpe_event("ReadHDF5", "yellow");
787 
788   mpe_event.start("gather parts");
789 
790   CHECK_OPEN_HANDLES;
791 
792   for (int i = 0; i < subset_list_length; ++i) {
793     dbgOut.printf(2, "Select by \"%s\" with num_tag_values = %d\n",
794                   subset_list[i].tag_name, subset_list[i].num_tag_values);
795     if (subset_list[i].num_tag_values) {
796       assert(0 != subset_list[i].tag_values);
797       dbgOut.printf(2, "  \"%s\" values = { %d",
798         subset_list[i].tag_name, subset_list[i].tag_values[0]);
799       for (int j = 1; j < subset_list[i].num_tag_values; ++j)
800         dbgOut.printf(2, ", %d", subset_list[i].tag_values[j]);
801       dbgOut.printf(2, " }\n");
802     }
803   }
804   if (num_parts)
805     dbgOut.printf(2, "Partition with num_parts = %d and part_number = %d\n",
806                   num_parts, part_number);
807 
808   dbgOut.tprint(1, "RETRIEVING TAGGED ENTITIES\n");
809 
810   Range file_ids;
811   ErrorCode rval = get_subset_ids(subset_list, subset_list_length, file_ids);
812   if (MB_SUCCESS != rval)
813     MB_SET_ERR(rval, "ReadHDF5 Failure");
814 
815   if (cputime)
816     _times[SUBSET_IDS_TIME] = timer->time_elapsed();
817 
818   if (num_parts) {
819     if (num_parts>(int)file_ids.size())
820     {
821       MB_SET_ERR(MB_FAILURE, "Only " << file_ids.size() << " parts to distribute to " << num_parts << " processes.");
822     }
823     rval = get_partition(file_ids, num_parts, part_number);
824     if (MB_SUCCESS != rval)
825       MB_SET_ERR(rval, "ReadHDF5 Failure");
826   }
827 
828   if (cputime)
829     _times[GET_PARTITION_TIME] = timer->time_elapsed();
830 
831   dbgOut.print_ints(4, "Set file IDs for partial read: ", file_ids);
832   mpe_event.end();
833   mpe_event.start("gather related sets");
834   dbgOut.tprint(1, "GATHERING ADDITIONAL ENTITIES\n");
835 
836   enum RecusiveSetMode {RSM_NONE, RSM_SETS, RSM_CONTENTS};
837   const char* const set_opts[] = {"NONE", "SETS", "CONTENTS", NULL};
838   int child_mode;
839   rval = opts.match_option("CHILDREN", set_opts, child_mode);
840   if (MB_ENTITY_NOT_FOUND == rval)
841     child_mode = RSM_CONTENTS;
842   else if (MB_SUCCESS != rval) {
843     MB_SET_ERR(rval, "Invalid value for 'CHILDREN' option");
844   }
845   int content_mode;
846   rval = opts.match_option("SETS", set_opts, content_mode);
847   if (MB_ENTITY_NOT_FOUND == rval)
848     content_mode = RSM_CONTENTS;
849   else if (MB_SUCCESS != rval) {
850     MB_SET_ERR(rval, "Invalid value for 'SETS' option");
851   }
852 
853   // If we want the contents of contained/child sets,
854   // search for them now (before gathering the non-set contents
855   // of the sets.)
856   Range sets;
857   intersect(fileInfo->sets, file_ids, sets);
858   if (content_mode == RSM_CONTENTS || child_mode == RSM_CONTENTS) {
859     dbgOut.tprint(1, "  doing read_set_ids_recursive\n");
860     rval = read_set_ids_recursive(sets, content_mode == RSM_CONTENTS, child_mode == RSM_CONTENTS);
861     if (MB_SUCCESS != rval)
862       MB_SET_ERR(rval, "ReadHDF5 Failure");
863   }
864 
865   if (cputime)
866     _times[GET_SET_IDS_TIME] = timer->time_elapsed();
867   debug_barrier();
868 
869   // Get elements and vertices contained in sets
870   dbgOut.tprint(1, "  doing get_set_contents\n");
871   rval = get_set_contents(sets, file_ids);
872   if (MB_SUCCESS != rval)
873     MB_SET_ERR(rval, "ReadHDF5 Failure");
874 
875   if (cputime)
876     _times[GET_SET_CONTENTS_TIME] = timer->time_elapsed();
877 
878   dbgOut.print_ints(5, "File IDs for partial read: ", file_ids);
879   debug_barrier();
880   mpe_event.end();
881   dbgOut.tprint(1, "GATHERING NODE IDS\n");
882 
883   // Figure out the maximum dimension of entity to be read
884   int max_dim = 0;
885   for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
886     EntityType type = CN::EntityTypeFromName(fileInfo->elems[i].type);
887     if (type <= MBVERTEX || type >= MBENTITYSET) {
888       assert(false); // For debug code die for unknown element types
889       continue; // For release code, skip unknown element types
890     }
891     int dim = CN::Dimension(type);
892     if (dim > max_dim) {
893       Range subset;
894       intersect(fileInfo->elems[i].desc, file_ids, subset);
895       if (!subset.empty())
896         max_dim = dim;
897     }
898   }
899 #ifdef MOAB_HAVE_MPI
900   if (nativeParallel) {
901     int send = max_dim;
902     MPI_Allreduce(&send, &max_dim, 1, MPI_INT, MPI_MAX, *mpiComm);
903   }
904 #endif
905 
906   // If input contained any polyhedra, then need to get faces
907   // of the polyhedra before the next loop because we need to
908   // read said faces in that loop.
909   for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
910     EntityType type = CN::EntityTypeFromName(fileInfo->elems[i].type);
911     if (type != MBPOLYHEDRON)
912       continue;
913 
914     debug_barrier();
915     dbgOut.print(2, "    Getting polyhedra faces\n");
916     mpe_event.start("reading connectivity for ", fileInfo->elems[i].handle);
917 
918     Range polyhedra;
919     intersect(fileInfo->elems[i].desc, file_ids, polyhedra);
920     rval = read_elems(i, polyhedra, &file_ids);
921     mpe_event.end(rval);
922     if (MB_SUCCESS != rval)
923       MB_SET_ERR(rval, "ReadHDF5 Failure");
924   }
925 
926   if (cputime)
927     _times[GET_POLYHEDRA_TIME] = timer->time_elapsed();
928   // Get node file ids for all elements
929   Range nodes;
930   intersect(fileInfo->nodes, file_ids, nodes);
931   for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
932     EntityType type = CN::EntityTypeFromName(fileInfo->elems[i].type);
933     if (type <= MBVERTEX || type >= MBENTITYSET) {
934       assert(false); // For debug code die for unknown element types
935       continue; // For release code, skip unknown element types
936     }
937     if (MBPOLYHEDRON == type)
938       continue;
939 
940     debug_barrier();
941     dbgOut.printf(2, "    Getting element node IDs for: %s\n", fileInfo->elems[i].handle);
942 
943     Range subset;
944     intersect(fileInfo->elems[i].desc, file_ids, subset);
945     mpe_event.start("reading connectivity for ", fileInfo->elems[i].handle);
946 
947     // If dimension is max_dim, then we can create the elements now
948     // so we don't have to read the table again later (connectivity
949     // will be fixed up after nodes are created when update_connectivity())
950     // is called.  For elements of a smaller dimension, we just build
951     // the node ID range now because a) we'll have to read the whole
952     // connectivity table again later, and b) we don't want to worry
953     // about accidentally creating multiple copies of the same element.
954     if (CN::Dimension(type) == max_dim)
955       rval = read_elems(i, subset, &nodes);
956     else
957       rval = read_elems(i, subset, nodes);
958     mpe_event.end(rval);
959     if (MB_SUCCESS != rval)
960       MB_SET_ERR(rval, "ReadHDF5 Failure");
961   }
962   if (cputime)
963     _times[GET_ELEMENTS_TIME] = timer->time_elapsed();
964   debug_barrier();
965   mpe_event.start("read coords");
966   dbgOut.tprintf(1, "READING NODE COORDINATES (%lu nodes in %lu selects)\n",
967                      (unsigned long)nodes.size(), (unsigned long)nodes.psize());
968 
969   // Read node coordinates and create vertices in MOAB
970   // NOTE: This populates the RangeMap with node file ids,
971   //       which is expected by read_node_adj_elems.
972   rval = read_nodes(nodes);
973   mpe_event.end(rval);
974   if (MB_SUCCESS != rval)
975     MB_SET_ERR(rval, "ReadHDF5 Failure");
976 
977   if (cputime)
978     _times[GET_NODES_TIME] = timer->time_elapsed();
979 
980   debug_barrier();
981   dbgOut.tprint(1, "READING ELEMENTS\n");
982 
983   // Decide if we need to read additional elements
984   enum SideMode {SM_EXPLICIT, SM_NODES, SM_SIDES};
985   int side_mode;
986   const char* const options[] = {"EXPLICIT", "NODES", "SIDES", 0};
987   rval = opts.match_option("ELEMENTS", options, side_mode);
988   if (MB_ENTITY_NOT_FOUND == rval) {
989     // If only nodes were specified, then default to "NODES", otherwise
990     // default to "SIDES".
991     if (0 == max_dim)
992       side_mode = SM_NODES;
993     else
994       side_mode = SM_SIDES;
995   }
996   else if (MB_SUCCESS != rval) {
997     MB_SET_ERR(rval, "Invalid value for 'ELEMENTS' option");
998   }
999 
1000   if (side_mode == SM_SIDES /*ELEMENTS=SIDES*/ && max_dim == 0 /*node-based*/) {
1001     // Read elements until we find something. Once we find something,
1002     // read only elements of the same dimension. NOTE: loop termination
1003     // criterion changes on both sides (max_dim can be changed in loop
1004     // body).
1005     for (int dim = 3; dim >= max_dim; --dim) {
1006       for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
1007         EntityType type = CN::EntityTypeFromName(fileInfo->elems[i].type);
1008         if (CN::Dimension(type) == dim) {
1009           debug_barrier();
1010           dbgOut.tprintf(2, "    Reading node-adjacent elements for: %s\n", fileInfo->elems[i].handle);
1011           mpe_event.start("reading connectivity for ", fileInfo->elems[i].handle);
1012           Range ents;
1013           rval = read_node_adj_elems(fileInfo->elems[i]);
1014           mpe_event.end(rval);
1015           if (MB_SUCCESS != rval)
1016             MB_SET_ERR(rval, "ReadHDF5 Failure");
1017           if (!ents.empty())
1018             max_dim = 3;
1019         }
1020       }
1021     }
1022   }
1023 
1024   if (cputime)
1025     _times[GET_NODEADJ_TIME] = timer->time_elapsed();
1026   Range side_entities;
1027   if (side_mode != SM_EXPLICIT /*ELEMENTS=NODES || ELEMENTS=SIDES*/) {
1028     if (0 == max_dim)
1029       max_dim = 4;
1030     // Now read any additional elements for which we've already read all
1031     // of the nodes.
1032     for (int dim = max_dim - 1; dim > 0; --dim) {
1033       for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
1034         EntityType type = CN::EntityTypeFromName(fileInfo->elems[i].type);
1035         if (CN::Dimension(type) == dim) {
1036           debug_barrier();
1037           dbgOut.tprintf(2, "    Reading node-adjacent elements for: %s\n", fileInfo->elems[i].handle);
1038           mpe_event.start("reading connectivity for ", fileInfo->elems[i].handle);
1039           rval = read_node_adj_elems(fileInfo->elems[i], &side_entities);
1040           mpe_event.end(rval);
1041           if (MB_SUCCESS != rval)
1042             MB_SET_ERR(rval, "ReadHDF5 Failure");
1043         }
1044       }
1045     }
1046   }
1047 
1048   // We need to do this here for polyhedra to be handled correctly.
1049   // We have to wait until the faces are read in the above code block,
1050   // but need to create the connectivity before doing update_connectivity,
1051   // which might otherwise delete polyhedra faces.
1052   if (cputime)
1053    _times[GET_SIDEELEM_TIME] = timer->time_elapsed();
1054 
1055   debug_barrier();
1056   dbgOut.tprint(1, "UPDATING CONNECTIVITY ARRAYS FOR READ ELEMENTS\n");
1057   mpe_event.start("updating connectivity for elements read before vertices");
1058   rval = update_connectivity();
1059   mpe_event.end();
1060   if (MB_SUCCESS != rval)
1061     MB_SET_ERR(rval, "ReadHDF5 Failure");
1062 
1063   if (cputime)
1064    _times[UPDATECONN_TIME] = timer->time_elapsed();
1065 
1066   dbgOut.tprint(1, "READING ADJACENCIES\n");
1067   for (int i = 0; i < fileInfo->num_elem_desc; ++i) {
1068     if (fileInfo->elems[i].have_adj  /*&&
1069         idMap.intersects(fileInfo->elems[i].desc.start_id, fileInfo->elems[i].desc.count) */) {
1070       mpe_event.start("reading adjacencies for ", fileInfo->elems[i].handle);
1071       long len;
1072       hid_t th = mhdf_openAdjacency(filePtr, fileInfo->elems[i].handle, &len, &status);
1073       if (is_error(status))
1074         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1075 
1076       rval = read_adjacencies(th, len);
1077       mhdf_closeData(filePtr, th, &status);
1078       mpe_event.end(rval);
1079       if (MB_SUCCESS != rval)
1080         MB_SET_ERR(rval, "ReadHDF5 Failure");
1081     }
1082   }
1083 
1084   if (cputime)
1085    _times[ADJACENCY_TIME] = timer->time_elapsed();
1086 
1087   // If doing ELEMENTS=SIDES then we need to delete any entities
1088   // that we read that aren't actually sides (e.g. an interior face
1089   // that connects two disjoint portions of the part). Both
1090   // update_connectivity and reading of any explicit adjacencies must
1091   // happen before this.
1092   if (side_mode == SM_SIDES) {
1093     debug_barrier();
1094     mpe_event.start("cleaning up non-side lower-dim elements");
1095     dbgOut.tprint(1, "CHECKING FOR AND DELETING NON-SIDE ELEMENTS\n");
1096     rval = delete_non_side_elements(side_entities);
1097     mpe_event.end(rval);
1098     if (MB_SUCCESS != rval)
1099       MB_SET_ERR(rval, "ReadHDF5 Failure");
1100   }
1101 
1102   if (cputime)
1103    _times[DELETE_NON_SIDEELEM_TIME] = timer->time_elapsed();
1104 
1105   debug_barrier();
1106   dbgOut.tprint(1, "READING SETS\n");
1107 
1108   // If reading contained/child sets but not their contents then find
1109   // them now. If we were also reading their contents we would
1110   // have found them already.
1111   if (content_mode == RSM_SETS || child_mode == RSM_SETS) {
1112     dbgOut.tprint(1, "  doing read_set_ids_recursive\n");
1113     mpe_event.start("finding recursively contained sets");
1114     rval = read_set_ids_recursive(sets, content_mode == RSM_SETS, child_mode == RSM_SETS);
1115     mpe_event.end(rval);
1116     if (MB_SUCCESS != rval)
1117       MB_SET_ERR(rval, "ReadHDF5 Failure");
1118   }
1119 
1120   if (cputime)
1121    _times[READ_SET_IDS_RECURS_TIME] = timer->time_elapsed();
1122 
1123   dbgOut.tprint(1, "  doing find_sets_containing\n");
1124   mpe_event.start("finding sets containing any read entities");
1125 
1126   // Decide whether to read set-containing parents
1127   bool read_set_containing_parents = true;
1128   std::string tmp_opt;
1129   rval = opts.get_option("NO_SET_CONTAINING_PARENTS", tmp_opt);
1130   if (MB_SUCCESS == rval)
1131     read_set_containing_parents = false;
1132 
1133   // Append file IDs of sets containing any of the nodes or elements
1134   // we've read up to this point.
1135   rval = find_sets_containing(sets, read_set_containing_parents);
1136   mpe_event.end(rval);
1137   if (MB_SUCCESS != rval)
1138     MB_SET_ERR(rval, "ReadHDF5 Failure");
1139 
1140   if (cputime)
1141      _times[FIND_SETS_CONTAINING_TIME] = timer->time_elapsed();
1142 
1143   // Now actually read all set data and instantiate sets in MOAB.
1144   // Get any contained sets out of file_ids.
1145   mpe_event.start("reading set contents/parents/children");
1146   EntityHandle first_set = fileInfo->sets.start_id;
1147   sets.merge(file_ids.lower_bound(first_set),
1148              file_ids.lower_bound(first_set + fileInfo->sets.count));
1149   dbgOut.tprint(1, "  doing read_sets\n");
1150   rval = read_sets(sets);
1151   mpe_event.end(rval);
1152   if (MB_SUCCESS != rval)
1153     MB_SET_ERR(rval, "ReadHDF5 Failure");
1154 
1155   if (cputime)
1156    _times[READ_SETS_TIME] = timer->time_elapsed();
1157 
1158   dbgOut.tprint(1, "READING TAGS\n");
1159 
1160   for (int i = 0; i < fileInfo->num_tag_desc; ++i) {
1161     mpe_event.start("reading tag: ", fileInfo->tags[i].name);
1162     rval = read_tag(i);
1163     if (MB_SUCCESS != rval)
1164       MB_SET_ERR(rval, "ReadHDF5 Failure");
1165   }
1166 
1167   if (cputime)
1168    _times[READ_TAGS_TIME] = timer->time_elapsed();
1169 
1170   dbgOut.tprint(1, "PARTIAL READ COMPLETE.\n");
1171 
1172   return MB_SUCCESS;
1173 }
1174 
search_tag_values(int tag_index,const std::vector<int> & sorted_values,Range & file_ids,bool sets_only)1175 ErrorCode ReadHDF5::search_tag_values(int tag_index,
1176                                       const std::vector<int>& sorted_values,
1177                                       Range& file_ids,
1178                                       bool sets_only)
1179 {
1180   ErrorCode rval;
1181   mhdf_Status status;
1182   std::vector<EntityHandle>::iterator iter;
1183   const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
1184   long size;
1185   long start_id;
1186 
1187   CHECK_OPEN_HANDLES;
1188 
1189   debug_barrier();
1190 
1191   // Do dense data
1192 
1193   hid_t table;
1194   const char* name;
1195   std::vector<EntityHandle> indices;
1196   // These are probably in order of dimension, so iterate
1197   // in reverse order to make Range insertions more efficient.
1198   std::vector<int> grp_indices(tag.dense_elem_indices, tag.dense_elem_indices + tag.num_dense_indices);
1199   for (std::vector<int>::reverse_iterator i = grp_indices.rbegin(); i != grp_indices.rend(); ++i) {
1200     int idx = *i;
1201     if (idx == -2) {
1202       name = mhdf_set_type_handle();
1203       start_id = fileInfo->sets.start_id;
1204     }
1205     else if (sets_only) {
1206       continue;
1207     }
1208     else if (idx == -1) {
1209       name = mhdf_node_type_handle();
1210      start_id = fileInfo->nodes.start_id;
1211     }
1212     else {
1213       if (idx < 0 || idx >= fileInfo->num_elem_desc)
1214         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1215       name = fileInfo->elems[idx].handle;
1216       start_id = fileInfo->elems[idx].desc.start_id;
1217     }
1218     table = mhdf_openDenseTagData(filePtr, tag.name, name, &size, &status);
1219     if (is_error(status))
1220       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1221     rval = search_tag_values(table, size, sorted_values, indices);
1222     mhdf_closeData(filePtr, table, &status);
1223     if (MB_SUCCESS != rval || is_error(status))
1224       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1225     // Convert from table indices to file IDs and add to result list
1226     std::sort(indices.begin(), indices.end(), std::greater<EntityHandle>());
1227     std::transform(indices.begin(), indices.end(), range_inserter(file_ids),
1228                    std::bind1st(std::plus<long>(), start_id));
1229     indices.clear();
1230   }
1231 
1232   if (!tag.have_sparse)
1233     return MB_SUCCESS;
1234 
1235   // Do sparse data
1236 
1237   hid_t tables[2];
1238   long junk; // Redundant value for non-variable-length tags
1239   mhdf_openSparseTagData(filePtr, tag.name, &size, &junk, tables, &status);
1240   if (is_error(status))
1241     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1242   rval = search_tag_values(tables[1], size, sorted_values, indices);
1243   mhdf_closeData(filePtr, tables[1], &status);
1244   if (MB_SUCCESS != rval || is_error(status)) {
1245     mhdf_closeData(filePtr, tables[0], &status);
1246     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1247   }
1248   // Convert to ranges
1249   std::sort(indices.begin(), indices.end());
1250   std::vector<EntityHandle> ranges;
1251   iter = indices.begin();
1252   while (iter != indices.end()) {
1253     ranges.push_back(*iter);
1254     EntityHandle last = *iter;
1255     for (++iter; iter != indices.end() && (last + 1) == *iter; ++iter, ++last);
1256     ranges.push_back(last);
1257   }
1258   // Read file ids
1259   iter = ranges.begin();
1260   unsigned long offset = 0;
1261   while (iter != ranges.end()) {
1262     long begin = *iter; ++iter;
1263     long end   = *iter; ++iter;
1264     mhdf_readSparseTagEntitiesWithOpt(tables[0], begin, end - begin + 1,
1265                                       handleType, &indices[offset], indepIO, &status);
1266     if (is_error(status)) {
1267       mhdf_closeData(filePtr, tables[0], &status);
1268       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1269     }
1270     offset += end - begin + 1;
1271   }
1272   mhdf_closeData(filePtr, tables[0], &status);
1273   if (is_error(status))
1274     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1275   assert(offset == indices.size());
1276   std::sort(indices.begin(), indices.end());
1277 
1278   if (sets_only) {
1279     iter = std::lower_bound(indices.begin(), indices.end(),
1280               (EntityHandle)(fileInfo->sets.start_id + fileInfo->sets.count));
1281     indices.erase(iter, indices.end());
1282     iter = std::lower_bound(indices.begin(), indices.end(),
1283                             fileInfo->sets.start_id);
1284     indices.erase(indices.begin(), iter);
1285   }
1286   copy_sorted_file_ids(&indices[0], indices.size(), file_ids);
1287 
1288   return MB_SUCCESS;
1289 }
1290 
get_tagged_entities(int tag_index,Range & file_ids)1291 ErrorCode ReadHDF5::get_tagged_entities(int tag_index, Range& file_ids)
1292 {
1293   const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
1294 
1295   CHECK_OPEN_HANDLES;
1296 
1297   // Do dense data
1298   Range::iterator hint = file_ids.begin();
1299   for (int i = 0; i < tag.num_dense_indices; ++i) {
1300     int idx = tag.dense_elem_indices[i];
1301     mhdf_EntDesc* ents;
1302     if (idx == -2)
1303       ents = &fileInfo->sets;
1304     else if (idx == -1)
1305       ents = &fileInfo->nodes;
1306     else {
1307       if (idx < 0 || idx >= fileInfo->num_elem_desc)
1308         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1309       ents = &(fileInfo->elems[idx].desc);
1310     }
1311 
1312     EntityHandle h = (EntityHandle)ents->start_id;
1313     hint = file_ids.insert(hint, h, h + ents->count - 1);
1314   }
1315 
1316   if (!tag.have_sparse)
1317     return MB_SUCCESS;
1318 
1319   // Do sparse data
1320 
1321   mhdf_Status status;
1322   hid_t tables[2];
1323   long size, junk;
1324   mhdf_openSparseTagData(filePtr, tag.name, &size, &junk, tables, &status);
1325   if (is_error(status))
1326     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1327   mhdf_closeData(filePtr, tables[1], &status);
1328   if (is_error(status)) {
1329     mhdf_closeData(filePtr, tables[0], &status);
1330     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1331   }
1332 
1333   hid_t file_type = H5Dget_type(tables[0]);
1334   if (file_type < 0)
1335     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1336 
1337   hint = file_ids.begin();
1338   EntityHandle* buffer = reinterpret_cast<EntityHandle*>(dataBuffer);
1339   const long buffer_size = bufferSize / std::max(sizeof(EntityHandle), H5Tget_size(file_type));
1340   long remaining = size, offset = 0;
1341   while (remaining) {
1342     long count = std::min(buffer_size, remaining);
1343     assert_range(buffer, count);
1344     mhdf_readSparseTagEntitiesWithOpt(*tables, offset, count,
1345                                       file_type, buffer, collIO, &status);
1346     if (is_error(status)) {
1347       H5Tclose(file_type);
1348       mhdf_closeData(filePtr, *tables, &status);
1349       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1350     }
1351     H5Tconvert(file_type, handleType, count, buffer, NULL, H5P_DEFAULT);
1352 
1353     std::sort(buffer, buffer + count);
1354     for (long i = 0; i < count; ++i)
1355       hint = file_ids.insert(hint, buffer[i], buffer[i]);
1356 
1357     remaining -= count;
1358     offset += count;
1359   }
1360 
1361   H5Tclose(file_type);
1362   mhdf_closeData(filePtr, *tables, &status);
1363   if (is_error(status))
1364     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1365 
1366   return MB_SUCCESS;
1367 }
1368 
search_tag_values(hid_t tag_table,unsigned long table_size,const std::vector<int> & sorted_values,std::vector<EntityHandle> & value_indices)1369 ErrorCode ReadHDF5::search_tag_values(hid_t tag_table,
1370                                       unsigned long table_size,
1371                                       const std::vector<int>& sorted_values,
1372                                       std::vector<EntityHandle>& value_indices)
1373 {
1374   debug_barrier();
1375 
1376   CHECK_OPEN_HANDLES;
1377 
1378   mhdf_Status status;
1379   size_t chunk_size = bufferSize / sizeof(int);
1380   int * buffer = reinterpret_cast<int*>(dataBuffer);
1381   size_t remaining = table_size, offset = 0;
1382   while (remaining) {
1383     // Get a block of tag values
1384     size_t count = std::min(chunk_size, remaining);
1385     assert_range(buffer, count);
1386     mhdf_readTagValuesWithOpt(tag_table, offset, count, H5T_NATIVE_INT, buffer, collIO, &status);
1387     if (is_error(status))
1388       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1389 
1390     // Search tag values
1391     for (size_t i = 0; i < count; ++i)
1392       if (std::binary_search(sorted_values.begin(), sorted_values.end(), (int)buffer[i]))
1393         value_indices.push_back(i + offset);
1394 
1395     offset += count;
1396     remaining -= count;
1397   }
1398 
1399   return MB_SUCCESS;
1400 }
1401 
read_nodes(const Range & node_file_ids)1402 ErrorCode ReadHDF5::read_nodes(const Range& node_file_ids)
1403 {
1404   ErrorCode rval;
1405   mhdf_Status status;
1406   const int dim = fileInfo->nodes.vals_per_ent;
1407   Range range;
1408 
1409   CHECK_OPEN_HANDLES;
1410 
1411   if (node_file_ids.empty())
1412     return MB_SUCCESS;
1413 
1414   int cdim;
1415   rval = iFace->get_dimension(cdim);
1416   if (MB_SUCCESS != rval)
1417     MB_SET_ERR(rval, "ReadHDF5 Failure");
1418 
1419   if (cdim < dim) {
1420     rval = iFace->set_dimension(dim);
1421     if (MB_SUCCESS != rval)
1422       MB_SET_ERR(rval, "ReadHDF5 Failure");
1423   }
1424 
1425   hid_t data_id = mhdf_openNodeCoordsSimple(filePtr, &status);
1426   if (is_error(status))
1427     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1428 
1429   EntityHandle handle;
1430   std::vector<double*> arrays(dim);
1431   const size_t num_nodes = node_file_ids.size();
1432   rval = readUtil->get_node_coords(dim, (int)num_nodes, 0, handle, arrays);
1433   if (MB_SUCCESS != rval) {
1434     mhdf_closeData(filePtr, data_id, &status);
1435     MB_SET_ERR(rval, "ReadHDF5 Failure");
1436   }
1437 
1438   if (blockedCoordinateIO) {
1439     try {
1440       for (int d = 0; d < dim; ++d) {
1441         ReadHDF5Dataset reader("blocked coords", data_id, nativeParallel, mpiComm, false);
1442         reader.set_column(d);
1443         reader.set_file_ids(node_file_ids, fileInfo->nodes.start_id, num_nodes, H5T_NATIVE_DOUBLE);
1444         dbgOut.printf(3, "Reading %lu chunks for coordinate dimension %d\n", reader.get_read_count(), d);
1445         // Should normally only have one read call, unless sparse nature
1446         // of file_ids caused reader to do something strange
1447         size_t count, offset = 0;
1448         int nn = 0;
1449         while (!reader.done()) {
1450           dbgOut.printf(3, "Reading chunk %d for dimension %d\n", ++nn, d);
1451           reader.read(arrays[d] + offset, count);
1452           offset += count;
1453         }
1454         if (offset != num_nodes) {
1455           mhdf_closeData(filePtr, data_id, &status);
1456           assert(false);
1457           return MB_FAILURE;
1458         }
1459       }
1460     }
1461     catch (ReadHDF5Dataset::Exception) {
1462       mhdf_closeData(filePtr, data_id, &status);
1463       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1464     }
1465   }
1466   else { // !blockedCoordinateIO
1467     double* buffer = (double*)dataBuffer;
1468     long chunk_size = bufferSize / (3 * sizeof(double));
1469     long coffset = 0;
1470     int nn = 0;
1471     try {
1472       ReadHDF5Dataset reader("interleaved coords", data_id, nativeParallel, mpiComm, false);
1473       reader.set_file_ids(node_file_ids, fileInfo->nodes.start_id, chunk_size, H5T_NATIVE_DOUBLE);
1474       dbgOut.printf(3, "Reading %lu chunks for coordinate coordinates\n", reader.get_read_count());
1475       while (!reader.done()) {
1476         dbgOut.tprintf(3, "Reading chunk %d of node coords\n", ++nn);
1477 
1478         size_t count;
1479         reader.read(buffer, count);
1480 
1481         for (size_t i = 0; i < count; ++i)
1482           for (int d = 0; d < dim; ++d)
1483             arrays[d][coffset + i] = buffer[dim*i + d];
1484         coffset += count;
1485       }
1486     }
1487     catch (ReadHDF5Dataset::Exception) {
1488       mhdf_closeData(filePtr, data_id, &status);
1489       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1490     }
1491   }
1492 
1493   dbgOut.print(3, "Closing node coordinate table\n");
1494   mhdf_closeData(filePtr, data_id, &status);
1495   for (int d = dim; d < cdim; ++d)
1496     memset(arrays[d], 0, num_nodes * sizeof(double));
1497 
1498   dbgOut.printf(3, "Updating ID to handle map for %lu nodes\n", (unsigned long)node_file_ids.size());
1499   return insert_in_id_map(node_file_ids, handle);
1500 }
1501 
read_elems(int i)1502 ErrorCode ReadHDF5::read_elems(int i)
1503 {
1504   Range ids;
1505   ids.insert(fileInfo->elems[i].desc.start_id,
1506              fileInfo->elems[i].desc.start_id + fileInfo->elems[i].desc.count - 1);
1507   return read_elems(i, ids);
1508 }
1509 
read_elems(int i,const Range & file_ids,Range * node_ids)1510 ErrorCode ReadHDF5::read_elems(int i, const Range& file_ids, Range* node_ids)
1511 {
1512   if (fileInfo->elems[i].desc.vals_per_ent < 0) {
1513     if (node_ids != 0) // Not implemented for version 3 format of poly data
1514       MB_CHK_ERR(MB_TYPE_OUT_OF_RANGE);
1515     return read_poly(fileInfo->elems[i], file_ids);
1516   }
1517   else
1518     return read_elems(fileInfo->elems[i], file_ids, node_ids);
1519 }
1520 
read_elems(const mhdf_ElemDesc & elems,const Range & file_ids,Range * node_ids)1521 ErrorCode ReadHDF5::read_elems(const mhdf_ElemDesc& elems, const Range& file_ids, Range* node_ids)
1522 {
1523   CHECK_OPEN_HANDLES;
1524 
1525   debug_barrier();
1526   dbgOut.tprintf(1, "READING %s CONNECTIVITY (%lu elems in %lu selects)\n",
1527                  elems.handle, (unsigned long)file_ids.size(), (unsigned long)file_ids.psize());
1528 
1529   ErrorCode rval = MB_SUCCESS;
1530   mhdf_Status status;
1531 
1532   EntityType type = CN::EntityTypeFromName(elems.type);
1533   if (type == MBMAXTYPE) {
1534     MB_SET_ERR(MB_FAILURE, "Unknown element type: \"" << elems.type << "\"");
1535   }
1536 
1537   const int nodes_per_elem = elems.desc.vals_per_ent;
1538   const size_t count = file_ids.size();
1539   hid_t data_id = mhdf_openConnectivitySimple(filePtr, elems.handle, &status);
1540   if (is_error(status))
1541     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1542 
1543   EntityHandle handle;
1544   EntityHandle* array = 0;
1545   if (count > 0)
1546     rval = readUtil->get_element_connect(count, nodes_per_elem, type,
1547                                          0, handle, array);
1548   if (MB_SUCCESS != rval)
1549     MB_SET_ERR(rval, "ReadHDF5 Failure");
1550 
1551   try {
1552     EntityHandle* buffer = reinterpret_cast<EntityHandle*>(dataBuffer);
1553     const size_t buffer_size = bufferSize / (sizeof(EntityHandle) * nodes_per_elem);
1554     ReadHDF5Dataset reader(elems.handle, data_id, nativeParallel, mpiComm);
1555     reader.set_file_ids(file_ids, elems.desc.start_id, buffer_size, handleType);
1556     dbgOut.printf(3, "Reading connectivity in %lu chunks for element group \"%s\"\n",
1557                   reader.get_read_count(), elems.handle);
1558     EntityHandle* iter = array;
1559     int nn = 0;
1560     while (!reader.done()) {
1561       dbgOut.printf(3, "Reading chunk %d for \"%s\"\n", ++nn, elems.handle);
1562 
1563       size_t num_read;
1564       reader.read(buffer, num_read);
1565       iter = std::copy(buffer, buffer + num_read*nodes_per_elem, iter);
1566 
1567       if (node_ids) {
1568         std::sort(buffer, buffer + num_read*nodes_per_elem);
1569         num_read = std::unique(buffer, buffer + num_read*nodes_per_elem) - buffer;
1570         copy_sorted_file_ids(buffer, num_read, *node_ids);
1571       }
1572     }
1573     assert(iter - array == (ptrdiff_t)count * nodes_per_elem);
1574   }
1575   catch (ReadHDF5Dataset::Exception) {
1576     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1577   }
1578 
1579   if (!node_ids) {
1580     rval = convert_id_to_handle(array, count * nodes_per_elem);
1581     if (MB_SUCCESS != rval)
1582       MB_SET_ERR(rval, "ReadHDF5 Failure");
1583 
1584     rval = readUtil->update_adjacencies(handle, count, nodes_per_elem, array);
1585     if (MB_SUCCESS != rval)
1586       MB_SET_ERR(rval, "ReadHDF5 Failure");
1587   }
1588   else {
1589     IDConnectivity t;
1590     t.handle = handle;
1591     t.count = count;
1592     t.nodes_per_elem = nodes_per_elem;
1593     t.array = array;
1594     idConnectivityList.push_back(t);
1595   }
1596 
1597   return insert_in_id_map(file_ids, handle);
1598 }
1599 
update_connectivity()1600 ErrorCode ReadHDF5::update_connectivity()
1601 {
1602   ErrorCode rval;
1603   std::vector<IDConnectivity>::iterator i;
1604   for (i = idConnectivityList.begin(); i != idConnectivityList.end(); ++i) {
1605     rval = convert_id_to_handle(i->array, i->count * i->nodes_per_elem);
1606     if (MB_SUCCESS != rval)
1607       MB_SET_ERR(rval, "ReadHDF5 Failure");
1608 
1609     rval = readUtil->update_adjacencies(i->handle, i->count, i->nodes_per_elem, i->array);
1610     if (MB_SUCCESS != rval)
1611       MB_SET_ERR(rval, "ReadHDF5 Failure");
1612   }
1613   idConnectivityList.clear();
1614 
1615   return MB_SUCCESS;
1616 }
1617 
read_node_adj_elems(const mhdf_ElemDesc & group,Range * handles_out)1618 ErrorCode ReadHDF5::read_node_adj_elems(const mhdf_ElemDesc& group, Range* handles_out)
1619 {
1620   mhdf_Status status;
1621   ErrorCode rval;
1622 
1623   CHECK_OPEN_HANDLES;
1624 
1625   hid_t table = mhdf_openConnectivitySimple(filePtr, group.handle, &status);
1626   if (is_error(status))
1627     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1628 
1629   rval = read_node_adj_elems(group, table, handles_out);
1630 
1631   mhdf_closeData(filePtr, table, &status);
1632   if (MB_SUCCESS == rval && is_error(status))
1633     MB_SET_ERR_RET_VAL("ReadHDF5 Failure", MB_FAILURE);
1634 
1635   return rval;
1636 }
1637 
read_node_adj_elems(const mhdf_ElemDesc & group,hid_t table_handle,Range * handles_out)1638 ErrorCode ReadHDF5::read_node_adj_elems(const mhdf_ElemDesc& group,
1639                                         hid_t table_handle,
1640                                         Range* handles_out)
1641 {
1642   CHECK_OPEN_HANDLES;
1643 
1644   debug_barrier();
1645 
1646   mhdf_Status status;
1647   ErrorCode rval;
1648   IODebugTrack debug_track(debugTrack, std::string(group.handle));
1649 
1650   // Copy data to local variables (makes other code clearer)
1651   const int node_per_elem = group.desc.vals_per_ent;
1652   long start_id = group.desc.start_id;
1653   long remaining = group.desc.count;
1654   const EntityType type = CN::EntityTypeFromName(group.type);
1655 
1656   // Figure out how many elements we can read in each pass
1657   long* const buffer = reinterpret_cast<long*>(dataBuffer);
1658   const long buffer_size = bufferSize / (node_per_elem * sizeof(buffer[0]));
1659   // Read all element connectivity in buffer_size blocks
1660   long offset = 0;
1661   dbgOut.printf(3, "Reading node-adjacent elements from \"%s\" in %ld chunks\n",
1662                 group.handle, (remaining + buffer_size - 1) / buffer_size);
1663   int nn = 0;
1664   Range::iterator hint;
1665   if (handles_out)
1666     hint = handles_out->begin();
1667   while (remaining) {
1668     dbgOut.printf(3, "Reading chunk %d of connectivity data for \"%s\"\n", ++nn, group.handle);
1669 
1670     // Read a block of connectivity data
1671     const long count = std::min(remaining, buffer_size);
1672     debug_track.record_io(offset, count);
1673     assert_range(buffer, count * node_per_elem);
1674     mhdf_readConnectivityWithOpt(table_handle, offset, count, H5T_NATIVE_LONG, buffer, collIO, &status);
1675     if (is_error(status))
1676       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1677     offset += count;
1678     remaining -= count;
1679 
1680     // Count the number of elements in the block that we want,
1681     // zero connectivity for other elements
1682     long num_elem = 0;
1683     long* iter = buffer;
1684     for (long i = 0; i < count; ++i) {
1685       for (int j = 0; j < node_per_elem; ++j) {
1686         iter[j] = (long)idMap.find(iter[j]);
1687         if (!iter[j]) {
1688           iter[0] = 0;
1689           break;
1690         }
1691       }
1692       if (iter[0])
1693         ++num_elem;
1694       iter += node_per_elem;
1695     }
1696 
1697     if (!num_elem) {
1698       start_id += count;
1699       continue;
1700     }
1701 
1702     // Create elements
1703     EntityHandle handle;
1704     EntityHandle* array;
1705     rval = readUtil->get_element_connect((int)num_elem,
1706                                          node_per_elem,
1707                                          type,
1708                                          0,
1709                                          handle,
1710                                          array);
1711     if (MB_SUCCESS != rval)
1712       MB_SET_ERR(rval, "ReadHDF5 Failure");
1713 
1714     // Copy all non-zero connectivity values
1715     iter = buffer;
1716     EntityHandle* iter2 = array;
1717     EntityHandle h = handle;
1718     for (long i = 0; i < count; ++i) {
1719       if (!*iter) {
1720         iter += node_per_elem;
1721         continue;
1722       }
1723       if (!idMap.insert(start_id + i, h++, 1).second)
1724         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1725 
1726       long* const end = iter + node_per_elem;
1727       for ( ; iter != end; ++iter, ++iter2)
1728         *iter2 = (EntityHandle)*iter;
1729     }
1730     assert(iter2 - array == num_elem * node_per_elem);
1731     start_id += count;
1732 
1733     rval = readUtil->update_adjacencies(handle, num_elem, node_per_elem, array);
1734     if (MB_SUCCESS != rval)
1735       MB_SET_ERR(rval, "ReadHDF5 Failure");
1736     if (handles_out)
1737       hint = handles_out->insert(hint, handle, handle + num_elem - 1);
1738    }
1739 
1740   debug_track.all_reduce();
1741   return MB_SUCCESS;
1742 }
1743 
read_elems(int i,const Range & elems_in,Range & nodes)1744 ErrorCode ReadHDF5::read_elems(int i, const Range& elems_in, Range& nodes)
1745 {
1746   CHECK_OPEN_HANDLES;
1747 
1748   debug_barrier();
1749   dbgOut.tprintf(1, "READING %s CONNECTIVITY (%lu elems in %lu selects)\n", fileInfo->elems[i].handle,
1750                     (unsigned long)elems_in.size(), (unsigned long)elems_in.psize());
1751 
1752   EntityHandle* const buffer = reinterpret_cast<EntityHandle*>(dataBuffer);
1753   const int node_per_elem = fileInfo->elems[i].desc.vals_per_ent;
1754   const size_t buffer_size = bufferSize / (node_per_elem * sizeof(EntityHandle));
1755 
1756   if (elems_in.empty())
1757     return MB_SUCCESS;
1758 
1759   assert((long)elems_in.front() >= fileInfo->elems[i].desc.start_id);
1760   assert((long)elems_in.back() - fileInfo->elems[i].desc.start_id < fileInfo->elems[i].desc.count);
1761 
1762   // We don't support version 3 style poly element data
1763   if (fileInfo->elems[i].desc.vals_per_ent <= 0)
1764     MB_CHK_ERR(MB_TYPE_OUT_OF_RANGE);
1765 
1766   mhdf_Status status;
1767   hid_t table = mhdf_openConnectivitySimple(filePtr, fileInfo->elems[i].handle, &status);
1768   if (is_error(status))
1769     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1770 
1771   try {
1772     ReadHDF5Dataset reader(fileInfo->elems[i].handle, table, nativeParallel, mpiComm);
1773     reader.set_file_ids(elems_in, fileInfo->elems[i].desc.start_id,
1774                         buffer_size, handleType);
1775     dbgOut.printf(3, "Reading node list in %lu chunks for \"%s\"\n", reader.get_read_count(), fileInfo->elems[i].handle);
1776     int nn = 0;
1777     while (!reader.done()) {
1778       dbgOut.printf(3, "Reading chunk %d of \"%s\" connectivity\n", ++nn, fileInfo->elems[i].handle);
1779       size_t num_read;
1780       reader.read(buffer, num_read);
1781       std::sort(buffer, buffer + num_read*node_per_elem);
1782       num_read = std::unique(buffer, buffer + num_read*node_per_elem) - buffer;
1783       copy_sorted_file_ids(buffer, num_read, nodes);
1784     }
1785   }
1786   catch (ReadHDF5Dataset::Exception) {
1787     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1788   }
1789 
1790   return MB_SUCCESS;
1791 }
1792 
read_poly(const mhdf_ElemDesc & elems,const Range & file_ids)1793 ErrorCode ReadHDF5::read_poly(const mhdf_ElemDesc& elems, const Range& file_ids)
1794 {
1795   class PolyReader : public ReadHDF5VarLen {
1796     private:
1797       const EntityType type;
1798       ReadHDF5* readHDF5;
1799     public:
1800     PolyReader(EntityType elem_type, void* buffer, size_t buffer_size,
1801                ReadHDF5* owner, DebugOutput& dbg)
1802                : ReadHDF5VarLen(dbg, buffer, buffer_size),
1803                  type(elem_type), readHDF5(owner)
1804                {}
1805     virtual ~PolyReader() {}
1806     ErrorCode store_data(EntityHandle file_id, void* data, long len, bool)
1807     {
1808       size_t valid;
1809       EntityHandle* conn = reinterpret_cast<EntityHandle*>(data);
1810       readHDF5->convert_id_to_handle(conn, len, valid);
1811       if (valid != (size_t)len)
1812         MB_CHK_ERR(MB_ENTITY_NOT_FOUND);
1813       EntityHandle handle;
1814       ErrorCode rval = readHDF5->moab()->create_element(type, conn, len, handle);
1815       if (MB_SUCCESS != rval)
1816         MB_SET_ERR(rval, "ReadHDF5 Failure");
1817 
1818       rval = readHDF5->insert_in_id_map(file_id, handle);
1819       return rval;
1820     }
1821   };
1822 
1823   CHECK_OPEN_HANDLES;
1824 
1825   debug_barrier();
1826 
1827   EntityType type = CN::EntityTypeFromName(elems.type);
1828   if (type == MBMAXTYPE) {
1829     MB_SET_ERR(MB_FAILURE, "Unknown element type: \"" << elems.type << "\"");
1830   }
1831 
1832   hid_t handles[2];
1833   mhdf_Status status;
1834   long num_poly, num_conn, first_id;
1835   mhdf_openPolyConnectivity(filePtr, elems.handle, &num_poly, &num_conn, &first_id,
1836                             handles, &status);
1837   if (is_error(status))
1838     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1839 
1840   std::string nm(elems.handle);
1841   ReadHDF5Dataset offset_reader((nm + " offsets").c_str(), handles[0], nativeParallel, mpiComm, true);
1842   ReadHDF5Dataset connect_reader((nm + " data").c_str(), handles[1], nativeParallel, mpiComm, true);
1843 
1844   PolyReader tool(type, dataBuffer, bufferSize, this, dbgOut);
1845   return tool.read(offset_reader, connect_reader, file_ids, first_id, handleType);
1846 }
1847 
delete_non_side_elements(const Range & side_ents)1848 ErrorCode ReadHDF5::delete_non_side_elements(const Range& side_ents)
1849 {
1850   ErrorCode rval;
1851 
1852   // Build list of entities that we need to find the sides of
1853   Range explicit_ents;
1854   Range::iterator hint = explicit_ents.begin();
1855   for (IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i) {
1856     EntityHandle start = i->value;
1857     EntityHandle end = i->value + i->count - 1;
1858     EntityType type = TYPE_FROM_HANDLE(start);
1859     assert(type == TYPE_FROM_HANDLE(end)); // Otherwise handle space entirely full!!
1860     if (type != MBVERTEX && type != MBENTITYSET)
1861       hint = explicit_ents.insert(hint, start, end);
1862   }
1863   explicit_ents = subtract(explicit_ents, side_ents);
1864 
1865   // Figure out which entities we want to delete
1866   Range dead_ents(side_ents);
1867   Range::iterator ds, de, es;
1868   ds = dead_ents.lower_bound(CN::TypeDimensionMap[1].first);
1869   de = dead_ents.lower_bound(CN::TypeDimensionMap[2].first, ds);
1870   if (ds != de) {
1871     // Get subset of explicit ents of dimension greater than 1
1872     es = explicit_ents.lower_bound(CN::TypeDimensionMap[2].first);
1873     Range subset, adj;
1874     subset.insert(es, explicit_ents.end());
1875     rval = iFace->get_adjacencies(subset, 1, false, adj, Interface::UNION);
1876     if (MB_SUCCESS != rval)
1877       return rval;
1878     dead_ents = subtract(dead_ents, adj);
1879   }
1880   ds = dead_ents.lower_bound(CN::TypeDimensionMap[2].first);
1881   de = dead_ents.lower_bound(CN::TypeDimensionMap[3].first, ds);
1882   assert(de == dead_ents.end());
1883   if (ds != de) {
1884     // Get subset of explicit ents of dimension 3
1885     es = explicit_ents.lower_bound(CN::TypeDimensionMap[3].first);
1886     Range subset, adj;
1887     subset.insert(es, explicit_ents.end());
1888     rval = iFace->get_adjacencies(subset, 2, false, adj, Interface::UNION);
1889     if (MB_SUCCESS != rval)
1890       return rval;
1891     dead_ents = subtract(dead_ents, adj);
1892   }
1893 
1894   // Now delete anything remaining in dead_ents
1895   dbgOut.printf(2, "Deleting %lu elements\n", (unsigned long)dead_ents.size());
1896   dbgOut.print(4, "\tDead entities: ", dead_ents);
1897   rval = iFace->delete_entities(dead_ents);
1898   if (MB_SUCCESS != rval)
1899     MB_SET_ERR(rval, "ReadHDF5 Failure");
1900 
1901   // Remove dead entities from ID map
1902   while (!dead_ents.empty()) {
1903     EntityHandle start = dead_ents.front();
1904     EntityID count = dead_ents.const_pair_begin()->second - start + 1;
1905     IDMap::iterator rit;
1906     for (rit = idMap.begin(); rit != idMap.end(); ++rit)
1907       if (rit->value <= start && (EntityID)(start - rit->value) < rit->count)
1908         break;
1909     if (rit == idMap.end())
1910       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1911 
1912     EntityID offset = start - rit->value;
1913     EntityID avail = rit->count - offset;
1914     if (avail < count)
1915       count = avail;
1916 
1917     dead_ents.erase(dead_ents.begin(), dead_ents.begin() + count);
1918     idMap.erase(rit->begin + offset, count);
1919   }
1920 
1921   return MB_SUCCESS;
1922 }
1923 
read_sets(const Range & file_ids)1924 ErrorCode ReadHDF5::read_sets(const Range& file_ids)
1925 {
1926   CHECK_OPEN_HANDLES;
1927 
1928   debug_barrier();
1929 
1930   mhdf_Status status;
1931   ErrorCode rval;
1932 
1933   const size_t num_sets = fileInfo->sets.count;
1934   if (!num_sets) // If no sets at all!
1935     return MB_SUCCESS;
1936 
1937   // Create sets
1938   std::vector<unsigned> flags(file_ids.size());
1939   Range::iterator si = file_ids.begin();
1940   for (size_t i = 0; i < flags.size(); ++i, ++si)
1941     flags[i] = setMeta[*si - fileInfo->sets.start_id][3] & ~(long)mhdf_SET_RANGE_BIT;
1942   EntityHandle start_handle;
1943   rval = readUtil->create_entity_sets(flags.size(), &flags[0], 0, start_handle);
1944   if (MB_SUCCESS != rval)
1945     MB_SET_ERR(rval, "ReadHDF5 Failure");
1946   rval = insert_in_id_map(file_ids, start_handle);
1947   if (MB_SUCCESS != rval)
1948     MB_SET_ERR(rval, "ReadHDF5 Failure");
1949 
1950   // Read contents
1951   if (fileInfo->have_set_contents) {
1952     long len = 0;
1953     hid_t handle = mhdf_openSetData(filePtr, &len, &status);
1954     if (is_error(status))
1955       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1956 
1957     ReadHDF5Dataset dat("set contents", handle, nativeParallel, mpiComm, true);
1958     rval = read_set_data(file_ids, start_handle, dat, CONTENT);
1959     if (MB_SUCCESS != rval)
1960       MB_SET_ERR(rval, "ReadHDF5 Failure");
1961   }
1962 
1963   // Read set child lists
1964   if (fileInfo->have_set_children) {
1965     long len = 0;
1966     hid_t handle = mhdf_openSetChildren(filePtr, &len, &status);
1967     if (is_error(status))
1968       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1969 
1970     ReadHDF5Dataset dat("set children", handle, nativeParallel, mpiComm, true);
1971     rval = read_set_data(file_ids, start_handle, dat, CHILD);
1972     if (MB_SUCCESS != rval)
1973       MB_SET_ERR(rval, "ReadHDF5 Failure");
1974   }
1975 
1976   // Read set parent lists
1977   if (fileInfo->have_set_parents) {
1978     long len = 0;
1979     hid_t handle = mhdf_openSetParents(filePtr, &len, &status);
1980     if (is_error(status))
1981       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
1982 
1983     ReadHDF5Dataset dat("set parents", handle, nativeParallel, mpiComm, true);
1984     rval = read_set_data(file_ids, start_handle, dat, PARENT);
1985     if (MB_SUCCESS != rval)
1986       MB_SET_ERR(rval, "ReadHDF5 Failure");
1987   }
1988 
1989   return MB_SUCCESS;
1990 }
1991 
read_all_set_meta()1992 ErrorCode ReadHDF5::read_all_set_meta()
1993 {
1994   CHECK_OPEN_HANDLES;
1995 
1996   assert(!setMeta);
1997   const long num_sets = fileInfo->sets.count;
1998   if (!num_sets)
1999     return MB_SUCCESS;
2000 
2001   mhdf_Status status;
2002   hid_t handle = mhdf_openSetMetaSimple(filePtr, &status);
2003   if (is_error(status)) {
2004     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2005   }
2006 
2007   // Allocate extra space if we need it for data conversion
2008   hid_t meta_type = H5Dget_type(handle);
2009   size_t size = H5Tget_size(meta_type);
2010   if (size > sizeof(long))
2011     setMeta = new long[(num_sets * size + (sizeof(long)-1)) / sizeof(long)][4];
2012    else
2013     setMeta = new long[num_sets][4];
2014 
2015   // Set some parameters based on whether or not each proc reads the
2016   // table or only the root reads it and bcasts it to the others
2017   int rank = 0;
2018   bool bcast = false;
2019   hid_t ioprop = H5P_DEFAULT;
2020 #ifdef MOAB_HAVE_MPI
2021   MPI_Comm comm = 0;
2022   if (nativeParallel) {
2023     rank = myPcomm->proc_config().proc_rank();
2024     comm = myPcomm->proc_config().proc_comm();
2025     bcast = bcastDuplicateReads;
2026     if (!bcast)
2027       ioprop = collIO;
2028   }
2029 #endif
2030 
2031   if (!bcast || 0 == rank) {
2032     mhdf_readSetMetaWithOpt(handle, 0, num_sets, meta_type, setMeta, ioprop, &status);
2033     if (is_error(status)) {
2034       H5Tclose(meta_type);
2035       mhdf_closeData(filePtr, handle, &status);
2036       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2037     }
2038 
2039      H5Tconvert(meta_type, H5T_NATIVE_LONG, num_sets*4, setMeta, 0, H5P_DEFAULT);
2040   }
2041   mhdf_closeData(filePtr, handle, &status);
2042   if (is_error(status))
2043     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2044   H5Tclose(meta_type);
2045 
2046   if (bcast) {
2047 #ifdef MOAB_HAVE_MPI
2048     int ierr = MPI_Bcast((void*)setMeta, num_sets*4, MPI_LONG, 0, comm);
2049     if (MPI_SUCCESS != ierr)
2050       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2051 #else
2052     assert(rank == 0); // If not MPI, then only one proc
2053 #endif
2054   }
2055 
2056   return MB_SUCCESS;
2057 }
2058 
read_set_ids_recursive(Range & sets_in_out,bool contained_sets,bool child_sets)2059 ErrorCode ReadHDF5::read_set_ids_recursive(Range& sets_in_out,
2060                                            bool contained_sets,
2061                                            bool child_sets)
2062 {
2063   CHECK_OPEN_HANDLES;
2064   mhdf_Status status;
2065 
2066   if (!fileInfo->have_set_children)
2067     child_sets = false;
2068   if (!fileInfo->have_set_contents)
2069     contained_sets = false;
2070   if (!child_sets && !contained_sets)
2071     return MB_SUCCESS;
2072 
2073   // Open data tables
2074   if (fileInfo->sets.count == 0) {
2075     assert(sets_in_out.empty());
2076     return MB_SUCCESS;
2077   }
2078 
2079   if (!contained_sets && !child_sets)
2080     return MB_SUCCESS;
2081 
2082   ReadHDF5Dataset cont("set contents", false, mpiComm);
2083   ReadHDF5Dataset child("set children", false, mpiComm);
2084 
2085   if (contained_sets) {
2086     long content_len = 0;
2087     hid_t content_handle = mhdf_openSetData(filePtr, &content_len, &status);
2088     if (is_error(status))
2089        MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2090     try {
2091       cont.init(content_handle, true);
2092     }
2093     catch (ReadHDF5Dataset::Exception) {
2094       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2095     }
2096   }
2097 
2098   if (child_sets) {
2099     long child_len = 0;
2100     hid_t child_handle = mhdf_openSetChildren(filePtr, &child_len, &status);
2101     if (is_error(status))
2102       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2103     try {
2104       child.init(child_handle, true);
2105     }
2106     catch (ReadHDF5Dataset::Exception) {
2107       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2108     }
2109   }
2110 
2111   ErrorCode rval = MB_SUCCESS;
2112   Range children, new_children(sets_in_out);
2113   int iteration_count = 0;
2114   do {
2115     ++iteration_count;
2116     dbgOut.tprintf(2, "Iteration %d of read_set_ids_recursive\n", iteration_count);
2117     children.clear();
2118     if (child_sets) {
2119       rval = read_set_data(new_children, 0, child, CHILD, &children);
2120       if (MB_SUCCESS != rval)
2121         break;
2122     }
2123     if (contained_sets) {
2124       rval = read_set_data(new_children, 0, cont, CONTENT, &children);
2125       // Remove any non-set values
2126       Range::iterator it = children.lower_bound(fileInfo->sets.start_id);
2127       children.erase(children.begin(), it);
2128       it = children.lower_bound(fileInfo->sets.start_id + fileInfo->sets.count);
2129       children.erase(it, children.end());
2130       if (MB_SUCCESS != rval)
2131         break;
2132     }
2133     new_children = subtract(children, sets_in_out);
2134     dbgOut.print_ints(2, "Adding additional contained/child sets", new_children);
2135     sets_in_out.merge(new_children);
2136   } while (!new_children.empty());
2137 
2138   return MB_SUCCESS;
2139 }
2140 
find_sets_containing(Range & sets_out,bool read_set_containing_parents)2141 ErrorCode ReadHDF5::find_sets_containing(Range& sets_out,
2142                                          bool read_set_containing_parents)
2143 {
2144   ErrorCode rval;
2145   mhdf_Status status;
2146 
2147   CHECK_OPEN_HANDLES;
2148 
2149   if (!fileInfo->have_set_contents)
2150     return MB_SUCCESS;
2151   assert(fileInfo->sets.count);
2152 
2153   // Open data tables
2154   long content_len = 0;
2155   hid_t content_handle = mhdf_openSetData(filePtr, &content_len, &status);
2156   if (is_error(status))
2157     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2158 
2159   hid_t data_type = H5Dget_type(content_handle);
2160 
2161   rval = find_sets_containing(content_handle, data_type, content_len,
2162                               read_set_containing_parents, sets_out);
2163 
2164   H5Tclose(data_type);
2165 
2166   mhdf_closeData(filePtr, content_handle, &status);
2167   if (MB_SUCCESS == rval && is_error(status))
2168     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2169 
2170   return rval;
2171 }
2172 
set_map_intersect(bool ranged,const long * contents,int content_len,const RangeMap<long,EntityHandle> & id_map)2173 static bool set_map_intersect(bool ranged,
2174                               const long* contents,
2175                               int content_len,
2176                               const RangeMap<long, EntityHandle>& id_map)
2177 {
2178   if (ranged) {
2179     if (!content_len || id_map.empty())
2180       return false;
2181 
2182     const long* j = contents;
2183     const long* const end = contents + content_len;
2184     assert(content_len % 2 == 0);
2185     while (j != end) {
2186       long start = *(j++);
2187       long count = *(j++);
2188       if (id_map.intersects(start, count))
2189         return true;
2190     }
2191   }
2192   else {
2193     const long* const end = contents + content_len;
2194     for (const long* i = contents; i != end; ++i)
2195       if (id_map.exists(*i))
2196         return true;
2197   }
2198 
2199   return false;
2200 }
2201 
2202 struct SetContOffComp {
operator ()moab::SetContOffComp2203   bool operator()(const long a1[4], const long a2[4])
2204     { return a1[ReadHDF5::CONTENT] < a2[0]; }
2205 };
2206 
find_sets_containing(hid_t contents_handle,hid_t content_type,long contents_len,bool read_set_containing_parents,Range & file_ids)2207 ErrorCode ReadHDF5::find_sets_containing(hid_t contents_handle,
2208                                          hid_t content_type,
2209                                          long contents_len,
2210                                          bool read_set_containing_parents,
2211                                          Range& file_ids)
2212 {
2213   CHECK_OPEN_HANDLES;
2214 
2215   // Scan all set contents data
2216 
2217   const size_t content_size = H5Tget_size(content_type);
2218   const long num_sets = fileInfo->sets.count;
2219   dbgOut.printf(2, "Searching contents of %ld\n", num_sets);
2220   mhdf_Status status;
2221 
2222   int rank = 0;
2223   bool bcast = false;
2224 #ifdef MOAB_HAVE_MPI
2225   MPI_Comm comm = 0;
2226   if (nativeParallel) {
2227     rank = myPcomm->proc_config().proc_rank();
2228     comm = myPcomm->proc_config().proc_comm();
2229     bcast = bcastDuplicateReads;
2230   }
2231 #endif
2232 
2233   // Check offsets so that we don't read past end of table or
2234   // walk off end of array.
2235   long prev = -1;
2236   for (long  i = 0; i < num_sets; ++i) {
2237     if (setMeta[i][CONTENT] < prev) {
2238       std::cerr << "Invalid data in set contents offsets at position "
2239                 << i << ": index " << setMeta[i][CONTENT]
2240                 << " is less than previous index " << prev << std::endl;
2241       std::cerr.flush();
2242       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2243     }
2244     prev = setMeta[i][CONTENT];
2245   }
2246   if (setMeta[num_sets - 1][CONTENT] >= contents_len) {
2247     std::cerr << "Maximum set content index " << setMeta[num_sets - 1][CONTENT]
2248               << " exceeds contents table length of " << contents_len
2249               << std::endl;
2250     std::cerr.flush();
2251     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2252   }
2253 
2254   // Set up buffer for reading set contents
2255   long* const content_buffer = (long*)dataBuffer;
2256   const long content_len = bufferSize / std::max(content_size, sizeof(long));
2257 
2258   // Scan set table
2259   Range::iterator hint = file_ids.begin();
2260   Range tmp_range;
2261   long prev_idx = -1;
2262   int mm = 0;
2263   long sets_offset = 0;
2264   long temp_content[4];
2265   while (sets_offset < num_sets) {
2266     temp_content[0] = content_len + prev_idx;
2267     long sets_count = std::lower_bound(setMeta + sets_offset,
2268                                        setMeta + num_sets,
2269                                        temp_content,
2270                                        SetContOffComp())
2271                                        - setMeta - sets_offset;
2272     assert(sets_count >= 0 && sets_offset + sets_count <= num_sets);
2273     if (!sets_count) { // Contents of single set don't fit in buffer
2274       long content_remaining = setMeta[sets_offset][CONTENT] - prev_idx;
2275       long content_offset = prev_idx + 1;
2276       while (content_remaining) {
2277         long content_count = content_len < content_remaining ?
2278                              2*(content_len / 2) : content_remaining;
2279         assert_range(content_buffer, content_count);
2280         dbgOut.printf(3, "Reading chunk %d (%ld values) from set contents table\n", ++mm, content_count);
2281         if (!bcast || 0 == rank) {
2282           if (!bcast)
2283             mhdf_readSetDataWithOpt(contents_handle, content_offset,
2284                                     content_count, content_type,
2285                                     content_buffer, collIO, &status);
2286           else
2287             mhdf_readSetData(contents_handle, content_offset,
2288                              content_count, content_type,
2289                              content_buffer, &status);
2290           if (is_error(status))
2291             MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2292 
2293           H5Tconvert(content_type, H5T_NATIVE_LONG, content_count, content_buffer, 0, H5P_DEFAULT);
2294         }
2295         if (bcast) {
2296           #ifdef MOAB_HAVE_MPI
2297             int ierr = MPI_Bcast(content_buffer, content_count, MPI_LONG, 0, comm);
2298             if (MPI_SUCCESS != ierr)
2299               MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2300           #else
2301             assert(rank == 0); // If not MPI, then only one proc
2302           #endif
2303         }
2304 
2305         if (read_set_containing_parents) {
2306           tmp_range.clear();
2307           if (setMeta[sets_offset][3] & mhdf_SET_RANGE_BIT) tmp_range.insert(*content_buffer, *(content_buffer + 1));
2308           else std::copy(content_buffer, content_buffer + content_count, range_inserter(tmp_range));
2309           tmp_range = intersect(tmp_range, file_ids);
2310         }
2311 
2312         if (!tmp_range.empty() ||
2313             set_map_intersect(setMeta[sets_offset][3] & mhdf_SET_RANGE_BIT,
2314                               content_buffer, content_count, idMap)) {
2315           long id = fileInfo->sets.start_id + sets_offset;
2316           hint = file_ids.insert(hint, id, id);
2317           if (!nativeParallel) // Don't stop if doing READ_PART because we need to read collectively
2318             break;
2319         }
2320         content_remaining -= content_count;
2321         content_offset += content_count;
2322       }
2323       prev_idx = setMeta[sets_offset][CONTENT];
2324       sets_count = 1;
2325     }
2326     else if (long read_num = setMeta[sets_offset + sets_count - 1][CONTENT] - prev_idx) {
2327       assert(sets_count > 0);
2328       assert_range(content_buffer, read_num);
2329       dbgOut.printf(3, "Reading chunk %d (%ld values) from set contents table\n", ++mm, read_num);
2330       if (!bcast || 0 == rank) {
2331         if (!bcast)
2332           mhdf_readSetDataWithOpt(contents_handle, prev_idx + 1, read_num,
2333                                   content_type, content_buffer, collIO, &status);
2334         else
2335           mhdf_readSetData(contents_handle, prev_idx + 1, read_num,
2336                            content_type, content_buffer, &status);
2337         if (is_error(status))
2338           MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2339 
2340         H5Tconvert(content_type, H5T_NATIVE_LONG, read_num, content_buffer, 0, H5P_DEFAULT);
2341       }
2342       if (bcast) {
2343         #ifdef MOAB_HAVE_MPI
2344           int ierr = MPI_Bcast(content_buffer, read_num, MPI_LONG, 0, comm);
2345           if (MPI_SUCCESS != ierr)
2346             MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2347         #else
2348           assert(rank == 0); // If not MPI, then only one proc
2349         #endif
2350       }
2351 
2352       long* buff_iter = content_buffer;
2353       for (long i = 0; i < sets_count; ++i) {
2354         long set_size = setMeta[i + sets_offset][CONTENT] - prev_idx;
2355         prev_idx += set_size;
2356 
2357         // Check whether contents include set already being loaded
2358         if (read_set_containing_parents) {
2359           tmp_range.clear();
2360           if (setMeta[sets_offset + i][3] & mhdf_SET_RANGE_BIT)
2361           {
2362             // put in tmp_range the contents on the set
2363             // file_ids contain at this points only other sets
2364             const long* j = buff_iter;
2365             const long* const end = buff_iter + set_size;
2366             assert(set_size % 2 == 0);
2367             while (j != end) {
2368               long start = *(j++);
2369               long count = *(j++);
2370               tmp_range.insert(start, start+count-1);
2371             }
2372           }
2373           else
2374             std::copy(buff_iter, buff_iter + set_size, range_inserter(tmp_range));
2375           tmp_range = intersect(tmp_range, file_ids);
2376         }
2377 
2378         if (!tmp_range.empty() ||
2379             set_map_intersect(setMeta[sets_offset + i][3] & mhdf_SET_RANGE_BIT,
2380                               buff_iter, set_size, idMap)) {
2381           long id = fileInfo->sets.start_id + sets_offset + i;
2382           hint = file_ids.insert(hint, id, id);
2383         }
2384         buff_iter += set_size;
2385       }
2386     }
2387 
2388     sets_offset += sets_count;
2389   }
2390 
2391   return MB_SUCCESS;
2392 }
2393 
copy_set_contents(Range::iterator hint,int ranged,EntityHandle * contents,long length,Range & results)2394 static Range::iterator copy_set_contents(Range::iterator hint,
2395                                          int ranged,
2396                                          EntityHandle* contents,
2397                                          long length,
2398                                          Range& results)
2399 {
2400   if (ranged) {
2401     assert(length % 2 == 0);
2402     for (long i = 0; i < length; i += 2)
2403       hint = results.insert(hint, contents[i], contents[i] + contents[i + 1] - 1);
2404   }
2405   else {
2406     std::sort(contents, contents+length);
2407     for (long i = 0; i < length; ++i)
2408       hint = results.insert(hint, contents[i]);
2409   }
2410   return hint;
2411 }
2412 
read_set_data(const Range & set_file_ids,EntityHandle start_handle,ReadHDF5Dataset & data,SetMode mode,Range * file_ids_out)2413 ErrorCode ReadHDF5::read_set_data(const Range& set_file_ids,
2414                                   EntityHandle start_handle,
2415                                   ReadHDF5Dataset& data,
2416                                   SetMode mode,
2417                                   Range* file_ids_out)
2418 {
2419   ErrorCode rval;
2420   Range::const_pair_iterator pi;
2421   Range::iterator out_hint;
2422   if (file_ids_out)
2423     out_hint = file_ids_out->begin();
2424 
2425   // Construct range of offsets into data table at which to read
2426   // Note: all offsets are incremented by TWEAK because Range cannot
2427   // store zeros.
2428   const long TWEAK = 1;
2429   Range data_offsets;
2430   Range::iterator hint = data_offsets.begin();
2431   pi = set_file_ids.const_pair_begin();
2432   if ((long)pi->first == fileInfo->sets.start_id) {
2433     long second = pi->second - fileInfo->sets.start_id;
2434     if  (setMeta[second][mode] >= 0)
2435       hint = data_offsets.insert(hint, TWEAK, setMeta[second][mode] + TWEAK);
2436     ++pi;
2437   }
2438   for ( ; pi != set_file_ids.const_pair_end(); ++pi) {
2439     long first = pi->first - fileInfo->sets.start_id;
2440     long second = pi->second - fileInfo->sets.start_id;
2441     long idx1 = setMeta[first - 1][mode] + 1;
2442     long idx2 = setMeta[second][mode];
2443     if (idx2 >= idx1)
2444       hint = data_offsets.insert(hint, idx1 + TWEAK, idx2 + TWEAK);
2445   }
2446   try {
2447     data.set_file_ids(data_offsets, TWEAK, bufferSize / sizeof(EntityHandle), handleType);
2448   }
2449   catch (ReadHDF5Dataset::Exception) {
2450     return MB_FAILURE;
2451   }
2452 
2453   // We need to increment this for each processed set because
2454   // the sets were created in the order of the ids in file_ids.
2455   EntityHandle h = start_handle;
2456 
2457   const long ranged_flag = (mode == CONTENT) ? mhdf_SET_RANGE_BIT : 0;
2458 
2459   std::vector<EntityHandle> partial; // For when we read only part of the contents of a set/entity
2460   Range::const_iterator fileid_iter = set_file_ids.begin();
2461   EntityHandle* buffer = reinterpret_cast<EntityHandle*>(dataBuffer);
2462   size_t count, offset;
2463 
2464   int nn = 0;
2465 #ifdef  MOAB_HAVE_MPI
2466   if (nativeParallel && mode==CONTENT && myPcomm->proc_config().proc_size()>1 && data_offsets.empty())
2467   {
2468     MB_SET_ERR_CONT( "ReadHDF5 Failure: Attempt reading an empty dataset on proc " <<
2469         myPcomm->proc_config().proc_rank());
2470     MPI_Abort(myPcomm->proc_config().proc_comm(), 1);
2471   }
2472 #endif
2473   while (!data.done()) {
2474     dbgOut.printf(3, "Reading chunk %d of %s\n", ++nn, data.get_debug_desc());
2475     try {
2476       data.read(buffer, count);
2477     }
2478     catch (ReadHDF5Dataset::Exception) {
2479       return MB_FAILURE;
2480     }
2481 
2482     // Assert not appropriate here - I might have treated all my file ids, but maybe
2483     // another proc hasn't; for me, count will be zero, so I won't do anything, but
2484     // I still need to go through the motions to make the read work
2485 
2486     // Handle 'special' case where we read some, but not all
2487     // of the data for an entity during the last iteration.
2488     offset = 0;
2489     if (!partial.empty()) { // Didn't read all of previous entity
2490       assert(fileid_iter != set_file_ids.end());
2491       size_t num_prev = partial.size();
2492       size_t idx = *fileid_iter - fileInfo->sets.start_id;
2493       size_t len = idx ? setMeta[idx][mode] - setMeta[idx - 1][mode] : setMeta[idx][mode] + 1;
2494       offset = len - num_prev;
2495       if (offset > count) { // Still don't have all
2496         partial.insert(partial.end(), buffer, buffer + count);
2497         continue;
2498       }
2499 
2500       partial.insert(partial.end(), buffer, buffer + offset);
2501       if (file_ids_out) {
2502         out_hint = copy_set_contents(out_hint, setMeta[idx][3] & ranged_flag,
2503                                      &partial[0], partial.size(), *file_ids_out);
2504       }
2505       else {
2506         switch (mode) {
2507           size_t valid;
2508           case CONTENT:
2509             if (setMeta[idx][3] & ranged_flag) {
2510               if (len % 2)
2511                 MB_CHK_ERR(MB_INDEX_OUT_OF_RANGE);
2512               Range range;
2513               convert_range_to_handle(&partial[0], len / 2, range);
2514               rval = moab()->add_entities(h, range);
2515             }
2516             else {
2517               convert_id_to_handle(&partial[0], len, valid);
2518               rval = moab()->add_entities(h, &partial[0], valid);
2519             }
2520             break;
2521           case CHILD:
2522             convert_id_to_handle(&partial[0], len, valid);
2523             rval = moab()->add_child_meshsets(h, &partial[0], valid);
2524             break;
2525           case PARENT:
2526             convert_id_to_handle(&partial[0], len, valid);
2527             rval = moab()->add_parent_meshsets(h, &partial[0], valid);
2528             break;
2529           default:
2530             break;
2531         }
2532         if (MB_SUCCESS != rval)
2533           MB_SET_ERR(rval, "ReadHDF5 Failure");
2534       }
2535 
2536       ++fileid_iter;
2537       ++h;
2538       partial.clear();
2539     }
2540 
2541     // Process contents for all entities for which we
2542     // have read the complete list
2543     while (offset < count) {
2544       assert(fileid_iter != set_file_ids.end());
2545       size_t idx = *fileid_iter - fileInfo->sets.start_id;
2546       size_t len = idx ? setMeta[idx][mode] - setMeta[idx - 1][mode] : setMeta[idx][mode] + 1;
2547        // If we did not read all of the final entity,
2548        // store what we did read to be processed in the
2549        // next iteration
2550       if (offset + len > count) {
2551         partial.insert(partial.end(), buffer + offset, buffer + count);
2552         break;
2553       }
2554 
2555       if (file_ids_out) {
2556         out_hint = copy_set_contents(out_hint, setMeta[idx][3] & ranged_flag,
2557                                      buffer + offset, len, *file_ids_out);
2558       }
2559       else {
2560         switch (mode) {
2561           size_t valid;
2562           case CONTENT:
2563             if (setMeta[idx][3] & ranged_flag) {
2564               if (len % 2)
2565                 MB_CHK_ERR(MB_INDEX_OUT_OF_RANGE);
2566               Range range;
2567               convert_range_to_handle(buffer + offset, len / 2, range);
2568               rval = moab()->add_entities(h, range);
2569             }
2570             else {
2571               convert_id_to_handle(buffer + offset, len, valid);
2572               rval = moab()->add_entities(h, buffer + offset, valid);
2573             }
2574             break;
2575           case CHILD:
2576             convert_id_to_handle(buffer + offset, len, valid);
2577             rval = moab()->add_child_meshsets(h, buffer + offset, valid);
2578             break;
2579           case PARENT:
2580             convert_id_to_handle(buffer + offset, len, valid);
2581             rval = moab()->add_parent_meshsets(h, buffer + offset, valid);
2582             break;
2583           default:
2584             break;
2585         }
2586         if (MB_SUCCESS != rval)
2587           MB_SET_ERR(rval, "ReadHDF5 Failure");
2588       }
2589 
2590       ++fileid_iter;
2591       ++h;
2592       offset += len;
2593     }
2594   }
2595 
2596   return MB_SUCCESS;
2597 }
2598 
get_set_contents(const Range & sets,Range & file_ids)2599 ErrorCode ReadHDF5::get_set_contents(const Range& sets, Range& file_ids)
2600 {
2601   CHECK_OPEN_HANDLES;
2602 
2603   if (!fileInfo->have_set_contents)
2604     return MB_SUCCESS;
2605   dbgOut.tprint(2, "Reading set contained file IDs\n");
2606   try {
2607     mhdf_Status status;
2608     long content_len;
2609     hid_t contents = mhdf_openSetData(filePtr, &content_len, &status);
2610     if (is_error(status))
2611       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2612     ReadHDF5Dataset data("set contents", contents, nativeParallel, mpiComm, true);
2613 
2614     return read_set_data(sets, 0, data, CONTENT, &file_ids);
2615   }
2616   catch (ReadHDF5Dataset::Exception) {
2617     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2618   }
2619 }
2620 
read_adjacencies(hid_t table,long table_len)2621 ErrorCode ReadHDF5::read_adjacencies(hid_t table, long table_len)
2622 {
2623   CHECK_OPEN_HANDLES;
2624 
2625   ErrorCode rval;
2626   mhdf_Status status;
2627 
2628   debug_barrier();
2629 
2630   hid_t read_type = H5Dget_type(table);
2631   if (read_type < 0)
2632     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2633   const bool convert = !H5Tequal(read_type, handleType);
2634 
2635   EntityHandle* buffer = (EntityHandle*)dataBuffer;
2636   size_t chunk_size = bufferSize / H5Tget_size(read_type);
2637   size_t remaining = table_len;
2638   size_t left_over = 0;
2639   size_t offset = 0;
2640   dbgOut.printf(3, "Reading adjacency list in %lu chunks\n",
2641     (unsigned long)(remaining + chunk_size - 1) / chunk_size);
2642   int nn = 0;
2643   while (remaining) {
2644     dbgOut.printf(3, "Reading chunk %d of adjacency list\n", ++nn);
2645 
2646     size_t count = std::min(chunk_size, remaining);
2647     count -= left_over;
2648     remaining -= count;
2649 
2650     assert_range(buffer + left_over, count);
2651     mhdf_readAdjacencyWithOpt(table, offset, count, read_type, buffer + left_over,
2652                               collIO, &status);
2653     if (is_error(status))
2654       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2655 
2656     if (convert) {
2657       herr_t err = H5Tconvert(read_type, handleType, count, buffer + left_over, 0, H5P_DEFAULT);
2658       if (err < 0)
2659         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2660     }
2661 
2662     EntityHandle* iter = buffer;
2663     EntityHandle* end = buffer + count + left_over;
2664     while (end - iter >= 3) {
2665       EntityHandle h = idMap.find(*iter++);
2666       EntityHandle count2 = *iter++;
2667       if (!h) {
2668         iter += count2;
2669         continue;
2670       }
2671 
2672       if (count2 < 1)
2673         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2674 
2675       if (end < count2 + iter) {
2676         iter -= 2;
2677         break;
2678       }
2679 
2680       size_t valid;
2681       convert_id_to_handle(iter, count2, valid, idMap);
2682       rval = iFace->add_adjacencies(h, iter, valid, false);
2683       if (MB_SUCCESS != rval)
2684         MB_SET_ERR(rval, "ReadHDF5 Failure");
2685 
2686       iter += count2;
2687     }
2688 
2689     left_over = end - iter;
2690     assert_range((char*)buffer, left_over);
2691     assert_range((char*)iter, left_over);
2692     memmove(buffer, iter, left_over);
2693   }
2694 
2695   assert(!left_over); // Unexpected truncation of data
2696 
2697   return MB_SUCCESS;
2698 }
2699 
read_tag(int tag_index)2700 ErrorCode ReadHDF5::read_tag(int tag_index)
2701 {
2702   CHECK_OPEN_HANDLES;
2703 
2704   dbgOut.tprintf(2, "Reading tag \"%s\"\n", fileInfo->tags[tag_index].name);
2705 
2706   debug_barrier();
2707 
2708   ErrorCode rval;
2709   mhdf_Status status;
2710   Tag tag = 0;
2711   hid_t read_type = -1;
2712   bool table_type;
2713   rval = create_tag(fileInfo->tags[tag_index], tag, read_type);
2714   if (MB_SUCCESS != rval)
2715     MB_SET_ERR(rval, "ReadHDF5 Failure");
2716 
2717   if (fileInfo->tags[tag_index].have_sparse) {
2718     hid_t handles[3];
2719     long num_ent, num_val;
2720     mhdf_openSparseTagData(filePtr,
2721                            fileInfo->tags[tag_index].name,
2722                            &num_ent, &num_val,
2723                            handles, &status);
2724     if (is_error(status)) {
2725       if (read_type) H5Tclose(read_type);
2726       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2727     }
2728 
2729     table_type = false;
2730     if (read_type == 0) {
2731       read_type = H5Dget_type(handles[1]);
2732       if (read_type == 0) {
2733         mhdf_closeData(filePtr, handles[0], &status);
2734         mhdf_closeData(filePtr, handles[0], &status);
2735         if (fileInfo->tags[tag_index].size <= 0)
2736           mhdf_closeData(filePtr, handles[2], &status);
2737         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2738       }
2739       table_type = true;
2740     }
2741 
2742     if (fileInfo->tags[tag_index].size > 0) {
2743       dbgOut.printf(2, "Reading sparse data for tag \"%s\"\n", fileInfo->tags[tag_index].name);
2744       rval = read_sparse_tag(tag, read_type, handles[0], handles[1], num_ent);
2745     }
2746     else {
2747       dbgOut.printf(2, "Reading var-len sparse data for tag \"%s\"\n", fileInfo->tags[tag_index].name);
2748       rval = read_var_len_tag(tag, read_type, handles[0], handles[1], handles[2], num_ent, num_val);
2749     }
2750 
2751     if (table_type) {
2752       H5Tclose(read_type);
2753       read_type = 0;
2754     }
2755 
2756     mhdf_closeData(filePtr, handles[0], &status);
2757     if (MB_SUCCESS == rval && is_error(status))
2758       rval = MB_FAILURE;
2759     mhdf_closeData(filePtr, handles[1], &status);
2760     if (MB_SUCCESS == rval && is_error(status))
2761       rval = MB_FAILURE;
2762     if (fileInfo->tags[tag_index].size <= 0) {
2763       mhdf_closeData(filePtr, handles[2], &status);
2764       if (MB_SUCCESS == rval && is_error(status))
2765         rval = MB_FAILURE;
2766     }
2767     if (MB_SUCCESS != rval) {
2768       if (read_type) H5Tclose(read_type);
2769       MB_SET_ERR(rval, "ReadHDF5 Failure");
2770     }
2771   }
2772 
2773   for (int j = 0; j < fileInfo->tags[tag_index].num_dense_indices; ++j) {
2774     long count;
2775     const char* name = 0;
2776     mhdf_EntDesc* desc;
2777     int elem_idx = fileInfo->tags[tag_index].dense_elem_indices[j];
2778     if (elem_idx == -2) {
2779       desc = &fileInfo->sets;
2780       name = mhdf_set_type_handle();
2781     }
2782     else if (elem_idx == -1) {
2783       desc = &fileInfo->nodes;
2784       name = mhdf_node_type_handle();
2785     }
2786     else if (elem_idx >= 0 && elem_idx < fileInfo->num_elem_desc) {
2787       desc = &fileInfo->elems[elem_idx].desc;
2788       name = fileInfo->elems[elem_idx].handle;
2789     }
2790     else {
2791       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2792     }
2793 
2794     dbgOut.printf(2, "Read dense data block for tag \"%s\" on \"%s\"\n", fileInfo->tags[tag_index].name, name);
2795 
2796     hid_t handle = mhdf_openDenseTagData(filePtr,
2797                                          fileInfo->tags[tag_index].name,
2798                                          name,
2799                                          &count, &status);
2800     if (is_error(status)) {
2801       rval = MB_FAILURE; // rval = error(MB_FAILURE);
2802       break;
2803     }
2804 
2805     if (count > desc->count) {
2806       mhdf_closeData(filePtr, handle, &status);
2807       MB_SET_ERR(MB_FAILURE, "Invalid data length for dense tag data: " << name << "/" << fileInfo->tags[tag_index].name);
2808     }
2809 
2810     table_type = false;
2811     if (read_type == 0) {
2812       read_type = H5Dget_type(handle);
2813       if (read_type == 0) {
2814         mhdf_closeData(filePtr, handle, &status);
2815         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2816       }
2817       table_type = true;
2818     }
2819 
2820     rval = read_dense_tag(tag, name, read_type, handle, desc->start_id, count);
2821 
2822     if (table_type) {
2823       H5Tclose(read_type);
2824       read_type = 0;
2825     }
2826 
2827     mhdf_closeData(filePtr, handle, &status);
2828     if (MB_SUCCESS != rval)
2829       break;
2830     if (is_error(status)) {
2831       rval = MB_FAILURE;
2832       break;
2833     }
2834   }
2835 
2836   if (read_type)
2837     H5Tclose(read_type);
2838   return rval;
2839 }
2840 
create_tag(const mhdf_TagDesc & info,Tag & handle,hid_t & hdf_type)2841 ErrorCode ReadHDF5::create_tag(const mhdf_TagDesc& info,
2842                                Tag& handle,
2843                                hid_t& hdf_type)
2844 {
2845   CHECK_OPEN_HANDLES;
2846 
2847   ErrorCode rval;
2848   mhdf_Status status;
2849   TagType storage;
2850   DataType mb_type;
2851   bool re_read_default = false;
2852 
2853   switch (info.storage) {
2854     case mhdf_DENSE_TYPE:
2855       storage = MB_TAG_DENSE;
2856       break;
2857     case mhdf_SPARSE_TYPE:
2858       storage = MB_TAG_SPARSE;
2859       break;
2860     case mhdf_BIT_TYPE:
2861       storage = MB_TAG_BIT;
2862       break;
2863     case mhdf_MESH_TYPE:
2864       storage = MB_TAG_MESH;
2865       break;
2866     default:
2867       MB_SET_ERR(MB_FAILURE, "Invalid storage type for tag '" << info.name << "': " << info.storage);
2868   }
2869 
2870   // Type-specific stuff
2871   if (info.type == mhdf_BITFIELD) {
2872     if (info.size < 1 || info.size > 8) {
2873       MB_SET_ERR(MB_FAILURE, "Invalid bit tag: class is MB_TAG_BIT, num bits = " << info.size);
2874     }
2875     hdf_type = H5Tcopy(H5T_NATIVE_B8);
2876     mb_type = MB_TYPE_BIT;
2877     if (hdf_type < 0)
2878       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2879   }
2880   else if (info.type == mhdf_OPAQUE) {
2881     mb_type = MB_TYPE_OPAQUE;
2882 
2883     // Check for user-provided type
2884     Tag type_handle;
2885     std::string tag_type_name = "__hdf5_tag_type_";
2886     tag_type_name += info.name;
2887     rval = iFace->tag_get_handle(tag_type_name.c_str(), sizeof(hid_t), MB_TYPE_OPAQUE, type_handle);
2888     if (MB_SUCCESS == rval) {
2889       EntityHandle root = 0;
2890       rval = iFace->tag_get_data(type_handle, &root, 1, &hdf_type);
2891       if (MB_SUCCESS != rval)
2892         MB_SET_ERR(rval, "ReadHDF5 Failure");
2893       hdf_type = H5Tcopy(hdf_type);
2894       re_read_default = true;
2895     }
2896     else if (MB_TAG_NOT_FOUND == rval) {
2897       hdf_type = 0;
2898     }
2899     else
2900       MB_SET_ERR(rval, "ReadHDF5 Failure");
2901 
2902     if (hdf_type < 0)
2903       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2904   }
2905   else {
2906     switch (info.type) {
2907       case mhdf_INTEGER:
2908         hdf_type = H5T_NATIVE_INT;
2909         mb_type = MB_TYPE_INTEGER;
2910         break;
2911       case mhdf_FLOAT:
2912         hdf_type = H5T_NATIVE_DOUBLE;
2913         mb_type = MB_TYPE_DOUBLE;
2914         break;
2915       case mhdf_BOOLEAN:
2916         hdf_type = H5T_NATIVE_UINT;
2917         mb_type = MB_TYPE_INTEGER;
2918         break;
2919       case mhdf_ENTITY_ID:
2920         hdf_type = handleType;
2921         mb_type = MB_TYPE_HANDLE;
2922         break;
2923       default:
2924         MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2925     }
2926 
2927     if (info.size > 1) { // Array
2928         hsize_t tmpsize = info.size;
2929 #if defined(H5Tarray_create_vers) && H5Tarray_create_vers > 1
2930         hdf_type = H5Tarray_create2(hdf_type, 1, &tmpsize);
2931 #else
2932         hdf_type = H5Tarray_create(hdf_type, 1, &tmpsize, NULL);
2933 #endif
2934     }
2935     else {
2936       hdf_type = H5Tcopy(hdf_type);
2937     }
2938     if (hdf_type < 0)
2939       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
2940   }
2941 
2942   // If default or global/mesh value in file, read it.
2943   if (info.default_value || info.global_value) {
2944     if (re_read_default) {
2945       mhdf_getTagValues(filePtr, info.name, hdf_type, info.default_value, info.global_value, &status);
2946       if (mhdf_isError(&status)) {
2947         if (hdf_type)
2948           H5Tclose(hdf_type);
2949         MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
2950       }
2951     }
2952 
2953     if (MB_TYPE_HANDLE == mb_type) {
2954       if (info.default_value) {
2955         rval = convert_id_to_handle((EntityHandle*)info.default_value, info.default_value_size);
2956         if (MB_SUCCESS != rval) {
2957           if (hdf_type)
2958             H5Tclose(hdf_type);
2959           MB_SET_ERR(rval, "ReadHDF5 Failure");
2960         }
2961       }
2962       if (info.global_value) {
2963         rval = convert_id_to_handle((EntityHandle*)info.global_value, info.global_value_size);
2964         if (MB_SUCCESS != rval) {
2965           if (hdf_type)
2966             H5Tclose(hdf_type);
2967           MB_SET_ERR(rval, "ReadHDF5 Failure");
2968         }
2969       }
2970     }
2971   }
2972 
2973   // Get tag handle, creating if necessary
2974   if (info.size < 0)
2975     rval = iFace->tag_get_handle(info.name, info.default_value_size,
2976                                  mb_type, handle, storage | MB_TAG_CREAT | MB_TAG_VARLEN | MB_TAG_DFTOK,
2977                                  info.default_value);
2978   else
2979     rval = iFace->tag_get_handle(info.name, info.size, mb_type, handle,
2980                                  storage | MB_TAG_CREAT | MB_TAG_DFTOK, info.default_value);
2981   if (MB_SUCCESS != rval) {
2982     if (hdf_type)
2983       H5Tclose(hdf_type);
2984     MB_SET_ERR(MB_FAILURE, "Tag type in file does not match type in database for \"" << info.name << "\"");
2985   }
2986 
2987   if (info.global_value) {
2988     EntityHandle root = 0;
2989     if (info.size > 0) { // Fixed-length tag
2990       rval = iFace->tag_set_data(handle, &root, 1, info.global_value);
2991     }
2992     else {
2993       int tag_size = info.global_value_size;
2994       rval = iFace->tag_set_by_ptr(handle, &root, 1, &info.global_value, &tag_size);
2995     }
2996     if (MB_SUCCESS != rval) {
2997       if (hdf_type)
2998         H5Tclose(hdf_type);
2999       MB_SET_ERR(rval, "ReadHDF5 Failure");
3000     }
3001   }
3002 
3003   return MB_SUCCESS;
3004 }
3005 
read_dense_tag(Tag tag_handle,const char * ent_name,hid_t hdf_read_type,hid_t data,long start_id,long num_values)3006 ErrorCode ReadHDF5::read_dense_tag(Tag tag_handle,
3007                                    const char* ent_name,
3008                                    hid_t hdf_read_type,
3009                                    hid_t data,
3010                                    long start_id,
3011                                    long num_values)
3012 {
3013   CHECK_OPEN_HANDLES;
3014 
3015   ErrorCode rval;
3016   DataType mb_type;
3017 
3018   rval = iFace->tag_get_data_type(tag_handle, mb_type);
3019   if (MB_SUCCESS != rval)
3020     MB_SET_ERR(rval, "ReadHDF5 Failure");
3021 
3022   int read_size;
3023   rval = iFace->tag_get_bytes(tag_handle, read_size);
3024   if (MB_SUCCESS != rval) // Wrong function for variable-length tags
3025     MB_SET_ERR(rval, "ReadHDF5 Failure");
3026   //if (MB_TYPE_BIT == mb_type)
3027     //read_size = (read_size + 7) / 8; // Convert bits to bytes, plus 7 for ceiling
3028 
3029   if (hdf_read_type) { // If not opaque
3030     hsize_t hdf_size = H5Tget_size(hdf_read_type);
3031     if (hdf_size != (hsize_t)read_size)
3032       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3033   }
3034 
3035   // Get actual entities read from file
3036   Range file_ids, handles;
3037   Range::iterator f_ins = file_ids.begin(), h_ins = handles.begin();
3038   IDMap::iterator l, u;
3039   l = idMap.lower_bound(start_id);
3040   u = idMap.lower_bound(start_id + num_values - 1);
3041   if (l != idMap.end() && start_id + num_values > l->begin) {
3042     if (l == u) {
3043       size_t beg = std::max(start_id, l->begin);
3044       size_t end = std::min(start_id + num_values, u->begin + u->count) - 1;
3045       f_ins = file_ids.insert(f_ins, beg, end);
3046       h_ins = handles.insert(h_ins, l->value + (beg - l->begin),
3047                                     l->value + (end - l->begin));
3048     }
3049     else {
3050       size_t beg = std::max(start_id, l->begin);
3051       f_ins = file_ids.insert(f_ins, beg, l->begin + l->count - 1);
3052       h_ins = handles.insert(h_ins, l->value + (beg - l->begin), l->value + l->count - 1);
3053       for (++l; l != u; ++l) {
3054         f_ins = file_ids.insert(f_ins, l->begin, l->begin + l->count - 1);
3055         h_ins = handles.insert(h_ins, l->value, l->value + l->count - 1);
3056       }
3057       if (u != idMap.end() && u->begin < start_id + num_values) {
3058         size_t end = std::min(start_id + num_values, u->begin + u->count - 1);
3059         f_ins = file_ids.insert(f_ins, u->begin, end);
3060         h_ins = handles.insert(h_ins, u->value, u->value + end - u->begin);
3061       }
3062     }
3063   }
3064 
3065   // Given that all of the entities for this dense tag data should
3066   // have been created as a single contiguous block, the resulting
3067   // MOAB handle range should be contiguous.
3068   // THE ABOVE IS NOT NECESSARILY TRUE. SOMETIMES LOWER-DIMENSION
3069   // ENTS ARE READ AND THEN DELETED FOR PARTIAL READS.
3070   //assert(handles.empty() || handles.size() == (handles.back() - handles.front() + 1));
3071 
3072   std::string tn("<error>");
3073   iFace->tag_get_name(tag_handle, tn);
3074   tn += " data for ";
3075   tn += ent_name;
3076   try {
3077     h_ins = handles.begin();
3078     ReadHDF5Dataset reader(tn.c_str(), data, nativeParallel, mpiComm, false);
3079     long buffer_size = bufferSize / read_size;
3080     reader.set_file_ids(file_ids, start_id, buffer_size, hdf_read_type);
3081     dbgOut.printf(3, "Reading dense data for tag \"%s\" and group \"%s\" in %lu chunks\n",
3082                       tn.c_str(), ent_name, reader.get_read_count());
3083     int nn = 0;
3084     while (!reader.done()) {
3085       dbgOut.printf(3, "Reading chunk %d of \"%s\" data\n", ++nn, tn.c_str());
3086 
3087       size_t count;
3088       reader.read(dataBuffer, count);
3089 
3090       if (MB_TYPE_HANDLE == mb_type) {
3091         rval = convert_id_to_handle((EntityHandle*)dataBuffer, count * read_size / sizeof(EntityHandle));
3092         if (MB_SUCCESS != rval)
3093           MB_SET_ERR(rval, "ReadHDF5 Failure");
3094       }
3095 
3096       Range ents;
3097       Range::iterator end = h_ins;
3098       end += count;
3099       ents.insert(h_ins, end);
3100       h_ins = end;
3101 
3102       rval = iFace->tag_set_data(tag_handle, ents, dataBuffer);
3103       if (MB_SUCCESS != rval) {
3104         dbgOut.printf(1, "Internal error setting data for tag \"%s\"\n", tn.c_str());
3105         MB_SET_ERR(rval, "ReadHDF5 Failure");
3106       }
3107     }
3108   }
3109   catch (ReadHDF5Dataset::Exception) {
3110     dbgOut.printf(1, "Internal error reading dense data for tag \"%s\"\n", tn.c_str());
3111     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3112   }
3113 
3114   return MB_SUCCESS;
3115 }
3116 
3117 // Read entire ID table and for those file IDs corresponding
3118 // to entities that we have read from the file add both the
3119 // offset into the offset range and the handle into the handle
3120 // range. If handles are not ordered, switch to using a vector.
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)3121 ErrorCode ReadHDF5::read_sparse_tag_indices(const char* name,
3122                                             hid_t id_table,
3123                                             EntityHandle start_offset, // Can't put zero in a Range
3124                                             Range& offset_range,
3125                                             Range& handle_range,
3126                                             std::vector<EntityHandle>& handle_vect)
3127 {
3128   CHECK_OPEN_HANDLES;
3129 
3130   offset_range.clear();
3131   handle_range.clear();
3132   handle_vect.clear();
3133 
3134   ErrorCode rval;
3135   Range::iterator handle_hint = handle_range.begin();
3136   Range::iterator offset_hint = offset_range.begin();
3137 
3138   EntityHandle* idbuf = (EntityHandle*)dataBuffer;
3139   size_t idbuf_size = bufferSize / sizeof(EntityHandle);
3140 
3141   std::string tn(name);
3142   tn += " indices";
3143 
3144   assert(start_offset > 0); // Can't put zero in a Range
3145   try {
3146     ReadHDF5Dataset id_reader(tn.c_str(), id_table, nativeParallel, mpiComm, false);
3147     id_reader.set_all_file_ids(idbuf_size, handleType);
3148     size_t offset = start_offset;
3149     dbgOut.printf(3, "Reading file ids for sparse tag \"%s\" in %lu chunks\n", name, id_reader.get_read_count());
3150     int nn = 0;
3151     while (!id_reader.done()) {\
3152       dbgOut.printf(3, "Reading chunk %d of \"%s\" IDs\n", ++nn, name);
3153       size_t count;
3154       id_reader.read(idbuf, count);
3155 
3156       rval = convert_id_to_handle(idbuf, count);
3157       if (MB_SUCCESS != rval)
3158         MB_SET_ERR(rval, "ReadHDF5 Failure");
3159 
3160       // idbuf will now contain zero-valued handles for those
3161       // tag values that correspond to entities we are not reading
3162       // from the file.
3163       for (size_t i = 0; i < count; ++i) {
3164         if (idbuf[i]) {
3165           offset_hint = offset_range.insert(offset_hint, offset + i);
3166           if (!handle_vect.empty()) {
3167             handle_vect.push_back(idbuf[i]);
3168           }
3169           else if (handle_range.empty() || idbuf[i] > handle_range.back()) {
3170             handle_hint = handle_range.insert(handle_hint, idbuf[i]);
3171           }
3172           else {
3173             handle_vect.resize(handle_range.size());
3174             std::copy(handle_range.begin(), handle_range.end(), handle_vect.begin());
3175             handle_range.clear();
3176             handle_vect.push_back(idbuf[i]);
3177             dbgOut.print(2, "Switching to unordered list for tag handle list\n");
3178           }
3179         }
3180       }
3181 
3182       offset += count;
3183     }
3184   }
3185   catch (ReadHDF5Dataset::Exception) {
3186     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3187   }
3188 
3189   return MB_SUCCESS;
3190 }
3191 
read_sparse_tag(Tag tag_handle,hid_t hdf_read_type,hid_t id_table,hid_t value_table,long)3192 ErrorCode ReadHDF5::read_sparse_tag(Tag tag_handle,
3193                                     hid_t hdf_read_type,
3194                                     hid_t id_table,
3195                                     hid_t value_table,
3196                                     long /*num_values*/)
3197 {
3198   CHECK_OPEN_HANDLES;
3199 
3200   // Read entire ID table and for those file IDs corresponding
3201   // to entities that we have read from the file add both the
3202   // offset into the offset range and the handle into the handle
3203   // range.  If handles are not ordered, switch to using a vector.
3204   const EntityHandle base_offset = 1; // Can't put zero in a Range
3205   std::vector<EntityHandle> handle_vect;
3206   Range handle_range, offset_range;
3207   std::string tn("<error>");
3208   iFace->tag_get_name(tag_handle, tn);
3209   ErrorCode rval = read_sparse_tag_indices(tn.c_str(),
3210                                            id_table, base_offset,
3211                                            offset_range, handle_range,
3212                                            handle_vect);
3213   if (MB_SUCCESS != rval)
3214     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3215 
3216   DataType mbtype;
3217   rval = iFace->tag_get_data_type(tag_handle, mbtype);
3218   if (MB_SUCCESS != rval)
3219     MB_SET_ERR(rval, "ReadHDF5 Failure");
3220 
3221   int read_size;
3222   rval = iFace->tag_get_bytes(tag_handle, read_size);
3223   if (MB_SUCCESS != rval) // Wrong function for variable-length tags
3224     MB_SET_ERR(rval, "ReadHDF5 Failure");
3225   //if (MB_TYPE_BIT == mbtype)
3226     //read_size = (read_size + 7) / 8; // Convert bits to bytes, plus 7 for ceiling
3227 
3228   if (hdf_read_type) { // If not opaque
3229     hsize_t hdf_size = H5Tget_size(hdf_read_type);
3230     if (hdf_size != (hsize_t)read_size)
3231       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3232   }
3233 
3234   const int handles_per_tag = read_size / sizeof(EntityHandle);
3235 
3236   // Now read data values
3237   size_t chunk_size = bufferSize / read_size;
3238   try {
3239     ReadHDF5Dataset val_reader((tn + " values").c_str(), value_table, nativeParallel, mpiComm, false);
3240     val_reader.set_file_ids(offset_range, base_offset, chunk_size, hdf_read_type);
3241     dbgOut.printf(3, "Reading sparse values for tag \"%s\" in %lu chunks\n", tn.c_str(), val_reader.get_read_count());
3242     int nn = 0;
3243     size_t offset = 0;
3244     while (!val_reader.done()) {
3245       dbgOut.printf(3, "Reading chunk %d of \"%s\" values\n", ++nn, tn.c_str());
3246       size_t count;
3247       val_reader.read(dataBuffer, count);
3248       if (MB_TYPE_HANDLE == mbtype) {
3249         rval = convert_id_to_handle((EntityHandle*)dataBuffer, count*handles_per_tag);
3250         if (MB_SUCCESS != rval)
3251           MB_SET_ERR(rval, "ReadHDF5 Failure");
3252       }
3253 
3254       if (!handle_vect.empty()) {
3255         rval = iFace->tag_set_data(tag_handle, &handle_vect[offset], count, dataBuffer);
3256         offset += count;
3257       }
3258       else {
3259         Range r;
3260         r.merge(handle_range.begin(), handle_range.begin() + count);
3261         handle_range.erase(handle_range.begin(), handle_range.begin() + count);
3262         rval = iFace->tag_set_data(tag_handle, r, dataBuffer);
3263       }
3264       if (MB_SUCCESS != rval)
3265         MB_SET_ERR(rval, "ReadHDF5 Failure");
3266     }
3267   }
3268   catch (ReadHDF5Dataset::Exception) {
3269     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3270   }
3271 
3272   return MB_SUCCESS;
3273 }
3274 
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,long)3275 ErrorCode ReadHDF5::read_var_len_tag(Tag tag_handle,
3276                                      hid_t hdf_read_type,
3277                                      hid_t ent_table,
3278                                      hid_t val_table,
3279                                      hid_t off_table,
3280                                      long /*num_entities*/,
3281                                      long /*num_values*/)
3282 {
3283   CHECK_OPEN_HANDLES;
3284 
3285   ErrorCode rval;
3286   DataType mbtype;
3287 
3288   rval = iFace->tag_get_data_type(tag_handle, mbtype);
3289   if (MB_SUCCESS != rval)
3290     MB_SET_ERR(rval, "ReadHDF5 Failure");
3291 
3292   // Can't do variable-length bit tags
3293   if (MB_TYPE_BIT == mbtype)
3294     MB_CHK_ERR(MB_VARIABLE_DATA_LENGTH);
3295 
3296   // If here, MOAB tag must be variable-length
3297   int mbsize;
3298   if (MB_VARIABLE_DATA_LENGTH != iFace->tag_get_bytes(tag_handle, mbsize)) {
3299     assert(false);
3300     MB_CHK_ERR(MB_VARIABLE_DATA_LENGTH);
3301   }
3302 
3303   int read_size;
3304   if (hdf_read_type) {
3305     hsize_t hdf_size = H5Tget_size(hdf_read_type);
3306     if (hdf_size < 1)
3307       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3308     read_size = hdf_size;
3309   }
3310   else {
3311     // Opaque
3312     read_size = 1;
3313   }
3314 
3315   std::string tn("<error>");
3316   iFace->tag_get_name(tag_handle, tn);
3317 
3318   // Read entire ID table and for those file IDs corresponding
3319   // to entities that we have read from the file add both the
3320   // offset into the offset range and the handle into the handle
3321   // range. If handles are not ordered, switch to using a vector.
3322   const EntityHandle base_offset = 1; // Can't put zero in a Range
3323   std::vector<EntityHandle> handle_vect;
3324   Range handle_range, offset_range;
3325   rval = read_sparse_tag_indices(tn.c_str(),
3326                                  ent_table, base_offset,
3327                                  offset_range, handle_range,
3328                                  handle_vect);
3329 
3330   // This code only works if the id_table is an ordered list.
3331   // This assumption was also true for the previous iteration
3332   // of this code, but wasn't checked. MOAB's file writer
3333   // always writes an ordered list for id_table.
3334   if (!handle_vect.empty()) {
3335     MB_SET_ERR(MB_FAILURE, "Unordered file ids for variable length tag not supported");
3336   }
3337 
3338   class VTReader : public ReadHDF5VarLen {
3339       Tag tagHandle;
3340       bool isHandle;
3341       size_t readSize;
3342       ReadHDF5* readHDF5;
3343     public:
3344       ErrorCode store_data(EntityHandle file_id, void* data, long count, bool)
3345       {
3346         ErrorCode rval1;
3347         if (isHandle) {
3348           assert( readSize == sizeof(EntityHandle) );
3349           rval1 = readHDF5->convert_id_to_handle((EntityHandle*)data, count);MB_CHK_ERR(rval1);
3350         }
3351         int n = count;
3352         return readHDF5->moab()->tag_set_by_ptr(tagHandle, &file_id, 1, &data, &n);
3353       }
3354       VTReader(DebugOutput& debug_output, void* buffer, size_t buffer_size,
3355                Tag tag, bool is_handle_tag, size_t read_size1, ReadHDF5* owner)
3356         : ReadHDF5VarLen(debug_output, buffer, buffer_size),
3357           tagHandle(tag),
3358           isHandle(is_handle_tag),
3359           readSize(read_size1),
3360           readHDF5(owner)
3361       {}
3362   };
3363 
3364   VTReader tool(dbgOut, dataBuffer, bufferSize, tag_handle,
3365                  MB_TYPE_HANDLE == mbtype, read_size, this);
3366   try {
3367     // Read offsets into value table.
3368     std::vector<unsigned> counts;
3369     Range offsets;
3370     ReadHDF5Dataset off_reader((tn + " offsets").c_str(), off_table, nativeParallel, mpiComm, false);
3371     rval = tool.read_offsets(off_reader, offset_range, base_offset,
3372                              base_offset, offsets, counts);
3373     if (MB_SUCCESS != rval)
3374       MB_SET_ERR(rval, "ReadHDF5 Failure");
3375 
3376     // Read tag values
3377     Range empty;
3378     ReadHDF5Dataset val_reader((tn + " values").c_str(), val_table, nativeParallel, mpiComm, false);
3379     rval = tool.read_data(val_reader, offsets, base_offset, hdf_read_type,
3380                           handle_range, counts, empty);
3381     if (MB_SUCCESS != rval)
3382       MB_SET_ERR(rval, "ReadHDF5 Failure");
3383   }
3384   catch (ReadHDF5Dataset::Exception) {
3385     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3386   }
3387 
3388   return MB_SUCCESS;
3389 }
3390 
convert_id_to_handle(EntityHandle * array,size_t size)3391 ErrorCode ReadHDF5::convert_id_to_handle(EntityHandle* array,
3392                                          size_t size)
3393 {
3394   convert_id_to_handle(array, size, idMap);
3395   return MB_SUCCESS;
3396 }
3397 
convert_id_to_handle(EntityHandle * array,size_t size,const RangeMap<long,EntityHandle> & id_map)3398 void ReadHDF5::convert_id_to_handle(EntityHandle* array,
3399                                     size_t size,
3400                                     const RangeMap<long, EntityHandle>& id_map)
3401 {
3402   for (EntityHandle* const end = array + size; array != end; ++array)
3403     *array = id_map.find(*array);
3404 }
3405 
convert_id_to_handle(EntityHandle * array,size_t size,size_t & new_size,const RangeMap<long,EntityHandle> & id_map)3406 void ReadHDF5::convert_id_to_handle(EntityHandle* array,
3407                                     size_t size, size_t& new_size,
3408                                     const RangeMap<long, EntityHandle>& id_map)
3409 {
3410   RangeMap<long, EntityHandle>::const_iterator it;
3411   new_size = 0;
3412   for (size_t i = 0; i < size; ++i) {
3413     it = id_map.lower_bound(array[i]);
3414     if (it != id_map.end() && it->begin <= (long)array[i])
3415       array[new_size++] = it->value + (array[i] - it->begin);
3416   }
3417 }
3418 
convert_range_to_handle(const EntityHandle * ranges,size_t num_ranges,const RangeMap<long,EntityHandle> & id_map,Range & merge)3419 void ReadHDF5::convert_range_to_handle(const EntityHandle* ranges,
3420                                        size_t num_ranges,
3421                                        const RangeMap<long, EntityHandle>& id_map,
3422                                        Range& merge)
3423 {
3424   RangeMap<long, EntityHandle>::iterator it = id_map.begin();
3425   Range::iterator hint = merge.begin();
3426   for (size_t i = 0; i < num_ranges; ++i) {
3427     long id = ranges[2*i];
3428     const long end = id + ranges[2*i + 1];
3429     // We assume that 'ranges' is sorted, but check just in case it isn't.
3430     if (it == id_map.end() || it->begin > id)
3431       it = id_map.begin();
3432     it = id_map.lower_bound(it, id_map.end(), id);
3433     if (it == id_map.end())
3434       continue;
3435     if (id < it->begin)
3436       id = it->begin;
3437     while (id < end) {
3438       if (id < it->begin) id = it->begin;
3439       const long off = id - it->begin;
3440       long count = std::min(it->count - off,  end - id);
3441       // It is possible that this new subrange is starting after the end
3442       // It will result in negative count, which does not make sense
3443       // We are done with this range, go to the next one
3444       if (count <= 0)
3445         break;
3446       hint = merge.insert(hint, it->value + off, it->value + off + count - 1);
3447       id += count;
3448       if (id < end) {
3449         if (++it == id_map.end())
3450           break;
3451         if (it->begin > end)
3452           break;
3453       }
3454     }
3455   }
3456 }
3457 
convert_range_to_handle(const EntityHandle * array,size_t num_ranges,Range & range)3458 ErrorCode ReadHDF5::convert_range_to_handle(const EntityHandle* array,
3459                                             size_t num_ranges,
3460                                             Range& range)
3461 {
3462   convert_range_to_handle(array, num_ranges, idMap, range);
3463   return MB_SUCCESS;
3464 }
3465 
insert_in_id_map(const Range & file_ids,EntityHandle start_id)3466 ErrorCode ReadHDF5::insert_in_id_map(const Range& file_ids,
3467                                      EntityHandle start_id)
3468 {
3469   IDMap tmp_map;
3470   bool merge = !idMap.empty() && !file_ids.empty() && idMap.back().begin > (long)file_ids.front();
3471   IDMap& map = merge ? tmp_map : idMap;
3472   Range::const_pair_iterator p;
3473   for (p = file_ids.const_pair_begin(); p != file_ids.const_pair_end(); ++p) {
3474     size_t count = p->second - p->first + 1;
3475     if (!map.insert(p->first, start_id, count).second)
3476       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3477     start_id += count;
3478   }
3479   if (merge && !idMap.merge(tmp_map))
3480     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3481 
3482   return MB_SUCCESS;
3483 }
3484 
insert_in_id_map(long file_id,EntityHandle handle)3485 ErrorCode ReadHDF5::insert_in_id_map(long file_id,
3486                                      EntityHandle handle)
3487 {
3488   if (!idMap.insert(file_id, handle, 1).second)
3489     MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3490   return MB_SUCCESS;
3491 }
3492 
read_qa(EntityHandle)3493 ErrorCode ReadHDF5::read_qa(EntityHandle)
3494 {
3495   CHECK_OPEN_HANDLES;
3496 
3497   mhdf_Status status;
3498   //std::vector<std::string> qa_list;
3499 
3500   int qa_len;
3501   char** qa = mhdf_readHistory(filePtr, &qa_len, &status);
3502   if (mhdf_isError(&status)) {
3503     MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3504   }
3505   //qa_list.resize(qa_len);
3506   for (int i = 0; i < qa_len; i++) {
3507     //qa_list[i] = qa[i];
3508     free(qa[i]);
3509   }
3510   free(qa);
3511 
3512   /** FIX ME - how to put QA list on set?? */
3513 
3514   return MB_SUCCESS;
3515 }
3516 
store_file_ids(Tag tag)3517 ErrorCode ReadHDF5::store_file_ids(Tag tag)
3518 {
3519   CHECK_OPEN_HANDLES;
3520 
3521   //typedef int tag_type;
3522   typedef long tag_type;
3523   // change it to be able to read much bigger files (long is 64 bits ...)
3524 
3525   tag_type* buffer = reinterpret_cast<tag_type*>(dataBuffer);
3526   const long buffer_size = bufferSize / sizeof(tag_type);
3527   for (IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i) {
3528     IDMap::Range range = *i;
3529 
3530     // Make sure the values will fit in the tag type
3531     IDMap::key_type rv = range.begin + (range.count - 1);
3532     tag_type tv = (tag_type)rv;
3533     if ((IDMap::key_type)tv != rv) {
3534       assert(false);
3535       return MB_INDEX_OUT_OF_RANGE;
3536     }
3537 
3538     while (range.count) {
3539       long count = buffer_size < range.count ? buffer_size : range.count;
3540 
3541       Range handles;
3542       handles.insert(range.value, range.value + count - 1);
3543       range.value += count;
3544       range.count -= count;
3545       for (long j = 0; j < count; ++j)
3546         buffer[j] = (tag_type)range.begin++;
3547 
3548       ErrorCode rval = iFace->tag_set_data(tag, handles, buffer);
3549       if (MB_SUCCESS != rval)
3550         return rval;
3551     }
3552   }
3553 
3554   return MB_SUCCESS;
3555 }
3556 
store_sets_file_ids()3557 ErrorCode ReadHDF5::store_sets_file_ids()
3558 {
3559   CHECK_OPEN_HANDLES;
3560 
3561   // create a tag that will not be saved, but it will be
3562   // used by visit plugin to match the sets and their file ids
3563   // it is the same type as the tag defined in ReadParallelcpp, for file id
3564   Tag setFileIdTag;
3565   long default_val=0;
3566   ErrorCode rval = iFace->tag_get_handle("__FILE_ID_FOR_SETS", sizeof(long), MB_TYPE_OPAQUE, setFileIdTag,
3567       (MB_TAG_DENSE | MB_TAG_CREAT),  &default_val);
3568 
3569   if (MB_SUCCESS != rval || 0==setFileIdTag)
3570     return rval;
3571   //typedef int tag_type;
3572   typedef long tag_type;
3573   // change it to be able to read much bigger files (long is 64 bits ...)
3574 
3575   tag_type* buffer = reinterpret_cast<tag_type*>(dataBuffer);
3576   const long buffer_size = bufferSize / sizeof(tag_type);
3577   for (IDMap::iterator i = idMap.begin(); i != idMap.end(); ++i) {
3578     IDMap::Range range = *i;
3579     EntityType htype = iFace->type_from_handle(range.value);
3580     if (MBENTITYSET!=htype)
3581       continue;
3582     // work only with entity sets
3583     // Make sure the values will fit in the tag type
3584     IDMap::key_type rv = range.begin + (range.count - 1);
3585     tag_type tv = (tag_type)rv;
3586     if ((IDMap::key_type)tv != rv) {
3587       assert(false);
3588       return MB_INDEX_OUT_OF_RANGE;
3589     }
3590 
3591     while (range.count) {
3592       long count = buffer_size < range.count ? buffer_size : range.count;
3593 
3594       Range handles;
3595       handles.insert(range.value, range.value + count - 1);
3596       range.value += count;
3597       range.count -= count;
3598       for (long j = 0; j < count; ++j)
3599         buffer[j] = (tag_type)range.begin++;
3600 
3601       rval = iFace->tag_set_data(setFileIdTag, handles, buffer);
3602       if (MB_SUCCESS != rval)
3603         return rval;
3604     }
3605   }
3606   return MB_SUCCESS;
3607 }
3608 
read_tag_values(const char * file_name,const char * tag_name,const FileOptions & opts,std::vector<int> & tag_values_out,const SubsetList * subset_list)3609 ErrorCode ReadHDF5::read_tag_values(const char* file_name,
3610                                     const char* tag_name,
3611                                     const FileOptions& opts,
3612                                     std::vector<int>& tag_values_out,
3613                                     const SubsetList* subset_list)
3614 {
3615   ErrorCode rval;
3616 
3617   rval = set_up_read(file_name, opts);
3618   if (MB_SUCCESS != rval)
3619     MB_SET_ERR(rval, "ReadHDF5 Failure");
3620 
3621   int tag_index;
3622   rval = find_int_tag(tag_name, tag_index);
3623   if (MB_SUCCESS != rval) {
3624     clean_up_read(opts);
3625     MB_SET_ERR(rval, "ReadHDF5 Failure");
3626   }
3627 
3628   if (subset_list) {
3629     Range file_ids;
3630     rval = get_subset_ids(subset_list->tag_list, subset_list->tag_list_length, file_ids);
3631     if (MB_SUCCESS != rval) {
3632       clean_up_read(opts);
3633       MB_SET_ERR(rval, "ReadHDF5 Failure");
3634     }
3635 
3636     rval = read_tag_values_partial(tag_index, file_ids, tag_values_out);
3637     if (MB_SUCCESS != rval) {
3638       clean_up_read(opts);
3639       MB_SET_ERR(rval, "ReadHDF5 Failure");
3640     }
3641   }
3642   else {
3643     rval = read_tag_values_all(tag_index, tag_values_out);
3644     if (MB_SUCCESS != rval) {
3645       clean_up_read(opts);
3646       MB_SET_ERR(rval, "ReadHDF5 Failure");
3647     }
3648   }
3649 
3650   return clean_up_read(opts);
3651 }
3652 
read_tag_values_partial(int tag_index,const Range & file_ids,std::vector<int> & tag_values)3653 ErrorCode ReadHDF5::read_tag_values_partial(int tag_index,
3654                                             const Range& file_ids,
3655                                             std::vector<int>& tag_values)
3656 {
3657   CHECK_OPEN_HANDLES;
3658 
3659   mhdf_Status status;
3660   const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
3661   long num_ent, num_val;
3662   size_t count;
3663   std::string tn(tag.name);
3664 
3665   // Read sparse values
3666   if (tag.have_sparse) {
3667     hid_t handles[3];
3668     mhdf_openSparseTagData(filePtr, tag.name, &num_ent, &num_val, handles, &status);
3669     if (mhdf_isError(&status)) {
3670       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3671     }
3672 
3673     try {
3674       // Read all entity handles and fill 'offsets' with ranges of
3675       // offsets into the data table for entities that we want.
3676       Range offsets;
3677       long* buffer = reinterpret_cast<long*>(dataBuffer);
3678       const long buffer_size = bufferSize/sizeof(long);
3679       ReadHDF5Dataset ids((tn + " ids").c_str(), handles[0], nativeParallel, mpiComm);
3680       ids.set_all_file_ids(buffer_size, H5T_NATIVE_LONG);
3681       size_t offset = 0;
3682       dbgOut.printf(3, "Reading sparse IDs for tag \"%s\" in %lu chunks\n",
3683                     tag.name, ids.get_read_count());
3684       int nn = 0;
3685       while (!ids.done()) {
3686         dbgOut.printf(3, "Reading chunk %d of IDs for \"%s\"\n", ++nn, tag.name);
3687         ids.read(buffer, count);
3688 
3689         std::sort(buffer, buffer + count);
3690         Range::iterator ins = offsets.begin();
3691         Range::const_iterator i = file_ids.begin();
3692         for (size_t j = 0; j < count; ++j) {
3693           while (i != file_ids.end() && (long)*i < buffer[j])
3694             ++i;
3695           if (i == file_ids.end())
3696             break;
3697           if ((long)*i == buffer[j]) {
3698             ins = offsets.insert(ins, j + offset, j + offset);
3699           }
3700         }
3701 
3702         offset += count;
3703       }
3704 
3705       tag_values.clear();
3706       tag_values.reserve(offsets.size());
3707       const size_t data_buffer_size = bufferSize / sizeof(int);
3708       int* data_buffer = reinterpret_cast<int*>(dataBuffer);
3709       ReadHDF5Dataset vals((tn + " sparse vals").c_str(), handles[1], nativeParallel, mpiComm);
3710       vals.set_file_ids(offsets, 0, data_buffer_size, H5T_NATIVE_INT);
3711       dbgOut.printf(3, "Reading sparse values for tag \"%s\" in %lu chunks\n",
3712                     tag.name, vals.get_read_count());
3713       nn = 0;
3714       // Should normally only have one read call, unless sparse nature
3715       // of file_ids caused reader to do something strange
3716       while (!vals.done()) {
3717         dbgOut.printf(3, "Reading chunk %d of values for \"%s\"\n", ++nn, tag.name);
3718         vals.read(data_buffer, count);
3719         tag_values.insert(tag_values.end(), data_buffer, data_buffer + count);
3720       }
3721     }
3722     catch (ReadHDF5Dataset::Exception) {
3723       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3724     }
3725   }
3726 
3727   std::sort(tag_values.begin(), tag_values.end());
3728   tag_values.erase(std::unique(tag_values.begin(), tag_values.end()), tag_values.end());
3729 
3730   // Read dense values
3731   std::vector<int> prev_data, curr_data;
3732   for (int i = 0; i < tag.num_dense_indices; ++i) {
3733     int grp = tag.dense_elem_indices[i];
3734     const char* gname = 0;
3735     mhdf_EntDesc* desc = 0;
3736     if (grp == -1) {
3737       gname = mhdf_node_type_handle();
3738       desc = &fileInfo->nodes;
3739     }
3740     else if (grp == -2) {
3741       gname = mhdf_set_type_handle();
3742       desc = &fileInfo->sets;
3743     }
3744     else {
3745       assert(grp >= 0 && grp < fileInfo->num_elem_desc);
3746       gname = fileInfo->elems[grp].handle;
3747       desc = &fileInfo->elems[grp].desc;
3748     }
3749 
3750     Range::iterator s = file_ids.lower_bound((EntityHandle)(desc->start_id));
3751     Range::iterator e = Range::lower_bound(s, file_ids.end(),
3752                                            (EntityHandle)(desc->start_id) + desc->count);
3753     Range subset;
3754     subset.merge(s, e);
3755 
3756     hid_t handle = mhdf_openDenseTagData(filePtr, tag.name, gname, &num_val, &status);
3757     if (mhdf_isError(&status)) {
3758       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3759     }
3760 
3761     try {
3762       curr_data.clear();
3763       tag_values.reserve(subset.size());
3764       const size_t data_buffer_size = bufferSize/sizeof(int);
3765       int* data_buffer = reinterpret_cast<int*>(dataBuffer);
3766 
3767       ReadHDF5Dataset reader((tn + " dense vals").c_str(), handle, nativeParallel, mpiComm);
3768       reader.set_file_ids(subset, desc->start_id, data_buffer_size, H5T_NATIVE_INT);
3769       dbgOut.printf(3, "Reading dense data for tag \"%s\" and group \"%s\" in %lu chunks\n",
3770                     tag.name, fileInfo->elems[grp].handle, reader.get_read_count());
3771       int nn = 0;
3772       // Should normally only have one read call, unless sparse nature
3773       // of file_ids caused reader to do something strange
3774       while (!reader.done()) {
3775         dbgOut.printf(3, "Reading chunk %d of \"%s\"/\"%s\"\n", ++nn, tag.name, fileInfo->elems[grp].handle);
3776         reader.read(data_buffer, count);
3777         curr_data.insert(curr_data.end(), data_buffer, data_buffer + count);
3778       }
3779     }
3780     catch (ReadHDF5Dataset::Exception) {
3781       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3782     }
3783 
3784     std::sort(curr_data.begin(), curr_data.end());
3785     curr_data.erase(std::unique(curr_data.begin(), curr_data.end()), curr_data.end());
3786     prev_data.clear();
3787     tag_values.swap(prev_data);
3788     std::set_union(prev_data.begin(), prev_data.end(),
3789                    curr_data.begin(), curr_data.end(),
3790                    std::back_inserter(tag_values));
3791   }
3792 
3793   return MB_SUCCESS;
3794 }
3795 
read_tag_values_all(int tag_index,std::vector<int> & tag_values)3796 ErrorCode ReadHDF5::read_tag_values_all(int tag_index,
3797                                         std::vector<int>& tag_values)
3798 {
3799   CHECK_OPEN_HANDLES;
3800 
3801   mhdf_Status status;
3802   const mhdf_TagDesc& tag = fileInfo->tags[tag_index];
3803   long junk, num_val;
3804 
3805   // Read sparse values
3806   if (tag.have_sparse) {
3807     hid_t handles[3];
3808     mhdf_openSparseTagData(filePtr, tag.name, &junk, &num_val, handles, &status);
3809     if (mhdf_isError(&status)) {
3810       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3811     }
3812 
3813     mhdf_closeData(filePtr, handles[0], &status);
3814     if (mhdf_isError(&status)) {
3815       MB_SET_ERR_CONT(mhdf_message(&status));
3816       mhdf_closeData(filePtr, handles[1], &status);
3817       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3818     }
3819 
3820     hid_t file_type = H5Dget_type(handles[1]);
3821     tag_values.resize(num_val);
3822     mhdf_readTagValuesWithOpt(handles[1], 0, num_val, file_type,
3823                               &tag_values[0], collIO, &status);
3824     if (mhdf_isError(&status)) {
3825       MB_SET_ERR_CONT(mhdf_message(&status));
3826       H5Tclose(file_type);
3827       mhdf_closeData(filePtr, handles[1], &status);
3828       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3829     }
3830     H5Tconvert(file_type, H5T_NATIVE_INT, num_val, &tag_values[0], 0, H5P_DEFAULT);
3831     H5Tclose(file_type);
3832 
3833     mhdf_closeData(filePtr, handles[1], &status);
3834     if (mhdf_isError(&status)) {
3835       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3836     }
3837   }
3838 
3839   std::sort(tag_values.begin(), tag_values.end());
3840   tag_values.erase(std::unique(tag_values.begin(), tag_values.end()), tag_values.end());
3841 
3842   // Read dense values
3843   std::vector<int> prev_data, curr_data;
3844   for (int i = 0; i < tag.num_dense_indices; ++i) {
3845     int grp = tag.dense_elem_indices[i];
3846     const char* gname = 0;
3847     if (grp == -1)
3848       gname = mhdf_node_type_handle();
3849     else if (grp == -2)
3850       gname = mhdf_set_type_handle();
3851     else
3852       gname = fileInfo->elems[grp].handle;
3853     hid_t handle = mhdf_openDenseTagData(filePtr, tag.name, gname, &num_val, &status);
3854     if (mhdf_isError(&status)) {
3855       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3856     }
3857 
3858     hid_t file_type = H5Dget_type(handle);
3859     curr_data.resize(num_val);
3860     mhdf_readTagValuesWithOpt(handle, 0, num_val, file_type, &curr_data[0], collIO, &status);
3861     if (mhdf_isError(&status)) {
3862       MB_SET_ERR_CONT(mhdf_message(&status));
3863       H5Tclose(file_type);
3864       mhdf_closeData(filePtr, handle, &status);
3865       MB_SET_ERR(MB_FAILURE, "ReadHDF5 Failure");
3866     }
3867 
3868     H5Tconvert(file_type, H5T_NATIVE_INT, num_val, &curr_data[0], 0, H5P_DEFAULT);
3869     H5Tclose(file_type);
3870     mhdf_closeData(filePtr, handle, &status);
3871     if (mhdf_isError(&status)) {
3872       MB_SET_ERR(MB_FAILURE, mhdf_message(&status));
3873     }
3874 
3875     std::sort(curr_data.begin(), curr_data.end());
3876     curr_data.erase(std::unique(curr_data.begin(), curr_data.end()), curr_data.end());
3877 
3878     prev_data.clear();
3879     tag_values.swap(prev_data);
3880     std::set_union(prev_data.begin(), prev_data.end(),
3881                    curr_data.begin(), curr_data.end(),
3882                    std::back_inserter(tag_values));
3883   }
3884 
3885   return MB_SUCCESS;
3886 }
print_times()3887 void ReadHDF5::print_times()
3888 {
3889 #ifdef MOAB_HAVE_MPI
3890   if (!myPcomm) {
3891     double recv[NUM_TIMES];
3892     MPI_Reduce((void*)_times, recv, NUM_TIMES, MPI_DOUBLE, MPI_MAX, 0, myPcomm->proc_config().proc_comm());
3893     for (int i=0; i<NUM_TIMES; i++)
3894       _times[i]=recv[i]; // just get the max from all of them
3895   }
3896   if (0==myPcomm->proc_config().proc_rank() )
3897   {
3898 #endif
3899 
3900     std::cout << "ReadHDF5:             " << _times[TOTAL_TIME] << std::endl
3901               << "  get set meta        " << _times[SET_META_TIME] << std::endl
3902               << "  partial subsets     " << _times[SUBSET_IDS_TIME] << std::endl
3903               << "  partition time      " << _times[GET_PARTITION_TIME] << std::endl
3904               << "  get set ids         " << _times[GET_SET_IDS_TIME] << std::endl
3905               << "  set contents        " << _times[GET_SET_CONTENTS_TIME] << std::endl
3906               << "  polyhedra           " << _times[GET_POLYHEDRA_TIME] << std::endl
3907               << "  elements            " << _times[GET_ELEMENTS_TIME] << std::endl
3908               << "  nodes               " << _times[GET_NODES_TIME] << std::endl
3909               << "  node adjacency      " << _times[GET_NODEADJ_TIME] << std::endl
3910               << "  side elements       " << _times[GET_SIDEELEM_TIME] << std::endl
3911               << "  update connectivity " << _times[UPDATECONN_TIME] << std::endl
3912               << "  adjacency           " << _times[ADJACENCY_TIME] << std::endl
3913               << "  delete non_adj      "  << _times[DELETE_NON_SIDEELEM_TIME] << std::endl
3914               << "  recursive sets      " << _times[READ_SET_IDS_RECURS_TIME] << std::endl
3915               << "  find contain_sets   " << _times[FIND_SETS_CONTAINING_TIME] << std::endl
3916               << "  read sets           " << _times[READ_SETS_TIME] << std::endl
3917               << "  read tags           " << _times[READ_TAGS_TIME] << std::endl
3918               << "  store file ids      " << _times[STORE_FILE_IDS_TIME] << std::endl
3919               << "  read qa records     " << _times[READ_QA_TIME] << std::endl;
3920 
3921 #ifdef MOAB_HAVE_MPI
3922   }
3923 #endif
3924 }
3925 
3926 } // namespace moab
3927