#include #include #include "h5core/h5_core.h" #include "h5_core_private.h" #define MIN( x, y ) ( (x) <= (y) ? (x) : (y) ) #define MAX( x, y ) ( (x) >= (y) ? (x) : (y) ) /*! \note A partition must not be part of another partition. A partition must not divide another partition into two pieces. After handling the ghost zones, the partition must not be empty We must track the overall size somewhere. This is a good place to do it. (?) */ static void _normalize_partition ( h5b_partition_t *const p /*!< IN/OUT: partition */ ) { h5_size_t tmp; p->i_start = MAX(0, p->i_start); p->j_start = MAX(0, p->j_start); p->k_start = MAX(0, p->k_start); if ( p->i_start > p->i_end ) { tmp = p->i_start; p->i_start = p->i_end; p->i_end = tmp; } if ( p->j_start > p->j_end ) { tmp = p->j_start; p->j_start = p->j_end; p->j_end = tmp; } if ( p->k_start > p->k_end ) { tmp = p->k_start; p->k_start = p->k_end; p->k_end = tmp; } } #ifdef PARALLEL_IO /* MLH: this could be improved with an MPI_Reduce and MAX operator... * but the user_layout array-of-structs would need to be a struct-of-arrays */ static void _get_max_dimensions ( h5_file_t *const f, h5b_partition_t *const user_layout ) { int proc; h5b_fdata_t *b = f->b; h5b_partition_t *p = user_layout; b->i_max = 0; b->j_max = 0; b->k_max = 0; for ( proc = 0; proc < f->nprocs; proc++, p++ ) { if ( p->i_end > b->i_max ) b->i_max = p->i_end; if ( p->j_end > b->j_max ) b->j_max = p->j_end; if ( p->k_end > b->k_max ) b->k_max = p->k_end; } } #define _NO_GHOSTZONE(p,q) ( (p->i_end < q->i_start) \ || (p->j_end < q->j_start) \ || (p->k_end < q->k_start) ) /*! \ingroup h5block_private \internal Check whether two partitions have a common ghost-zone. \return value != \c 0 if yes otherwise \c 0 */ static inline int have_ghostzone ( const h5b_partition_t *const p, /*!< IN: partition \c p */ const h5b_partition_t *const q /*!< IN: partition \c q */ ) { return ( ! ( _NO_GHOSTZONE ( p, q ) || _NO_GHOSTZONE ( q, p ) ) ); } /*! \ingroup h5block_private \internal Calculate volume of partition. \return volume */ static inline h5_int64_t volume_of_partition ( const h5b_partition_t *const p /*!< IN: partition */ ) { return (p->i_end - p->i_start) * (p->j_end - p->j_start) * (p->k_end - p->k_start); } /*! \ingroup h5block_private \internal Calc volume of ghost-zone. \return volume */ static inline h5_int64_t volume_of_ghostzone ( const h5b_partition_t *const p, /*!< IN: ptr to first partition */ const h5b_partition_t *const q /*!< IN: ptr to second partition */ ) { h5_int64_t dx = MIN ( p->i_end, q->i_end ) - MAX ( p->i_start, q->i_start ) + 1; h5_int64_t dy = MIN ( p->j_end, q->j_end ) - MAX ( p->j_start, q->j_start ) + 1; h5_int64_t dz = MIN ( p->k_end, q->k_end ) - MAX ( p->k_start, q->k_start ) + 1; return dx * dy * dz; } /*! \ingroup h5block_private \internal Dissolve ghost-zone by moving the X coordinates. Nothing will be changed if \c { p->i_start <= q->i_end <= p->i_end }. In this case \c -1 will be returned. \return H5_SUCCESS or -1 */ static h5_int64_t _dissolve_X_ghostzone ( h5b_partition_t *const p, /*!< IN/OUT: ptr to first partition */ h5b_partition_t *const q /*!< IN/OUT: ptr to second partition */ ) { if ( p->i_start > q->i_start ) return _dissolve_X_ghostzone( q, p ); if ( q->i_end <= p->i_end ) /* no dissolving */ return -1; p->i_end = ( p->i_end + q->i_start ) >> 1; q->i_start = p->i_end + 1; return 0; } /*! \ingroup h5block_private \internal Dissolve ghost-zone by moving the Y coordinates. Nothing will be changed if \c { p->j_start <= q->j_end <= p->j_end }. In this case \c -1 will be returned. \return H5_SUCCESS or -1 */ static h5_int64_t _dissolve_Y_ghostzone ( h5b_partition_t *const p, /*!< IN/OUT: ptr to first partition */ h5b_partition_t *const q /*!< IN/OUT: ptr to second partition */ ) { if ( p->j_start > q->j_start ) return _dissolve_Y_ghostzone( q, p ); if ( q->j_end <= p->j_end ) /* no dissolving */ return -1; p->j_end = ( p->j_end + q->j_start ) >> 1; q->j_start = p->j_end + 1; return 0; } /*! \ingroup h5block_private \internal Dissolve ghost-zone by moving the Z coordinates. Nothing will be changed if \c { p->k_start <= q->k_end <= p->k_end }. In this case \c -1 will be returned. \return H5_SUCCESS or -1 */ static h5_int64_t _dissolve_Z_ghostzone ( h5b_partition_t *const p, /*!< IN/OUT: ptr to first partition */ h5b_partition_t *const q /*!< IN/OUT: ptr to second partition */ ) { if ( p->k_start > q->k_start ) return _dissolve_Z_ghostzone( q, p ); if ( q->k_end <= p->k_end ) /* no dissolving */ return -1; p->k_end = ( p->k_end + q->k_start ) >> 1; q->k_start = p->k_end + 1; return 0; } /*! \ingroup h5block_private \internal Dissolve ghost-zone for partitions \p and \q. Dissolving is done by moving either the X, Y or Z plane. We never move more than one plane per partition. Thus we always have three possibilities to dissolve the ghost-zone. The "best" is the one with the largest remaining volume of the partitions. \return H5_SUCCESS or error code. */ static h5_err_t _dissolve_ghostzone ( h5_file_t *const f, h5b_partition_t *const p, /*!< IN/OUT: ptr to first partition */ h5b_partition_t *const q /*!< IN/OUT: ptr to second partition */ ) { UNUSED_ARGUMENT (f); h5b_partition_t p_; h5b_partition_t q_; h5b_partition_t p_best; h5b_partition_t q_best; h5_int64_t vol; h5_int64_t max_vol = 0; p_ = *p; q_ = *q; if ( _dissolve_X_ghostzone ( &p_, &q_ ) == 0 ) { vol = volume_of_partition ( &p_ ) + volume_of_partition ( &q_ ); if ( vol > max_vol ) { max_vol = vol; p_best = p_; q_best = q_; } } p_ = *p; q_ = *q; if ( _dissolve_Y_ghostzone ( &p_, &q_ ) == 0 ) { vol = volume_of_partition ( &p_ ) + volume_of_partition ( &q_ ); if ( vol > max_vol ) { max_vol = vol; p_best = p_; q_best = q_; } } p_ = *p; q_ = *q; if ( _dissolve_Z_ghostzone ( &p_, &q_ ) == 0 ) { vol = volume_of_partition ( &p_ ) + volume_of_partition ( &q_ ); if ( vol > max_vol ) { max_vol = vol; p_best = p_; q_best = q_; } } if ( max_vol <= 0 ) { return h5_error ( H5_ERR_LAYOUT, "Cannot dissolve ghostzones in specified layout!" ); } *p = p_best; *q = q_best; return H5_SUCCESS; } /*! \ingroup h5block_private \internal Dissolve all ghost-zones. Ghost-zone are dissolved in the order of their magnitude, largest first. \note Dissolving ghost-zones automaticaly is not trivial! The implemented algorithmn garanties, that there are no ghost-zones left and that we have the same result on all processors. But there may be zones which are not assigned to a partition any more. May be we should check this and return an error in this case. Then the user have to decide to continue or to abort. \b {Error Codes} \b H5PART_NOMEM_ERR \return H5_SUCCESS or error code. */ static inline h5_err_t _dissolve_ghostzones ( h5_file_t *const f, const h5b_partition_t *const user_layout, h5b_partition_t *const write_layout ) { H5_PRIV_FUNC_ENTER (h5_err_t, "f=%p, user_layout=%p, write_layout=%p", f, user_layout, write_layout); h5b_partition_t *p; h5b_partition_t *q; int proc_p, proc_q; struct list { struct list *prev; struct list *next; h5b_partition_t *p; h5b_partition_t *q; h5_int64_t vol; } *p_begin, *p_el, *p_max, *p_end, *p_save; memcpy( write_layout, user_layout, f->nprocs*sizeof(h5b_partition_t) ); TRY( p_begin = (struct list*)h5_calloc (1, sizeof(*p_begin)) ); p_max = p_end = p_begin; memset( p_begin, 0, sizeof ( *p_begin ) ); for ( proc_p = 0, p = write_layout; proc_p < f->nprocs-1; proc_p++, p++ ) { for ( proc_q = proc_p+1, q = &write_layout[proc_q]; proc_q < f->nprocs; proc_q++, q++ ) { if ( have_ghostzone ( p, q ) ) { TRY( p_el = (struct list*)h5_calloc (1, sizeof(*p_el)) ); p_el->p = p; p_el->q = q; p_el->vol = volume_of_ghostzone ( p, q ); p_el->prev = p_end; p_el->next = NULL; if ( p_el->vol > p_max->vol ) p_max = p_el; p_end->next = p_el; p_end = p_el; } } } while ( p_begin->next ) { if ( p_max->next ) p_max->next->prev = p_max->prev; p_max->prev->next = p_max->next; _dissolve_ghostzone ( f, p_max->p, p_max->q ); h5_free (p_max); p_el = p_max = p_begin->next; while ( p_el ) { if ( have_ghostzone ( p_el->p, p_el->q ) ) { p_el->vol = volume_of_ghostzone ( p_el->p, p_el->q ); if ( p_el->vol > p_max->vol ) p_max = p_el; p_el = p_el->next; } else { if ( p_el->next ) p_el->next->prev = p_el->prev; p_el->prev->next = p_el->next; p_save = p_el->next; h5_free (p_el); p_el = p_save; } } } h5_free (p_begin); H5_PRIV_FUNC_RETURN (H5_SUCCESS); } #endif h5_err_t h5bpriv_release_hyperslab ( h5_file_t *const f /*!< IN: file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); if (f->b->shape > 0) { TRY (hdf5_close_dataspace (f->b->shape)); f->b->shape = -1; } if (f->b->diskshape > 0) { TRY (hdf5_close_dataspace(f->b->diskshape)); f->b->diskshape = -1; } if (f->b->memshape > 0) { TRY (hdf5_close_dataspace(f->b->memshape)); f->b->memshape = -1; } H5_PRIV_API_RETURN (H5_SUCCESS); } h5_err_t h5bpriv_open_block_group ( h5_file_t *const f /*!< IN: file handle */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p", f); h5b_fdata_t *b = f->b; TRY (hdf5_close_group (b->block_gid)); b->block_gid = hdf5_open_group (f->step_gid, H5_BLOCKNAME); if (f->b->block_gid < 0) H5_PRIV_API_LEAVE (h5_error( H5_ERR_INVAL, "Time step does not contain H5Block data!")); H5_PRIV_API_RETURN (H5_SUCCESS); } static h5_err_t _create_block_group ( h5_file_t *const f /*!< IN: file handle */ ) { H5_PRIV_FUNC_ENTER (h5_err_t, "f=%p", f); h5_err_t exists; TRY (exists = hdf5_link_exists (f->step_gid, H5_BLOCKNAME)); if (exists > 0) { TRY (h5bpriv_open_block_group(f)); } else { TRY (hdf5_close_group(f->b->block_gid) ); TRY (f->b->block_gid = hdf5_create_group( f->step_gid, H5_BLOCKNAME) ); } H5_PRIV_FUNC_RETURN (H5_SUCCESS); } h5_err_t h5bpriv_have_field_group ( h5_file_t *const f, /*!< IN: file handle */ const char *name ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p, name='%s'", f, name); char name2[H5_DATANAME_LEN]; h5_normalize_dataset_name (name, name2); TRY( h5bpriv_open_block_group(f) ); H5_PRIV_API_RETURN (hdf5_link_exists(f->b->block_gid, name2)); } h5_err_t h5bpriv_open_field_group ( h5_file_t *const f, /*!< IN: file handle */ const char *name ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p, name='%s'", f, name); char name2[H5_DATANAME_LEN]; h5_normalize_dataset_name (name, name2); TRY (hdf5_close_group (f->b->field_gid)); TRY (h5bpriv_open_block_group (f)); f->b->field_gid = hdf5_open_group (f->b->block_gid, name2); if (f->b->field_gid < 0) return h5_error( H5_ERR_INVAL, "Field '%s' does not exist!", name2); H5_PRIV_API_RETURN (H5_SUCCESS); } h5_err_t h5bpriv_create_field_group ( h5_file_t *const f, /*!< IN: file handle */ const char *name /*!< IN: name of field group to create */ ) { H5_PRIV_API_ENTER (h5_err_t, "f=%p, name='%s'", f, name); h5b_fdata_t *b = f->b; TRY( _create_block_group(f) ); char name2[H5_DATANAME_LEN]; h5_normalize_dataset_name (name, name2); h5_err_t exists; TRY (exists = hdf5_link_exists ( b->block_gid, name2)); if (exists > 0) { TRY (h5bpriv_open_field_group (f, name2)); } else { TRY (hdf5_close_group (f->b->field_gid) ); TRY (b->field_gid = hdf5_create_group (b->block_gid, name2)); } H5_CORE_API_RETURN (H5_SUCCESS); } h5_int64_t h5b_3d_has_view ( h5_file_t *const f /*!< IN: File handle */ ) { return f->b->have_layout; } h5_err_t h5b_3d_set_view ( h5_file_t *const f, /*!< IN: File handle */ const h5_size_t i_start, /*!< IN: start index of \c i */ const h5_size_t i_end, /*!< IN: end index of \c i */ const h5_size_t j_start, /*!< IN: start index of \c j */ const h5_size_t j_end, /*!< IN: end index of \c j */ const h5_size_t k_start, /*!< IN: start index of \c k */ const h5_size_t k_end /*!< IN: end index of \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, " "i_start=%llu, i_end=%llu, " "j_start=%llu, j_end=%llu, " "k_start=%llu, k_end=%llu", f, (long long unsigned)i_start, (long long unsigned)i_end, (long long unsigned)j_start, (long long unsigned)j_end, (long long unsigned)k_start, (long long unsigned)k_end); h5b_partition_t *p = f->b->user_layout; p->i_start = i_start; p->i_end = i_end; p->j_start = j_start; p->j_end = j_end; p->k_start = k_start; p->k_end = k_end; _normalize_partition(p); #ifdef PARALLEL_IO h5b_fdata_t *b = f->b; h5b_partition_t *user_layout; h5b_partition_t *write_layout; size_t size = f->nprocs * sizeof (h5b_partition_t); TRY( user_layout = h5_calloc (1, size) ); TRY( write_layout = h5_calloc (1, size) ); TRY( h5priv_mpi_allgather( p, 1, f->b->partition_mpi_t, user_layout, 1, f->b->partition_mpi_t, f->comm) ); _get_max_dimensions(f, user_layout); TRY( _dissolve_ghostzones(f, user_layout, write_layout) ); b->user_layout[0] = user_layout[f->myproc]; b->write_layout[0] = write_layout[f->myproc]; b->have_layout = 1; p = b->user_layout; h5_debug ( "[%d] User layout: %lld:%lld, %lld:%lld, %lld:%lld", f->myproc, (long long)p->i_start, (long long)p->i_end, (long long)p->j_start, (long long)p->j_end, (long long)p->k_start, (long long)p->k_end ); p = b->write_layout; h5_debug ( "[%d] Ghost-zone layout: %lld:%lld, %lld:%lld, %lld:%lld", f->myproc, (long long)p->i_start, (long long)p->i_end, (long long)p->j_start, (long long)p->j_end, (long long)p->k_start, (long long)p->k_end ); h5_free(user_layout); h5_free(write_layout); TRY( h5bpriv_release_hyperslab(f) ); #endif H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_get_view ( h5_file_t *const f, /*!< IN: File handle */ h5_size_t *const i_start, /*!< OUT: start index of \c i */ h5_size_t *const i_end, /*!< OUT: end index of \c i */ h5_size_t *const j_start, /*!< OUT: start index of \c j */ h5_size_t *const j_end, /*!< OUT: end index of \c j */ h5_size_t *const k_start, /*!< OUT: start index of \c k */ h5_size_t *const k_end /*!< OUT: end index of \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, " "i_start=%p, i_end=%p, " "j_start=%p, j_end=%p, " "k_start=%p, k_end=%p", f, i_start, i_end, j_start, j_end, k_start, k_end); h5b_partition_t *p = f->b->user_layout; *i_start = p->i_start; *i_end = p->i_end; *j_start = p->j_start; *j_end = p->j_end; *k_start = p->k_start; *k_end = p->k_end; H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_get_reduced_view ( h5_file_t *const f, /*!< IN: File handle */ h5_size_t *const i_start, /*!< OUT: start index of \c i */ h5_size_t *const i_end, /*!< OUT: end index of \c i */ h5_size_t *const j_start, /*!< OUT: start index of \c j */ h5_size_t *const j_end, /*!< OUT: end index of \c j */ h5_size_t *const k_start, /*!< OUT: start index of \c k */ h5_size_t *const k_end /*!< OUT: end index of \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, " "i_start=%p, i_end=%p, " "j_start=%p, j_end=%p, " "k_start=%p, k_end=%p", f, i_start, i_end, j_start, j_end, k_start, k_end); h5b_partition_t *p = f->b->write_layout; *i_start = p->i_start; *i_end = p->i_end; *j_start = p->j_start; *j_end = p->j_end; *k_start = p->k_start; *k_end = p->k_end; H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_set_chunk ( h5_file_t *const f, /*!< IN: File handle */ const h5_size_t i, /*!< IN: size of \c i */ const h5_size_t j, /*!< IN: size of \c j */ const h5_size_t k /*!< IN: size of \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, i=%llu, j=%llu, k=%llu", f, (long long unsigned)i, (long long unsigned)j, (long long unsigned)k); if ( i == 0 || j == 0 || k == 0 ) { h5_info ("Disabling chunking" ); TRY (hdf5_set_layout_property(f->b->dcreate_prop, H5D_CONTIGUOUS)); } else { h5_info ("Setting chunk to (%lld,%lld,%lld)", (long long)i, (long long)j, (long long)k); hsize_t dims[3] = { k, j, i }; TRY (hdf5_set_chunk_property (f->b->dcreate_prop, 1, dims)); } H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_get_chunk ( h5_file_t *const f, /*!< IN: File handle */ const char *field_name, /*!< IN: name of dataset */ h5_size_t *const i, /*!< OUT: size of \c i */ h5_size_t *const j, /*!< OUT: size of \c j */ h5_size_t *const k /*!< OUT: size of \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, i=%p, j=%p, k=%p", f, i, j, k); CHECK_TIMEGROUP ( f ); h5b_fdata_t *b = f->b; TRY( h5bpriv_open_field_group ( f, field_name ) ); hid_t dataset_id; hid_t plist_id; hsize_t hdims[3]; TRY (dataset_id = hdf5_open_dataset (b->field_gid, H5_BLOCKNAME_X)); TRY (plist_id = hdf5_get_dataset_create_plist (dataset_id)); TRY (hdf5_get_chunk_property (plist_id, 3, hdims)); TRY (hdf5_close_property (plist_id)); TRY (hdf5_close_dataset (dataset_id)); *i = hdims[2]; *j = hdims[1]; *k = hdims[0]; h5_info("Found chunk dimensions (%lld,%lld,%lld)", (long long)hdims[0], (long long)hdims[1], (long long)hdims[2] ); H5_CORE_API_RETURN (H5_SUCCESS); } #ifdef PARALLEL_IO h5_err_t h5b_3d_set_grid ( h5_file_t *const f, /*!< IN: File handle */ const h5_size_t i, /*!< IN: dimension in \c i */ const h5_size_t j, /*!< IN: dimension in \c j */ const h5_size_t k /*!< IN: dimension in \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, i=%llu, j=%llu, k=%llu", f, (long long unsigned)i, (long long unsigned)j, (long long unsigned)k); if (i*j*k != f->nprocs) { H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "Grid dimensions (%lld,%lld,%lld) do not multiply " "out to %d MPI processors!", (long long)i, (long long)j, (long long)k, f->nprocs)); } f->b->k_grid = i; f->b->j_grid = j; f->b->i_grid = k; int dims[3] = { k, j, i }; int period[3] = { 0, 0, 0 }; TRY( h5priv_mpi_cart_create( f->comm, 3, dims, period, 0, &f->b->cart_comm) ); f->b->have_grid = 1; H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_get_grid_coords ( h5_file_t *const f, /*!< IN: File handle */ const int proc, /*!< IN: MPI processor */ h5_int64_t *i, /*!< OUT: index in \c i */ h5_int64_t *j, /*!< OUT: index in \c j */ h5_int64_t *k /*!< OUT: index in \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, proc=%d, i=%p, j=%p, k=%p", f, proc, i, j, k); if ( ! f->b->have_grid ) H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "Grid dimensions have not been set!")); int coords[3]; TRY( h5priv_mpi_cart_coords(f->b->cart_comm, proc, 3, coords) ); *k = coords[0]; *j = coords[1]; *i = coords[2]; H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_3d_set_dims ( h5_file_t *const f, /*!< IN: File handle */ const h5_size_t i, /*!< IN: dimension in \c i */ const h5_size_t j, /*!< IN: dimension in \c j */ const h5_size_t k /*!< IN: dimension in \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, i=%llu, j=%llu, k=%llu", f, (long long unsigned)i, (long long unsigned)j, (long long unsigned)k); if ( ! f->b->have_grid ) H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "Grid dimensions have not been set!")); h5_size_t dims[3] = { k, j, i }; h5_size_t check_dims[3] = { k, j, i }; TRY( h5priv_mpi_bcast( check_dims, 3, MPI_LONG_LONG, 0, f->comm) ); if ( dims[0] != check_dims[0] || dims[1] != check_dims[1] || dims[2] != check_dims[2] ) { H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "[%d] Block dimensions do not agree: " "(%lld,%lld,%lld) != (%lld,%lld,%lld)!", f->myproc, (long long)dims[0], (long long)dims[1], (long long)dims[2], (long long)check_dims[0], (long long)check_dims[1], (long long)check_dims[2])); } h5_int64_t coords[3]; TRY( h5b_3d_get_grid_coords(f, f->myproc, coords+0, coords+1, coords+2) ); h5b_fdata_t *b = f->b; b->user_layout->i_start = coords[2]*dims[2]; b->user_layout->i_end = (coords[2]+1)*dims[2] - 1; b->user_layout->j_start = coords[1]*dims[1]; b->user_layout->j_end = (coords[1]+1)*dims[1] - 1; b->user_layout->k_start = coords[0]*dims[0]; b->user_layout->k_end = (coords[0]+1)*dims[0] - 1; b->write_layout[0] = b->user_layout[0]; b->i_max = b->i_grid * dims[2] - 1; b->j_max = b->j_grid * dims[1] - 1; b->k_max = b->k_grid * dims[0] - 1; b->have_layout = 1; H5_CORE_API_RETURN (H5_SUCCESS); } #endif h5_err_t h5b_3d_set_halo ( h5_file_t *const f, /*!< IN: File handle */ const h5_size_t i, /*!< IN: radius in \c i */ const h5_size_t j, /*!< IN: radius in \c j */ const h5_size_t k /*!< IN: radius in \c k */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, i=%llu, j=%llu, k=%llu", f, (long long unsigned)i, (long long unsigned)j, (long long unsigned)k); if ( ! f->b->have_grid ) { H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "Grid dimensions have not been set!")); } else if ( ! f->b->have_layout ) { H5_CORE_API_LEAVE ( h5_error(H5_ERR_INVAL, "Block dimensions for grid have not been set!")); } h5b_fdata_t *b = f->b; b->user_layout->i_start -= i; b->user_layout->i_end += i; b->user_layout->j_start -= j; b->user_layout->j_end += j; b->user_layout->k_start -= k; b->user_layout->k_end += k; H5_CORE_API_RETURN (H5_SUCCESS); } h5_ssize_t h5b_get_num_fields ( h5_file_t *const f /*!< IN: File handle */ ) { H5_CORE_API_ENTER (h5_ssize_t, "f=%p", f); CHECK_TIMEGROUP( f ); TRY (h5bpriv_open_block_group(f)); H5_CORE_API_RETURN (hdf5_get_num_objs_in_group (f->b->block_gid)); } h5_err_t h5b_get_field_info_by_name ( h5_file_t *const f, /*!< IN: file handle */ const char *name, /*!< OUT: field name */ h5_size_t *field_rank, /*!< OUT: field rank */ h5_size_t *field_dims, /*!< OUT: field dimensions */ h5_size_t *elem_rank, /*!< OUT: element rank */ h5_int64_t *type /*!< OUT: datatype */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, name='%s', " "field_rank=%p, field_dims=%p, elem_rank=%p, type=%p", f, name, field_rank, field_dims, elem_rank, type); CHECK_TIMEGROUP( f ); hsize_t dims[16]; /* give it plenty of space even though we don't expect rank > 3 */ hsize_t _field_rank, _elem_rank; h5_size_t i, j; TRY( h5bpriv_open_field_group(f, name) ); hid_t dataset_id; hid_t dataspace_id; TRY (dataset_id = hdf5_open_dataset (f->b->field_gid, H5_BLOCKNAME_X)); TRY (dataspace_id = hdf5_get_dataset_space (dataset_id) ); TRY (_field_rank = hdf5_get_dims_of_dataspace (dataspace_id, dims, NULL)); if (field_rank) *field_rank = (h5_size_t) _field_rank; if (field_dims) { for ( i = 0, j = _field_rank-1; i < _field_rank; i++, j-- ) field_dims[i] = (h5_size_t)dims[j]; } TRY (_elem_rank = hdf5_get_num_objs_in_group (f->b->field_gid)); if (elem_rank) *elem_rank = (h5_size_t) _elem_rank; hid_t h5type; TRY (h5type = hdf5_get_dataset_type (dataset_id)); if ( type ) TRY( *type = h5_normalize_h5_type(h5type) ); TRY (hdf5_close_dataspace (dataspace_id)); TRY (hdf5_close_dataset (dataset_id)); H5_CORE_API_RETURN (H5_SUCCESS); } h5_err_t h5b_get_field_info ( h5_file_t *const f, /*!< IN: file handle */ const h5_size_t idx, /*!< IN: index of field */ char *name, /*!< OUT: field name */ const h5_size_t len_name, /*!< IN: buffer size */ h5_size_t *field_rank, /*!< OUT: field rank */ h5_size_t *field_dims, /*!< OUT: field dimensions */ h5_size_t *elem_rank, /*!< OUT: element rank */ h5_int64_t *type /*!< OUT: datatype */ ) { H5_CORE_API_ENTER (h5_err_t, "f=%p, idx=%llu, " "name=%p, len_name=%llu, " "field_rank=%p, field_dims=%p, elem_rank=%p, type=%p", f, (long long unsigned)idx, name, (long long unsigned)len_name, field_rank, field_dims, elem_rank, type); CHECK_TIMEGROUP( f ); TRY (h5bpriv_open_block_group(f)); TRY (hdf5_get_objname_by_idx( f->b->block_gid, (hsize_t)idx, name, (size_t)len_name) ); H5_CORE_API_RETURN (h5b_get_field_info_by_name ( f, name, field_rank, field_dims, elem_rank, type)); }