diff --git a/examples/hello/hdf5Writer/helloHDF5Writer.cpp b/examples/hello/hdf5Writer/helloHDF5Writer.cpp index ecfe1b940a2bf105f93f4477a23a4d02e5f02b88..07088fb2ee76ab6276b5214960cb3836ce153c80 100644 --- a/examples/hello/hdf5Writer/helloHDF5Writer.cpp +++ b/examples/hello/hdf5Writer/helloHDF5Writer.cpp @@ -8,10 +8,10 @@ #include <iostream> #include <vector> -#include <mpi.h> - #include <adios2.h> +#include <mpi.h> + int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); @@ -65,6 +65,11 @@ int main(int argc, char *argv[]) intCountDim1 = intDim1 - rank * (intDim1 / size); } + std::cout << " rank=" << rank << " of " << size + << ", dim1 count: " << intCountDim1 + << ", offset: " << intOffsetDim1 << std::endl; + std::cout << " intOffsetDim2=" << intOffsetDim2 << " " << intDim2 + << std::endl; try { // Define variable and local size @@ -83,7 +88,7 @@ int main(int argc, char *argv[]) // Define method for engine creation, it is basically straight-forward // parameters - adios::Method &HDF5Settings = adios.DeclareMethod("w"); + adios::Method &HDF5Settings = adios.DeclareMethod("hdf5"); HDF5Settings.SetEngine("HDF5Writer"); HDF5Settings.SetParameters("chunck=yes", "collectiveIO=yes"); // HDF5Settings.AddTransport( "Mdtm", "localIP=128.0.0.0.1", @@ -98,19 +103,36 @@ int main(int argc, char *argv[]) throw std::ios_base::failure( "ERROR: failed to create HDF5 I/O engine at Open\n"); - HDF5Writer->Write(ioMyDoubles, myDoubles.data() + - doubleVOffset); // Base class Engine - // own the Write<T> - // that will call - // overloaded Write - // from Derived - HDF5Writer->Write(ioMyInts, - myInts.data() + (intOffsetDim1 * intDim2 * rank)); - - HDF5Writer->Write(ioMyCFloats, myCFloats.data() + complexOffset); - HDF5Writer->Write(ioMyCDoubles, myCDoubles.data() + complexOffset); - HDF5Writer->Write(ioMyCLongDoubles, - myCLongDoubles.data() + complexOffset); + int ts = 0; + int totalts = 3; + while (true) + { + if (rank == 0) + { + std::cout << " total timesteps: " << totalts << " curr: " << ts + << " th" << std::endl; + } + HDF5Writer->Write(ioMyDoubles, + myDoubles.data() + + doubleVOffset); // Base class Engine + // own the Write<T> + // that will call + // overloaded Write + // from Derived + HDF5Writer->Write(ioMyInts, + myInts.data() + (intOffsetDim1 * intDim2)); + + HDF5Writer->Write(ioMyCFloats, myCFloats.data() + complexOffset); + HDF5Writer->Write(ioMyCDoubles, myCDoubles.data() + complexOffset); + HDF5Writer->Write(ioMyCLongDoubles, + myCLongDoubles.data() + complexOffset); + ts++; + if (ts >= totalts) + { + break; + } + HDF5Writer->Advance(); + } HDF5Writer->Close(); } catch (std::invalid_argument &e) diff --git a/source/adios2/ADIOS.cpp b/source/adios2/ADIOS.cpp index ac4725a53e4257fe58e1a06bef1e10578db4fb52..8fd661a80b0c3f3a15446728afa25955965cd928 100644 --- a/source/adios2/ADIOS.cpp +++ b/source/adios2/ADIOS.cpp @@ -194,7 +194,16 @@ std::shared_ptr<Engine> ADIOS::Open(const std::string &name, "HDF5 library, can't use HDF5\n"); #endif } - + else if (type == "HDF5Reader") // -Junmin + { +#ifdef ADIOS2_HAVE_HDF5 + return std::make_shared<HDF5Reader>(*this, name, accessMode, mpiComm, + method); +#else + throw std::invalid_argument("ERROR: this version didn't compile with " + "HDF5 library, can't use HDF5\n"); +#endif + } else { if (m_DebugMode == true) diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt index 7099e25b265fc69134904739ca277005eaceaac7..98e2c4ac25dcdc10b65df177971933d7c0b6d46f 100644 --- a/source/adios2/CMakeLists.txt +++ b/source/adios2/CMakeLists.txt @@ -106,6 +106,7 @@ if(ADIOS_USE_HDF5) target_sources(adios2 PRIVATE engine/hdf5/HDF5ReaderP.cpp engine/hdf5/HDF5WriterP.cpp + engine/hdf5/HDF5Common.cpp ) target_link_libraries(adios2 PRIVATE ${HDF5_C_LIBRARIES}) endif() diff --git a/source/adios2/engine/hdf5/HDF5Common.cpp b/source/adios2/engine/hdf5/HDF5Common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2a9c521ee6b08d50094910ea43e85920d395350 --- /dev/null +++ b/source/adios2/engine/hdf5/HDF5Common.cpp @@ -0,0 +1,223 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * HDF5Common.cpp + * + * Created on: April 20, 2017 + * Author: Junmin + */ + +#include "HDF5Common.h" + +#include <complex> +#include <iostream> + +#include "adios2/ADIOSMPI.h" + +namespace adios +{ + +#define H5_ERROR std::cout << "[ADIOS H5 ERROR] " + +HDF5Common::HDF5Common() +: m_WriteMode(false), m_CurrentTimeStep(0), m_NumTimeSteps(0) +{ + m_DefH5TypeComplexFloat = + H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>)); + H5Tinsert(m_DefH5TypeComplexFloat, "freal", 0, H5T_NATIVE_FLOAT); + H5Tinsert(m_DefH5TypeComplexFloat, "fimg", H5Tget_size(H5T_NATIVE_FLOAT), + H5T_NATIVE_FLOAT); + + m_DefH5TypeComplexDouble = + H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>)); + H5Tinsert(m_DefH5TypeComplexDouble, "dreal", 0, H5T_NATIVE_DOUBLE); + H5Tinsert(m_DefH5TypeComplexDouble, "dimg", H5Tget_size(H5T_NATIVE_DOUBLE), + H5T_NATIVE_DOUBLE); + + m_DefH5TypeComplexLongDouble = + H5Tcreate(H5T_COMPOUND, sizeof(std::complex<long double>)); + H5Tinsert(m_DefH5TypeComplexLongDouble, "ldouble real", 0, + H5T_NATIVE_LDOUBLE); + H5Tinsert(m_DefH5TypeComplexLongDouble, "ldouble img", + H5Tget_size(H5T_NATIVE_LDOUBLE), H5T_NATIVE_LDOUBLE); +} + +void HDF5Common::Init(const std::string name, MPI_Comm comm, bool toWrite) +{ + m_WriteMode = toWrite; + + // + m_PropertyListId = H5Pcreate(H5P_FILE_ACCESS); + +#ifdef ADIOS2_HAVE_MPI + H5Pset_fapl_mpio(m_PropertyListId, comm, MPI_INFO_NULL); +#endif + + std::string ts0 = "/TimeStep0"; + + if (toWrite) + { + /* + * Create a new file collectively and release property list identifier. + */ + m_FileId = H5Fcreate(name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, + m_PropertyListId); + if (m_FileId >= 0) + { + m_GroupId = H5Gcreate2(m_FileId, ts0.c_str(), H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + if (m_GroupId < 0) + { + std::clog << "H5Common::Init: ERROR" << std::endl; + throw std::runtime_error("HDF5: Unable to create group " + ts0); + } + } + } + else + { + // read a file collectively + m_FileId = H5Fopen(name.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); + if (m_FileId >= 0) + { + m_GroupId = H5Gopen(m_FileId, ts0.c_str(), H5P_DEFAULT); + } + } + + H5Pclose(m_PropertyListId); +} + +void HDF5Common::WriteTimeSteps() +{ + if (m_FileId < 0) + { + // std::cerr<<"[ADIOS HDF5Error]: Invalid file to record timestep + // to."<<std::endl; + H5_ERROR << "Invalid file to record timestep to." << std::endl; + return; + } + + if (!m_WriteMode) + { + return; + } + + hid_t s = H5Screate(H5S_SCALAR); + + hid_t attr = H5Acreate(m_FileId, "NumTimeSteps", H5T_NATIVE_UINT, s, + H5P_DEFAULT, H5P_DEFAULT); + uint totalTimeSteps = m_CurrentTimeStep + 1; + + if (m_GroupId < 0) + { + totalTimeSteps = m_CurrentTimeStep; + } + + H5Awrite(attr, H5T_NATIVE_UINT, &totalTimeSteps); + + H5Sclose(s); + H5Aclose(attr); +} + +unsigned int HDF5Common::GetNumTimeSteps() +{ + if (m_WriteMode) + { + return -1; + } + + if (m_FileId < 0) + { + std::cerr + << "[ADIOS HDF5Error]: Invalid file to read timestep attribute." + << std::endl; + return -1; + } + + if (m_NumTimeSteps <= 0) + { + hid_t attr = H5Aopen(m_FileId, "NumTimeSteps", H5P_DEFAULT); + + H5Aread(attr, H5T_NATIVE_UINT, &m_NumTimeSteps); + H5Aclose(attr); + } + + return m_NumTimeSteps; +} + +void HDF5Common::Close() +{ + if (m_FileId < 0) + { + return; + } + + WriteTimeSteps(); + + if (m_GroupId >= 0) + { + H5Gclose(m_GroupId); + } + + H5Fclose(m_FileId); + m_FileId = -1; + m_GroupId = -1; +} + +void HDF5Common::Advance() +{ + if (m_GroupId >= 0) + { + H5Gclose(m_GroupId); + m_GroupId = -1; + } + + if (m_WriteMode) + { + // m_GroupId = H5Gcreate2(m_FileId, tsname.c_str(), H5P_DEFAULT, + // H5P_DEFAULT, H5P_DEFAULT); + } + else + { + if (m_NumTimeSteps == 0) + { + GetNumTimeSteps(); + } + if (m_CurrentTimeStep + 1 >= m_NumTimeSteps) + { + return; + } + + std::string timeStepName = + "/TimeStep" + std::to_string(m_CurrentTimeStep + 1); + m_GroupId = H5Gopen(m_FileId, timeStepName.c_str(), H5P_DEFAULT); + if (m_GroupId < 0) + { + throw std::runtime_error("HDF5: Unable to open group " + + timeStepName); + } + } + ++m_CurrentTimeStep; +} + +void HDF5Common::CheckWriteGroup() +{ + if (!m_WriteMode) + { + return; + } + if (m_GroupId >= 0) + { + return; + } + + std::string timeStepName = "/TimeStep" + std::to_string(m_CurrentTimeStep); + m_GroupId = H5Gcreate2(m_FileId, timeStepName.c_str(), H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); + if (m_GroupId < 0) + { + throw std::runtime_error("HDF5: Unable to create group " + + timeStepName); + } +} +} diff --git a/source/adios2/engine/hdf5/HDF5Common.h b/source/adios2/engine/hdf5/HDF5Common.h new file mode 100644 index 0000000000000000000000000000000000000000..d5a6a77190b1ed2465bf62b82073835b061afe27 --- /dev/null +++ b/source/adios2/engine/hdf5/HDF5Common.h @@ -0,0 +1,57 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * HDF5CommonP.h + * + * Created on: March 20, 2017 + * Author: Junmin + */ + +#ifndef ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_ +#define ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_ + +#include <string> + +#include "adios2/ADIOSMPICommOnly.h" + +#include <hdf5.h> + +namespace adios +{ + +class HDF5Common +{ + +public: + /** + * Constructor for HDF5 file + */ + HDF5Common(); + + void Init(const std::string name, MPI_Comm comm, bool toWrite); + void Close(); + void Advance(); + + unsigned int GetNumTimeSteps(); + void WriteTimeSteps(); + + hid_t m_PropertyListId, m_FileId; + hid_t m_GroupId; + + hid_t m_DefH5TypeComplexDouble; + hid_t m_DefH5TypeComplexFloat; + hid_t m_DefH5TypeComplexLongDouble; + + unsigned int m_CurrentTimeStep; + + void CheckWriteGroup(); + +private: + bool m_WriteMode; + unsigned int m_NumTimeSteps; +}; + +} // end namespace adios + +#endif /* ADIOS2_ENGINE_HDF5_HDF5COMMON_P_H_ */ diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.cpp b/source/adios2/engine/hdf5/HDF5ReaderP.cpp index 782135c00da4f7ef2e0f18fd2aa17e48277e97ea..7f3ead729cae47aaa634e6a0d2365a2294584a06 100644 --- a/source/adios2/engine/hdf5/HDF5ReaderP.cpp +++ b/source/adios2/engine/hdf5/HDF5ReaderP.cpp @@ -10,4 +10,249 @@ #include "HDF5ReaderP.h" -#include <iostream> //needs to go away, this is just for demo purposes +#include "adios2/ADIOSMPI.h" + +namespace adios +{ + +HDF5Reader::HDF5Reader(ADIOS &adios, const std::string name, + const std::string accessMode, MPI_Comm mpiComm, + const Method &method) +: Engine(adios, "HDF5Reader", name, accessMode, mpiComm, method, + " HDF5Reader constructor (or call to ADIOS Open).\n") + +{ + Init(); +} + +HDF5Reader::~HDF5Reader() { Close(); } + +bool HDF5Reader::isValid() +{ + if (m_AccessMode != "r" && m_AccessMode != "read") + { + return false; + } + if (m_H5File.m_FileId >= 0) + { + return true; + } +} +void HDF5Reader::Init() +{ + if (m_AccessMode != "r" && m_AccessMode != "read") + { + throw std::invalid_argument( + "ERROR: HDF5Reader doesn't support access mode " + m_AccessMode + + ", in call to ADIOS Open or HDF5Reader constructor\n"); + } + + m_H5File.Init(m_Name, m_MPIComm, false); + m_H5File.GetNumTimeSteps(); +} + +Variable<void> *HDF5Reader::InquireVariable(const std::string &variableName, + const bool readIn) +{ + std::cout << "Not implemented: HDF5Reader::InquireVariable()" << std::endl; + return nullptr; +} + +Variable<char> *HDF5Reader::InquireVariableChar(const std::string &variableName, + const bool readIn) +{ + return nullptr; +} + +Variable<unsigned char> * +HDF5Reader::InquireVariableUChar(const std::string &variableName, + const bool readIn) +{ + return nullptr; +} + +Variable<short> * +HDF5Reader::InquireVariableShort(const std::string &variableName, + const bool readIn) +{ + return nullptr; +} + +Variable<unsigned short> * +HDF5Reader::InquireVariableUShort(const std::string &variableName, + const bool readIn) +{ + return nullptr; +} + +Variable<int> *HDF5Reader::InquireVariableInt(const std::string &variableName, + const bool) +{ + return nullptr; +} + +Variable<unsigned int> * +HDF5Reader::InquireVariableUInt(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<long int> * +HDF5Reader::InquireVariableLInt(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<unsigned long int> * +HDF5Reader::InquireVariableULInt(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<long long int> * +HDF5Reader::InquireVariableLLInt(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<unsigned long long int> * +HDF5Reader::InquireVariableULLInt(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<float> * +HDF5Reader::InquireVariableFloat(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<double> * +HDF5Reader::InquireVariableDouble(const std::string &variableName, const bool) +{ + + if (m_RankMPI == 0) + { + std::cout << " ... reading var: " << variableName << std::endl; + } + int totalts = m_H5File.GetNumTimeSteps(); + + if (m_RankMPI == 0) + { + std::cout << " ... I saw total timesteps: " << totalts << std::endl; + } + + return nullptr; +} + +Variable<long double> * +HDF5Reader::InquireVariableLDouble(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<std::complex<float>> * +HDF5Reader::InquireVariableCFloat(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<std::complex<double>> * +HDF5Reader::InquireVariableCDouble(const std::string &variableName, const bool) +{ + return nullptr; +} + +Variable<std::complex<long double>> * +HDF5Reader::InquireVariableCLDouble(const std::string &variableName, const bool) +{ + return nullptr; +} + +VariableCompound * +HDF5Reader::InquireVariableCompound(const std::string &variableName, + const bool readIn) +{ + return nullptr; +} + +template <class T> +void HDF5Reader::UseHDFRead(const std::string &variableName, T *values, + hid_t h5Type) +{ + hid_t dataSetId = + H5Dopen(m_H5File.m_GroupId, variableName.c_str(), H5P_DEFAULT); + if (m_RankMPI == 0) + { + std::cout << " opened to read: " << variableName << std::endl; + } + + if (dataSetId < 0) + { + return; + } + hid_t fileSpace = H5Dget_space(dataSetId); + + if (fileSpace < 0) + { + return; + } + int ndims = H5Sget_simple_extent_ndims(fileSpace); + hsize_t dims[ndims]; + herr_t status_n = H5Sget_simple_extent_dims(fileSpace, dims, NULL); + + hsize_t start[ndims] = {0}, count[ndims] = {0}, stride[ndims] = {1}; + + int totalElements = 1; + for (int i = 0; i < ndims; i++) + { + std::cout << " [" << i << "] th dimension: " << dims[i] << std::endl; + count[i] = dims[i]; + totalElements *= dims[i]; + } + + start[0] = m_RankMPI * dims[0] / m_SizeMPI; + count[0] = dims[0] / m_SizeMPI; + if (m_RankMPI == m_SizeMPI - 1) + { + count[0] = dims[0] - count[0] * (m_SizeMPI - 1); + std::cout << " rank = " << m_RankMPI << ", count=" << count[0] + << std::endl; + } + + hid_t ret = H5Sselect_hyperslab(fileSpace, H5S_SELECT_SET, start, stride, + count, NULL); + if (ret < 0) + { + return; + } + + hid_t memDataSpace = H5Screate_simple(ndims, count, NULL); + + int elementsRead = 1; + for (int i = 0; i < ndims; i++) + { + elementsRead *= count[i]; + } + + T data_array[elementsRead]; + ret = H5Dread(dataSetId, h5Type, memDataSpace, fileSpace, H5P_DEFAULT, + data_array); + + for (int i = 0; i < elementsRead; i++) + { + std::cout << "... rank " << m_RankMPI << " , " << data_array[i] + << std::endl; + } + + H5Sclose(memDataSpace); + + H5Sclose(fileSpace); + H5Dclose(dataSetId); +} + +void HDF5Reader::Advance(float timeoutSec) { m_H5File.Advance(); } + +void HDF5Reader::Close(const int transportIndex) { m_H5File.Close(); } + +} // end namespace adios diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.h b/source/adios2/engine/hdf5/HDF5ReaderP.h index 42e4dab6be48f5fdda07b7fcd5aac35bb135e63e..70c71137b5c6a4f7edc92600cae66a2ec67fb07d 100644 --- a/source/adios2/engine/hdf5/HDF5ReaderP.h +++ b/source/adios2/engine/hdf5/HDF5ReaderP.h @@ -11,4 +11,115 @@ #ifndef ADIOS2_ENGINE_HDF5_HDF5READERP_H_ #define ADIOS2_ENGINE_HDF5_HDF5READERP_H_ +#include "HDF5Common.h" + +#include "adios2/ADIOSMPICommOnly.h" +#include "adios2/core/Engine.h" + +namespace adios +{ + +class HDF5Reader : public Engine +{ + +public: + /** + * Constructor for single HDF5 reader engine, reads from HDF5 format + * @param name unique name given to the engine + * @param accessMode + * @param mpiComm + * @param method + */ + HDF5Reader(ADIOS &adios, const std::string name, + const std::string accessMode, MPI_Comm mpiComm, + const Method &method); + + virtual ~HDF5Reader(); + + bool isValid(); + + Variable<void> *InquireVariable(const std::string &variableName, + const bool readIn = true); + + Variable<char> *InquireVariableChar(const std::string &variableName, + const bool readIn = true); + + Variable<unsigned char> * + InquireVariableUChar(const std::string &variableName, + const bool readIn = true); + + Variable<short> *InquireVariableShort(const std::string &variableName, + const bool readIn = true); + + Variable<unsigned short> * + InquireVariableUShort(const std::string &variableName, + const bool readIn = true); + + Variable<int> *InquireVariableInt(const std::string &variableName, + const bool readIn = true); + + Variable<unsigned int> *InquireVariableUInt(const std::string &variableName, + const bool readIn = true); + + Variable<long int> *InquireVariableLInt(const std::string &variableName, + const bool readIn = true); + + Variable<unsigned long int> * + InquireVariableULInt(const std::string &variableName, + const bool readIn = true); + + Variable<long long int> * + InquireVariableLLInt(const std::string &variableName, + const bool readIn = true); + + Variable<unsigned long long int> * + InquireVariableULLInt(const std::string &variableName, + const bool readIn = true); + + Variable<float> *InquireVariableFloat(const std::string &variableName, + const bool readIn = true); + + Variable<double> *InquireVariableDouble(const std::string &variableName, + const bool readIn = true); + Variable<long double> * + InquireVariableLDouble(const std::string &variableName, + const bool readIn = true); + + Variable<std::complex<float>> * + InquireVariableCFloat(const std::string &variableName, + const bool readIn = true); + + Variable<std::complex<double>> * + InquireVariableCDouble(const std::string &variableName, + const bool readIn = true); + + Variable<std::complex<long double>> * + InquireVariableCLDouble(const std::string &variableName, + const bool readIn = true); + + /** + * Not implemented + * @param name + * @param readIn + * @return + */ + VariableCompound *InquireVariableCompound(const std::string &variableName, + const bool readIn = true); + + void Advance(float timeoutSecc = 0.0); + + void Close(const int transportIndex = -1); + + template <typename T> + void UseHDFRead(const std::string &variableName, T *values, hid_t h5Type); + + /* + template <class T> + void ReadMe(Variable<T> &variable, T *values, hid_t h5type); + */ +private: + HDF5Common m_H5File; + void Init(); +}; +}; #endif /* ADIOS2_ENGINE_HDF5_HDF5READERP_H_ */ diff --git a/source/adios2/engine/hdf5/HDF5WriterP.cpp b/source/adios2/engine/hdf5/HDF5WriterP.cpp index bb01c6301ed4328fedff18a525645372c91680b5..784f1aea4267c84f47d071637f93a936bd6d6a51 100644 --- a/source/adios2/engine/hdf5/HDF5WriterP.cpp +++ b/source/adios2/engine/hdf5/HDF5WriterP.cpp @@ -10,8 +10,6 @@ #include "HDF5WriterP.h" -#include <iostream> //needs to go away, this is just for demo purposes - #include "adios2/ADIOSMPI.h" #include "adios2/core/Support.h" #include "adios2/core/adiosFunctions.h" //CSVToVector @@ -27,40 +25,10 @@ HDF5Writer::HDF5Writer(ADIOS &adios, const std::string name, " HDF5Writer constructor (or call to ADIOS Open).\n"), m_Buffer(m_DebugMode) { - // - // 16, 4 vs: 8 - // std::cout<<sizeof(std::complex<double>)<<", - // "<<sizeof(H5T_NATIVE_DOUBLE)<<" vs: - // "<<H5Tget_size(H5T_NATIVE_DOUBLE)<<std::endl; - // 8, 4 vs: 4 - // std::cout<<sizeof(std::complex<float>)<<", "<<sizeof(H5T_NATIVE_FLOAT)<<" - // vs: "<<H5Tget_size(H5T_NATIVE_FLOAT)<<std::endl; - // 32, 4 vs: 16 - // std::cout<<sizeof(std::complex<long double>)<<", - // "<<sizeof(H5T_NATIVE_LDOUBLE)<<" vs: - // "<<H5Tget_size(H5T_NATIVE_LDOUBLE)<<std::endl; - - DefH5T_COMPLEX_FLOAT = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>)); - H5Tinsert(DefH5T_COMPLEX_FLOAT, "freal", 0, H5T_NATIVE_FLOAT); - H5Tinsert(DefH5T_COMPLEX_FLOAT, "fimg", H5Tget_size(H5T_NATIVE_FLOAT), - H5T_NATIVE_FLOAT); - - DefH5T_COMPLEX_DOUBLE = - H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>)); - H5Tinsert(DefH5T_COMPLEX_DOUBLE, "dreal", 0, H5T_NATIVE_DOUBLE); - H5Tinsert(DefH5T_COMPLEX_DOUBLE, "dimg", H5Tget_size(H5T_NATIVE_DOUBLE), - H5T_NATIVE_DOUBLE); - - DefH5T_COMPLEX_LongDOUBLE = - H5Tcreate(H5T_COMPOUND, sizeof(std::complex<long double>)); - H5Tinsert(DefH5T_COMPLEX_LongDOUBLE, "ldouble real", 0, H5T_NATIVE_LDOUBLE); - H5Tinsert(DefH5T_COMPLEX_LongDOUBLE, "ldouble img", - H5Tget_size(H5T_NATIVE_LDOUBLE), H5T_NATIVE_LDOUBLE); - Init(); } -HDF5Writer::~HDF5Writer() {} +HDF5Writer::~HDF5Writer() { Close(); } void HDF5Writer::Init() { @@ -71,23 +39,8 @@ void HDF5Writer::Init() "ERROR: HDF5Writer doesn't support access mode " + m_AccessMode + ", in call to ADIOS Open or HDF5Writer constructor\n"); } - // std::cout << "method: # of inputs:" << m_Method.m_Parameters.size() << - // std::endl; - - // std::cout << "::Init hdf5 parallel writer. File name:" << m_Name << - // std::endl; - - _plist_id = H5Pcreate(H5P_FILE_ACCESS); - -#ifdef ADIOS2_HAVE_MPI - H5Pset_fapl_mpio(_plist_id, m_MPIComm, MPI_INFO_NULL); -#endif - /* - * Create a new file collectively and release property list identifier. - */ - _file_id = H5Fcreate(m_Name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, _plist_id); - H5Pclose(_plist_id); + m_H5File.Init(m_Name, m_MPIComm, true); } void HDF5Writer::Write(Variable<char> &variable, const char *values) @@ -165,19 +118,19 @@ void HDF5Writer::Write(Variable<long double> &variable, void HDF5Writer::Write(Variable<std::complex<float>> &variable, const std::complex<float> *values) { - UseHDFWrite(variable, values, DefH5T_COMPLEX_FLOAT); + UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexFloat); } void HDF5Writer::Write(Variable<std::complex<double>> &variable, const std::complex<double> *values) { - UseHDFWrite(variable, values, DefH5T_COMPLEX_DOUBLE); + UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexDouble); } void HDF5Writer::Write(Variable<std::complex<long double>> &variable, const std::complex<long double> *values) { - UseHDFWrite(variable, values, DefH5T_COMPLEX_LongDOUBLE); + UseHDFWrite(variable, values, m_H5File.m_DefH5TypeComplexLongDouble); } // String version @@ -269,87 +222,96 @@ void HDF5Writer::Write(const std::string variableName, const std::complex<float> *values) { UseHDFWrite(m_ADIOS.GetVariable<std::complex<float>>(variableName), values, - DefH5T_COMPLEX_FLOAT); + m_H5File.m_DefH5TypeComplexFloat); } void HDF5Writer::Write(const std::string variableName, const std::complex<double> *values) { UseHDFWrite(m_ADIOS.GetVariable<std::complex<double>>(variableName), values, - DefH5T_COMPLEX_DOUBLE); + m_H5File.m_DefH5TypeComplexDouble); } void HDF5Writer::Write(const std::string variableName, const std::complex<long double> *values) { UseHDFWrite(m_ADIOS.GetVariable<std::complex<long double>>(variableName), - values, DefH5T_COMPLEX_LongDOUBLE); + values, m_H5File.m_DefH5TypeComplexLongDouble); } -void HDF5Writer::Close(const int transportIndex) -{ - // std::cout << " ===> CLOSING HDF5 <===== " << std::endl; - // H5Dclose(_dset_id); - // H5Sclose(_filespace); - // H5Sclose(_memspace); - // H5Pclose(_plist_id); - H5Fclose(_file_id); -} +void HDF5Writer::Advance(float timeoutSec) { m_H5File.Advance(); } + +void HDF5Writer::Close(const int transportIndex) { m_H5File.Close(); } template <class T> void HDF5Writer::UseHDFWrite(Variable<T> &variable, const T *values, - hid_t h5type) + hid_t h5Type) { + m_H5File.CheckWriteGroup(); // here comes your magic at Writing now variable.m_UserValues has the data // passed by the user // set variable variable.m_AppValues = values; m_WrittenVariables.insert(variable.m_Name); - int dimSize = variable.m_GlobalDimensions.size(); - /* - std::cout << "writting : " << variable.m_Name - << " dim size:" << variable.m_GlobalDimensions.size() << - std::endl; + int dimSize = std::max(variable.m_GlobalDimensions.size(), + variable.m_LocalDimensions.size()); - for (int i = 0; i < dimSize; i++) { - std::cout << " dim: " << i << ", size:" << variable.m_GlobalDimensions[i] - << " offset=" << variable.m_Offsets[i] - << " count=" << variable.m_LocalDimensions[i] << std::endl; - } - */ std::vector<hsize_t> dimsf, count, offset; for (int i = 0; i < dimSize; i++) { - dimsf.push_back(variable.m_GlobalDimensions[i]); - count.push_back(variable.m_LocalDimensions[i]); - offset.push_back(variable.m_Offsets[i]); + if (variable.m_GlobalDimensions.size() == dimSize) + { + dimsf.push_back(variable.m_GlobalDimensions[i]); + } + else + { + dimsf.push_back(variable.m_LocalDimensions[i]); + } + + if (variable.m_LocalDimensions.size() == dimSize) + { + count.push_back(variable.m_LocalDimensions[i]); + if (variable.m_Offsets.size() == dimSize) + { + offset.push_back(variable.m_Offsets[i]); + } + else + { + offset.push_back(0); + } + } + else + { + count.push_back(variable.m_GlobalDimensions[i]); + offset.push_back(0); + } } - _filespace = H5Screate_simple(dimSize, dimsf.data(), NULL); + hid_t fileSpace = H5Screate_simple(dimSize, dimsf.data(), NULL); - _dset_id = H5Dcreate(_file_id, variable.m_Name.c_str(), h5type, _filespace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - // H5Sclose(_filespace); + hid_t dsetID = + H5Dcreate(m_H5File.m_GroupId, variable.m_Name.c_str(), h5Type, + fileSpace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // H5Sclose(fileSpace); - _memspace = H5Screate_simple(dimSize, count.data(), NULL); + hid_t memSpace = H5Screate_simple(dimSize, count.data(), NULL); // Select hyperslab - _filespace = H5Dget_space(_dset_id); - H5Sselect_hyperslab(_filespace, H5S_SELECT_SET, offset.data(), NULL, + fileSpace = H5Dget_space(dsetID); + H5Sselect_hyperslab(fileSpace, H5S_SELECT_SET, offset.data(), NULL, count.data(), NULL); // Create property list for collective dataset write. - _plist_id = H5Pcreate(H5P_DATASET_XFER); + hid_t plistID = H5Pcreate(H5P_DATASET_XFER); #ifdef ADIOS2_HAVE_MPI - H5Pset_dxpl_mpio(_plist_id, H5FD_MPIO_COLLECTIVE); + H5Pset_dxpl_mpio(plistID, H5FD_MPIO_COLLECTIVE); #endif herr_t status; - status = - H5Dwrite(_dset_id, h5type, _memspace, _filespace, _plist_id, values); + status = H5Dwrite(dsetID, h5Type, memSpace, fileSpace, plistID, values); if (status < 0) { @@ -357,13 +319,10 @@ void HDF5Writer::UseHDFWrite(Variable<T> &variable, const T *values, std::cerr << " Write failed. " << std::endl; } - // std::cout << " ==> User is responsible for freeing the data " << - // std::endl; - - H5Dclose(_dset_id); - H5Sclose(_filespace); - H5Sclose(_memspace); - H5Pclose(_plist_id); + H5Dclose(dsetID); + H5Sclose(fileSpace); + H5Sclose(memSpace); + H5Pclose(plistID); } } // end namespace adios diff --git a/source/adios2/engine/hdf5/HDF5WriterP.h b/source/adios2/engine/hdf5/HDF5WriterP.h index cca6b53ee38edc4b55ca5613b7889a9654a4ed9c..21151a18ab648cab1b8d389436a13dfb3518c3ef 100644 --- a/source/adios2/engine/hdf5/HDF5WriterP.h +++ b/source/adios2/engine/hdf5/HDF5WriterP.h @@ -12,6 +12,8 @@ #ifndef ADIOS2_ENGINE_HDF5_HDF5WRITERP_H__ #define ADIOS2_ENGINE_HDF5_HDF5WRITERP_H__ +#include "HDF5Common.h" + #include "adios2/ADIOSConfig.h" #include "adios2/ADIOSMPICommOnly.h" #include "adios2/capsule/heap/STLVector.h" @@ -27,14 +29,11 @@ class HDF5Writer : public Engine public: /** - * Constructor for single BP capsule engine, writes in BP format into a - * single - * heap capsule + * Constructor for HDF5 writer engine, writes in hdf5 format * @param name unique name given to the engine * @param accessMode * @param mpiComm * @param method - * @param debugMode */ HDF5Writer(ADIOS &adios, const std::string name, const std::string accessMode, MPI_Comm mpiComm, @@ -86,6 +85,8 @@ public: void Write(const std::string variableName, const std::complex<long double> *values); + void Advance(float timeoutSec = 0.0); + void Close(const int transportIndex = -1); private: @@ -93,17 +94,11 @@ private: capsule::STLVector m_Buffer; void Init(); - void clean(); - - hid_t _plist_id, _file_id, _dset_id; - hid_t _memspace, _filespace; - hid_t DefH5T_COMPLEX_DOUBLE; - hid_t DefH5T_COMPLEX_FLOAT; - hid_t DefH5T_COMPLEX_LongDOUBLE; + HDF5Common m_H5File; template <class T> - void UseHDFWrite(Variable<T> &variable, const T *values, hid_t h5type); + void UseHDFWrite(Variable<T> &variable, const T *values, hid_t h5Type); }; } // end namespace adios diff --git a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp index bac7570fbc6230ed915f2c33645e738f5a7b61e0..3f2b6a69f8ab11257cb14674feb1a174bf23d8ef 100644 --- a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp +++ b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp @@ -9,6 +9,7 @@ #include <stdexcept> #include <adios2.h> + #include <hdf5.h> #include <gtest/gtest.h> @@ -23,6 +24,162 @@ public: SmallTestData m_TestData; }; +class HDF5NativeReader +{ + +public: + HDF5NativeReader(const std::string fileName); + ~HDF5NativeReader(); + + bool Advance(); + + void GetVarInfo(const std::string varName, std::vector<hsize_t> &dims, + hid_t &h5Type); + void ReadVar(const std::string varName, void *dataArray); + + int m_CurrentTimeStep; + unsigned int m_TotalTimeSteps; + +private: + hid_t m_FilePropertyListId; + hid_t m_FileId; + hid_t m_GroupId; +}; + +HDF5NativeReader::HDF5NativeReader(const std::string fileName) +: m_CurrentTimeStep(0), m_TotalTimeSteps(0) +{ + m_FilePropertyListId = H5Pcreate(H5P_FILE_ACCESS); + +#ifdef ADIOS2_HAVE_MPI + // read a file collectively + H5Pset_fapl_mpio(m_FilePropertyListId, MPI_COMM_WORLD, MPI_INFO_NULL); +#endif + + m_FileId = H5Fopen(fileName.c_str(), H5F_ACC_RDONLY, m_FilePropertyListId); + if (m_FileId < 0) + { + throw std::runtime_error("Unable to open " + fileName + " for reading"); + } + + std::string ts0 = "/TimeStep0"; + m_GroupId = H5Gopen(m_FileId, ts0.c_str(), H5P_DEFAULT); + if (m_GroupId < 0) + { + throw std::runtime_error("Unable to open group " + ts0 + + " for reading"); + } + + hid_t attrId = H5Aopen(m_FileId, "NumTimeSteps", H5P_DEFAULT); + if (attrId < 0) + { + throw std::runtime_error("Unable to open attribute NumTimeSteps"); + } + H5Aread(attrId, H5T_NATIVE_UINT, &m_TotalTimeSteps); + H5Aclose(attrId); +} + +HDF5NativeReader::~HDF5NativeReader() +{ + if (m_GroupId >= 0) + { + H5Gclose(m_GroupId); + } + + H5Fclose(m_FileId); + H5Pclose(m_FilePropertyListId); +} + +void HDF5NativeReader::GetVarInfo(const std::string varName, + std::vector<hsize_t> &dims, hid_t &h5Type) +{ + hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT); + if (dataSetId < 0) + { + throw std::runtime_error("Unable to open dataset " + varName); + } + + hid_t fileSpaceId = H5Dget_space(dataSetId); + if (fileSpaceId < 0) + { + throw std::runtime_error("Unable to get filespace for dataset " + + varName); + } + + const int ndims = H5Sget_simple_extent_ndims(fileSpaceId); + if (ndims < 0) + { + throw std::runtime_error( + "Unable to get number of dimensions for dataset " + varName); + } + + dims.resize(ndims); + if (H5Sget_simple_extent_dims(fileSpaceId, dims.data(), NULL) != ndims) + { + throw std::runtime_error("Unable to get dimensions for dataset " + + varName); + } + + h5Type = H5Dget_type(dataSetId); + + H5Sclose(fileSpaceId); + H5Dclose(dataSetId); +} + +bool HDF5NativeReader::Advance() +{ + if (m_GroupId >= 0) + { + H5Gclose(m_GroupId); + m_GroupId = -1; + } + + if (m_CurrentTimeStep + 1 >= m_TotalTimeSteps) + { + return false; + } + + std::string tsName = "/TimeStep" + std::to_string(m_CurrentTimeStep + 1); + m_GroupId = H5Gopen(m_FileId, tsName.c_str(), H5P_DEFAULT); + if (m_GroupId < 0) + { + throw std::runtime_error("Unable to open group " + tsName + + " for reading"); + } + ++m_CurrentTimeStep; + + return true; +} + +void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray) +{ + if (m_GroupId < 0) + { + throw std::runtime_error("Can't read variable " + varName + + " since a group is not currently open"); + } + + hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT); + if (dataSetId < 0) + { + throw std::runtime_error("Unable to open dataset " + varName); + } + + hid_t fileSpace = H5Dget_space(dataSetId); + if (fileSpace < 0) + { + throw std::runtime_error("Unable to get filespace for dataset " + + varName); + } + + hid_t h5type = H5Dget_type(dataSetId); + hid_t ret = + H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataArray); + + H5Sclose(fileSpace); + H5Dclose(dataSetId); +} + //****************************************************************************** // 1D 1x8 test data //****************************************************************************** @@ -34,8 +191,7 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8) // Write test data using ADIOS2 { - adios::ADIOS adios(adios::Verbose::WARN, true); - + adios::ADIOS adios(adios::Verbose::WARN, true); // moved up // Declare 1D variables { auto &var_i8 = adios.DefineVariable<char>("i8", adios::Dims{8}); @@ -96,10 +252,115 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8) engine->Close(); } - // Read test data using HDF5 +// Read test data using HDF5 +#ifdef ADIOS2_HAVE_MPI + // Read everything from rank 0 + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) +#endif { - ASSERT_TRUE(false) - << "Native HDF5 read validation is not yet implemented"; + std::array<char, 8> I8; + std::array<int16_t, 8> I16; + std::array<int32_t, 8> I32; + std::array<int64_t, 8> I64; + std::array<unsigned char, 8> U8; + std::array<uint16_t, 8> U16; + std::array<uint32_t, 8> U32; + std::array<uint64_t, 8> U64; + std::array<float, 8> R32; + std::array<double, 8> R64; + + HDF5NativeReader hdf5Reader(fname); + + // Read stuff + for (size_t t = 0; t < 3; ++t) + { + std::vector<hsize_t> gDims; + hid_t h5Type; + + hdf5Reader.GetVarInfo("i8", gDims, h5Type); + + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("i8", I8.data()); + + hdf5Reader.GetVarInfo("i16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("i16", I16.data()); + + hdf5Reader.GetVarInfo("i32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("i32", I32.data()); + + hdf5Reader.GetVarInfo("i64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("i64", I64.data()); + + hdf5Reader.GetVarInfo("u8", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("u8", U8.data()); + + hdf5Reader.GetVarInfo("u16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("u16", U16.data()); + + hdf5Reader.GetVarInfo("u32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("u32", U32.data()); + + hdf5Reader.GetVarInfo("u64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("u64", U64.data()); + + hdf5Reader.GetVarInfo("r32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("r32", R32.data()); + + hdf5Reader.GetVarInfo("r64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1); + ASSERT_EQ(gDims.size(), 1); + ASSERT_EQ(gDims[0], 8); + hdf5Reader.ReadVar("r64", R64.data()); + + // Check if it's correct + for (size_t i = 0; i < 8; ++i) + { + std::stringstream ss; + ss << "t=" << t << " i=" << i; + std::string msg = ss.str(); + + EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg; + EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg; + EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg; + EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg; + EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg; + EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg; + EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg; + EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg; + EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg; + EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg; + } + + hdf5Reader.Advance(); + } } } @@ -196,10 +457,123 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4) engine->Close(); } - // Read test data using HDF5 +// Read test data using HDF5 +#ifdef ADIOS2_HAVE_MPI + // Read everything from rank 0 + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) +#endif { - ASSERT_TRUE(false) - << "Native HDF5 read validation is not yet implemented"; + HDF5NativeReader hdf5Reader(fname); + + std::array<char, 8> I8; + std::array<int16_t, 8> I16; + std::array<int32_t, 8> I32; + std::array<int64_t, 8> I64; + std::array<unsigned char, 8> U8; + std::array<uint16_t, 8> U16; + std::array<uint32_t, 8> U32; + std::array<uint64_t, 8> U64; + std::array<float, 8> R32; + std::array<double, 8> R64; + + // Read stuff + for (size_t t = 0; t < 3; ++t) + { + std::vector<hsize_t> gDims; + hid_t h5Type; + + hdf5Reader.GetVarInfo("i8", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("i8", I8.data()); + + hdf5Reader.GetVarInfo("i16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("i16", I16.data()); + + hdf5Reader.GetVarInfo("i32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("i32", I32.data()); + + hdf5Reader.GetVarInfo("i64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("i64", I64.data()); + + hdf5Reader.GetVarInfo("u8", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("u8", U8.data()); + + hdf5Reader.GetVarInfo("u16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("u16", U16.data()); + + hdf5Reader.GetVarInfo("u32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("u32", U32.data()); + + hdf5Reader.GetVarInfo("u64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("u64", U64.data()); + + hdf5Reader.GetVarInfo("r32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("r32", R32.data()); + + hdf5Reader.GetVarInfo("r64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 2); + ASSERT_EQ(gDims[1], 4); + hdf5Reader.ReadVar("r64", R64.data()); + + // Check if it's correct + for (size_t i = 0; i < 8; ++i) + { + std::stringstream ss; + ss << "t=" << t << " i=" << i; + std::string msg = ss.str(); + + EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg; + EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg; + EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg; + EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg; + EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg; + EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg; + EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg; + EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg; + EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg; + EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg; + } + hdf5Reader.Advance(); + } } } @@ -296,10 +670,123 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2) engine->Close(); } - // Read test data using HDF5 +// Read test data using HDF5 +#ifdef ADIOS2_HAVE_MPI + // Read everything from rank 0 + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) +#endif { - ASSERT_TRUE(false) - << "Native HDF5 read validation is not yet implemented"; + + HDF5NativeReader hdf5Reader(fname); + + std::array<char, 8> I8; + std::array<int16_t, 8> I16; + std::array<int32_t, 8> I32; + std::array<int64_t, 8> I64; + std::array<unsigned char, 8> U8; + std::array<uint16_t, 8> U16; + std::array<uint32_t, 8> U32; + std::array<uint64_t, 8> U64; + std::array<float, 8> R32; + std::array<double, 8> R64; + + // Read stuff + for (size_t t = 0; t < 3; ++t) + { + std::vector<hsize_t> gDims; + hid_t h5Type; + + hdf5Reader.GetVarInfo("i8", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_CHAR), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("i8", I8.data()); + + hdf5Reader.GetVarInfo("i16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_SHORT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("i16", I16.data()); + + hdf5Reader.GetVarInfo("i32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_INT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("i32", I32.data()); + + hdf5Reader.GetVarInfo("i64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_LONG), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("i64", I64.data()); + + hdf5Reader.GetVarInfo("u8", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UCHAR), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("u8", U8.data()); + + hdf5Reader.GetVarInfo("u16", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_USHORT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("u16", U16.data()); + + hdf5Reader.GetVarInfo("u32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_UINT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("u32", U32.data()); + + hdf5Reader.GetVarInfo("u64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_ULONG), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("u64", U64.data()); + + hdf5Reader.GetVarInfo("r32", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_FLOAT), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("r32", R32.data()); + + hdf5Reader.GetVarInfo("r64", gDims, h5Type); + ASSERT_EQ(H5Tequal(h5Type, H5T_NATIVE_DOUBLE), 1); + ASSERT_EQ(gDims.size(), 2); + ASSERT_EQ(gDims[0], 4); + ASSERT_EQ(gDims[1], 2); + hdf5Reader.ReadVar("r64", R64.data()); + + for (size_t i = 0; i < 8; ++i) + { + std::stringstream ss; + ss << "t=" << t << " i=" << i; + std::string msg = ss.str(); + + EXPECT_EQ(I8[i], m_TestData.I8[i + t]) << msg; + EXPECT_EQ(I16[i], m_TestData.I16[i + t]) << msg; + EXPECT_EQ(I32[i], m_TestData.I32[i + t]) << msg; + EXPECT_EQ(I64[i], m_TestData.I64[i + t]) << msg; + EXPECT_EQ(U8[i], m_TestData.U8[i + t]) << msg; + EXPECT_EQ(U16[i], m_TestData.U16[i + t]) << msg; + EXPECT_EQ(U32[i], m_TestData.U32[i + t]) << msg; + EXPECT_EQ(U64[i], m_TestData.U64[i + t]) << msg; + EXPECT_EQ(R32[i], m_TestData.R32[i + t]) << msg; + EXPECT_EQ(R64[i], m_TestData.R64[i + t]) << msg; + } + hdf5Reader.Advance(); + } } }