diff --git a/.gitattributes b/.gitattributes index 6a31b53..8bc6965 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,6 +33,13 @@ src/H5BlockReadWrite.h -text src/H5BlockReadWriteF.c -text src/H5BlockReadWriteF90.inc -text src/H5BlockTypes.h -text +src/H5MultiBlock.c -text +src/H5MultiBlock.h -text +src/H5MultiBlockErrors.h -text +src/H5MultiBlockPrivate.h -text +src/H5MultiBlockReadWrite.c -text +src/H5MultiBlockReadWrite.h -text +src/H5MultiBlockTypes.h -text src/H5Part.c -text src/H5Part.h -text src/H5PartErrors.h -text @@ -44,6 +51,7 @@ src/Makefile.am -text src/TestUnderscore.f -text src/TestUnderscoreC.c -text src/generate-h5bl-readwrite.py -text +src/generate-h5multi-readwrite.py -text test/Bench.c -text test/BlockTestSpecs.txt -text test/H5BlockDissolveGhosts.c -text diff --git a/src/H5Block.c b/src/H5Block.c index 9a55182..bc01722 100644 --- a/src/H5Block.c +++ b/src/H5Block.c @@ -182,6 +182,11 @@ _H5Block_close ( if ( herr < 0 ) return HANDLE_H5S_CLOSE_ERR; b->memshape = -1; } + if ( b->create_prop != H5P_DEFAULT ) { + herr = H5Pclose ( b->create_prop ); + if ( herr < 0 ) return HANDLE_H5P_CLOSE_ERR ("create_prop"); + b->create_prop = H5P_DEFAULT; + } free ( f->block ); f->block = NULL; f->close_block = NULL; @@ -674,7 +679,7 @@ _dissolve_ghostzones ( \internal */ -h5part_int64_t +static h5part_int64_t _release_hyperslab ( H5PartFile *f /*!< IN: file handle */ ) { @@ -720,7 +725,7 @@ H5BlockDefine3DFieldLayout( ) { SET_FNAME ( "H5BlockDefine3DFieldLayout" ); - INIT( f ); + BLOCK_INIT( f ); struct H5BlockStruct *b = f->block; struct H5BlockPartition *p = &b->user_layout[f->myproc]; @@ -731,7 +736,7 @@ H5BlockDefine3DFieldLayout( p->k_start = k_start; p->k_end = k_end; - _normalize_partition( p ); + _normalize_partition ( p ); h5part_int64_t herr = _allgather ( f ); if ( herr < 0 ) return HANDLE_MPI_ALLGATHER_ERR; @@ -760,13 +765,13 @@ H5BlockDefine3DFieldLayout( h5part_int64_t H5BlockDefine3DChunkDims( H5PartFile *f, /*!< IN: File handle */ - const h5part_int64_t i, /*!< IN: size of \c i */ - const h5part_int64_t j, /*!< IN: size of \c j */ - const h5part_int64_t k /*!< IN: size of \c k */ + const h5part_int64_t i, /*!< IN: size of \c i */ + const h5part_int64_t j, /*!< IN: size of \c j */ + const h5part_int64_t k /*!< IN: size of \c k */ ) { SET_FNAME ( "H5BlockDefine3DChunkDims" ); - INIT( f ); + BLOCK_INIT( f ); struct H5BlockStruct *b = f->block; @@ -782,6 +787,8 @@ H5BlockDefine3DChunkDims( (long long)b->chunk[0] ); b->create_prop = H5Pcreate (H5P_DATASET_CREATE); + if (b->create_prop < 0) return HANDLE_H5P_CREATE_ERR; + herr_t herr = H5Pset_chunk ( b->create_prop, 3, b->chunk ); if ( herr < 0 ) return HANDLE_H5P_SET_CHUNK_ERR; @@ -804,7 +811,7 @@ H5BlockGet3DChunkDims( ) { SET_FNAME ( "H5BlockGet3DChunkDims" ); - INIT( f ); + BLOCK_INIT( f ); struct H5BlockStruct *b = f->block; @@ -869,7 +876,7 @@ H5Block3dGetPartitionOfProc ( ) { SET_FNAME ( "H5Block3dGetProcOf" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_LAYOUT ( f ); if ( ( proc < 0 ) || ( proc >= f->nprocs ) ) @@ -909,7 +916,7 @@ H5Block3dGetReducedPartitionOfProc ( ) { SET_FNAME ( "H5Block3dGetProcOf" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_LAYOUT ( f ); if ( ( proc < 0 ) || ( proc >= f->nprocs ) ) @@ -945,7 +952,7 @@ H5Block3dGetProcOf ( ) { SET_FNAME ( "H5Block3dGetProcOf" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_LAYOUT ( f ); struct H5BlockPartition *layout = f->block->write_layout; @@ -1060,8 +1067,8 @@ _H5Block_close_field_group ( \return \c H5PART_SUCCESS or error code */ -static h5part_int64_t -_select_hyperslab_for_reading ( +h5part_int64_t +_H5Block_select_hyperslab_for_reading ( H5PartFile *f, /*!< IN: file handle */ hid_t dataset ) { @@ -1155,6 +1162,7 @@ _H5Block_read_data ( hid_t type /*!< IN: data type */ ) { + h5part_int64_t herr; struct H5BlockStruct *b = f->block; #if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 @@ -1164,7 +1172,7 @@ _H5Block_read_data ( #endif if ( dataset_id < 0 ) return HANDLE_H5D_OPEN_ERR ( name ); - h5part_int64_t herr = _select_hyperslab_for_reading ( f, dataset_id ); + herr = _H5Block_select_hyperslab_for_reading ( f, dataset_id ); if ( herr < 0 ) return herr; herr = H5Dread ( @@ -1172,7 +1180,7 @@ _H5Block_read_data ( type, f->block->memshape, f->block->diskshape, - H5P_DEFAULT, + f->xfer_prop, data ); if ( herr < 0 ) return HANDLE_H5D_READ_ERR ( name, f->timestep ); @@ -1400,7 +1408,6 @@ _H5Block_write_data ( herr_t herr; hid_t dataset; - hid_t create_prop = H5P_DEFAULT; struct H5BlockStruct *b = f->block; #if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 @@ -1420,7 +1427,6 @@ _H5Block_write_data ( b->shape, b->create_prop ); #endif - if ( dataset < 0 ) return HANDLE_H5D_CREATE_ERR ( name, f->timestep ); herr = H5Dwrite ( @@ -1435,11 +1441,6 @@ _H5Block_write_data ( herr = H5Dclose ( dataset ); if ( herr < 0 ) return HANDLE_H5D_CLOSE_ERR; - if ( create_prop != H5P_DEFAULT ) { - herr = H5Pclose ( create_prop ); - if ( herr < 0 ) return HANDLE_H5P_CLOSE_ERR ( "create_prop" ); - } - return H5PART_SUCCESS; } @@ -1458,7 +1459,7 @@ H5BlockGetNumFields ( ) { SET_FNAME ( "H5BlockGetNumFields" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); if ( ! _H5Part_have_group ( f->timegroup, H5BLOCK_GROUPNAME_BLOCK ) ) @@ -1558,7 +1559,7 @@ H5BlockGetFieldInfo ( ) { SET_FNAME ( "H5BlockGetFieldInfo" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); h5part_int64_t herr = _H5Part_get_object_name ( @@ -1591,7 +1592,7 @@ H5BlockGetFieldInfoByName ( ) { SET_FNAME ( "H5BlockGetFieldInfo" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); return _get_field_info ( @@ -1620,7 +1621,7 @@ _write_field_attrib ( h5part_int64_t herr = _H5Block_open_field_group ( f, field_name ); if ( herr < 0 ) return herr; - _H5Part_write_attrib ( + herr = _H5Part_write_attrib ( f->block->field_group_id, attrib_name, attrib_type, @@ -1653,7 +1654,7 @@ H5BlockWriteFieldAttrib ( ) { SET_FNAME ( "H5BlockWriteFieldAttrib" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE( f ); CHECK_TIMEGROUP( f ); @@ -1681,7 +1682,7 @@ H5BlockWriteFieldAttribString ( ) { SET_FNAME ( "H5BlockWriteFieldAttribString" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE( f ); CHECK_TIMEGROUP( f ); @@ -1706,7 +1707,7 @@ H5BlockGetNumFieldAttribs ( ) { SET_FNAME ( "H5BlockGetNumFieldAttribs" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); h5part_int64_t herr = _H5Block_open_field_group ( f, field_name ); @@ -1744,7 +1745,7 @@ H5BlockGetFieldAttribInfo ( ) { SET_FNAME ( "H5BlockGetFieldAttribInfo" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); h5part_int64_t herr = _H5Block_open_field_group ( f, field_name ); @@ -1815,7 +1816,7 @@ H5BlockReadFieldAttrib ( ) { SET_FNAME ( "H5PartReadFieldAttrib" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); return _read_field_attrib ( @@ -1840,7 +1841,7 @@ H5Block3dGetFieldOrigin ( ) { SET_FNAME ( "H5BlockSetFieldOrigin" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); h5part_float64_t origin[3]; @@ -1874,7 +1875,7 @@ H5Block3dSetFieldOrigin ( ) { SET_FNAME ( "H5BlockSetFieldOrigin" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE( f ); CHECK_TIMEGROUP( f ); @@ -1906,7 +1907,7 @@ H5Block3dGetFieldSpacing ( ) { SET_FNAME ( "H5BlockGetFieldSpacing" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); h5part_float64_t spacing[3]; @@ -1940,7 +1941,7 @@ H5Block3dSetFieldSpacing ( ) { SET_FNAME ( "H5BlockSetFieldSpacing" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE( f ); CHECK_TIMEGROUP( f ); @@ -1970,7 +1971,7 @@ H5BlockHasFieldData ( ) { SET_FNAME ( "H5BlockHasFieldData" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP( f ); if ( ! _H5Part_have_group ( f->timegroup, H5BLOCK_GROUPNAME_BLOCK ) ) { diff --git a/src/H5BlockErrors.h b/src/H5BlockErrors.h index c1553d4..43e39de 100644 --- a/src/H5BlockErrors.h +++ b/src/H5BlockErrors.h @@ -34,6 +34,7 @@ _H5Part_get_funcname(), \ H5PART_ERR_INVAL, \ "Group \"%s\" already exists", name ) + #define HANDLE_H5S_CREATE_SIMPLE_3D_ERR( dims ) \ (*_err_handler) ( \ _H5Part_get_funcname(), \ diff --git a/src/H5BlockF.c b/src/H5BlockF.c index 375ca91..5c5b85c 100755 --- a/src/H5BlockF.c +++ b/src/H5BlockF.c @@ -99,14 +99,14 @@ h5bl_define3dlayout ( h5part_int64_t h5bl_define3dchunkdims ( h5part_int64_t *f, - const h5part_int64_t i, - const h5part_int64_t j, - const h5part_int64_t k + const h5part_int64_t *i, + const h5part_int64_t *j, + const h5part_int64_t *k ) { H5PartFile *filehandle = (H5PartFile*)(size_t)*f; - return H5BlockDefine3DChunkDims ( filehandle, i, j, k ); + return H5BlockDefine3DChunkDims ( filehandle, *i, *j, *k ); } h5part_int64_t diff --git a/src/H5BlockPrivate.h b/src/H5BlockPrivate.h index 4dc1570..bf370cd 100644 --- a/src/H5BlockPrivate.h +++ b/src/H5BlockPrivate.h @@ -3,7 +3,7 @@ #define H5BLOCK_GROUPNAME_BLOCK "Block" -#define INIT( f ) { \ +#define BLOCK_INIT( f ) { \ h5part_int64_t herr = _H5Block_init ( f ); \ if ( herr < 0 ) return herr; \ } @@ -34,6 +34,12 @@ _H5Block_create_field_group ( H5PartFile *f, const char *name ); + +h5part_int64_t +_H5Block_select_hyperslab_for_reading ( + H5PartFile *f, + hid_t dataset + ); h5part_int64_t _H5Block_write_data ( diff --git a/src/H5BlockReadWrite.c b/src/H5BlockReadWrite.c index c4a1b39..b78bd92 100644 --- a/src/H5BlockReadWrite.c +++ b/src/H5BlockReadWrite.c @@ -31,7 +31,7 @@ H5Block3dWriteScalarFieldFloat64 ( ) { SET_FNAME ( "H5Block3dWriteScalarFieldFloat64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -67,7 +67,7 @@ H5Block3dReadScalarFieldFloat64 ( ) { SET_FNAME ( "H5Block3dReadScalarFieldFloat64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -106,7 +106,7 @@ H5Block3dWrite3dVectorFieldFloat64 ( ) { SET_FNAME ( "H5Block3dWrite3dVectorFieldFloat64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -150,7 +150,7 @@ H5Block3dRead3dVectorFieldFloat64 ( ) { SET_FNAME ( "H5Block3dRead3dVectorFieldFloat64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -189,7 +189,7 @@ H5Block3dWriteScalarFieldFloat32 ( ) { SET_FNAME ( "H5Block3dWriteScalarFieldFloat32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -225,7 +225,7 @@ H5Block3dReadScalarFieldFloat32 ( ) { SET_FNAME ( "H5Block3dReadScalarFieldFloat32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -264,7 +264,7 @@ H5Block3dWrite3dVectorFieldFloat32 ( ) { SET_FNAME ( "H5Block3dWrite3dVectorFieldFloat32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -308,7 +308,7 @@ H5Block3dRead3dVectorFieldFloat32 ( ) { SET_FNAME ( "H5Block3dRead3dVectorFieldFloat32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -347,7 +347,7 @@ H5Block3dWriteScalarFieldInt64 ( ) { SET_FNAME ( "H5Block3dWriteScalarFieldInt64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -383,7 +383,7 @@ H5Block3dReadScalarFieldInt64 ( ) { SET_FNAME ( "H5Block3dReadScalarFieldInt64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -422,7 +422,7 @@ H5Block3dWrite3dVectorFieldInt64 ( ) { SET_FNAME ( "H5Block3dWrite3dVectorFieldInt64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -466,7 +466,7 @@ H5Block3dRead3dVectorFieldInt64 ( ) { SET_FNAME ( "H5Block3dRead3dVectorFieldInt64" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -505,7 +505,7 @@ H5Block3dWriteScalarFieldInt32 ( ) { SET_FNAME ( "H5Block3dWriteScalarFieldInt32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -541,7 +541,7 @@ H5Block3dReadScalarFieldInt32 ( ) { SET_FNAME ( "H5Block3dReadScalarFieldInt32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -580,7 +580,7 @@ H5Block3dWrite3dVectorFieldInt32 ( ) { SET_FNAME ( "H5Block3dWrite3dVectorFieldInt32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -624,7 +624,7 @@ H5Block3dRead3dVectorFieldInt32 ( ) { SET_FNAME ( "H5Block3dRead3dVectorFieldInt32" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); diff --git a/src/H5MultiBlock.c b/src/H5MultiBlock.c new file mode 100644 index 0000000..e165dca --- /dev/null +++ b/src/H5MultiBlock.c @@ -0,0 +1,779 @@ +/*! + \defgroup h5multiblock_c_api H5MultiBlock C API + + This package includes C code for writing and reading 3D datasets intended + for distributed memory applications. The underlying file format is H5Part, + a simple data storage schema and API derived from HDF5. In particular, we + use the H5Block subset of H5Part for managing 3D field data. To achieve large + contiguous reads and writes, the datasets use HDF5's chunking mechanism to + reorder the layout on disk such that local subfields (or "blocks") of the + 3D field are stored contiguously (as opposed to storing an entire column + contiguously, as in the Fortran column-major layout for an array). We refer + to this chunked layout as "multiblock" and the column-major layout as + "uniblock." Multiblocked datasets exhibit the following constraints: + + * All blocks must be the same size (a requirement of the HDF5 chunking + mechanism). + * The block dimensions must divide the field dimensions, to prevent fringe + data that will lower performance by interfering with contiguous I/O + operations. + * For load-balancing purposes, the total number of blocks that the field + is decomposed into must be a multiple of the number of nodes in the + distributed system. (For ease of implementation, we require that the + number of blocks equal the number of nodes.) + +*/ + +/*! + \internal + + \defgroup h5multiblock_static H5MultiBlock Static +*/ + +/*! + \internal + + \defgroup h5multiblock_private H5MultiBlock Private +*/ + +#include +#include +#include + +#include +#include "H5Part.h" +#include "H5PartErrors.h" +#include "H5PartPrivate.h" + +#include "H5Block.h" +#include "H5BlockTypes.h" +#include "H5BlockErrors.h" +#include "H5BlockPrivate.h" + +#include "H5MultiBlock.h" +#include "H5MultiBlockTypes.h" +#include "H5MultiBlockErrors.h" +#include "H5MultiBlockPrivate.h" + +#ifdef PARALLEL_IO + + +/******************************************************************************* +* Static functions +*******************************************************************************/ + +/*! + \ingroup h5multiblock_static + + \internal + + Check whether \c f points to a valid file handle. + + \return H5PART_SUCCESS or error code +*/ +static h5part_int64_t +_file_is_valid ( + const H5PartFile *f /*!< IN: file handle */ + ) { + + if ( f == NULL ) + return H5PART_ERR_BADFD; + if ( f->file == 0 ) + return H5PART_ERR_BADFD; + if ( f->block == NULL ) + return H5PART_ERR_BADFD; + if ( f->multiblock == NULL ) + return H5PART_ERR_BADFD; + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_static + + \internal + + Gets the block decomposition and offsets. + + \return H5PART_SUCCESS or error code +*/ +static h5part_int64_t +_get_decomp_and_offsets ( + const H5PartFile *f /*!< IN: file handle */ + ) { + + h5part_int64_t i, j, k; + h5part_int64_t nblocks; + + struct H5MultiBlockStruct *mb = f->multiblock; + + mb->decomp[0] = mb->field_dims[0] / mb->block_dims[0]; + mb->decomp[1] = mb->field_dims[1] / mb->block_dims[1]; + mb->decomp[2] = mb->field_dims[2] / mb->block_dims[2]; + + _H5Part_print_debug ("PROC[%d]: Block decomposition: (%ld,%ld,%ld)", + f->myproc, + mb->decomp[0], + mb->decomp[1], + mb->decomp[2] ); + + i = f->myproc % mb->decomp[0]; + j = (f->myproc / mb->decomp[0]) % mb->decomp[1]; + k = f->myproc / (mb->decomp[0] * mb->decomp[1]); + + /* keep track of blocks that border the edges of the field */ + if (i == 0) mb->field_edges | H5MB_EDGE_X0; + if (i == mb->decomp[0] - 1) mb->field_edges | H5MB_EDGE_X1; + if (j == 0) mb->field_edges | H5MB_EDGE_Y0; + if (j == mb->decomp[1] - 1) mb->field_edges | H5MB_EDGE_Y1; + if (j == 0) mb->field_edges | H5MB_EDGE_Z0; + if (j == mb->decomp[2] - 1) mb->field_edges | H5MB_EDGE_Z1; + + mb->offsets[0] = i * mb->block_dims[0]; + mb->offsets[1] = j * mb->block_dims[1]; + mb->offsets[2] = k * mb->block_dims[2]; + + _H5Part_print_debug ("PROC[%d]: Block offsets: (%ld,%ld,%ld)", + f->myproc, + mb->offsets[0], + mb->offsets[1], + mb->offsets[0] ); + + nblocks = mb->decomp[0] * mb->decomp[1] * mb->decomp[2]; + + if (f->myproc == 0) { + _H5Part_print_info ("Number of blocks: %ld", nblocks); + } + + if (nblocks != f->nprocs) { + return HANDLE_H5PART_BLOCK_DECOMP_ERR; + } + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_static + + \internal + + Calculates an integer \c divisor of \c m that is >= the \c n root of \c m. + + Used for finding block decompositions for an arbitrary number of processors. + + \return \c divisor +*/ +static int +_nth_root_int_divisor (const int m, const int n) +{ + int i, root; + double p; + + p = 1.0 / (double) n; + root = (int) ceil ( pow ((double) m, p) ); + for (i=root; i<=m; i++) + { + if (m % i == 0) return i; + } + + return i; +} + +/*! + \ingroup h5multiblock_static + + \internal + + Allocates a block using the dimensions read from the file and the halo + radii specified by the user. + + \return H5PART_SUCCESS or error code +*/ +static h5part_int64_t +_alloc_block ( + const H5PartFile *f, /*!< IN: file handle */ + char **data, /*!< IN/OUT: buffer to alloc */ + hid_t type /*!< IN: HDF5 datatype of buffer */ + ) { + + char *buffer; + size_t datasize; + size_t nelems; + + struct H5MultiBlockStruct *mb = f->multiblock; + + /* size of datatype */ + datasize = H5Tget_size ( type ); + + /* number of elements */ + nelems = mb->block_dims[0] + 2*mb->halo_radii[0]; + nelems *= mb->block_dims[1] + 2*mb->halo_radii[1]; + nelems *= mb->block_dims[2] + 2*mb->halo_radii[2]; + + buffer = (char*) malloc ( nelems * datasize ); + if ( ! buffer ) return HANDLE_H5PART_NOMEM_ERR; + + *data = buffer; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_static + + \internal + + Takes a contiguous buffer of data and rearranges it in place to add padding + with \c radius layers. Assumes that \c buffer is already large enough to + perform this operation. + + \return H5PART_SUCCESS or error code +*/ +static h5part_int64_t +_pad_block ( + const H5PartFile *f, /*!< IN: file handle */ + char *data, /*!< IN/OUT: buffer to pad */ + hid_t type /*!< IN: HDF5 datatype of buffer */ + ) { + + size_t datasize; + h5part_int64_t j, k; + h5part_int64_t iDst, iSrc; + h5part_int64_t xSize, xySize; + h5part_int64_t hxSize, hxySize; + h5part_int64_t hxInset; + + struct H5MultiBlockStruct *mb = f->multiblock; + + /* size of datatype */ + datasize = H5Tget_size ( type ); + + /* size of row in original block */ + xSize = mb->block_dims[0] * datasize; + + /* size of slab in original block */ + xySize = xSize * mb->block_dims[1]; + + /* size of row/slab with halo regions */ + hxSize = (mb->block_dims[0] + 2*mb->halo_radii[0]) * datasize; + hxySize = hxSize * (mb->block_dims[1] + 2*mb->halo_radii[1]); + + /* inset of row in halo region */ + hxInset = mb->halo_radii[0] * datasize; + + for (k=(mb->block_dims[2]-1);k>=0;k--) + { + for (j=(mb->block_dims[1]-1);j>=0;j--) + { + iSrc = k*xySize + j*xSize; + + iDst = (k + mb->halo_radii[2]) * hxySize + + (j + mb->halo_radii[1]) * hxSize + + hxInset; + + memcpy ( data + iDst, data + iSrc, xSize ); + } + } + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_static + + \internal + + Exchanges halo regions among neighboring blocks using MPI. + + \return H5PART_SUCCESS or error code +*/ +static h5part_int64_t +_halo_exchange ( + const H5PartFile *f, /*!< IN: file handle */ + char *data, /*!< IN/OUT: local buffer */ + hid_t type /*!< IN: HDF5 datatype of buffer */ + ) { + + return H5PART_SUCCESS; +} + +/******************************************************************************* +* Private functions +*******************************************************************************/ + +/*! + \ingroup h5multiblock_private + + \internal + + Initialize H5MultiBlock internal structure. + + \return H5PART_SUCCESS or error code +*/ +h5part_int64_t +_H5MultiBlock_init ( + H5PartFile *f /*!< IN: file handle */ + ) { + + struct H5MultiBlockStruct *mb; + + BLOCK_INIT( f ); + + if (f->multiblock != NULL) return H5PART_SUCCESS; + + f->multiblock = + (struct H5MultiBlockStruct*) malloc( sizeof (*f->multiblock) ); + if ( f->multiblock == NULL ) { + return HANDLE_H5PART_NOMEM_ERR; + } + mb = f->multiblock; + + mb->field_edges = 0; + mb->halo = 0; + mb->read = 0; + mb->have_decomp = 0; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_private + + \internal + + Free H5MultiBlock internal struct; + + \return H5PART_SUCCESS or error code +*/ +h5part_int64_t +_H5MultiBlock_close ( + H5PartFile *f /*!< IN: file handle */ + ) { + + free ( f->multiblock ); + f->multiblock = NULL; + f->close_multiblock = NULL; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_private + + \internal + + Read a multiblock field \c name into the buffer starting at \c data + using the current time-step and the block decomposition and dimensions + defined in the file. + + \return H5PART_SUCCESS or error code +*/ +h5part_int64_t +_H5MultiBlock_read_data ( + H5PartFile *f, /*!< IN: file handle */ + const char *field_name, /*!< IN: Name of field */ + char **data, /*!< OUT: ptr to read buffer ptr*/ + hid_t type /*!< IN: HDF5 datatype of buffer */ + ) { + + MULTIBLOCK_INIT( f ); + + hid_t dataset_id; + hid_t dataspace_id; + int rank; + h5part_int64_t herr; + + struct H5BlockStruct *b = f->block; + struct H5MultiBlockStruct *mb = f->multiblock; + + char * const fname = _H5Part_get_funcname(); + + herr = _H5Block_open_field_group ( f, field_name ); + if ( herr < 0 ) return herr; + +#if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 + dataset_id = H5Dopen2 ( b->field_group_id, "0", H5P_DEFAULT ); +#else + dataset_id = H5Dopen ( b->field_group_id, "0" ); +#endif + if ( dataset_id < 0 ) return HANDLE_H5D_OPEN_ERR ( "0" ); + + /* read block dimensions from field attribute */ + herr = _H5Part_read_attrib ( + b->field_group_id, + H5MULTIBLOCK_ATTR_NAME, + mb->block_dims ); + if ( herr < 0 ) return herr; + + _H5Part_print_debug ("PROC[%d]: Block dimensions: (%ld,%ld,%ld)", + f->myproc, + mb->block_dims[0], + mb->block_dims[1], + mb->block_dims[2] ); + + dataspace_id = H5Dget_space ( dataset_id ); + if ( dataspace_id < 0 ) return HANDLE_H5D_GET_SPACE_ERR; + + rank = H5Sget_simple_extent_dims ( + dataspace_id, + (hsize_t*)mb->field_dims, + NULL ); + if ( rank < 0 ) return HANDLE_H5S_GET_SIMPLE_EXTENT_DIMS_ERR; + if ( rank != 3 ) return HANDLE_H5PART_DATASET_RANK_ERR ( rank, 3 ); + + herr = _alloc_block ( f, data, type ); + if ( herr < 0 ) return herr; + + herr = _get_decomp_and_offsets ( f ); + if ( herr < 0 ) return herr; + + mb->have_decomp = 1; + + herr = H5BlockDefine3DFieldLayout ( f, + mb->offsets[0], mb->offsets[0] + mb->block_dims[0] - 1, + mb->offsets[1], mb->offsets[1] + mb->block_dims[1] - 1, + mb->offsets[2], mb->offsets[2] + mb->block_dims[2] - 1); + if ( herr < 0 ) return herr; + + _H5Part_set_funcname ( fname ); + + herr = _H5Block_select_hyperslab_for_reading ( f, dataset_id ); + if ( herr < 0 ) return herr; + + herr = H5Dread ( + dataset_id, + type, + f->block->memshape, + f->block->diskshape, + f->xfer_prop, + *data ); + if ( herr < 0 ) return HANDLE_H5D_READ_ERR ( field_name, f->timestep ); + + herr = H5Dclose ( dataset_id ); + if ( herr < 0 ) return HANDLE_H5D_CLOSE_ERR; + + herr = _H5Block_close_field_group ( f ); + if ( herr < 0 ) return herr; + + if ( mb->halo ) { + _pad_block ( f, *data, type ); + _halo_exchange ( f, *data, type ); + } + + mb->read = 1; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_private + + \internal + + Write a multiblock field \c name from the buffer starting at \c data + to the current time-step using the defined block decomposition and dimensions. + + \return H5PART_SUCCESS or error code +*/ +h5part_int64_t +_H5MultiBlock_write_data ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const void* data, /*!< IN: data buffer */ + hid_t type /*!< IN: HDF5 datatype */ + ) { + + MULTIBLOCK_INIT( f ); + CHECK_WRITABLE_MODE( f ); + CHECK_TIMEGROUP( f ); + CHECK_DECOMP ( f ); + + hid_t dataset; + h5part_int64_t herr; + + struct H5BlockStruct *b = f->block; + struct H5MultiBlockStruct *mb = f->multiblock; + + char * const fname = _H5Part_get_funcname(); + + herr = H5BlockDefine3DFieldLayout ( f, + mb->offsets[0], mb->offsets[0] + mb->block_dims[0] - 1, + mb->offsets[1], mb->offsets[1] + mb->block_dims[1] - 1, + mb->offsets[2], mb->offsets[2] + mb->block_dims[2] - 1); + if ( herr < 0 ) return herr; + + herr = H5BlockDefine3DChunkDims( f, + mb->block_dims[0], + mb->block_dims[1], + mb->block_dims[2]); + if ( herr < 0 ) return herr; + + _H5Part_set_funcname ( fname ); + + herr = _H5Block_create_field_group ( f, name ); + if ( herr < 0 ) return herr; + +#if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 + dataset = H5Dcreate2 ( + b->field_group_id, + "0", + type, + b->shape, + H5P_DEFAULT, + b->create_prop, + H5P_DEFAULT ); +#else + dataset = H5Dcreate ( + b->field_group_id, + "0", + type, + b->shape, + b->create_prop ); +#endif + if ( dataset < 0 ) return HANDLE_H5D_CREATE_ERR ( name, f->timestep ); + + herr = H5Dwrite ( + dataset, + type, + b->memshape, + b->diskshape, + f->xfer_prop, + data ); + if ( herr < 0 ) return HANDLE_H5D_WRITE_ERR ( name, f->timestep ); + + herr = H5Dclose ( dataset ); + if ( herr < 0 ) return HANDLE_H5D_CLOSE_ERR; + + /* write out the block dimensions to a special field attribute */ + herr = _H5Part_write_attrib ( + f->block->field_group_id, + H5MULTIBLOCK_ATTR_NAME, + H5T_NATIVE_INT64, + mb->block_dims, + 3 ); + if ( herr < 0 ) return herr; + + herr = _H5Block_close_field_group ( f ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + + +/******************************************************************************* +* Public API +*******************************************************************************/ + +/*! + \ingroup h5multiblock_c_api + + Define the radius for halo exchanges between the blocks. Blocks on the edges + of the field will be padded with zero values out to the radius. + + \return \c H5PART_SUCCESS on success +*/ +h5part_int64_t +H5MultiBlock3dDefineRadius ( + H5PartFile *f, /* IN: file handle */ + const h5part_int64_t r /* IN: radius for i, j and k directions*/ + ) { + + SET_FNAME ( "H5MultiBlock3dDefineRadius" ); + MULTIBLOCK_INIT( f ); + + struct H5MultiBlockStruct *mb = f->multiblock; + + mb->halo_radii[0] = + mb->halo_radii[1] = + mb->halo_radii[2] = r; + + mb->halo = 1; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Define the radii for halo exchanges between the blocks. Blocks on the edges + of the field will be padded with zero values out to the radius. + + Different radii can be set for each direction. + + \return \c H5PART_SUCCESS on success +*/ +h5part_int64_t +H5MultiBlock3dDefineRadii ( + H5PartFile *f, /* IN: file handle */ + const h5part_int64_t ri, /* IN: radius for i direction */ + const h5part_int64_t rj, /* IN: radius for j direction */ + const h5part_int64_t rk /* IN: radius for k direction */ + ) { + + SET_FNAME ( "H5MultiBlock3dDefineRadii" ); + MULTIBLOCK_INIT( f ); + + struct H5MultiBlockStruct *mb = f->multiblock; + + mb->halo_radii[0] = rk; + mb->halo_radii[1] = rj; + mb->halo_radii[2] = ri; + + mb->halo = 1; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Define the field and block dimensions for writing. + + \return \c H5PART_SUCCESS on success + \c H5PART_ERR_INVAL if block dims do not divide field dims +*/ +h5part_int64_t +H5MultiBlock3dDefineDims ( + H5PartFile *f, /* IN: file handle */ + const h5part_int64_t *field_dims, /* IN: field dimensions */ + const h5part_int64_t *block_dims /* IN: block dimensions */ + ) { + + SET_FNAME ( "H5MultiBlock3dDefineDims" ); + MULTIBLOCK_INIT ( f ); + + struct H5MultiBlockStruct *mb = f->multiblock; + + mb->field_dims[0] = field_dims[0]; + mb->field_dims[1] = field_dims[1]; + mb->field_dims[2] = field_dims[2]; + + mb->block_dims[0] = block_dims[0]; + mb->block_dims[1] = block_dims[1]; + mb->block_dims[2] = block_dims[2]; + + h5part_int64_t herr = _get_decomp_and_offsets ( f ); + if ( herr < 0 ) return H5PART_ERR_INVAL; + + mb->have_decomp = 1; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Returns the field dimensions of the last field that was read. + + \return \c H5PART_SUCCESS on success
+ \c H5PART_ERR_INVAL if no field has been read yet + +*/ +h5part_int64_t +H5MultiBlock3dGetFieldDims( + H5PartFile *f, + h5part_int64_t *dims + ) { + + SET_FNAME ( "H5MultiBlock3dGetFieldDims" ); + MULTIBLOCK_INIT ( f ); + + struct H5MultiBlockStruct *mb = f->multiblock; + + if ( ! mb->read ) return H5PART_ERR_INVAL; + + dims[0] = mb->field_dims[0]; + dims[1] = mb->field_dims[1]; + dims[2] = mb->field_dims[2]; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Returns the block dimensions of the last field that was read. + + \return \c H5PART_SUCCESS on success
+ \c H5PART_ERR_INVAL if no field has been read yet + +*/ +h5part_int64_t +H5MultiBlock3dGetBlockDims( + H5PartFile *f, /* IN: file handle */ + const char *field_name, /* IN: field name */ + h5part_int64_t *dims /* OUT: block dimensions */ + ) { + + SET_FNAME ( "H5MultiBlock3dGetBlockDims" ); + MULTIBLOCK_INIT ( f ); + + struct H5MultiBlockStruct *mb = f->multiblock; + + if ( ! mb->read ) return H5PART_ERR_INVAL; + + dims[0] = mb->block_dims[0]; + dims[1] = mb->block_dims[1]; + dims[2] = mb->block_dims[2]; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Return the offsets for the block belonging to processor \c proc. + + \return \c H5PART_SUCCESS on success
+ \c H5PART_ERR_INVAL if proc is invalid +*/ +h5part_int64_t +H5MultiBlock3dGetOffsetsOfProc ( + H5PartFile *f, /* IN: file handle */ + const h5part_int64_t proc, /* IN: processor number */ + h5part_int64_t *offsets /* OUT: 3d array of offsets */ + ) { + + SET_FNAME ( "H5MultiBlock3dGetOffsetsOfProc" ); + MULTIBLOCK_INIT ( f ); + + if ( ( proc < 0 ) || ( proc >= f->nprocs ) ) + return H5PART_ERR_INVAL; + + struct H5MultiBlockStruct *mb = f->multiblock; + + offsets[0] = mb->offsets[0]; + offsets[1] = mb->offsets[1]; + offsets[2] = mb->offsets[2]; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Finds a 3D block decomposition for an arbitrary number of processors + \c nprocs. + + \return \c H5PART_SUCCESS on success
+ \c H5PART_ERR_INVAL if the decomp doesn't have \c nprocs blocks +*/ + +h5part_int64_t +H5MultiBlock3dCalculateDecomp ( + const int nprocs, /*!< IN: number of processors/blocks */ + h5part_int64_t *decomp /*!< OUT: 3D block decomposition */ + ) { + + decomp[0] = _nth_root_int_divisor (nprocs, 3); + decomp[1] = _nth_root_int_divisor (nprocs / decomp[0], 2); + decomp[2] = nprocs / decomp[0] / decomp[1]; + + if (decomp[0] * decomp[1] * decomp[2] != nprocs) { + return H5PART_ERR_INVAL; + } + + return H5PART_SUCCESS; +} + +#endif + diff --git a/src/H5MultiBlock.h b/src/H5MultiBlock.h new file mode 100644 index 0000000..faed341 --- /dev/null +++ b/src/H5MultiBlock.h @@ -0,0 +1,67 @@ +#ifndef __H5MULTIBLOCK_H +#define __H5MULTIBLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + Include read/write call variants for different data types and + field dimensions. +*/ +#include "H5MultiBlockReadWrite.h" + +#define H5MULTIBLOCK_ATTR_NAME "__BlockDims__" + +h5part_int64_t +H5MultiBlock3dDefineRadius ( + H5PartFile *f, + const h5part_int64_t r + ); + +h5part_int64_t +H5MultiBlock3dDefineRadii ( + H5PartFile *f, + const h5part_int64_t ri, + const h5part_int64_t rj, + const h5part_int64_t rk + ); + +h5part_int64_t +H5MultiBlock3dDefineDims ( + H5PartFile *f, + const h5part_int64_t *field_dims, + const h5part_int64_t *block_dims + ); + +h5part_int64_t +H5MultiBlock3dGetFieldDims( + H5PartFile *f, + h5part_int64_t *dims + ); + +h5part_int64_t +H5MultiBlock3dGetBlockDims( + H5PartFile *f, + const char *field_name, + h5part_int64_t *dims + ); + +h5part_int64_t +H5MultiBlock3dGetOffsetsOfProc ( + H5PartFile *f, + const h5part_int64_t proc, + h5part_int64_t *offsets + ); + +h5part_int64_t +H5MultiBlock3dCalculateDecomp ( + const int nprocs, + h5part_int64_t *decomp + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/H5MultiBlockErrors.h b/src/H5MultiBlockErrors.h new file mode 100644 index 0000000..a0f7a5b --- /dev/null +++ b/src/H5MultiBlockErrors.h @@ -0,0 +1,19 @@ +#ifndef __H5MULTIBLOCKERRORS_H +#define __H5MULTIBLOCKERRORS_H + +#define _err_handler H5PartGetErrorHandler() + +#define CHECK_DECOMP( f ) \ + if ( ! f->multiblock->have_decomp ) \ + return (*_err_handler) ( \ + _H5Part_get_funcname(), \ + H5PART_ERR_DECOMP, \ + "No dimensions defined." ) + +#define HANDLE_H5PART_BLOCK_DECOMP_ERR \ + (*_err_handler) ( \ + _H5Part_get_funcname(), \ + H5PART_ERR_DECOMP, \ + "Number of blocks does not equal number of procs" ); + +#endif diff --git a/src/H5MultiBlockPrivate.h b/src/H5MultiBlockPrivate.h new file mode 100644 index 0000000..340a95c --- /dev/null +++ b/src/H5MultiBlockPrivate.h @@ -0,0 +1,35 @@ +#ifndef __H5MULTIBLOCKPRIVATE_H +#define __H5MULTIBLOCKPRIVATE_H + +#define MULTIBLOCK_INIT( f ) { \ + h5part_int64_t herr = _H5MultiBlock_init ( f ); \ + if ( herr < 0 ) return herr; \ +} + +h5part_int64_t +_H5MultiBlock_init ( + H5PartFile *f + ); + +h5part_int64_t +_H5MultiBlock_close ( + H5PartFile *f + ); + +h5part_int64_t +_H5MultiBlock_write_data ( + H5PartFile *f, + const char *field_name, + const void *data, + const hid_t type + ); + +h5part_int64_t +_H5MultiBlock_read_data ( + H5PartFile *f, + const char *field_name, + char **data, + hid_t type + ); + +#endif diff --git a/src/H5MultiBlockReadWrite.c b/src/H5MultiBlockReadWrite.c new file mode 100644 index 0000000..38bbcc5 --- /dev/null +++ b/src/H5MultiBlockReadWrite.c @@ -0,0 +1,239 @@ + +#include +#include + +#include +#include "H5Part.h" +#include "H5PartErrors.h" +#include "H5PartPrivate.h" + +#include "H5MultiBlockErrors.h" +#include "H5MultiBlockPrivate.h" + +/*! + \ingroup h5multiblock_c_api + + Write a multiblock field \c name from the buffer starting at \c data + to the current time-step using the defined block decomposition and dimensions. + Values are floating points (64-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dWriteFieldFloat64 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const h5part_float64_t *data /*!< IN: data to write */ + ) { + + SET_FNAME( "H5MultiBlock3dWriteFieldFloat64" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_write_data ( f, name, data, H5T_NATIVE_DOUBLE ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Allocate a buffer to hold a block from a multiblock field and place the + pointer in \c data, then read the block into the buffer. Uses the block + decomposition specified in the file and the defined halo radius. + Values are floating points (64-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dReadFieldFloat64 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to read */ + h5part_float64_t **data /*!< OUT: ptr to read buffer */ + ) { + + SET_FNAME( "H5MultiBlock3dReadFieldFloat64" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_read_data ( f, name, (char**) data, H5T_NATIVE_DOUBLE ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Write a multiblock field \c name from the buffer starting at \c data + to the current time-step using the defined block decomposition and dimensions. + Values are floating points (32-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dWriteFieldFloat32 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const h5part_float32_t *data /*!< IN: data to write */ + ) { + + SET_FNAME( "H5MultiBlock3dWriteFieldFloat32" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_write_data ( f, name, data, H5T_NATIVE_FLOAT ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Allocate a buffer to hold a block from a multiblock field and place the + pointer in \c data, then read the block into the buffer. Uses the block + decomposition specified in the file and the defined halo radius. + Values are floating points (32-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dReadFieldFloat32 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to read */ + h5part_float32_t **data /*!< OUT: ptr to read buffer */ + ) { + + SET_FNAME( "H5MultiBlock3dReadFieldFloat32" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_read_data ( f, name, (char**) data, H5T_NATIVE_FLOAT ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Write a multiblock field \c name from the buffer starting at \c data + to the current time-step using the defined block decomposition and dimensions. + Values are integers (64-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dWriteFieldInt64 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const h5part_int64_t *data /*!< IN: data to write */ + ) { + + SET_FNAME( "H5MultiBlock3dWriteFieldInt64" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_write_data ( f, name, data, H5T_NATIVE_INT64 ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Allocate a buffer to hold a block from a multiblock field and place the + pointer in \c data, then read the block into the buffer. Uses the block + decomposition specified in the file and the defined halo radius. + Values are integers (64-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dReadFieldInt64 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to read */ + h5part_int64_t **data /*!< OUT: ptr to read buffer */ + ) { + + SET_FNAME( "H5MultiBlock3dReadFieldInt64" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_read_data ( f, name, (char**) data, H5T_NATIVE_INT64 ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Write a multiblock field \c name from the buffer starting at \c data + to the current time-step using the defined block decomposition and dimensions. + Values are integers (32-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dWriteFieldInt32 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const h5part_int32_t *data /*!< IN: data to write */ + ) { + + SET_FNAME( "H5MultiBlock3dWriteFieldInt32" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_write_data ( f, name, data, H5T_NATIVE_INT32 ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} + +/*! + \ingroup h5multiblock_c_api + + Allocate a buffer to hold a block from a multiblock field and place the + pointer in \c data, then read the block into the buffer. Uses the block + decomposition specified in the file and the defined halo radius. + Values are integers (32-bit). + + You must use the Fortran indexing scheme to access items in \c data. + + \return \c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock3dReadFieldInt32 ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to read */ + h5part_int32_t **data /*!< OUT: ptr to read buffer */ + ) { + + SET_FNAME( "H5MultiBlock3dReadFieldInt32" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_read_data ( f, name, (char**) data, H5T_NATIVE_INT32 ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} diff --git a/src/H5MultiBlockReadWrite.h b/src/H5MultiBlockReadWrite.h new file mode 100644 index 0000000..6da6ce6 --- /dev/null +++ b/src/H5MultiBlockReadWrite.h @@ -0,0 +1,71 @@ + +#ifndef __H5MULTIBLOCKREADWRITE_H +#define __H5MULTIBLOCKREADWRITE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +h5part_int64_t +H5MultiBlock3dWriteFieldFloat64 ( + H5PartFile *f, + const char *name, + const h5part_float64_t *data + ); + +h5part_int64_t +H5MultiBlock3dReadFieldFloat64 ( + H5PartFile *f, + const char *name, + h5part_float64_t **data + ); + +h5part_int64_t +H5MultiBlock3dWriteFieldFloat32 ( + H5PartFile *f, + const char *name, + const h5part_float32_t *data + ); + +h5part_int64_t +H5MultiBlock3dReadFieldFloat32 ( + H5PartFile *f, + const char *name, + h5part_float32_t **data + ); + +h5part_int64_t +H5MultiBlock3dWriteFieldInt64 ( + H5PartFile *f, + const char *name, + const h5part_int64_t *data + ); + +h5part_int64_t +H5MultiBlock3dReadFieldInt64 ( + H5PartFile *f, + const char *name, + h5part_int64_t **data + ); + +h5part_int64_t +H5MultiBlock3dWriteFieldInt32 ( + H5PartFile *f, + const char *name, + const h5part_int32_t *data + ); + +h5part_int64_t +H5MultiBlock3dReadFieldInt32 ( + H5PartFile *f, + const char *name, + h5part_int32_t **data + ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/H5MultiBlockTypes.h b/src/H5MultiBlockTypes.h new file mode 100644 index 0000000..533fcb5 --- /dev/null +++ b/src/H5MultiBlockTypes.h @@ -0,0 +1,25 @@ +#ifndef __H5MULTIBLOCKTYPES_H +#define __H5MULTIBLOCKTYPES_H + +struct H5MultiBlockStruct { + h5part_int64_t halo_radii[3]; + h5part_int64_t block_dims[3]; + h5part_int64_t field_dims[3]; + h5part_int64_t decomp[3]; + h5part_int64_t offsets[3]; + char field_edges; + int read; + int halo; + int have_decomp; +}; + +#define H5PART_ERR_DECOMP -102 + +#define H5MB_EDGE_X0 0x01 +#define H5MB_EDGE_X1 0x02 +#define H5MB_EDGE_Y0 0x04 +#define H5MB_EDGE_Y1 0x08 +#define H5MB_EDGE_Z0 0x10 +#define H5MB_EDGE_Z1 0x20 + +#endif diff --git a/src/H5Part.c b/src/H5Part.c index 618a794..fea74f9 100644 --- a/src/H5Part.c +++ b/src/H5Part.c @@ -100,7 +100,7 @@ Last modified on April 19, 2007. static unsigned _debug = 0; static h5part_int64_t _h5part_errno = H5PART_SUCCESS; static h5part_error_handler _err_handler = H5PartReportErrorHandler; -static char *__funcname = "NONE"; +static char *__funcname; /********** Declaration of private functions ******/ @@ -512,6 +512,14 @@ H5PartCloseFile ( f->close_block = NULL; } +#ifdef PARALLEL_IO + if ( f->multiblock && f->close_multiblock ) { + (*f->close_multiblock) ( f ); + f->multiblock = NULL; + f->close_multiblock = NULL; + } +#endif + if( f->shape > 0 ) { r = H5Sclose( f->shape ); if ( r < 0 ) HANDLE_H5S_CLOSE_ERR; @@ -2878,6 +2886,7 @@ _init ( void ) { herr_t r5; if ( ! __init ) { + _H5Part_set_funcname ( "NONE" ); #if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8 r5 = H5Eset_auto2 ( H5E_DEFAULT, _h5_error_handler, NULL ); #else @@ -3033,14 +3042,15 @@ _H5Part_print_debug_detail ( void _H5Part_set_funcname ( - char * const fname + char * const fname ) { __funcname = fname; } -const char * +char * const _H5Part_get_funcname ( void ) { return __funcname; } + diff --git a/src/H5Part.h b/src/H5Part.h index a0b2b91..0f11b91 100644 --- a/src/H5Part.h +++ b/src/H5Part.h @@ -14,6 +14,11 @@ extern "C" { #include "H5PartTypes.h" +#include "H5Block.h" +#ifdef PARALLEL_IO +#include "H5MultiBlock.h" +#endif + /* error values */ #define H5PART_SUCCESS 0 #define H5PART_ERR_NOMEM -12 diff --git a/src/H5PartPrivate.h b/src/H5PartPrivate.h index e547dc2..7e7cc5e 100644 --- a/src/H5PartPrivate.h +++ b/src/H5PartPrivate.h @@ -47,7 +47,7 @@ _H5Part_set_funcname ( char * const fname ); -const char * +char * const _H5Part_get_funcname ( void ); diff --git a/src/H5PartTypes.h b/src/H5PartTypes.h index 004caea..29f61d0 100644 --- a/src/H5PartTypes.h +++ b/src/H5PartTypes.h @@ -81,6 +81,11 @@ struct H5PartFile { struct H5BlockStruct *block; h5part_int64_t (*close_block)(struct H5PartFile *f); + +#ifdef PARALLEL_IO + struct H5MultiBlockStruct *multiblock; + h5part_int64_t (*close_multiblock)(struct H5PartFile *f); +#endif }; typedef struct H5PartFile H5PartFile; @@ -89,6 +94,4 @@ typedef struct H5PartFile H5PartFile; # define SEEK_END 2 #endif - - #endif diff --git a/src/Makefile.am b/src/Makefile.am index a9216ee..eeba89e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,13 +40,18 @@ lib_LIBRARIES = @MTARGET@ EXTRA_LIBRARIES = libH5Part.a libH5PartF.a # Header files that I wish to install in $(prefix)/include -include_HEADERS = H5Part.h H5PartTypes.h H5PartErrors.h H5Block.h H5BlockReadWrite.h H5BlockTypes.h H5BlockErrors.h H5Part.inc H5PartF90.inc H5BlockF90.inc H5BlockReadWriteF90.inc @UNDERSCORE_H@ +include_HEADERS = H5Part.h H5PartTypes.h H5PartErrors.h \ + H5Block.h H5BlockReadWrite.h H5BlockTypes.h H5BlockErrors.h \ + H5MultiBlock.h H5MultiBlockReadWrite.h H5MultiBlockTypes.h H5MultiBlockErrors.h \ + H5Part.inc H5PartF90.inc \ + H5BlockF90.inc H5BlockReadWriteF90.inc \ + @UNDERSCORE_H@ # Listing of all possible headers that I may include -EXTRA_HEADERS = H5PartPrivate.h H5BlockPrivate.h +EXTRA_HEADERS = H5PartPrivate.h H5BlockPrivate.h H5MultiBlockPrivate.h # Listing of sources -libH5Part_a_SOURCES = H5Part.c H5Block.c H5BlockReadWrite.c +libH5Part_a_SOURCES = H5Part.c H5Block.c H5BlockReadWrite.c H5MultiBlock.c H5MultiBlockReadWrite.c libH5PartF_a_SOURCES = H5PartF.c H5BlockF.c H5BlockReadWriteF.c @@ -55,7 +60,7 @@ H5Part.inc: H5PartF90.inc # Specific building instruction (What compilers to use...) # ------------ Serial Lib build commands ------------ -libH5Part.a: H5Part.o H5Block.o H5BlockReadWrite.o +libH5Part.a: H5Part.o H5Block.o H5BlockReadWrite.o H5MultiBlock.o H5MultiBlockReadWrite.o ${AR} rucs $@ $^ libH5PartF.a: H5Part.o H5PartF.o H5Block.o H5BlockF.o H5BlockReadWrite.o H5BlockReadWriteF.o @@ -70,6 +75,10 @@ H5Block.o: H5Block.c H5Part.h H5PartPrivate.h H5PartTypes.h H5Block.h H5BlockTyp H5BlockF.o: H5BlockF.c Underscore.h H5Block.h H5BlockReadWrite.o: H5BlockReadWrite.c H5Part.h H5PartPrivate.h H5PartTypes.h H5Block.h H5BlockPrivate.h H5BlockReadWrite.h H5BlockTypes.h H5BlockReadWriteF.o: H5BlockF.c Underscore.h H5Block.h H5BlockReadWrite.h +H5MultiBlock.o: H5MultiBlock.c +H5MultiBlockF.o: H5MultiBlockF.c +H5MultiBlockReadWrite.o: H5MultiBlockReadWrite.c +H5MultiBlockReadWriteF.o: H5MultiBlockReadWriteF.c # ----------- Build Parallel H5Part Stuff ------------ diff --git a/src/generate-h5bl-readwrite.py b/src/generate-h5bl-readwrite.py index e0e78d9..8da8a53 100755 --- a/src/generate-h5bl-readwrite.py +++ b/src/generate-h5bl-readwrite.py @@ -97,7 +97,7 @@ H5Block#DIM#dWriteScalarField#TYPE_ABV# ( ) { SET_FNAME ( "H5Block#DIM#dWriteScalarField#TYPE_ABV#" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -135,7 +135,7 @@ H5Block#DIM#dReadScalarField#TYPE_ABV# ( ) { SET_FNAME ( "H5Block#DIM#dReadScalarField#TYPE_ABV#" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -268,7 +268,7 @@ H5Block#DIM#dWrite3dVectorField#TYPE_ABV# ( ) { SET_FNAME ( "H5Block#DIM#dWrite3dVectorField#TYPE_ABV#" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_WRITABLE_MODE ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); @@ -314,7 +314,7 @@ H5Block#DIM#dRead3dVectorField#TYPE_ABV# ( ) { SET_FNAME ( "H5Block#DIM#dRead3dVectorField#TYPE_ABV#" ); - INIT ( f ); + BLOCK_INIT ( f ); CHECK_TIMEGROUP ( f ); CHECK_LAYOUT ( f ); diff --git a/src/generate-h5multi-readwrite.py b/src/generate-h5multi-readwrite.py new file mode 100755 index 0000000..c8c5313 --- /dev/null +++ b/src/generate-h5multi-readwrite.py @@ -0,0 +1,256 @@ +#!/usr/bin/python + +c_head = """ +#include +#include + +#include +#include "H5Part.h" +#include "H5PartErrors.h" +#include "H5PartPrivate.h" + +#include "H5MultiBlockErrors.h" +#include "H5MultiBlockPrivate.h" +""" + +h_head = """ +#ifndef __H5MULTIBLOCKREADWRITE_H +#define __H5MULTIBLOCKREADWRITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +""" + +h_tail = """ + +#ifdef __cplusplus +} +#endif + +#endif +""" + +fc_head = """ +#include "H5Part.h" +#include "H5PartPrivate.h" +#include "H5Block.h" +#include "H5BlockReadWrite.h" +#include "Underscore.h" + +#if defined(F77_SINGLE_UNDERSCORE) +#define F77NAME(a,b) a +#elif defined(F77_CRAY_UNDERSCORE) +#define F77NAME(a,b) b +#elif defined(F77_NO_UNDERSCORE) +#else +#error Error, no way to determine how to construct fortran bindings +#endif +""" + +fi_head = """ +INTERFACE +""" + +fi_tail = """ +END INTERFACE +""" + +write_h = """ +h5part_int64_t +H5MultiBlock#DIM#dWriteField#TYPE_ABV# ( + H5PartFile *f, + const char *name, + const h5part_#TYPE_H5P#_t *data + ); +""" + +read_h = """ +h5part_int64_t +H5MultiBlock#DIM#dReadField#TYPE_ABV# ( + H5PartFile *f, + const char *name, + h5part_#TYPE_H5P#_t **data + ); +""" + +write_c = """ +/*! + \\ingroup h5multiblock_c_api + + Write a multiblock field \\c name from the buffer starting at \\c data + to the current time-step using the defined block decomposition and dimensions. + Values are #TYPE_FULL#. + + You must use the Fortran indexing scheme to access items in \\c data. + + \\return \\c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock#DIM#dWriteField#TYPE_ABV# ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to write */ + const h5part_#TYPE_H5P#_t *data /*!< IN: data to write */ + ) { + + SET_FNAME( "H5MultiBlock#DIM#dWriteField#TYPE_ABV#" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_write_data ( f, name, data, #TYPE_HDF5# ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} +""" + +read_c = """ +/*! + \\ingroup h5multiblock_c_api + + Allocate a buffer to hold a block from a multiblock field and place the + pointer in \\c data, then read the block into the buffer. Uses the block + decomposition specified in the file and the defined halo radius. + Values are #TYPE_FULL#. + + You must use the Fortran indexing scheme to access items in \\c data. + + \\return \\c H5PART_SUCCESS or error code +*/ +h5part_int64_t +H5MultiBlock#DIM#dReadField#TYPE_ABV# ( + H5PartFile *f, /*!< IN: file handle */ + const char *name, /*!< IN: name of dataset to read */ + h5part_#TYPE_H5P#_t **data /*!< OUT: ptr to read buffer */ + ) { + + SET_FNAME( "H5MultiBlock#DIM#dReadField#TYPE_ABV#" ); + + h5part_int64_t herr; + + herr = _H5MultiBlock_read_data ( f, name, (char**) data, #TYPE_HDF5# ); + if ( herr < 0 ) return herr; + + return H5PART_SUCCESS; +} +""" + +write_fi = """ +INTEGER*8 FUNCTION h5multi_#DIM#d_write_field_#TYPE_F90_ABV# ( filehandle, name, data ) + INTEGER*8, INTENT(IN) :: filehandle + CHARACTER(LEN=*), INTENT(IN) :: name + #TYPE_F90#, INTENT(IN) :: data(*) +END FUNCTION +""" + +read_fi = """ +INTEGER*8 FUNCTION h5multi_#DIM#d_read_field_#TYPE_F90_ABV# ( filehandle, name, data ) + INTEGER*8, INTENT(IN) :: filehandle + CHARACTER(LEN=*), INTENT(IN) :: name + #TYPE_F90#, INTENT(OUT) :: data(*) +END FUNCTION +""" + +write_fc = """ +#if ! defined(F77_NO_UNDERSCORE) +#define h5multi_#DIM#d_write_field_#TYPE_F90_ABV# F77NAME ( \\ + h5multi_#DIM#d_write_field_#TYPE_F90_ABV#_, \\ + H5MULTI_#DIM#D_WRITE_FIELD_#TYPE_F90_ABVC# ) +#endif + +h5part_int64_t +h5multi_#DIM#d_write_field_#TYPE_F90_ABV# ( + h5part_int64_t *f, + const char *field_name, + const h5part_#TYPE_H5P#_t *data, + const int l_field_name + ) { + + H5PartFile *filehandle = (H5PartFile*)(size_t)*f; + + char *field_name2 = _H5Part_strdupfor2c ( field_name, l_field_name ); + + h5part_int64_t herr = H5MultiBlock#DIM#dWriteField#TYPE_ABV# ( + filehandle, field_name2, data ); + + free ( field_name2 ); + return herr; +} +""" + +read_fc = """ +#if ! defined(F77_NO_UNDERSCORE) +#define h5multi_#DIM#d_read_field_#TYPE_F90_ABV# F77NAME ( \\ + h5multi_#DIM#d_read_field_#TYPE_F90_ABV#_, \\ + H5MULTI_#DIM#D_READ_FIELD_#TYPE_F90_ABVC# ) +#endif + +h5part_int64_t +h5multi_#DIM#d_read_field_#TYPE_F90_ABV# ( + h5part_int64_t *f, + const char *field_name, + h5part_#TYPE_H5P#_t **data, + const int l_field_name + ) { + + H5PartFile *filehandle = (H5PartFile*)(size_t)*f; + + char *field_name2 = _H5Part_strdupfor2c ( field_name, l_field_name ); + + h5part_int64_t herr = H5MultiBlock#DIM#dReadField#TYPE_ABV# ( + filehandle, field_name2, (char**) data ); + + free ( field_name2 ); + return herr; +} +""" + +dims = [ "3" ] +types = [ + ["floating points (64-bit)", "Float64", "float64", "H5T_NATIVE_DOUBLE", "REAL*8", "r8", "R8"], + ["floating points (32-bit)", "Float32", "float32", "H5T_NATIVE_FLOAT", "REAL*4", "r4", "R4"], + ["integers (64-bit)", "Int64", "int64", "H5T_NATIVE_INT64", "INTEGER*8", "i8", "I8"], + ["integers (32-bit)", "Int32", "int32", "H5T_NATIVE_INT32", "INTEGER*4", "i4", "I4"] +] + +def create_call(template, type, dim): + fcn = template + fcn = fcn.replace('#DIM#',dim)\ + .replace('#TYPE_FULL#',type[0])\ + .replace('#TYPE_ABV#',type[1])\ + .replace('#TYPE_H5P#',type[2])\ + .replace('#TYPE_HDF5#',type[3])\ + .replace('#TYPE_F90#',type[4])\ + .replace('#TYPE_F90_ABV#',type[5])\ + .replace('#TYPE_F90_ABVC#',type[6]) + return fcn + +def write_calls(): + cfile = file('H5MultiBlockReadWrite.c','w') + cfile.write(c_head) + hfile = file('H5MultiBlockReadWrite.h','w') + hfile.write(h_head) +# fcfile = file('H5MultiBlockReadWriteF.c','w') +# fcfile.write(fc_head) +# fifile = file('H5MultiBlockReadWriteF90.inc','w') +# fifile.write(fi_head) + for dim in dims: + for type in types: + cfile.write(create_call(write_c,type,dim)); + cfile.write(create_call(read_c,type,dim)); + hfile.write(create_call(write_h,type,dim)); + hfile.write(create_call(read_h,type,dim)); +# fcfile.write(create_call(write_fc,type,dim)); +# fcfile.write(create_call(read_fc,type,dim)); +# fifile.write(create_call(write_fi,type,dim)); +# fifile.write(create_call(read_fi,type,dim)); + cfile.close() + hfile.write(h_tail) + hfile.close() +# fcfile.close() +# fifile.write(fi_tail) +# fifile.close() + +write_calls() +