1021 lines
28 KiB
C
1021 lines
28 KiB
C
/*
|
|
Copyright (c) 2006-2015, The Regents of the University of California,
|
|
through Lawrence Berkeley National Laboratory (subject to receipt of any
|
|
required approvals from the U.S. Dept. of Energy) and the Paul Scherrer
|
|
Institut (Switzerland). All rights reserved.
|
|
|
|
License: see file COPYING in top level of source distribution.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "h5_private.h"
|
|
#include "h5_hdf5_private.h"
|
|
|
|
#include "h5_model_private.h"
|
|
#include "h5_mpi_private.h"
|
|
#include "h5_readwrite_private.h"
|
|
#include "h5b_types_private.h"
|
|
#include "h5core/h5_syscall.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. (?)
|
|
*/
|
|
h5_err_t
|
|
h5b_has_field_data (
|
|
const h5_file_t fh
|
|
) {
|
|
h5_file_p f = (h5_file_p)fh;
|
|
H5_CORE_API_ENTER (h5_err_t, "f=%p", f);
|
|
CHECK_FILEHANDLE (f);
|
|
h5_err_t exists;
|
|
h5_err_t result = H5_NOK;
|
|
TRY (exists = hdf5_link_exists (f->step_gid, H5BLOCK_GROUPNAME_BLOCK));
|
|
if (exists)
|
|
result = H5_SUCCESS;
|
|
H5_CORE_API_RETURN (result);
|
|
}
|
|
|
|
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 (
|
|
const h5_file_p 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 (
|
|
h5b_partition_t *const p, /*!< IN/OUT: ptr to first partition */
|
|
h5b_partition_t *const q /*!< IN/OUT: ptr to second partition */
|
|
) {
|
|
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_VIEW,
|
|
"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 (
|
|
const h5_file_p 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 (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 (
|
|
const h5_file_p 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 (
|
|
const h5_file_p 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, H5BLOCK_GROUPNAME_BLOCK);
|
|
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 (
|
|
const h5_file_p 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, H5BLOCK_GROUPNAME_BLOCK));
|
|
|
|
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, H5BLOCK_GROUPNAME_BLOCK) );
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5bpriv_have_field_group (
|
|
const h5_file_p 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];
|
|
h5priv_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 (
|
|
const h5_file_p 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];
|
|
h5priv_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 (
|
|
const h5_file_p 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];
|
|
h5priv_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 (
|
|
const h5_file_t fh /*!< IN: File handle */
|
|
) {
|
|
return ((h5_file_p)fh)->b->have_layout;
|
|
}
|
|
|
|
h5_err_t
|
|
h5b_3d_set_view (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
h5b_fdata_t *b = f->b;
|
|
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);
|
|
b->user_layout[0].i_start = i_start;
|
|
b->user_layout[0].i_end = i_end;
|
|
b->user_layout[0].j_start = j_start;
|
|
b->user_layout[0].j_end = j_end;
|
|
b->user_layout[0].k_start = k_start;
|
|
b->user_layout[0].k_end = k_end;
|
|
_normalize_partition(&b->user_layout[0]);
|
|
|
|
#ifdef PARALLEL_IO
|
|
h5b_partition_t *user_layout;
|
|
h5b_partition_t *write_layout;
|
|
|
|
TRY (user_layout = h5_calloc (f->nprocs, sizeof (*user_layout)));
|
|
TRY (write_layout = h5_calloc (f->nprocs, sizeof (*write_layout)));
|
|
|
|
user_layout[f->myproc] = b->user_layout[0];
|
|
|
|
TRY (h5priv_mpi_allgather(
|
|
MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
|
|
user_layout, 1, f->b->partition_mpi_t, f->props->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];
|
|
|
|
h5_debug (
|
|
"User layout: %lld:%lld, %lld:%lld, %lld:%lld",
|
|
(long long)b->user_layout[0].i_start,
|
|
(long long)b->user_layout[0].i_end,
|
|
(long long)b->user_layout[0].j_start,
|
|
(long long)b->user_layout[0].j_end,
|
|
(long long)b->user_layout[0].k_start,
|
|
(long long)b->user_layout[0].k_end );
|
|
|
|
h5_debug (
|
|
"Ghost-zone layout: %lld:%lld, %lld:%lld, %lld:%lld",
|
|
(long long)b->write_layout[0].i_start,
|
|
(long long)b->write_layout[0].i_end,
|
|
(long long)b->write_layout[0].j_start,
|
|
(long long)b->write_layout[0].j_end,
|
|
(long long)b->write_layout[0].k_start,
|
|
(long long)b->write_layout[0].k_end );
|
|
|
|
h5_free(user_layout);
|
|
h5_free(write_layout);
|
|
#endif
|
|
TRY( h5bpriv_release_hyperslab(f) );
|
|
b->have_layout = 1;
|
|
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5b_3d_get_view (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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->props->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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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->props->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((h5_file_t)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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh /*!< IN: File handle */
|
|
) {
|
|
h5_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 = h5priv_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 (
|
|
const h5_file_t fh, /*!< 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_file_p f = (h5_file_p)fh;
|
|
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 (
|
|
(h5_file_t)f,
|
|
name, field_rank, field_dims, elem_rank, type));
|
|
}
|
|
|