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