diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..8d61025ec0377f930f400895d15feecdeea84231 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,37 @@ +defaults: &defaults + working_directory: /home/adios2 + steps: + - checkout: + path: /home/adios2/source + - run: + name: Update + command: bash source/scripts/circle/runOnCircle.sh update + - run: + name: Configure + command: bash source/scripts/circle/runOnCircle.sh configure + - run: + name: Build + command: bash source/scripts/circle/runOnCircle.sh build + - run: + name: Test + command: bash source/scripts/circle/runOnCircle.sh test + +version: 2 + +jobs: + "el7-gcc48": + <<: *defaults + docker: + - image: ornladios/adios2:el7-ohpc + + "el7-gcc7-openmpi": + <<: *defaults + docker: + - image: ornladios/adios2:el7-ohpc + +workflows: + version: 2 + build: + jobs: + - "el7-gcc48" + - "el7-gcc7-openmpi" diff --git a/.gitignore b/.gitignore index 04e38af8eabeb74636565371d2f097b1143b8827..e8f3faf4a79b32344df3ad93783d6da29a36cd74 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ *.bp.dir build/ +# Mac OSX finder-related files +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index e31f749bf9acf63d09836b41d882dec7323219db..cdafaba1843dbc5b579a49fd179fde211400f17f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ # accompanying file Copyright.txt for details. #------------------------------------------------------------------------------# -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.6) # Fail immediately if not using an out-of-source build if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) @@ -45,7 +45,7 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) include(ADIOSFunctions) # Default to a debug build if not specified -if(NOT CMAKE_BUILD_TYPE) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE) endif() @@ -59,18 +59,10 @@ include(CMakeDependentOption) # to that. Otherwise base the default on whether or not shared libs are even # supported. get_property(SHARED_LIBS_SUPPORTED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) -if(DEFINED ADIOS2_BUILD_SHARED_LIBS) - set(ADIOS2_BUILD_SHARED_LIBS_DEFAULT ${ADIOS2_BUILD_SHARED_LIBS}) -elseif(DEFINED BUILD_SHARED_LIBS) - set(ADIOS2_BUILD_SHARED_LIBS_DEFAULT ${BUILD_SHARED_LIBS}) -else() - set(ADIOS2_BUILD_SHARED_LIBS_DEFAULT ${SHARED_LIBS_SUPPORTED}) -endif() -cmake_dependent_option(ADIOS2_BUILD_SHARED_LIBS - "Build shared libraries (so/dylib/dll)." ${ADIOS2_BUILD_SHARED_LIBS_DEFAULT} +cmake_dependent_option(BUILD_SHARED_LIBS + "Build shared libraries (so/dylib/dll)." ${SHARED_LIBS_SUPPORTED} "SHARED_LIBS_SUPPORTED" OFF ) -set(BUILD_SHARED_LIBS ${ADIOS2_BUILD_SHARED_LIBS}) mark_as_advanced(BUILD_SHARED_LIBS) # Setup PIC defaults. If explicitly specified somehow, then default @@ -98,15 +90,18 @@ adios_option(ZeroMQ "Enable support for ZeroMQ" AUTO) adios_option(HDF5 "Enable support for the HDF5 engine" AUTO) adios_option(ADIOS1 "Enable support for the ADIOS 1.x engine" AUTO) adios_option(Python "Enable support for Python bindings" AUTO) +adios_option(Fortran "Enable support for Fortran bindings" OFF) adios_option(SysVShMem "Enable support for SysV Shared Memory IPC on *NIX" AUTO) include(${ADIOS2_SOURCE_DIR}/cmake/DetectOptions.cmake) if(ADIOS2_HAVE_MPI) - # Workaround for OpenMPI forcing the link of C++ bindings - add_definitions(-DOMPI_SKIP_MPICXX) + # Workaround for MPI forcing the link of C++ bindings + add_definitions(-DOMPI_SKIP_MPICXX -DMPICH_SKIP_MPICXX) endif() -GenerateADIOSHeaderConfig(MPI ZFP BZip2 ADIOS1 HDF5 ZeroMQ DataMan Python SysVShMem) +GenerateADIOSHeaderConfig(MPI ZFP BZip2 ADIOS1 HDF5 DataMan Python Fortran + SysVShMem) + install(FILES ${ADIOS2_BINARY_DIR}/source/adios2/ADIOSConfig.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2 ) @@ -146,7 +141,9 @@ else() set(ADIOS2_BUILD_TESTING_DEFAULT ON) endif() unset(BUILD_TESTING) -option(ADIOS2_BUILD_TESTING "Build the ADIOS2 testing tree" ${ADIOS2_BUILD_TESTING_DEFAULT}) +option(ADIOS2_BUILD_TESTING "Build the ADIOS2 testing tree" + ${ADIOS2_BUILD_TESTING_DEFAULT}) + include(CTest) set(BUILD_TESTING ${ADIOS2_BUILD_TESTING}) if(BUILD_TESTING) @@ -165,9 +162,18 @@ GenerateADIOSPackageConfig() message("") message("ADIOS2 build configuration:") message(" ADIOS Version: ${ADIOS2_VERSION}") -message(" C++ Compiler : ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} ${CMAKE_CXX_COMPILER_WRAPPER}") +message(" C++ Compiler : ${CMAKE_CXX_COMPILER_ID} " + "${CMAKE_CXX_COMPILER_VERSION} " + "${CMAKE_CXX_COMPILER_WRAPPER}") message(" ${CMAKE_CXX_COMPILER}") message("") +if(ADIOS2_HAVE_Fortran) + message(" Fortran Compiler : ${CMAKE_Fortran_COMPILER_ID} " + "${CMAKE_Fortran_COMPILER_VERSION} " + "${CMAKE_Fortran_COMPILER_WRAPPER}") + message(" ${CMAKE_Fortran_COMPILER}") + message("") +endif() message(" Installation prefix: ${CMAKE_INSTALL_PREFIX}") message(" Features:") if(BUILD_SHARED_LIBS) @@ -181,7 +187,8 @@ message(" Library Type: ${msg_lib_type}") message(" Build Type: ${CMAKE_BUILD_TYPE}") message(" Testing: ${BUILD_TESTING}") message(" Build Options:") -foreach(opt BZip2 ZFP MPI DataMan ZeroMQ HDF5 ADIOS1 Python SysVShMem) + +foreach(opt BZip2 ZFP MPI DataMan ZeroMQ HDF5 ADIOS1 Python Fortran SysVShMem) message_pad(" ${opt}" 15 label) if(${ADIOS2_HAVE_${opt}}) message("${label}: ON") diff --git a/ReadMe.md b/ReadMe.md index 5781eadd310df4f8f6353f80db73d892b61fdf46..1f8e52fbdf3c82e261c079d85092c382fdc84964 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,3 +1,11 @@ +[]() +[](./LICENSE) + + +[](https://circleci.com/gh/ornladios/ADIOS2) +[](https://travis-ci.org/ornladios/ADIOS2) +[](https://ci.appveyor.com/project/ornladios/adios2) + # Adaptable Input / Output System (ADIOS) v2.0 This is v2.0 of the ADIOS I/O system, developed as part of the U.S. Department of Energy Exascale Computing Program. @@ -72,6 +80,7 @@ ADIOS2 build configuration: HDF5 : ON ADIOS1 : OFF Python : ON + C : ON SysVShMem: ON -- Configuring done @@ -92,6 +101,7 @@ The following options can be specified with CMake's `-DVAR=VALUE` syntax to cont | `ADIOS2_USE_HDF5` | **`AUTO`**/``ON``/``OFF`` | Enable the [HDF5](https://www.hdfgroup.org) engine. | | `ADIOS2_USE_ADIOS1` | **`AUTO`**/``ON``/``OFF`` | Enable the [ADIOS 1.x](https://www.olcf.ornl.gov/center-projects/adios/) engine. | | `ADIOS2_USE_Python` | **`AUTO`**/``ON``/``OFF`` | Enable the Python >= 2.7 bindings. | +| `ADIOS2_USE_C` | **`AUTO`**/``ON``/``OFF`` | Enable the C bindings library libadios2_c.so or libadios2_c.a | Note: The `ADIOS2_USE_HDF5` and `ADIOS2_USE_ADIOS1` options require the use of a matching serial or parallel version depending on whether `ADIOS2_USE_MPI` is enabled. SImilary, enabling MPI and Python bindings requires the presence of `mpi4py`. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000000000000000000000000000000000..d0e4f72b4ca1a344af41f9d535fc7fc38a812ff5 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,48 @@ +version: 1.0.{build} + +skip_branch_with_pr: true + +os: + - Visual Studio 2015 + - Visual Studio 2017 + +platform: + - x86 + +# install: +# ### Having trouble with enabling python on windows +# - set PATH=C:\Python27-x64;C:\Python27-x64\Scripts;%PATH% +# - "python.exe -m pip install numpy" + +# init: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + +before_build: +- del /q /f "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" +- cd C:\projects\adios2 +- git reset --hard %APPVEYOR_PULL_REQUEST_HEAD_COMMIT% +- ps: | + $env:CUSTOM_BUILD_NAME = ("{0}_{1}_vs{2}" -f $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH, $env:APPVEYOR_BUILD_NUMBER, $env:APPVEYOR_BUILD_WORKER_IMAGE.split()[2] ) +- ctest.exe -VV -S ../adios2/scripts\appveyor\av_default.cmake + -Ddashboard_full=OFF + -Ddashboard_do_update=true + -DCTEST_BUILD_NAME=%CUSTOM_BUILD_NAME% + +build_script: +- ctest.exe -VV -S ../adios2/scripts\appveyor\av_default.cmake + -Ddashboard_full=OFF + -Ddashboard_do_configure=true + -DCTEST_BUILD_NAME=%CUSTOM_BUILD_NAME% +- ctest.exe -VV -S ../adios2/scripts\appveyor\av_default.cmake + -Ddashboard_full=OFF + -Ddashboard_do_build=true + -DCTEST_BUILD_NAME=%CUSTOM_BUILD_NAME% + +test_script: +- ctest.exe -VV -S ../adios2/scripts\appveyor\av_default.cmake + -Ddashboard_full=OFF + -Ddashboard_do_test=true + -DCTEST_BUILD_NAME=%CUSTOM_BUILD_NAME% + +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/bindings/C/CMakeLists.txt b/bindings/C/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ba156809ce432785faa84567fa3b646f1c399fe --- /dev/null +++ b/bindings/C/CMakeLists.txt @@ -0,0 +1,20 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + + +target_sources(adios2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/adios2_c.cpp) +target_include_directories(adios2 + PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> +) + +install( + FILES adios2_c.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +install( + FILES adios2/adios2_c_enums.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2 +) diff --git a/bindings/C/adios2/adios2_c_enums.h b/bindings/C/adios2/adios2_c_enums.h new file mode 100644 index 0000000000000000000000000000000000000000..3ea471ee62f4013d8ef8702c6d44083d8737a2c2 --- /dev/null +++ b/bindings/C/adios2/adios2_c_enums.h @@ -0,0 +1,74 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_c_enums.h + * + * Created on: Aug 7, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_BINDINGS_C_ADIOS2_C_ENUMS_H_ +#define ADIOS2_BINDINGS_C_ADIOS2_C_ENUMS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + adios2_debug_mode_on = 0, + adios2_debug_mode_off = 1, +} adios2_debug_mode; + +typedef enum { + adios2_constant_dims_true = 0, + adios2_constant_dims_false = 1, +} adios2_constant_dims; + +typedef enum { + + adios2_type_char = 0, + adios2_type_int = 1, + adios2_type_float = 2, + adios2_type_double = 3, + adios2_type_float_complex = 4, + adios2_type_double_complex = 5, + + adios2_type_int8_t = 6, + adios2_type_int16_t = 7, + adios2_type_int32_t = 8, + adios2_type_int64_t = 9, + + adios2_type_string, + adios2_type_signed_char, + + adios2_type_short, + + adios2_type_long_int, + adios2_type_long_long_int, + + adios2_type_unsigned_char, + adios2_type_unsigned_short, + adios2_type_unsigned_int, + adios2_type_unsigned_long_int, + adios2_type_unsigned_long_long_int, + + adios2_type_uint8_t, + adios2_type_uint16_t, + adios2_type_uint32_t, + adios2_type_uint64_t +} adios2_type; + +typedef enum { + adios2_open_mode_undefined, + adios2_open_mode_write, + adios2_open_mode_read, + adios2_open_mode_append, + adios2_open_mode_read_write +} adios2_open_mode; + +#ifdef __cplusplus +} // end extern C +#endif + +#endif /* ADIOS2_BINDINGS_C_ADIOS2_C_ENUMS_H_ */ diff --git a/bindings/C/adios2_c.cpp b/bindings/C/adios2_c.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb13516feffa1031645f1e229dfe2723581295a3 --- /dev/null +++ b/bindings/C/adios2_c.cpp @@ -0,0 +1,338 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_c.h : ADIOS2 C bindings definitions + * + * Created on: Mar 13, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include "adios2_c.h" + +#include <string> +#include <vector> + +#include <adios2.h> +#include <adios2/ADIOSMPI.h> + +adios2_ADIOS *adios2_init_config(const char *config_file, MPI_Comm mpi_comm, + const adios2_debug_mode debug_mode) +{ + const bool debugBool = (debug_mode == adios2_debug_mode_on) ? true : false; + adios2_ADIOS *adios = reinterpret_cast<adios2_ADIOS *>( + new adios2::ADIOS(config_file, mpi_comm, debugBool)); + + return adios; +} + +adios2_ADIOS *adios2_init(MPI_Comm mpi_comm, const adios2_debug_mode debug_mode) +{ + return adios2_init_config("", mpi_comm, debug_mode); +} + +adios2_ADIOS *adios2_init_config_nompi(const char *config_file, + const adios2_debug_mode debug_mode) +{ + return adios2_init_config(config_file, MPI_COMM_SELF, debug_mode); +} + +adios2_ADIOS *adios2_init_nompi(const adios2_debug_mode debug_mode) +{ + return adios2_init_config("", MPI_COMM_SELF, debug_mode); +} + +adios2_IO *adios2_declare_io(adios2_ADIOS *adios, const char *ioName) +{ + adios2_IO *io = reinterpret_cast<adios2_IO *>( + &reinterpret_cast<adios2::ADIOS *>(adios)->DeclareIO(ioName)); + return io; +} + +adios2_Variable * +adios2_define_variable(adios2_IO *io, const char *name, const adios2_type type, + const size_t ndims, const size_t *shape, + const size_t *start, const size_t *count, + const adios2_constant_dims constant_dims) +{ + const bool constantSizeBool = + (constant_dims == adios2_constant_dims_true) ? true : false; + + std::vector<size_t> shapeV, startV, countV; + + if (shape != NULL) + { + shapeV.assign(shape, shape + ndims); + } + + if (start != NULL) + { + startV.assign(start, start + ndims); + } + + if (count != NULL) + { + countV.assign(count, count + ndims); + } + + adios2::IO &ioCpp = *reinterpret_cast<adios2::IO *>(io); + adios2::VariableBase *variable = nullptr; + + switch (type) + { + case (adios2_type_string):; + break; + + case (adios2_type_char): + variable = + dynamic_cast<adios2::Variable<char> *>(&ioCpp.DefineVariable<char>( + name, shapeV, startV, countV, constantSizeBool)); + break; + + case (adios2_type_signed_char): + variable = dynamic_cast<adios2::Variable<signed char> *>( + &ioCpp.DefineVariable<char>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_short): + variable = dynamic_cast<adios2::Variable<short> *>( + &ioCpp.DefineVariable<short>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_int): + variable = + dynamic_cast<adios2::Variable<int> *>(&ioCpp.DefineVariable<int>( + name, shapeV, startV, countV, constantSizeBool)); + break; + + case (adios2_type_long_int): + variable = dynamic_cast<adios2::Variable<long int> *>( + &ioCpp.DefineVariable<long int>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_long_long_int): + variable = dynamic_cast<adios2::Variable<long long int> *>( + &ioCpp.DefineVariable<long long int>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_unsigned_char): + variable = dynamic_cast<adios2::Variable<unsigned char> *>( + &ioCpp.DefineVariable<unsigned char>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_unsigned_short): + variable = dynamic_cast<adios2::Variable<unsigned short> *>( + &ioCpp.DefineVariable<unsigned short>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_unsigned_int): + variable = dynamic_cast<adios2::Variable<unsigned int> *>( + &ioCpp.DefineVariable<unsigned int>(name, shapeV, startV, countV, + constantSizeBool)); + break; + case (adios2_type_unsigned_long_int): + variable = dynamic_cast<adios2::Variable<unsigned long int> *>( + &ioCpp.DefineVariable<unsigned long int>(name, shapeV, startV, + countV, constantSizeBool)); + break; + + case (adios2_type_unsigned_long_long_int): + variable = dynamic_cast<adios2::Variable<unsigned long long int> *>( + &ioCpp.DefineVariable<unsigned long long int>( + name, shapeV, startV, countV, constantSizeBool)); + break; + + case (adios2_type_float): + variable = dynamic_cast<adios2::Variable<float> *>( + &ioCpp.DefineVariable<float>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_double): + variable = dynamic_cast<adios2::Variable<double> *>( + &ioCpp.DefineVariable<double>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_float_complex): + variable = dynamic_cast<adios2::Variable<std::complex<float>> *>( + &ioCpp.DefineVariable<std::complex<float>>( + name, shapeV, startV, countV, constantSizeBool)); + break; + + case (adios2_type_double_complex): + variable = dynamic_cast<adios2::Variable<std::complex<double>> *>( + &ioCpp.DefineVariable<std::complex<double>>( + name, shapeV, startV, countV, constantSizeBool)); + break; + + case (adios2_type_int8_t): + + variable = dynamic_cast<adios2::Variable<int8_t> *>( + &ioCpp.DefineVariable<int8_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_int16_t): + variable = dynamic_cast<adios2::Variable<int16_t> *>( + &ioCpp.DefineVariable<int16_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_int32_t): + variable = dynamic_cast<adios2::Variable<int32_t> *>( + &ioCpp.DefineVariable<int32_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_int64_t): + variable = dynamic_cast<adios2::Variable<int64_t> *>( + &ioCpp.DefineVariable<int64_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_uint8_t): + + variable = dynamic_cast<adios2::Variable<uint8_t> *>( + &ioCpp.DefineVariable<uint8_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_uint16_t): + variable = dynamic_cast<adios2::Variable<uint16_t> *>( + &ioCpp.DefineVariable<uint16_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_uint32_t): + variable = dynamic_cast<adios2::Variable<uint32_t> *>( + &ioCpp.DefineVariable<uint32_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + + case (adios2_type_uint64_t): + variable = dynamic_cast<adios2::Variable<uint64_t> *>( + &ioCpp.DefineVariable<uint64_t>(name, shapeV, startV, countV, + constantSizeBool)); + break; + } + + return reinterpret_cast<adios2_Variable *>(variable); +} + +adios2_Variable *adios2_get_variable(adios2_IO *io, const char *name) +{ + adios2::VariableBase *variable = + reinterpret_cast<adios2::IO *>(io)->GetVariableBase(name); + + return reinterpret_cast<adios2_Variable *>(variable); +} + +void adios2_set_engine(adios2_IO *io, const char *engine_type) +{ + reinterpret_cast<adios2::IO *>(io)->SetEngine(engine_type); +} + +void adios2_set_param(adios2_IO *io, const char *key, const char *value) +{ + reinterpret_cast<adios2::IO *>(io)->SetSingleParameter(key, value); +} + +unsigned int adios2_add_transport(adios2_IO *io, const char *transport_type) +{ + return reinterpret_cast<adios2::IO *>(io)->AddTransport(transport_type); +} + +void adios2_set_transport_param(adios2_IO *io, + const unsigned int transport_index, + const char *key, const char *value) +{ + reinterpret_cast<adios2::IO *>(io)->SetTransportSingleParameter( + transport_index, key, value); +} + +struct adios2_Engine +{ + std::shared_ptr<adios2::Engine> EngineCpp; +}; + +adios2_Engine *adios2_open(adios2_IO *io, const char *name, + const adios2_open_mode open_mode) +{ + auto &ioCpp = *reinterpret_cast<adios2::IO *>(io); + return adios2_open_new_comm(io, name, open_mode, ioCpp.m_MPIComm); +} + +adios2_Engine *adios2_open_new_comm(adios2_IO *io, const char *name, + const adios2_open_mode open_mode, + MPI_Comm mpi_comm) +{ + auto &ioCpp = *reinterpret_cast<adios2::IO *>(io); + adios2_Engine *engine = new adios2_Engine; + + switch (open_mode) + { + + case adios2_open_mode_write: + engine->EngineCpp = ioCpp.Open(name, adios2::OpenMode::Write, mpi_comm); + break; + + case adios2_open_mode_read: + engine->EngineCpp = ioCpp.Open(name, adios2::OpenMode::Read, mpi_comm); + break; + + case adios2_open_mode_append: + engine->EngineCpp = + ioCpp.Open(name, adios2::OpenMode::Append, mpi_comm); + break; + + case adios2_open_mode_read_write: + engine->EngineCpp = + ioCpp.Open(name, adios2::OpenMode::ReadWrite, mpi_comm); + break; + + case adios2_open_mode_undefined: + + break; + } + + return engine; +} + +void adios2_write(adios2_Engine *engine, adios2_Variable *variable, + const void *values) +{ + auto &variableBase = *reinterpret_cast<adios2::VariableBase *>(variable); + adios2_write_by_name(engine, variableBase.m_Name.c_str(), values); +} + +void adios2_write_by_name(adios2_Engine *engine, const char *variable_name, + const void *values) +{ + engine->EngineCpp->Write(variable_name, values); +} + +void adios2_advance(adios2_Engine *engine) { engine->EngineCpp->Advance(); } + +void adios2_close(adios2_Engine *engine) +{ + engine->EngineCpp->Close(); + delete engine; +} + +void adios2_close_by_index(adios2_Engine *engine, + const unsigned int transport_index) +{ + engine->EngineCpp->Close(transport_index); +} + +void adios2_finalize(adios2_ADIOS *adios) +{ + delete reinterpret_cast<adios2::ADIOS *>(adios); +} diff --git a/bindings/C/adios2_c.h b/bindings/C/adios2_c.h new file mode 100644 index 0000000000000000000000000000000000000000..99a69112a673dd83bb79e64837dc507ebb96efce --- /dev/null +++ b/bindings/C/adios2_c.h @@ -0,0 +1,215 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_c.h : ADIOS2 C bindings declarations + * + * Created on: Mar 13, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_BINDINGS_C_ADIOS2_C_H_ +#define ADIOS2_BINDINGS_C_ADIOS2_C_H_ + +#include <stddef.h> //size_t + +#include "adios2/ADIOSConfig.h" +#include "adios2/ADIOSMPICommOnly.h" +#include "adios2/adios2_c_enums.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct adios2_ADIOS adios2_ADIOS; +typedef struct adios2_IO adios2_IO; +typedef struct adios2_Variable adios2_Variable; +typedef struct adios2_Engine adios2_Engine; + +/** + * Create an ADIOS struct pointer handler using a runtime config file in MPI + * application. + * @param config_file runtime configuration file, XML format, future: JSON + * @param mpi_comm MPI communicator from application for ADIOS scope + * @param debug_mode adios2_debug_mode_on or adios2_debug_mode_off + * @return valid ADIOS* handler + */ +adios2_ADIOS *adios2_init_config(const char *config_file, MPI_Comm mpi_comm, + const adios2_debug_mode debug_mode); + +/** + * Create an ADIOS struct pointer in MPI application. + * @param mpi_comm MPI communicator from application for ADIOS scope + * @param debug_mode adios2_debug_mode_on or adios2_debug_mode_off + * @return valid ADIOS* handler + */ +adios2_ADIOS *adios2_init(MPI_Comm mpi_comm, + const adios2_debug_mode debug_mode); + +/** + * Create an ADIOS struct pointer handler using a runtime config file in serial + * nonMPI + * application. + * @param config_file runtime configuration file, XML format, future: JSON + * @param debug_mode adios2_debug_mode_on or adios2_debug_mode_off + * @return valid ADIOS* handler + */ +adios2_ADIOS *adios2_init_config_nompi(const char *config_file, + const adios2_debug_mode debug_mode); + +/** + * Create an ADIOS struct pointer handler in serial nonMPI application. + * @param debug_mode adios2_debug_mode_on or adios2_debug_mode_off + * @return valid ADIOS* handler + */ +adios2_ADIOS *adios2_init_nompi(const adios2_debug_mode debug_mode); + +/** + * Create an IO struct pointer handler from ADIOS* handler + * @param adios ADIOS* handler that owns the IO* handler + * @param io_name unique name for the newly declared io handler + * @return valid IO* handler + */ +adios2_IO *adios2_declare_io(adios2_ADIOS *adios, const char *io_name); + +/** + * Sets engine type for current io handler + * @param io handler + * @param engine_type available engine type + */ +void adios2_set_engine(adios2_IO *io, const char *engine_type); + +/** + * Set a single engine parameter + * @param io handler + * @param key parameter key + * @param value parameter value + */ +void adios2_set_param(adios2_IO *io, const char *key, const char *value); + +/** + * Set a transport for the present io + * @param io handler + * @param transport_type "File", "WAN" + * @return transport_index handler used for setting transport parameters or at + * Close + */ +unsigned int adios2_add_transport(adios2_IO *io, const char *transport_type); + +/** + * Sets a single transport parameter using io and transport_index (from + * adios2_add_transport) handlers + * @param io handler + * @param transport_index handler from adios2_add_transport + * @param key parameter key + * @param value parameter value + */ +void adios2_set_transport_param(adios2_IO *io, + const unsigned int transport_index, + const char *key, const char *value); + +/** + * + * @param io handler that owns the variable + * @param name unique variable name inside IO handler + * @param type primitive type + * @param ndims number of dimensions + * @param shape total MPI dimensions + * @param start local MPI start (offset) + * @param count local MPI count + * @param constant_size adios2_constant_dims_true: shape, start and count are + * constant, or + * adios2_constant_size_false + * @return variable handler + */ +adios2_Variable * +adios2_define_variable(adios2_IO *io, const char *name, const adios2_type type, + const size_t ndims, const size_t *shape, + const size_t *start, const size_t *count, + const adios2_constant_dims constant_dims); + +/** + * Returns a handler to a previously defined variable identified by a unique + * name + * @param io handler to variable io owner + * @param name unique name input + * @return variable handler if found + */ +adios2_Variable *adios2_get_variable(adios2_IO *io, const char *name); + +/** + * Create an adios2_Engine, from adios2_IO, that executes all IO operations. + * Resuse MPI_Comm passed to adios2_ADIOS that created adios2_IO io + * @param io input that creates the adios2_Engine + * @param name engine name + * @param open_mode read, write, append use adios2_open_mode enum + * @return engine handler + */ +adios2_Engine *adios2_open(adios2_IO *io, const char *name, + const adios2_open_mode open_mode); + +/** + * Create an adios2_Engine, from adios2_IO, that executes all IO operations. + * Allows passing a new communicator. + * @param io input that creates the adios2_Engine + * @param name engine name + * @param open_mode read, write, append use adios2_open_mode enum + * @param mpi_comm allows passing a new MPI communicator + * @return engine handler + */ +adios2_Engine *adios2_open_new_comm(adios2_IO *io, const char *name, + const adios2_open_mode open_mode, + MPI_Comm mpi_comm); + +/** + * Write a variable using a adios2_Variable handler + * @param engine handler for engine executing the write + * @param variable handler for variable from adios2_define_variable + * @param values application data to be written for this variable + */ +void adios2_write(adios2_Engine *engine, adios2_Variable *variable, + const void *values); + +/** + * Write a variable using a variable name created from adios2_define_variable + * @param engine handler for engine executing the write + * @param variable_name unique variable name, within io that create the engine. + * @param values application data to be written for this variable + */ +void adios2_write_by_name(adios2_Engine *engine, const char *variable_name, + const void *values); + +/** + * Advance time step for writes + * @param engine handler executing IO tasks + */ +void adios2_advance(adios2_Engine *engine); + +/** + * Close all transports in adios2_Engine + * @param engine handler containing all transports to + * be closed. engine Becomes NULL after this function is called. + */ +void adios2_close(adios2_Engine *engine); + +/** + * Close a particular transport from the index returned by adios2_add_transport + * @param engine handler containing all transports to + * be closed. NOTE: engine NEVER becomes NULL due to this function. + * @param transport_index handler from adios2_add_transport + */ +void adios2_close_by_index(adios2_Engine *engine, + const unsigned int transport_index); + +/** + * Final point for adios2_ADIOS handler. + * Deallocate adios pointer. Required to avoid memory leaks. + * @param adios input to be deallocated + */ +void adios2_finalize(adios2_ADIOS *adios); + +#ifdef __cplusplus +} // end extern C +#endif + +#endif /* ADIOS2_BINDINGS_C_ADIOS2_C_H_ */ diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index c21b8b329a9fe124899f3629e3a76f423ef66338..c775e4e0c05eb384a7cb9393f1aa6e442ab3e7a6 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,3 +1,14 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + if(ADIOS2_HAVE_Python) add_subdirectory(python) endif() + +if(ADIOS2_HAVE_Fortran) + add_subdirectory(fortran) +endif() + +add_subdirectory(C) diff --git a/bindings/fortran/CMakeLists.txt b/bindings/fortran/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..89b2de128408772b3f1b9f48ebd680da6db64362 --- /dev/null +++ b/bindings/fortran/CMakeLists.txt @@ -0,0 +1,39 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +add_library(adios2_f adios2_mod.f90 adios2_params_mod.f90 adios2_adios_mod.f90 + adios2_io_mod.f90 adios2_engine_mod.f90 + adios2_engine_write_mod.f90 adios2_functions_mod.f90 + adios2_f2c.cpp) + +if(ADIOS2_HAVE_MPI) + target_sources(adios2_f PRIVATE mpi/adios2_adios_init_mod.f90 + mpi/adios2_io_open_mod.f90) +else() + target_sources(adios2_f PRIVATE nompi/adios2_adios_init_nompi_mod.f90 + nompi/adios2_io_open_nompi_mod.f90 ) +endif() + +target_link_libraries(adios2_f PRIVATE adios2) + + +if(ADIOS2_HAVE_MPI) + target_compile_definitions(adios2_f PUBLIC ADIOS2_HAVE_MPI_F) + target_include_directories(adios2_f PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${MPI_C_INCLUDE_PATH} + ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(adios2_f PRIVATE ${MPI_C_LIBRARIES} + ${MPI_Fortran_LIBRARIES}) +else() + target_include_directories(adios2_f PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) +endif() + +install( + TARGETS ${adios2_f} EXPORT adios2 + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/bindings/fortran/adios2_adios_mod.f90 b/bindings/fortran/adios2_adios_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..296de00840a42cffa173dce4fd7f7cb1df4f679c --- /dev/null +++ b/bindings/fortran/adios2_adios_mod.f90 @@ -0,0 +1,29 @@ + +module adios2_adios + + use adios2_adios_init + implicit none + +contains + + subroutine adios2_declare_io(io, adios, io_name, ierr) + integer(kind=8), intent(out) :: io + integer(kind=8), intent(in) :: adios + character*(*), intent(in) :: io_name + integer, intent(out) :: ierr + + call adios2_declare_io_f2c(io, adios, TRIM(ADJUSTL(io_name))//char(0), & + & ierr) + + end + + + subroutine adios2_finalize(adios, ierr) + integer(kind=8), intent(in) :: adios + integer, intent(out) :: ierr + + call adios2_finalize_f2c(adios, ierr) + end + + +end module diff --git a/bindings/fortran/adios2_engine_mod.f90 b/bindings/fortran/adios2_engine_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..71f972698ad16d25c048ffb98cbc4e0815ff40ac --- /dev/null +++ b/bindings/fortran/adios2_engine_mod.f90 @@ -0,0 +1,33 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_engine_mod.f90 : ADIOS2 Fortran bindings for Engine class +! +! Created on: Aug 22, 2017 +! Author: William F Godoy godoywf@ornl.gov +! +module adios2_engine + use adios2_engine_write + implicit none + +contains + + subroutine adios2_advance(engine, ierr) + integer(kind=8), intent(in) :: engine + integer, intent(out) :: ierr + + call adios2_advance_f2c(engine, ierr) + + end subroutine + + + subroutine adios2_close(engine, ierr) + integer(kind=8), intent(in) :: engine + integer, intent(out) :: ierr + + call adios2_close_f2c(engine, ierr) + + end subroutine + +end module diff --git a/bindings/fortran/adios2_engine_write_mod.f90 b/bindings/fortran/adios2_engine_write_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..735c83da309cd0407a3911e13d95b3ecd32f4844 --- /dev/null +++ b/bindings/fortran/adios2_engine_write_mod.f90 @@ -0,0 +1,660 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_engine_write_mod.f90 : ADIOS2 Fortran bindings for Engine generic +! Write functions +! +! Created on: Aug 22, 2017 +! Author: William F Godoy godoywf@ornl.gov +! +module adios2_engine_write + + interface adios2_write + + ! Single Value + module procedure adios2_write_integer + module procedure adios2_write_real + module procedure adios2_write_dp + module procedure adios2_write_complex + module procedure adios2_write_complex_dp + module procedure adios2_write_integer1 + module procedure adios2_write_integer2 + module procedure adios2_write_integer8 + + ! 1D Array + module procedure adios2_write_integer_1d + module procedure adios2_write_real_1d + module procedure adios2_write_dp_1d + module procedure adios2_write_complex_1d + module procedure adios2_write_complex_dp_1d + module procedure adios2_write_integer1_1d + module procedure adios2_write_integer2_1d + module procedure adios2_write_integer8_1d + + ! 2D Array + module procedure adios2_write_integer_2d + module procedure adios2_write_real_2d + module procedure adios2_write_dp_2d + module procedure adios2_write_complex_2d + module procedure adios2_write_complex_dp_2d + module procedure adios2_write_integer1_2d + module procedure adios2_write_integer2_2d + module procedure adios2_write_integer8_2d + + ! 3D Array + module procedure adios2_write_integer_3d + module procedure adios2_write_real_3d + module procedure adios2_write_dp_3d + module procedure adios2_write_complex_3d + module procedure adios2_write_complex_dp_3d + module procedure adios2_write_integer1_3d + module procedure adios2_write_integer2_3d + module procedure adios2_write_integer8_3d + + ! 4D Array + module procedure adios2_write_integer_4d + module procedure adios2_write_real_4d + module procedure adios2_write_dp_4d + module procedure adios2_write_complex_4d + module procedure adios2_write_complex_dp_4d + module procedure adios2_write_integer1_4d + module procedure adios2_write_integer2_4d + module procedure adios2_write_integer8_4d + + ! 5D Array + module procedure adios2_write_integer_5d + module procedure adios2_write_real_5d + module procedure adios2_write_dp_5d + module procedure adios2_write_complex_5d + module procedure adios2_write_complex_dp_5d + module procedure adios2_write_integer1_5d + module procedure adios2_write_integer2_5d + module procedure adios2_write_integer8_5d + + ! 6D Array + module procedure adios2_write_integer_6d + module procedure adios2_write_real_6d + module procedure adios2_write_dp_6d + module procedure adios2_write_complex_6d + module procedure adios2_write_complex_dp_6d + module procedure adios2_write_integer1_6d + module procedure adios2_write_integer2_6d + module procedure adios2_write_integer8_6d + + end interface + +contains + + ! Single Value + subroutine adios2_write_integer( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + + subroutine adios2_write_integer8( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + ! 1D Array + subroutine adios2_write_integer_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_1d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + ! 2D Array + subroutine adios2_write_integer_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_2d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + ! 3D Array + subroutine adios2_write_integer_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_3d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + + ! 4D Array + subroutine adios2_write_integer_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_4d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + + ! 5D Array + subroutine adios2_write_integer_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_5d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + + ! 6D Array + subroutine adios2_write_integer_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer, dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_real_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real, dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_dp_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + real(kind=8), dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex, dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_complex_dp_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + complex(kind=8), dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer1_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=1), dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer2_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=2), dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + + subroutine adios2_write_integer8_6d( engine, variable, values, ierr ) + integer(kind=8), intent(in):: engine + integer(kind=8), intent(in):: variable + integer(kind=8), dimension(:,:,:,:,:,:), intent(in):: values + integer, intent(out):: ierr + + call adios2_write_f2c(engine, variable, values, ierr) + + end subroutine + +end module diff --git a/bindings/fortran/adios2_f2c.cpp b/bindings/fortran/adios2_f2c.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e09b1aa95bb853cc15c3360845eb0fbda760586 --- /dev/null +++ b/bindings/fortran/adios2_f2c.cpp @@ -0,0 +1,272 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_f.cpp : C-header glue code implmentation for functions called from + * Fortran modules + * + * Created on: Aug 14, 2017 + * Author: William F Godoy + */ + +#include "adios2_f2c.h" + +#include <stdexcept> +#include <type_traits> //std::static_assert +#include <vector> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ADIOS2_HAVE_MPI_F +void adios2_init_f2c_(adios2_ADIOS **adios, MPI_Fint *comm, + const int *debug_mode, int *ierr) +{ + adios2_init_config_f2c_(adios, "", comm, debug_mode, ierr); +} + +void adios2_init_config_f2c_(adios2_ADIOS **adios, const char *config_file, + MPI_Fint *comm, const int *debug_mode, int *ierr) +{ + *ierr = 0; + try + { + *adios = + adios2_init_config(config_file, MPI_Comm_f2c(*comm), + static_cast<adios2_debug_mode>(*debug_mode)); + } + catch (std::exception &e) + { + *ierr = 1; + } +} +#else +void adios2_init_f2c_(adios2_ADIOS **adios, const int *debug_mode, int *ierr) +{ + adios2_init_config_f2c_(adios, "", debug_mode, ierr); +} + +void adios2_init_config_f2c_(adios2_ADIOS **adios, const char *config_file, + const int *debug_mode, int *ierr) +{ + *ierr = 0; + try + { + *adios = adios2_init_config_nompi( + config_file, static_cast<adios2_debug_mode>(*debug_mode)); + } + catch (std::exception &e) + { + *ierr = 1; + } +} +#endif + +void adios2_declare_io_f2c_(adios2_IO **io, adios2_ADIOS **adios, + const char *io_name, int *ierr) +{ + *ierr = 0; + + try + { + *io = adios2_declare_io(*adios, io_name); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_set_param_f2c_(adios2_IO **io, const char *key, const char *value, + int *ierr) +{ + *ierr = 0; + + try + { + adios2_set_param(*io, key, value); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_add_transport_f2c_(int *transport_index, adios2_IO **io, + const char *transport_type, int *ierr) +{ + *ierr = 0; + *transport_index = -1; + + try + { + *transport_index = + static_cast<int>(adios2_add_transport(*io, transport_type)); + } + catch (std::exception &e) + { + *ierr = 1; + } + + if (*transport_index == -1) + { + *ierr = 1; + } +} + +void adios2_set_transport_param_f2c_(adios2_IO **io, const int *transport_index, + const char *key, const char *value, + int *ierr) +{ + *ierr = 0; + + try + { + adios2_set_transport_param( + *io, static_cast<unsigned int>(*transport_index), key, value); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_define_variable_f2c_(adios2_Variable **variable, adios2_IO **io, + const char *variable_name, const int *type, + const int *ndims, const int *shape, + const int *start, const int *count, + const int *constant_dims, int *ierr) +{ + auto lf_IntToSizeT = [](const int *ndims, + const int *dims) -> std::vector<std::size_t> { + + std::vector<std::size_t> vecSizeT(*ndims); + for (unsigned int dim = 0; dim < *ndims; ++dim) + { + vecSizeT[dim] = dims[dim]; + } + return vecSizeT; + }; + + *ierr = 0; + + std::vector<std::size_t> shapeV, startV, countV; + if (shape != NULL) + { + shapeV = lf_IntToSizeT(ndims, shape); + } + + if (start != NULL) + { + startV = lf_IntToSizeT(ndims, start); + } + + if (count != NULL) + { + countV = lf_IntToSizeT(ndims, count); + } + + try + { + *variable = adios2_define_variable( + *io, variable_name, static_cast<adios2_type>(*type), *ndims, + shapeV.data(), startV.data(), countV.data(), + static_cast<adios2_constant_dims>(*constant_dims)); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_open_f2c_(adios2_Engine **engine, adios2_IO **io, const char *name, + const int *open_mode, int *ierr) +{ + *ierr = 0; + try + { + *engine = + adios2_open(*io, name, static_cast<adios2_open_mode>(*open_mode)); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +#ifdef ADIOS2_HAVE_MPI_F +void adios2_open_new_comm_f2c_(adios2_Engine **engine, adios2_IO **io, + const char *name, const int *open_mode, + MPI_Fint *comm, int *ierr) +{ + *ierr = 0; + try + { + *engine = adios2_open_new_comm( + *io, name, static_cast<adios2_open_mode>(*open_mode), + MPI_Comm_f2c(*comm)); + } + catch (std::exception &e) + { + *ierr = 1; + } +} +#endif + +void adios2_write_f2c_(adios2_Engine **engine, adios2_Variable **variable, + const void *values, int *ierr) +{ + *ierr = 0; + try + { + adios2_write(*engine, *variable, values); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_advance_f2c_(adios2_Engine **engine, int *ierr) +{ + *ierr = 0; + try + { + adios2_advance(*engine); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_close_f2c_(adios2_Engine **engine, int *ierr) +{ + *ierr = 0; + try + { + adios2_close(*engine); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +void adios2_finalize_f2c_(adios2_ADIOS **adios, int *ierr) +{ + *ierr = 0; + try + { + adios2_finalize(*adios); + } + catch (std::exception &e) + { + *ierr = 1; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/bindings/fortran/adios2_f2c.h b/bindings/fortran/adios2_f2c.h new file mode 100644 index 0000000000000000000000000000000000000000..49c55ab5015730d43ba555cc584760bd85acaae6 --- /dev/null +++ b/bindings/fortran/adios2_f2c.h @@ -0,0 +1,80 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_f.h : C-header glue code for functions called from Fortran modules + * + * Created on: Aug 15, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef BINDINGS_FORTRAN_ADIOS2_F2C_H_ +#define BINDINGS_FORTRAN_ADIOS2_F2C_H_ + +#include <stddef.h> + +#ifdef ADIOS2_HAVE_MPI_F +#include <mpi.h> +#endif + +#include <adios2_c.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ADIOS2_HAVE_MPI_F +void adios2_init_f2c_(adios2_ADIOS **adios, MPI_Fint *comm, + const int *debug_mode, int *ierr); + +void adios2_init_config_f2c_(adios2_ADIOS **adios, const char *config_file, + MPI_Fint *comm, const int *debug_mode, int *ierr); +#else +void adios2_init_f2c_(adios2_ADIOS **adios, const int *debug_mode, int *ierr); + +void adios2_init_config_f2c_(adios2_ADIOS **adios, const char *config_file, + const int *debug_mode, int *ierr); +#endif + +void adios2_declare_io_f2c_(adios2_IO **io, adios2_ADIOS **adios, + const char *io_name, int *ierr); + +void adios2_set_param_f2c_(adios2_IO **io, const char *key, const char *value, + int *ierr); + +void adios2_add_transport_f2c_(int *transport_index, adios2_IO **io, + const char *transport_type, int *ierr); + +void adios2_set_transport_param_f2c_(adios2_IO **io, const int *transport_index, + const char *key, const char *value, + int *ierr); + +void adios2_define_variable_f2c_(adios2_Variable **variable, adios2_IO **io, + const char *variable_name, const int *type, + const int *ndims, const int *shape, + const int *start, const int *count, + const int *constant_dims, int *ierr); + +void adios2_open_f2c_(adios2_Engine **engine, adios2_IO **io, const char *name, + const int *open_mode, int *ierr); + +#ifdef ADIOS2_HAVE_MPI_F +void adios2_open_new_comm_f2c_(adios2_Engine **engine, adios2_IO **io, + const char *name, const int *open_mode, + MPI_Fint *comm, int *ierr); +#endif + +void adios2_write_f2c_(adios2_Engine **engine, adios2_Variable **variable, + const void *values, int *ierr); + +void adios2_advance_f2c_(adios2_Engine **engine, int *ierr); + +void adios2_close_f2c_(adios2_Engine **engine, int *ierr); + +void adios2_finalize_f2c_(adios2_ADIOS **adios, int *ierr); + +#ifdef __cplusplus +} +#endif + +#endif /* BINDINGS_FORTRAN_ADIOS2_F2C_H_ */ diff --git a/bindings/fortran/adios2_functions_mod.f90 b/bindings/fortran/adios2_functions_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..82ccbd60880687cba8e7c2b65e455e700bd1f5ba --- /dev/null +++ b/bindings/fortran/adios2_functions_mod.f90 @@ -0,0 +1,16 @@ +module adios2_functions + implicit none + +contains + + integer function adios2_LogicalToInt( logical_value ) + logical, value, intent(in) :: logical_value + + adios2_LogicalToInt = 0 + if( logical_value ) then + adios2_LogicalToInt = 1 + end if + + end function + +end module diff --git a/bindings/fortran/adios2_io_mod.f90 b/bindings/fortran/adios2_io_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..6a8d645f1547f095c02de1af123d4a02a23f4651 --- /dev/null +++ b/bindings/fortran/adios2_io_mod.f90 @@ -0,0 +1,82 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_io.f90 : ADIOS2 Fortran bindings for IO class +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! +module adios2_io + + use adios2_io_open + use adios2_functions + implicit none + +contains + + subroutine adios2_set_param(io, key, value, ierr) + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: key + character*(*), intent(in) :: value + integer, intent(out) :: ierr + + call adios2_set_param_f2c( io, TRIM(ADJUSTL(key))//char(0), & + & TRIM(ADJUSTL(value))//char(0) ) + + end subroutine + + + subroutine adios2_add_transport(transport_index, io, transport_type, ierr) + integer, intent(out):: transport_index + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: transport_type + integer, intent(out) :: ierr + + call adios2_add_transport_f2c( transport_index, io, & + & TRIM(ADJUSTL(transport_type))//char(0), ierr) + + end subroutine + + + subroutine adios2_set_transport_param(io, transport_index, key, value, ierr) + integer(kind=8), intent(in):: io + integer, intent(in):: transport_index + character*(*), intent(in) :: key + character*(*), intent(in) :: value + integer, intent(out):: ierr + + call adios2_set_transport_param_f2c(io, transport_index, & + & TRIM(ADJUSTL(key))//char(0), TRIM(ADJUSTL(value))//char(0), & + & ierr) + + end subroutine + + + subroutine adios2_define_variable(variable, io, variable_name, & + & adios2_type, ndims, shape_dims, start_dims, count_dims, & + & adios2_constant_dims, ierr) + integer(kind=8), intent(out) :: variable + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: variable_name + integer, intent(in) :: adios2_type + integer, intent(in) :: ndims + integer, dimension(:), intent(in) :: shape_dims + integer, dimension(:), intent(in) :: start_dims + integer, dimension(:), intent(in) :: count_dims + logical, intent(in) :: adios2_constant_dims + integer, intent(out) :: ierr + + !local + integer constant_dims + + constant_dims = adios2_LogicalToInt(adios2_constant_dims) + + call adios2_define_variable_f2c(variable, io, & + & TRIM(ADJUSTL(variable_name))//char(0), adios2_type, ndims, & + & shape_dims, start_dims, count_dims, constant_dims, ierr) + + end subroutine + + +end module diff --git a/bindings/fortran/adios2_mod.f90 b/bindings/fortran/adios2_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..9fd25ff3450fa585a04ef84275f6e6b915bc044c --- /dev/null +++ b/bindings/fortran/adios2_mod.f90 @@ -0,0 +1,19 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_mod.f90 : ADIOS2 Fortran bindings central module +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + +module adios2 + + use adios2_params + use adios2_adios + use adios2_io +! use adios2_variable + use adios2_engine + +end module diff --git a/bindings/fortran/adios2_params_mod.f90 b/bindings/fortran/adios2_params_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..59f934e3e0aa499b9f411f9500b266675dbb0df0 --- /dev/null +++ b/bindings/fortran/adios2_params_mod.f90 @@ -0,0 +1,41 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_mod.f90 : ADIOS2 Fortran bindings central module +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! +module adios2_params + implicit none + + ! Debug mode + logical, parameter :: adios2_debug_mode_on = .true. + logical, parameter :: adios2_debug_mode_off = .false. + + ! Type + integer, parameter :: adios2_type_character = 0 + integer, parameter :: adios2_type_integer = 1 + integer, parameter :: adios2_type_real = 2 + integer, parameter :: adios2_type_dp = 3 + integer, parameter :: adios2_type_complex = 4 + integer, parameter :: adios2_type_complex_dp = 5 + + integer, parameter :: adios2_type_integer1 = 6 + integer, parameter :: adios2_type_integer2 = 7 + integer, parameter :: adios2_type_integer4 = 8 + integer, parameter :: adios2_type_integer8 = 9 + + ! Constant dims + logical, parameter :: adios2_constant_dims_true = .true. + logical, parameter :: adios2_constant_dims_false = .false. + + ! Open Mode + integer, parameter :: adios2_open_mode_undefined = 0 + integer, parameter :: adios2_open_mode_write = 1 + integer, parameter :: adios2_open_mode_read = 2 + integer, parameter :: adios2_open_mode_append = 3 + integer, parameter :: adios2_open_mode_read_write = 4 + +end module diff --git a/bindings/fortran/mpi/adios2_adios_init_mod.f90 b/bindings/fortran/mpi/adios2_adios_init_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..55638f4bbe723752062b848c96c45d784380ee2f --- /dev/null +++ b/bindings/fortran/mpi/adios2_adios_init_mod.f90 @@ -0,0 +1,45 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_adios_init_mod.f90 : ADIOS2 Fortran bindings for ADIOS class Init +! functions +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + +module adios2_adios_init + + use adios2_functions + implicit none + +contains + + subroutine adios2_init(adios, comm, adios2_debug_mode, ierr) + integer(kind=8), intent(out) :: adios + integer, intent(in) :: comm + logical, value, intent(in) :: adios2_debug_mode + integer, intent(out) :: ierr + + call adios2_init_config(adios, char(0), comm, adios2_debug_mode, ierr) + + end subroutine + + + subroutine adios2_init_config(adios, config_file, comm, adios2_debug_mode, & + & ierr) + integer(kind=8), intent(out) :: adios + character*(*), intent(in) :: config_file + integer, intent(in) :: comm + logical, value, intent(in) :: adios2_debug_mode + integer, intent(out) :: ierr + ! local + integer debug_mode + + debug_mode = adios2_LogicalToInt(adios2_debug_mode) + call adios2_init_config_f2c(adios, config_file, comm, debug_mode, ierr) + + end subroutine + +end module diff --git a/bindings/fortran/mpi/adios2_io_open_mod.f90 b/bindings/fortran/mpi/adios2_io_open_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..05f6d37759a31d487b1e0245f06a7ca222dc426f --- /dev/null +++ b/bindings/fortran/mpi/adios2_io_open_mod.f90 @@ -0,0 +1,43 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_io_open_mod.f90 : ADIOS2 Fortran bindings for IO class open function +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + +module adios2_io_open + implicit none + +contains + + subroutine adios2_open(engine, io, name, adios2_open_mode, ierr) + integer(kind=8), intent(out) :: engine + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: name + integer, intent(in) :: adios2_open_mode + integer, intent(out) :: ierr + + call adios2_open_f2c(engine, io, TRIM(ADJUSTL(name))//char(0), & + & adios2_open_mode, ierr) + + end subroutine + + + subroutine adios2_open_new_comm(engine, io, name, adios2_open_mode, comm, & + & ierr) + integer(kind=8), intent(out) :: engine + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: name + integer, intent(in) :: adios2_open_mode + integer, intent(in) :: comm + integer, intent(out) :: ierr + + call adios2_open_new_comm_f2c(engine, io, TRIM(ADJUSTL(name))//char(0),& + & adios2_open_mode, comm, ierr) + + end subroutine + +end module diff --git a/bindings/fortran/nompi/adios2_adios_init_nompi_mod.f90 b/bindings/fortran/nompi/adios2_adios_init_nompi_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..351174a02d19c45e1af34fe7a40c5c0dddebca75 --- /dev/null +++ b/bindings/fortran/nompi/adios2_adios_init_nompi_mod.f90 @@ -0,0 +1,41 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_init_nompi_mod.f90 : ADIOS2 Fortran bindings nonMPI init functions +! +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + +module adios2_adios_init + + use adios2_functions + implicit none + +contains + + subroutine adios2_init(adios, adios2_debug_mode, ierr) + integer(kind=8), intent(out) :: adios + logical, value, intent(in) :: adios2_debug_mode + integer, intent(out) :: ierr + + call adios2_init_config(adios, "", adios2_debug_mode, ierr) + + end subroutine + + + subroutine adios2_init_config(adios, config_file, adios2_debug_mode, ierr) + integer(kind=8), intent(out) :: adios + character*(*), intent(in) :: config_file + logical, value, intent(in) :: adios2_debug_mode + integer, intent(out) :: ierr + ! local + integer debug_mode + + debug_mode = adios2_LogicalToInt(adios2_debug_mode) + call adios2_init_config_f2c(adios, config_file, debug_mode, ierr) + + end subroutine + +end module diff --git a/bindings/fortran/nompi/adios2_io_open_nompi_mod.f90 b/bindings/fortran/nompi/adios2_io_open_nompi_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..d0a86535eee4ebd852e0edeb872991a894c207e3 --- /dev/null +++ b/bindings/fortran/nompi/adios2_io_open_nompi_mod.f90 @@ -0,0 +1,28 @@ +! +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! adios2_io_open_nompi_mod.f90 : ADIOS2 Fortran bindings for IO class open +! function +! Created on: Mar 13, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + +module adios2_io_open + implicit none + +contains + + subroutine adios2_open(engine, io, name, adios2_open_mode, ierr) + integer(kind=8), intent(out) :: engine + integer(kind=8), intent(in) :: io + character*(*), intent(in) :: name + integer, intent(in) :: adios2_open_mode + integer, intent(out) :: ierr + + call adios2_open_f2c(engine, io, TRIM(ADJUSTL(name))//char(0), & + & adios2_open_mode, ierr) + + end subroutine + +end module diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt index 90d030a55245ad5ee4e0d691a093d6e160567fa7..a6ced9fc20570ec0b41b0343ea705906cf1b284a 100644 --- a/bindings/python/CMakeLists.txt +++ b/bindings/python/CMakeLists.txt @@ -1,7 +1,3 @@ -set(Python_ADDITIONAL_VERSIONS 3 2.7) -find_package(PythonInterp REQUIRED) -find_package(PythonLibsNew REQUIRED) - pybind11_add_module(adios2py MODULE ADIOSPy.h ADIOSPy.cpp @@ -19,7 +15,6 @@ pybind11_add_module(adios2py MODULE ) target_link_libraries(adios2py PRIVATE adios2) if(ADIOS2_HAVE_MPI) - find_package(PythonModule REQUIRED COMPONENTS mpi4py mpi4py/mpi4py.h) target_link_libraries(adios2py PRIVATE PythonModule::mpi4py) endif() diff --git a/cmake/ADIOS2ConfigCommon.cmake.in b/cmake/ADIOS2ConfigCommon.cmake.in index 945a97a9810c9c3c70364bf7d0ba8e218f4881cf..c32881dab5ee8a31b178133d38c16698277d8c19 100644 --- a/cmake/ADIOS2ConfigCommon.cmake.in +++ b/cmake/ADIOS2ConfigCommon.cmake.in @@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.5) include(CMakeFindDependencyMacro) +set(ADIOS2_HAVE_C @ADIOS2_HAVE_C@) +if(ADIOS2_HAVE_C) + find_dependency(C) +endif() + +set(ADIOS2_HAVE_Fortran @ADIOS2_HAVE_Fortran@) + set(ADIOS2_HAVE_MPI @ADIOS2_HAVE_MPI@) if(ADIOS2_HAVE_MPI) find_dependency(MPI) diff --git a/cmake/DetectOptions.cmake b/cmake/DetectOptions.cmake index 5022c676d3c31fe1dbaa82907f0ec9b72417a614..2562e77a2b94180e0d3e5d2b397bdb3c326050c0 100644 --- a/cmake/DetectOptions.cmake +++ b/cmake/DetectOptions.cmake @@ -16,75 +16,86 @@ set(adios2_find_modules) # BZip2 if(ADIOS2_USE_BZip2 STREQUAL AUTO) find_package(BZip2) - if(BZIP2_FOUND) - set(ADIOS2_HAVE_BZip2 TRUE) - endif() elseif(ADIOS2_USE_BZip2) + find_package(BZip2 REQUIRED) +endif() +if(BZIP2_FOUND) set(ADIOS2_HAVE_BZip2 TRUE) endif() # ZFP if(ADIOS2_USE_ZFP STREQUAL AUTO) find_package(ZFP) - if(ZFP_FOUND) - set(ADIOS2_HAVE_ZFP TRUE) - endif() elseif(ADIOS2_USE_ZFP) + find_package(ZFP REQUIRED) +endif() +if(ZFP_FOUND) set(ADIOS2_HAVE_ZFP TRUE) endif() +set(mpi_find_components C) + +# Fortran +if(ADIOS2_USE_Fortran STREQUAL AUTO) + # Currently auto-detection for language support does not work in CMake. See + # documentation for the "enable_language" command + message(WARN "Auto-detection of Fortran is not currently supported; Disabling") + #enable_language(Fortran OPTIONAL) +elseif(ADIOS2_USE_Fortran) + enable_language(Fortran) +endif() +if(CMAKE_Fortran_COMPILER_LOADED) + set(ADIOS2_HAVE_Fortran TRUE) + list(APPEND mpi_find_components Fortran) +endif() + # MPI if(ADIOS2_USE_MPI STREQUAL AUTO) - find_package(MPI COMPONENTS C) - if(MPI_FOUND) - set(ADIOS2_HAVE_MPI TRUE) - endif() + find_package(MPI COMPONENTS ${mpi_find_components}) elseif(ADIOS2_USE_MPI) + find_package(MPI COMPONENTS ${mpi_find_components} REQUIRED) +endif() +if(MPI_FOUND) set(ADIOS2_HAVE_MPI TRUE) endif() # DataMan -if(ADIOS2_USE_DataMan STREQUAL AUTO) - if(SHARED_LIBS_SUPPORTED AND NOT MSVC) - set(ADIOS2_HAVE_DataMan TRUE) - endif() -elseif(ADIOS2_USE_DataMan) +if(SHARED_LIBS_SUPPORTED AND NOT MSVC) set(ADIOS2_HAVE_DataMan TRUE) endif() # ZeroMQ if(ADIOS2_USE_ZeroMQ STREQUAL AUTO) find_package(ZeroMQ) - if(ZeroMQ_FOUND) - set(ADIOS2_HAVE_ZeroMQ TRUE) - endif() elseif(ADIOS2_USE_ZeroMQ) + find_package(ZeroMQ REQUIRED) +endif() +if(ZeroMQ_FOUND) set(ADIOS2_HAVE_ZeroMQ TRUE) endif() # HDF5 if(ADIOS2_USE_HDF5 STREQUAL AUTO) find_package(HDF5 COMPONENTS C) - if(HDF5_FOUND AND - ((ADIOS2_HAVE_MPI AND HDF5_IS_PARALLEL) OR - NOT (ADIOS2_HAVE_MPI OR HDF5_IS_PARALLEL))) - set(ADIOS2_HAVE_HDF5 TRUE) - endif() elseif(ADIOS2_USE_HDF5) + find_package(HDF5 REQUIRED COMPONENTS C) +endif() +if(HDF5_FOUND AND + ((ADIOS2_HAVE_MPI AND HDF5_IS_PARALLEL) OR + NOT (ADIOS2_HAVE_MPI OR HDF5_IS_PARALLEL))) set(ADIOS2_HAVE_HDF5 TRUE) endif() # ADIOS1 +if(NOT ADIOS2_HAVE_MPI) + set(adios1_find_args COMPONENTS sequential) +endif() if(ADIOS2_USE_ADIOS1 STREQUAL AUTO) - if(NOT ADIOS2_HAVE_MPI) - set(adios1_args COMPONENTS sequential) - endif() - find_package(ADIOS1 1.12.0 ${adios1_args}) - unset(adios1_args) - if(ADIOS1_FOUND) - set(ADIOS2_HAVE_ADIOS1 TRUE) - endif() + find_package(ADIOS1 1.12.0 ${adios1_find_args}) elseif(ADIOS2_USE_ADIOS1) + find_package(ADIOS1 1.12.0 REQUIRED ${adios1_find_args}) +endif() +if(ADIOS1_FOUND) set(ADIOS2_HAVE_ADIOS1 TRUE) endif() @@ -93,39 +104,35 @@ endif() list(INSERT CMAKE_MODULE_PATH 0 "${ADIOS2_SOURCE_DIR}/thirdparty/pybind11/pybind11/tools" ) -if(ADIOS2_USE_Python STREQUAL AUTO) +if(ADIOS2_USE_Python) + if(NOT (ADIOS2_USE_Python STREQUAL AUTO)) + set(python_find_args REQUIRED) + endif() if(SHARED_LIBS_SUPPORTED AND ADIOS2_ENABLE_PIC) set(Python_ADDITIONAL_VERSIONS 3 2.7) - find_package(PythonInterp) - find_package(PythonLibsNew) - if(PYTHONLIBS_FOUND) - if(ADIOS2_HAVE_MPI) - find_package(PythonModule COMPONENTS mpi4py mpi4py/mpi4py.h) - if(PythonModule_mpi4py_FOUND) - set(ADIOS2_HAVE_Python TRUE) - endif() - else() - set(ADIOS2_HAVE_Python TRUE) - endif() + list(APPEND python_find_args COMPONENTS Interp Libs numpy) + if(ADIOS2_HAVE_MPI) + list(APPEND python_find_args "mpi4py\\\;mpi4py/mpi4py.h") endif() + find_package(PythonFull ${python_find_args}) endif() -elseif(ADIOS2_USE_Python) - set(ADIOS2_HAVE_Python TRUE) +endif() +if(PythonFull_FOUND) + set(ADIOS2_HAVE_Python ON) endif() #SysV IPC -if(ADIOS2_USE_SysVShMem STREQUAL AUTO) - if(UNIX) - include(CheckSymbolExists) - CHECK_SYMBOL_EXISTS(shmget "sys/ipc.h;sys/shm.h" HAVE_shmget) - if(HAVE_shmget) - set(ADIOS2_HAVE_SysVShMem ON) - else() - set(ADIOS2_HAVE_SysVShMem OFF) - endif() +if(UNIX) + include(CheckSymbolExists) + CHECK_SYMBOL_EXISTS(shmget "sys/ipc.h;sys/shm.h" HAVE_shmget) + if(HAVE_shmget) + set(ADIOS2_HAVE_SysVShMem ON) else() set(ADIOS2_HAVE_SysVShMem OFF) endif() -elseif(ADIOS2_USE_SysVShMem) - set(ADIOS2_HAVE_SysVShMem TRUE) +else() + set(ADIOS2_HAVE_SysVShMem OFF) endif() + +# Multithreading +find_package(Threads REQUIRED) diff --git a/cmake/FindHDF5.cmake b/cmake/FindHDF5.cmake new file mode 100644 index 0000000000000000000000000000000000000000..23d5043d75cf8466e6d8a3629f2b210db18d7779 --- /dev/null +++ b/cmake/FindHDF5.cmake @@ -0,0 +1,11 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +# This module is already included in new versions of CMake +if(CMAKE_VERSION VERSION_LESS 3.9) + include(${CMAKE_CURRENT_LIST_DIR}/upstream/FindHDF5.cmake) +else() + include(${CMAKE_ROOT}/Modules/FindHDF5.cmake) +endif() diff --git a/cmake/FindPythonFull.cmake b/cmake/FindPythonFull.cmake new file mode 100644 index 0000000000000000000000000000000000000000..6b70423eaaf0fef9254c22c1a772569267eeef0a --- /dev/null +++ b/cmake/FindPythonFull.cmake @@ -0,0 +1,56 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# +# +# PythonFull +# ----------- +# +# Try to find various pieces needed for a full python environment including +# python libs, interpreter, and modules +# +# This module defines the following variables: +# +# PythonFull_FOUND +# PYTHONINTERP_FOUND +# PYTHON_EXECUTABLE +# PYTHONLIBS_FOUND +# PYTHON_LIBRARIES +# PythonModule_${module_NAME}_FOUND +# +# This is intented to be called by specifying components for libraries, +# interpreter, and modules. So, for example, if you needed libraries, the +# interpreter, mpi4py, and numpy then you would call: +# +# find_package(PythonFull COMPONENTS Interp Libs mpi4py numpy) +# + +include(CMakeFindDependencyMacro) +set(_req_vars) +foreach(comp IN LISTS PythonFull_FIND_COMPONENTS) + if(comp STREQUAL Interp) + find_package(PythonInterp) + set(PythonFull_${comp}_FOUND ${PYTHONINTERP_FOUND}) + list(APPEND _req_vars PYTHON_EXECUTABLE) + elseif(comp STREQUAL Libs) + find_package(PythonLibsNew) + set(PythonFull_${comp}_FOUND ${PYTHONLIBS_FOUND}) + list(APPEND _req_vars PYTHON_LIBRARIES) + else() + # Parse off any specified headers and libs for a given module + set(_comp ${comp}) + list(GET _comp 0 _mod) + string(REGEX REPLACE "${_mod}\\\;[^;]*" "${_mod}" + PythonFull_FIND_COMPONENTS "${PythonFull_FIND_COMPONENTS}" + ) + set(PythonFull_FIND_REQUIRED_${_mod} TRUE) + find_package(PythonModule COMPONENTS ${_comp}) + set(PythonFull_${_mod}_FOUND ${PythonModule_${_mod}_FOUND}) + endif() +endforeach() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PythonFull + REQUIRED_VARS ${_req_vars} + HANDLE_COMPONENTS +) diff --git a/cmake/FindPythonModule.cmake b/cmake/FindPythonModule.cmake index 492d1d28f4205b856903fae195fa9d9a208f042d..c47f71dbc19c6ae8ddcb3ee8618c69b79487802f 100644 --- a/cmake/FindPythonModule.cmake +++ b/cmake/FindPythonModule.cmake @@ -119,8 +119,9 @@ set( PythonModule_${module_NAME}_PATH endif() include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(PythonModule_${module_NAME} DEFAULT_MSG - ${required_vars} + find_package_handle_standard_args(PythonModule_${module_NAME} + FOUND_VAR PythonModule_${module_NAME}_FOUND + REQUIRED_VARS ${required_vars} ) endif() diff --git a/cmake/upstream/FindHDF5.cmake b/cmake/upstream/FindHDF5.cmake new file mode 100644 index 0000000000000000000000000000000000000000..aef46cb611f5cbaf0cbc488514a411250f48163b --- /dev/null +++ b/cmake/upstream/FindHDF5.cmake @@ -0,0 +1,938 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindHDF5 +# -------- +# +# Find HDF5, a library for reading and writing self describing array data. +# +# +# +# This module invokes the HDF5 wrapper compiler that should be installed +# alongside HDF5. Depending upon the HDF5 Configuration, the wrapper +# compiler is called either h5cc or h5pcc. If this succeeds, the module +# will then call the compiler with the -show argument to see what flags +# are used when compiling an HDF5 client application. +# +# The module will optionally accept the COMPONENTS argument. If no +# COMPONENTS are specified, then the find module will default to finding +# only the HDF5 C library. If one or more COMPONENTS are specified, the +# module will attempt to find the language bindings for the specified +# components. The only valid components are C, CXX, Fortran, HL, and +# Fortran_HL. If the COMPONENTS argument is not given, the module will +# attempt to find only the C bindings. +# +# This module will read the variable +# HDF5_USE_STATIC_LIBRARIES to determine whether or not to prefer a +# static link to a dynamic link for HDF5 and all of it's dependencies. +# To use this feature, make sure that the HDF5_USE_STATIC_LIBRARIES +# variable is set before the call to find_package. +# +# To provide the module with a hint about where to find your HDF5 +# installation, you can set the environment variable HDF5_ROOT. The +# Find module will then look in this path when searching for HDF5 +# executables, paths, and libraries. +# +# Both the serial and parallel HDF5 wrappers are considered and the first +# directory to contain either one will be used. In the event that both appear +# in the same directory the serial version is preferentially selected. This +# behavior can be reversed by setting the variable HDF5_PREFER_PARALLEL to +# true. +# +# In addition to finding the includes and libraries required to compile +# an HDF5 client application, this module also makes an effort to find +# tools that come with the HDF5 distribution that may be useful for +# regression testing. +# +# This module will define the following variables: +# +# :: +# +# HDF5_FOUND - true if HDF5 was found on the system +# HDF5_VERSION - HDF5 version in format Major.Minor.Release +# HDF5_INCLUDE_DIRS - Location of the hdf5 includes +# HDF5_INCLUDE_DIR - Location of the hdf5 includes (deprecated) +# HDF5_DEFINITIONS - Required compiler definitions for HDF5 +# HDF5_LIBRARIES - Required libraries for all requested bindings +# HDF5_HL_LIBRARIES - Required libraries for the HDF5 high level API for all +# bindings, if the HL component is enabled +# +# Available components are: C CXX Fortran and HL. For each enabled language +# binding, a corresponding HDF5_${LANG}_LIBRARIES variable, and potentially +# HDF5_${LANG}_DEFINITIONS, will be defined. +# If the HL component is enabled, then an HDF5_${LANG}_HL_LIBRARIES will +# also be defined. With all components enabled, the following variables will be defined: +# +# :: +# +# HDF5_C_DEFINITIONS -- Required compiler definitions for HDF5 C bindings +# HDF5_CXX_DEFINITIONS -- Required compiler definitions for HDF5 C++ bindings +# HDF5_Fortran_DEFINITIONS -- Required compiler definitions for HDF5 Fortran bindings +# HDF5_C_INCLUDE_DIRS -- Required include directories for HDF5 C bindings +# HDF5_CXX_INCLUDE_DIRS -- Required include directories for HDF5 C++ bindings +# HDF5_Fortran_INCLUDE_DIRS -- Required include directories for HDF5 Fortran bindings +# HDF5_C_LIBRARIES - Required libraries for the HDF5 C bindings +# HDF5_CXX_LIBRARIES - Required libraries for the HDF5 C++ bindings +# HDF5_Fortran_LIBRARIES - Required libraries for the HDF5 Fortran bindings +# HDF5_C_HL_LIBRARIES - Required libraries for the high level C bindings +# HDF5_CXX_HL_LIBRARIES - Required libraries for the high level C++ bindings +# HDF5_Fortran_HL_LIBRARIES - Required libraries for the high level Fortran +# bindings. +# +# HDF5_IS_PARALLEL - Whether or not HDF5 was found with parallel IO support +# HDF5_C_COMPILER_EXECUTABLE - the path to the HDF5 C wrapper compiler +# HDF5_CXX_COMPILER_EXECUTABLE - the path to the HDF5 C++ wrapper compiler +# HDF5_Fortran_COMPILER_EXECUTABLE - the path to the HDF5 Fortran wrapper compiler +# HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary C compiler +# which is also the HDF5 wrapper +# HDF5_CXX_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary C++ +# compiler which is also +# the HDF5 wrapper +# HDF5_Fortran_COMPILER_EXECUTABLE_NO_INTERROGATE - path to the primary +# Fortran compiler which +# is also the HDF5 wrapper +# HDF5_DIFF_EXECUTABLE - the path to the HDF5 dataset comparison tool +# +# The following variable can be set to guide the search for HDF5 libraries and includes: +# +# ``HDF5_ROOT`` +# Specify the path to the HDF5 installation to use. +# +# ``HDF5_FIND_DEBUG`` +# Set to a true value to get some extra debugging output. +# +# ``HDF5_NO_FIND_PACKAGE_CONFIG_FILE`` +# Set to a true value to skip trying to find ``hdf5-config.cmake``. + +# This module is maintained by Will Dicharry <wdicharry@stellarscience.com>. + +include(${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake) +include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake) + +# List of the valid HDF5 components +set(HDF5_VALID_LANGUAGE_BINDINGS C CXX Fortran) + +# Validate the list of find components. +if(NOT HDF5_FIND_COMPONENTS) + set(HDF5_LANGUAGE_BINDINGS "C") +else() + set(HDF5_LANGUAGE_BINDINGS) + # add the extra specified components, ensuring that they are valid. + set(FIND_HL OFF) + foreach(component IN LISTS HDF5_FIND_COMPONENTS) + list(FIND HDF5_VALID_LANGUAGE_BINDINGS ${component} component_location) + if(NOT component_location EQUAL -1) + list(APPEND HDF5_LANGUAGE_BINDINGS ${component}) + elseif(component STREQUAL "HL") + set(FIND_HL ON) + elseif(component STREQUAL "Fortran_HL") # only for compatibility + list(APPEND HDF5_LANGUAGE_BINDINGS Fortran) + set(FIND_HL ON) + set(HDF5_FIND_REQUIRED_Fortran_HL False) + set(HDF5_FIND_REQUIRED_Fortran True) + set(HDF5_FIND_REQUIRED_HL True) + else() + message(FATAL_ERROR "${component} is not a valid HDF5 component.") + endif() + endforeach() + if(NOT HDF5_LANGUAGE_BINDINGS) + get_property(__langs GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(__lang IN LISTS __langs) + if(__lang MATCHES "^(C|CXX|Fortran)$") + list(APPEND HDF5_LANGUAGE_BINDINGS ${__lang}) + endif() + endforeach() + endif() + list(REMOVE_ITEM HDF5_FIND_COMPONENTS Fortran_HL) # replaced by Fortran and HL + list(REMOVE_DUPLICATES HDF5_LANGUAGE_BINDINGS) +endif() + +# Determine whether to search for serial or parallel executable first +if(HDF5_PREFER_PARALLEL) + set(HDF5_C_COMPILER_NAMES h5pcc h5cc) + set(HDF5_CXX_COMPILER_NAMES h5pc++ h5c++) + set(HDF5_Fortran_COMPILER_NAMES h5pfc h5fc) +else() + set(HDF5_C_COMPILER_NAMES h5cc h5pcc) + set(HDF5_CXX_COMPILER_NAMES h5c++ h5pc++) + set(HDF5_Fortran_COMPILER_NAMES h5fc h5pfc) +endif() + +# We may have picked up some duplicates in various lists during the above +# process for the language bindings (both the C and C++ bindings depend on +# libz for example). Remove the duplicates. It appears that the default +# CMake behavior is to remove duplicates from the end of a list. However, +# for link lines, this is incorrect since unresolved symbols are searched +# for down the link line. Therefore, we reverse the list, remove the +# duplicates, and then reverse it again to get the duplicates removed from +# the beginning. +macro(_HDF5_remove_duplicates_from_beginning _list_name) + if(${_list_name}) + list(REVERSE ${_list_name}) + list(REMOVE_DUPLICATES ${_list_name}) + list(REVERSE ${_list_name}) + endif() +endmacro() + + +# Test first if the current compilers automatically wrap HDF5 + +function(_HDF5_test_regular_compiler_C success version is_parallel) + set(scratch_directory + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if(NOT ${success} OR + NOT EXISTS ${scratch_directory}/compiler_has_h5_c) + set(test_file ${scratch_directory}/cmake_hdf5_test.c) + file(WRITE ${test_file} + "#include <hdf5.h>\n" + "#include <hdf5_hl.h>\n" + "const char* info_ver = \"INFO\" \":\" H5_VERSION;\n" + "#ifdef H5_HAVE_PARALLEL\n" + "const char* info_parallel = \"INFO\" \":\" \"PARALLEL\";\n" + "#endif\n" + "int main(int argc, char **argv) {\n" + " int require = 0;\n" + " require += info_ver[argc];\n" + "#ifdef H5_HAVE_PARALLEL\n" + " require += info_parallel[argc];\n" + "#endif\n" + " hid_t fid;\n" + " fid = H5Fcreate(\"foo.h5\",H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);\n" + " return 0;\n" + "}") + try_compile(${success} ${scratch_directory} ${test_file} + COPY_FILE ${scratch_directory}/compiler_has_h5_c + ) + endif() + if(${success}) + file(STRINGS ${scratch_directory}/compiler_has_h5_c INFO_STRINGS + REGEX "^INFO:" + ) + string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + INFO_VER "${INFO_STRINGS}" + ) + set(${version} ${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + set(${version} ${HDF5_CXX_VERSION}.${CMAKE_MATCH_3}) + endif() + set(${version} ${${version}} PARENT_SCOPE) + + if(INFO_STRINGS MATCHES "INFO:PARALLEL") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() +endfunction() + +function(_HDF5_test_regular_compiler_CXX success version is_parallel) + set(scratch_directory ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if(NOT ${success} OR + NOT EXISTS ${scratch_directory}/compiler_has_h5_cxx) + set(test_file ${scratch_directory}/cmake_hdf5_test.cxx) + file(WRITE ${test_file} + "#include <H5Cpp.h>\n" + "#ifndef H5_NO_NAMESPACE\n" + "using namespace H5;\n" + "#endif\n" + "const char* info_ver = \"INFO\" \":\" H5_VERSION;\n" + "#ifdef H5_HAVE_PARALLEL\n" + "const char* info_parallel = \"INFO\" \":\" \"PARALLEL\";\n" + "#endif\n" + "int main(int argc, char **argv) {\n" + " int require = 0;\n" + " require += info_ver[argc];\n" + "#ifdef H5_HAVE_PARALLEL\n" + " require += info_parallel[argc];\n" + "#endif\n" + " H5File file(\"foo.h5\", H5F_ACC_TRUNC);\n" + " return 0;\n" + "}") + try_compile(${success} ${scratch_directory} ${test_file} + COPY_FILE ${scratch_directory}/compiler_has_h5_cxx + ) + endif() + if(${success}) + file(STRINGS ${scratch_directory}/compiler_has_h5_cxx INFO_STRINGS + REGEX "^INFO:" + ) + string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" + INFO_VER "${INFO_STRINGS}" + ) + set(${version} ${CMAKE_MATCH_1}) + if(CMAKE_MATCH_3) + set(${version} ${HDF5_CXX_VERSION}.${CMAKE_MATCH_3}) + endif() + set(${version} ${${version}} PARENT_SCOPE) + + if(INFO_STRINGS MATCHES "INFO:PARALLEL") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() +endfunction() + +function(_HDF5_test_regular_compiler_Fortran success is_parallel) + if(NOT ${success}) + set(scratch_directory + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + set(test_file ${scratch_directory}/cmake_hdf5_test.f90) + file(WRITE ${test_file} + "program hdf5_hello\n" + " use hdf5\n" + " use h5lt\n" + " use h5ds\n" + " integer error\n" + " call h5open_f(error)\n" + " call h5close_f(error)\n" + "end\n") + try_compile(${success} ${scratch_directory} ${test_file}) + if(${success}) + execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -showconfig + OUTPUT_VARIABLE config_output + ERROR_VARIABLE config_error + RESULT_VARIABLE config_result + ) + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE PARENT_SCOPE) + else() + set(${is_parallel} FALSE PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + +# Invoke the HDF5 wrapper compiler. The compiler return value is stored to the +# return_value argument, the text output is stored to the output variable. +macro( _HDF5_invoke_compiler language output return_value version is_parallel) + set(${version}) + if(HDF5_USE_STATIC_LIBRARIES) + set(lib_type_args -noshlib) + else() + set(lib_type_args -shlib) + endif() + set(scratch_dir ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) + if("${language}" STREQUAL "C") + set(test_file ${scratch_dir}/cmake_hdf5_test.c) + elseif("${language}" STREQUAL "CXX") + set(test_file ${scratch_dir}/cmake_hdf5_test.cxx) + elseif("${language}" STREQUAL "Fortran") + set(test_file ${scratch_dir}/cmake_hdf5_test.f90) + endif() + exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} + ARGS -show ${lib_type_args} ${test_file} + OUTPUT_VARIABLE ${output} + RETURN_VALUE ${return_value} + ) + if(NOT ${${return_value}} EQUAL 0) + message(STATUS + "Unable to determine HDF5 ${language} flags from HDF5 wrapper.") + endif() + exec_program( ${HDF5_${language}_COMPILER_EXECUTABLE} + ARGS -showconfig + OUTPUT_VARIABLE config_output + RETURN_VALUE config_return + ) + if(NOT ${return_value} EQUAL 0) + message( STATUS + "Unable to determine HDF5 ${language} version from HDF5 wrapper.") + endif() + string(REGEX MATCH "HDF5 Version: ([a-zA-Z0-9\\.\\-]*)" version_match "${config_output}") + if(version_match) + string(REPLACE "HDF5 Version: " "" ${version} "${version_match}") + string(REPLACE "-patch" "." ${version} "${${version}}") + endif() + if(config_output MATCHES "Parallel HDF5: yes") + set(${is_parallel} TRUE) + else() + set(${is_parallel} FALSE) + endif() +endmacro() + +# Parse a compile line for definitions, includes, library paths, and libraries. +macro( _HDF5_parse_compile_line + compile_line_var + include_paths + definitions + library_paths + libraries + libraries_hl) + + if(UNIX) + separate_arguments(_HDF5_COMPILE_ARGS UNIX_COMMAND "${${compile_line_var}}") + else() + separate_arguments(_HDF5_COMPILE_ARGS WINDOWS_COMMAND "${${compile_line_var}}") + endif() + + foreach(arg IN LISTS _HDF5_COMPILE_ARGS) + if("${arg}" MATCHES "^-I(.*)$") + # include directory + list(APPEND ${include_paths} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-D(.*)$") + # compile definition + list(APPEND ${definitions} "-D${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-L(.*)$") + # library search path + list(APPEND ${library_paths} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-l(hdf5.*hl.*)$") + # library name (hl) + list(APPEND ${libraries_hl} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^-l(.*)$") + # library name + list(APPEND ${libraries} "${CMAKE_MATCH_1}") + elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.(a|so|dylib|sl|lib)$") + # library file + if(NOT EXISTS "${arg}") + continue() + endif() + get_filename_component(_HDF5_LPATH "${arg}" DIRECTORY) + get_filename_component(_HDF5_LNAME "${arg}" NAME_WE) + string(REGEX REPLACE "^lib" "" _HDF5_LNAME "${_HDF5_LNAME}") + list(APPEND ${library_paths} "${_HDF5_LPATH}") + if(_HDF5_LNAME MATCHES "hdf5.*hl") + list(APPEND ${libraries_hl} "${_HDF5_LNAME}") + else() + list(APPEND ${libraries} "${_HDF5_LNAME}") + endif() + endif() + endforeach() +endmacro() + +# Select a preferred imported configuration from a target +function(_HDF5_select_imported_config target imported_conf) + # We will first assign the value to a local variable _imported_conf, then assign + # it to the function argument at the end. + get_target_property(_imported_conf ${target} MAP_IMPORTED_CONFIG_${CMAKE_BUILD_TYPE}) + if (NOT _imported_conf) + # Get available imported configurations by examining target properties + get_target_property(_imported_conf ${target} IMPORTED_CONFIGURATIONS) + if(HDF5_FIND_DEBUG) + message(STATUS "Found imported configurations: ${_imported_conf}") + endif() + # Find the imported configuration that we prefer. + # We do this by making list of configurations in order of preference, + # starting with ${CMAKE_BUILD_TYPE} and ending with the first imported_conf + set(_preferred_confs ${CMAKE_BUILD_TYPE}) + list(GET _imported_conf 0 _fallback_conf) + list(APPEND _preferred_confs RELWITHDEBINFO RELEASE DEBUG ${_fallback_conf}) + if(HDF5_FIND_DEBUG) + message(STATUS "Start search through imported configurations in the following order: ${_preferred_confs}") + endif() + # Now find the first of these that is present in imported_conf + cmake_policy(PUSH) + cmake_policy(SET CMP0057 NEW) # support IN_LISTS + foreach (_conf IN LISTS _preferred_confs) + if (${_conf} IN_LIST _imported_conf) + set(_imported_conf ${_conf}) + break() + endif() + endforeach() + cmake_policy(POP) + endif() + if(HDF5_FIND_DEBUG) + message(STATUS "Selected imported configuration: ${_imported_conf}") + endif() + # assign value to function argument + set(${imported_conf} ${_imported_conf} PARENT_SCOPE) +endfunction() + + +if(NOT HDF5_ROOT) + set(HDF5_ROOT $ENV{HDF5_ROOT}) +endif() +if(HDF5_ROOT) + set(_HDF5_SEARCH_OPTS NO_DEFAULT_PATH) +else() + set(_HDF5_SEARCH_OPTS) +endif() + +# Try to find HDF5 using an installed hdf5-config.cmake +if(NOT HDF5_FOUND AND NOT HDF5_NO_FIND_PACKAGE_CONFIG_FILE) + find_package(HDF5 QUIET NO_MODULE + HINTS ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS} + ) + if( HDF5_FOUND) + if(HDF5_FIND_DEBUG) + message(STATUS "Found HDF5 at ${HDF5_DIR} via NO_MODULE. Now trying to extract locations etc.") + endif() + set(HDF5_IS_PARALLEL ${HDF5_ENABLE_PARALLEL}) + set(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR}) + set(HDF5_LIBRARIES) + if (NOT TARGET hdf5 AND NOT TARGET hdf5-static AND NOT TARGET hdf5-shared) + # Some HDF5 versions (e.g. 1.8.18) used hdf5::hdf5 etc + set(_target_prefix "hdf5::") + endif() + set(HDF5_C_TARGET ${_target_prefix}hdf5) + set(HDF5_C_HL_TARGET ${_target_prefix}hdf5_hl) + set(HDF5_CXX_TARGET ${_target_prefix}hdf5_cpp) + set(HDF5_CXX_HL_TARGET ${_target_prefix}hdf5_hl_cpp) + set(HDF5_Fortran_TARGET ${_target_prefix}hdf5_fortran) + set(HDF5_Fortran_HL_TARGET ${_target_prefix}hdf5_hl_fortran) + set(HDF5_DEFINITIONS "") + if(HDF5_USE_STATIC_LIBRARIES) + set(_suffix "-static") + else() + set(_suffix "-shared") + endif() + foreach(_lang ${HDF5_LANGUAGE_BINDINGS}) + + #Older versions of hdf5 don't have a static/shared suffix so + #if we detect that occurrence clear the suffix + if(_suffix AND NOT TARGET ${HDF5_${_lang}_TARGET}${_suffix}) + if(NOT TARGET ${HDF5_${_lang}_TARGET}) + #cant find this component with or without the suffix + #so bail out, and let the following locate HDF5 + set(HDF5_FOUND FALSE) + break() + endif() + set(_suffix "") + endif() + + if(HDF5_FIND_DEBUG) + message(STATUS "Trying to get properties of target ${HDF5_${_lang}_TARGET}${_suffix}") + endif() + # Find library for this target. Complicated as on Windows with a DLL, we need to search for the import-lib. + _HDF5_select_imported_config(${HDF5_${_lang}_TARGET}${_suffix} _hdf5_imported_conf) + get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} ) + if (NOT _hdf5_lang_location) + # no import lib, just try LOCATION + get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} LOCATION_${_hdf5_imported_conf}) + if (NOT _hdf5_lang_location) + get_target_property(_hdf5_lang_location ${HDF5_${_lang}_TARGET}${_suffix} LOCATION) + endif() + endif() + if( _hdf5_lang_location ) + set(HDF5_${_lang}_LIBRARY ${_hdf5_lang_location}) + list(APPEND HDF5_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_${_lang}_LIBRARIES ${HDF5_${_lang}_TARGET}${_suffix}) + set(HDF5_${_lang}_FOUND True) + endif() + if(FIND_HL) + get_target_property(__lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} IMPORTED_IMPLIB_${_hdf5_imported_conf} ) + if (NOT _hdf5_lang_hl_location) + get_target_property(_hdf5_lang_hl_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION_${_hdf5_imported_conf}) + if (NOT _hdf5_hl_lang_location) + get_target_property(_hdf5_hl_lang_location ${HDF5_${_lang}_HL_TARGET}${_suffix} LOCATION) + endif() + endif() + if( _hdf5_lang_hl_location ) + set(HDF5_${_lang}_HL_LIBRARY ${_hdf5_lang_hl_location}) + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${_lang}_HL_TARGET}${_suffix}) + set(HDF5_${_lang}_HL_LIBRARIES ${HDF5_${_lang}_HL_TARGET}${_suffix}) + set(HDF5_HL_FOUND True) + endif() + unset(_hdf5_lang_hl_location) + endif() + unset(_hdf5_imported_conf) + unset(_hdf5_lang_location) + endforeach() + endif() +endif() + +if(NOT HDF5_FOUND) + set(_HDF5_NEED_TO_SEARCH False) + set(HDF5_COMPILER_NO_INTERROGATE True) + # Only search for languages we've enabled + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + # First check to see if our regular compiler is one of wrappers + if(__lang STREQUAL "C") + _HDF5_test_regular_compiler_C( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_VERSION + HDF5_${__lang}_IS_PARALLEL) + elseif(__lang STREQUAL "CXX") + _HDF5_test_regular_compiler_CXX( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_VERSION + HDF5_${__lang}_IS_PARALLEL) + elseif(__lang STREQUAL "Fortran") + _HDF5_test_regular_compiler_Fortran( + HDF5_${__lang}_COMPILER_NO_INTERROGATE + HDF5_${__lang}_IS_PARALLEL) + else() + continue() + endif() + if(HDF5_${__lang}_COMPILER_NO_INTERROGATE) + message(STATUS "HDF5: Using hdf5 compiler wrapper for all ${__lang} compiling") + set(HDF5_${__lang}_FOUND True) + set(HDF5_${__lang}_COMPILER_EXECUTABLE_NO_INTERROGATE + "${CMAKE_${__lang}_COMPILER}" + CACHE FILEPATH "HDF5 ${__lang} compiler wrapper") + set(HDF5_${__lang}_DEFINITIONS) + set(HDF5_${__lang}_INCLUDE_DIRS) + set(HDF5_${__lang}_LIBRARIES) + set(HDF5_${__lang}_HL_LIBRARIES) + + mark_as_advanced(HDF5_${__lang}_COMPILER_EXECUTABLE_NO_INTERROGATE) + + set(HDF5_${__lang}_FOUND True) + set(HDF5_HL_FOUND True) + else() + set(HDF5_COMPILER_NO_INTERROGATE False) + # If this language isn't using the wrapper, then try to seed the + # search options with the wrapper + find_program(HDF5_${__lang}_COMPILER_EXECUTABLE + NAMES ${HDF5_${__lang}_COMPILER_NAMES} NAMES_PER_DIR + HINTS ${HDF5_ROOT} + PATH_SUFFIXES bin Bin + DOC "HDF5 ${__lang} Wrapper compiler. Used only to detect HDF5 compile flags." + ${_HDF5_SEARCH_OPTS} + ) + mark_as_advanced( HDF5_${__lang}_COMPILER_EXECUTABLE ) + unset(HDF5_${__lang}_COMPILER_NAMES) + + if(HDF5_${__lang}_COMPILER_EXECUTABLE) + _HDF5_invoke_compiler(${__lang} HDF5_${__lang}_COMPILE_LINE + HDF5_${__lang}_RETURN_VALUE HDF5_${__lang}_VERSION HDF5_${__lang}_IS_PARALLEL) + if(HDF5_${__lang}_RETURN_VALUE EQUAL 0) + message(STATUS "HDF5: Using hdf5 compiler wrapper to determine ${__lang} configuration") + _HDF5_parse_compile_line( HDF5_${__lang}_COMPILE_LINE + HDF5_${__lang}_INCLUDE_DIRS + HDF5_${__lang}_DEFINITIONS + HDF5_${__lang}_LIBRARY_DIRS + HDF5_${__lang}_LIBRARY_NAMES + HDF5_${__lang}_HL_LIBRARY_NAMES + ) + set(HDF5_${__lang}_LIBRARIES) + + foreach(L IN LISTS HDF5_${__lang}_LIBRARY_NAMES) + set(_HDF5_SEARCH_NAMES_LOCAL) + if("x${L}" MATCHES "hdf5") + # hdf5 library + set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS}) + if(HDF5_USE_STATIC_LIBRARIES) + if(WIN32) + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}) + else() + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}.a) + endif() + endif() + else() + # external library + set(_HDF5_SEARCH_OPTS_LOCAL) + endif() + find_library(HDF5_${__lang}_LIBRARY_${L} + NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${L} NAMES_PER_DIR + HINTS ${HDF5_${__lang}_LIBRARY_DIRS} + ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS_LOCAL} + ) + unset(_HDF5_SEARCH_OPTS_LOCAL) + unset(_HDF5_SEARCH_NAMES_LOCAL) + if(HDF5_${__lang}_LIBRARY_${L}) + list(APPEND HDF5_${__lang}_LIBRARIES ${HDF5_${__lang}_LIBRARY_${L}}) + else() + list(APPEND HDF5_${__lang}_LIBRARIES ${L}) + endif() + endforeach() + if(FIND_HL) + set(HDF5_${__lang}_HL_LIBRARIES) + foreach(L IN LISTS HDF5_${__lang}_HL_LIBRARY_NAMES) + set(_HDF5_SEARCH_NAMES_LOCAL) + if("x${L}" MATCHES "hdf5") + # hdf5 library + set(_HDF5_SEARCH_OPTS_LOCAL ${_HDF5_SEARCH_OPTS}) + if(HDF5_USE_STATIC_LIBRARIES) + if(WIN32) + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}) + else() + set(_HDF5_SEARCH_NAMES_LOCAL lib${L}.a) + endif() + endif() + else() + # external library + set(_HDF5_SEARCH_OPTS_LOCAL) + endif() + find_library(HDF5_${__lang}_LIBRARY_${L} + NAMES ${_HDF5_SEARCH_NAMES_LOCAL} ${L} NAMES_PER_DIR + HINTS ${HDF5_${__lang}_LIBRARY_DIRS} + ${HDF5_ROOT} + ${_HDF5_SEARCH_OPTS_LOCAL} + ) + unset(_HDF5_SEARCH_OPTS_LOCAL) + unset(_HDF5_SEARCH_NAMES_LOCAL) + if(HDF5_${__lang}_LIBRARY_${L}) + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${HDF5_${__lang}_LIBRARY_${L}}) + else() + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${L}) + endif() + endforeach() + set(HDF5_HL_FOUND True) + endif() + + set(HDF5_${__lang}_FOUND True) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_DEFINITIONS) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_${__lang}_HL_LIBRARIES) + else() + set(_HDF5_NEED_TO_SEARCH True) + endif() + else() + set(_HDF5_NEED_TO_SEARCH True) + endif() + endif() + if(HDF5_${__lang}_VERSION) + if(NOT HDF5_VERSION) + set(HDF5_VERSION ${HDF5_${__lang}_VERSION}) + elseif(NOT HDF5_VERSION VERSION_EQUAL HDF5_${__lang}_VERSION) + message(WARNING "HDF5 Version found for language ${__lang}, ${HDF5_${__lang}_VERSION} is different than previously found version ${HDF5_VERSION}") + endif() + endif() + if(DEFINED HDF5_${__lang}_IS_PARALLEL) + if(NOT DEFINED HDF5_IS_PARALLEL) + set(HDF5_IS_PARALLEL ${HDF5_${__lang}_IS_PARALLEL}) + elseif(NOT HDF5_IS_PARALLEL AND HDF5_${__lang}_IS_PARALLEL) + message(WARNING "HDF5 found for language ${__lang} is parallel but previously found language is not parallel.") + elseif(HDF5_IS_PARALLEL AND NOT HDF5_${__lang}_IS_PARALLEL) + message(WARNING "HDF5 found for language ${__lang} is not parallel but previously found language is parallel.") + endif() + endif() + endforeach() +else() + set(_HDF5_NEED_TO_SEARCH True) +endif() + +if(NOT HDF5_FOUND AND HDF5_COMPILER_NO_INTERROGATE) + # No arguments necessary, all languages can use the compiler wrappers + set(HDF5_FOUND True) + set(HDF5_METHOD "Included by compiler wrappers") + set(HDF5_REQUIRED_VARS HDF5_METHOD) +elseif(NOT HDF5_FOUND AND NOT _HDF5_NEED_TO_SEARCH) + # Compiler wrappers aren't being used by the build but were found and used + # to determine necessary include and library flags + set(HDF5_INCLUDE_DIRS) + set(HDF5_LIBRARIES) + set(HDF5_HL_LIBRARIES) + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + if(HDF5_${__lang}_FOUND) + if(NOT HDF5_${__lang}_COMPILER_NO_INTERROGATE) + list(APPEND HDF5_DEFINITIONS ${HDF5_${__lang}_DEFINITIONS}) + list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIRS}) + list(APPEND HDF5_LIBRARIES ${HDF5_${__lang}_LIBRARIES}) + if(FIND_HL) + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${__lang}_HL_LIBRARIES}) + endif() + endif() + endif() + endforeach() + _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS) + _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES) + set(HDF5_FOUND True) + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES) + if(FIND_HL) + list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES) + endif() +endif() + +find_program( HDF5_DIFF_EXECUTABLE + NAMES h5diff + HINTS ${HDF5_ROOT} + PATH_SUFFIXES bin Bin + ${_HDF5_SEARCH_OPTS} + DOC "HDF5 file differencing tool." ) +mark_as_advanced( HDF5_DIFF_EXECUTABLE ) + +if( NOT HDF5_FOUND ) + # seed the initial lists of libraries to find with items we know we need + set(HDF5_C_LIBRARY_NAMES hdf5) + set(HDF5_C_HL_LIBRARY_NAMES hdf5_hl) + + set(HDF5_CXX_LIBRARY_NAMES hdf5_cpp ${HDF5_C_LIBRARY_NAMES}) + set(HDF5_CXX_HL_LIBRARY_NAMES hdf5_hl_cpp ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_CXX_LIBRARY_NAMES}) + + set(HDF5_Fortran_LIBRARY_NAMES hdf5_fortran ${HDF5_C_LIBRARY_NAMES}) + set(HDF5_Fortran_HL_LIBRARY_NAMES hdf5hl_fortran ${HDF5_C_HL_LIBRARY_NAMES} ${HDF5_Fortran_LIBRARY_NAMES}) + + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + # find the HDF5 include directories + if("${__lang}" STREQUAL "Fortran") + set(HDF5_INCLUDE_FILENAME hdf5.mod) + elseif("${__lang}" STREQUAL "CXX") + set(HDF5_INCLUDE_FILENAME H5Cpp.h) + else() + set(HDF5_INCLUDE_FILENAME hdf5.h) + endif() + + find_path(HDF5_${__lang}_INCLUDE_DIR ${HDF5_INCLUDE_FILENAME} + HINTS ${HDF5_ROOT} + PATHS $ENV{HOME}/.local/include + PATH_SUFFIXES include Include + ${_HDF5_SEARCH_OPTS} + ) + mark_as_advanced(HDF5_${__lang}_INCLUDE_DIR) + # set the _DIRS variable as this is what the user will normally use + set(HDF5_${__lang}_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIR}) + list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIR}) + + # find the HDF5 libraries + foreach(LIB IN LISTS HDF5_${__lang}_LIBRARY_NAMES) + if(HDF5_USE_STATIC_LIBRARIES) + # According to bug 1643 on the CMake bug tracker, this is the + # preferred method for searching for a static library. + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search + # first for the full static library name, but fall back to a + # generic search on the name if the static search fails. + set( THIS_LIBRARY_SEARCH_DEBUG + lib${LIB}d.a lib${LIB}_debug.a lib${LIB}d lib${LIB}_D lib${LIB}_debug + lib${LIB}d-static.a lib${LIB}_debug-static.a ${LIB}d-static ${LIB}_D-static ${LIB}_debug-static ) + set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a lib${LIB} lib${LIB}-static.a ${LIB}-static) + else() + set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_D ${LIB}_debug ${LIB}d-shared ${LIB}_D-shared ${LIB}_debug-shared) + set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared) + if(WIN32) + list(APPEND HDF5_DEFINITIONS "-DH5_BUILT_AS_DYNAMIC_LIB") + endif() + endif() + find_library(HDF5_${LIB}_LIBRARY_DEBUG + NAMES ${THIS_LIBRARY_SEARCH_DEBUG} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + find_library( HDF5_${LIB}_LIBRARY_RELEASE + NAMES ${THIS_LIBRARY_SEARCH_RELEASE} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + select_library_configurations( HDF5_${LIB} ) + list(APPEND HDF5_${__lang}_LIBRARIES ${HDF5_${LIB}_LIBRARY}) + endforeach() + if(HDF5_${__lang}_LIBRARIES) + set(HDF5_${__lang}_FOUND True) + endif() + + # Append the libraries for this language binding to the list of all + # required libraries. + list(APPEND HDF5_LIBRARIES ${HDF5_${__lang}_LIBRARIES}) + + if(FIND_HL) + foreach(LIB IN LISTS HDF5_${__lang}_HL_LIBRARY_NAMES) + if(HDF5_USE_STATIC_LIBRARIES) + # According to bug 1643 on the CMake bug tracker, this is the + # preferred method for searching for a static library. + # See https://gitlab.kitware.com/cmake/cmake/issues/1643. We search + # first for the full static library name, but fall back to a + # generic search on the name if the static search fails. + set( THIS_LIBRARY_SEARCH_DEBUG + lib${LIB}d.a lib${LIB}_debug.a lib${LIB}d lib${LIB}_D lib${LIB}_debug + lib${LIB}d-static.a lib${LIB}_debug-static.a lib${LIB}d-static lib${LIB}_D-static lib${LIB}_debug-static ) + set( THIS_LIBRARY_SEARCH_RELEASE lib${LIB}.a ${LIB} lib${LIB}-static.a lib${LIB}-static) + else() + set( THIS_LIBRARY_SEARCH_DEBUG ${LIB}d ${LIB}_D ${LIB}_debug ${LIB}d-shared ${LIB}_D-shared ${LIB}_debug-shared) + set( THIS_LIBRARY_SEARCH_RELEASE ${LIB} ${LIB}-shared) + endif() + find_library(HDF5_${LIB}_LIBRARY_DEBUG + NAMES ${THIS_LIBRARY_SEARCH_DEBUG} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + find_library( HDF5_${LIB}_LIBRARY_RELEASE + NAMES ${THIS_LIBRARY_SEARCH_RELEASE} + HINTS ${HDF5_ROOT} PATH_SUFFIXES lib Lib + ${_HDF5_SEARCH_OPTS} + ) + select_library_configurations( HDF5_${LIB} ) + list(APPEND HDF5_${__lang}_HL_LIBRARIES ${HDF5_${LIB}_LIBRARY}) + endforeach() + + # Append the libraries for this language binding to the list of all + # required libraries. + list(APPEND HDF5_HL_LIBRARIES ${HDF5_${__lang}_HL_LIBRARIES}) + endif() + endforeach() + if(FIND_HL AND HDF5_HL_LIBRARIES) + set(HDF5_HL_FOUND True) + endif() + + _HDF5_remove_duplicates_from_beginning(HDF5_DEFINITIONS) + _HDF5_remove_duplicates_from_beginning(HDF5_INCLUDE_DIRS) + _HDF5_remove_duplicates_from_beginning(HDF5_LIBRARIES) + _HDF5_remove_duplicates_from_beginning(HDF5_HL_LIBRARIES) + + # If the HDF5 include directory was found, open H5pubconf.h to determine if + # HDF5 was compiled with parallel IO support + set( HDF5_IS_PARALLEL FALSE ) + set( HDF5_VERSION "" ) + foreach( _dir IN LISTS HDF5_INCLUDE_DIRS ) + foreach(_hdr "${_dir}/H5pubconf.h" "${_dir}/H5pubconf-64.h" "${_dir}/H5pubconf-32.h") + if( EXISTS "${_hdr}" ) + file( STRINGS "${_hdr}" + HDF5_HAVE_PARALLEL_DEFINE + REGEX "HAVE_PARALLEL 1" ) + if( HDF5_HAVE_PARALLEL_DEFINE ) + set( HDF5_IS_PARALLEL TRUE ) + endif() + unset(HDF5_HAVE_PARALLEL_DEFINE) + + file( STRINGS "${_hdr}" + HDF5_VERSION_DEFINE + REGEX "^[ \t]*#[ \t]*define[ \t]+H5_VERSION[ \t]+" ) + if( "${HDF5_VERSION_DEFINE}" MATCHES + "H5_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?\"" ) + set( HDF5_VERSION "${CMAKE_MATCH_1}" ) + if( CMAKE_MATCH_3 ) + set( HDF5_VERSION ${HDF5_VERSION}.${CMAKE_MATCH_3}) + endif() + endif() + unset(HDF5_VERSION_DEFINE) + endif() + endforeach() + endforeach() + set( HDF5_IS_PARALLEL ${HDF5_IS_PARALLEL} CACHE BOOL + "HDF5 library compiled with parallel IO support" ) + mark_as_advanced( HDF5_IS_PARALLEL ) + + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS) + if(FIND_HL) + list(APPEND HDF5_REQUIRED_VARS HDF5_HL_LIBRARIES) + endif() +endif() + +# For backwards compatibility we set HDF5_INCLUDE_DIR to the value of +# HDF5_INCLUDE_DIRS +if( HDF5_INCLUDE_DIRS ) + set( HDF5_INCLUDE_DIR "${HDF5_INCLUDE_DIRS}" ) +endif() + +# If HDF5_REQUIRED_VARS is empty at this point, then it's likely that +# something external is trying to explicitly pass already found +# locations +if(NOT HDF5_REQUIRED_VARS) + set(HDF5_REQUIRED_VARS HDF5_LIBRARIES HDF5_INCLUDE_DIRS) +endif() + +find_package_handle_standard_args(HDF5 + REQUIRED_VARS ${HDF5_REQUIRED_VARS} + VERSION_VAR HDF5_VERSION + HANDLE_COMPONENTS +) + +unset(_HDF5_SEARCH_OPTS) + +if( HDF5_FOUND AND NOT HDF5_DIR) + # hide HDF5_DIR for the non-advanced user to avoid confusion with + # HDF5_DIR-NOT_FOUND while HDF5 was found. + mark_as_advanced(HDF5_DIR) +endif() + +if (HDF5_FIND_DEBUG) + message(STATUS "HDF5_DIR: ${HDF5_DIR}") + message(STATUS "HDF5_DEFINITIONS: ${HDF5_DEFINITIONS}") + message(STATUS "HDF5_INCLUDE_DIRS: ${HDF5_INCLUDE_DIRS}") + message(STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}") + message(STATUS "HDF5_HL_LIBRARIES: ${HDF5_HL_LIBRARIES}") + foreach(__lang IN LISTS HDF5_LANGUAGE_BINDINGS) + message(STATUS "HDF5_${__lang}_DEFINITIONS: ${HDF5_${__lang}_DEFINITIONS}") + message(STATUS "HDF5_${__lang}_INCLUDE_DIR: ${HDF5_${__lang}_INCLUDE_DIR}") + message(STATUS "HDF5_${__lang}_INCLUDE_DIRS: ${HDF5_${__lang}_INCLUDE_DIRS}") + message(STATUS "HDF5_${__lang}_LIBRARY: ${HDF5_${__lang}_LIBRARY}") + message(STATUS "HDF5_${__lang}_LIBRARIES: ${HDF5_${__lang}_LIBRARIES}") + message(STATUS "HDF5_${__lang}_HL_LIBRARY: ${HDF5_${__lang}_HL_LIBRARY}") + message(STATUS "HDF5_${__lang}_HL_LIBRARIES: ${HDF5_${__lang}_HL_LIBRARIES}") + endforeach() +endif() diff --git a/cmake/upstream/GoogleTest.cmake b/cmake/upstream/GoogleTest.cmake index 944070ae16e2e37837893881d8be32bbdd2b8dc1..ba09bf6b278fd2cb4527a4fb249d569f9b2a8de3 100644 --- a/cmake/upstream/GoogleTest.cmake +++ b/cmake/upstream/GoogleTest.cmake @@ -14,6 +14,7 @@ This module defines functions to help use the Google Test infrastructure. gtest_add_tests(TARGET target [SOURCES src1...] + [EXEC_WRAPPER wrapper1...] [EXTRA_ARGS arg1...] [WORKING_DIRECTORY dir] [TEST_PREFIX prefix] @@ -31,6 +32,10 @@ This module defines functions to help use the Google Test infrastructure. this option is not given, the :prop_tgt:`SOURCES` property of the specified ``target`` will be used to obtain the list of sources. + ``EXEC_WRAPPER wrapper1...`` + Any extra arguments to pass on the command line before each test case. This + can be userful when the test case should be run in parallel. + ``EXTRA_ARGS arg1...`` Any extra arguments to pass on the command line to each test case. @@ -66,6 +71,7 @@ This module defines functions to help use the Google Test infrastructure. include(GoogleTest) add_executable(FooTest FooUnitTest.cxx) gtest_add_tests(TARGET FooTest + EXEC_WRAPPER mpirun -n 2 TEST_SUFFIX .noArgs TEST_LIST noArgsTests ) @@ -119,6 +125,7 @@ function(gtest_add_tests) ) set(multiValueArgs SOURCES + EXEC_WRAPPER EXTRA_ARGS ) set(allKeywords ${options} ${oneValueArgs} ${multiValueArgs}) @@ -182,6 +189,13 @@ function(gtest_add_tests) continue() endif() + # Wrap the test executable in another command if necessary + if (ARGS_EXEC_WRAPPER) + set(ctest_test_command ${ARGS_EXEC_WRAPPER} $<TARGET_FILE:${ARGS_TARGET}>) + else() + set(ctest_test_command ${ARGS_TARGET}) + endif() + # Make sure tests disabled in GTest get disabled in CTest if(gtest_test_name MATCHES "(^|\\.)DISABLED_") # Add the disabled test if CMake is new enough @@ -198,7 +212,7 @@ function(gtest_add_tests) ) add_test(NAME ${ctest_test_name} ${workDir} - COMMAND ${ARGS_TARGET} + COMMAND ${ctest_test_command} --gtest_also_run_disabled_tests --gtest_filter=${gtest_test_name} ${ARGS_EXTRA_ARGS} @@ -210,7 +224,7 @@ function(gtest_add_tests) set(ctest_test_name ${ARGS_TEST_PREFIX}${gtest_test_name}${ARGS_TEST_SUFFIX}) add_test(NAME ${ctest_test_name} ${workDir} - COMMAND ${ARGS_TARGET} + COMMAND ${ctest_test_command} --gtest_filter=${gtest_test_name} ${ARGS_EXTRA_ARGS} ) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7f606ea7fa4baf827cb634a1a8a63cd710ee4b26..978bc0d91a1c894ac29673554651ba46eb0669a7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(basics) add_subdirectory(hello) add_subdirectory(heatTransfer) +add_subdirectory(plugins) if(ADIOS2_BUILD_EXAMPLES_EXPERIMENTAL) add_subdirectory(experimental) diff --git a/examples/basics/globalArray/CMakeLists.txt b/examples/basics/globalArray/CMakeLists.txt index f9a9b07dd5bbc1c0361f0fe4930f2b0efcf76280..62192593245e554fb315dc3d56c18994d4661905 100644 --- a/examples/basics/globalArray/CMakeLists.txt +++ b/examples/basics/globalArray/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(globalArray_write globalArray_write.cpp) target_link_libraries(globalArray_write adios2) if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) target_include_directories(globalArray_write PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(globalArray_write ${MPI_C_LIBRARIES}) endif() diff --git a/examples/basics/joinedArray/CMakeLists.txt b/examples/basics/joinedArray/CMakeLists.txt index f8d775e84b3e6d09f3fb8aa2a8f8d67fc82e5c94..a0a7b06413911738666e6b968653cdb831ff9e26 100644 --- a/examples/basics/joinedArray/CMakeLists.txt +++ b/examples/basics/joinedArray/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(joinedArray_write joinedArray_write.cpp) target_link_libraries(joinedArray_write adios2) if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) target_include_directories(joinedArray_write PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(joinedArray_write ${MPI_C_LIBRARIES}) endif() diff --git a/examples/basics/localArray/CMakeLists.txt b/examples/basics/localArray/CMakeLists.txt index 3f46669a629802cc351bded5f4b4deb5df5d2bed..a42506de02aa74c4f4fef3c99c5c1e50e49ad19a 100644 --- a/examples/basics/localArray/CMakeLists.txt +++ b/examples/basics/localArray/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(localArray_write localArray_write.cpp) target_link_libraries(localArray_write adios2) if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) target_include_directories(localArray_write PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(localArray_write ${MPI_C_LIBRARIES}) endif() diff --git a/examples/basics/values/CMakeLists.txt b/examples/basics/values/CMakeLists.txt index 619fdc326200801d35c065ab42966996308600d3..79e27ea6077d0e3e04400245a5e3e13409ddb09b 100644 --- a/examples/basics/values/CMakeLists.txt +++ b/examples/basics/values/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(values_write values_write.cpp) target_link_libraries(values_write adios2) if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) target_include_directories(values_write PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(values_write ${MPI_C_LIBRARIES}) endif() diff --git a/examples/experimental/multistep/CMakeLists.txt b/examples/experimental/multistep/CMakeLists.txt index b5f75bb22f3288c69952fbe19fdb49be2f1ef53e..546074f51d6dc87c55e5ba822778e792953ae093 100644 --- a/examples/experimental/multistep/CMakeLists.txt +++ b/examples/experimental/multistep/CMakeLists.txt @@ -6,19 +6,12 @@ add_executable(writer_multistep writer_multistep.cpp) add_executable(reader_stepping reader_stepping.cpp) add_executable(reader_allsteps reader_allsteps.cpp) -target_link_libraries(writer_multistep adios2) -target_link_libraries(reader_stepping adios2) -target_link_libraries(reader_allsteps adios2) -if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) +foreach(tgt IN ITEMS writer_multistep reader_stepping reader_allsteps) + target_link_libraries(${tgt} adios2) - target_include_directories(writer_multistep PRIVATE ${MPI_C_INCLUDE_PATH}) - target_link_libraries(writer_multistep ${MPI_C_LIBRARIES}) - - target_include_directories(reader_stepping PRIVATE ${MPI_C_INCLUDE_PATH}) - target_link_libraries(reader_stepping ${MPI_C_LIBRARIES}) - - target_include_directories(reader_allsteps PRIVATE ${MPI_C_INCLUDE_PATH}) - target_link_libraries(reader_allsteps ${MPI_C_LIBRARIES}) -endif() + if(ADIOS2_HAVE_MPI) + target_include_directories(${tgt} PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(${tgt} ${MPI_C_LIBRARIES}) + endif() +endforeach() diff --git a/examples/experimental/runtimeconfig/hello/CMakeLists.txt b/examples/experimental/runtimeconfig/hello/CMakeLists.txt index 28adedce753ea338bbb3d6bea81987ab84f2de09..9770b299c4d377fdf6f0e8177c776db8dee817c5 100644 --- a/examples/experimental/runtimeconfig/hello/CMakeLists.txt +++ b/examples/experimental/runtimeconfig/hello/CMakeLists.txt @@ -1,6 +1,4 @@ if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(helloBPWriterXML helloBPWriterXML.cpp) target_include_directories(helloBPWriterXML PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(helloBPWriterXML ${MPI_C_LIBRARIES}) diff --git a/examples/heatTransfer/read/CMakeLists.txt b/examples/heatTransfer/read/CMakeLists.txt index 5691e81b41f61d55ba77f41243a350d6bc7c4f47..30797b43a01f63f8af4808f25d97ab50cfbeb772 100644 --- a/examples/heatTransfer/read/CMakeLists.txt +++ b/examples/heatTransfer/read/CMakeLists.txt @@ -4,21 +4,14 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) + add_executable(heatTransfer_read_adios2 heatRead_adios2.cpp PrintData.h) + target_include_directories(heatTransfer_read_adios2 + PRIVATE ${MPI_C_INCLUDE_PATH} + ) + target_link_libraries(heatTransfer_read_adios2 adios2 ${MPI_C_LIBRARIES}) if(ADIOS2_HAVE_ADIOS1) - - find_package(MPI COMPONENTS C REQUIRED) - find_package(ADIOS1 REQUIRED) - - add_executable(heatTransfer_read_adios2 heatRead_adios2.cpp PrintData.cpp) - target_include_directories(heatTransfer_read_adios2 - PRIVATE ${MPI_C_INCLUDE_PATH} - ) - target_link_libraries(heatTransfer_read_adios2 - adios2 ${MPI_C_LIBRARIES} - ) - - add_executable(heatTransfer_read_adios1 heatRead_adios1.cpp PrintData.cpp) + add_executable(heatTransfer_read_adios1 heatRead_adios1.cpp PrintData.h) target_include_directories(heatTransfer_read_adios1 PRIVATE ${MPI_C_INCLUDE_PATH} ) @@ -26,5 +19,4 @@ if(ADIOS2_HAVE_MPI) adios1::adios ${MPI_C_LIBRARIES} ) endif() - -endif() \ No newline at end of file +endif() diff --git a/examples/heatTransfer/read/PrintData.cpp b/examples/heatTransfer/read/PrintData.cpp deleted file mode 100644 index edbc6688fba93569b4d3eb9b74190735d9b21be7..0000000000000000000000000000000000000000 --- a/examples/heatTransfer/read/PrintData.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Distributed under the OSI-approved Apache License, Version 2.0. See - * accompanying file Copyright.txt for details. - * - * PrintData.cpp - * - * Created on: Apr 2017 - * Author: Norbert Podhorszki - */ - -#include <fstream> -#include <iomanip> -#include <iostream> -#include <string> - -#include "PrintData.h" - -void printData(double *xy, size_t *size, size_t *offset, int rank, int steps) -{ - std::ofstream myfile; - std::string filename = "data." + std::to_string(rank); - myfile.open(filename); - double *data = xy; - uint64_t nelems = size[0] * size[1]; - for (int step = 0; step < steps; step++) - { - myfile << "rank=" << rank << " size=" << size[0] << "x" << size[1] - << " offsets=" << offset[0] << ":" << offset[1] - << " step=" << step << std::endl; - - myfile << " time row columns " << offset[1] << "..." - << offset[1] + size[1] - 1 << std::endl; - myfile << " "; - for (int j = 0; j < size[1]; j++) - { - myfile << std::setw(9) << offset[1] + j; - } - myfile << std::endl; - myfile << "------------------------------------------------------------" - "--\n"; - for (int i = 0; i < size[0]; i++) - { - myfile << std::setw(5) << step << std::setw(5) << offset[0] + i; - for (int j = 0; j < size[1]; j++) - { - myfile << std::setw(9) << std::setprecision(2) - << data[i * size[1] + j]; - } - myfile << std::endl; - } - data += nelems; - } - myfile.close(); -} - -void printData(double *xy, uint64_t *size, uint64_t *offset, int rank, - int steps) -{ - std::ofstream myfile; - std::string filename = "data." + std::to_string(rank); - myfile.open(filename); - double *data = xy; - uint64_t nelems = size[0] * size[1]; - for (int step = 0; step < steps; step++) - { - myfile << "rank=" << rank << " size=" << size[0] << "x" << size[1] - << " offsets=" << offset[0] << ":" << offset[1] - << " step=" << step << std::endl; - - myfile << " time row columns " << offset[1] << "..." - << offset[1] + size[1] - 1 << std::endl; - myfile << " "; - for (int j = 0; j < size[1]; j++) - { - myfile << std::setw(9) << offset[1] + j; - } - myfile << std::endl; - myfile << "------------------------------------------------------------" - "--\n"; - for (int i = 0; i < size[0]; i++) - { - myfile << std::setw(5) << step << std::setw(5) << offset[0] + i; - for (int j = 0; j < size[1]; j++) - { - myfile << std::setw(9) << std::setprecision(2) - << data[i * size[1] + j]; - } - myfile << std::endl; - } - data += nelems; - } - myfile.close(); -} diff --git a/examples/heatTransfer/read/PrintData.h b/examples/heatTransfer/read/PrintData.h index 13e1e527ce1a27036d0f65c540be48a459b3b3eb..f18948af619cae90f15eabdc0073d46612e37577 100644 --- a/examples/heatTransfer/read/PrintData.h +++ b/examples/heatTransfer/read/PrintData.h @@ -12,9 +12,48 @@ #define PRINTDATA_H_ #include <cstdint> +#include <fstream> +#include <iomanip> +#include <iostream> +#include <string> -void printData(double *xy, size_t *size, size_t *offset, int rank, int steps); -void printData(double *xy, uint64_t *size, uint64_t *offset, int rank, - int steps); +template <class T> +void printData(double *xy, T *size, T *offset, int rank, int steps) +{ + std::ofstream myfile; + std::string filename = "data." + std::to_string(rank); + myfile.open(filename); + double *data = xy; + uint64_t nelems = size[0] * size[1]; + for (int step = 0; step < steps; step++) + { + myfile << "rank=" << rank << " size=" << size[0] << "x" << size[1] + << " offsets=" << offset[0] << ":" << offset[1] + << " step=" << step << std::endl; + + myfile << " time row columns " << offset[1] << "..." + << offset[1] + size[1] - 1 << std::endl; + myfile << " "; + for (int j = 0; j < size[1]; j++) + { + myfile << std::setw(9) << offset[1] + j; + } + myfile << std::endl; + myfile << "------------------------------------------------------------" + "--\n"; + for (int i = 0; i < size[0]; i++) + { + myfile << std::setw(5) << step << std::setw(5) << offset[0] + i; + for (int j = 0; j < size[1]; j++) + { + myfile << std::setw(9) << std::setprecision(2) + << data[i * size[1] + j]; + } + myfile << std::endl; + } + data += nelems; + } + myfile.close(); +} #endif /* PRINTDATA_H_ */ diff --git a/examples/heatTransfer/write/CMakeLists.txt b/examples/heatTransfer/write/CMakeLists.txt index a40186bb05e6d8225d73d5d58fea4fc380de47b6..a6c459bca092e6f0c706f982e7b17a36f04caeab 100644 --- a/examples/heatTransfer/write/CMakeLists.txt +++ b/examples/heatTransfer/write/CMakeLists.txt @@ -4,9 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - find_package(Threads REQUIRED) - add_executable(heatTransfer_write_adios2 main.cpp HeatTransfer.cpp @@ -16,15 +13,14 @@ if(ADIOS2_HAVE_MPI) target_include_directories(heatTransfer_write_adios2 PRIVATE ${MPI_C_INCLUDE_PATH} ) - target_link_libraries(heatTransfer_write_adios2 adios2 ${MPI_C_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(heatTransfer_write_adios2 + adios2 ${MPI_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ) target_compile_definitions(heatTransfer_write_adios2 PRIVATE - -DDEFAULT_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/config.xml) + -DDEFAULT_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/config.xml + ) if(ADIOS2_HAVE_ADIOS1) - find_package(ADIOS1 REQUIRED) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(heatTransfer_write_adios1 main.cpp HeatTransfer.cpp @@ -40,9 +36,6 @@ if(ADIOS2_HAVE_MPI) endif() if(ADIOS2_HAVE_HDF5) - find_package(HDF5 REQUIRED) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(heatTransfer_write_hdf5 main.cpp HeatTransfer.cpp @@ -53,14 +46,8 @@ if(ADIOS2_HAVE_MPI) PRIVATE ${MPI_C_INCLUDE_PATH} ${HDF5_C_INCLUDE_DIRS} ) target_link_libraries(heatTransfer_write_hdf5 - ${MPI_C_LIBRARIES} ${HDF5_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ${HDF5_C_LIBRARIES} ${MPI_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) - endif() - - - if(ADIOS2_HAVE_HDF5) - find_package(HDF5 REQUIRED) - find_package(MPI COMPONENTS C REQUIRED) add_executable(heatTransfer_write_ph5 main.cpp @@ -72,15 +59,10 @@ if(ADIOS2_HAVE_MPI) PRIVATE ${MPI_C_INCLUDE_PATH} ${HDF5_C_INCLUDE_DIRS} ) target_link_libraries(heatTransfer_write_ph5 - ${MPI_C_LIBRARIES} ${HDF5_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ${HDF5_C_LIBRARIES} ${MPI_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) - endif() - - - if(ADIOS2_HAVE_HDF5) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(heatTransfer_write_a2h5 + add_executable(heatTransfer_write_a2h5 main.cpp HeatTransfer.cpp Settings.cpp @@ -90,12 +72,8 @@ if(ADIOS2_HAVE_MPI) target_include_directories(heatTransfer_write_a2h5 PRIVATE ${MPI_C_INCLUDE_PATH} ) - #target_link_libraries(heatTransfer_write_a2h5 - # ${MPI_C_LIBRARIES} - #) - target_link_libraries(heatTransfer_write_a2h5 PUBLIC adios2 - ${CMAKE_THREAD_LIBS_INIT}) - + target_link_libraries(heatTransfer_write_a2h5 + adios2 ${MPI_C_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ) endif() - endif() diff --git a/examples/hello/CMakeLists.txt b/examples/hello/CMakeLists.txt index 2850407da804fce34afa2c23bdfce603865e4795..e01daa485f2ba9171b37d39f652613552a6bbcd8 100644 --- a/examples/hello/CMakeLists.txt +++ b/examples/hello/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(bpWriter) add_subdirectory(bpTimeWriter) add_subdirectory(bpFlushWriter) +add_subdirectory(bpAttributeWriter) if(ADIOS2_HAVE_ADIOS1) add_subdirectory(adios1Writer) diff --git a/examples/hello/adios1Writer/CMakeLists.txt b/examples/hello/adios1Writer/CMakeLists.txt index f8e52ae9d22e385cf061ed92d8352f301e1815e0..3b5c016b66047fb21944652f17969120c67420c4 100644 --- a/examples/hello/adios1Writer/CMakeLists.txt +++ b/examples/hello/adios1Writer/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_adios1Writer helloADIOS1Writer.cpp) target_include_directories(hello_adios1Writer PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_adios1Writer ${MPI_C_LIBRARIES}) diff --git a/examples/hello/bpAttributeWriter/CMakeLists.txt b/examples/hello/bpAttributeWriter/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..30faba4aff8d91e37bd65cb2e6792876200636d3 --- /dev/null +++ b/examples/hello/bpAttributeWriter/CMakeLists.txt @@ -0,0 +1,18 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +if(ADIOS2_HAVE_MPI) + find_package(MPI COMPONENTS C REQUIRED) + + add_executable(hello_bpAttributeWriter helloBPAttributeWriter.cpp) + target_include_directories(hello_bpAttributeWriter PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(hello_bpAttributeWriter ${MPI_C_LIBRARIES}) + +else() + add_executable(hello_bpAttributeWriter helloBPAttributeWriter_nompi.cpp) + +endif() + +target_link_libraries(hello_bpAttributeWriter adios2) diff --git a/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp b/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7061f1db3a7ffdc19c96bb5afe47e4c2f3c28288 --- /dev/null +++ b/examples/hello/bpAttributeWriter/helloBPAttributeWriter.cpp @@ -0,0 +1,95 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * helloBPWriter.cpp: Simple self-descriptive example of how to write a variable + * to a BP File that lives in several MPI processes. + * + * Created on: Feb 16, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include <ios> //std::ios_base::failure +#include <iostream> //std::cout +#include <mpi.h> +#include <stdexcept> //std::invalid_argument std::exception +#include <string> +#include <vector> + +#include <adios2.h> + +int main(int argc, char *argv[]) +{ + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + /** Application variable */ + std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const std::size_t Nx = myFloats.size(); + + try + { + /** ADIOS class factory of IO class objects, DebugON is recommended */ + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); + + /*** IO class object: settings and factory of Settings: Variables, + * Parameters, Transports, and Execution: Engines */ + adios2::IO &bpIO = adios.DeclareIO("BPFile_N2N"); + + /** global array : name, { shape (total) }, { start (local) }, { count + * (local) }, all are constant dimensions */ + adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>( + "bpFloats", {size * Nx}, {rank * Nx}, {Nx}, adios2::ConstantDims); + + bpIO.DefineAttribute<std::string>("Single_String", + "File generated with ADIOS2"); + + std::vector<std::string> myStrings = {"one", "two", "three"}; + bpIO.DefineAttribute<std::string>("Array_of_Strings", myStrings.data(), + myStrings.size()); + + bpIO.DefineAttribute<double>("Attr_Double", 0.f); + std::vector<double> myDoubles = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + bpIO.DefineAttribute<double>("Array_of_Doubles", myDoubles.data(), + myDoubles.size()); + + /** Engine derived class, spawned to start IO operations */ + auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write); + + if (!bpWriter) + { + throw std::ios_base::failure( + "ERROR: bpWriter not created at Open\n"); + } + + /** Write variable for buffering */ + bpWriter->Write<float>(bpFloats, myFloats.data()); + + /** Create bp file, engine becomes unreachable after this*/ + bpWriter->Close(); + } + catch (std::invalid_argument &e) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM from rank " + << rank << "\n"; + std::cout << e.what() << "\n"; + } + catch (std::ios_base::failure &e) + { + std::cout + << "IO System base failure exception, STOPPING PROGRAM from rank " + << rank << "\n"; + std::cout << e.what() << "\n"; + } + catch (std::exception &e) + { + std::cout << "Exception, STOPPING PROGRAM from rank " << rank << "\n"; + std::cout << e.what() << "\n"; + } + + MPI_Finalize(); + + return 0; +} diff --git a/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp b/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..850d907ea325fa9348c29c910c1b074030c36716 --- /dev/null +++ b/examples/hello/bpAttributeWriter/helloBPAttributeWriter_nompi.cpp @@ -0,0 +1,83 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * helloBPWriter_nompi.cpp sequential non-mpi version of helloBPWriter + * + * Created on: Jan 9, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include <ios> //std::ios_base::failure +#include <iostream> //std::cout +#include <stdexcept> //std::invalid_argument std::exception +#include <string> +#include <vector> + +#include <adios2.h> + +int main(int argc, char *argv[]) +{ + /** Application variable */ + std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const std::size_t Nx = myFloats.size(); + + try + { + /** ADIOS class factory of IO class objects, DebugON is recommended */ + adios2::ADIOS adios(adios2::DebugON); + + /*** IO class object: settings and factory of Settings: Variables, + * Parameters, Transports, and Execution: Engines */ + adios2::IO &bpIO = adios.DeclareIO("BPFile_N2N"); + + /** global array: name, { shape (total dimensions) }, { start (local) }, + * { count (local) }, all are constant dimensions */ + adios2::Variable<float> &bpFloats = bpIO.DefineVariable<float>( + "bpFloats", {}, {}, {Nx}, adios2::ConstantDims); + + bpIO.DefineAttribute<std::string>("Single_String", + "File generated with ADIOS2"); + + std::vector<std::string> myStrings = {"one", "two", "three"}; + bpIO.DefineAttribute<std::string>("Array_of_Strings", myStrings.data(), + myStrings.size()); + + bpIO.DefineAttribute<double>("Attr_Double", 0.f); + std::vector<double> myDoubles = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + bpIO.DefineAttribute<double>("Array_of_Doubles", myDoubles.data(), + myDoubles.size()); + + /** Engine derived class, spawned to start IO operations */ + auto bpWriter = bpIO.Open("myVector.bp", adios2::OpenMode::Write); + + if (!bpWriter) + { + throw std::ios_base::failure( + "ERROR: bpWriter not created at Open\n"); + } + + /** Write variable for buffering */ + bpWriter->Write<float>(bpFloats, myFloats.data()); + + /** Create bp file, engine becomes unreachable after this*/ + bpWriter->Close(); + } + catch (std::invalid_argument &e) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::ios_base::failure &e) + { + std::cout << "IO System base failure exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::exception &e) + { + std::cout << "Exception, STOPPING PROGRAM from rank\n"; + std::cout << e.what() << "\n"; + } + + return 0; +} diff --git a/examples/hello/bpBZip2Wrapper/CMakeLists.txt b/examples/hello/bpBZip2Wrapper/CMakeLists.txt index 3803a998a7103673cdee602633c71a03a049da24..702d5aaeb3383508227210f076aec4f43b7b117b 100644 --- a/examples/hello/bpBZip2Wrapper/CMakeLists.txt +++ b/examples/hello/bpBZip2Wrapper/CMakeLists.txt @@ -4,15 +4,11 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_bpBZip2Wrapper helloBPBZip2Wrapper.cpp) target_include_directories(hello_bpBZip2Wrapper PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_bpBZip2Wrapper ${MPI_C_LIBRARIES}) - else() add_executable(hello_bpBZip2Wrapper helloBPBZip2Wrapper_nompi.cpp) - endif() target_link_libraries(hello_bpBZip2Wrapper adios2) diff --git a/examples/hello/bpFlushWriter/CMakeLists.txt b/examples/hello/bpFlushWriter/CMakeLists.txt index ed554a4b4b9abfe17688da507e286371b10535b0..777704ef21ea820ac6d928dedb869fd323ea495c 100644 --- a/examples/hello/bpFlushWriter/CMakeLists.txt +++ b/examples/hello/bpFlushWriter/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_bpFlushWriter helloBPFlushWriter.cpp) target_include_directories(hello_bpFlushWriter PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_bpFlushWriter ${MPI_C_LIBRARIES}) diff --git a/examples/hello/bpTimeWriter/CMakeLists.txt b/examples/hello/bpTimeWriter/CMakeLists.txt index 30551c498bc783e88054ed85c1e90ef5acd51e19..68834e2887d52954186e6f5e6b9d20b70ed38ec9 100644 --- a/examples/hello/bpTimeWriter/CMakeLists.txt +++ b/examples/hello/bpTimeWriter/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_bpTimeWriter helloBPTimeWriter.cpp) target_include_directories(hello_bpTimeWriter PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_bpTimeWriter ${MPI_C_LIBRARIES}) diff --git a/examples/hello/bpWriter/CMakeLists.txt b/examples/hello/bpWriter/CMakeLists.txt index c252a25e6409a13177f7172b21962f93d33e0677..8c834597ac2748dc398d3323c4cac038a179d674 100644 --- a/examples/hello/bpWriter/CMakeLists.txt +++ b/examples/hello/bpWriter/CMakeLists.txt @@ -4,15 +4,37 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_bpWriter helloBPWriter.cpp) target_include_directories(hello_bpWriter PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_bpWriter ${MPI_C_LIBRARIES}) + add_executable(hello_bpWriter_c helloBPWriter.c) + target_include_directories(hello_bpWriter_c PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(hello_bpWriter_c ${MPI_C_LIBRARIES}) + + if(ADIOS2_HAVE_Fortran) + add_executable(hello_bpWriter_f helloBPWriter.f90) + target_include_directories(hello_bpWriter_f + PRIVATE ${MPI_Fortran_INCLUDE_PATH} + ${MPI_C_INCLUDE_PATH}) + + target_link_libraries(hello_bpWriter_f PRIVATE ${MPI_Fortran_LIBRARIES} + ${MPI_C_LIBRARIES}) + endif() + else() add_executable(hello_bpWriter helloBPWriter_nompi.cpp) + add_executable(hello_bpWriter_c helloBPWriter_nompi.c) + + if(ADIOS2_HAVE_Fortran) + add_executable(hello_bpWriter_f helloBPWriter_nompi.f90) + endif() endif() target_link_libraries(hello_bpWriter adios2) +target_link_libraries(hello_bpWriter_c adios2) + +if(ADIOS2_HAVE_Fortran) + target_link_libraries(hello_bpWriter_f PRIVATE adios2_f) +endif() diff --git a/examples/hello/bpWriter/helloBPWriter.c b/examples/hello/bpWriter/helloBPWriter.c new file mode 100644 index 0000000000000000000000000000000000000000..6bc7f45d3b25ce48244d6e24006b44d330f3246e --- /dev/null +++ b/examples/hello/bpWriter/helloBPWriter.c @@ -0,0 +1,61 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * helloBPWriter.c : C bindings version of C++11 helloBPWriter.cpp + * + * Created on: Aug 8, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ +#include <mpi.h> +#include <stdlib.h> // malloc, free + +#include <adios2_c.h> + +int main(int argc, char *argv[]) +{ + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + // application input, data in heap + const size_t Nx = 10; + float *myFloats; + myFloats = malloc(sizeof(float) * Nx); + + unsigned int i; + for (i = 0; i < Nx; ++i) + { + myFloats[i] = i; + } + + adios2_ADIOS *adiosH = adios2_init(MPI_COMM_WORLD, adios2_debug_mode_on); + adios2_IO *ioH = adios2_declare_io(adiosH, "BPFile_N2N"); + + // dims are allocated in stack + size_t shape[1]; + shape[0] = (size_t)size * Nx; + + size_t start[1]; + start[0] = (size_t)rank * Nx; + + size_t count[1]; + count[0] = Nx; + + adios2_Variable *variableH = + adios2_define_variable(ioH, "bpFloats", adios2_type_float, 1, shape, + start, count, adios2_constant_dims_true); + adios2_Engine *engineH = + adios2_open(ioH, "myVector_c.bp", adios2_open_mode_write); + + adios2_write(engineH, variableH, myFloats); + adios2_close(engineH); + adios2_finalize(adiosH); + + free(myFloats); + + MPI_Finalize(); + + return 0; +} diff --git a/examples/hello/bpWriter/helloBPWriter.f90 b/examples/hello/bpWriter/helloBPWriter.f90 new file mode 100644 index 0000000000000000000000000000000000000000..5ae00add8615f36f772cb9071581ed1efa4d2207 --- /dev/null +++ b/examples/hello/bpWriter/helloBPWriter.f90 @@ -0,0 +1,56 @@ +program helloBPWriter + use mpi + use adios2 + + implicit none + + integer, dimension(1) :: shape_dims, start_dims, count_dims + real, dimension(:), allocatable :: myArray + integer :: inx, irank, isize, ierr, i + integer(kind=8) :: adios, io, var1, engine1 + + ! Launch MPI + call MPI_Init(ierr) + call MPI_Comm_rank(MPI_COMM_WORLD, irank, ierr) + call MPI_Comm_size(MPI_COMM_WORLD, isize, ierr) + + ! Application variables + inx = 10 + allocate( myArray(inx) ) + + do i=1,inx + myArray(i) = i-1 + end do + + ! Variable dimensions + shape_dims(1) = isize * inx + start_dims(1) = irank * inx + count_dims(1) = inx + + ! Create adios handler passing the communicator, debug mode and error flag + call adios2_init(adios, MPI_COMM_WORLD, adios2_debug_mode_on, ierr) + + ! Declare an IO process configuration inside adios + call adios2_declare_io(io, adios, "bpIO", ierr) + + ! Defines a variable to be written in bp format + call adios2_define_variable(var1, io, "myArray", adios2_type_real, 1, & + & shape_dims, start_dims, count_dims, adios2_constant_dims_true, ierr) + + ! Open myVector_f.bp in write mode, this launches an engine + call adios2_open(engine1, io, "myVector_f.bp", adios2_open_mode_write, ierr) + + ! Write myArray contents to bp buffer, based on var1 metadata + call adios2_write(engine1, var1, myArray, ierr) + + ! Closes engine1 and deallocates it, becomes unreachable + call adios2_close(engine1, ierr) + + ! Deallocates adios and calls its destructor + call adios2_finalize(adios, ierr) + + deallocate(myArray) + + call MPI_Finalize(ierr) + +end program helloBPWriter diff --git a/examples/hello/bpWriter/helloBPWriter_nompi.c b/examples/hello/bpWriter/helloBPWriter_nompi.c new file mode 100644 index 0000000000000000000000000000000000000000..c86e78be613f4e9c2a59b7fbb69cb48fa442f896 --- /dev/null +++ b/examples/hello/bpWriter/helloBPWriter_nompi.c @@ -0,0 +1,48 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * helloBPWriter_nompi.c : C bindings version of C++11 helloBPWriter_nompi.cpp + * + * Created on: Aug 8, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include <stdlib.h> //malloc, free + +#include <adios2_c.h> + +int main(int argc, char *argv[]) +{ + // application input, data in heap + const size_t Nx = 10; + float *myFloats; + myFloats = malloc(sizeof(float) * Nx); + + unsigned int i; + for (i = 0; i < Nx; ++i) + { + myFloats[i] = i; + } + + adios2_ADIOS *adiosH = adios2_init_nompi(adios2_debug_mode_on); + adios2_IO *ioH = adios2_declare_io(adiosH, "BPFile_N2N"); + + // count dims are allocated in stack + size_t count[1]; + count[0] = Nx; + + adios2_Variable *variableH = + adios2_define_variable(ioH, "bpFloats", adios2_type_float, 1, NULL, + NULL, count, adios2_constant_dims_true); + adios2_Engine *engineH = + adios2_open(ioH, "myVector_c.bp", adios2_open_mode_write); + + adios2_write(engineH, variableH, myFloats); + adios2_close(engineH); + adios2_finalize(adiosH); + + free(myFloats); + + return 0; +} diff --git a/examples/hello/bpWriter/helloBPWriter_nompi.f90 b/examples/hello/bpWriter/helloBPWriter_nompi.f90 new file mode 100644 index 0000000000000000000000000000000000000000..22268da83bfeae474ea2ea1922e2f78065e71f35 --- /dev/null +++ b/examples/hello/bpWriter/helloBPWriter_nompi.f90 @@ -0,0 +1,48 @@ +program helloBPWriter + + use adios2 + + implicit none + + integer :: inx, i, ierr + integer(kind=8) :: adios, io, var1, engine1 + real, dimension(:), allocatable :: myArray + integer, dimension(1) :: shape_dims, start_dims, count_dims + + !application variables + inx = 10 + allocate( myArray(inx) ) + + do i=1,inx + myArray(i) = i-1 + end do + + shape_dims(1) = inx + start_dims(1) = 0 + count_dims(1) = inx + + ! Initialize adios handler + call adios2_init(adios, adios2_debug_mode_on, ierr) + + ! Declare an IO configuration inside adios + call adios2_declare_io(io, adios, "bpIO", ierr) + + ! Defines variable metadata to be written in bp file + call adios2_define_variable(var1, io, "myArray", adios2_type_real, 1, & + & shape_dims, start_dims, count_dims, adios2_constant_dims_true, ierr) + + ! Open myVector_f.bp in write mode + call adios2_open(engine1, io, "myVector_f.bp", adios2_open_mode_write, ierr) + + ! Write myArray contents to bp buffer, based on var1 metadata + call adios2_write(engine1, var1, myArray, ierr) + + ! Closes engine1 and deallocates it, becomes unreachable + call adios2_close(engine1, ierr) + + ! Deallocates adios and calls its destructor + call adios2_finalize(adios, ierr) + + deallocate(myArray) + +end program helloBPWriter diff --git a/examples/hello/bpZfpWrapper/CMakeLists.txt b/examples/hello/bpZfpWrapper/CMakeLists.txt index c5cb52b74f20dc3bdced1ea0e63a5a5373a33329..c6802384e091d450d900ddb90599ab707dde5a9c 100644 --- a/examples/hello/bpZfpWrapper/CMakeLists.txt +++ b/examples/hello/bpZfpWrapper/CMakeLists.txt @@ -4,15 +4,12 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_bpZfpWrapper helloBPZfpWrapper.cpp) target_include_directories(hello_bpZfpWrapper PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_bpZfpWrapper ${MPI_C_LIBRARIES}) else() add_executable(hello_bpZfpWrapper helloBPZfpWrapper_nompi.cpp) - endif() target_link_libraries(hello_bpZfpWrapper adios2) diff --git a/examples/hello/datamanReader/CMakeLists.txt b/examples/hello/datamanReader/CMakeLists.txt index f180c9062b4c74d2b9a3cd21098c539cf1d3293f..1c1baa846fe64e3357d0a82b90354cca50cccde7 100644 --- a/examples/hello/datamanReader/CMakeLists.txt +++ b/examples/hello/datamanReader/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_datamanReader helloDataManReader.cpp) target_include_directories(hello_datamanReader PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_datamanReader ${MPI_C_LIBRARIES}) diff --git a/examples/hello/datamanWriter/CMakeLists.txt b/examples/hello/datamanWriter/CMakeLists.txt index 3e5c955837a67d596a6c515577ec52a6af466154..4a41f3e730d4032f05c09dffe7c381cf6d7cc917 100644 --- a/examples/hello/datamanWriter/CMakeLists.txt +++ b/examples/hello/datamanWriter/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_datamanWriter helloDataManWriter.cpp) target_include_directories(hello_datamanWriter PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_datamanWriter ${MPI_C_LIBRARIES}) diff --git a/examples/hello/hdf5Writer/CMakeLists.txt b/examples/hello/hdf5Writer/CMakeLists.txt index a2f7e6abd8d2bb83c1eca0f4e0bc9219e9b99dc2..d5d4311250ddd6cd76a2909f88d53ea17da3eb81 100644 --- a/examples/hello/hdf5Writer/CMakeLists.txt +++ b/examples/hello/hdf5Writer/CMakeLists.txt @@ -4,8 +4,6 @@ #------------------------------------------------------------------------------# if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) - add_executable(hello_hdf5Writer helloHDF5Writer.cpp) target_include_directories(hello_hdf5Writer PRIVATE ${MPI_C_INCLUDE_PATH}) target_link_libraries(hello_hdf5Writer ${MPI_C_LIBRARIES}) diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd9914576866a2c9a4c1c4a6d7766e3d65acde19 --- /dev/null +++ b/examples/plugins/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(engine) diff --git a/examples/plugins/engine/CMakeLists.txt b/examples/plugins/engine/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..37b3215da513cf1d15f56679ce14174ecd764d8c --- /dev/null +++ b/examples/plugins/engine/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(examplePluginEngine_class + examplePluginEngine_class.cpp + ExampleEnginePlugin.h ExampleEnginePlugin.cpp +) +target_link_libraries(examplePluginEngine_class adios2) diff --git a/examples/plugins/engine/ExampleEnginePlugin.cpp b/examples/plugins/engine/ExampleEnginePlugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fdbf85b04035e9cd9c0f29712ec952f9825b000 --- /dev/null +++ b/examples/plugins/engine/ExampleEnginePlugin.cpp @@ -0,0 +1,106 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleEnginePlugin.cpp This plugin does nothing but write API calls out to a + * log file. + * + * Created on: Jul 31, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#include "ExampleEnginePlugin.h" + +#include <cstdio> +#include <cstring> +#include <ctime> + +#ifndef _WIN32 +#include <sys/time.h> +#endif + +namespace +{ +std::string now() +{ + tm *timeInfo; +#ifdef _WIN32 + time_t rawTime; + std::time(&rawTime); + timeInfo = std::localtime(&rawTime); +#else + timeval curTime; + gettimeofday(&curTime, nullptr); + timeInfo = std::localtime(&curTime.tv_sec); +#endif + + char timeBuf[80]; + std::memset(timeBuf, 0, sizeof(timeBuf)); + std::strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%dT%H:%M:%S", timeInfo); + +#ifdef _WIN32 + return std::string(timeBuf); +#else + double subSec = curTime.tv_usec / 1e6; + char subSecBuf[9]; + std::memset(subSecBuf, 0, sizeof(subSecBuf)); + std::sprintf(subSecBuf, "%1.6f", subSec); + return std::string(timeBuf) + std::string(&subSecBuf[1]); +#endif +} +} + +namespace adios2 +{ + +ExampleEnginePlugin::ExampleEnginePlugin(IO &io, const std::string &name, + const OpenMode openMode, + MPI_Comm mpiComm) +: adios2::PluginEngineInterface(io, name, openMode, mpiComm) +{ + Init(); +} + +ExampleEnginePlugin::~ExampleEnginePlugin() { m_Log.close(); } + +void ExampleEnginePlugin::Close(const int transportIndex) +{ + m_Log << now() << " Close with transportIndex " << transportIndex + << std::endl; +} + +void ExampleEnginePlugin::Init() +{ + std::string logName = "ExamplePlugin.log"; + auto paramLogNameIt = m_IO.m_Parameters.find("LogName"); + if (paramLogNameIt != m_IO.m_Parameters.end()) + { + logName = paramLogNameIt->second; + } + + m_Log.open(logName); + if (!m_Log) + { + throw std::ios_base::failure( + "ExampleEnginePlugin: Failed to open log file " + logName); + } + + m_Log << now() << " Init" << std::endl; +} + +#define define(T) \ + void ExampleEnginePlugin::DoWrite(Variable<T> &variable, const T *values) \ + { \ + m_Log << now() << " Writing variable \"" << variable.m_Name << "\"" \ + << std::endl; \ + } +ADIOS2_FOREACH_TYPE_1ARG(define) +#undef define +void ExampleEnginePlugin::DoWrite(VariableCompound &variable, + const void *values) +{ + m_Log << now() << " Writing variable \"" << variable.m_Name << "\"" + << std::endl; +} + +} // end namespace adios2 diff --git a/examples/plugins/engine/ExampleEnginePlugin.h b/examples/plugins/engine/ExampleEnginePlugin.h new file mode 100644 index 0000000000000000000000000000000000000000..aa81d0a1aa1c9e906d0dcaeb4ca91a7ab710e446 --- /dev/null +++ b/examples/plugins/engine/ExampleEnginePlugin.h @@ -0,0 +1,51 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * ExampleEnginePlugin.h This plugin does nothing but write API calls out to a + * log file. + * + * Created on: Jul 31, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#ifndef EXAMPLEENGINEPLUGIN_H_ +#define EXAMPLEENGINEPLUGIN_H_ + +#include <fstream> +#include <string> + +#include <adios2/ADIOSMPICommOnly.h> +#include <adios2/ADIOSMacros.h> +#include <adios2/ADIOSTypes.h> +#include <adios2/core/IO.h> +#include <adios2/engine/plugin/PluginEngineInterface.h> + +namespace adios2 +{ + +/** An engine interface to be used aby the plugin infrastructure */ +class ExampleEnginePlugin : public PluginEngineInterface +{ +public: + ExampleEnginePlugin(IO &io, const std::string &name, + const OpenMode openMode, MPI_Comm mpiComm); + virtual ~ExampleEnginePlugin(); + + void Close(const int transportIndex = -1) override; + +protected: + void Init() override; + +#define declare(T) \ + void DoWrite(Variable<T> &variable, const T *values) override; + ADIOS2_FOREACH_TYPE_1ARG(declare) +#undef declare + void DoWrite(VariableCompound &variable, const void *values) override; + +private: + std::ofstream m_Log; +}; + +} // end namespace adios2 +#endif /* EXAMPLEENGINEPLUGIN_H_ */ diff --git a/examples/plugins/engine/examplePluginEngine_class.cpp b/examples/plugins/engine/examplePluginEngine_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8a65905dd72e905b3284e07c3f3919558fb1a73 --- /dev/null +++ b/examples/plugins/engine/examplePluginEngine_class.cpp @@ -0,0 +1,77 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * helloBPWriter_nompi.cpp sequential non-mpi version of helloBPWriter + * + * Created on: Jan 9, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include <ios> //std::ios_base::failure +#include <iostream> //std::cout +#include <stdexcept> //std::invalid_argument std::exception +#include <vector> + +#include <adios2.h> +#include <adios2/engine/plugin/PluginEngine.h> + +#include "ExampleEnginePlugin.h" + +int main(int argc, char *argv[]) +{ + /** Application variable */ + std::vector<float> myFloats = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + const std::size_t Nx = myFloats.size(); + + adios2::PluginEngine::RegisterPlugin<adios2::ExampleEnginePlugin>( + "MyPlugin"); + + try + { + /** ADIOS class factory of IO class objects, DebugON is recommended */ + adios2::ADIOS adios(adios2::DebugON); + + /*** IO class object: settings and factory of Settings: Variables, + * Parameters, Transports, and Execution: Engines */ + adios2::IO &io = adios.DeclareIO("PluginIO"); + + /** global array: name, { shape (total dimensions) }, { start (local) }, + * { count (local) }, all are constant dimensions */ + adios2::Variable<float> &var = io.DefineVariable<float>( + "data", {}, {}, {Nx}, adios2::ConstantDims); + + /** Engine derived class, spawned to start IO operations */ + io.SetEngine("PluginEngine"); + io.SetParameters({{"PluginName", "MyPlugin"}}); + auto writer = io.Open("TestPlugin", adios2::OpenMode::Write); + + if (!writer) + { + throw std::ios_base::failure("ERROR: writer not created at Open\n"); + } + + /** Write variable for buffering */ + writer->Write<float>(var, myFloats.data()); + + /** Create bp file, engine becomes unreachable after this*/ + writer->Close(); + } + catch (std::invalid_argument &e) + { + std::cout << "Invalid argument exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::ios_base::failure &e) + { + std::cout << "IO System base failure exception, STOPPING PROGRAM\n"; + std::cout << e.what() << "\n"; + } + catch (std::exception &e) + { + std::cout << "Exception, STOPPING PROGRAM from rank\n"; + std::cout << e.what() << "\n"; + } + + return 0; +} diff --git a/scripts/appveyor/av_default.cmake b/scripts/appveyor/av_default.cmake new file mode 100644 index 0000000000000000000000000000000000000000..81ad4fbbb1c51f6eb0649f3b939f0bdbe54afd2d --- /dev/null +++ b/scripts/appveyor/av_default.cmake @@ -0,0 +1,31 @@ +# Client maintainer: chuck.atkins@kitware.com +set(CTEST_SITE "AppVeyor") +set(CTEST_BUILD_CONFIGURATION Release) +set(CTEST_CONFIGURATION_TYPE Release) +set(CTEST_CMAKE_GENERATOR "Visual Studio 14 2015 Win64") +set(CTEST_TEST_ARGS PARALLEL_LEVEL 4) + +message("av_default.cmake, CTEST_BUILD_NAME=${CTEST_BUILD_NAME}, push build notes is ADIOS_CTEST_SUBMIT_NOTES=${ADIOS_CTEST_SUBMIT_NOTES}") + +set(dashboard_model Experimental) +set(dashboard_binary_name "build_visual-studio") +set(dashboard_track "Continuous Integration") + +set(CTEST_GIT_COMMAND "git.exe") +set(CTEST_UPDATE_VERSION_ONLY TRUE) +set(CTEST_SOURCE_DIRECTORY "$ENV{APPVEYOR_BUILD_FOLDER}") +set(CTEST_DASHBOARD_ROOT "C:/projects/adios2build") + +set(dashboard_cache " +ADIOS2_USE_ADIOS1:STRING=OFF +ADIOS2_USE_BZip2:STRING=OFF +ADIOS2_USE_DataMan:STRING=OFF +ADIOS2_USE_Fortran:STRING=OFF +ADIOS2_USE_HDF5:STRING=OFF +ADIOS2_USE_MPI:STRING=OFF +ADIOS2_USE_Python:STRING=OFF +ADIOS2_USE_ZFP:STRING=OFF +ADIOS2_USE_ZeroMQ:STRING=OFF +") + +include(${CMAKE_CURRENT_LIST_DIR}/../dashboard/adios_common.cmake) diff --git a/scripts/circle/.dockerignore b/scripts/circle/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..92649f08b17c0351ac49985400dfb9b16e013293 --- /dev/null +++ b/scripts/circle/.dockerignore @@ -0,0 +1,4 @@ +runOnCircle.sh +postComment.sh +*.cmake +findStatus.py diff --git a/scripts/circle/Dockerfile b/scripts/circle/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d4201627d4f95b55c5797a223cd5a06882044718 --- /dev/null +++ b/scripts/circle/Dockerfile @@ -0,0 +1,87 @@ +FROM centos:centos7 + +# Install extra repos +RUN yum -y install epel-release https://github.com/openhpc/ohpc/releases/download/v1.3.GA/ohpc-release-1.3-1.el7.x86_64.rpm + +# Install core dev packages +RUN yum -y install \ + curl file \ + gcc gcc-c++ gcc-gfortran \ + git make autoconf automake libtool\ + bzip2-devel zeromq-devel hdf5-devel \ + python-devel numpy + +# Install gcc7 OpenHPC packages +RUN yum -y install \ + lmod-ohpc gnu7-compilers-ohpc openmpi-gnu7-ohpc phdf5-gnu7-openmpi-ohpc + +# Cleanup headers and packages +RUN yum clean all + +# Install the CMake binary +WORKDIR /opt/cmake/3.6.0 +RUN curl -L https://cmake.org/files/v3.6/cmake-3.6.0-Linux-x86_64.tar.gz | \ + tar --strip-components=1 -xzv + +# ZFP +WORKDIR /opt/zfp +RUN mkdir build install && \ + git clone https://github.com/LLNL/zfp.git src && \ + cd build && \ + /opt/cmake/3.6.0/bin/cmake \ + -DCMAKE_INSTALL_PREFIX=/opt/zfp/install \ + ../src && \ + make -j8 install && \ + cd ../ && \ + rm -rf build src + +# ADIOS1 + +# Source setup +WORKDIR /opt/adios1/1.12.0 +RUN mkdir source && \ + curl -L https://github.com/ornladios/ADIOS/archive/v1.12.0.tar.gz | \ + tar -C source --strip-components=1 -xzv && \ + cd source && ./autogen.sh + +# GCC 4.8 +RUN cd source && \ + CFLAGS="-O2 -fPIC" CXXFLAGS="-O2 -fPIC" FCFLAGS="-O2 -fPIC" \ + ./configure --prefix=/opt/adios1/1.12.0/gnu48 --without-mpi && \ + make -j8 install && \ + make distclean + +# GCC 7 +RUN cd source && \ + . /etc/profile && \ + module load gnu7 openmpi phdf5 && \ + CFLAGS="-O2 -fPIC" CXXFLAGS="-O2 -fPIC" FCFLAGS="-O2 -fPIC" \ + ./configure --prefix=/opt/adios1/1.12.0/gnu7_openmpi && \ + make -j8 install + +# Cleanup +RUN rm -rf /opt/adios1/1.12.0/source + +# mpi4py +WORKDIR /opt +RUN . /etc/profile && \ + module purge && \ + module load gnu7 openmpi && \ + curl -L https://bitbucket.org/mpi4py/mpi4py/downloads/mpi4py-2.0.0.tar.gz | \ + tar -xzv && \ + cd mpi4py-2.0.0 && \ + python setup.py build && \ + python setup.py install && \ + cd ../ && rm -rf mpi4py-2.0.0 + +# Create a non-root user to run the builds/tests +RUN export uid=1001 gid=1001 && \ + mkdir -p /home/adios2 && \ + echo "adios2:x:${uid}:${gid}:adios2,,,:/home/adios2:/bin/bash" >> /etc/passwd && \ + echo "adios2:x:${uid}:" >> /etc/group && \ + chown ${uid}:${gid} -R /home/adios2 + +USER adios2 +ENV HOME /home/adios2 +WORKDIR /home/adios2 +CMD /bin/bash diff --git a/scripts/circle/EnvironmentModules.cmake b/scripts/circle/EnvironmentModules.cmake new file mode 100644 index 0000000000000000000000000000000000000000..60328e38b6bad7b7bfa5b86854b3805444866efc --- /dev/null +++ b/scripts/circle/EnvironmentModules.cmake @@ -0,0 +1,207 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# EnvironmentModules +# ------------------ +# +# Make environment module commands available to CMake scripts. This module +# is compatible with both Lua based Lmod and TCL based EnvironmentModules +# +# Module Command +# ^^^^^^^^^^^^^^ +# +# This module searched for the module command in the following variable: +# +# :: +# +# MODULE_COMMAND - The low level module command to use. Currently supported +# are implementations are the Lua based Lmod and TCL based +# EnvironmentModules. The ENV{MODULESHOME} variable, +# usually set by the module environment, is used as a hint +# to locate the command. +# +# Provided Functions +# ^^^^^^^^^^^^^^^^^^ +# +# This module defines the following functions: +# +# :: +# +# module(...) - Execute an arbitry module command +# module_swap(out_mod in_mod) - Swap out one currently loaded module for +# another +# module_list(out_var) - Retrieve the currently loaded modules, +# making the output available as a properly +# formatted CMake ;list variable. +# module_avail(out_var) - Retrieve the availabe modules that can be +# loaded, making the output available as a +# properly formatted CMake ;-seperated list +# variable. + +# Execute an aribitrary module command. Usage: +# module(cmd arg1 ... argN) +# Process the given command and arguments as if they were passed +# directly to the module command in your shell environment. +# module( +# COMMAND cmd arg1 .. argN +# [OUTPUT_VARIABLE out_var] +# [RESULT_VARIABLE ret_var] +# ) +function(module) + if(NOT MODULE_COMMAND) + message(ERROR "Failed to process module command. MODULE_COMMAND not found") + return() + endif() + + set(options) + set(oneValueArgs OUTPUT_VARIABLE RESULT_VARIABLE) + set(multiValueArgs COMMAND) + cmake_parse_arguments(MOD_ARGS + "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGV} + ) + if(NOT MOD_ARGS_COMMAND) + # If no explicit command argument was given, then treat the calling syntax + # as: module(cmd args...) + set(exec_cmd ${ARGV}) + else() + set(exec_cmd ${MOD_ARGS_COMMAND}) + endif() + + if(MOD_ARGS_OUTPUT_VARIABLE) + set(err_var_args ERROR_VARIABLE err_var) + endif() + + execute_process( + COMMAND mktemp -t module.cmake.XXXXXXXXXXXX + OUTPUT_VARIABLE tempfile_name + ) + string(STRIP "${tempfile_name}" tempfile_name) + + # If the $MODULESHOME/init/cmake file exists then assume that the CMake + # "shell" functionality exits + if(EXISTS "$ENV{MODULESHOME}/init/cmake") + execute_process( + COMMAND ${MODULE_COMMAND} cmake ${exec_cmd} + OUTPUT_FILE ${tempfile_name} + ${err_var_args} + RESULT_VARIABLE ret_var + ) + else() # fallback to the sh shell and manually convert to CMake + execute_process( + COMMAND ${MODULE_COMMAND} sh ${exec_cmd} + OUTPUT_VARIABLE out_var + ${err_var_args} + RESULT_VARIABLE ret_var + ) + endif() + + # If we executed successfully then process and cleanup the temp file + if("${ret_var}" EQUAL 0) + # No CMake shell so we need to process the sh output into CMake code + if(NOT EXISTS "$ENV{MODULESHOME}/init/cmake") + file(WRITE ${tempfile_name} "") + string(REPLACE "\n" ";" out_var "${out_var}") + foreach(sh_cmd IN LISTS out_var) + if(sh_cmd MATCHES "^ *unset *([^ ]*)") + set(cmake_cmd "unset(ENV{${CMAKE_MATCH_1}})") + elseif(sh_cmd MATCHES "^ *export *([^ ]*)") + set(cmake_cmd "set(ENV{${CMAKE_MATCH_1}} \"\${${CMAKE_MATCH_1}}\")") + elseif(sh_cmd MATCHES " *([^ =]*) *= *(.*)") + set(var_name "${CMAKE_MATCH_1}") + set(var_value "${CMAKE_MATCH_2}") + if(var_value MATCHES "^\"(.*[^\\])\"") + # If it's in quotes, take the value as is + set(var_value "${CMAKE_MATCH_1}") + else() + # Otherwise, strip trailing spaces + string(REGEX REPLACE "([^\\])? +$" "\\1" var_value "${var_value}") + endif() + string(REPLACE "\\ " " " var_value "${var_value}") + set(cmake_cmd "set(${var_name} \"${var_value}\")") + else() + continue() + endif() + file(APPEND ${tempfile_name} "${cmake_cmd}\n") + endforeach() + endif() + + # Process the change in environment variables + include(${tempfile_name}) + file(REMOVE ${tempfile_name}) + endif() + + # Push the output back out to the calling scope + if(MOD_ARGS_OUTPUT_VARIABLE) + set(${MOD_ARGS_OUTPUT_VARIABLE} "${err_var}" PARENT_SCOPE) + endif() + if(MOD_ARGS_RESULT_VARIABLE) + set(${MOD_ARGS_RESULT_VARIABLE} ${ret_var} PARENT_SCOPE) + endif() +endfunction(module) + +# Swap one module for another +function(module_swap out_mod in_mod) + module(COMMAND -t swap ${out_mod} ${in_mod} OUTPUT_VARIABLE tmp_out) +endfunction() + +# Retrieve the currently loaded modules +function(module_list out_var) + cmake_policy(SET CMP0007 NEW) + module(COMMAND -t list OUTPUT_VARIABLE tmp_out) + + # Convert output into a CMake list + string(REPLACE "\n" ";" ${out_var} "${tmp_out}") + + # Remove title headers and empty entries + list(REMOVE_ITEM ${out_var} "No modules loaded") + if(${out_var}) + list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$") + endif() + list(FILTER ${out_var} EXCLUDE REGEX "^(.*:)?$") + + set(${out_var} ${${out_var}} PARENT_SCOPE) +endfunction() + +# Retrieve the list of available modules +function(module_avail out_var) + cmake_policy(SET CMP0007 NEW) + module(COMMAND -t avail OUTPUT_VARIABLE tmp_out) + + # Convert output into a CMake list + string(REPLACE "\n" ";" tmp_out "${tmp_out}") + + set(${out_var}) + foreach(MOD IN LISTS tmp_out) + # Remove directory entries and empty values + if(MOD MATCHES "^(.*:)?$") + continue() + endif() + + # Convert default modules + if(MOD MATCHES "^(.*)/$" ) # "foo/" + list(APPEND ${out_var} ${CMAKE_MATCH_1}) + elseif(MOD MATCHES "^((.*)/.*)\\(default\\)$") # "foo/1.2.3(default)" + list(APPEND ${out_var} ${CMAKE_MATCH_2}) + list(APPEND ${out_var} ${CMAKE_MATCH_1}) + else() + list(APPEND ${out_var} ${MOD}) + endif() + endforeach() + + set(${out_var} ${${out_var}} PARENT_SCOPE) +endfunction() + +# Make sure our CMake is new enough +if(CMAKE_VERSION VERSION_LESS 3.6) + message(FATAL_ERROR + "The EnvironmentModules interface requires at least CMake v3.6" + ) +endif() + +# Make sure we know where the underlying module command is +find_program(MODULE_COMMAND + NAMES lmod modulecmd + HINTS ENV MODULESHOME + PATH_SUFFIXES libexec +) diff --git a/scripts/circle/circle_el7-gcc48.cmake b/scripts/circle/circle_el7-gcc48.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3efe1284b1c499b506ae2ef7ac508739ccd4796d --- /dev/null +++ b/scripts/circle/circle_el7-gcc48.cmake @@ -0,0 +1,38 @@ +# Client maintainer: chuck.atkins@kitware.com +set(CTEST_SITE "CircleCI") +set(CTEST_BUILD_CONFIGURATION Release) +set(CTEST_CMAKE_GENERATOR "Unix Makefiles") +set(CTEST_BUILD_FLAGS "-k -j4") +set(CTEST_TEST_ARGS PARALLEL_LEVEL 4) + +set(dashboard_model Experimental) +set(dashboard_binary_name "build_$ENV{CIRCLE_JOB}") +set(dashboard_track "Continuous Integration") + +set(CTEST_GIT_COMMAND "/usr/bin/git") +set(CTEST_UPDATE_VERSION_ONLY TRUE) +set(CTEST_SOURCE_DIRECTORY "$ENV{CIRCLE_WORKING_DIRECTORY}/source") +set(CTEST_DASHBOARD_ROOT "$ENV{HOME}") + +include(${CMAKE_CURRENT_LIST_DIR}/EnvironmentModules.cmake) +module(purge) + +set(ENV{CC} gcc) +set(ENV{CXX} g++) +set(ENV{FC} gfortran) + +set(dashboard_cache " +ADIOS2_USE_ADIOS1:STRING=ON +ADIOS2_USE_BZip2:STRING=ON +ADIOS2_USE_DataMan:STRING=ON +ADIOS2_USE_Fortran:STRING=ON +ADIOS2_USE_HDF5:STRING=ON +ADIOS2_USE_MPI:STRING=OFF +ADIOS2_USE_Python:STRING=ON +ADIOS2_USE_ZFP:STRING=ON +ADIOS2_USE_ZeroMQ:STRING=ON +ZFP_ROOT_DIR:PATH=/opt/zfp/install +ADIOS1_ROOT:PATH=/opt/adios1/1.12.0/gnu48 +") + +include(${CMAKE_CURRENT_LIST_DIR}/../dashboard/adios_common.cmake) diff --git a/scripts/circle/circle_el7-gcc7-openmpi.cmake b/scripts/circle/circle_el7-gcc7-openmpi.cmake new file mode 100644 index 0000000000000000000000000000000000000000..e337585db7bcb3bdea6e3c3fba1ff666b696b173 --- /dev/null +++ b/scripts/circle/circle_el7-gcc7-openmpi.cmake @@ -0,0 +1,41 @@ +# Client maintainer: chuck.atkins@kitware.com +set(CTEST_SITE "CircleCI") +set(CTEST_BUILD_CONFIGURATION Release) +set(CTEST_CMAKE_GENERATOR "Unix Makefiles") +set(CTEST_BUILD_FLAGS "-k -j4") +set(CTEST_TEST_ARGS PARALLEL_LEVEL 4) + +set(dashboard_model Experimental) +set(dashboard_binary_name "build_$ENV{CIRCLE_JOB}") +set(dashboard_track "Continuous Integration") + +set(CTEST_GIT_COMMAND "/usr/bin/git") +set(CTEST_UPDATE_VERSION_ONLY TRUE) +set(CTEST_SOURCE_DIRECTORY "$ENV{CIRCLE_WORKING_DIRECTORY}/source") +set(CTEST_DASHBOARD_ROOT "$ENV{HOME}") + +include(${CMAKE_CURRENT_LIST_DIR}/EnvironmentModules.cmake) +module(purge) +module(load gnu7) +module(load openmpi) +module(load phdf5) + +set(ENV{CC} gcc) +set(ENV{CXX} g++) +set(ENV{FC} gfortran) + +set(dashboard_cache " +ADIOS2_USE_ADIOS1:STRING=ON +ADIOS2_USE_BZip2:STRING=ON +ADIOS2_USE_DataMan:STRING=ON +ADIOS2_USE_Fortran:STRING=ON +ADIOS2_USE_HDF5:STRING=ON +ADIOS2_USE_MPI:STRING=ON +ADIOS2_USE_Python:STRING=ON +ADIOS2_USE_ZFP:STRING=ON +ADIOS2_USE_ZeroMQ:STRING=ON +ZFP_ROOT_DIR:PATH=/opt/zfp/install +ADIOS1_ROOT:PATH=/opt/adios1/1.12.0/gnu7_openmpi +") + +include(${CMAKE_CURRENT_LIST_DIR}/../dashboard/adios_common.cmake) diff --git a/scripts/circle/findStatus.py b/scripts/circle/findStatus.py new file mode 100644 index 0000000000000000000000000000000000000000..44592ab848910dae22a9fa5cd57846039c07dd97 --- /dev/null +++ b/scripts/circle/findStatus.py @@ -0,0 +1,25 @@ +import sys +import json +import argparse + + +def searchForContext(context): + print('Searching for a status with context: %s' % context) + statuses = json.load(sys.stdin) + + for stat in statuses: + if 'context' in stat and stat['context'] == context: + sys.exit(0) + + sys.exit(1) + + +# ============================================================================= +# Main +# ============================================================================= + +if __name__ == "__main__": + parser = argparse.ArgumentParser("Parse github api status list") + parser.add_argument("--context", default=None, help="context of interest") + args = parser.parse_args() + searchForContext(args.context) diff --git a/scripts/circle/postComment.sh b/scripts/circle/postComment.sh new file mode 100755 index 0000000000000000000000000000000000000000..ca1f847fb5d90d5fb0c6307804c0489311897136 --- /dev/null +++ b/scripts/circle/postComment.sh @@ -0,0 +1,40 @@ +#!/usr/bin/bash + +PULLREQUESTS=${CIRCLE_PULL_REQUESTS} # comma-separated list of pr urls +REPO=${CIRCLE_PROJECT_REPONAME} # repo name +OWNER=${CIRCLE_PROJECT_USERNAME} # organization or user the repo lives under +TOKEN=${GITHUB_API_KEY} # added to env via CircleCI project settings +COMMIT=${CIRCLE_SHA1} # sha being tested +COMPAREURL=${CIRCLE_COMPARE_URL} # CircleCI provides url for comparing this sha with previous + +SHASNIP=$(echo $COMMIT | cut -c1-7) # Grab first 7 characters of the sha to use as link text +CDASHPROJECT="ADIOS" +CDASHURL="https://open.cdash.org/index.php?compare1=61&filtercount=1&field1=revision&project=${CDASHPROJECT}&showfilters=0&limit=100&value1=${COMMIT}&showfeed=0" +COMMENTBODY="View build and test results for change [${SHASNIP}](${COMPAREURL}) on [CDash](${CDASHURL})" +APIBASEURL="https://api.github.com/repos" + +get_post_data() +{ + cat <<EOF +{ + "body": "$COMMENTBODY" +} +EOF +} + +postBody="$(get_post_data)" + +IFS=',' read -ra ADDR <<< "$PULLREQUESTS" +for i in "${ADDR[@]}"; do + # For each pr url, find the pr number + if [[ "$i" =~ ADIOS2/pull/([[:digit:]]+) ]]; + then + prNum=${BASH_REMATCH[1]} + postUrl="${APIBASEURL}/${OWNER}/${REPO}/issues/${prNum}/comments" + + curl -u "${OWNER}:${TOKEN}" "${postUrl}" -H "Content-Type: application/json" -H "Accept: application/vnd.github.v3+json" -d "${postBody}" + else + echo "Unable to find PR number in ${i}" + fi +done + diff --git a/scripts/circle/runOnCircle.sh b/scripts/circle/runOnCircle.sh new file mode 100755 index 0000000000000000000000000000000000000000..20f0fbfabd0615dc41f719013aaf296b08b17a5f --- /dev/null +++ b/scripts/circle/runOnCircle.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +API_BASE="https://api.github.com/repos/ornladios/adios2" +USER=${STATUS_ROBOT_NAME} +TOKEN=${STATUS_ROBOT_KEY} +COMMIT=${CIRCLE_SHA1} +CDASH_STATUS_CONTEXT="cdash" + +build_status_body() { + cat <<EOF +{ + "state": "success", + "target_url": "https://open.cdash.org/index.php?compare1=61&filtercount=1&field1=revision&project=ADIOS&showfilters=0&limit=100&value1=${COMMIT}&showfeed=0", + "description": "Build and test results available on CDash", + "context": "${CDASH_STATUS_CONTEXT}" +} +EOF +} + +check_and_post_status() { + PYTHON_SCRIPT="${SOURCE_DIR}/scripts/circle/findStatus.py" + curl -u "${STATUS_ROBOT_NAME}:${STATUS_ROBOT_KEY}" "${API_BASE}/commits/${COMMIT}/statuses" | python ${PYTHON_SCRIPT} --context ${CDASH_STATUS_CONTEXT} + if [ $? -ne 0 ] + then + echo "Need to post a status for context ${CDASH_STATUS_CONTEXT}" + postBody="$(build_status_body)" + postUrl="${API_BASE}/statuses/${COMMIT}" + curl -u "${OWNER}:${TOKEN}" "${postUrl}" -H "Content-Type: application/json" -H "Accept: application/vnd.github.v3+json" -d "${postBody}" + fi +} + +get_real_branch_name() { + APIURL="${API_BASE}/pulls/${CIRCLE_PR_NUMBER}" + RESULT=`curl -s ${APIURL} | python -c "import sys, json; print(json.load(sys.stdin)['head']['ref'])" 2> /dev/null` + + if [ $? -eq 0 ] + then + REALBRANCH=$RESULT + else + REALBRANCH=$CIRCLE_BRANCH + fi +} + +check_var() { + if [ -z "$1" ] + then + echo "Error: The $1 environment variable is undefined" + exit 1 + fi +} + +check_var CIRCLE_WORKING_DIRECTORY +check_var CIRCLE_BRANCH +check_var CIRCLE_JOB +check_var CIRCLE_BUILD_NUM +check_var CIRCLE_PR_NUMBER + +if [ ! "${CUSTOM_BUILD_NAME}" ] +then + get_real_branch_name + + LINETOSAVE="export CUSTOM_BUILD_NAME=${REALBRANCH}_${CIRCLE_BUILD_NUM}_${CIRCLE_JOB}" + + # Set the custom build name for this step + eval $LINETOSAVE + + # Also make sure it will get set for the following steps + echo "${LINETOSAVE}" >> $BASH_ENV +fi + +SOURCE_DIR=${CIRCLE_WORKING_DIRECTORY}/source +CTEST_SCRIPT="${SOURCE_DIR}/scripts/circle/circle_${CIRCLE_JOB}.cmake" + +if [ ! -f "${CTEST_SCRIPT}" ] +then + echo "Unable to find CTest script $(basename ${CTEST_SCRIPT})" + exit 2 +fi + +case "$1" in + update|configure|build|test) + STEP=$1 + if [ "$STEP" == "update" ] + then + check_and_post_status + fi + ;; + *) + echo "Usage: $0 (update|configure|build|test)" + exit 3 + ;; +esac + +# Manually source the bash env setup, freeing up $BASH_ENV used by circleci +. /etc/profile >/dev/null + +/opt/cmake/3.6.0/bin/ctest -VV -S ${CTEST_SCRIPT} -Ddashboard_full=OFF -Ddashboard_do_${STEP}=TRUE -DCTEST_BUILD_NAME=${CUSTOM_BUILD_NAME} diff --git a/scripts/dashboard/adios_common.cmake b/scripts/dashboard/adios_common.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4cd0b3ab8a085fdf63f2795ebdbf6de13ce88728 --- /dev/null +++ b/scripts/dashboard/adios_common.cmake @@ -0,0 +1,81 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# +# +# ADIOS Common Dashboard Script +# +# This script contains basic dashboard driver code common to all +# clients. +# +# # Client maintainer: me@mydomain.net +# set(CTEST_SITE "machine.site") +# set(CTEST_BUILD_NAME "Platform-Compiler") +# set(CTEST_CONFIGURATION_TYPE Debug) +# set(CTEST_CMAKE_GENERATOR "Unix Makefiles") +# include(${CTEST_SCRIPT_DIRECTORY}/adios_common.cmake) +# +# Then run a scheduled task (cron job) with a command line such as +# +# ctest -S ~/Dashboards/Scripts/my_dashboard.cmake -V +# +# By default the source and build trees will be placed in the path +# "../My Tests/" relative to your script location. +# +# The following variables may be set before including this script +# to configure it: +# +# dashboard_model = Nightly | Experimental +# dashboard_root_name = Change name of "MyTests" directory +# dashboard_source_name = Name of source directory (adios) +# dashboard_binary_name = Name of binary directory (adios-build) +# dashboard_cache = Initial CMakeCache.txt file content + +# dashboard_do_checkout = True to enable source checkout via git +# dashboard_do_update = True to enable source update +# dashboard_do_configure = True to enable the Configure step +# dashboard_do_build = True to enable the Build step +# dashboard_do_test = True to enable the Test step +# dashboard_do_coverage = True to enable coverage (ex: gcov) +# dashboard_do_memcheck = True to enable memcheck (ex: valgrind) + +# CTEST_GIT_COMMAND = path to git command-line client +# CTEST_BUILD_FLAGS = build tool arguments (ex: -j2) +# CTEST_DASHBOARD_ROOT = Where to put source and build trees +# CTEST_TEST_CTEST = Whether to run long CTestTest* tests +# CTEST_TEST_TIMEOUT = Per-test timeout length +# CTEST_TEST_ARGS = ctest_test args (ex: PARALLEL_LEVEL 4) +# CMAKE_MAKE_PROGRAM = Path to "make" tool to use +# +# Options to configure Git: +# dashboard_git_url = Custom git clone url +# dashboard_git_branch = Custom remote branch to track +# dashboard_git_crlf = Value of core.autocrlf for repository +# + +# For Makefile generators the script may be executed from an +# environment already configured to use the desired compilers. +# Alternatively the environment may be set at the top of the script: +# +# set(ENV{CC} /path/to/cc) # C compiler +# set(ENV{CXX} /path/to/cxx) # C++ compiler +# set(ENV{FC} /path/to/fc) # Fortran compiler (optional) +# set(ENV{LD_LIBRARY_PATH} /path/to/vendor/lib) # (if necessary) + +set(CTEST_PROJECT_NAME "ADIOS2") +set(CTEST_DROP_SITE "open.cdash.org") +set(dashboard_git_url "https://github.com/ornladios/ADIOS2.git") + +if(NOT ADIOS_CTEST_SUBMIT_NOTES) + set(ADIOS_CTEST_SUBMIT_NOTES TRUE) +endif() +if(NOT dashboard_root_name) + set(dashboard_root_name "Builds/My Tests") +endif() +if(NOT dashboard_source_name) + set(dashboard_source_name "ADIOS2") +endif() +if(NOT dashboard_model) + set(dashboard_model Experimental) +endif() +include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) diff --git a/scripts/dashboard/common.cmake b/scripts/dashboard/common.cmake new file mode 100644 index 0000000000000000000000000000000000000000..ac88d93726957d9728a67b9e0b1d6f81f42a3d2a --- /dev/null +++ b/scripts/dashboard/common.cmake @@ -0,0 +1,460 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# +# +# "Universal" Dashboard Script +# +# This script contains basic dashboard driver code common to all +# clients and projects. It is a combination of the universal.cmake script in +# the Kitware DashboardScriptsNG repo and cmake_common.cmake used by CMake +# dashboards. +# +# Create a project-specific common script with code of the following form, +# where the final line includes this script. +# +# set(CTEST_PROJECT_NAME "OpenChemistry") +# set(CTEST_DROP_SITE "cdash.openchemistry.org") +# +# set(dashboard_git_url "git://source.openchemistry.org/openchemistry.git") +# set(dashboard_root_name "MyTests") +# set(dashboard_source_name "openchemistry") +# +# get_filename_component(dir ${CMAKE_CURRENT_LIST_FILE} PATH) +# include(${dir}/universal.cmake) +# +# The following variables may be set before including this script +# to configure it: +# +# dashboard_model = Nightly | Experimental +# dashboard_root_name = Change name of "My Tests" directory +# dashboard_source_name = Name of source directory (CMake) +# dashboard_binary_name = Name of binary directory (CMake-build) +# dashboard_cache = Initial CMakeCache.txt file content +# dashboard_track = The name of the CDash "Track" to submit to + +# dashboard_do_checkout = True to enable source checkout via git +# dashboard_do_update = True to enable the Update step +# dashboard_do_configure = True to enable the Configure step +# dashboard_do_build = True to enable the Build step +# dashboard_do_test = True to enable the Test step +# dashboard_do_coverage = True to enable coverage (ex: gcov) +# dashboard_do_memcheck = True to enable memcheck (ex: valgrind) + +# CTEST_GIT_COMMAND = path to git command-line client +# CTEST_BUILD_FLAGS = build tool arguments (ex: -j2) +# CTEST_DASHBOARD_ROOT = Where to put source and build trees +# CTEST_TEST_CTEST = Whether to run long CTestTest* tests +# CTEST_TEST_TIMEOUT = Per-test timeout length +# CTEST_TEST_ARGS = ctest_test args (ex: PARALLEL_LEVEL 4) +# CMAKE_MAKE_PROGRAM = Path to "make" tool to use +# +# Options to configure Git: +# dashboard_git_url = Custom git clone url +# dashboard_git_branch = Custom remote branch to track +# dashboard_git_crlf = Value of core.autocrlf for repository +# +# For Makefile generators the script may be executed from an +# environment already configured to use the desired compilers. +# Alternatively the environment may be set at the top of the script: +# +# set(ENV{CC} /path/to/cc) # C compiler +# set(ENV{CXX} /path/to/cxx) # C++ compiler +# set(ENV{FC} /path/to/fc) # Fortran compiler (optional) +# set(ENV{LD_LIBRARY_PATH} /path/to/vendor/lib) # (if necessary) + +cmake_minimum_required(VERSION 2.8.2 FATAL_ERROR) + +if(NOT DEFINED dashboard_full) + set(dashboard_full TRUE) +endif() + +# Initialize all build steps to "ON" +if(NOT DEFINED dashboard_do_update) + set(dashboard_do_update ${dashboard_full}) +endif() + +if(NOT DEFINED dashboard_do_checkout) + set(dashboard_do_checkout ${dashboard_full}) +endif() + +if(NOT DEFINED dashboard_do_configure) + set(dashboard_do_configure ${dashboard_full}) +endif() + +if(NOT DEFINED dashboard_do_build) + set(dashboard_do_build ${dashboard_full}) +endif() + +if(NOT DEFINED dashboard_do_test) + set(dashboard_do_test ${dashboard_full}) +endif() + +# Default code coverage and memtesting to off +if(NOT DEFINED dashboard_do_coverage) + set(dashboard_do_coverage FALSE) +endif() + +if(NOT DEFINED dashboard_do_memcheck) + set(dashboard_do_memcheck FALSE) +endif() + +if(NOT DEFINED dashboard_fresh) + if(dashboard_full OR dashboard_do_update) + set(dashboard_fresh TRUE) + else() + set(dashboard_fresh FALSE) + endif() +endif() + +if(NOT DEFINED CTEST_PROJECT_NAME) + message(FATAL_ERROR "project-specific script including 'universal.cmake' should set CTEST_PROJECT_NAME") +endif() + +if(NOT DEFINED dashboard_user_home) + set(dashboard_user_home "$ENV{HOME}") +endif() + +# Select the top dashboard directory. +if(NOT DEFINED dashboard_root_name) + set(dashboard_root_name "My Tests") +endif() +if(NOT DEFINED CTEST_DASHBOARD_ROOT) + get_filename_component(CTEST_DASHBOARD_ROOT "${CTEST_SCRIPT_DIRECTORY}/../${dashboard_root_name}" ABSOLUTE) +endif() + +# Select the model (Nightly, Experimental, Continuous). +if(NOT DEFINED dashboard_model) + set(dashboard_model Nightly) +endif() +if(NOT "${dashboard_model}" MATCHES "^(Nightly|Experimental)$") + message(FATAL_ERROR "dashboard_model must be Nightly or Experimental") +endif() + + +# Default to a Debug build. +if(NOT DEFINED CTEST_BUILD_CONFIGURATION) + set(CTEST_BUILD_CONFIGURATION Debug) +endif() + +# Choose CTest reporting mode. +if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make|Ninja") + # Launchers work only with Makefile and Ninja generators. + set(CTEST_USE_LAUNCHERS 0) +elseif(NOT DEFINED CTEST_USE_LAUNCHERS) + # The setting is ignored by CTest < 2.8 so we need no version test. + set(CTEST_USE_LAUNCHERS 1) +endif() + +# Configure testing. +if(NOT DEFINED CTEST_TEST_CTEST) + set(CTEST_TEST_CTEST 1) +endif() +if(NOT CTEST_TEST_TIMEOUT) + set(CTEST_TEST_TIMEOUT 1500) +endif() + +# Select Git source to use. +if(dashboard_do_checkout) + if(NOT DEFINED dashboard_git_url) + message(FATAL_ERROR "project-specific script including 'universal.cmake' should set dashboard_git_url") + endif() + if(NOT DEFINED dashboard_git_branch) + set(dashboard_git_branch master) + endif() + if(NOT DEFINED dashboard_git_crlf) + if(UNIX) + set(dashboard_git_crlf false) + else() + set(dashboard_git_crlf true) + endif() + endif() + + # Look for a GIT command-line client. + if(NOT DEFINED CTEST_GIT_COMMAND) + find_program(CTEST_GIT_COMMAND + NAMES git git.cmd + PATH_SUFFIXES Git/cmd Git/bin + ) + endif() + if(NOT CTEST_GIT_COMMAND) + message(FATAL_ERROR "CTEST_GIT_COMMAND not available!") + endif() +endif() + +# Select a source directory name. +if(NOT DEFINED CTEST_SOURCE_DIRECTORY) + if(DEFINED dashboard_source_name) + set(CTEST_SOURCE_DIRECTORY ${CTEST_DASHBOARD_ROOT}/${dashboard_source_name}) + else() + set(CTEST_SOURCE_DIRECTORY ${CTEST_DASHBOARD_ROOT}/${CTEST_PROJECT_NAME}) + endif() +endif() + +# Select a build directory name. +if(NOT DEFINED CTEST_BINARY_DIRECTORY) + if(DEFINED dashboard_binary_name) + set(CTEST_BINARY_DIRECTORY ${CTEST_DASHBOARD_ROOT}/${dashboard_binary_name}) + else() + set(CTEST_BINARY_DIRECTORY ${CTEST_SOURCE_DIRECTORY}-build) + endif() +endif() + +macro(dashboard_git) + execute_process( + COMMAND ${CTEST_GIT_COMMAND} ${ARGN} + WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}" + OUTPUT_VARIABLE dashboard_git_output + ERROR_VARIABLE dashboard_git_output + RESULT_VARIABLE dashboard_git_failed + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE + ) +endmacro() + +if(dashboard_do_checkout) + # Delete source tree if it is incompatible with current VCS. + if(EXISTS ${CTEST_SOURCE_DIRECTORY}) + if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}/.git") + set(vcs_refresh "because it is not managed by git.") + else() + execute_process( + COMMAND ${CTEST_GIT_COMMAND} reset --hard + WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}" + OUTPUT_VARIABLE output + ERROR_VARIABLE output + RESULT_VARIABLE failed + ) + if(failed) + set(vcs_refresh "because its .git may be corrupted.") + endif() + endif() + if(vcs_refresh AND "${CTEST_SOURCE_DIRECTORY}" MATCHES "/CMake[^/]*") + message("Deleting source tree\n") + message(" ${CTEST_SOURCE_DIRECTORY}\n${vcs_refresh}") + file(REMOVE_RECURSE "${CTEST_SOURCE_DIRECTORY}") + endif() + endif() + + # Support initial checkout if necessary. + if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}" + AND NOT DEFINED CTEST_CHECKOUT_COMMAND) + # Generate an initial checkout script. + get_filename_component(_name "${CTEST_SOURCE_DIRECTORY}" NAME) + set(ctest_checkout_script ${CTEST_DASHBOARD_ROOT}/${_name}-init.cmake) + file(WRITE ${ctest_checkout_script} "# git repo init script for ${_name} +execute_process( + COMMAND \"${CTEST_GIT_COMMAND}\" clone -n -- \"${dashboard_git_url}\" + \"${CTEST_SOURCE_DIRECTORY}\" + ) +if(EXISTS \"${CTEST_SOURCE_DIRECTORY}/.git\") + execute_process( + COMMAND \"${CTEST_GIT_COMMAND}\" config core.autocrlf ${dashboard_git_crlf} + WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" + ) + execute_process( + COMMAND \"${CTEST_GIT_COMMAND}\" fetch + WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" + ) + execute_process( + COMMAND \"${CTEST_GIT_COMMAND}\" checkout ${dashboard_git_branch} + WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" + ) +endif()" + ) + set(CTEST_CHECKOUT_COMMAND "\"${CMAKE_COMMAND}\" -P \"${ctest_checkout_script}\"") + elseif(EXISTS "${CTEST_SOURCE_DIRECTORY}/.git") + # Upstream URL. + dashboard_git(config --get remote.origin.url) + if(NOT dashboard_git_output STREQUAL "${dashboard_git_url}") + dashboard_git(config remote.origin.url "${dashboard_git_url}") + endif() + + # Local checkout. + dashboard_git(symbolic-ref HEAD) + if(NOT dashboard_git_output STREQUAL "${dashboard_git_branch}") + dashboard_git(checkout ${dashboard_git_branch}) + if(dashboard_git_failed) + message(FATAL_ERROR "Failed to checkout branch ${dashboard_git_branch}:\n${dashboard_git_output}") + endif() + endif() + endif() +endif() + +#----------------------------------------------------------------------------- + +# Check for required variables. +foreach(req + CTEST_CMAKE_GENERATOR + CTEST_SITE + CTEST_BUILD_NAME + ) + if(NOT DEFINED ${req}) + message(FATAL_ERROR "The containing script must set ${req}") + endif() +endforeach(req) + +# Print summary information. +set(vars "") +foreach(v + CTEST_SITE + CTEST_BUILD_NAME + CTEST_SOURCE_DIRECTORY + CTEST_BINARY_DIRECTORY + CTEST_CMAKE_GENERATOR + CTEST_BUILD_CONFIGURATION + CTEST_GIT_COMMAND + CTEST_CHECKOUT_COMMAND + CTEST_CONFIGURE_COMMAND + CTEST_SCRIPT_DIRECTORY + CTEST_USE_LAUNCHERS + ) + set(vars "${vars} ${v}=[${${v}}]\n") +endforeach(v) +message("Dashboard script configuration:\n${vars}\n") + +# Avoid non-ascii characters in tool output. +set(ENV{LC_ALL} C) + +# Helper macro to write the initial cache. +macro(write_cache) + set(cache_build_type "") + set(cache_make_program "") + if(CTEST_CMAKE_GENERATOR MATCHES "Make|Ninja") + set(cache_build_type CMAKE_BUILD_TYPE:STRING=${CTEST_BUILD_CONFIGURATION}) + if(CMAKE_MAKE_PROGRAM) + set(cache_make_program CMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}) + endif() + endif() + file(WRITE ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt " +SITE:STRING=${CTEST_SITE} +BUILDNAME:STRING=${CTEST_BUILD_NAME} +CTEST_TEST_CTEST:BOOL=${CTEST_TEST_CTEST} +CTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} +DART_TESTING_TIMEOUT:STRING=${CTEST_TEST_TIMEOUT} +GIT_EXECUTABLE:FILEPATH=${CTEST_GIT_COMMAND} +${cache_build_type} +${cache_make_program} +${dashboard_cache} +") +endmacro(write_cache) + +if(COMMAND dashboard_hook_init) + dashboard_hook_init() +endif() + +if(dashboard_fresh) + if(EXISTS CTEST_BINARY_DIRECTORY) + message("Clearing build tree...") + ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) + else() + file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}") + endif() + message("Starting fresh build...") + write_cache() +endif() + +# Start a new submission. +if(dashboard_track) + set(dashboard_track_arg TRACK "${dashboard_track}") +endif() +message("Calling ctest_start") +if(dashboard_fresh) + if(COMMAND dashboard_hook_start) + dashboard_hook_start() + endif() + ctest_start(${dashboard_model} ${dashboard_track_arg}) + ctest_submit(PARTS Start) + if(COMMAND dashboard_hook_started) + dashboard_hook_started() + endif() +else() + ctest_start(${dashboard_model} ${dashboard_track_arg} APPEND) +endif() + +# Look for updates. +if(dashboard_do_update) + if(COMMAND dashboard_hook_update) + dashboard_hook_update() + endif() + message("Calling ctest_update...") + ctest_update(RETURN_VALUE count) + set(CTEST_CHECKOUT_COMMAND) # checkout on first iteration only + message("Found ${count} changed files") + + if(ADIOS_CTEST_SUBMIT_NOTES) + message("Submitting dashboard scripts as Notes") + # Send the main script as a note while submitting the Update part + set(CTEST_NOTES_FILES + "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}" + "${CMAKE_CURRENT_LIST_FILE}" + ) + ctest_submit(PARTS Update Notes) + else() + message("Skipping notes submission for Update step") + ctest_submit(PARTS Update) + endif() +endif() + +if(dashboard_do_configure) + if(COMMAND dashboard_hook_configure) + dashboard_hook_configure() + endif() + message("Calling ctest_configure") + ctest_configure(${dashboard_configure_args}) + if(ADIOS_CTEST_SUBMIT_NOTES) + message("Submitting CMakeCache.txt as Notes") + set(CTEST_NOTES_FILES "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt") + ctest_submit(PARTS Configure Notes) + else() + message("Skipping notes submission for Configure step") + ctest_submit(PARTS Configure) + endif() +endif() + +ctest_read_custom_files(${CTEST_BINARY_DIRECTORY}) + +if(dashboard_do_build) + if(COMMAND dashboard_hook_build) + dashboard_hook_build() + endif() + message("Calling ctest_build") + ctest_build() + ctest_submit(PARTS Build) +endif() + +if(dashboard_do_test) + if(COMMAND dashboard_hook_test) + dashboard_hook_test() + endif() + message("Calling ctest_test") + ctest_test(${CTEST_TEST_ARGS} RETURN_VALUE TEST_RESULTS) + if(${TEST_RESULTS} EQUAL 0) + message("ctest test results return value: ${TEST_RESULTS}") + else() + message(SEND_ERROR "Some tests failed") + endif() + ctest_submit(PARTS Test) +endif() + +if(dashboard_do_coverage) + if(COMMAND dashboard_hook_coverage) + dashboard_hook_coverage() + endif() + message("Calling ctest_coverage") + ctest_coverage() + ctest_submit(PARTS Coverage) +endif() + +if(dashboard_do_memcheck) + if(COMMAND dashboard_hook_memcheck) + dashboard_hook_memcheck() + endif() + message("Calling ctest_memcheck") + ctest_memcheck() + ctest_submit(PARTS MemCheck) +endif() + +if(COMMAND dashboard_hook_end) + dashboard_hook_end() +endif() diff --git a/source/adios2/ADIOSConfig.h.in b/source/adios2/ADIOSConfig.h.in index 44b9128c1f50b81c4d0458fe163833c1138aecdb..9a2570846194bfab15913bcf0d248fc3de9641ed 100644 --- a/source/adios2/ADIOSConfig.h.in +++ b/source/adios2/ADIOSConfig.h.in @@ -45,10 +45,15 @@ /* CMake Option: ADIOS_USE_DataMan=ON */ #cmakedefine ADIOS2_HAVE_DATAMAN +/* CMake Option: ADIOS_USE_SysVShMem=ON */ +#cmakedefine ADIOS2_HAVE_SYSVSHMEM + +/* Optional Language Bindings: */ + /* CMake Option: ADIOS_USE_Python=ON */ #cmakedefine ADIOS2_HAVE_PYTHON -/* CMake Option: ADIOS_USE_SysVShMem=ON */ -#cmakedefine ADIOS2_HAVE_SYSVSHMEM +/* CMake Option: ADIOS_USE_Fortran=ON */ +#cmakedefine ADIOS2_HAVE_FORTRAN #endif /* ADIOSCONFIG_H_ */ diff --git a/source/adios2/ADIOSMPI.h b/source/adios2/ADIOSMPI.h index 95ae7619aebdb9b32af02a9f6adbd7b2488f06a3..7fc6ac05188e4d41f4c51fe0131643229a1138e5 100644 --- a/source/adios2/ADIOSMPI.h +++ b/source/adios2/ADIOSMPI.h @@ -12,6 +12,7 @@ #include <mpi.h> #else #include "adios2/mpidummy.h" +using namespace adios2::mpi; #endif #include <climits> //UXXX_MAX diff --git a/source/adios2/ADIOSMPICommOnly.h b/source/adios2/ADIOSMPICommOnly.h index 0a10379f5e32289d55ffcd984e59450d6efc26bc..2dba99e435ecfb0bb83a910ae31b01699a244456 100644 --- a/source/adios2/ADIOSMPICommOnly.h +++ b/source/adios2/ADIOSMPICommOnly.h @@ -11,10 +11,18 @@ #ifdef ADIOS2_HAVE_MPI #include <mpi.h> #else +#ifdef __cplusplus namespace adios2 { +namespace mpi +{ using MPI_Comm = int; +} // end namespace mpi } // end namespace adios +using adios2::mpi::MPI_Comm; +#else +typedef int MPI_Comm; +#endif #endif #endif /* ADIOS2_ADIOSMPICOMMONLY_H_ */ diff --git a/source/adios2/ADIOSMacros.h b/source/adios2/ADIOSMacros.h index f3043732b588cbde469d3b5f9e06adcc85afa03b..1f01f9ea600594a77b764181b90a504aa3fd4174 100644 --- a/source/adios2/ADIOSMacros.h +++ b/source/adios2/ADIOSMacros.h @@ -8,6 +8,8 @@ #ifndef ADIOS2_ADIOSMACROS_H #define ADIOS2_ADIOSMACROS_H +#include <string> + #include "adios2/ADIOSTypes.h" // The ADIOS_FOREACH_TYPE_1ARG macro assumes the given argument is a macro which // takes a single argument that is a type and then inserts the given MACRO for @@ -24,6 +26,7 @@ // #define ADIOS2_FOREACH_TYPE_1ARG(MACRO) \ MACRO(char) \ + MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ MACRO(unsigned short) \ @@ -42,6 +45,7 @@ #define ADIOS2_FOREACH_PRIMITIVE_TYPE_1ARG(MACRO) \ MACRO(char) \ + MACRO(signed char) \ MACRO(unsigned char) \ MACRO(short) \ MACRO(unsigned short) \ @@ -49,6 +53,8 @@ MACRO(unsigned int) \ MACRO(long int) \ MACRO(unsigned long int) \ + MACRO(long long int) \ + MACRO(unsigned long long int) \ MACRO(float) \ MACRO(double) @@ -62,4 +68,78 @@ MACRO(float) \ MACRO(double) +#define ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(MACRO) \ + MACRO(std::string) \ + MACRO(char) \ + MACRO(signed char) \ + MACRO(unsigned char) \ + MACRO(short) \ + MACRO(unsigned short) \ + MACRO(int) \ + MACRO(unsigned int) \ + MACRO(long int) \ + MACRO(unsigned long int) \ + MACRO(long long int) \ + MACRO(unsigned long long int) \ + MACRO(float) \ + MACRO(double) \ + MACRO(long double) + +// The ADIOS_FOREACH_TYPE_2ARGS macro assumes the given argument is a macro +// which takes two arguments, the first being a type, and the second being a +// label for that type, i.e. std::complex<float> and CFloat. +// +// An example of this might be to define a virtual method for each known +// type, and since the method is virtual then it cannot be a template. +// For example: +// +// #define declare_foo(T,L) virtual const T& foo ## L (std::string bar); +// ADIOS_FOREACH_TYPE_2ARGS(declare_foo) +// #undef declare_foo +// +// is equivalent to: +// +// virtual char& foo_Char(std::string bar); +// virtual unsigned char& foo_UChar(std::string bar); +// virtual short& foo_Short(std::string bar); +// virtual unsigned short& foo_UShort(std::string bar); +// ... +// virtual std::complex<long double>& foo_CLDouble(std::string bar); +// +#define ADIOS2_FOREACH_TYPE_2ARGS(MACRO) \ + MACRO(char, Char) \ + MACRO(unsigned char, UChar) \ + MACRO(short, Short) \ + MACRO(unsigned short, UShort) \ + MACRO(int, Int) \ + MACRO(unsigned int, UInt) \ + MACRO(long int, LInt) \ + MACRO(long long int, LLInt) \ + MACRO(unsigned long int, ULInt) \ + MACRO(unsigned long long int, ULLInt) \ + MACRO(float, Float) \ + MACRO(double, Double) \ + MACRO(long double, LDouble) \ + MACRO(std::complex<float>, CFloat) \ + MACRO(std::complex<double>, CDouble) \ + MACRO(std::complex<long double>, CLDouble) + +#define ADIOS2_FOREACH_PRIMITIVE_TYPE_2ARGS(MACRO) \ + MACRO(char, Char) \ + MACRO(unsigned char, UChar) \ + MACRO(short, Short) \ + MACRO(unsigned short, UShort) \ + MACRO(int, Int) \ + MACRO(unsigned int, UInt) \ + MACRO(long int, LInt) \ + MACRO(long long int, LLInt) \ + MACRO(unsigned long int, ULInt) \ + MACRO(unsigned long long int, ULLInt) \ + MACRO(float, Float) \ + MACRO(double, Double) + +#define ADIOS2_FOREACH_COMPLEX_TYPE_2ARGS(MACRO) \ + MACRO(std::complex<float>, CFloat) \ + MACRO(std::complex<double>, CDouble) + #endif /* ADIOS2_ADIOSMACROS_H */ diff --git a/source/adios2/ADIOSTypes.h b/source/adios2/ADIOSTypes.h index bb806e56960f57681c2edd4ff500a94fc67103d5..0078b66b855ec5728cae3e43ad883c0d27fa1ddb 100644 --- a/source/adios2/ADIOSTypes.h +++ b/source/adios2/ADIOSTypes.h @@ -166,6 +166,13 @@ constexpr float DefaultBufferGrowthFactor(1.05f); * 2Gb - 100Kb (tolerance)*/ constexpr size_t DefaultMaxFileBatchSize(2147381248); +constexpr char PathSeparator = +#ifdef _WIN32 + '\\'; +#else + '/'; +#endif + // adios alias values and types constexpr bool DebugON = true; constexpr bool DebugOFF = false; diff --git a/source/adios2/CMakeLists.txt b/source/adios2/CMakeLists.txt index f0891b33b70a60ff70f7a3d075c4ba6404c76f28..8115d1ead819073920e2d3fea4ec1a707449459b 100644 --- a/source/adios2/CMakeLists.txt +++ b/source/adios2/CMakeLists.txt @@ -4,6 +4,8 @@ #------------------------------------------------------------------------------# add_library(adios2 + core/Attribute.cpp core/Attribute.tcc + core/AttributeBase.cpp core/ADIOS.cpp core/Engine.cpp core/IO.cpp core/IO.tcc @@ -16,6 +18,7 @@ add_library(adios2 core/VariableCompound.cpp core/VariableCompound.tcc #helper + helper/adiosDynamicBinder.h helper/adiosDynamicBinder.cpp helper/adiosMath.cpp helper/adiosMPIFunctions.cpp helper/adiosString.cpp @@ -26,6 +29,10 @@ add_library(adios2 # engine/bp/BPFileReader.cpp engine/bp/BPFileWriter.cpp engine/bp/BPFileWriter.tcc + engine/plugin/PluginEngine.h engine/plugin/PluginEngine.inl + engine/plugin/PluginEngine.cpp + engine/plugin/PluginEngineInterface.h engine/plugin/PluginEngineInterface.cpp + toolkit/capsule/Capsule.cpp toolkit/capsule/heap/STLVector.cpp @@ -49,9 +56,7 @@ target_include_directories(adios2 $<BUILD_INTERFACE:${ADIOS2_BINARY_DIR}/source> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ) -target_link_libraries(adios2 PRIVATE adios2sys pugixml) - -find_package(Threads REQUIRED) +target_link_libraries(adios2 PRIVATE adios2sys_interface pugixml) target_link_libraries(adios2 PUBLIC ${CMAKE_THREAD_LIBS_INIT}) if(UNIX) @@ -79,19 +84,16 @@ endif() if(ADIOS2_HAVE_BZip2) - find_package(BZip2 REQUIRED) target_sources(adios2 PRIVATE transform/compress/CompressBZip2.cpp) target_link_libraries(adios2 PRIVATE BZip2::BZip2) endif() if(ADIOS2_HAVE_ZFP) - find_package(ZFP REQUIRED) target_sources(adios2 PRIVATE transform/compress/CompressZfp.cpp) target_link_libraries(adios2 PRIVATE zfp::zfp) endif() if(ADIOS2_HAVE_MPI) - find_package(MPI COMPONENTS C REQUIRED) target_include_directories(adios2 PUBLIC ${MPI_C_INCLUDE_PATH}) target_link_libraries(adios2 PUBLIC ${MPI_C_LIBRARIES}) else() @@ -99,12 +101,6 @@ else() endif() if(ADIOS2_HAVE_ADIOS1) - if(ADIOS2_HAVE_MPI) - find_package(ADIOS1 1.12.0 REQUIRED) - else() - find_package(ADIOS1 1.12.0 COMPONENTS sequential REQUIRED) - endif() - target_sources(adios2 PRIVATE engine/adios1/ADIOS1Reader.cpp engine/adios1/ADIOS1Writer.cpp @@ -116,18 +112,6 @@ if(ADIOS2_HAVE_ADIOS1) endif() if(ADIOS2_HAVE_HDF5) - find_package(HDF5 REQUIRED) - if(ADIOS2_HAVE_MPI AND (NOT HDF5_IS_PARALLEL)) - message(FATAL_ERROR - "A sequential version of HDF5 was detected but the parallel version " - "of ADIOS is being built, which requires a parallel HDF5." - ) - elseif((NOT ADIOS2_HAVE_MPI) AND HDF5_IS_PARALLEL) - message(FATAL_ERROR - "A parallel version of HDF5 was detected but the sequential version " - "of ADIOS is being built, which requires a sequential HDF5." - ) - endif() if(HDF5_C_INCLUDE_DIRS) target_include_directories(adios2 PRIVATE ${HDF5_C_INCLUDE_DIRS}) else() diff --git a/source/adios2/core/Attribute.cpp b/source/adios2/core/Attribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e473101dcaec65e405c397f8e6122526d19a8f3 --- /dev/null +++ b/source/adios2/core/Attribute.cpp @@ -0,0 +1,17 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * Attribute.cpp : needed for template separation using Attribute.tcc + * + * Created on: Aug 3, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include "Attribute.h" +#include "Attribute.tcc" + +namespace adios2 +{ + +} // end namespace adios2 diff --git a/source/adios2/core/Attribute.h b/source/adios2/core/Attribute.h new file mode 100644 index 0000000000000000000000000000000000000000..ebac57baa185837ba88c419fa7a30d8c312457f9 --- /dev/null +++ b/source/adios2/core/Attribute.h @@ -0,0 +1,48 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * Attribute.h : template class that defines typed attributes + * + * Created on: Aug 1, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_CORE_ATTRIBUTE_H_ +#define ADIOS2_CORE_ATTRIBUTE_H_ + +#include "adios2/core/AttributeBase.h" + +namespace adios2 +{ +/** @brief Attributes provide complementary information to IO Variables*/ +template <class T> +class Attribute : public AttributeBase +{ + +public: + std::vector<T> m_DataArray; + T m_DataSingleValue; + + /** + * Data array constructor + * @param name + * @param data + * @param elements + */ + Attribute<T>(const std::string &name, const T *data, const size_t elements); + + /** + * Single value constructor + * @param name + * @param data + * @param elements + */ + Attribute<T>(const std::string &name, const T &data); + + ~Attribute<T>() = default; +}; + +} // end namespace adios2 + +#endif /* ADIOS2_CORE_ATTRIBUTE_H_ */ diff --git a/source/adios2/core/Attribute.tcc b/source/adios2/core/Attribute.tcc new file mode 100644 index 0000000000000000000000000000000000000000..69846e400f8e7ba87ca5f66d3f06f76d6f7fdba5 --- /dev/null +++ b/source/adios2/core/Attribute.tcc @@ -0,0 +1,44 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * Attribute.tcc + * + * Created on: Aug 1, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_CORE_ATTRIBUTE_TCC_ +#define ADIOS2_CORE_ATTRIBUTE_TCC_ + +#include "Attribute.h" + +#include "adios2/ADIOSMacros.h" +#include "adios2/helper/adiosFunctions.h" //GetType<T> + +namespace adios2 +{ + +#define declare_type(T) \ + \ + template <> \ + Attribute<T>::Attribute(const std::string &name, const T *array, \ + const size_t elements) \ + : AttributeBase(name, GetType<T>(), elements, false), \ + m_DataArray(std::vector<T>(array, array + elements)), \ + m_DataSingleValue() \ + { \ + } \ + \ + template <> \ + Attribute<T>::Attribute(const std::string &name, const T &value) \ + : AttributeBase(name, GetType<T>(), 1, true), m_DataSingleValue(value) \ + { \ + } + +ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_type) +#undef declare_type + +} // end namespace adios2 + +#endif /* ADIOS2_CORE_ATTRIBUTE_TCC_ */ diff --git a/source/adios2/core/AttributeBase.cpp b/source/adios2/core/AttributeBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1c7eafedb400ceb4894cff84530c4f3f20676f2 --- /dev/null +++ b/source/adios2/core/AttributeBase.cpp @@ -0,0 +1,23 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * AttributeBase.cpp + * + * Created on: Aug 1, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include "AttributeBase.h" + +namespace adios2 +{ + +AttributeBase::AttributeBase(const std::string &name, const std::string type, + const size_t elements, const bool isSingleValue) +: m_Name(name), m_Type(type), m_Elements(elements), + m_IsSingleValue(isSingleValue) +{ +} + +} // end namespace adios2 diff --git a/source/adios2/core/AttributeBase.h b/source/adios2/core/AttributeBase.h new file mode 100644 index 0000000000000000000000000000000000000000..9ed5039d5bd153eb029b45bd68aef1669b6ef833 --- /dev/null +++ b/source/adios2/core/AttributeBase.h @@ -0,0 +1,47 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * AttributeBase.h : base class for Attribute<T> class, allows RTTI at read time + * + * Created on: Aug 1, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef ADIOS2_CORE_ATTRIBUTEBASE_H_ +#define ADIOS2_CORE_ATTRIBUTEBASE_H_ + +/// \cond EXCLUDE_FROM_DOXYGEN +#include <string> +/// \endcond + +#include "adios2/ADIOSConfig.h" +#include "adios2/ADIOSTypes.h" + +namespace adios2 +{ + +class AttributeBase +{ + +public: + const std::string m_Name; + const std::string m_Type; + const size_t m_Elements; + const bool m_IsSingleValue; + + /** + * Unique constructor used by Attribute<T> derived class + * @param name + * @param type + * @param elements + */ + AttributeBase(const std::string &name, const std::string type, + const size_t elements, const bool isSingleValue); + + virtual ~AttributeBase() = default; +}; + +} // end namespace adios2 + +#endif /* ADIOS2_CORE_ATTRIBUTEBASE_H_ */ diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp index 51f7a1a78daa51ec7923a6f03c481c5812a9af59..9d19e892b7d357e35e1bbe3ef2de05ff4377df5c 100644 --- a/source/adios2/core/Engine.cpp +++ b/source/adios2/core/Engine.cpp @@ -35,7 +35,15 @@ void Engine::SetCallBack( { } -// should these functions throw an exception? +void Engine::Write(VariableBase &variable, const void *values) +{ + DoWrite(variable.m_Name, values); +} + +void Engine::Write(const std::string &variableName, const void *values) +{ + DoWrite(variableName, values); +} void Engine::Advance(const float /*timeout_sec*/) {} void Engine::Advance(const AdvanceMode /*mode*/, const float /*timeout_sec*/) {} @@ -89,13 +97,26 @@ void Engine::DoWrite(const std::string &variableName, const void *values) if (type == "compound") { - DoWrite(m_IO.GetVariableCompound(variableName), values); + VariableCompound &variable = m_IO.GetVariableCompound(variableName); + + if (m_DebugMode) + { + variable.CheckDimsBeforeWrite("Write " + variable.m_Name); + } + + DoWrite(variable, values); } #define declare_type(T) \ else if (type == GetType<T>()) \ { \ - DoWrite(m_IO.GetVariable<T>(variableName), \ - reinterpret_cast<const T *>(values)); \ + Variable<T> &variable = m_IO.GetVariable<T>(variableName); \ + \ + if (m_DebugMode) \ + { \ + variable.CheckDimsBeforeWrite("Write " + variable.m_Name); \ + } \ + \ + DoWrite(variable, reinterpret_cast<const T *>(values)); \ } ADIOS2_FOREACH_TYPE_1ARG(declare_type) #undef declare_type @@ -107,88 +128,15 @@ VariableBase *Engine::InquireVariableUnknown(const std::string &name, { return nullptr; } -Variable<char> *Engine::InquireVariableChar(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<unsigned char> *Engine::InquireVariableUChar(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<short> *Engine::InquireVariableShort(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<unsigned short> *Engine::InquireVariableUShort(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<int> *Engine::InquireVariableInt(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<unsigned int> *Engine::InquireVariableUInt(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<long int> *Engine::InquireVariableLInt(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<unsigned long int> * -Engine::InquireVariableULInt(const std::string &name, const bool readIn) -{ - return nullptr; -} -Variable<long long int> *Engine::InquireVariableLLInt(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<unsigned long long int> * -Engine::InquireVariableULLInt(const std::string &name, const bool readIn) -{ - return nullptr; -} - -Variable<float> *Engine::InquireVariableFloat(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<double> *Engine::InquireVariableDouble(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<long double> *Engine::InquireVariableLDouble(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<cfloat> *Engine::InquireVariableCFloat(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<cdouble> *Engine::InquireVariableCDouble(const std::string &name, - const bool readIn) -{ - return nullptr; -} -Variable<cldouble> *Engine::InquireVariableCLDouble(const std::string &name, - const bool readIn) -{ - return nullptr; -} +#define define(T, L) \ + Variable<T> *Engine::InquireVariable##L(const std::string &name, \ + const bool readIn) \ + { \ + return nullptr; \ + } +ADIOS2_FOREACH_TYPE_2ARGS(define) +#undef define #define declare_type(T) \ void Engine::DoScheduleRead(Variable<T> &variable, const T *values) \ @@ -212,4 +160,14 @@ void Engine::ThrowUp(const std::string function) const "\n"); } -} // end namespace adios +#define declare_template_instantiation(T) \ + template void Engine::Write<T>(Variable<T> &, const T *); \ + template void Engine::Write<T>(Variable<T> &, const T); \ + \ + template void Engine::Write<T>(const std::string &, const T *); \ + template void Engine::Write<T>(const std::string &, const T); + +ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + +} // end namespace adios2 diff --git a/source/adios2/core/Engine.h b/source/adios2/core/Engine.h index 89076d81ed938e553f5e098dfc90cb58eb5d9b58..3a405452f07e5dd2c381d3e6884eb0974900f5ec 100644 --- a/source/adios2/core/Engine.h +++ b/source/adios2/core/Engine.h @@ -37,6 +37,9 @@ namespace adios2 * Close */ class Engine { +public: + using AdvanceAsyncCallback = + std::function<void(std::shared_ptr<adios2::Engine>)>; public: /** @@ -63,31 +66,44 @@ public: void Write(Variable<T> &variable, const T *values); /** - * String version - * @param variableName + * Single value version + * @param variable * @param values */ template <class T> - void Write(const std::string &variableName, const T *values); + void Write(Variable<T> &variable, const T value); /** - * Single value version - * @param variable + * String version + * @param variableName * @param values */ template <class T> - void Write(Variable<T> &variable, const T values); + void Write(const std::string &variableName, const T *values); /** - * Single value version using string as variable handlers, allows rvalues to + * Single value version using string as variable handlers, allows + * rvalues to * be passed * @param variableName * @param values */ template <class T> - void Write(const std::string &variableName, const T values); + void Write(const std::string &variableName, const T value); - /// Read API + /** + * Runtime version for either Variable<T> or VariableCompound + * @param variable + * @param values + */ + void Write(VariableBase &variable, const void *values); + + /** + * Runtime version + * @param variableName + * @param values + */ + void Write(const std::string &variableName, const void *values); /** * @@ -234,9 +250,8 @@ public: * readers * @param callback Will be called when advance is completed. */ - virtual void - AdvanceAsync(const AdvanceMode mode, - std::function<void(std::shared_ptr<adios2::Engine>)> callback); + virtual void AdvanceAsync(const AdvanceMode mode, + AdvanceAsyncCallback callback); AdvanceStatus GetAdvanceStatus(); @@ -343,40 +358,11 @@ protected: // READ virtual VariableBase *InquireVariableUnknown(const std::string &name, const bool readIn); - virtual Variable<char> *InquireVariableChar(const std::string &name, - const bool readIn); - virtual Variable<unsigned char> * - InquireVariableUChar(const std::string &name, const bool readIn); - virtual Variable<short> *InquireVariableShort(const std::string &name, - const bool readIn); - virtual Variable<unsigned short> * - InquireVariableUShort(const std::string &name, const bool readIn); - virtual Variable<int> *InquireVariableInt(const std::string &name, - const bool readIn); - virtual Variable<unsigned int> *InquireVariableUInt(const std::string &name, - const bool readIn); - virtual Variable<long int> *InquireVariableLInt(const std::string &name, - const bool readIn); - virtual Variable<unsigned long int> * - InquireVariableULInt(const std::string &name, const bool readIn); - virtual Variable<long long int> * - InquireVariableLLInt(const std::string &name, const bool readIn); - virtual Variable<unsigned long long int> * - InquireVariableULLInt(const std::string &name, const bool readIn); - - virtual Variable<float> *InquireVariableFloat(const std::string &name, - const bool readIn); - virtual Variable<double> *InquireVariableDouble(const std::string &name, - const bool readIn); - virtual Variable<long double> * - InquireVariableLDouble(const std::string &name, const bool readIn); - - virtual Variable<cfloat> *InquireVariableCFloat(const std::string &name, - const bool readIn); - virtual Variable<cdouble> *InquireVariableCDouble(const std::string &name, - const bool readIn); - virtual Variable<cldouble> *InquireVariableCLDouble(const std::string &name, - const bool readIn); +#define declare(T, L) \ + virtual Variable<T> *InquireVariable##L(const std::string &name, \ + const bool readIn); + ADIOS2_FOREACH_TYPE_2ARGS(declare) +#undef declare // Known-type #define declare_type(T) \ @@ -394,7 +380,17 @@ private: void ThrowUp(const std::string function) const; }; -} // end namespace adios +#define declare_template_instantiation(T) \ + extern template void Engine::Write<T>(Variable<T> &, const T *); \ + extern template void Engine::Write<T>(Variable<T> &, const T); \ + \ + extern template void Engine::Write<T>(const std::string &, const T *); \ + extern template void Engine::Write<T>(const std::string &, const T); + +ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + +} // end namespace adios2 #include "Engine.inl" diff --git a/source/adios2/core/Engine.inl b/source/adios2/core/Engine.inl index dccf770fd98215718fb83fdf6c0ba771827d1b8f..486df9c53c150d2a4d2813f5db81d85d9fcf5257 100644 --- a/source/adios2/core/Engine.inl +++ b/source/adios2/core/Engine.inl @@ -24,37 +24,6 @@ T *Engine::AllocateVariable(Variable<T> &variable, T fillValue) variable.m_Name + " in call to \n"); } -template <class T> -void Engine::Write(Variable<T> &variable, const T *values) -{ - if (m_DebugMode) - { - variable.CheckDimsBeforeWrite("Write(" + variable.m_Name + ")"); - } - - DoWrite(variable, values); -} - -template <class T> -void Engine::Write(const std::string &variableName, const T *values) -{ - Write(m_IO.GetVariable<T>(variableName), values); -} - -template <class T> -void Engine::Write(Variable<T> &variable, const T values) -{ - const T val = values; // need an address for memory copy - Write(variable, &values); -} - -template <class T> -void Engine::Write(const std::string &variableName, const T values) -{ - const T val = values; // need an address for memory copy - Write(m_IO.GetVariable<T>(variableName), &values); -} - template <class T> void Engine::Read(Variable<T> &variable, T *values) { @@ -122,6 +91,6 @@ void Engine::ScheduleRead(const std::string &variableName, T &values) DoScheduleRead(variableName, &values); } -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_CORE_ENGINE_INL_ */ diff --git a/source/adios2/core/Engine.tcc b/source/adios2/core/Engine.tcc index 2aa935e722edce42f70cc55e8ca5383220be61fa..74666c7324f17e0fef9ee6ec6174763991883ece 100644 --- a/source/adios2/core/Engine.tcc +++ b/source/adios2/core/Engine.tcc @@ -16,6 +16,37 @@ namespace adios2 { +template <class T> +void Engine::Write(Variable<T> &variable, const T *values) +{ + if (m_DebugMode) + { + variable.CheckDimsBeforeWrite("Write " + variable.m_Name); + } + + DoWrite(variable, values); +} + +template <class T> +void Engine::Write(Variable<T> &variable, const T values) +{ + const T val = values; // need an address for memory copy + Write(variable, &values); +} + +template <class T> +void Engine::Write(const std::string &variableName, const T *values) +{ + Write(m_IO.GetVariable<T>(variableName), values); +} + +template <class T> +void Engine::Write(const std::string &variableName, const T values) +{ + const T val = values; // need an address for memory copy + Write(m_IO.GetVariable<T>(variableName), &values); +} + template <> Variable<char> *Engine::InquireVariable<char>(const std::string &variableName, const bool readIn) diff --git a/source/adios2/core/IO.cpp b/source/adios2/core/IO.cpp index fe70d534ec6094c44a30440ddd2072daf12bcd2b..e635a100863235e804bc300dae48218382ededc5 100644 --- a/source/adios2/core/IO.cpp +++ b/source/adios2/core/IO.cpp @@ -13,6 +13,7 @@ #include "adios2/ADIOSMPI.h" #include "adios2/engine/bp/BPFileWriter.h" +#include "adios2/engine/plugin/PluginEngine.h" #include "adios2/helper/adiosFunctions.h" //BuildParametersMap #ifdef ADIOS2_HAVE_DATAMAN // external dependencies @@ -45,6 +46,12 @@ void IO::SetIOMode(const IOMode ioMode) { m_IOMode = ioMode; }; void IO::SetParameters(const Params ¶meters) { m_Parameters = parameters; } +void IO::SetSingleParameter(const std::string key, + const std::string value) noexcept +{ + m_Parameters[key] = value; +} + const Params &IO::GetParameters() const { return m_Parameters; } unsigned int IO::AddTransport(const std::string type, const Params ¶meters) @@ -60,9 +67,77 @@ unsigned int IO::AddTransport(const std::string type, const Params ¶meters) return static_cast<unsigned int>(m_TransportsParameters.size() - 1); } +void IO::SetTransportSingleParameter(const unsigned int transportIndex, + const std::string key, + const std::string value) +{ + if (m_DebugMode) + { + if (transportIndex >= + static_cast<unsigned int>(m_TransportsParameters.size())) + { + throw std::invalid_argument("ERROR: transportIndex is larger than " + "transports created with AddTransport " + "function calls\n"); + } + } + + m_TransportsParameters[transportIndex][key] = value; +} + +VariableCompound & +IO::DefineVariableCompound(const std::string &name, const size_t sizeOfVariable, + const Dims &shape, const Dims &start, + const Dims &count, const bool constantDims) +{ + if (m_DebugMode) + { + auto itVariable = m_Variables.find(name); + if (!IsEnd(itVariable, m_Variables)) + { + throw std::invalid_argument("ERROR: variable " + name + + " exists in IO object " + m_Name + + ", in call to DefineVariable\n"); + } + } + const unsigned int size = m_Compound.size(); + auto itVariableCompound = m_Compound.emplace( + size, VariableCompound(name, sizeOfVariable, shape, start, count, + constantDims, m_DebugMode)); + m_Variables.emplace(name, std::make_pair("compound", size)); + return itVariableCompound.first->second; +} + VariableCompound &IO::GetVariableCompound(const std::string &name) { - return m_Compound.at(GetVariableIndex(name)); + return m_Compound.at(GetMapIndex(name, m_Variables, "VariableCompound")); +} + +const DataMap &IO::GetAttributesDataMap() const noexcept +{ + return m_Attributes; +} + +VariableBase *IO::GetVariableBase(const std::string &name) noexcept +{ + VariableBase *variableBase = nullptr; + auto itVariable = m_Variables.find(name); + if (itVariable == m_Variables.end()) + { + return variableBase; + } + + const std::string type(itVariable->second.first); + if (type == "compound") + { + variableBase = &GetVariableCompound(name); + } +#define declare_type(T) \ + else if (type == GetType<T>()) { variableBase = &GetVariable<T>(name); } + ADIOS2_FOREACH_TYPE_1ARG(declare_type) +#undef declare_type + + return variableBase; } std::string IO::GetVariableType(const std::string &name) const @@ -214,6 +289,10 @@ std::shared_ptr<Engine> IO::Open(const std::string &name, "HDF5 library, can't use HDF5\n"); #endif } + else if (m_EngineType == "PluginEngine") + { + engine = std::make_shared<PluginEngine>(*this, name, openMode, mpiComm); + } else { if (m_DebugMode) @@ -235,30 +314,42 @@ std::shared_ptr<Engine> IO::Open(const std::string &name, } // PRIVATE Functions -unsigned int IO::GetVariableIndex(const std::string &name) const +unsigned int IO::GetMapIndex(const std::string &name, const DataMap &dataMap, + const std::string hint) const { + auto itDataMap = dataMap.find(name); + if (m_DebugMode) { - if (!VariableExists(name)) + if (IsEnd(itDataMap, dataMap)) { - throw std::invalid_argument( - "ERROR: variable " + m_Name + - " wasn't created with DefineVariable, in call to IO object " + - m_Name + " GetVariable\n"); + throw std::invalid_argument("ERROR: " + hint + " " + m_Name + + " wasn't created with Define " + hint + + ", in call to IO object " + m_Name + + " Get" + hint + "\n"); } } - auto itVariable = m_Variables.find(name); - return itVariable->second.second; + return itDataMap->second.second; } -bool IO::VariableExists(const std::string &name) const +void IO::CheckAttributeCommon(const std::string &name) const { - bool exists = false; - if (m_Variables.count(name) == 1) + auto itAttribute = m_Attributes.find(name); + if (!IsEnd(itAttribute, m_Attributes)) { - exists = true; + throw std::invalid_argument("ERROR: attribute " + name + + " exists in IO object " + m_Name + + ", in call to DefineAttribute\n"); } - return exists; +} + +bool IO::IsEnd(DataMap::const_iterator itDataMap, const DataMap &dataMap) const +{ + if (itDataMap == dataMap.end()) + { + return true; + } + return false; } void IO::CheckTransportType(const std::string type) const @@ -275,11 +366,22 @@ void IO::CheckTransportType(const std::string type) const // Explicitly instantiate the necessary public template implementations #define define_template_instantiation(T) \ - template Variable<T> &IO::DefineVariable<T>( \ - const std::string &, const Dims, const Dims, const Dims, const bool); \ + template Variable<T> &IO::DefineVariable<T>(const std::string &, \ + const Dims &, const Dims &, \ + const Dims &, const bool); \ template Variable<T> &IO::GetVariable<T>(const std::string &); ADIOS2_FOREACH_TYPE_1ARG(define_template_instantiation) #undef define_template_instatiation +#define declare_template_instantiation(T) \ + template Attribute<T> &IO::DefineAttribute<T>(const std::string &, \ + const T *, const size_t); \ + template Attribute<T> &IO::DefineAttribute<T>(const std::string &, \ + const T &); \ + template Attribute<T> &IO::GetAttribute(const std::string &); + +ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + } // end namespace adios diff --git a/source/adios2/core/IO.h b/source/adios2/core/IO.h index 59fc9f6c7fb2589feaf1f470d230b7b6b56d0e3d..f29191dac387e7d9b97b44d9ee8b8b5d3cca1ce1 100644 --- a/source/adios2/core/IO.h +++ b/source/adios2/core/IO.h @@ -24,12 +24,16 @@ #include "adios2/ADIOSMPICommOnly.h" #include "adios2/ADIOSMacros.h" #include "adios2/ADIOSTypes.h" +#include "adios2/core/Attribute.h" #include "adios2/core/Variable.h" #include "adios2/core/VariableCompound.h" namespace adios2 { +/** used for Variables and Attributes */ +using DataMap = std::map<std::string, std::pair<std::string, unsigned int>>; + // forward declaration needed as IO is passed to Engine derived // classes class Engine; @@ -87,6 +91,14 @@ public: */ void SetParameters(const Params ¶meters = Params()); + /** + * Sets a single parameter overwriting value if key exists; + * @param key parameter key + * @param value parameter value + */ + void SetSingleParameter(const std::string key, + const std::string value) noexcept; + /** * Retrieve existing parameter set */ @@ -96,11 +108,23 @@ public: * Adds a transport and its parameters for the IO Engine * @param type must be a supported transport type * @param params acceptable parameters for a particular transport - * @return + * @return transportIndex handler */ unsigned int AddTransport(const std::string type, const Params ¶ms = Params()); + /** + * Set a single parameter to an existing transport identified with a + * transportIndex handler from AddTransport. This function overwrites + * existing parameter. + * @param transportIndex index handler from AddTransport + * @param key parameter key + * @param value parameter value + */ + void SetTransportSingleParameter(const unsigned int transportIndex, + const std::string key, + const std::string value); + /** * Define a Variable of primitive data type for I/O. * Default (name only) is a local single value, @@ -114,9 +138,10 @@ public: * @return reference to Variable object */ template <class T> - Variable<T> &DefineVariable(const std::string &name, const Dims shape = {}, - const Dims start = {}, const Dims count = {}, - const bool constantShape = false); + Variable<T> & + DefineVariable(const std::string &name, const Dims &shape = Dims{}, + const Dims &start = Dims{}, const Dims &count = Dims{}, + const bool constantDims = false); /** * Define a Variable of primitive data type for I/O. @@ -130,12 +155,39 @@ public: * change over time * @return reference to Variable object */ + template <class T> + VariableCompound &DefineVariableCompound(const std::string &name, + const Dims &shape = Dims{}, + const Dims &start = Dims{}, + const Dims &count = Dims{}, + const bool constantDims = false); + + VariableCompound &DefineVariableCompound(const std::string &name, + const size_t sizeOfVariable, + const Dims &shape = Dims{}, + const Dims &start = Dims{}, + const Dims &count = Dims{}, + const bool constantDims = false); + /** + * Define attribute from contiguous data array owned by an application + * @param name must be unique for the IO object + * @param array pointer to user data + * @param elements number of data elements + * @return reference to internal Attribute + */ template <class T> - VariableCompound & - DefineVariableCompound(const std::string &name, const Dims shape = Dims{}, - const Dims start = Dims{}, const Dims count = Dims{}, - const bool constantShape = false); + Attribute<T> &DefineAttribute(const std::string &name, const T *array, + const size_t elements); + + /** + * Define attribute from a single variable making a copy + * @param name must be unique for the IO object + * @param value single data value + * @return reference to internal Attribute + */ + template <class T> + Attribute<T> &DefineAttribute(const std::string &name, const T &value); /** * Removes an existing Variable previously created with DefineVariable or @@ -155,6 +207,14 @@ public: template <class T> Variable<T> &GetVariable(const std::string &name); + /** + * Runtime function: return a pointer to VariableBase + * @param name unique variable identifier + * @return nullptr if not found, pointer to VariableBase if variable is + * found + */ + VariableBase *GetVariableBase(const std::string &name) noexcept; + /** * Gets an existing variable of compound type by name * @param name of variable to be retrieved @@ -163,6 +223,21 @@ public: */ VariableCompound &GetVariableCompound(const std::string &name); + /** + * Return map with attributes name and type info + * @return m_Attributes + */ + const DataMap &GetAttributesDataMap() const noexcept; + + /** + * Gets an existing attribute of primitive type by name + * @param name of attribute to be retrieved + * @return reference to an existing attribute created with DefineAttribute + * throws an exception if Attribute is not found + */ + template <class T> + Attribute<T> &GetAttribute(const std::string &name); + /** * Get the type if variable (by name id) exists * @param name input id @@ -222,10 +297,11 @@ private: * pair.second = index in fixed size map (e.g. m_Int8, m_Double) * </pre> */ - std::map<std::string, std::pair<std::string, unsigned int>> m_Variables; + DataMap m_Variables; /** Variable containers based on fixed-size type */ std::map<unsigned int, Variable<char>> m_Char; + std::map<unsigned int, Variable<signed char>> m_SChar; std::map<unsigned int, Variable<unsigned char>> m_UChar; std::map<unsigned int, Variable<short>> m_Short; std::map<unsigned int, Variable<unsigned short>> m_UShort; @@ -243,25 +319,64 @@ private: std::map<unsigned int, Variable<cldouble>> m_CLDouble; std::map<unsigned int, VariableCompound> m_Compound; - std::map<std::string, std::string> m_AttributesString; - std::map<std::string, double> m_AttributesNumeric; - - std::set<std::string> m_EngineNames; - /** Gets the internal reference to a variable map for type T * This function is specialized in IO.tcc */ template <class T> std::map<unsigned int, Variable<T>> &GetVariableMap(); - /** Gets the internal index in variable map for an existing variable */ - unsigned int GetVariableIndex(const std::string &name) const; + /** + * Map holding attribute identifiers + * <pre> + * key: unique attribute name, + * value: pair.first = type as string GetType<T> from + * helper/adiosTemplates.h + * pair.second = index in fixed size map (e.g. m_Int8, m_Double) + * </pre> + */ + DataMap m_Attributes; + + std::map<unsigned int, Attribute<std::string>> m_StringA; + std::map<unsigned int, Attribute<char>> m_CharA; + std::map<unsigned int, Attribute<signed char>> m_SCharA; + std::map<unsigned int, Attribute<unsigned char>> m_UCharA; + std::map<unsigned int, Attribute<short>> m_ShortA; + std::map<unsigned int, Attribute<unsigned short>> m_UShortA; + std::map<unsigned int, Attribute<int>> m_IntA; + std::map<unsigned int, Attribute<unsigned int>> m_UIntA; + std::map<unsigned int, Attribute<long int>> m_LIntA; + std::map<unsigned int, Attribute<unsigned long int>> m_ULIntA; + std::map<unsigned int, Attribute<long long int>> m_LLIntA; + std::map<unsigned int, Attribute<unsigned long long int>> m_ULLIntA; + std::map<unsigned int, Attribute<float>> m_FloatA; + std::map<unsigned int, Attribute<double>> m_DoubleA; + std::map<unsigned int, Attribute<long double>> m_LDoubleA; + + template <class T> + std::map<unsigned int, Attribute<T>> &GetAttributeMap(); + + /** + * Gets map index for Variables or Attributes + * @param name + * @param dataMap m_Variables or m_Attributes + * @param hint "Variable", "Attribute", or "VariableCompound" + * @return index in type map + */ + unsigned int GetMapIndex(const std::string &name, const DataMap &dataMap, + const std::string hint) const; + + /** Checks if attribute exists, called from DefineAttribute different + * signatures */ + void CheckAttributeCommon(const std::string &name) const; + + std::set<std::string> m_EngineNames; /** - * Checks if variable exists by checking its name - * @param name unique variable name to be checked against existing variables - * @return true: variable name exists, false: variable name doesn't exist + * Checks if iterator points to end. Used for Variables and Attributes. + * @param itDataMap iterator to be tested + * @param dataMap map + * @return true: itDataMap == dataMap.end(), false otherwise */ - bool VariableExists(const std::string &name) const; + bool IsEnd(DataMap::const_iterator itDataMap, const DataMap &dataMap) const; void CheckTransportType(const std::string type) const; }; @@ -269,14 +384,24 @@ private: // Explicit declaration of the public template methods #define declare_template_instantiation(T) \ extern template Variable<T> &IO::DefineVariable<T>( \ - const std::string &name, const Dims, const Dims, const Dims, \ - const bool constantShape); \ + const std::string &, const Dims &, const Dims &, const Dims &, \ + const bool); \ extern template Variable<T> &IO::GetVariable<T>(const std::string &name); ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) #undef declare_template_instantiation -} // end namespace adios +#define declare_template_instantiation(T) \ + extern template Attribute<T> &IO::DefineAttribute<T>( \ + const std::string &, const T *, const size_t); \ + extern template Attribute<T> &IO::DefineAttribute<T>(const std::string &, \ + const T &); \ + extern template Attribute<T> &IO::GetAttribute(const std::string &); + +ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + +} // end namespace adios2 #include "adios2/core/IO.inl" diff --git a/source/adios2/core/IO.inl b/source/adios2/core/IO.inl index 6ef9299c028b5033a4030448308ee695cca69db4..4a89c759c71952c545eb8f49184d37bc49880202 100644 --- a/source/adios2/core/IO.inl +++ b/source/adios2/core/IO.inl @@ -2,7 +2,8 @@ * Distributed under the OSI-approved Apache License, Version 2.0. See * accompanying file Copyright.txt for details. * - * IO.inl inline template functions implementation of IO class + * IO.inl inline template functions implementation of IO class. VariableCompound + * can take any type so must be inlined as type is not known a priori. * * Created on: May 15, 2017 * Author: William F Godoy godoywf@ornl.gov @@ -21,27 +22,14 @@ namespace adios2 template <class T> VariableCompound &IO::DefineVariableCompound(const std::string &name, - const Dims shape, const Dims start, - const Dims count, - const bool constantShape) + const Dims &shape, const Dims &start, + const Dims &count, + const bool constantDims) { - if (m_DebugMode) - { - if (VariableExists(name)) - { - throw std::invalid_argument("ERROR: variable " + name + - " exists in IO object " + m_Name + - ", in call to DefineVariable\n"); - } - } - const unsigned int size = m_Compound.size(); - auto itVariableCompound = m_Compound.emplace( - size, VariableCompound(name, sizeof(T), shape, start, count, - constantShape, m_DebugMode)); - m_Variables.emplace(name, std::make_pair("compound", size)); - return itVariableCompound.first->second; + return DefineVariableCompound(name, sizeof(T), shape, start, count, + constantDims); } -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_CORE_IO_INL_ */ diff --git a/source/adios2/core/IO.tcc b/source/adios2/core/IO.tcc index dddb3167848b6849ab92c1d0cfd8a16b7af1ddeb..d4c19ab8cd92b0063fc619ef7556517fd2b0aa36 100644 --- a/source/adios2/core/IO.tcc +++ b/source/adios2/core/IO.tcc @@ -26,13 +26,14 @@ namespace adios2 { template <class T> -Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape, - const Dims start, const Dims count, - const bool constantShape) +Variable<T> &IO::DefineVariable(const std::string &name, const Dims &shape, + const Dims &start, const Dims &count, + const bool constantDims) { if (m_DebugMode) { - if (VariableExists(name)) + auto itVariable = m_Variables.find(name); + if (!IsEnd(itVariable, m_Variables)) { throw std::invalid_argument("ERROR: variable " + name + " exists in IO object " + m_Name + @@ -41,10 +42,11 @@ Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape, } auto &variableMap = GetVariableMap<T>(); - const unsigned int size = variableMap.size(); + const unsigned int size = + static_cast<const unsigned int>(variableMap.size()); auto itVariablePair = variableMap.emplace(size, Variable<T>(name, shape, start, count, - constantShape, m_DebugMode)); + constantDims, m_DebugMode)); m_Variables.emplace(name, std::make_pair(GetType<T>(), size)); return itVariablePair.first->second; @@ -53,7 +55,53 @@ Variable<T> &IO::DefineVariable(const std::string &name, const Dims shape, template <class T> Variable<T> &IO::GetVariable(const std::string &name) { - return GetVariableMap<T>().at(GetVariableIndex(name)); + return GetVariableMap<T>().at(GetMapIndex(name, m_Variables, "Variable")); +} + +template <class T> +Attribute<T> &IO::DefineAttribute(const std::string &name, const T &value) +{ + if (m_DebugMode) + { + CheckAttributeCommon(name); + } + + auto &attributeMap = GetAttributeMap<T>(); + const unsigned int size = + static_cast<const unsigned int>(attributeMap.size()); + + auto itAttributePair = + attributeMap.emplace(size, Attribute<T>(name, value)); + m_Attributes.emplace(name, std::make_pair(GetType<T>(), size)); + + return itAttributePair.first->second; +} + +template <class T> +Attribute<T> &IO::DefineAttribute(const std::string &name, const T *array, + const size_t elements) +{ + if (m_DebugMode) + { + CheckAttributeCommon(name); + } + + auto &attributeMap = GetAttributeMap<T>(); + const unsigned int size = + static_cast<const unsigned int>(attributeMap.size()); + + auto itAttributePair = + attributeMap.emplace(size, Attribute<T>(name, array, elements)); + m_Attributes.emplace(name, std::make_pair(GetType<T>(), size)); + + return itAttributePair.first->second; +} + +template <class T> +Attribute<T> &IO::GetAttribute(const std::string &name) +{ + return GetAttributeMap<T>().at( + GetMapIndex(name, m_Attributes, "Attribute")); } // PRIVATE @@ -63,6 +111,12 @@ std::map<unsigned int, Variable<char>> &IO::GetVariableMap() return m_Char; } +template <> +std::map<unsigned int, Variable<signed char>> &IO::GetVariableMap() +{ + return m_SChar; +} + template <> std::map<unsigned int, Variable<unsigned char>> &IO::GetVariableMap() { @@ -153,6 +207,97 @@ std::map<unsigned int, Variable<cldouble>> &IO::GetVariableMap() return m_CLDouble; } -} // end namespace adios +// attributes +template <> +std::map<unsigned int, Attribute<std::string>> &IO::GetAttributeMap() +{ + return m_StringA; +} + +template <> +std::map<unsigned int, Attribute<char>> &IO::GetAttributeMap() +{ + return m_CharA; +} + +template <> +std::map<unsigned int, Attribute<signed char>> &IO::GetAttributeMap() +{ + return m_SCharA; +} + +template <> +std::map<unsigned int, Attribute<unsigned char>> &IO::GetAttributeMap() +{ + return m_UCharA; +} + +template <> +std::map<unsigned int, Attribute<short>> &IO::GetAttributeMap() +{ + return m_ShortA; +} + +template <> +std::map<unsigned int, Attribute<unsigned short>> &IO::GetAttributeMap() +{ + return m_UShortA; +} + +template <> +std::map<unsigned int, Attribute<int>> &IO::GetAttributeMap() +{ + return m_IntA; +} + +template <> +std::map<unsigned int, Attribute<unsigned int>> &IO::GetAttributeMap() +{ + return m_UIntA; +} + +template <> +std::map<unsigned int, Attribute<long int>> &IO::GetAttributeMap() +{ + return m_LIntA; +} + +template <> +std::map<unsigned int, Attribute<unsigned long int>> &IO::GetAttributeMap() +{ + return m_ULIntA; +} + +template <> +std::map<unsigned int, Attribute<long long int>> &IO::GetAttributeMap() +{ + return m_LLIntA; +} + +template <> +std::map<unsigned int, Attribute<unsigned long long int>> &IO::GetAttributeMap() +{ + return m_ULLIntA; +} + +template <> +std::map<unsigned int, Attribute<float>> &IO::GetAttributeMap() +{ + return m_FloatA; +} + +template <> +std::map<unsigned int, Attribute<double>> &IO::GetAttributeMap() +{ + return m_DoubleA; +} + +template <> +std::map<unsigned int, Attribute<long double>> &IO::GetAttributeMap() +{ + return m_LDoubleA; +} + +} // end namespace adios2 #endif /* ADIOS2_CORE_IO_TCC_ */ diff --git a/source/adios2/core/Variable.cpp b/source/adios2/core/Variable.cpp index 55777209f8e5382653e6d185106d1eff596c8d94..86b5e3d165d79ef6da78cd90db00ca49e64ea6fd 100644 --- a/source/adios2/core/Variable.cpp +++ b/source/adios2/core/Variable.cpp @@ -2,7 +2,7 @@ * Distributed under the OSI-approved Apache License, Version 2.0. See * accompanying file Copyright.txt for details. * - * Variable.cpp needed for template separation using Variable.tcc + * Variable.cpp : needed for template separation using Variable.tcc * * Created on: Jun 8, 2017 * Author: William F Godoy godoywf@ornl.gov @@ -14,4 +14,4 @@ namespace adios2 { -} // end namespace adios +} // end namespace adios2 diff --git a/source/adios2/core/Variable.h b/source/adios2/core/Variable.h index 9ed428735bb8f924d61d7314cd94fbd49084a781..dbf5ec2dc00f5754d098f8ef79c8cee44f971b3f 100644 --- a/source/adios2/core/Variable.h +++ b/source/adios2/core/Variable.h @@ -18,8 +18,6 @@ #include <vector> /// \endcond -#include "adios2/ADIOSMacros.h" -#include "adios2/core/Transform.h" #include "adios2/core/VariableBase.h" namespace adios2 @@ -50,15 +48,15 @@ public: * @param constantShape * @param debugMode */ - Variable<T>(const std::string &name, const Dims shape, const Dims start, - const Dims count, const bool constantShape, + Variable<T>(const std::string &name, const Dims &shape, const Dims &start, + const Dims &count, const bool constantShape, const bool debugMode); - virtual ~Variable<T>() = default; + ~Variable<T>() = default; void ApplyTransforms() final; }; -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_CORE_VARIABLE_H_ */ diff --git a/source/adios2/core/Variable.tcc b/source/adios2/core/Variable.tcc index e5a241109009f95fd99e07aa5750f5bfca1a93a7..0de077a2e58fc3dd66314eca48143213f82c335d 100644 --- a/source/adios2/core/Variable.tcc +++ b/source/adios2/core/Variable.tcc @@ -14,7 +14,7 @@ #include "Variable.h" #include "adios2/ADIOSMacros.h" -#include "adios2/helper/adiosFunctions.h" //GetType +#include "adios2/helper/adiosFunctions.h" //GetType<T> namespace adios2 { @@ -22,11 +22,11 @@ namespace adios2 #define declare_type(T) \ \ template <> \ - Variable<T>::Variable(const std::string &name, const Dims shape, \ - const Dims start, const Dims count, \ - const bool constantShape, const bool debugMode) \ + Variable<T>::Variable(const std::string &name, const Dims &shape, \ + const Dims &start, const Dims &count, \ + const bool constantDims, const bool debugMode) \ : VariableBase(name, GetType<T>(), sizeof(T), shape, start, count, \ - constantShape, debugMode) \ + constantDims, debugMode) \ { \ } \ \ @@ -38,6 +38,6 @@ namespace adios2 ADIOS2_FOREACH_TYPE_1ARG(declare_type) #undef declare_type -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_CORE_VARIABLE_TCC_ */ diff --git a/source/adios2/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp index d98f572d15db6b399d008e6d5c4364cbbd29f91c..775944e0a775fb2f0ff635c36b50ec790cdf54f0 100644 --- a/source/adios2/core/VariableBase.cpp +++ b/source/adios2/core/VariableBase.cpp @@ -21,8 +21,8 @@ namespace adios2 { VariableBase::VariableBase(const std::string &name, const std::string type, - const size_t elementSize, const Dims shape, - const Dims start, const Dims count, + const size_t elementSize, const Dims &shape, + const Dims &start, const Dims &count, const bool constantDims, const bool debugMode) : m_Name(name), m_Type(type), m_ElementSize(elementSize), m_Shape(shape), m_Start(start), m_Count(count), m_ConstantDims(constantDims), @@ -41,7 +41,7 @@ size_t VariableBase::TotalSize() const noexcept return GetTotalSize(m_Count); } -void VariableBase::SetSelection(const Dims start, const Dims count) +void VariableBase::SetSelection(const Dims &start, const Dims &count) { if (m_DebugMode) { diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h index 61fc093dfd72f5860565edc4eb5da69d5ec72611..f169a3299d8251eda7f6d599e6ec2b042673c15d 100644 --- a/source/adios2/core/VariableBase.h +++ b/source/adios2/core/VariableBase.h @@ -63,8 +63,8 @@ public: unsigned int m_AvailableSteps = 1; VariableBase(const std::string &name, const std::string type, - const size_t elementSize, const Dims shape, const Dims start, - const Dims count, const bool constantShape, + const size_t elementSize, const Dims &shape, const Dims &start, + const Dims &count, const bool constantShape, const bool debugMode); virtual ~VariableBase() = default; @@ -82,7 +82,7 @@ public: size_t TotalSize() const noexcept; /** Set the local dimension and global offset of the variable */ - void SetSelection(const Dims start, const Dims count); + void SetSelection(const Dims &start, const Dims &count); /** Overloaded version of SetSelection using a SelectionBoundingBox */ void SetSelection(const SelectionBoundingBox &selection); diff --git a/source/adios2/core/VariableCompound.cpp b/source/adios2/core/VariableCompound.cpp index ab946581dfcc080b8ca509e1ae3ee37981e906b0..8fee9b54b27b93878ec858c3fab41717249bb6bc 100644 --- a/source/adios2/core/VariableCompound.cpp +++ b/source/adios2/core/VariableCompound.cpp @@ -19,10 +19,10 @@ namespace adios2 VariableCompound::VariableCompound(const std::string name, const size_t sizeOfStruct, const Dims shape, const Dims start, const Dims count, - const bool constantShape, + const bool constantDims, const bool debugMode) : VariableBase(name, "compound", sizeOfStruct, shape, start, count, - constantShape, debugMode) + constantDims, debugMode) { } diff --git a/source/adios2/core/VariableCompound.h b/source/adios2/core/VariableCompound.h index 369058c8553c456451a558827b21fe1b22bd9506..70494e0e6968f6ee96dbfea8a41569510e31fc43 100644 --- a/source/adios2/core/VariableCompound.h +++ b/source/adios2/core/VariableCompound.h @@ -41,7 +41,7 @@ public: VariableCompound(const std::string name, const std::size_t sizeOfStruct, const Dims shape, const Dims start, const Dims count, - const bool constantShape, const bool debugMode); + const bool constantDims, const bool debugMode); ~VariableCompound() = default; diff --git a/source/adios2/engine/bp/BPFileWriter.cpp b/source/adios2/engine/bp/BPFileWriter.cpp index a37b69c68de70986c81a5ae00d2557b8cdc548d4..175d9975645db538748c467d26635aaeeced01d5 100644 --- a/source/adios2/engine/bp/BPFileWriter.cpp +++ b/source/adios2/engine/bp/BPFileWriter.cpp @@ -12,6 +12,7 @@ #include "BPFileWriter.tcc" #include "adios2/ADIOSMPI.h" +#include "adios2/ADIOSMacros.h" #include "adios2/core/IO.h" #include "adios2/helper/adiosFunctions.h" //CheckIndexRange #include "adios2/toolkit/transport/file/FileStream.h" @@ -47,7 +48,7 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_type) void BPFileWriter::Advance(const float /*timeout_sec*/) { - m_BP1Writer.Advance(); + m_BP1Writer.Advance(m_IO); } void BPFileWriter::Close(const int transportIndex) @@ -65,7 +66,7 @@ void BPFileWriter::Close(const int transportIndex) } // close bp buffer by flattening data and metadata - m_BP1Writer.Close(); + m_BP1Writer.Close(m_IO); // send data to corresponding transports m_TransportsManager.WriteFiles(m_BP1Writer.m_HeapBuffer.GetData(), m_BP1Writer.m_HeapBuffer.m_DataPosition, diff --git a/source/adios2/engine/bp/BPFileWriter.tcc b/source/adios2/engine/bp/BPFileWriter.tcc index 649201ff80c59527eafed3ea291d0c4fe66861d4..d6ccde49cd61661e3bf1b5ec758e3306660c9292 100644 --- a/source/adios2/engine/bp/BPFileWriter.tcc +++ b/source/adios2/engine/bp/BPFileWriter.tcc @@ -34,15 +34,9 @@ void BPFileWriter::DoWriteCommon(Variable<T> &variable, const T *values) const size_t newSize = m_BP1Writer.m_HeapBuffer.GetDataSize(); - // if (resizeResult == format::BP1Base::ResizeResult::Success) - // { - // std::cout << "Old buffer size: " << oldSize << "\n"; - // std::cout << "New buffer size: " << newSize << "\n"; - // } - if (resizeResult == format::BP1Base::ResizeResult::Flush) { - m_BP1Writer.Flush(); + m_BP1Writer.Flush(m_IO); auto &heapBuffer = m_BP1Writer.m_HeapBuffer; m_TransportsManager.WriteFiles(heapBuffer.GetData(), diff --git a/source/adios2/engine/hdf5/HDF5ReaderP.cpp b/source/adios2/engine/hdf5/HDF5ReaderP.cpp index a1d3b8c3c664171189042ad1133ee87fc33ad901..985514e9bdc0a640dc631b974c06230fd87c790f 100644 --- a/source/adios2/engine/hdf5/HDF5ReaderP.cpp +++ b/source/adios2/engine/hdf5/HDF5ReaderP.cpp @@ -77,13 +77,17 @@ void HDF5ReaderP::UseHDFRead(const std::string &variableName, T *values, 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}; + // hsize_t start[ndims] = {0}, count[ndims] = {0}, stride[ndims] = {1}; + hsize_t start[ndims], count[ndims], stride[ndims]; int totalElements = 1; for (int i = 0; i < ndims; i++) { count[i] = dims[i]; totalElements *= dims[i]; + start[i] = 0; + count[i] = 0; + stride[i] = 1; } start[0] = rank * dims[0] / size; diff --git a/source/adios2/engine/plugin/PluginEngine.cpp b/source/adios2/engine/plugin/PluginEngine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c81aa060fa61b6e8b135d801f9e1682f0b57eb6d --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.cpp @@ -0,0 +1,191 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.cpp + * + * Created on: July 17, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#include "PluginEngine.h" +#include "PluginEngineInterface.h" + +#include <functional> +#include <map> +#include <memory> +#include <stdexcept> +#include <utility> + +#include "adios2/helper/adiosDynamicBinder.h" + +namespace adios2 +{ + +/******************************************************************************/ + +struct PluginEngine::Impl +{ + using Registry = + std::map<std::string, std::pair<EngineCreateFun, EngineDestroyFun>>; + static Registry m_Registry; + + std::string m_PluginName; + std::unique_ptr<adios2::DynamicBinder> m_Binder; + EngineCreateFun m_HandleCreate; + EngineDestroyFun m_HandleDestroy; + PluginEngineInterface *m_Plugin = nullptr; +}; +PluginEngine::Impl::Registry PluginEngine::Impl::m_Registry; + +/******************************************************************************/ + +void PluginEngine::RegisterPlugin(const std::string pluginName, + EngineCreateFun create, + EngineDestroyFun destroy) +{ + PluginEngine::Impl::m_Registry.emplace(pluginName, + std::make_pair(create, destroy)); +} + +/******************************************************************************/ + +PluginEngine::PluginEngine(IO &io, const std::string &name, + const OpenMode openMode, MPI_Comm mpiComm) +: Engine("Plugin", io, name, openMode, mpiComm), m_Impl(new Impl) +{ + Init(); + m_Impl->m_Plugin = + m_Impl->m_HandleCreate(io, m_Impl->m_PluginName, openMode, mpiComm); +} + +PluginEngine::~PluginEngine() { m_Impl->m_HandleDestroy(m_Impl->m_Plugin); } + +void PluginEngine::PerformReads(ReadMode mode) +{ + m_Impl->m_Plugin->PerformReads(mode); +} + +void PluginEngine::Release() { m_Impl->m_Plugin->Release(); } + +void PluginEngine::Advance(const float timeoutSeconds) +{ + m_Impl->m_Plugin->Advance(timeoutSeconds); +} + +void PluginEngine::Advance(const AdvanceMode mode, const float timeoutSeconds) +{ + m_Impl->m_Plugin->Advance(mode, timeoutSeconds); +} + +void PluginEngine::AdvanceAsync(const AdvanceMode mode, + AdvanceAsyncCallback callback) +{ + m_Impl->m_Plugin->AdvanceAsync(mode, callback); +} + +void PluginEngine::SetCallBack( + std::function<void(const void *, std::string, std::string, std::string, + std::vector<size_t>)> + callback) +{ + m_Impl->m_Plugin->SetCallBack(callback); +} + +void PluginEngine::Close(const int transportIndex) +{ + m_Impl->m_Plugin->Close(transportIndex); +} + +void PluginEngine::Init() +{ + auto paramPluginNameIt = m_IO.m_Parameters.find("PluginName"); + if (paramPluginNameIt == m_IO.m_Parameters.end()) + { + throw std::invalid_argument("PluginEngine: PluginName must be " + "specified in engine parameters"); + } + m_Impl->m_PluginName = paramPluginNameIt->second; + + // First we check to see if we can find the plugin currently registerd + auto registryEntryIt = + PluginEngine::Impl::m_Registry.find(m_Impl->m_PluginName); + + if (registryEntryIt != PluginEngine::Impl::m_Registry.end()) + { + m_Impl->m_HandleCreate = registryEntryIt->second.first; + m_Impl->m_HandleDestroy = registryEntryIt->second.second; + } + else + { + // It's not currently registered so try to load it from a shared + // library + // + auto paramPluginLibraryIt = m_IO.m_Parameters.find("PluginLibrary"); + if (paramPluginLibraryIt == m_IO.m_Parameters.end()) + { + throw std::invalid_argument( + "PluginEngine: PluginLibrary must be specified in " + "engine parameters if no PluginName " + "is specified"); + } + std::string &pluginLibrary = paramPluginLibraryIt->second; + + m_Impl->m_Binder.reset(new adios2::DynamicBinder(pluginLibrary)); + + m_Impl->m_HandleCreate = reinterpret_cast<EngineCreatePtr>( + m_Impl->m_Binder->GetSymbol("EngineCreate")); + if (!m_Impl->m_HandleCreate) + { + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineCreate symbol in specified plugin " + "library"); + } + + m_Impl->m_HandleDestroy = reinterpret_cast<EngineDestroyPtr>( + m_Impl->m_Binder->GetSymbol("EngineDestroy")); + if (!m_Impl->m_HandleDestroy) + { + throw std::runtime_error("PluginEngine: Unable to locate " + "EngineDestroy symbol in specified plugin " + "library"); + } + } +} + +#define define(T) \ + void PluginEngine::DoWrite(Variable<T> &variable, const T *values) \ + { \ + m_Impl->m_Plugin->DoWrite(variable, values); \ + } \ + void PluginEngine::DoScheduleRead(Variable<T> &variable, const T *values) \ + { \ + m_Impl->m_Plugin->DoScheduleRead(variable, values); \ + } \ + void PluginEngine::DoScheduleRead(const std::string &variableName, \ + const T *values) \ + { \ + m_Impl->m_Plugin->DoScheduleRead(variableName, values); \ + } +ADIOS2_FOREACH_TYPE_1ARG(define) +#undef define +void PluginEngine::DoWrite(VariableCompound &variable, const void *values) +{ + m_Impl->m_Plugin->DoWrite(variable, values); +} + +#define define(T, L) \ + Variable<T> *PluginEngine::InquireVariable##L(const std::string &name, \ + const bool readIn) \ + { \ + return m_Impl->m_Plugin->InquireVariable##L(name, readIn); \ + } +ADIOS2_FOREACH_TYPE_2ARGS(define) +#undef define +VariableBase *PluginEngine::InquireVariableUnknown(const std::string &name, + const bool readIn) +{ + return m_Impl->m_Plugin->InquireVariableUnknown(name, readIn); +} + +} // end namespace adios diff --git a/source/adios2/engine/plugin/PluginEngine.h b/source/adios2/engine/plugin/PluginEngine.h new file mode 100644 index 0000000000000000000000000000000000000000..290f04efdab7b4d213ffb12dea2451e8b149f2b2 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.h @@ -0,0 +1,112 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.h Support for an engine implemented outside libadios2 + * + * Created on: July 17, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ +#define ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ + +#include "PluginEngineInterface.h" + +#include <functional> // for function +#include <memory> // for unique_ptr +#include <string> // for string +#include <type_traits> // for add_pointer +#include <vector> // for vector + +#include "adios2/ADIOSMPICommOnly.h" +#include "adios2/ADIOSMacros.h" +#include "adios2/ADIOSTypes.h" +#include "adios2/core/Engine.h" +#include "adios2/core/IO.h" +#include "adios2/core/Variable.h" +#include "adios2/core/VariableCompound.h" + +namespace adios2 +{ + +/** A front-end wrapper for an engine implemented outside of libadios2 */ +class PluginEngine : public Engine +{ +public: + // Function pointers used for the plugin factory methods + + using EngineCreatePtr = std::add_pointer<PluginEngineInterface *( + IO &, const std::string &, const OpenMode, MPI_Comm)>::type; + using EngineDestroyPtr = + std::add_pointer<void(PluginEngineInterface *)>::type; + using EngineCreateFun = + std::function<std::remove_pointer<EngineCreatePtr>::type>; + using EngineDestroyFun = + std::function<std::remove_pointer<EngineDestroyPtr>::type>; + + static void RegisterPlugin(const std::string pluginName, + EngineCreateFun create, + EngineDestroyFun destroy); + static void RegisterPlugin(const std::string pluginName, + EngineCreatePtr create, EngineDestroyPtr destroy) + { + RegisterPlugin(pluginName, EngineCreateFun(create), + EngineDestroyFun(destroy)); + } + + // This is just a shortcut method to handle the case where the class type is + // directly available to the caller so a sim[ple new and delete call is + // sufficient to create and destroy the engine object + template <typename T> + static void RegisterPlugin(const std::string name); + +public: + PluginEngine(IO &io, const std::string &name, const OpenMode openMode, + MPI_Comm mpiComm); + virtual ~PluginEngine(); + + void PerformReads(ReadMode mode) override; + void Release() override; + void Advance(const float timeoutSeconds = 0.0) override; + void Advance(const AdvanceMode mode, + const float timeoutSeconds = 0.0) override; + void AdvanceAsync(const AdvanceMode mode, + AdvanceAsyncCallback callback) override; + + void SetCallBack(std::function<void(const void *, std::string, std::string, + std::string, std::vector<size_t>)> + callback) override; + + void Close(const int transportIndex = -1) override; + +protected: + void Init() override; + +#define declare(T) \ + void DoWrite(Variable<T> &variable, const T *values) override; \ + void DoScheduleRead(Variable<T> &variable, const T *values) override; \ + void DoScheduleRead(const std::string &variableName, const T *values) \ + override; + ADIOS2_FOREACH_TYPE_1ARG(declare) +#undef declare + void DoWrite(VariableCompound &variable, const void *values) override; + +#define declare(T, L) \ + Variable<T> *InquireVariable##L(const std::string &name, \ + const bool readIn) override; + ADIOS2_FOREACH_TYPE_2ARGS(declare) +#undef declare + VariableBase *InquireVariableUnknown(const std::string &name, + const bool readIn) override; + +private: + struct Impl; + std::unique_ptr<Impl> m_Impl; +}; + +} // end namespace adios + +#include "PluginEngine.inl" + +#endif /* ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ */ diff --git a/source/adios2/engine/plugin/PluginEngine.inl b/source/adios2/engine/plugin/PluginEngine.inl new file mode 100644 index 0000000000000000000000000000000000000000..e28cbd8b327c306a64cb57bc4b83bc830ee74653 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngine.inl @@ -0,0 +1,36 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngine.h Support for an engine implemented outside libadios2 + * + * Created on: July 17, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ +#define ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINE_H_ +#error "Inline file should only be included from it's header, never on it's own" +#endif + +#include "PluginEngine.h" + +namespace adios2 +{ + +template <typename T> +void PluginEngine::RegisterPlugin(const std::string name) +{ + EngineCreateFun createFun = + [](IO &io, const std::string &name, const OpenMode openMode, + MPI_Comm mpiComm) -> PluginEngineInterface * { + return new T(io, name, openMode, mpiComm); + }; + EngineDestroyFun destroyFun = [](Engine *obj) -> void { delete obj; }; + + RegisterPlugin(name, createFun, destroyFun); +} +} + +#endif // ADIOS2_ENGINE_PLUGIN_ENGINE_INL_ diff --git a/source/adios2/engine/plugin/PluginEngineInterface.cpp b/source/adios2/engine/plugin/PluginEngineInterface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6e20d69668f2e31f41c4deabe0319c130abeed4 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngineInterface.cpp @@ -0,0 +1,23 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngineInterface.cxx + * + * Created on: Aug 17, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#include "PluginEngineInterface.h" + +namespace adios2 +{ + +PluginEngineInterface::PluginEngineInterface(IO &io, const std::string &name, + const OpenMode openMode, + MPI_Comm mpiComm) +: Engine("PluginInterface", io, name, openMode, mpiComm) +{ +} + +} // end namespace adios diff --git a/source/adios2/engine/plugin/PluginEngineInterface.h b/source/adios2/engine/plugin/PluginEngineInterface.h new file mode 100644 index 0000000000000000000000000000000000000000..20d9e9c144f6b348528cf142856826b66ce24623 --- /dev/null +++ b/source/adios2/engine/plugin/PluginEngineInterface.h @@ -0,0 +1,41 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * PluginEngineInterface.h Engines using the plugin interface should derive from + * this class. + * + * Created on: July 17, 2017 + * Author: Chuck Atkins <chuck.atkins@kitware.com> + */ + +#ifndef ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ +#define ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ + +/// \cond EXCLUDE_FROM_DOXYGEN +/// \endcond + +#include "adios2/ADIOSConfig.h" +#include "adios2/ADIOSMPICommOnly.h" +#include "adios2/ADIOSTypes.h" +#include "adios2/core/Engine.h" +#include "adios2/core/IO.h" + +namespace adios2 +{ + +/** An engine interface to be used aby the plugin infrastructure */ +class PluginEngineInterface : public Engine +{ + // Give the plugin engine access to everything + friend class PluginEngine; + +public: + PluginEngineInterface(IO &io, const std::string &name, + const OpenMode openMode, MPI_Comm mpiComm); + virtual ~PluginEngineInterface() = default; +}; + +} // end namespace adios + +#endif /* ADIOS2_ENGINE_PLUGIN_PLUGINENGINEINTERFACE_H_ */ diff --git a/source/adios2/helper/adiosDynamicBinder.cpp b/source/adios2/helper/adiosDynamicBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00ecd6342178804ac83816e31f16f46f71d798a5 --- /dev/null +++ b/source/adios2/helper/adiosDynamicBinder.cpp @@ -0,0 +1,99 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * DynamicBinder.cpp + * + * Created on: Jul 21, 2017 + * Author: Chuck Atkins + */ + +#include "adiosDynamicBinder.h" + +#include <algorithm> // for copy +#include <iostream> // for operator<<, stringstream, bas... +#include <iterator> // for ostream_iterator +#include <sstream> // for stringstream +#include <stdexcept> // for runtime_error +#include <vector> // for vector + +#include <adios2sys/DynamicLoader.hxx> + +namespace adios2 +{ + +struct DynamicBinder::Impl +{ + adios2sys::DynamicLoader::LibraryHandle m_LibraryHandle; +}; + +DynamicBinder::DynamicBinder(std::string libName) +{ + std::vector<std::string> libPrefixes; + libPrefixes.emplace_back(""); + libPrefixes.emplace_back("lib"); +#ifdef __CYGWIN__ + libPrefixes.emplace_back("cyg"); +#endif + + std::vector<std::string> libSuffixes; +#ifdef __APPLE__ + libSuffixes.emplace_back(".dylib"); + libSuffixes.emplace_back(".so"); +#endif +#ifdef __hpux + libSuffixes.emplace_back(".sl"); +#endif +#ifdef __unix__ + libSuffixes.emplace_back(".so"); +#endif +#ifdef _WIN32 + libSuffixes.emplace_back(".dll"); +#endif + + std::vector<std::string> searchedLibs; + std::string fileName; + + // Test the various combinations of library names + for (const std::string &prefix : libPrefixes) + { + for (const std::string &suffix : libSuffixes) + { + fileName = prefix + libName + suffix; + m_Impl->m_LibraryHandle = + adios2sys::DynamicLoader::OpenLibrary(fileName); + searchedLibs.push_back(fileName); + if (m_Impl->m_LibraryHandle) + { + break; + } + } + if (m_Impl->m_LibraryHandle) + { + break; + } + } + if (!m_Impl->m_LibraryHandle) + { + std::stringstream errString; + errString << "Unable to locate the " << libName + << " library; searched for "; + std::copy(searchedLibs.begin(), searchedLibs.end(), + std::ostream_iterator<std::string>(errString, " ")); + + throw std::runtime_error(errString.str()); + } +} + +DynamicBinder::~DynamicBinder() +{ + adios2sys::DynamicLoader::CloseLibrary(m_Impl->m_LibraryHandle); +} + +DynamicBinder::VoidSymbolPointer +DynamicBinder::GetSymbol(std::string symbolName) +{ + return adios2sys::DynamicLoader::GetSymbolAddress(m_Impl->m_LibraryHandle, + symbolName); +} +}; diff --git a/source/adios2/helper/adiosDynamicBinder.h b/source/adios2/helper/adiosDynamicBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..5e68cde4595bf4d7f3f55e693356bb4fc08b6db0 --- /dev/null +++ b/source/adios2/helper/adiosDynamicBinder.h @@ -0,0 +1,38 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * DynamicBinder.h + * + * Created on: Jul 21, 2017 + * Author: Chuck Atkins + */ + +#ifndef ADIOS2_HELPER_DYNAMICBINDER_H_ +#define ADIOS2_HELPER_DYNAMICBINDER_H_ + +#include <memory> +#include <string> +#include <type_traits> + +namespace adios2 +{ + +class DynamicBinder +{ +public: + using VoidSymbolPointer = std::add_pointer<void()>::type; + +public: + DynamicBinder(std::string libName); + ~DynamicBinder(); + + VoidSymbolPointer GetSymbol(std::string symbolName); + +private: + struct Impl; + std::unique_ptr<Impl> m_Impl; +}; +} + +#endif // ADIOS2_HELPER_DYNAMICBINDER_H_ diff --git a/source/adios2/helper/adiosType.inl b/source/adios2/helper/adiosType.inl index 5c4243b965b168a164bfd1e5e4239ab93ac20ae3..b81bb598183f5f11080ef293a61f3ed396366718 100644 --- a/source/adios2/helper/adiosType.inl +++ b/source/adios2/helper/adiosType.inl @@ -27,12 +27,24 @@ inline std::string GetType<void>() noexcept { return "unknown"; } + +template <> +inline std::string GetType<std::string>() noexcept +{ + return "string"; +} + template <> inline std::string GetType<char>() noexcept { return "char"; } template <> +inline std::string GetType<signed char>() noexcept +{ + return "signed char"; +} +template <> inline std::string GetType<unsigned char>() noexcept { return "unsigned char"; diff --git a/source/adios2/mpidummy.cpp b/source/adios2/mpidummy.cpp index c97938e95d78063c73195ac0cacd2275335f516c..51a5dcf881e3c516d90adaee0388da69b9ccee91 100644 --- a/source/adios2/mpidummy.cpp +++ b/source/adios2/mpidummy.cpp @@ -41,6 +41,8 @@ namespace adios2 { +namespace mpi +{ static char mpierrmsg[MPI_MAX_ERROR_STRING]; @@ -380,4 +382,5 @@ int MPI_Get_processor_name(char *name, int *resultlen) return 0; } +} // end namespace mpi } // end namespace adios diff --git a/source/adios2/mpidummy.h b/source/adios2/mpidummy.h index 5457f0dd7788c55653787571271a4294878d9079..1194d2a1f9d2714d10cf6d4cd5a8496809c9431e 100644 --- a/source/adios2/mpidummy.h +++ b/source/adios2/mpidummy.h @@ -16,6 +16,8 @@ namespace adios2 { +namespace mpi +{ typedef int MPI_Comm; typedef std::uint64_t MPI_Status; @@ -123,6 +125,7 @@ int MPI_Get_processor_name(char *name, int *resultlen); double MPI_Wtime(); +} // end namespace mpi } // end namespace adios #endif /* ADIOS2_MPIDUMMY_H_ */ diff --git a/source/adios2/toolkit/format/bp1/BP1Base.cpp b/source/adios2/toolkit/format/bp1/BP1Base.cpp index ecc990f38bef44f499eb417f0e9e609845ae5a6c..8d4e6a314d3e78031870d1f652c5da7cbc936f40 100644 --- a/source/adios2/toolkit/format/bp1/BP1Base.cpp +++ b/source/adios2/toolkit/format/bp1/BP1Base.cpp @@ -11,6 +11,7 @@ #include "BP1Base.h" #include "BP1Base.tcc" +#include "adios2/ADIOSTypes.h" //PathSeparator #include "adios2/helper/adiosFunctions.h" //CreateDirectory, StringToTimeUnit namespace adios2 @@ -111,8 +112,16 @@ BP1Base::GetBPNames(const std::vector<std::string> &baseNames) const noexcept const int rank) -> std::string { const std::string bpBaseName = AddExtension(baseName, ".bp"); - // name.bp.dir/name.bp.rank - const std::string bpName(bpBaseName + ".dir/" + bpBaseName + "." + + + // path/root.bp.dir/root.bp.rank + std::string bpRootName = bpBaseName; + const auto lastPathSeparator(bpBaseName.find_last_of(PathSeparator)); + + if (lastPathSeparator != std::string::npos) + { + bpRootName = bpBaseName.substr(lastPathSeparator); + } + const std::string bpName(bpBaseName + ".dir/" + bpRootName + "." + std::to_string(rank)); return bpName; }; @@ -424,4 +433,4 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) #undef declare_template_instantiation } // end namespace format -} // end namespace adios +} // end namespace adios2 diff --git a/source/adios2/toolkit/format/bp1/BP1Base.h b/source/adios2/toolkit/format/bp1/BP1Base.h index 084a26298cbb7bbd879ddfe4f153ee85b57ee5ea..083c3861ab20268ccfd283e07e389e3c96228bf6 100644 --- a/source/adios2/toolkit/format/bp1/BP1Base.h +++ b/source/adios2/toolkit/format/bp1/BP1Base.h @@ -303,6 +303,6 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) #undef declare_template_instantiation } // end namespace format -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1BASE_H_ */ diff --git a/source/adios2/toolkit/format/bp1/BP1Base.tcc b/source/adios2/toolkit/format/bp1/BP1Base.tcc index 4d5aab4e14dc8dfe209175d819f849517c8f56a9..58b361b465d985fbfa27db2e416824c45ea7ca2b 100644 --- a/source/adios2/toolkit/format/bp1/BP1Base.tcc +++ b/source/adios2/toolkit/format/bp1/BP1Base.tcc @@ -22,12 +22,24 @@ namespace adios2 namespace format { +template <> +int8_t BP1Base::GetDataType<std::string>() const noexcept +{ + return type_string; +} + template <> int8_t BP1Base::GetDataType<char>() const noexcept { return type_byte; } +template <> +int8_t BP1Base::GetDataType<signed char>() const noexcept +{ + return type_byte; +} + template <> int8_t BP1Base::GetDataType<short>() const noexcept { diff --git a/source/adios2/toolkit/format/bp1/BP1Structs.h b/source/adios2/toolkit/format/bp1/BP1Structs.h index b62b79f582d855fa5646a53bbfb364a6f29313f7..9d1724c9f2210858fb063500ba5a1c3e03a26d57 100644 --- a/source/adios2/toolkit/format/bp1/BP1Structs.h +++ b/source/adios2/toolkit/format/bp1/BP1Structs.h @@ -58,7 +58,8 @@ struct BP1MetadataSet */ uint32_t TimeStep = 1; - BP1Index PGIndex = BP1Index(0); ///< single buffer for PGIndex + /** single buffer for PGIndex */ + BP1Index PGIndex = BP1Index(0); // no priority for now /** @brief key: variable name, value: bp metadata variable index */ @@ -67,7 +68,10 @@ struct BP1MetadataSet /** @brief key: attribute name, value: bp metadata attribute index */ std::unordered_map<std::string, BP1Index> AttributesIndices; - const unsigned int MiniFooterSize = 28; ///< from bpls reader + bool AreAttributesWritten = false; + + /** Fixed size for mini footer */ + const unsigned int MiniFooterSize = 28; // PG (relative) positions in Data buffer, to be updated every advance step // or init @@ -85,6 +89,6 @@ struct BP1MetadataSet }; } // end namespace format -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_TOOLKIT_FORMAT_BP1_BP1STRUCTS_H_ */ diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.cpp b/source/adios2/toolkit/format/bp1/BP1Writer.cpp index 7bc9f34b18e379806764b3c36808272b03d67e76..103d56e03a0b944ccd2c0a9d1c3d83eec097055d 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.cpp +++ b/source/adios2/toolkit/format/bp1/BP1Writer.cpp @@ -14,6 +14,8 @@ #include <string> #include <vector> +#include "adios2/helper/adiosFunctions.h" //GetType<T> + namespace adios2 { namespace format @@ -117,10 +119,14 @@ void BP1Writer::WriteProcessGroupIndex( } } -void BP1Writer::Advance() +void BP1Writer::Advance(IO &io) { // enforce memory policy here to restrict buffer size for each timestep // this is flushing + if (m_Profiler.IsActive) + { + m_Profiler.Timers.at("buffering").Resume(); + } if (m_MaxBufferSize == DefaultMaxBufferSize) { @@ -128,12 +134,7 @@ void BP1Writer::Advance() m_MaxBufferSize = m_HeapBuffer.m_DataPosition + 64; } - if (m_Profiler.IsActive) - { - m_Profiler.Timers.at("buffering").Resume(); - } - - FlattenData(); + FlattenData(io); ++m_MetadataSet.TimeStep; if (m_Profiler.IsActive) @@ -142,14 +143,14 @@ void BP1Writer::Advance() } } -void BP1Writer::Flush() +void BP1Writer::Flush(IO &io) { if (m_Profiler.IsActive) { m_Profiler.Timers.at("buffering").Resume(); } - FlattenData(); + FlattenData(io); if (m_Profiler.IsActive) { @@ -157,7 +158,7 @@ void BP1Writer::Flush() } } -void BP1Writer::Close() noexcept +void BP1Writer::Close(IO &io) noexcept { if (m_Profiler.IsActive) { @@ -168,7 +169,7 @@ void BP1Writer::Close() noexcept { if (m_MetadataSet.DataPGIsOpen) { - FlattenData(); + FlattenData(io); } FlattenMetadata(); @@ -248,9 +249,64 @@ BP1Writer::AggregateProfilingJSON(const std::string &rankProfilingLog) noexcept } // PRIVATE FUNCTIONS -void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, - const Dims globalDimensions, - const Dims offsets, +void BP1Writer::WriteAttributes(IO &io) +{ + const auto attributesDataMap = io.GetAttributesDataMap(); + + auto &buffer = m_HeapBuffer.m_Data; + auto &position = m_HeapBuffer.m_DataPosition; + + // used only to update m_HeapBuffer.m_DataAbsolutePosition; + const size_t attributesCountPosition = position; + + // count is known ahead of time, write + const uint32_t attributesCount = + static_cast<const uint32_t>(attributesDataMap.size()); + CopyToBuffer(buffer, position, &attributesCount); + + // will go back + const size_t attributesLengthPosition = position; + position += 8; // skip attributes length + + m_HeapBuffer.m_DataAbsolutePosition += position - attributesCountPosition; + + uint32_t memberID = 0; + + for (const auto &attributePair : attributesDataMap) + { + const std::string name(attributePair.first); + const std::string type(attributePair.second.first); + + if (type == "unknown") + { + } +#define declare_type(T) \ + else if (type == GetType<T>()) \ + { \ + Stats<T> stats; \ + stats.Offset = m_HeapBuffer.m_DataAbsolutePosition; \ + stats.MemberID = memberID; \ + Attribute<T> &attribute = io.GetAttribute<T>(name); \ + WriteAttributeInData(attribute, stats); \ + WriteAttributeInIndex(attribute, stats); \ + } + ADIOS2_FOREACH_ATTRIBUTE_TYPE_1ARG(declare_type) +#undef declare_type + + ++memberID; + } + + // complete attributes length + const uint64_t attributesLength = + static_cast<const uint64_t>(position - attributesLengthPosition); + + size_t backPosition = attributesLengthPosition; + CopyToBuffer(buffer, backPosition, &attributesLength); +} + +void BP1Writer::WriteDimensionsRecord(const Dims &localDimensions, + const Dims &globalDimensions, + const Dims &offsets, std::vector<char> &buffer) noexcept { if (offsets.empty()) @@ -272,9 +328,9 @@ void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, } } -void BP1Writer::WriteDimensionsRecord(const Dims localDimensions, - const Dims globalDimensions, - const Dims offsets, +void BP1Writer::WriteDimensionsRecord(const Dims &localDimensions, + const Dims &globalDimensions, + const Dims &offsets, std::vector<char> &buffer, size_t &position, const bool isCharacteristic) noexcept @@ -356,7 +412,7 @@ BP1Writer::GetBP1Index(const std::string name, return itName->second; } -void BP1Writer::FlattenData() noexcept +void BP1Writer::FlattenData(IO &io) noexcept { auto &buffer = m_HeapBuffer.m_Data; auto &position = m_HeapBuffer.m_DataPosition; @@ -369,13 +425,19 @@ void BP1Writer::FlattenData() noexcept position - m_MetadataSet.DataPGVarsCountPosition - 8 - 4; CopyToBuffer(buffer, m_MetadataSet.DataPGVarsCountPosition, &varsLength); - // attributes (empty for now) count (4) and length (8) are zero by moving - // positions in time step zero - position += 12; - m_HeapBuffer.m_DataAbsolutePosition += 12; + // attributes are only written once + if (!m_MetadataSet.AreAttributesWritten) + { + WriteAttributes(io); + m_MetadataSet.AreAttributesWritten = true; + } + else + { + position += 12; + m_HeapBuffer.m_DataAbsolutePosition += 12; + } - // Finish writing pg group length - // without record itself, 12 due to empty attributes + // Finish writing pg group length without record itself const uint64_t dataPGLength = position - m_MetadataSet.DataPGLengthPosition - 8; CopyToBuffer(buffer, m_MetadataSet.DataPGLengthPosition, &dataPGLength); @@ -385,7 +447,7 @@ void BP1Writer::FlattenData() noexcept void BP1Writer::FlattenMetadata() noexcept { - auto lf_IndexCountLength = + auto lf_SetIndexCountLength = [](std::unordered_map<std::string, BP1Index> &indices, uint32_t &count, uint64_t &length) { @@ -426,12 +488,13 @@ void BP1Writer::FlattenMetadata() noexcept // var index count and length (total), and each index length uint32_t varsCount; uint64_t varsLength; - lf_IndexCountLength(m_MetadataSet.VarsIndices, varsCount, varsLength); + lf_SetIndexCountLength(m_MetadataSet.VarsIndices, varsCount, varsLength); + // attribute index count and length, and each index length uint32_t attributesCount; uint64_t attributesLength; - lf_IndexCountLength(m_MetadataSet.AttributesIndices, attributesCount, - attributesLength); + lf_SetIndexCountLength(m_MetadataSet.AttributesIndices, attributesCount, + attributesLength); const size_t footerSize = static_cast<const size_t>( (pgLength + 16) + (varsLength + 12) + (attributesLength + 12) + diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.h b/source/adios2/toolkit/format/bp1/BP1Writer.h index 7f65b749e2730dece386db1e273a4f77cf7208cf..5ba3fed6f527dbba902cfb4c9bfed640370319e7 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.h +++ b/source/adios2/toolkit/format/bp1/BP1Writer.h @@ -20,6 +20,8 @@ #include "adios2/ADIOSConfig.h" #include "adios2/ADIOSMacros.h" #include "adios2/ADIOSTypes.h" +#include "adios2/core/Attribute.h" +#include "adios2/core/IO.h" #include "adios2/core/Variable.h" #include "adios2/toolkit/capsule/heap/STLVector.h" #include "adios2/toolkit/format/bp1/BP1Base.h" @@ -41,7 +43,7 @@ public: */ BP1Writer(MPI_Comm mpiComm, const bool debugMode = false); - virtual ~BP1Writer() = default; + ~BP1Writer() = default; /** * Writes a process group index PGIndex and list of methods (from @@ -69,16 +71,16 @@ public: void WriteVariablePayload(const Variable<T> &variable) noexcept; /** Flattens data buffer and closes current process group */ - void Advance(); + void Advance(IO &io); /** Flattens data buffer and close current process group, doesn't * advance time index */ - void Flush(); + void Flush(IO &io); /** * @param isFirstClose true: first time close, false: already closed buffer */ - void Close() noexcept; + void Close(IO &io) noexcept; /** * Get a string with profiling information for this rank @@ -102,6 +104,65 @@ private: /** BP format version */ const uint8_t m_Version = 3; + /** + * Writes in BP buffer all attributes defined in an IO object. + * Called by FlattenData function + * @param io input containing attributes + */ + void WriteAttributes(IO &io); + + /** + * Called from WriteAttributeInData specialized functions + * @param attribute input + * @param stats + * @return attribute length position + */ + template <class T> + size_t WriteAttributeHeaderInData(const Attribute<T> &attribute, + Stats<T> &stats) noexcept; + + /** + * Called from WriteAttributeInData specialized functions + * @param attribute input + * @param stats + * @param attributeLengthPosition + */ + template <class T> + void + WriteAttributeLengthInData(const Attribute<T> &attribute, Stats<T> &stats, + const size_t attributeLengthPosition) noexcept; + + /** + * Write a single attribute in data buffer, called from WriteAttributes + * @param attribute input + * @param stats + */ + template <class T> + void WriteAttributeInData(const Attribute<T> &attribute, + Stats<T> &stats) noexcept; + + /** + * Writes attribute value in index characteristic value. + * @param characteristicID + * @param characteristicsCounter + * @param attribute + * @param buffer + */ + template <class T> + void WriteAttributeCharacteristicValueInIndex( + std::uint8_t &characteristicsCounter, const Attribute<T> &attribute, + std::vector<char> &buffer) noexcept; + + /** + * Write a single attribute in m_Metadata AttributesIndex, called from + * WriteAttributes + * @param attribute + * @param stats + */ + template <class T> + void WriteAttributeInIndex(const Attribute<T> &attribute, + const Stats<T> &stats) noexcept; + /** * Get variable statistics * @param variable @@ -160,14 +221,16 @@ private: * data * characteristic */ - void WriteDimensionsRecord(const Dims localDimensions, - const Dims globalDimensions, const Dims offsets, + void WriteDimensionsRecord(const Dims &localDimensions, + const Dims &globalDimensions, + const Dims &offsets, std::vector<char> &buffer) noexcept; /** Overloaded version for data buffer */ - void WriteDimensionsRecord(const Dims localDimensions, - const Dims globalDimensions, const Dims offsets, - std::vector<char> &buffer, size_t &position, + void WriteDimensionsRecord(const Dims &localDimensions, + const Dims &globalDimensions, + const Dims &offsets, std::vector<char> &buffer, + size_t &position, const bool isCharacteristic = false) noexcept; /** Writes min max */ @@ -224,7 +287,7 @@ private: * @param metadataSet * @param buffer */ - void FlattenData() noexcept; + void FlattenData(IO &io) noexcept; /** * Flattens the metadata indices into a single metadata buffer in capsule @@ -245,6 +308,6 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) #undef declare_template_instantiation } // end namespace format -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_UTILITIES_FORMAT_BP1_BP1WRITER_H_ */ diff --git a/source/adios2/toolkit/format/bp1/BP1Writer.tcc b/source/adios2/toolkit/format/bp1/BP1Writer.tcc index c1aa88ca6643d8e98fe48c3c4145b137b7ec7ff4..321edf743638cd0e293f5f64dd90e6bd6a1d36b6 100644 --- a/source/adios2/toolkit/format/bp1/BP1Writer.tcc +++ b/source/adios2/toolkit/format/bp1/BP1Writer.tcc @@ -62,6 +62,7 @@ void BP1Writer::WriteVariablePayload(const Variable<T> &variable) noexcept CopyToBufferThreads(m_HeapBuffer.m_Data, m_HeapBuffer.m_DataPosition, variable.m_AppValues, variable.TotalSize(), m_Threads); + m_HeapBuffer.m_DataAbsolutePosition += variable.PayLoadSize(); if (m_Profiler.IsActive) @@ -71,6 +72,262 @@ void BP1Writer::WriteVariablePayload(const Variable<T> &variable) noexcept } // PRIVATE +template <class T> +size_t BP1Writer::WriteAttributeHeaderInData(const Attribute<T> &attribute, + Stats<T> &stats) noexcept +{ + auto &buffer = m_HeapBuffer.m_Data; + auto &position = m_HeapBuffer.m_DataPosition; + + // will go back to write length + const size_t attributeLengthPosition = position; + position += 4; // skip length + + CopyToBuffer(buffer, position, &stats.MemberID); + WriteNameRecord(attribute.m_Name, buffer, position); + position += 2; // skip path + + // TODO: attribute from Variable?? + constexpr int8_t no = 'n'; + CopyToBuffer(buffer, position, &no); // not associated with a Variable + + return attributeLengthPosition; +} + +template <class T> +void BP1Writer::WriteAttributeLengthInData( + const Attribute<T> &attribute, Stats<T> &stats, + const size_t attributeLengthPosition) noexcept +{ + auto &buffer = m_HeapBuffer.m_Data; + auto &position = m_HeapBuffer.m_DataPosition; + + // back to attribute length + const uint32_t attributeLength = + static_cast<const uint32_t>(position - attributeLengthPosition); + size_t backPosition = attributeLengthPosition; + CopyToBuffer(buffer, backPosition, &attributeLengthPosition); + + m_HeapBuffer.m_DataAbsolutePosition += position - attributeLengthPosition; +} + +template <> +inline void +BP1Writer::WriteAttributeInData(const Attribute<std::string> &attribute, + Stats<std::string> &stats) noexcept +{ + const size_t attributeLengthPosition = + WriteAttributeHeaderInData(attribute, stats); + + auto &buffer = m_HeapBuffer.m_Data; + auto &position = m_HeapBuffer.m_DataPosition; + + uint8_t dataType = GetDataType<std::string>(); + if (!attribute.m_IsSingleValue) + { + dataType = type_string_array; + } + CopyToBuffer(buffer, position, &dataType); + + // here record payload offset + stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition + position - + attributeLengthPosition; + + if (dataType == type_string) + { + const uint32_t dataSize = + static_cast<const uint32_t>(attribute.m_DataSingleValue.size()); + CopyToBuffer(buffer, position, &dataSize); + CopyToBuffer(buffer, position, attribute.m_DataSingleValue.data(), + attribute.m_DataSingleValue.size()); + } + else if (dataType == type_string_array) + { + const uint32_t elements = + static_cast<const uint32_t>(attribute.m_Elements); + CopyToBuffer(buffer, position, &elements); + + for (size_t s = 0; s < attribute.m_Elements; ++s) + { + // include zero terminated + const std::string element(attribute.m_DataArray[s] + '\0'); + + const uint32_t elementSize = + static_cast<const uint32_t>(element.size()); + + CopyToBuffer(buffer, position, &elementSize); + CopyToBuffer(buffer, position, element.data(), element.size()); + } + } + + WriteAttributeLengthInData(attribute, stats, attributeLengthPosition); +} + +template <class T> +void BP1Writer::WriteAttributeInData(const Attribute<T> &attribute, + Stats<T> &stats) noexcept +{ + const size_t attributeLengthPosition = + WriteAttributeHeaderInData(attribute, stats); + + auto &buffer = m_HeapBuffer.m_Data; + auto &position = m_HeapBuffer.m_DataPosition; + + uint8_t dataType = GetDataType<T>(); + CopyToBuffer(buffer, position, &dataType); + + // here record payload offset + stats.PayloadOffset = m_HeapBuffer.m_DataAbsolutePosition + position - + attributeLengthPosition; + + const uint32_t dataSize = attribute.m_Elements * sizeof(T); + CopyToBuffer(buffer, position, &dataSize); + + if (attribute.m_IsSingleValue) // single value + { + CopyToBuffer(buffer, position, &attribute.m_DataSingleValue); + } + else // array + { + CopyToBuffer(buffer, position, attribute.m_DataArray.data(), + attribute.m_Elements); + } + + WriteAttributeLengthInData(attribute, stats, attributeLengthPosition); +} + +template <> +inline void BP1Writer::WriteAttributeCharacteristicValueInIndex( + uint8_t &characteristicsCounter, const Attribute<std::string> &attribute, + std::vector<char> &buffer) noexcept +{ + uint8_t characteristicID = characteristic_value; + + InsertToBuffer(buffer, &characteristicID); + + if (attribute.m_IsSingleValue) // Single string + { + const uint16_t dataSize = + static_cast<const uint16_t>(attribute.m_DataSingleValue.size()); + InsertToBuffer(buffer, &dataSize); + InsertToBuffer(buffer, attribute.m_DataSingleValue.data(), + attribute.m_DataSingleValue.size()); + } + else // string array + { + for (size_t s = 0; s < attribute.m_Elements; ++s) + { + // without zero terminated character + const std::string element(attribute.m_DataArray[s]); + + const uint16_t elementSize = + static_cast<const uint16_t>(element.size()); + + InsertToBuffer(buffer, &elementSize); + InsertToBuffer(buffer, element.data(), element.size()); + } + } + ++characteristicsCounter; +} + +template <class T> +void BP1Writer::WriteAttributeCharacteristicValueInIndex( + uint8_t &characteristicsCounter, const Attribute<T> &attribute, + std::vector<char> &buffer) noexcept +{ + uint8_t characteristicID = characteristic_value; + + InsertToBuffer(buffer, &characteristicID); + + if (attribute.m_IsSingleValue) // single value + { + InsertToBuffer(buffer, &attribute.m_DataSingleValue); + } + else // array + { + InsertToBuffer(buffer, attribute.m_DataArray.data(), + attribute.m_Elements); + } + ++characteristicsCounter; +} + +template <class T> +void BP1Writer::WriteAttributeInIndex(const Attribute<T> &attribute, + const Stats<T> &stats) noexcept +{ + BP1Index index(stats.MemberID); + auto &buffer = index.Buffer; + + buffer.insert(buffer.end(), 4, '\0'); // skip attribute length (4) + InsertToBuffer(buffer, &stats.MemberID); + buffer.insert(buffer.end(), 2, '\0'); // skip group name + WriteNameRecord(attribute.m_Name, buffer); + buffer.insert(buffer.end(), 2, '\0'); // skip path + + uint8_t dataType = GetDataType<T>(); // dataType + + if (dataType == type_string && !attribute.m_IsSingleValue) + { + dataType = type_string_array; + } + + InsertToBuffer(buffer, &dataType); + + // Characteristics Sets Count in Metadata + index.Count = 1; + InsertToBuffer(buffer, &index.Count); + + // START OF CHARACTERISTICS + const size_t characteristicsCountPosition = buffer.size(); + // skip characteristics count(1) + length (4) + buffer.insert(buffer.end(), 5, '\0'); + uint8_t characteristicsCounter = 0; + + // DIMENSIONS + uint8_t characteristicID = characteristic_dimensions; + InsertToBuffer(buffer, &characteristicID); + constexpr uint8_t dimensions = 1; + InsertToBuffer(buffer, &dimensions); // count + constexpr uint16_t dimensionsLength = 24; + InsertToBuffer(buffer, &dimensionsLength); // length + WriteDimensionsRecord({attribute.m_Elements}, {}, {}, buffer); + ++characteristicsCounter; + + // VALUE + WriteAttributeCharacteristicValueInIndex(characteristicsCounter, attribute, + buffer); + + // TIME Index + WriteCharacteristicRecord(characteristic_time_index, characteristicsCounter, + stats.TimeIndex, buffer); + + const uint32_t rankU32 = + static_cast<const uint32_t>(m_BP1Aggregator.m_RankMPI); + WriteCharacteristicRecord(characteristic_file_index, characteristicsCounter, + rankU32, buffer); + + WriteCharacteristicRecord(characteristic_offset, characteristicsCounter, + stats.Offset, buffer); + + WriteCharacteristicRecord(characteristic_payload_offset, + characteristicsCounter, stats.PayloadOffset, + buffer); + // END OF CHARACTERISTICS + + // Back to characteristics count and length + size_t backPosition = characteristicsCountPosition; + CopyToBuffer(buffer, backPosition, &characteristicsCounter); // count (1) + + // remove its own length (4) + characteristic counter (1) + const uint32_t characteristicsLength = static_cast<const uint32_t>( + buffer.size() - characteristicsCountPosition - 4 - 1); + + CopyToBuffer(buffer, backPosition, &characteristicsLength); // length + + // Finish characteristic count length + m_MetadataSet.AttributesIndices.emplace(attribute.m_Name, index); +} + template <class T> BP1Writer::Stats<typename TypeInfo<T>::ValueType> BP1Writer::GetStats(const Variable<T> &variable) const noexcept @@ -103,7 +360,7 @@ void BP1Writer::WriteVariableMetadataInData( WriteNameRecord(variable.m_Name, buffer, position); position += 2; // skip path - const uint8_t dataType = GetDataType<T>(); // dataType + const uint8_t dataType = GetDataType<T>(); CopyToBuffer(buffer, position, &dataType); constexpr char no = 'n'; // isDimension @@ -126,8 +383,8 @@ void BP1Writer::WriteVariableMetadataInData( // Back to varLength including payload size // not need to remove its own size (8) from length from bpdump - const uint64_t varLength = - position - varLengthPosition + variable.PayLoadSize(); + const uint64_t varLength = static_cast<const uint64_t>( + position - varLengthPosition + variable.PayLoadSize()); size_t backPosition = varLengthPosition; CopyToBuffer(buffer, backPosition, &varLength); @@ -143,8 +400,7 @@ void BP1Writer::WriteVariableMetadataInIndex( { auto &buffer = index.Buffer; - if (isNew) // write variable header (might be shared with - // attributes index) + if (isNew) // write variable header { buffer.insert(buffer.end(), 4, '\0'); // skip var length (4) InsertToBuffer(buffer, &stats.MemberID); @@ -345,6 +601,6 @@ void BP1Writer::WriteVariableCharacteristics( } } // end namespace format -} // end namespace adios +} // end namespace adios2 -#endif // ADIOS2_UTILITIES_FORMAT_BP1_BP1WRITER_TCC_ +#endif // ADIOS2_TOOLKIT_FORMAT_BP1_BP1WRITER_TCC_ diff --git a/source/adios2/toolkit/interop/adios1/ADIOS1Common.h b/source/adios2/toolkit/interop/adios1/ADIOS1Common.h index 75f5c99fb568e7e5d3091c22e1709a2ba1c553cc..0473c896b10954f2d7d0bb4b2878184cba25d9a0 100644 --- a/source/adios2/toolkit/interop/adios1/ADIOS1Common.h +++ b/source/adios2/toolkit/interop/adios1/ADIOS1Common.h @@ -97,6 +97,6 @@ ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) #undef declare_template_instantiation } // end namespace interop -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_TOOLKIT_INTEROP_ADIOS1_ADIOS1COMMON_H_ */ diff --git a/source/adios2/toolkit/interop/adios1/ADIOS1Common.tcc b/source/adios2/toolkit/interop/adios1/ADIOS1Common.tcc index b0fde3f8edfdf06348f4b4e937812c8615c19770..2233621a8907f6b44147e83177668c2df726a5ce 100644 --- a/source/adios2/toolkit/interop/adios1/ADIOS1Common.tcc +++ b/source/adios2/toolkit/interop/adios1/ADIOS1Common.tcc @@ -48,6 +48,11 @@ enum ADIOS_DATATYPES ADIOS1Common::GetADIOS1Type<char>() const { return adios_byte; } +template <> +enum ADIOS_DATATYPES ADIOS1Common::GetADIOS1Type<signed char>() const { + return adios_byte; +} + template <> enum ADIOS_DATATYPES ADIOS1Common::GetADIOS1Type<unsigned char>() const { return adios_unsigned_byte; @@ -126,6 +131,6 @@ enum ADIOS_DATATYPES ADIOS1Common::GetADIOS1Type<cldouble>() const { } } // end namespace interop -} // end namespace adios +} // end namespace adios2 #endif /* ADIOS2_TOOLKIT_INTEROP_ADIOS1_ADIOS1COMMON_TCC_ */ diff --git a/source/adios2/toolkit/interop/hdf5/HDF5Common.tcc b/source/adios2/toolkit/interop/hdf5/HDF5Common.tcc index 54ca1bc764ed33d52f2662842115ed899ceb04e2..e5555692b833e76b334ce3fcb9e42b5d9c849570 100644 --- a/source/adios2/toolkit/interop/hdf5/HDF5Common.tcc +++ b/source/adios2/toolkit/interop/hdf5/HDF5Common.tcc @@ -103,6 +103,11 @@ hid_t HDF5Common::GetHDF5Type<char>() return H5T_NATIVE_CHAR; } template <> +hid_t HDF5Common::GetHDF5Type<signed char>() +{ + return H5T_NATIVE_SCHAR; +} +template <> hid_t HDF5Common::GetHDF5Type<unsigned char>() { return H5T_NATIVE_UCHAR; diff --git a/testing/adios2/bindings/C/CMakeLists.txt b/testing/adios2/bindings/C/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9897e1b0316505c8972a5a72fea5f24584c18a76 --- /dev/null +++ b/testing/adios2/bindings/C/CMakeLists.txt @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +if(ADIOS2_HAVE_MPI) + add_executable(TestBPWriteTypes_c TestBPWriteTypes.c) + target_include_directories(TestBPWriteTypes_c PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteTypes_c ${MPI_C_LIBRARIES}) +else() + add_executable(TestBPWriteTypes_c TestBPWriteTypes_nompi.c) +endif() + +target_link_libraries(TestBPWriteTypes_c adios2) + +add_test(NAME BPWrite_c COMMAND TestBPWriteTypes_c) diff --git a/testing/adios2/bindings/C/SmallTestData_c.h b/testing/adios2/bindings/C/SmallTestData_c.h new file mode 100644 index 0000000000000000000000000000000000000000..f3aea0ce684d5038e5d536720a37e6b3320ceeae --- /dev/null +++ b/testing/adios2/bindings/C/SmallTestData_c.h @@ -0,0 +1,35 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + */ + +#ifndef TESTING_ADIOS2_BINDINGS_C_SMALLTESTDATA_C_H_ +#define TESTING_ADIOS2_BINDINGS_C_SMALLTESTDATA_C_H_ + +size_t data_Nx = 10; +char data_I8[10] = {0, 1, -2, 3, -4, 5, -6, 7, -8, 9}; +short data_I16[10] = {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}; +int data_I32[10] = {131072, 131073, -131070, 131075, -131068, + 131077, -131066, 131079, -131064, 131081}; +long int data_I64[10] = {8589934592, 8589934593, -8589934590, 8589934595, + -8589934588, 8589934597, -8589934586, 8589934599, + -8589934584, 8589934601}; + +unsigned char data_U8[10] = {128, 129, 130, 131, 132, 133, 134, 135, 136, 137}; + +unsigned short data_U16[10] = {32768, 32769, 32770, 32771, 32772, + 32773, 32774, 32775, 32776, 32777}; + +unsigned int data_U32[10] = {2147483648, 2147483649, 2147483650, 2147483651, + 2147483652, 2147483653, 2147483654, 2147483655, + 2147483656, 2147483657}; + +unsigned long int data_U64[10] = {9223372036854775808UL, 9223372036854775809UL, + 9223372036854775810UL, 9223372036854775811UL, + 9223372036854775812UL, 9223372036854775813UL, + 9223372036854775814UL, 9223372036854775815UL, + 9223372036854775816UL, 9223372036854775817UL}; +float data_R32[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +double data_R64[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + +#endif /* TESTING_ADIOS2_BINDINGS_C_SMALLTESTDATA_C_H_ */ diff --git a/testing/adios2/bindings/C/TestBPWriteTypes.c b/testing/adios2/bindings/C/TestBPWriteTypes.c new file mode 100644 index 0000000000000000000000000000000000000000..55917aad8d47ab807ca24810fffeb230a2024466 --- /dev/null +++ b/testing/adios2/bindings/C/TestBPWriteTypes.c @@ -0,0 +1,102 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * TestBPWriteTypes.c + * + * Created on: Aug 9, 2017 + * Author: wgodoy + */ + +#include <mpi.h> + +#include <adios2_c.h> + +#include "SmallTestData_c.h" + +int main(int argc, char *argv[]) +{ + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + adios2_ADIOS *adiosH = adios2_init(MPI_COMM_WORLD, adios2_debug_mode_on); + + // IO + adios2_IO *ioH = adios2_declare_io(adiosH, "CArrayTypes"); + // Set engine parameters + adios2_set_engine(ioH, "BPFileWriter"); + adios2_set_param(ioH, "ProfileUnits", "Microseconds"); + adios2_set_param(ioH, "Threads", "1"); + + // Set transport and parameters + const unsigned int transportID = adios2_add_transport(ioH, "File"); + adios2_set_transport_param(ioH, transportID, "library", "fstream"); + + // count dims are allocated in stack + size_t count[1]; + count[0] = data_Nx; + + // Define variables in ioH + { + + adios2_define_variable(ioH, "varI8", adios2_type_char, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI16", adios2_type_short, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI32", adios2_type_int, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI64", adios2_type_long_int, 1, NULL, + NULL, count, adios2_constant_dims_true); + + adios2_define_variable(ioH, "varU8", adios2_type_unsigned_char, 1, NULL, + NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU16", adios2_type_unsigned_short, 1, + NULL, NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU32", adios2_type_unsigned_int, 1, NULL, + NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU64", adios2_type_unsigned_long_int, 1, + NULL, NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varR32", adios2_type_float, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varR64", adios2_type_double, 1, NULL, NULL, + count, adios2_constant_dims_true); + } + // get variables + adios2_Variable *varI8 = adios2_get_variable(ioH, "varI8"); + adios2_Variable *varI16 = adios2_get_variable(ioH, "varI16"); + adios2_Variable *varI32 = adios2_get_variable(ioH, "varI32"); + adios2_Variable *varI64 = adios2_get_variable(ioH, "varI64"); + adios2_Variable *varU8 = adios2_get_variable(ioH, "varU8"); + adios2_Variable *varU16 = adios2_get_variable(ioH, "varU16"); + adios2_Variable *varU32 = adios2_get_variable(ioH, "varU32"); + adios2_Variable *varU64 = adios2_get_variable(ioH, "varU64"); + adios2_Variable *varR32 = adios2_get_variable(ioH, "varR32"); + adios2_Variable *varR64 = adios2_get_variable(ioH, "varR64"); + + // Open Engine handler, Write and Close + adios2_Engine *engineH = + adios2_open(ioH, "ctypes.bp", adios2_open_mode_write); + + adios2_write(engineH, varI8, data_I8); + adios2_write(engineH, varI16, data_I16); + adios2_write(engineH, varI32, data_I32); + adios2_write(engineH, varI64, data_I64); + + adios2_write(engineH, varU8, data_U8); + adios2_write(engineH, varU16, data_U16); + adios2_write(engineH, varU32, data_U32); + adios2_write(engineH, varU64, data_U64); + + adios2_write(engineH, varR32, data_R32); + adios2_write(engineH, varR64, data_R64); + + adios2_close(engineH); + + // deallocate adiosH + adios2_finalize(adiosH); + + MPI_Finalize(); + return 0; +} diff --git a/testing/adios2/bindings/C/TestBPWriteTypes_nompi.c b/testing/adios2/bindings/C/TestBPWriteTypes_nompi.c new file mode 100644 index 0000000000000000000000000000000000000000..247e5b4bdbd135bc56b1b99dd8d82db11b67b9a9 --- /dev/null +++ b/testing/adios2/bindings/C/TestBPWriteTypes_nompi.c @@ -0,0 +1,92 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * TestBPWriteTypes.c + * + * Created on: Aug 9, 2017 + * Author: wgodoy + */ + +#include <adios2_c.h> + +#include "SmallTestData_c.h" + +int main(int argc, char *argv[]) +{ + adios2_ADIOS *adiosH = adios2_init_nompi(adios2_debug_mode_on); + + // IO + adios2_IO *ioH = adios2_declare_io(adiosH, "CArrayTypes"); + // Set engine parameters + adios2_set_engine(ioH, "BPFileWriter"); + adios2_set_param(ioH, "ProfileUnits", "Microseconds"); + adios2_set_param(ioH, "Threads", "1"); + + // Set transport and parameters + const unsigned int transportID = adios2_add_transport(ioH, "File"); + adios2_set_transport_param(ioH, transportID, "library", "fstream"); + + // count dims are allocated in stack + size_t count[1]; + count[0] = data_Nx; + + // Define variables in ioH + { + adios2_define_variable(ioH, "varI8", adios2_type_char, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI16", adios2_type_short, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI32", adios2_type_int, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varI64", adios2_type_long_int, 1, NULL, + NULL, count, adios2_constant_dims_true); + + adios2_define_variable(ioH, "varU8", adios2_type_unsigned_char, 1, NULL, + NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU16", adios2_type_unsigned_short, 1, + NULL, NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU32", adios2_type_unsigned_int, 1, NULL, + NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varU64", adios2_type_unsigned_long_int, 1, + NULL, NULL, count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varR32", adios2_type_float, 1, NULL, NULL, + count, adios2_constant_dims_true); + adios2_define_variable(ioH, "varR64", adios2_type_double, 1, NULL, NULL, + count, adios2_constant_dims_true); + } + // get variables + adios2_Variable *varI8 = adios2_get_variable(ioH, "varI8"); + adios2_Variable *varI16 = adios2_get_variable(ioH, "varI16"); + adios2_Variable *varI32 = adios2_get_variable(ioH, "varI32"); + adios2_Variable *varI64 = adios2_get_variable(ioH, "varI64"); + adios2_Variable *varU8 = adios2_get_variable(ioH, "varU8"); + adios2_Variable *varU16 = adios2_get_variable(ioH, "varU16"); + adios2_Variable *varU32 = adios2_get_variable(ioH, "varU32"); + adios2_Variable *varU64 = adios2_get_variable(ioH, "varU64"); + adios2_Variable *varR32 = adios2_get_variable(ioH, "varR32"); + adios2_Variable *varR64 = adios2_get_variable(ioH, "varR64"); + + // Open Engine handler, Write and Close + adios2_Engine *engineH = + adios2_open(ioH, "ctypes.bp", adios2_open_mode_write); + + adios2_write(engineH, varI8, data_I8); + adios2_write(engineH, varI16, data_I16); + adios2_write(engineH, varI32, data_I32); + adios2_write(engineH, varI64, data_I64); + + adios2_write(engineH, varU8, data_U8); + adios2_write(engineH, varU16, data_U16); + adios2_write(engineH, varU32, data_U32); + adios2_write(engineH, varU64, data_U64); + + adios2_write(engineH, varR32, data_R32); + adios2_write(engineH, varR64, data_R64); + + adios2_close(engineH); + + // deallocate adiosH + adios2_finalize(adiosH); + return 0; +} diff --git a/testing/adios2/bindings/CMakeLists.txt b/testing/adios2/bindings/CMakeLists.txt index 8aa1ecd22b23c1ddd515657bde6f8ac8c6ec7af1..e82e710498992578abd98a4c98f42d17dafea7df 100644 --- a/testing/adios2/bindings/CMakeLists.txt +++ b/testing/adios2/bindings/CMakeLists.txt @@ -6,3 +6,9 @@ if(ADIOS2_HAVE_Python) add_subdirectory(python) endif() + +if(ADIOS2_HAVE_Fortran) + add_subdirectory(fortran) +endif() + +add_subdirectory(C) \ No newline at end of file diff --git a/testing/adios2/bindings/fortran/CMakeLists.txt b/testing/adios2/bindings/fortran/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..913dab1a72d93ee04e465d10092e40599f6e130c --- /dev/null +++ b/testing/adios2/bindings/fortran/CMakeLists.txt @@ -0,0 +1,21 @@ +#------------------------------------------------------------------------------# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +#------------------------------------------------------------------------------# + +add_executable(TestBPWriteTypes_f SmallTestData_mod.f90) + +if(ADIOS2_HAVE_MPI) + target_sources(TestBPWriteTypes_f PRIVATE TestBPWriteTypes.f90) + target_include_directories(TestBPWriteTypes_f + PRIVATE ${MPI_Fortran_INCLUDE_PATH} + ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteTypes_f PRIVATE ${MPI_Fortran_LIBRARIES} + ${MPI_C_LIBRARIES}) +else() + target_sources(TestBPWriteTypes_f PRIVATE TestBPWriteTypes_nompi.f90) +endif() + +target_link_libraries(TestBPWriteTypes_f PRIVATE adios2_f) + +add_test(NAME BPWrite_f COMMAND TestBPWriteTypes_f) diff --git a/testing/adios2/bindings/fortran/SmallTestData_mod.f90 b/testing/adios2/bindings/fortran/SmallTestData_mod.f90 new file mode 100644 index 0000000000000000000000000000000000000000..e562714f57daa70c98584a47287312efe0efe528 --- /dev/null +++ b/testing/adios2/bindings/fortran/SmallTestData_mod.f90 @@ -0,0 +1,35 @@ +! Distributed under the OSI-approved Apache License, Version 2.0. See +! accompanying file Copyright.txt for details. +! +! SmallTestData.f90 : Fortran 90 arrays data for tests +! +! Created on: Aug 9, 2017 +! Author: William F Godoy godoywf@ornl.gov +! + + +module small_test_data + implicit none + + integer(kind=1), parameter, dimension(10) :: data_I8 = & + & (/ 0, 1, -2, 3, -4, 5, -6, 7, -8, 9 /) + + integer(kind=2), parameter, dimension(10) :: data_I16 = & + & (/ 512, 513, -510, 515, -508, 517, -506, 519, -504, 521 /) + + integer(kind=4), parameter, dimension(10) :: data_I32 = & + & (/ 131072, 131073, -131070, 131075, -131068, 131077, -131066, 131079, & + & -131064, 131081 /) + +! Having trouble with width +! integer(kind=8), parameter, dimension(10) :: data_I64 = & +! & (/ 8589934592, 8589934593, -8589934590, 8589934595, -8589934588, & +! & 8589934597, -8589934586, 8589934599, -8589934584, 8589934601 /) + + real, parameter, dimension(10) :: data_R32 = & + & (/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 /) + + real(kind=8), parameter, dimension(10) :: data_R64 = & + & (/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 /) + +end module diff --git a/testing/adios2/bindings/fortran/TestBPWriteTypes.f90 b/testing/adios2/bindings/fortran/TestBPWriteTypes.f90 new file mode 100644 index 0000000000000000000000000000000000000000..5340c1a59d28a5e86e3f7ffc8068f78eabc0c4ab --- /dev/null +++ b/testing/adios2/bindings/fortran/TestBPWriteTypes.f90 @@ -0,0 +1,50 @@ +program TestBPWriteTypes + use small_test_data + use mpi + use adios2 + implicit none + + integer, dimension(1) :: shape_dims, start_dims, count_dims + integer :: inx, irank, isize, ierr, i + + integer(kind=8) :: adios, io, engine + integer(kind=8), dimension(6) :: variables + + ! Launch MPI + call MPI_Init(ierr) + call MPI_Comm_rank(MPI_COMM_WORLD, irank, ierr) + call MPI_Comm_size(MPI_COMM_WORLD, isize, ierr) + + ! Application variables + inx = 10 + + ! Variable dimensions + shape_dims(1) = isize * inx + start_dims(1) = irank * inx + count_dims(1) = inx + + ! Create adios handler passing the communicator, debug mode and error flag + call adios2_init(adios, MPI_COMM_WORLD, adios2_debug_mode_on, ierr) + + ! Declare an IO process configuration inside adios + call adios2_declare_io(io, adios, "bpIO", ierr) + + ! Defines a variable to be written in bp format + call adios2_define_variable(variables(1), io, "var_I8", adios2_type_integer1, 1, & + & shape_dims, start_dims, count_dims, adios2_constant_dims_true, ierr) + + ! Open myVector_f.bp in write mode, this launches an engine + call adios2_open(engine, io, "ftypes.bp", adios2_open_mode_write, ierr) + + ! Write myArray contents to bp buffer, based on var1 metadata + call adios2_write(engine, variables(1), data_I8, ierr) + + ! Closes engine1 and deallocates it, becomes unreachable + call adios2_close(engine, ierr) + + ! Deallocates adios and calls its destructor + call adios2_finalize(adios, ierr) + + call MPI_Finalize(ierr) + +end program TestBPWriteTypes diff --git a/testing/adios2/bindings/fortran/TestBPWriteTypes_nompi.f90 b/testing/adios2/bindings/fortran/TestBPWriteTypes_nompi.f90 new file mode 100644 index 0000000000000000000000000000000000000000..3736a7ce9bd589107dc5b3aadbeb2c91c633e3c9 --- /dev/null +++ b/testing/adios2/bindings/fortran/TestBPWriteTypes_nompi.f90 @@ -0,0 +1,43 @@ +program TestBPWriteTypes + use small_test_data + use adios2 + implicit none + + integer, dimension(1) :: shape_dims, start_dims, count_dims + integer :: inx, ierr, i + + integer(kind=8) :: adios, io, engine + integer(kind=8), dimension(6) :: variables + + ! Application variables + inx = 10 + + ! Variable dimensions + shape_dims(1) = inx + start_dims(1) = 0 + count_dims(1) = inx + + ! Create adios handler passing the communicator, debug mode and error flag + call adios2_init(adios, adios2_debug_mode_on, ierr) + + ! Declare an IO process configuration inside adios + call adios2_declare_io(io, adios, "bpIO", ierr) + + ! Defines a variable to be written in bp format + call adios2_define_variable(variables(1), io, "var_I8", & + & adios2_type_integer1, 1, shape_dims, start_dims, count_dims, & + & adios2_constant_dims_true, ierr) + + ! Open myVector_f.bp in write mode, this launches an engine + call adios2_open(engine, io, "ftypes.bp", adios2_open_mode_write, ierr) + + ! Write myArray contents to bp buffer, based on var1 metadata + call adios2_write(engine, variables(1), data_I8, ierr) + + ! Closes engine1 and deallocates it, becomes unreachable + call adios2_close(engine, ierr) + + ! Deallocates adios and calls its destructor + call adios2_finalize(adios, ierr) + +end program TestBPWriteTypes diff --git a/testing/adios2/engine/SmallTestData.h b/testing/adios2/engine/SmallTestData.h index 05de0729e8e7fdf1ba957942892a24a945722082..829758a3ff87edb4fedd5879d3b208599caa7ed3 100644 --- a/testing/adios2/engine/SmallTestData.h +++ b/testing/adios2/engine/SmallTestData.h @@ -5,26 +5,39 @@ #ifndef TESTING_ADIOS2_ENGINE_SMALLTESTDATA_H_ #define TESTING_ADIOS2_ENGINE_SMALLTESTDATA_H_ +#include <cstdint> + +#include <array> +#include <limits> +#include <string> + +#ifdef WIN32 +#define NOMINMAX +#endif + // Test data for each type. Make sure our values exceed the range of the // previous size to make sure we all bytes for each element struct SmallTestData { - std::array<char, 10> I8 = {{0, 1, -2, 3, -4, 5, -6, 7, -8, 9}}; - std::array<short, 10> I16 = { + std::string S1 = "Testing ADIOS2 String Attributes"; + std::array<std::string, 3> S3 = {{"one", "two", "three"}}; + + std::array<int8_t, 10> I8 = {{0, 1, -2, 3, -4, 5, -6, 7, -8, 9}}; + std::array<int16_t, 10> I16 = { {512, 513, -510, 515, -508, 517, -506, 519, -504, 521}}; - std::array<int, 10> I32 = {{131072, 131073, -131070, 131075, -131068, - 131077, -131066, 131079, -131064, 131081}}; - std::array<long int, 10> I64 = { + std::array<int32_t, 10> I32 = {{131072, 131073, -131070, 131075, -131068, + 131077, -131066, 131079, -131064, 131081}}; + std::array<int64_t, 10> I64 = { {8589934592, 8589934593, -8589934590, 8589934595, -8589934588, 8589934597, -8589934586, 8589934599, -8589934584, 8589934601}}; - std::array<unsigned char, 10> U8 = { + std::array<uint8_t, 10> U8 = { {128, 129, 130, 131, 132, 133, 134, 135, 136, 137}}; - std::array<unsigned short, 10> U16 = { + std::array<uint16_t, 10> U16 = { {32768, 32769, 32770, 32771, 32772, 32773, 32774, 32775, 32776, 32777}}; - std::array<unsigned int, 10> U32 = { + std::array<uint32_t, 10> U32 = { {2147483648, 2147483649, 2147483650, 2147483651, 2147483652, 2147483653, 2147483654, 2147483655, 2147483656, 2147483657}}; - std::array<unsigned long int, 10> U64 = { + std::array<uint64_t, 10> U64 = { {9223372036854775808UL, 9223372036854775809UL, 9223372036854775810UL, 9223372036854775811UL, 9223372036854775812UL, 9223372036854775813UL, 9223372036854775814UL, 9223372036854775815UL, 9223372036854775816UL, @@ -33,4 +46,22 @@ struct SmallTestData std::array<double, 10> R64 = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; }; +SmallTestData generateNewSmallTestData(SmallTestData in, int step, int rank, + int size) +{ + int j = rank + 1 + step * size; + std::for_each(in.I8.begin(), in.I8.end(), [&](int8_t &v) { v += j; }); + std::for_each(in.I16.begin(), in.I16.end(), [&](int16_t &v) { v += j; }); + std::for_each(in.I32.begin(), in.I32.end(), [&](int32_t &v) { v += j; }); + std::for_each(in.I64.begin(), in.I64.end(), [&](int64_t &v) { v += j; }); + std::for_each(in.U8.begin(), in.U8.end(), [&](uint8_t &v) { v += j; }); + std::for_each(in.U16.begin(), in.U16.end(), [&](uint16_t &v) { v += j; }); + std::for_each(in.U32.begin(), in.U32.end(), [&](uint32_t &v) { v += j; }); + std::for_each(in.U64.begin(), in.U64.end(), [&](uint64_t &v) { v += j; }); + std::for_each(in.R32.begin(), in.R32.end(), [&](float &v) { v += j; }); + std::for_each(in.R64.begin(), in.R64.end(), [&](double &v) { v += j; }); + + return in; +} + #endif // TESTING_ADIOS2_ENGINE_SMALLTESTDATA_H_ diff --git a/testing/adios2/engine/adios1/CMakeLists.txt b/testing/adios2/engine/adios1/CMakeLists.txt index 259a2aed065852814bf0e4d82f88abb14cedd28c..ace06e557d1705e87449bc73972562005a035a1c 100644 --- a/testing/adios2/engine/adios1/CMakeLists.txt +++ b/testing/adios2/engine/adios1/CMakeLists.txt @@ -3,12 +3,15 @@ # accompanying file Copyright.txt for details. #------------------------------------------------------------------------------# -# MPI versions of the test are not properly implemented at the moment -if(NOT ADIOS2_HAVE_MPI) - find_package(ADIOS1 COMPONENTS sequential REQUIRED) - - add_executable(TestADIOS1WriteRead TestADIOS1WriteRead.cpp) - target_link_libraries(TestADIOS1WriteRead adios2 gtest adios1::adios) - - gtest_add_tests(TARGET TestADIOS1WriteRead) +add_executable(TestADIOS1WriteRead TestADIOS1WriteRead.cpp) +target_link_libraries(TestADIOS1WriteRead adios2 gtest adios1::adios) +if(ADIOS2_HAVE_MPI) + target_include_directories(TestADIOS1WriteRead PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestADIOS1WriteRead ${MPI_C_LIBRARIES}) + set(extra_test_args + EXEC_WRAPPER + ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ) endif() + +gtest_add_tests(TARGET TestADIOS1WriteRead ${extra_test_args}) diff --git a/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp b/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp index 19f338e4bd7138527f4a565d78721b9071a02408..99fc439bccb5667a190bba1d7553518f34418b71 100644 --- a/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp +++ b/testing/adios2/engine/adios1/TestADIOS1WriteRead.cpp @@ -16,6 +16,10 @@ #include "../SmallTestData.h" +#ifdef ADIOS2_HAVE_MPI +#include "mpi.h" +#endif + class ADIOS1WriteReadTest : public ::testing::Test { public: @@ -31,71 +35,116 @@ public: // ADIOS2 write, native ADIOS1 read TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read1D8) { + // Each process would write a 1x8 array and all processes would + // form a mpiSize * Nx 1D array std::string fname = "ADIOS2ADIOS1WriteADIOS1Read1D8.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { - adios_init_noxml(MPI_COMM_WORLD); - +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the ADIOS 1 Engine io.SetEngine("ADIOS1Writer"); - io.AddTransport("File"); + +#ifdef ADIOS2_HAVE_MPI + io.AddTransport("file", {{"library", "MPI"}}); +#else + io.AddTransport("file"); +#endif auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -107,13 +156,6 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read1D8) adios_finalize(0); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, "verbose=3"); @@ -127,62 +169,85 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read1D8) ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 1); - ASSERT_EQ(var_i8->dims[0], 8); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 1); - ASSERT_EQ(var_i16->dims[0], 8); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 1); - ASSERT_EQ(var_i32->dims[0], 8); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 1); - ASSERT_EQ(var_i64->dims[0], 8); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 1); - ASSERT_EQ(var_u8->dims[0], 8); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 1); - ASSERT_EQ(var_u16->dims[0], 8); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 1); - ASSERT_EQ(var_u32->dims[0], 8); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 1); - ASSERT_EQ(var_u64->dims[0], 8); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 1); - ASSERT_EQ(var_r32->dims[0], 8); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 1); - ASSERT_EQ(var_r64->dims[0], 8); - - 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; - - uint64_t start[1] = {0}; - uint64_t count[1] = {8}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], mpiSize * Nx); + + std::array<int8_t, Nx> I8; + std::array<int16_t, Nx> I16; + std::array<int32_t, Nx> I32; + std::array<int64_t, Nx> I64; + std::array<uint8_t, Nx> U8; + std::array<uint16_t, Nx> U16; + std::array<uint32_t, Nx> U32; + std::array<uint64_t, Nx> U64; + std::array<float, Nx> R32; + std::array<double, Nx> R64; + + uint64_t start[1] = {mpiRank * Nx}; + uint64_t count[1] = {Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(1, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -197,22 +262,22 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read1D8) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -260,71 +325,123 @@ TEST_F(ADIOS1WriteReadTest, DISABLED_ADIOS1WriteADIOS2ADIOS1Read1D8) // ADIOS2 write, native ADIOS1 read TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D2x4) { + // Each process would write a 2x4 array and all processes would + // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here std::string fname = "ADIOS2ADIOS1WriteADIOS1Read2D2x4Test.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 4; + + // Number of rows + const std::size_t Ny = 2; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { - adios_init_noxml(MPI_COMM_WORLD); - +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (Ny * (NumOfProcesses * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 4}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{2, 4}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{2, 4}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 4}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{2, 4}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the ADIOS 1 Engine io.SetEngine("ADIOS1Writer"); + +#ifdef ADIOS2_HAVE_MPI + io.AddTransport("file", {{"library", "MPI"}}); +#else io.AddTransport("file"); +#endif auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -336,13 +453,6 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D2x4) adios_finalize(0); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, "verbose=3"); @@ -356,72 +466,98 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D2x4) ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 2); - ASSERT_EQ(var_i8->dims[1], 4); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 2); - ASSERT_EQ(var_i16->dims[1], 4); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 2); - ASSERT_EQ(var_i32->dims[1], 4); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 2); - ASSERT_EQ(var_i64->dims[1], 4); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 2); - ASSERT_EQ(var_u8->dims[1], 4); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 2); - ASSERT_EQ(var_u16->dims[1], 4); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 2); - ASSERT_EQ(var_u32->dims[1], 4); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 2); - ASSERT_EQ(var_u64->dims[1], 4); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 2); - ASSERT_EQ(var_r32->dims[1], 4); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 2); - ASSERT_EQ(var_r64->dims[1], 4); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {2, 4}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, static_cast<uint64_t>(mpiRank * Nx)}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -436,22 +572,22 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D2x4) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -496,74 +632,125 @@ TEST_F(ADIOS1WriteReadTest, DISABLED_ADIOS1WriteADIOS2ADIOS1Read2D2x4) // 2D 4x2 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read -TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D4x2) +// ADIOS2 write using ADIOS1 Writer, native ADIOS1 read +TEST_F(ADIOS1WriteReadTest, _ADIOS2ADIOS1WriteADIOS1Read2D4x2) { + // Each process would write a 4x2 array and all processes would + // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here std::string fname = "ADIOS2ADIOS1WriteADIOS1Read2D4x2Test.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 2; + // Number of cols + const std::size_t Ny = 4; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { - adios_init_noxml(MPI_COMM_WORLD); - +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (4 * (NumberOfProcess * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{4, 2}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(mpiSize * Nx)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{4, 2}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{4, 2}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{4, 2}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{4, 2}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the ADIOS 1 Engine io.SetEngine("ADIOS1Writer"); + +#ifdef ADIOS2_HAVE_MPI + io.AddTransport("file", {{"library", "MPI"}}); +#else io.AddTransport("file"); +#endif auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -575,13 +762,6 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D4x2) adios_finalize(0); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, "verbose=3"); @@ -595,72 +775,98 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D4x2) ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 4); - ASSERT_EQ(var_i8->dims[1], 2); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 4); - ASSERT_EQ(var_i16->dims[1], 2); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 4); - ASSERT_EQ(var_i32->dims[1], 2); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 4); - ASSERT_EQ(var_i64->dims[1], 2); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 4); - ASSERT_EQ(var_u8->dims[1], 2); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 4); - ASSERT_EQ(var_u16->dims[1], 2); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 4); - ASSERT_EQ(var_u32->dims[1], 2); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 4); - ASSERT_EQ(var_u64->dims[1], 2); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 4); - ASSERT_EQ(var_r32->dims[1], 2); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 4); - ASSERT_EQ(var_r64->dims[1], 2); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {4, 2}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, static_cast<uint64_t>(mpiRank * Nx)}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -675,22 +881,22 @@ TEST_F(ADIOS1WriteReadTest, ADIOS2ADIOS1WriteADIOS1Read2D4x2) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -739,6 +945,7 @@ int main(int argc, char **argv) { #ifdef ADIOS2_HAVE_MPI MPI_Init(nullptr, nullptr); + adios_init_noxml(MPI_COMM_WORLD); #endif ::testing::InitGoogleTest(&argc, argv); diff --git a/testing/adios2/engine/bp/CMakeLists.txt b/testing/adios2/engine/bp/CMakeLists.txt index 3153fd2ab8e638c45a2c10bf63ae5aaafcb21dc9..fb032ba79213616b4dd555c61952bfdbe812eb84 100644 --- a/testing/adios2/engine/bp/CMakeLists.txt +++ b/testing/adios2/engine/bp/CMakeLists.txt @@ -4,28 +4,50 @@ #------------------------------------------------------------------------------# # MPI versions of the test are not properly implemented at the moment -if(NOT ADIOS2_HAVE_MPI) - - if(ADIOS2_HAVE_ADIOS1) - find_package(ADIOS1 COMPONENTS sequential REQUIRED) - - add_executable(TestBPWriteRead TestBPWriteRead.cpp) - target_link_libraries(TestBPWriteRead adios2 gtest adios1::adios) - - add_executable(TestBPWriteReadstdio TestBPWriteReadstdio.cpp) - target_link_libraries(TestBPWriteReadstdio adios2 gtest adios1::adios) - - add_executable(TestBPWriteReadfstream TestBPWriteReadfstream.cpp) - target_link_libraries(TestBPWriteReadfstream adios2 gtest adios1::adios) - - gtest_add_tests(TARGET TestBPWriteRead) - gtest_add_tests(TARGET TestBPWriteReadstdio) - gtest_add_tests(TARGET TestBPWriteReadfstream) - - endif() - + +if (ADIOS2_HAVE_ADIOS1) + add_executable(TestBPWriteRead TestBPWriteRead.cpp) + target_link_libraries(TestBPWriteRead adios2 gtest adios1::adios) + + add_executable(TestBPWriteReadAttributes TestBPWriteReadAttributes.cpp) + target_link_libraries(TestBPWriteReadAttributes adios2 gtest adios1::adios) + + add_executable(TestBPWriteReadstdio TestBPWriteReadstdio.cpp) + target_link_libraries(TestBPWriteReadstdio adios2 gtest adios1::adios) + + add_executable(TestBPWriteReadfstream TestBPWriteReadfstream.cpp) + target_link_libraries(TestBPWriteReadfstream adios2 gtest adios1::adios) + add_executable(TestBPWriteProfilingJSON TestBPWriteProfilingJSON.cpp) - target_link_libraries(TestBPWriteProfilingJSON adios2 gtest gtest_main NLohmannJson) - - gtest_add_tests(TARGET TestBPWriteProfilingJSON) + target_link_libraries(TestBPWriteProfilingJSON + adios2 gtest NLohmannJson + ) + + if(ADIOS2_HAVE_MPI) + target_include_directories(TestBPWriteRead PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteRead ${MPI_C_LIBRARIES}) + + target_include_directories(TestBPWriteReadAttributes PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteReadAttributes ${MPI_C_LIBRARIES}) + + target_include_directories(TestBPWriteReadstdio PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteReadstdio ${MPI_C_LIBRARIES}) + + target_include_directories(TestBPWriteReadfstream PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteReadfstream ${MPI_C_LIBRARIES}) + + target_include_directories(TestBPWriteProfilingJSON PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestBPWriteProfilingJSON ${MPI_C_LIBRARIES}) + + set(extra_test_args + EXEC_WRAPPER + ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ) + endif() + + gtest_add_tests(TARGET TestBPWriteRead ${extra_test_args}) + gtest_add_tests(TARGET TestBPWriteReadAttributes ${extra_test_args}) + gtest_add_tests(TARGET TestBPWriteReadstdio ${extra_test_args}) + gtest_add_tests(TARGET TestBPWriteReadfstream ${extra_test_args}) + gtest_add_tests(TARGET TestBPWriteProfilingJSON ${extra_test_args}) endif() diff --git a/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp b/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp index 501062dbc2f558e97e7ab1d94dec696289b57cac..5fbf1723c1d83603dd9b365ef7b97afb6133d782 100644 --- a/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp +++ b/testing/adios2/engine/bp/TestBPWriteProfilingJSON.cpp @@ -38,77 +38,118 @@ public: //****************************************************************************** // ADIOS2 write, native ADIOS1 read -TEST_F(BPWriteProfilingJSONTest, ADIOS2BPWriteProfilingJSON) +TEST_F(BPWriteProfilingJSONTest, DISABLED_ADIOS2BPWriteProfilingJSON) { - std::string fname = "ADIOS2BPWriteProfilingJSON.bp"; + // Use a relative path + file name to test path in file name capability + std::string fname; + fname = "foo/ADIOS2BPWriteProfilingJSON.bp"; + + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif // Write test data and profiling.json using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); io.SetParameters({{"Threads", "2"}}); - io.AddTransport("File", {{"Library", "POSIX"}}); + io.AddTransport("file", {{"Library", "POSIX"}}); auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); } - // Close the file engine->Close(); } @@ -116,25 +157,43 @@ TEST_F(BPWriteProfilingJSONTest, ADIOS2BPWriteProfilingJSON) // open json file, parse it to a json structure, and verify a few things { std::ifstream profilingJSONFile(fname + ".dir/profiling.json"); - std::stringstream buffer; - buffer << profilingJSONFile.rdbuf(); - - const json profilingJSON = json::parse(buffer); + const json profilingJSON = json::parse(profilingJSONFile); // check rank is zero - const int rank = profilingJSON[0].value("rank", -1); - ASSERT_EQ(rank, 0); + const int rank = profilingJSON[mpiRank].value("rank", -1); + ASSERT_EQ(rank, mpiRank); // check threads - const int threads = profilingJSON[0].value("threads", 0); + const int threads = profilingJSON[mpiRank].value("threads", 0); ASSERT_EQ(threads, 2); // check bytes - const unsigned long int bytes = profilingJSON[0].value("bytes", 0UL); + const unsigned long int bytes = + profilingJSON[mpiRank].value("bytes", 0UL); ASSERT_EQ(bytes, 6536); const auto transportType = - profilingJSON[0]["transport_0"].value("type", "0"); + profilingJSON[mpiRank]["transport_0"].value("type", "0"); ASSERT_EQ(transportType, "File_POSIX"); } } + +//****************************************************************************** +// main +//****************************************************************************** + +int main(int argc, char **argv) +{ +#ifdef ADIOS2_HAVE_MPI + MPI_Init(nullptr, nullptr); +#endif + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef ADIOS2_HAVE_MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/testing/adios2/engine/bp/TestBPWriteRead.cpp b/testing/adios2/engine/bp/TestBPWriteRead.cpp index 3857839916b6267b266a1dcfbb805d71915d0439..ed5ad92aaf1cea03057ccf7bc8ddd2691e69b0df 100644 --- a/testing/adios2/engine/bp/TestBPWriteRead.cpp +++ b/testing/adios2/engine/bp/TestBPWriteRead.cpp @@ -27,72 +27,121 @@ public: // 1D 1x8 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8) { + // Each process would write a 1x8 array and all processes would + // form a mpiSize * Nx 1D array std::string fname = "ADIOS2BPWriteADIOS1Read1D8.bp"; - // Write test data using ADIOS2 + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Write test data using BP { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); - io.AddTransport("File"); + io.AddTransport("file"); + + // QUESTION: It seems that BPFilterWriter cannot overwrite existing + // files + // Ex. if you tune Nx and NSteps, the test would fail. But if you clear + // the cache in + // ${adios2Build}/testing/adios2/engine/bp/ADIOS2BPWriteADIOS1Read1D8.bp.dir, + // then it works auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -102,83 +151,105 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 1); - ASSERT_EQ(var_i8->dims[0], 8); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 1); - ASSERT_EQ(var_i16->dims[0], 8); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 1); - ASSERT_EQ(var_i32->dims[0], 8); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 1); - ASSERT_EQ(var_i64->dims[0], 8); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 1); - ASSERT_EQ(var_u8->dims[0], 8); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 1); - ASSERT_EQ(var_u16->dims[0], 8); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 1); - ASSERT_EQ(var_u32->dims[0], 8); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 1); - ASSERT_EQ(var_u64->dims[0], 8); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 1); - ASSERT_EQ(var_r32->dims[0], 8); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 1); - ASSERT_EQ(var_r64->dims[0], 8); - - 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; - - uint64_t start[1] = {0}; - uint64_t count[1] = {8}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], mpiSize * Nx); + + std::array<int8_t, Nx> I8; + std::array<int16_t, Nx> I16; + std::array<int32_t, Nx> I32; + std::array<int64_t, Nx> I64; + std::array<uint8_t, Nx> U8; + std::array<uint16_t, Nx> U16; + std::array<uint32_t, Nx> U32; + std::array<uint64_t, Nx> U64; + std::array<float, Nx> R32; + std::array<double, Nx> R64; + + uint64_t start[1] = {mpiRank * Nx}; + uint64_t count[1] = {Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(1, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -193,22 +264,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -228,6 +299,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -243,38 +316,66 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead1D8) // 2D 2x4 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4) { + // Each process would write a 2x4 array and all processes would + // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here std::string fname = "ADIOS2BPWriteADIOS1Read2D2x4Test.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 4; + + // Number of rows + const std::size_t Ny = 2; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (Ny * (NumOfProcesses * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 4}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{2, 4}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{2, 4}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 4}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{2, 4}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine @@ -284,31 +385,52 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4) auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -318,93 +440,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 2); - ASSERT_EQ(var_i8->dims[1], 4); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 2); - ASSERT_EQ(var_i16->dims[1], 4); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 2); - ASSERT_EQ(var_i32->dims[1], 4); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 2); - ASSERT_EQ(var_i64->dims[1], 4); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 2); - ASSERT_EQ(var_u8->dims[1], 4); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 2); - ASSERT_EQ(var_u16->dims[1], 4); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 2); - ASSERT_EQ(var_u32->dims[1], 4); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 2); - ASSERT_EQ(var_u64->dims[1], 4); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 2); - ASSERT_EQ(var_r32->dims[1], 4); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 2); - ASSERT_EQ(var_r64->dims[1], 4); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {2, 4}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -419,22 +566,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -454,6 +601,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -472,69 +621,118 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead2D2x4) // ADIOS2 write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2) { + // Each process would write a 4x2 array and all processes would + // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here std::string fname = "ADIOS2BPWriteADIOS1Read2D4x2Test.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 2; + // Number of cols + const std::size_t Ny = 4; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (4 * (NumberOfProcess * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{4, 2}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(mpiSize * Nx)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{4, 2}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{4, 2}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{4, 2}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{4, 2}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); + io.AddTransport("file"); auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -544,93 +742,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 4); - ASSERT_EQ(var_i8->dims[1], 2); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 4); - ASSERT_EQ(var_i16->dims[1], 2); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 4); - ASSERT_EQ(var_i32->dims[1], 2); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 4); - ASSERT_EQ(var_i64->dims[1], 2); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 4); - ASSERT_EQ(var_u8->dims[1], 2); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 4); - ASSERT_EQ(var_u16->dims[1], 2); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 4); - ASSERT_EQ(var_u32->dims[1], 2); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 4); - ASSERT_EQ(var_u64->dims[1], 2); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 4); - ASSERT_EQ(var_r32->dims[1], 2); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 4); - ASSERT_EQ(var_r64->dims[1], 2); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {4, 2}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -645,22 +868,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -680,6 +903,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } diff --git a/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2bb5bfed14c791ef0ad49a89dc0d022fd13c8c7 --- /dev/null +++ b/testing/adios2/engine/bp/TestBPWriteReadAttributes.cpp @@ -0,0 +1,430 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + */ +#include <cstdint> +#include <cstring> + +#include <iostream> +#include <stdexcept> + +#include <adios2.h> +#include <adios_read.h> + +#include <gtest/gtest.h> + +#include "../SmallTestData.h" + +class BPWriteReadAttributeTest : public ::testing::Test +{ +public: + BPWriteReadAttributeTest() = default; + + SmallTestData m_TestData; +}; + +//****************************************************************************** +// 1D 1x8 test data +//****************************************************************************** + +// ADIOS2 write, native ADIOS1 read for single value attributes +TEST_F(BPWriteReadAttributeTest, ADIOS2BPWriteADIOS1ReadSingleTypes) +{ + std::string fname = "foo/ADIOS2BPWriteAttributeADIOS1ReadSingleTypes.bp"; + std::string fRootName = "ADIOS2BPWriteAttributeADIOS1ReadSingleTypes.bp"; + + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // FIXME: Since collective meta generation has not landed yet, so there is + // no way for us to gather different attribute data per process. Ideally we + // should use unique attribute data per process. Ex: + // std::to_string(mpiRank); + std::string mpiRankString = std::to_string(0); + std::string s1_Single = std::string("s1_Single_") + mpiRankString; + std::string i8_Single = std::string("i8_Single_") + mpiRankString; + std::string i16_Single = std::string("i16_Single_") + mpiRankString; + std::string i32_Single = std::string("i32_Single_") + mpiRankString; + std::string i64_Single = std::string("i64_Single_") + mpiRankString; + std::string u8_Single = std::string("u8_Single_") + mpiRankString; + std::string u16_Single = std::string("u16_Single_") + mpiRankString; + std::string u32_Single = std::string("u32_Single_") + mpiRankString; + std::string u64_Single = std::string("u64_Single_") + mpiRankString; + std::string float_Single = std::string("float_Single_") + mpiRankString; + std::string double_Single = std::string("double_Single_") + mpiRankString; + + // When collective meta generation has landed, use + // generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize); + // Generate current testing data + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, 0, 0, 0); + + // Write test data using BP + { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else + adios2::ADIOS adios(true); +#endif + adios2::IO &io = adios.DeclareIO("TestIO"); + + // Declare Single Value Attributes + { + io.DefineAttribute<std::string>(s1_Single, currentTestData.S1); + io.DefineAttribute<int8_t>(i8_Single, currentTestData.I8.front()); + io.DefineAttribute<int16_t>(i16_Single, + currentTestData.I16.front()); + io.DefineAttribute<int32_t>(i32_Single, + currentTestData.I32.front()); + io.DefineAttribute<int64_t>(i64_Single, + currentTestData.I64.front()); + + io.DefineAttribute<uint8_t>(u8_Single, currentTestData.U8.front()); + io.DefineAttribute<uint16_t>(u16_Single, + currentTestData.U16.front()); + io.DefineAttribute<uint32_t>(u32_Single, + currentTestData.U32.front()); + io.DefineAttribute<uint64_t>(u64_Single, + currentTestData.U64.front()); + + io.DefineAttribute<float>(float_Single, + currentTestData.R32.front()); + io.DefineAttribute<double>(double_Single, + currentTestData.R64.front()); + } + + // Create the BP Engine + io.SetEngine("BPFileWriter"); + + io.AddTransport("file"); + + auto engine = io.Open(fname, adios2::OpenMode::Write); + ASSERT_NE(engine.get(), nullptr); + + // Close the file + engine->Close(); + } + + { + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, + "verbose=3"); + + // Open the file for reading + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fRootName + "." + mpiRankString).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); + ASSERT_NE(f, nullptr); + + int size, status; + enum ADIOS_DATATYPES type; + void *data = nullptr; + + // status = adios_get_attr(f, "s1_Single_0", &type, &size, &data); + status = adios_get_attr(f, s1_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_string); + std::string singleStringAttribute(reinterpret_cast<char *>(data), size); + ASSERT_STREQ(singleStringAttribute.c_str(), currentTestData.S1.c_str()); + + status = adios_get_attr(f, i8_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_byte); + ASSERT_EQ(*reinterpret_cast<int8_t *>(data), + currentTestData.I8.front()); + + status = adios_get_attr(f, i16_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_short); + ASSERT_EQ(*reinterpret_cast<int16_t *>(data), + currentTestData.I16.front()); + + status = adios_get_attr(f, i32_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_integer); + ASSERT_EQ(*reinterpret_cast<int32_t *>(data), + currentTestData.I32.front()); + + status = adios_get_attr(f, i64_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_long); + ASSERT_EQ(*reinterpret_cast<int64_t *>(data), + currentTestData.I64.front()); + + status = adios_get_attr(f, u8_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_byte); + ASSERT_EQ(*reinterpret_cast<uint8_t *>(data), + currentTestData.U8.front()); + + status = adios_get_attr(f, u16_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_short); + ASSERT_EQ(*reinterpret_cast<uint16_t *>(data), + currentTestData.U16.front()); + + status = adios_get_attr(f, u32_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_integer); + ASSERT_EQ(*reinterpret_cast<uint32_t *>(data), + currentTestData.U32.front()); + + status = adios_get_attr(f, u64_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_long); + ASSERT_EQ(*reinterpret_cast<uint64_t *>(data), + currentTestData.U64.front()); + + status = adios_get_attr(f, float_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_real); + ASSERT_EQ(*reinterpret_cast<float *>(data), + currentTestData.R32.front()); + + status = adios_get_attr(f, double_Single.c_str(), &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_double); + ASSERT_EQ(*reinterpret_cast<double *>(data), + currentTestData.R64.front()); + + // Cleanup file + adios_read_close(f); + } +} + +// ADIOS2 write, native ADIOS1 read for array attributes +TEST_F(BPWriteReadAttributeTest, ADIOS2BPWriteADIOS1ReadArrayTypes) +{ + std::string fname = "foo/bar/ADIOS2BPWriteAttributeADIOS1ReadArrayTypes.bp"; + std::string fRootName = "ADIOS2BPWriteAttributeADIOS1ReadArrayTypes.bp"; + + // Write test data using ADIOS2 + { + adios2::ADIOS adios(true); + adios2::IO &io = adios.DeclareIO("TestIO"); + + // Declare Array Attributes + { + io.DefineAttribute<std::string>("s3_Array", m_TestData.S3.data(), + m_TestData.S3.size()); + io.DefineAttribute<int8_t>("i8_Array", m_TestData.I8.data(), + m_TestData.I8.size()); + io.DefineAttribute<int16_t>("i16_Array", m_TestData.I16.data(), + m_TestData.I16.size()); + io.DefineAttribute<int32_t>("i32_Array", m_TestData.I32.data(), + m_TestData.I32.size()); + io.DefineAttribute<int64_t>("i64_Array", m_TestData.I64.data(), + m_TestData.I64.size()); + + io.DefineAttribute<uint8_t>("u8_Array", m_TestData.U8.data(), + m_TestData.U8.size()); + io.DefineAttribute<uint16_t>("u16_Array", m_TestData.U16.data(), + m_TestData.U16.size()); + io.DefineAttribute<uint32_t>("u32_Array", m_TestData.U32.data(), + m_TestData.U32.size()); + io.DefineAttribute<uint64_t>("u64_Array", m_TestData.U64.data(), + m_TestData.U64.size()); + + io.DefineAttribute<float>("float_Array", m_TestData.R32.data(), + m_TestData.R32.size()); + io.DefineAttribute<double>("double_Array", m_TestData.R64.data(), + m_TestData.R64.size()); + } + + // Create the BP Engine + io.SetEngine("BPFileWriter"); + + io.AddTransport("file"); + + auto engine = io.Open(fname, adios2::OpenMode::Write); + ASSERT_NE(engine.get(), nullptr); + + // Close the file + engine->Close(); + } + + { + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + "verbose=3"); + + // Open the file for reading + ADIOS_FILE *f = + adios_read_open_file((fname + ".dir/" + fRootName + ".0").c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + ASSERT_NE(f, nullptr); + + int size, status; + enum ADIOS_DATATYPES type; + void *data = nullptr; + + status = adios_get_attr(f, "s3_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_string_array); + char **stringArray = reinterpret_cast<char **>(data); + + for (unsigned int i = 0; i < 3; ++i) + { + ASSERT_STREQ(std::string(stringArray[i]).c_str(), + m_TestData.S3[i].c_str()); + } + + status = adios_get_attr(f, "i8_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(int8_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_byte); + int8_t *I8 = reinterpret_cast<int8_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(I8[i], m_TestData.I8[i]); + } + + status = adios_get_attr(f, "i16_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(int16_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_short); + int16_t *I16 = reinterpret_cast<int16_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(I16[i], m_TestData.I16[i]); + } + + status = adios_get_attr(f, "i32_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(int32_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_integer); + + int32_t *I32 = reinterpret_cast<int32_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(I32[i], m_TestData.I32[i]); + } + + status = adios_get_attr(f, "i64_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(int64_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_long); + int64_t *I64 = reinterpret_cast<int64_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(I64[i], m_TestData.I64[i]); + } + + // uint + status = adios_get_attr(f, "u8_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(uint8_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_byte); + uint8_t *U8 = reinterpret_cast<uint8_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(U8[i], m_TestData.U8[i]); + } + + status = adios_get_attr(f, "u16_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(uint16_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_short); + uint16_t *U16 = reinterpret_cast<uint16_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(U16[i], m_TestData.U16[i]); + } + + status = adios_get_attr(f, "u32_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(uint32_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_integer); + uint32_t *U32 = reinterpret_cast<uint32_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(U32[i], m_TestData.U32[i]); + } + + status = adios_get_attr(f, "u64_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(uint64_t)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_unsigned_long); + uint64_t *U64 = reinterpret_cast<uint64_t *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(U64[i], m_TestData.U64[i]); + } + + status = adios_get_attr(f, "float_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(float)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_real); + float *R32 = reinterpret_cast<float *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(R32[i], m_TestData.R32[i]); + } + + status = adios_get_attr(f, "double_Array", &type, &size, &data); + ASSERT_EQ(status, 0); + ASSERT_EQ(size, 10 * sizeof(double)); + ASSERT_NE(data, nullptr); + ASSERT_EQ(type, adios_double); + double *R64 = reinterpret_cast<double *>(data); + + for (unsigned int i = 0; i < 10; ++i) + { + ASSERT_EQ(R64[i], m_TestData.R64[i]); + } + + // Cleanup file + adios_read_close(f); + } +} + +//****************************************************************************** +// main +//****************************************************************************** + +int main(int argc, char **argv) +{ +#ifdef ADIOS2_HAVE_MPI + MPI_Init(nullptr, nullptr); +#endif + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef ADIOS2_HAVE_MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp b/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp index b979663588eb7feac3f33db1dedb1bb029a8cce0..faaaf1fd9f0bd9555e02ab41831e4ca29b6b3cb9 100644 --- a/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp +++ b/testing/adios2/engine/bp/TestBPWriteReadfstream.cpp @@ -27,72 +27,120 @@ public: // 1D 1x8 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8fstream) { + // Each process would write a 1x8 array and all processes would + // form a mpiSize * Nx 1D array std::string fname = "ADIOS2BPWriteADIOS1Read1D8fstream.bp"; - // Write test data using ADIOS2 + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Write test data using BP { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); - io.AddTransport("File", {{"Library", "fstream"}}); + io.AddTransport("file", {{"Library", "fstream"}}); + // QUESTION: It seems that BPFilterWriter cannot overwrite existing + // files + // Ex. if you tune Nx and NSteps, the test would fail. But if you clear + // the cache in + // ${adios2Build}/testing/adios2/engine/bp/ADIOS2BPWriteADIOS1Read1D8.bp.dir, + // then it works auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -102,83 +150,105 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8fstream) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 1); - ASSERT_EQ(var_i8->dims[0], 8); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 1); - ASSERT_EQ(var_i16->dims[0], 8); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 1); - ASSERT_EQ(var_i32->dims[0], 8); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 1); - ASSERT_EQ(var_i64->dims[0], 8); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 1); - ASSERT_EQ(var_u8->dims[0], 8); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 1); - ASSERT_EQ(var_u16->dims[0], 8); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 1); - ASSERT_EQ(var_u32->dims[0], 8); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 1); - ASSERT_EQ(var_u64->dims[0], 8); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 1); - ASSERT_EQ(var_r32->dims[0], 8); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 1); - ASSERT_EQ(var_r64->dims[0], 8); - - 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; - - uint64_t start[1] = {0}; - uint64_t count[1] = {8}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], mpiSize * Nx); + + std::array<int8_t, Nx> I8; + std::array<int16_t, Nx> I16; + std::array<int32_t, Nx> I32; + std::array<int64_t, Nx> I64; + std::array<uint8_t, Nx> U8; + std::array<uint16_t, Nx> U16; + std::array<uint32_t, Nx> U32; + std::array<uint64_t, Nx> U64; + std::array<float, Nx> R32; + std::array<double, Nx> R64; + + uint64_t start[1] = {mpiRank * Nx}; + uint64_t count[1] = {Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(1, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -193,22 +263,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8fstream) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -228,6 +298,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8fstream) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -243,38 +315,66 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead1D8fstream) // 2D 2x4 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream) { + // Each process would write a 2x4 array and all processes would + // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here std::string fname = "ADIOS2BPWriteADIOS1Read2D2x4Testfstream.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 4; + + // Number of rows + const std::size_t Ny = 2; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (Ny * (NumOfProcesses * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 4}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{2, 4}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{2, 4}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 4}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{2, 4}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine @@ -284,31 +384,52 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream) auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -318,93 +439,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 2); - ASSERT_EQ(var_i8->dims[1], 4); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 2); - ASSERT_EQ(var_i16->dims[1], 4); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 2); - ASSERT_EQ(var_i32->dims[1], 4); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 2); - ASSERT_EQ(var_i64->dims[1], 4); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 2); - ASSERT_EQ(var_u8->dims[1], 4); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 2); - ASSERT_EQ(var_u16->dims[1], 4); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 2); - ASSERT_EQ(var_u32->dims[1], 4); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 2); - ASSERT_EQ(var_u64->dims[1], 4); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 2); - ASSERT_EQ(var_r32->dims[1], 4); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 2); - ASSERT_EQ(var_r64->dims[1], 4); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {2, 4}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -419,22 +565,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -454,6 +600,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4fstream) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -472,35 +620,62 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead2D2x4fstream) // ADIOS2 write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream) { + // Each process would write a 4x2 array and all processes would + // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here std::string fname = "ADIOS2BPWriteADIOS1Read2D4x2Testfstream.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 2; + // Number of cols + const std::size_t Ny = 4; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (4 * (NumberOfProcess * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{4, 2}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(mpiSize * Nx)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{4, 2}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{4, 2}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{4, 2}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{4, 2}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine @@ -510,31 +685,52 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream) auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -544,93 +740,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 4); - ASSERT_EQ(var_i8->dims[1], 2); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 4); - ASSERT_EQ(var_i16->dims[1], 2); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 4); - ASSERT_EQ(var_i32->dims[1], 2); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 4); - ASSERT_EQ(var_i64->dims[1], 2); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 4); - ASSERT_EQ(var_u8->dims[1], 2); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 4); - ASSERT_EQ(var_u16->dims[1], 2); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 4); - ASSERT_EQ(var_u32->dims[1], 2); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 4); - ASSERT_EQ(var_u64->dims[1], 2); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 4); - ASSERT_EQ(var_r32->dims[1], 2); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 4); - ASSERT_EQ(var_r64->dims[1], 2); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {4, 2}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -645,22 +866,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -680,6 +901,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2fstream) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } diff --git a/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp b/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp index 039601b80d4c8c1cc28bfb57337119b5166b78a7..a47653c7f1931804ce49bc9bfdac4557d9678b7c 100644 --- a/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp +++ b/testing/adios2/engine/bp/TestBPWriteReadstdio.cpp @@ -27,72 +27,124 @@ public: // 1D 1x8 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8stdio) { + // Each process would write a 1x8 array and all processes would + // form a mpiSize * Nx 1D array std::string fname = "ADIOS2BPWriteADIOS1Read1D8stdio.bp"; - // Write test data using ADIOS2 + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Write test data using BP { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); - io.AddTransport("File", {{"Library", "stdio"}}); +#ifdef ADIOS2_HAVE_MPI + io.AddTransport("file", {{"Library", "stdio"}}); +#else + io.AddTransport("file"); +#endif + // QUESTION: It seems that BPFilterWriter cannot overwrite existing + // files + // Ex. if you tune Nx and NSteps, the test would fail. But if you clear + // the cache in + // ${adios2Build}/testing/adios2/engine/bp/ADIOS2BPWriteADIOS1Read1D8.bp.dir, + // then it works auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -102,83 +154,105 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8stdio) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 1); - ASSERT_EQ(var_i8->dims[0], 8); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 1); - ASSERT_EQ(var_i16->dims[0], 8); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 1); - ASSERT_EQ(var_i32->dims[0], 8); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 1); - ASSERT_EQ(var_i64->dims[0], 8); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 1); - ASSERT_EQ(var_u8->dims[0], 8); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 1); - ASSERT_EQ(var_u16->dims[0], 8); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 1); - ASSERT_EQ(var_u32->dims[0], 8); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 1); - ASSERT_EQ(var_u64->dims[0], 8); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 1); - ASSERT_EQ(var_r32->dims[0], 8); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 1); - ASSERT_EQ(var_r64->dims[0], 8); - - 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; - - uint64_t start[1] = {0}; - uint64_t count[1] = {8}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], mpiSize * Nx); + + std::array<int8_t, Nx> I8; + std::array<int16_t, Nx> I16; + std::array<int32_t, Nx> I32; + std::array<int64_t, Nx> I64; + std::array<uint8_t, Nx> U8; + std::array<uint16_t, Nx> U16; + std::array<uint32_t, Nx> U32; + std::array<uint64_t, Nx> U64; + std::array<float, Nx> R32; + std::array<double, Nx> R64; + + uint64_t start[1] = {mpiRank * Nx}; + uint64_t count[1] = {Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(1, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -193,22 +267,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8stdio) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -228,6 +302,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read1D8stdio) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -243,72 +319,125 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead1D8stdio) // 2D 2x4 test data //****************************************************************************** -// ADIOS2 write, native ADIOS1 read +// ADIOS2 BP write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4stdio) { + // Each process would write a 2x4 array and all processes would + // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here std::string fname = "ADIOS2BPWriteADIOS1Read2D2x4Teststdio.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 4; + + // Number of rows + const std::size_t Ny = 2; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (Ny * (NumOfProcesses * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 4}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{2, 4}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{2, 4}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 4}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{2, 4}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); +#ifdef ADIOS2_HAVE_MPI io.AddTransport("file", {{"Library", "stdio"}}); +#else + io.AddTransport("file"); +#endif auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -318,93 +447,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4stdio) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 2); - ASSERT_EQ(var_i8->dims[1], 4); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 2); - ASSERT_EQ(var_i16->dims[1], 4); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 2); - ASSERT_EQ(var_i32->dims[1], 4); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 2); - ASSERT_EQ(var_i64->dims[1], 4); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 2); - ASSERT_EQ(var_u8->dims[1], 4); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 2); - ASSERT_EQ(var_u16->dims[1], 4); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 2); - ASSERT_EQ(var_u32->dims[1], 4); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 2); - ASSERT_EQ(var_u64->dims[1], 4); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 2); - ASSERT_EQ(var_r32->dims[1], 4); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 2); - ASSERT_EQ(var_r64->dims[1], 4); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {2, 4}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -419,22 +573,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4stdio) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -454,6 +608,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D2x4stdio) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } @@ -472,69 +628,122 @@ TEST_F(BPWriteReadTest, DISABLED_ADIOS2BPWriteADIOS2BPRead2D2x4stdio) // ADIOS2 write, native ADIOS1 read TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2stdio) { + // Each process would write a 4x2 array and all processes would + // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here std::string fname = "ADIOS2BPWriteADIOS1Read2D4x2Teststdio.bp"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 2; + // Number of cols + const std::size_t Ny = 4; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (4 * (NumberOfProcess * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{4, 2}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(mpiSize * Nx)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{4, 2}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{4, 2}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{4, 2}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{4, 2}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<double>("r64", shape, start, count); } // Create the BP Engine io.SetEngine("BPFileWriter"); + +#ifdef ADIOS2_HAVE_MPI io.AddTransport("file", {{"Library", "stdio"}}); +#else + io.AddTransport("file"); +#endif auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -544,93 +753,118 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2stdio) engine->Close(); } -// Read test data using ADIOS1 -#ifdef ADIOS2_HAVE_MPI - // Read everything from rank 0 - int rank; - MPI_Comm_rank(); - if (rank == 0) -#endif { - adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_WORLD, + adios_read_init_method(ADIOS_READ_METHOD_BP, MPI_COMM_SELF, "verbose=3"); // Open the file for reading - ADIOS_FILE *f = - adios_read_open_file((fname + ".dir/" + fname + ".0").c_str(), - ADIOS_READ_METHOD_BP, MPI_COMM_WORLD); + // Note: Since collective metadata generation is not implemented yet, + // SO for now we read each subfile instead of a single bp file with all + // metadata. + // Meanwhile if we open file with MPI_COMM_WORLD, then the selection + // bounding box should be [0, Nx] + std::string index = std::to_string(mpiRank); + ADIOS_FILE *f = adios_read_open_file( + (fname + ".dir/" + fname + "." + index).c_str(), + ADIOS_READ_METHOD_BP, MPI_COMM_SELF); ASSERT_NE(f, nullptr); // Check the variables exist ADIOS_VARINFO *var_i8 = adios_inq_var(f, "i8"); ASSERT_NE(var_i8, nullptr); ASSERT_EQ(var_i8->ndim, 2); - ASSERT_EQ(var_i8->dims[0], 4); - ASSERT_EQ(var_i8->dims[1], 2); + ASSERT_EQ(var_i8->global, 1); + ASSERT_EQ(var_i8->nsteps, NSteps); + ASSERT_EQ(var_i8->dims[0], Ny); + ASSERT_EQ(var_i8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i16 = adios_inq_var(f, "i16"); ASSERT_NE(var_i16, nullptr); ASSERT_EQ(var_i16->ndim, 2); - ASSERT_EQ(var_i16->dims[0], 4); - ASSERT_EQ(var_i16->dims[1], 2); + ASSERT_EQ(var_i16->global, 1); + ASSERT_EQ(var_i16->nsteps, NSteps); + ASSERT_EQ(var_i16->dims[0], Ny); + ASSERT_EQ(var_i16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i32 = adios_inq_var(f, "i32"); ASSERT_NE(var_i32, nullptr); ASSERT_EQ(var_i32->ndim, 2); - ASSERT_EQ(var_i32->dims[0], 4); - ASSERT_EQ(var_i32->dims[1], 2); + ASSERT_EQ(var_i32->global, 1); + ASSERT_EQ(var_i32->nsteps, NSteps); + ASSERT_EQ(var_i32->dims[0], Ny); + ASSERT_EQ(var_i32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_i64 = adios_inq_var(f, "i64"); ASSERT_NE(var_i64, nullptr); ASSERT_EQ(var_i64->ndim, 2); - ASSERT_EQ(var_i64->dims[0], 4); - ASSERT_EQ(var_i64->dims[1], 2); + ASSERT_EQ(var_i64->global, 1); + ASSERT_EQ(var_i64->nsteps, NSteps); + ASSERT_EQ(var_i64->dims[0], Ny); + ASSERT_EQ(var_i64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u8 = adios_inq_var(f, "u8"); ASSERT_NE(var_u8, nullptr); ASSERT_EQ(var_u8->ndim, 2); - ASSERT_EQ(var_u8->dims[0], 4); - ASSERT_EQ(var_u8->dims[1], 2); + ASSERT_EQ(var_u8->global, 1); + ASSERT_EQ(var_u8->nsteps, NSteps); + ASSERT_EQ(var_u8->dims[0], Ny); + ASSERT_EQ(var_u8->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u16 = adios_inq_var(f, "u16"); ASSERT_NE(var_u16, nullptr); ASSERT_EQ(var_u16->ndim, 2); - ASSERT_EQ(var_u16->dims[0], 4); - ASSERT_EQ(var_u16->dims[1], 2); + ASSERT_EQ(var_u16->global, 1); + ASSERT_EQ(var_u16->nsteps, NSteps); + ASSERT_EQ(var_u16->dims[0], Ny); + ASSERT_EQ(var_u16->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u32 = adios_inq_var(f, "u32"); ASSERT_NE(var_u32, nullptr); ASSERT_EQ(var_u32->ndim, 2); - ASSERT_EQ(var_u32->dims[0], 4); - ASSERT_EQ(var_u32->dims[1], 2); + ASSERT_EQ(var_u32->global, 1); + ASSERT_EQ(var_u32->nsteps, NSteps); + ASSERT_EQ(var_u32->dims[0], Ny); + ASSERT_EQ(var_u32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_u64 = adios_inq_var(f, "u64"); ASSERT_NE(var_u64, nullptr); ASSERT_EQ(var_u64->ndim, 2); - ASSERT_EQ(var_u64->dims[0], 4); - ASSERT_EQ(var_u64->dims[1], 2); + ASSERT_EQ(var_u64->global, 1); + ASSERT_EQ(var_u64->nsteps, NSteps); + ASSERT_EQ(var_u64->dims[0], Ny); + ASSERT_EQ(var_u64->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r32 = adios_inq_var(f, "r32"); ASSERT_NE(var_r32, nullptr); ASSERT_EQ(var_r32->ndim, 2); - ASSERT_EQ(var_r32->dims[0], 4); - ASSERT_EQ(var_r32->dims[1], 2); + ASSERT_EQ(var_r32->global, 1); + ASSERT_EQ(var_r32->nsteps, NSteps); + ASSERT_EQ(var_r32->dims[0], Ny); + ASSERT_EQ(var_r32->dims[1], mpiSize * Nx); ADIOS_VARINFO *var_r64 = adios_inq_var(f, "r64"); ASSERT_NE(var_r64, nullptr); ASSERT_EQ(var_r64->ndim, 2); - ASSERT_EQ(var_r64->dims[0], 4); - ASSERT_EQ(var_r64->dims[1], 2); - - 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; - - uint64_t start[2] = {0, 0}; - uint64_t count[2] = {4, 2}; + ASSERT_EQ(var_r64->global, 1); + ASSERT_EQ(var_r64->nsteps, NSteps); + ASSERT_EQ(var_r64->dims[0], Ny); + ASSERT_EQ(var_r64->dims[1], mpiSize * Nx); + + // If the size of the array is smaller than the data + // the result is weird... double and uint64_t would get completely + // garbage data + std::array<int8_t, Nx * Ny> I8; + std::array<int16_t, Nx * Ny> I16; + std::array<int32_t, Nx * Ny> I32; + std::array<int64_t, Nx * Ny> I64; + std::array<uint8_t, Nx * Ny> U8; + std::array<uint16_t, Nx * Ny> U16; + std::array<uint32_t, Nx * Ny> U32; + std::array<uint64_t, Nx * Ny> U64; + std::array<float, Nx * Ny> R32; + std::array<double, Nx * Ny> R64; + + uint64_t start[2] = {0, mpiRank * Nx}; + uint64_t count[2] = {Ny, Nx}; ADIOS_SELECTION *sel = adios_selection_boundingbox(2, start, count); // Read stuff - for (size_t t = 0; t < 3; ++t) + for (size_t t = 0; t < NSteps; ++t) { + // Generate test data for each rank uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); // Read the current step adios_schedule_read_byid(f, sel, var_i8->varid, t, 1, I8.data()); adios_schedule_read_byid(f, sel, var_i16->varid, t, 1, I16.data()); @@ -645,22 +879,22 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2stdio) adios_perform_reads(f, 1); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } } @@ -680,6 +914,8 @@ TEST_F(BPWriteReadTest, ADIOS2BPWriteADIOS1Read2D4x2stdio) // Cleanup file adios_read_close(f); + + adios_read_finalize_method(ADIOS_READ_METHOD_BP); } } diff --git a/testing/adios2/engine/hdf5/CMakeLists.txt b/testing/adios2/engine/hdf5/CMakeLists.txt index 9847eaee6b081946ccf2c98db47a23b587daa223..85a20cb648ae68c523f1ffe7c8b5a5a3873ba6b8 100644 --- a/testing/adios2/engine/hdf5/CMakeLists.txt +++ b/testing/adios2/engine/hdf5/CMakeLists.txt @@ -3,10 +3,23 @@ # accompanying file Copyright.txt for details. #------------------------------------------------------------------------------# -find_package(HDF5 REQUIRED) - add_executable(TestHDF5WriteRead TestHDF5WriteRead.cpp) -target_include_directories(TestHDF5WriteRead PRIVATE ${HDF5_C_INCLUDE_DIRS}) + +# Workaround for multiple versions of FindHDF5 +if(HDF5_C_INCLUDE_DIRS) + target_include_directories(TestHDF5WriteRead PRIVATE ${HDF5_C_INCLUDE_DIRS}) +else() + target_include_directories(TestHDF5WriteRead PRIVATE ${HDF5_INCLUDE_DIRS}) +endif() target_link_libraries(TestHDF5WriteRead adios2 gtest ${HDF5_C_LIBRARIES}) -gtest_add_tests(TARGET TestHDF5WriteRead) +if(ADIOS2_HAVE_MPI) + target_include_directories(TestHDF5WriteRead PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestHDF5WriteRead ${MPI_C_LIBRARIES}) + set(extra_test_args + EXEC_WRAPPER + ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ) +endif() + +gtest_add_tests(TARGET TestHDF5WriteRead ${extra_test_args}) diff --git a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp index e0cef14cb17924f199989464af83a89b7f977af3..dd92b35c81fc96b7a7ba7fe454285e99b79cd9c7 100644 --- a/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp +++ b/testing/adios2/engine/hdf5/TestHDF5WriteRead.cpp @@ -35,7 +35,11 @@ public: void GetVarInfo(const std::string varName, std::vector<hsize_t> &dims, hid_t &h5Type); - void ReadVar(const std::string varName, void *dataArray); + // If offset, count and memspaceSize are provided, then variable would be + // read by selection + void ReadVar(const std::string varName, void *dataArray, + hsize_t *offset = nullptr, hsize_t *count = nullptr, + const size_t memsspaceSize = 0); int m_CurrentTimeStep; unsigned int m_TotalTimeSteps; @@ -96,7 +100,8 @@ void HDF5NativeReader::GetVarInfo(const std::string varName, hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT); if (dataSetId < 0) { - throw std::runtime_error("Unable to open dataset " + varName); + throw std::runtime_error("Unable to open dataset " + varName + + " when getVarInfo"); } hid_t fileSpaceId = H5Dget_space(dataSetId); @@ -151,7 +156,9 @@ bool HDF5NativeReader::Advance() return true; } -void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray) +void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray, + hsize_t *offset, hsize_t *count, + const size_t memspaceSize) { if (m_GroupId < 0) { @@ -162,7 +169,8 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray) hid_t dataSetId = H5Dopen(m_GroupId, varName.c_str(), H5P_DEFAULT); if (dataSetId < 0) { - throw std::runtime_error("Unable to open dataset " + varName); + throw std::runtime_error("Unable to open dataset " + varName + + "when ReadVar"); } hid_t fileSpace = H5Dget_space(dataSetId); @@ -173,8 +181,35 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray) } hid_t h5type = H5Dget_type(dataSetId); - hid_t ret = - H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataArray); + + // Extend reader to support read by hyperslab selection + // Reference link: https://support.hdfgroup.org/HDF5/Tutor/select.html + // Check if hyperspace is provided + if (offset && count) + { + // Get the dataspace + hid_t dataspace = H5Dget_space(dataSetId); + // Define hyperslab in the dataset + hid_t status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, + NULL, count, NULL); + if (status < 0) + { + throw std::runtime_error( + "Unable to create a selection for dataset" + varName); + } + + hsize_t dimsm[1]; + dimsm[0] = memspaceSize; + hid_t memspace = H5Screate_simple(1, dimsm, NULL); + + hid_t ret = H5Dread(dataSetId, h5type, memspace, dataspace, H5P_DEFAULT, + dataArray); + } + else + { + hid_t ret = H5Dread(dataSetId, h5type, H5S_ALL, H5S_ALL, H5P_DEFAULT, + dataArray); + } H5Sclose(fileSpace); H5Dclose(dataSetId); @@ -187,67 +222,117 @@ void HDF5NativeReader::ReadVar(const std::string varName, void *dataArray) // ADIOS2 write, native HDF5 read TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8) { + // Each process would write a 1x8 array and all processes would + // form a mpiSize * Nx 1D array std::string fname = "ADIOS2HDF5WriteHDF5Read1D8.h5"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 8; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { - adios2::ADIOS adios(true); // moved up +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else + adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + + // Declare 1D variables (NumOfProcesses * Nx) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{8}); + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{8}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{8}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{8}); + io.DefineVariable<int64_t>("i64", shape, start, count); auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{8}); - auto &var_u16 = io.DefineVariable<unsigned short>("u16", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{8}); - auto &var_u64 = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{8}); + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{8}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{8}); + io.DefineVariable<double>("r64", shape, start, count); } - // Create the HDF5 Engine + // Create the ADIOS 1 Engine io.SetEngine("HDF5Writer"); + // HDf5 engine calls the HDF5 common object that calls the hDF5 library. + // The IO functionality, SetParameters and AddTransports will be added + // in the future. For now `io.AddTransport("file", { + // "library", "MPI"}});` is omitted. + // }) + io.AddTransport("file"); + auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 1D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel({mpiRank * Nx}, {Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -257,113 +342,115 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read1D8) engine->Close(); } -// 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 { - 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; + const size_t arraySize = Nx; + std::array<int8_t, arraySize> I8; + std::array<int16_t, arraySize> I16; + std::array<int32_t, arraySize> I32; + std::array<int64_t, arraySize> I64; + std::array<uint8_t, arraySize> U8; + std::array<uint16_t, arraySize> U16; + std::array<uint32_t, arraySize> U32; + std::array<uint64_t, arraySize> U64; + std::array<float, arraySize> R32; + std::array<double, arraySize> R64; HDF5NativeReader hdf5Reader(fname); - - // Read stuff - for (size_t t = 0; t < 3; ++t) + // 1D + hsize_t count[1], offset[1]; + count[0] = mpiRank * Nx; + offset[0] = Nx; + size_t globalArraySize = Nx * mpiSize; + + // For each variable, we would verify its global size and type. + // Then we would retrieve the data back which is written by the + // current process and validate the value + for (size_t t = 0; t < NSteps; ++t) { + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); + 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[0], globalArraySize); + hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } - hdf5Reader.Advance(); } } @@ -392,69 +479,124 @@ TEST_F(HDF5WriteReadTest, DISABLED_HDF5WriteADIOS2HDF5Read1D8) // ADIOS2 write, native HDF5 read TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4) { + // Each process would write a 2x4 array and all processes would + // form a 2D 2 * (numberOfProcess*Nx) matrix where Nx is 4 here std::string fname = "ADIOS2HDF5WriteHDF5Read2D2x4Test.h5"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 4; + + // Number of rows + const std::size_t Ny = 2; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (Ny * (NumOfProcesses * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 4}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{2, 4}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{2, 4}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 4}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{2, 4}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 4}); + io.DefineVariable<double>("r64", shape, start, count); } + // Create the ADIOS 1 Engine io.SetEngine("HDF5Writer"); + + // HDf5 engine calls the HDF5 common object that calls the hDF5 library. + // The IO functionality, SetParameters and AddTransports will be added + // in the future. For now `io.AddTransport("file", { + // "library", "MPI"}});` is omitted. + // }) io.AddTransport("file"); - // Create the HDF5 Engine auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -464,30 +606,36 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4) engine->Close(); } -// 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 { 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) + const size_t arraySize = Nx * Ny; + std::array<int8_t, arraySize> I8; + std::array<int16_t, arraySize> I16; + std::array<int32_t, arraySize> I32; + std::array<int64_t, arraySize> I64; + std::array<uint8_t, arraySize> U8; + std::array<uint16_t, arraySize> U16; + std::array<uint32_t, arraySize> U32; + std::array<uint64_t, arraySize> U64; + std::array<float, arraySize> R32; + std::array<double, arraySize> R64; + // 2D + hsize_t count[2], offset[2]; + count[0] = 0; + count[1] = mpiRank * Nx; + offset[0] = Ny; + offset[1] = Nx; + size_t globalArraySize = Nx * mpiSize; + + // For each variable, we would verify its global size and type. + // Then we would retrieve the data back which is written by the + // current process and validate the value + for (size_t t = 0; t < NSteps; ++t) { + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); + std::vector<hsize_t> gDims; hid_t h5Type; @@ -495,89 +643,89 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D2x4) 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize); // Check if it's correct - for (size_t i = 0; i < 8; ++i) + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } hdf5Reader.Advance(); } @@ -607,69 +755,124 @@ TEST_F(HDF5WriteReadTest, DISABLED_HDF5WriteADIOS2HDF5Read2D2x4) // ADIOS2 write, native HDF5 read TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2) { + + // Each process would write a 4x2 array and all processes would + // form a 2D 4 * (NumberOfProcess * Nx) matrix where Nx is 2 here std::string fname = "ADIOS2HDF5WriteHDF5Read2D4x2Test.h5"; + int mpiRank = 0, mpiSize = 1; + // Number of rows + const std::size_t Nx = 2; + // Number of cols + const std::size_t Ny = 4; + + // Number of steps + const std::size_t NSteps = 3; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + // Write test data using ADIOS2 { +#ifdef ADIOS2_HAVE_MPI + adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON); +#else adios2::ADIOS adios(true); +#endif adios2::IO &io = adios.DeclareIO("TestIO"); - // Declare 1D variables + // Declare 2D variables (4 * (NumberOfProcess * Nx)) + // The local process' part (start, count) can be defined now or later + // before Write(). { - auto &var_i8 = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{4, 2}); + adios2::Dims shape{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(mpiSize * Nx)}; + adios2::Dims start{static_cast<unsigned int>(0), + static_cast<unsigned int>(mpiRank * Nx)}; + adios2::Dims count{static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nx)}; + auto &var_i8 = io.DefineVariable<int8_t>("i8", shape, start, count); auto &var_i16 = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int16_t>("i16", shape, start, count); auto &var_i32 = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int32_t>("i32", shape, start, count); auto &var_i64 = - io.DefineVariable<long>("i64", {}, {}, adios2::Dims{4, 2}); - auto &var_u8 = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{4, 2}); - auto &var_u16 = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{4, 2}); - auto &var_u32 = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{4, 2}); - auto &var_u64 = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<int64_t>("i64", shape, start, count); + auto &var_u8 = + io.DefineVariable<uint8_t>("u8", shape, start, count); + auto &var_u16 = + io.DefineVariable<uint16_t>("u16", shape, start, count); + auto &var_u32 = + io.DefineVariable<uint32_t>("u32", shape, start, count); + auto &var_u64 = + io.DefineVariable<uint64_t>("u64", shape, start, count); auto &var_r32 = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<float>("r32", shape, start, count); auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{4, 2}); + io.DefineVariable<double>("r64", shape, start, count); } - // Create the HDF5 Engine + // Create the ADIOS 1 Engine io.SetEngine("HDF5Writer"); + + // HDf5 engine calls the HDF5 common object that calls the hDF5 library. + // The IO functionality, SetParameters and AddTransports will be added + // in the future. For now `io.AddTransport("file", { + // "library", "MPI"}});` is omitted. + // }) io.AddTransport("file"); auto engine = io.Open(fname, adios2::OpenMode::Write); ASSERT_NE(engine.get(), nullptr); - for (size_t step = 0; step < 3; ++step) + for (size_t step = 0; step < NSteps; ++step) { + // Generate test data for each process uniquely + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, step, mpiRank, mpiSize); + // Retrieve the variables that previously went out of scope - auto &var_i8 = io.GetVariable<char>("i8"); - auto &var_i16 = io.GetVariable<short>("i16"); - auto &var_i32 = io.GetVariable<int>("i32"); - auto &var_i64 = io.GetVariable<long>("i64"); - auto &var_u8 = io.GetVariable<unsigned char>("u8"); - auto &var_u16 = io.GetVariable<unsigned short>("u16"); - auto &var_u32 = io.GetVariable<unsigned int>("u32"); - auto &var_u64 = io.GetVariable<unsigned long>("u64"); + auto &var_i8 = io.GetVariable<int8_t>("i8"); + auto &var_i16 = io.GetVariable<int16_t>("i16"); + auto &var_i32 = io.GetVariable<int32_t>("i32"); + auto &var_i64 = io.GetVariable<int64_t>("i64"); + auto &var_u8 = io.GetVariable<uint8_t>("u8"); + auto &var_u16 = io.GetVariable<uint16_t>("u16"); + auto &var_u32 = io.GetVariable<uint32_t>("u32"); + auto &var_u64 = io.GetVariable<uint64_t>("u64"); auto &var_r32 = io.GetVariable<float>("r32"); auto &var_r64 = io.GetVariable<double>("r64"); + // Make a 2D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel( + {0, static_cast<unsigned int>(mpiRank * Nx)}, {Ny, Nx}); + var_i8.SetSelection(sel); + var_i16.SetSelection(sel); + var_i32.SetSelection(sel); + var_i64.SetSelection(sel); + var_u8.SetSelection(sel); + var_u16.SetSelection(sel); + var_u32.SetSelection(sel); + var_u64.SetSelection(sel); + var_r32.SetSelection(sel); + var_r64.SetSelection(sel); + // Write each one - engine->Write(var_i8, m_TestData.I8.data() + step); - engine->Write(var_i16, m_TestData.I16.data() + step); - engine->Write(var_i32, m_TestData.I32.data() + step); - engine->Write(var_i64, m_TestData.I64.data() + step); - engine->Write(var_u8, m_TestData.U8.data() + step); - engine->Write(var_u16, m_TestData.U16.data() + step); - engine->Write(var_u32, m_TestData.U32.data() + step); - engine->Write(var_u64, m_TestData.U64.data() + step); - engine->Write(var_r32, m_TestData.R32.data() + step); - engine->Write(var_r64, m_TestData.R64.data() + step); + // fill in the variable with values from starting index to + // starting index + count + engine->Write(var_i8, currentTestData.I8.data()); + engine->Write(var_i16, currentTestData.I16.data()); + engine->Write(var_i32, currentTestData.I32.data()); + engine->Write(var_i64, currentTestData.I64.data()); + engine->Write(var_u8, currentTestData.U8.data()); + engine->Write(var_u16, currentTestData.U16.data()); + engine->Write(var_u32, currentTestData.U32.data()); + engine->Write(var_u64, currentTestData.U64.data()); + engine->Write(var_r32, currentTestData.R32.data()); + engine->Write(var_r64, currentTestData.R64.data()); // Advance to the next time step engine->Advance(); @@ -679,31 +882,37 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2) engine->Close(); } -// 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 { 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) + const size_t arraySize = Nx * Ny; + std::array<int8_t, arraySize> I8; + std::array<int16_t, arraySize> I16; + std::array<int32_t, arraySize> I32; + std::array<int64_t, arraySize> I64; + std::array<uint8_t, arraySize> U8; + std::array<uint16_t, arraySize> U16; + std::array<uint32_t, arraySize> U32; + std::array<uint64_t, arraySize> U64; + std::array<float, arraySize> R32; + std::array<double, arraySize> R64; + // 2D + hsize_t count[2], offset[2]; + count[0] = 0; + count[1] = mpiRank * Nx; + offset[0] = Ny; + offset[1] = Nx; + size_t globalArraySize = Nx * mpiSize; + + // For each variable, we would verify its global size and type. + // Then we would retrieve the data back which is written by the + // current process and validate the value + for (size_t t = 0; t < NSteps; ++t) { + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, t, mpiRank, mpiSize); + std::vector<hsize_t> gDims; hid_t h5Type; @@ -711,88 +920,89 @@ TEST_F(HDF5WriteReadTest, ADIOS2HDF5WriteHDF5Read2D4x2) 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i8", I8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i16", I16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i32", I32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("i64", I64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u8", U8.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u16", U16.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u32", U32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("u64", U64.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("r32", R32.data(), count, offset, arraySize); 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()); + ASSERT_EQ(gDims[1], globalArraySize); + hdf5Reader.ReadVar("r64", R64.data(), count, offset, arraySize); - for (size_t i = 0; i < 8; ++i) + // Check if it's correct + for (size_t i = 0; i < Nx; ++i) { std::stringstream ss; - ss << "t=" << t << " i=" << i; + ss << "t=" << t << " i=" << i << " rank=" << mpiRank; 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; + EXPECT_EQ(I8[i], currentTestData.I8[i]) << msg; + EXPECT_EQ(I16[i], currentTestData.I16[i]) << msg; + EXPECT_EQ(I32[i], currentTestData.I32[i]) << msg; + EXPECT_EQ(I64[i], currentTestData.I64[i]) << msg; + EXPECT_EQ(U8[i], currentTestData.U8[i]) << msg; + EXPECT_EQ(U16[i], currentTestData.U16[i]) << msg; + EXPECT_EQ(U32[i], currentTestData.U32[i]) << msg; + EXPECT_EQ(U64[i], currentTestData.U64[i]) << msg; + EXPECT_EQ(R32[i], currentTestData.R32[i]) << msg; + EXPECT_EQ(R64[i], currentTestData.R64[i]) << msg; } hdf5Reader.Advance(); } diff --git a/testing/adios2/interface/CMakeLists.txt b/testing/adios2/interface/CMakeLists.txt index e68ccfa6187ab17710e4bca93579ede6ded95079..986133796b28597df33ed0591e9feab92cee400b 100644 --- a/testing/adios2/interface/CMakeLists.txt +++ b/testing/adios2/interface/CMakeLists.txt @@ -9,5 +9,25 @@ target_link_libraries(TestADIOSInterfaceWrite adios2 gtest gtest_main) add_executable(TestADIOSDefineVariable TestADIOSDefineVariable.cpp) target_link_libraries(TestADIOSDefineVariable adios2 gtest gtest_main) -gtest_add_tests(TARGET TestADIOSInterfaceWrite) -gtest_add_tests(TARGET TestADIOSDefineVariable) \ No newline at end of file +add_executable(TestADIOSDefineAttribute TestADIOSDefineAttribute.cpp) +target_link_libraries(TestADIOSDefineAttribute adios2 gtest gtest_main) + +if(ADIOS2_HAVE_MPI) + target_include_directories(TestADIOSInterfaceWrite PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestADIOSInterfaceWrite ${MPI_C_LIBRARIES}) + + target_include_directories(TestADIOSDefineVariable PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestADIOSDefineVariable ${MPI_C_LIBRARIES}) + + target_include_directories(TestADIOSDefineAttribute PRIVATE ${MPI_C_INCLUDE_PATH}) + target_link_libraries(TestADIOSDefineAttribute ${MPI_C_LIBRARIES}) + + set(extra_test_args + EXEC_WRAPPER + ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} + ) +endif() + +gtest_add_tests(TARGET TestADIOSInterfaceWrite ${extra_test_args}) +gtest_add_tests(TARGET TestADIOSDefineVariable ${extra_test_args}) +gtest_add_tests(TARGET TestADIOSDefineAttribute ${extra_test_args}) diff --git a/testing/adios2/interface/TestADIOSDefineAttribute.cpp b/testing/adios2/interface/TestADIOSDefineAttribute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70d25a10d0a37a1d68c4c9bf039ad2922a655781 --- /dev/null +++ b/testing/adios2/interface/TestADIOSDefineAttribute.cpp @@ -0,0 +1,555 @@ +#include <cstdint> + +#include <iostream> +#include <stdexcept> + +#include <adios2.h> + +#include <gtest/gtest.h> + +#include "../engine/SmallTestData.h" + +class ADIOSDefineAttributeTest : public ::testing::Test +{ +public: + ADIOSDefineAttributeTest() : adios(true), io(adios.DeclareIO("TestIO")) {} + + SmallTestData m_TestData; + +protected: + adios2::ADIOS adios; + adios2::IO &io; +}; + +TEST_F(ADIOSDefineAttributeTest, DefineAttributeNameException) +{ + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("attributeString") + std::to_string(mpiRank); + + // Attribute should be unique per process + auto &attributeString1 = io.DefineAttribute<std::string>(name, "-1"); + + EXPECT_THROW(auto &attributeString2 = + io.DefineAttribute<std::string>(name, "0"), + std::invalid_argument); + + EXPECT_THROW(auto &attributeString2 = + io.GetAttribute<std::string>("NoExistingAttribute"), + std::invalid_argument); + + EXPECT_NO_THROW(auto &attributeString3 = + io.GetAttribute<std::string>(name)); +} + +TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByValue) +{ + + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Define unique data for each process + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize); + + std::string mpiRankString = std::to_string(mpiRank); + std::string s1_Single = std::string("s1_Single_") + mpiRankString; + std::string i8_Single = std::string("i8_Single_") + mpiRankString; + std::string i16_Single = std::string("i16_Single_") + mpiRankString; + std::string i32_Single = std::string("i32_Single_") + mpiRankString; + std::string i64_Single = std::string("i64_Single_") + mpiRankString; + std::string u8_Single = std::string("u8_Single_") + mpiRankString; + std::string u16_Single = std::string("u16_Single_") + mpiRankString; + std::string u32_Single = std::string("u32_Single_") + mpiRankString; + std::string u64_Single = std::string("u64_Single_") + mpiRankString; + std::string float_Single = std::string("float_Single_") + mpiRankString; + std::string double_Single = std::string("double_Single_") + mpiRankString; + + // Define ADIOS global value + auto &attributeS1 = + io.DefineAttribute<std::string>(s1_Single, currentTestData.S1); + auto &attributeI8 = + io.DefineAttribute<int8_t>(i8_Single, currentTestData.I8.front()); + auto &attributeI16 = + io.DefineAttribute<int16_t>(i16_Single, currentTestData.I16.front()); + auto &attributeI32 = + io.DefineAttribute<int32_t>(i32_Single, currentTestData.I32.front()); + auto &attributeI64 = + io.DefineAttribute<int64_t>(i64_Single, currentTestData.I64.front()); + + auto &attributeU8 = + io.DefineAttribute<uint8_t>(u8_Single, currentTestData.U8.front()); + auto &attributeU16 = + io.DefineAttribute<uint16_t>(u16_Single, currentTestData.U16.front()); + auto &attributeU32 = + io.DefineAttribute<uint32_t>(u32_Single, currentTestData.U32.front()); + auto &attributeU64 = + io.DefineAttribute<uint64_t>(u64_Single, currentTestData.U64.front()); + + auto &attributeFloat = + io.DefineAttribute<float>(float_Single, currentTestData.R32.front()); + auto &attributeDouble = + io.DefineAttribute<double>(double_Single, currentTestData.R64.front()); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(attributeS1), + adios2::Attribute<std::string> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI8), + adios2::Attribute<int8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI16), + adios2::Attribute<int16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI32), + adios2::Attribute<int32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI64), + adios2::Attribute<int64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU8), + adios2::Attribute<uint8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU16), + adios2::Attribute<uint16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU32), + adios2::Attribute<uint32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU64), + adios2::Attribute<uint64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeFloat), + adios2::Attribute<float> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeDouble), + adios2::Attribute<double> &>(); + + // Verify the members are correct + ASSERT_EQ(attributeS1.m_IsSingleValue, true); + ASSERT_EQ(attributeS1.m_DataArray.empty(), true); + EXPECT_EQ(attributeS1.m_Name, s1_Single); + EXPECT_EQ(attributeS1.m_DataSingleValue, currentTestData.S1); + EXPECT_EQ(attributeS1.m_Elements, 1); + EXPECT_EQ(attributeS1.m_Type, "string"); + + ASSERT_EQ(attributeI8.m_IsSingleValue, true); + ASSERT_EQ(attributeI8.m_DataArray.empty(), true); + EXPECT_EQ(attributeI8.m_Name, i8_Single); + EXPECT_EQ(attributeI8.m_DataSingleValue, currentTestData.I8.front()); + EXPECT_EQ(attributeI8.m_Elements, 1); + EXPECT_EQ(attributeI8.m_Type, "signed char"); + + ASSERT_EQ(attributeI16.m_IsSingleValue, true); + ASSERT_EQ(attributeI16.m_DataArray.empty(), true); + EXPECT_EQ(attributeI16.m_Name, i16_Single); + EXPECT_EQ(attributeI16.m_DataSingleValue, currentTestData.I16.front()); + EXPECT_EQ(attributeI16.m_Elements, 1); + EXPECT_EQ(attributeI16.m_Type, "short"); + + ASSERT_EQ(attributeI32.m_IsSingleValue, true); + ASSERT_EQ(attributeI32.m_DataArray.empty(), true); + EXPECT_EQ(attributeI32.m_Name, i32_Single); + EXPECT_EQ(attributeI32.m_DataSingleValue, currentTestData.I32.front()); + EXPECT_EQ(attributeI32.m_Elements, 1); + EXPECT_EQ(attributeI32.m_Type, "int"); + + ASSERT_EQ(attributeI64.m_IsSingleValue, true); + ASSERT_EQ(attributeI64.m_DataArray.empty(), true); + EXPECT_EQ(attributeI64.m_Name, i64_Single); + EXPECT_EQ(attributeI64.m_DataSingleValue, currentTestData.I64.front()); + EXPECT_EQ(attributeI64.m_Elements, 1); + EXPECT_EQ(sizeof(attributeI64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeU8.m_IsSingleValue, true); + ASSERT_EQ(attributeU8.m_DataArray.empty(), true); + EXPECT_EQ(attributeU8.m_Name, u8_Single); + EXPECT_EQ(attributeU8.m_DataSingleValue, currentTestData.U8.front()); + EXPECT_EQ(attributeU8.m_Elements, 1); + EXPECT_EQ(attributeU8.m_Type, "unsigned char"); + + ASSERT_EQ(attributeU16.m_IsSingleValue, true); + ASSERT_EQ(attributeU16.m_DataArray.empty(), true); + EXPECT_EQ(attributeU16.m_Name, u16_Single); + EXPECT_EQ(attributeU16.m_DataSingleValue, currentTestData.U16.front()); + EXPECT_EQ(attributeU16.m_Elements, 1); + EXPECT_EQ(attributeU16.m_Type, "unsigned short"); + + ASSERT_EQ(attributeU32.m_IsSingleValue, true); + ASSERT_EQ(attributeU32.m_DataArray.empty(), true); + EXPECT_EQ(attributeU32.m_Name, u32_Single); + EXPECT_EQ(attributeU32.m_DataSingleValue, currentTestData.U32.front()); + EXPECT_EQ(attributeU32.m_Elements, 1); + EXPECT_EQ(attributeU32.m_Type, "unsigned int"); + + ASSERT_EQ(attributeU64.m_IsSingleValue, true); + ASSERT_EQ(attributeU64.m_DataArray.empty(), true); + EXPECT_EQ(attributeU64.m_Name, u64_Single); + EXPECT_EQ(attributeU64.m_DataSingleValue, currentTestData.U64.front()); + EXPECT_EQ(attributeU64.m_Elements, 1); + EXPECT_EQ(sizeof(attributeU64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeFloat.m_IsSingleValue, true); + ASSERT_EQ(attributeFloat.m_DataArray.empty(), true); + EXPECT_EQ(attributeFloat.m_Name, float_Single); + EXPECT_EQ(attributeFloat.m_DataSingleValue, currentTestData.R32.front()); + EXPECT_EQ(attributeFloat.m_Elements, 1); + EXPECT_EQ(attributeFloat.m_Type, "float"); + + ASSERT_EQ(attributeDouble.m_IsSingleValue, true); + ASSERT_EQ(attributeDouble.m_DataArray.empty(), true); + EXPECT_EQ(attributeDouble.m_Name, double_Single); + EXPECT_EQ(attributeDouble.m_DataSingleValue, currentTestData.R64.front()); + EXPECT_EQ(attributeDouble.m_Elements, 1); + EXPECT_EQ(attributeDouble.m_Type, "double"); +} + +TEST_F(ADIOSDefineAttributeTest, DefineAttributeTypeByReference) +{ + int mpiRank = 0, mpiSize = 1; + size_t numberOfElements = 10; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Define unique data for each process + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize); + + std::string mpiRankString = std::to_string(mpiRank); + std::string s3_Single = std::string("s3_Single_") + mpiRankString; + std::string i8_Single = std::string("i8_Single_") + mpiRankString; + std::string i16_Single = std::string("i16_Single_") + mpiRankString; + std::string i32_Single = std::string("i32_Single_") + mpiRankString; + std::string i64_Single = std::string("i64_Single_") + mpiRankString; + std::string u8_Single = std::string("u8_Single_") + mpiRankString; + std::string u16_Single = std::string("u16_Single_") + mpiRankString; + std::string u32_Single = std::string("u32_Single_") + mpiRankString; + std::string u64_Single = std::string("u64_Single_") + mpiRankString; + std::string float_Single = std::string("float_Single_") + mpiRankString; + std::string double_Single = std::string("double_Single_") + mpiRankString; + + // Define ADIOS global value + auto &attributeS3 = io.DefineAttribute<std::string>( + s3_Single, currentTestData.S3.data(), 3); + auto &attributeI8 = io.DefineAttribute<int8_t>( + i8_Single, currentTestData.I8.data(), numberOfElements); + auto &attributeI16 = io.DefineAttribute<int16_t>( + i16_Single, currentTestData.I16.data(), numberOfElements); + auto &attributeI32 = io.DefineAttribute<int32_t>( + i32_Single, currentTestData.I32.data(), numberOfElements); + auto &attributeI64 = io.DefineAttribute<int64_t>( + i64_Single, currentTestData.I64.data(), numberOfElements); + + auto &attributeU8 = io.DefineAttribute<uint8_t>( + u8_Single, currentTestData.U8.data(), numberOfElements); + auto &attributeU16 = io.DefineAttribute<uint16_t>( + u16_Single, currentTestData.U16.data(), numberOfElements); + auto &attributeU32 = io.DefineAttribute<uint32_t>( + u32_Single, currentTestData.U32.data(), numberOfElements); + auto &attributeU64 = io.DefineAttribute<uint64_t>( + u64_Single, currentTestData.U64.data(), numberOfElements); + + auto &attributeFloat = io.DefineAttribute<float>( + float_Single, currentTestData.R32.data(), numberOfElements); + auto &attributeDouble = io.DefineAttribute<double>( + double_Single, currentTestData.R64.data(), numberOfElements); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(attributeS3), + adios2::Attribute<std::string> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI8), + adios2::Attribute<int8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI16), + adios2::Attribute<int16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI32), + adios2::Attribute<int32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI64), + adios2::Attribute<int64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU8), + adios2::Attribute<uint8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU16), + adios2::Attribute<uint16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU32), + adios2::Attribute<uint32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU64), + adios2::Attribute<uint64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeFloat), + adios2::Attribute<float> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeDouble), + adios2::Attribute<double> &>(); + + // Verify the members are correct + ASSERT_EQ(attributeS3.m_IsSingleValue, false); + ASSERT_EQ(attributeS3.m_DataArray.empty(), false); + EXPECT_EQ(attributeS3.m_Name, s3_Single); + EXPECT_EQ(attributeS3.m_Elements, 3); + EXPECT_EQ(attributeS3.m_Type, "string"); + + ASSERT_EQ(attributeI8.m_IsSingleValue, false); + ASSERT_EQ(attributeI8.m_DataArray.empty(), false); + EXPECT_EQ(attributeI8.m_Name, i8_Single); + EXPECT_EQ(attributeI8.m_Elements, numberOfElements); + EXPECT_EQ(attributeI8.m_Type, "signed char"); + + ASSERT_EQ(attributeI16.m_IsSingleValue, false); + ASSERT_EQ(attributeI16.m_DataArray.empty(), false); + EXPECT_EQ(attributeI16.m_Name, i16_Single); + EXPECT_EQ(attributeI16.m_Elements, numberOfElements); + EXPECT_EQ(attributeI16.m_Type, "short"); + + ASSERT_EQ(attributeI32.m_IsSingleValue, false); + ASSERT_EQ(attributeI32.m_DataArray.empty(), false); + EXPECT_EQ(attributeI32.m_Name, i32_Single); + EXPECT_EQ(attributeI32.m_Elements, numberOfElements); + EXPECT_EQ(attributeI32.m_Type, "int"); + + ASSERT_EQ(attributeI64.m_IsSingleValue, false); + ASSERT_EQ(attributeI64.m_DataArray.empty(), false); + EXPECT_EQ(attributeI64.m_Name, i64_Single); + EXPECT_EQ(attributeI64.m_Elements, numberOfElements); + EXPECT_EQ(sizeof(attributeI64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeU8.m_IsSingleValue, false); + ASSERT_EQ(attributeU8.m_DataArray.empty(), false); + EXPECT_EQ(attributeU8.m_Name, u8_Single); + EXPECT_EQ(attributeU8.m_Elements, numberOfElements); + EXPECT_EQ(attributeU8.m_Type, "unsigned char"); + + ASSERT_EQ(attributeU16.m_IsSingleValue, false); + ASSERT_EQ(attributeU16.m_DataArray.empty(), false); + EXPECT_EQ(attributeU16.m_Name, u16_Single); + EXPECT_EQ(attributeU16.m_Elements, numberOfElements); + EXPECT_EQ(attributeU16.m_Type, "unsigned short"); + + ASSERT_EQ(attributeU32.m_IsSingleValue, false); + ASSERT_EQ(attributeU32.m_DataArray.empty(), false); + EXPECT_EQ(attributeU32.m_Name, u32_Single); + EXPECT_EQ(attributeU32.m_Elements, numberOfElements); + EXPECT_EQ(attributeU32.m_Type, "unsigned int"); + + ASSERT_EQ(attributeU64.m_IsSingleValue, false); + ASSERT_EQ(attributeU64.m_DataArray.empty(), false); + EXPECT_EQ(attributeU64.m_Name, u64_Single); + EXPECT_EQ(attributeU64.m_Elements, numberOfElements); + EXPECT_EQ(sizeof(attributeU64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeFloat.m_IsSingleValue, false); + ASSERT_EQ(attributeFloat.m_DataArray.empty(), false); + EXPECT_EQ(attributeFloat.m_Name, float_Single); + EXPECT_EQ(attributeFloat.m_Elements, numberOfElements); + EXPECT_EQ(attributeFloat.m_Type, "float"); + + ASSERT_EQ(attributeDouble.m_IsSingleValue, false); + ASSERT_EQ(attributeDouble.m_DataArray.empty(), false); + EXPECT_EQ(attributeDouble.m_Name, double_Single); + EXPECT_EQ(attributeDouble.m_Elements, numberOfElements); + EXPECT_EQ(attributeDouble.m_Type, "double"); + + // Verify data + for (size_t index = 0; index < numberOfElements; index++) + { + EXPECT_EQ(attributeI8.m_DataArray[index], currentTestData.I8.at(index)); + EXPECT_EQ(attributeI16.m_DataArray[index], + currentTestData.I16.at(index)); + EXPECT_EQ(attributeI32.m_DataArray[index], + currentTestData.I32.at(index)); + EXPECT_EQ(attributeU8.m_DataArray[index], currentTestData.U8.at(index)); + EXPECT_EQ(attributeU16.m_DataArray[index], + currentTestData.U16.at(index)); + EXPECT_EQ(attributeU32.m_DataArray[index], + currentTestData.U32.at(index)); + EXPECT_EQ(attributeFloat.m_DataArray[index], + currentTestData.R32.at(index)); + EXPECT_EQ(attributeDouble.m_DataArray[index], + currentTestData.R64.at(index)); + } +} + +TEST_F(ADIOSDefineAttributeTest, GetAttribute) +{ + int mpiRank = 0, mpiSize = 1; + size_t numberOfElements = 10; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + + // Define unique data for each process + SmallTestData currentTestData = + generateNewSmallTestData(m_TestData, 0, mpiRank, mpiSize); + + std::string mpiRankString = std::to_string(mpiRank); + std::string s3_Single = std::string("s3_Array_") + mpiRankString; + std::string i8_Single = std::string("i8_Array_") + mpiRankString; + std::string i16_Single = std::string("i16_Array_") + mpiRankString; + std::string i32_Single = std::string("i32_Array_") + mpiRankString; + std::string i64_Single = std::string("i64_Array_") + mpiRankString; + std::string u8_Single = std::string("u8_Array_") + mpiRankString; + std::string u16_Single = std::string("u16_Array_") + mpiRankString; + std::string u32_Single = std::string("u32_Array_") + mpiRankString; + std::string u64_Single = std::string("u64_Array_") + mpiRankString; + std::string float_Single = std::string("float_Array_") + mpiRankString; + std::string double_Single = std::string("double_Array_") + mpiRankString; + + // Define ADIOS global value + { + io.DefineAttribute<std::string>(s3_Single, currentTestData.S3.data(), + 3); + io.DefineAttribute<int8_t>(i8_Single, currentTestData.I8.data(), + numberOfElements); + io.DefineAttribute<int16_t>(i16_Single, currentTestData.I16.data(), + numberOfElements); + io.DefineAttribute<int32_t>(i32_Single, currentTestData.I32.data(), + numberOfElements); + io.DefineAttribute<int64_t>(i64_Single, currentTestData.I64.data(), + numberOfElements); + io.DefineAttribute<uint8_t>(u8_Single, currentTestData.U8.data(), + numberOfElements); + io.DefineAttribute<uint16_t>(u16_Single, currentTestData.U16.data(), + numberOfElements); + io.DefineAttribute<uint32_t>(u32_Single, currentTestData.U32.data(), + numberOfElements); + io.DefineAttribute<uint64_t>(u64_Single, currentTestData.U64.data(), + numberOfElements); + io.DefineAttribute<float>(float_Single, currentTestData.R32.data(), + numberOfElements); + io.DefineAttribute<double>(double_Single, currentTestData.R64.data(), + numberOfElements); + } + + auto &attributeS3 = io.GetAttribute<std::string>(s3_Single); + auto &attributeI8 = io.GetAttribute<int8_t>(i8_Single); + auto &attributeI16 = io.GetAttribute<int16_t>(i16_Single); + auto &attributeI32 = io.GetAttribute<int32_t>(i32_Single); + auto &attributeI64 = io.GetAttribute<int64_t>(i64_Single); + auto &attributeU8 = io.GetAttribute<uint8_t>(i8_Single); + auto &attributeU16 = io.GetAttribute<uint16_t>(i16_Single); + auto &attributeU32 = io.GetAttribute<uint32_t>(i32_Single); + auto &attributeU64 = io.GetAttribute<uint64_t>(i64_Single); + auto &attributeFloat = io.GetAttribute<float>(float_Single); + auto &attributeDouble = io.GetAttribute<double>(double_Single); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(attributeS3), + adios2::Attribute<std::string> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI8), + adios2::Attribute<int8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI16), + adios2::Attribute<int16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI32), + adios2::Attribute<int32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeI64), + adios2::Attribute<int64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU8), + adios2::Attribute<uint8_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU16), + adios2::Attribute<uint16_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU32), + adios2::Attribute<uint32_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeU64), + adios2::Attribute<uint64_t> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeFloat), + adios2::Attribute<float> &>(); + ::testing::StaticAssertTypeEq<decltype(attributeDouble), + adios2::Attribute<double> &>(); + + // Verify the members are correct + ASSERT_EQ(attributeS3.m_IsSingleValue, false); + ASSERT_EQ(attributeS3.m_DataArray.empty(), false); + EXPECT_EQ(attributeS3.m_Name, s3_Single); + EXPECT_EQ(attributeS3.m_Elements, 3); + EXPECT_EQ(attributeS3.m_Type, "string"); + + ASSERT_EQ(attributeI8.m_IsSingleValue, false); + ASSERT_EQ(attributeI8.m_DataArray.empty(), false); + EXPECT_EQ(attributeI8.m_Name, i8_Single); + EXPECT_EQ(attributeI8.m_Elements, numberOfElements); + EXPECT_EQ(attributeI8.m_Type, "signed char"); + + ASSERT_EQ(attributeI16.m_IsSingleValue, false); + ASSERT_EQ(attributeI16.m_DataArray.empty(), false); + EXPECT_EQ(attributeI16.m_Name, i16_Single); + EXPECT_EQ(attributeI16.m_Elements, numberOfElements); + EXPECT_EQ(attributeI16.m_Type, "short"); + + ASSERT_EQ(attributeI32.m_IsSingleValue, false); + ASSERT_EQ(attributeI32.m_DataArray.empty(), false); + EXPECT_EQ(attributeI32.m_Name, i32_Single); + EXPECT_EQ(attributeI32.m_Elements, numberOfElements); + EXPECT_EQ(attributeI32.m_Type, "int"); + + ASSERT_EQ(attributeI64.m_IsSingleValue, false); + ASSERT_EQ(attributeI64.m_DataArray.empty(), false); + EXPECT_EQ(attributeI64.m_Name, i64_Single); + EXPECT_EQ(attributeI64.m_Elements, numberOfElements); + EXPECT_EQ(sizeof(attributeI64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeU8.m_IsSingleValue, false); + ASSERT_EQ(attributeU8.m_DataArray.empty(), false); + EXPECT_EQ(attributeU8.m_Name, u8_Single); + EXPECT_EQ(attributeU8.m_Elements, numberOfElements); + EXPECT_EQ(attributeU8.m_Type, "unsigned char"); + + ASSERT_EQ(attributeU16.m_IsSingleValue, false); + ASSERT_EQ(attributeU16.m_DataArray.empty(), false); + EXPECT_EQ(attributeU16.m_Name, u16_Single); + EXPECT_EQ(attributeU16.m_Elements, numberOfElements); + EXPECT_EQ(attributeU16.m_Type, "unsigned short"); + + ASSERT_EQ(attributeU32.m_IsSingleValue, false); + ASSERT_EQ(attributeU32.m_DataArray.empty(), false); + EXPECT_EQ(attributeU32.m_Name, u32_Single); + EXPECT_EQ(attributeU32.m_Elements, numberOfElements); + EXPECT_EQ(attributeU32.m_Type, "unsigned int"); + + ASSERT_EQ(attributeU64.m_IsSingleValue, false); + ASSERT_EQ(attributeU64.m_DataArray.empty(), false); + EXPECT_EQ(attributeU64.m_Name, u64_Single); + EXPECT_EQ(attributeU64.m_Elements, numberOfElements); + EXPECT_EQ(sizeof(attributeU64.m_DataSingleValue), 8); + + ASSERT_EQ(attributeFloat.m_IsSingleValue, false); + ASSERT_EQ(attributeFloat.m_DataArray.empty(), false); + EXPECT_EQ(attributeFloat.m_Name, float_Single); + EXPECT_EQ(attributeFloat.m_Elements, numberOfElements); + EXPECT_EQ(attributeFloat.m_Type, "float"); + + ASSERT_EQ(attributeDouble.m_IsSingleValue, false); + ASSERT_EQ(attributeDouble.m_DataArray.empty(), false); + EXPECT_EQ(attributeDouble.m_Name, double_Single); + EXPECT_EQ(attributeDouble.m_Elements, numberOfElements); + EXPECT_EQ(attributeDouble.m_Type, "double"); + + // Verify data + for (size_t index = 0; index < numberOfElements; index++) + { + EXPECT_EQ(attributeI8.m_DataArray[index], currentTestData.I8.at(index)); + EXPECT_EQ(attributeI16.m_DataArray[index], + currentTestData.I16.at(index)); + EXPECT_EQ(attributeI32.m_DataArray[index], + currentTestData.I32.at(index)); + EXPECT_EQ(attributeU8.m_DataArray[index], currentTestData.U8.at(index)); + EXPECT_EQ(attributeU16.m_DataArray[index], + currentTestData.U16.at(index)); + EXPECT_EQ(attributeU32.m_DataArray[index], + currentTestData.U32.at(index)); + EXPECT_EQ(attributeFloat.m_DataArray[index], + currentTestData.R32.at(index)); + EXPECT_EQ(attributeDouble.m_DataArray[index], + currentTestData.R64.at(index)); + } +} + +int main(int argc, char **argv) +{ +#ifdef ADIOS2_HAVE_MPI + MPI_Init(nullptr, nullptr); +#endif + + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + +#ifdef ADIOS2_HAVE_MPI + MPI_Finalize(); +#endif + + return result; +} diff --git a/testing/adios2/interface/TestADIOSDefineVariable.cpp b/testing/adios2/interface/TestADIOSDefineVariable.cpp index 100f05fc4e7df69a6512a749cf7b3cf1eb705260..e46c826d295680b4f809ae346ef0d644d4d68c42 100644 --- a/testing/adios2/interface/TestADIOSDefineVariable.cpp +++ b/testing/adios2/interface/TestADIOSDefineVariable.cpp @@ -23,8 +23,15 @@ protected: TEST_F(ADIOSDefineVariableTest, DefineGlobalValue) { + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("globalValue"); + // Define ADIOS global value - auto &globalvalue = io.DefineVariable<int>("globalvalue"); + auto &globalvalue = io.DefineVariable<int>(name); // Verify the return type is as expected ::testing::StaticAssertTypeEq<decltype(globalvalue), @@ -34,7 +41,7 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalValue) ASSERT_EQ(globalvalue.m_Shape.size(), 0); EXPECT_EQ(globalvalue.m_Start.size(), 0); EXPECT_EQ(globalvalue.m_Count.size(), 0); - EXPECT_EQ(globalvalue.m_Name, "globalvalue"); + EXPECT_EQ(globalvalue.m_Name, name); EXPECT_EQ(globalvalue.m_Type, "int"); } @@ -59,10 +66,25 @@ TEST_F(ADIOSDefineVariableTest, DefineLocalValue) TEST_F(ADIOSDefineVariableTest, DefineGlobalArray) { + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + const std::size_t Nx(10), Ny(20), Nz(30); + + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize), + static_cast<unsigned int>(Ny * mpiSize), + static_cast<unsigned int>(Nz * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank), + static_cast<unsigned int>(Ny * mpiRank), + static_cast<unsigned int>(Nz * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx), + static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nz)}; // Define ADIOS global array - std::size_t n = 50; - auto &globalarray = io.DefineVariable<int>("globalarray", {100, n, 30}, - {50, n / 2, 0}, {10, n / 2, 30}); + auto &globalarray = + io.DefineVariable<int>("globalarray", shape, start, count); // Verify the return type is as expected ::testing::StaticAssertTypeEq<decltype(globalarray), @@ -70,17 +92,17 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArray) // Verify the dimensions, name, and type are correct ASSERT_EQ(globalarray.m_Shape.size(), 3); - EXPECT_EQ(globalarray.m_Shape[0], 100); - EXPECT_EQ(globalarray.m_Shape[1], n); - EXPECT_EQ(globalarray.m_Shape[2], 30); + EXPECT_EQ(globalarray.m_Shape[0], Nx * mpiSize); + EXPECT_EQ(globalarray.m_Shape[1], Ny * mpiSize); + EXPECT_EQ(globalarray.m_Shape[2], Nz * mpiSize); EXPECT_EQ(globalarray.m_Start.size(), 3); - EXPECT_EQ(globalarray.m_Start[0], 50); - EXPECT_EQ(globalarray.m_Start[1], n / 2); - EXPECT_EQ(globalarray.m_Start[2], 0); + EXPECT_EQ(globalarray.m_Start[0], Nx * mpiRank); + EXPECT_EQ(globalarray.m_Start[1], Ny * mpiRank); + EXPECT_EQ(globalarray.m_Start[2], Nz * mpiRank); EXPECT_EQ(globalarray.m_Count.size(), 3); - EXPECT_EQ(globalarray.m_Count[0], 10); - EXPECT_EQ(globalarray.m_Count[1], n / 2); - EXPECT_EQ(globalarray.m_Count[2], 30); + EXPECT_EQ(globalarray.m_Count[0], Nx); + EXPECT_EQ(globalarray.m_Count[1], Ny); + EXPECT_EQ(globalarray.m_Count[2], Nz); EXPECT_EQ(globalarray.m_Name, "globalarray"); EXPECT_EQ(globalarray.m_Type, "int"); } @@ -88,8 +110,25 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArray) TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayWithSelections) { // Define ADIOS global array with postponed size definition in SetSelection - std::size_t n = 50; - auto &globalarray = io.DefineVariable<int>("globalarray", {100, n, 30}); + + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + const std::size_t Nx(10), Ny(20), Nz(30); + + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize), + static_cast<unsigned int>(Ny * mpiSize), + static_cast<unsigned int>(Nz * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank), + static_cast<unsigned int>(Ny * mpiRank), + static_cast<unsigned int>(Nz * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx), + static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nz)}; + // Define ADIOS global array + auto &globalarray = io.DefineVariable<int>("globalarray", shape); // Verify the return type is as expected ::testing::StaticAssertTypeEq<decltype(globalarray), @@ -97,22 +136,22 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayWithSelections) // Make a 3D selection to describe the local dimensions of the // variable we write and its offsets in the global spaces - adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30}); + adios2::SelectionBoundingBox sel(start, count); globalarray.SetSelection(sel); // Verify the dimensions, name, and type are correct ASSERT_EQ(globalarray.m_Shape.size(), 3); - EXPECT_EQ(globalarray.m_Shape[0], 100); - EXPECT_EQ(globalarray.m_Shape[1], n); - EXPECT_EQ(globalarray.m_Shape[2], 30); + EXPECT_EQ(globalarray.m_Shape[0], Nx * mpiSize); + EXPECT_EQ(globalarray.m_Shape[1], Ny * mpiSize); + EXPECT_EQ(globalarray.m_Shape[2], Nz * mpiSize); EXPECT_EQ(globalarray.m_Start.size(), 3); - EXPECT_EQ(globalarray.m_Start[0], 50); - EXPECT_EQ(globalarray.m_Start[1], n / 2); - EXPECT_EQ(globalarray.m_Start[2], 0); + EXPECT_EQ(globalarray.m_Start[0], Nx * mpiRank); + EXPECT_EQ(globalarray.m_Start[1], Ny * mpiRank); + EXPECT_EQ(globalarray.m_Start[2], Nz * mpiRank); EXPECT_EQ(globalarray.m_Count.size(), 3); - EXPECT_EQ(globalarray.m_Count[0], 10); - EXPECT_EQ(globalarray.m_Count[1], n / 2); - EXPECT_EQ(globalarray.m_Count[2], 30); + EXPECT_EQ(globalarray.m_Count[0], Nx); + EXPECT_EQ(globalarray.m_Count[1], Ny); + EXPECT_EQ(globalarray.m_Count[2], Nz); EXPECT_EQ(globalarray.m_Name, "globalarray"); EXPECT_EQ(globalarray.m_Type, "int"); } @@ -120,30 +159,48 @@ TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayWithSelections) TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayConstantDims) { // Define ADIOS global array with locked-down dimensions - std::size_t n = 50; - auto &globalarray = io.DefineVariable<int>( - "globalarray", {100, n, 30}, {50, n / 2, 0}, {10, n / 2, 30}, true); + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + const std::size_t Nx(10), Ny(20), Nz(30); + + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize), + static_cast<unsigned int>(Ny * mpiSize), + static_cast<unsigned int>(Nz * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank), + static_cast<unsigned int>(Ny * mpiRank), + static_cast<unsigned int>(Nz * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx), + static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nz)}; + // Define ADIOS global array + auto &globalarray = + io.DefineVariable<int>("globalarray", shape, start, count, true); // Verify the return type is as expected ::testing::StaticAssertTypeEq<decltype(globalarray), adios2::Variable<int> &>(); - adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30}); + // Make a 3D selection to describe the local dimensions of the + // variable we write and its offsets in the global spaces + adios2::SelectionBoundingBox sel(start, count); EXPECT_THROW(globalarray.SetSelection(sel), std::invalid_argument); // Verify the dimensions, name, and type are correct ASSERT_EQ(globalarray.m_Shape.size(), 3); - EXPECT_EQ(globalarray.m_Shape[0], 100); - EXPECT_EQ(globalarray.m_Shape[1], n); - EXPECT_EQ(globalarray.m_Shape[2], 30); + EXPECT_EQ(globalarray.m_Shape[0], Nx * mpiSize); + EXPECT_EQ(globalarray.m_Shape[1], Ny * mpiSize); + EXPECT_EQ(globalarray.m_Shape[2], Nz * mpiSize); EXPECT_EQ(globalarray.m_Start.size(), 3); - EXPECT_EQ(globalarray.m_Start[0], 50); - EXPECT_EQ(globalarray.m_Start[1], n / 2); - EXPECT_EQ(globalarray.m_Start[2], 0); + EXPECT_EQ(globalarray.m_Start[0], Nx * mpiRank); + EXPECT_EQ(globalarray.m_Start[1], Ny * mpiRank); + EXPECT_EQ(globalarray.m_Start[2], Nz * mpiRank); EXPECT_EQ(globalarray.m_Count.size(), 3); - EXPECT_EQ(globalarray.m_Count[0], 10); - EXPECT_EQ(globalarray.m_Count[1], n / 2); - EXPECT_EQ(globalarray.m_Count[2], 30); + EXPECT_EQ(globalarray.m_Count[0], Nx); + EXPECT_EQ(globalarray.m_Count[1], Ny); + EXPECT_EQ(globalarray.m_Count[2], Nz); EXPECT_EQ(globalarray.m_Name, "globalarray"); EXPECT_EQ(globalarray.m_Type, "int"); } @@ -184,70 +241,92 @@ TEST_F(ADIOSDefineVariableTest, DefineLocalArray) TEST_F(ADIOSDefineVariableTest, DefineLocalArrayWithSelection) { - // Define ADIOS local array with postponed size definition in SetSelection - std::size_t n = 50; - auto &localarray = io.DefineVariable<int>( - "localarray", {}, {}, + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + const std::size_t Nx(10), Ny(20), Nz(30); + + adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize), + static_cast<unsigned int>(Ny * mpiSize), + static_cast<unsigned int>(Nz * mpiSize)}; + adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank), + static_cast<unsigned int>(Ny * mpiRank), + static_cast<unsigned int>(Nz * mpiRank)}; + adios2::Dims count{static_cast<unsigned int>(Nx), + static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nz)}; + // Define ADIOS global array + auto &localArray = io.DefineVariable<int>( + "localArray", {}, {}, {adios2::UnknownDim, adios2::UnknownDim, adios2::UnknownDim}); // Verify the return type is as expected - ::testing::StaticAssertTypeEq<decltype(localarray), + ::testing::StaticAssertTypeEq<decltype(localArray), adios2::Variable<int> &>(); - - ASSERT_EQ(localarray.m_Shape.size(), 0); - EXPECT_EQ(localarray.m_Start.size(), 0); - EXPECT_EQ(localarray.m_Count.size(), 3); - EXPECT_EQ(localarray.m_Count[0], 0); - EXPECT_EQ(localarray.m_Count[1], 0); - EXPECT_EQ(localarray.m_Count[2], 0); - EXPECT_EQ(localarray.m_Name, "localarray"); - EXPECT_EQ(localarray.m_Type, "int"); - EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray); + ASSERT_EQ(localArray.m_Shape.size(), 0); + EXPECT_EQ(localArray.m_Start.size(), 0); + EXPECT_EQ(localArray.m_Count.size(), 3); + EXPECT_EQ(localArray.m_Count[0], 0); + EXPECT_EQ(localArray.m_Count[1], 0); + EXPECT_EQ(localArray.m_Count[2], 0); + EXPECT_EQ(localArray.m_Name, "localArray"); + EXPECT_EQ(localArray.m_Type, "int"); + EXPECT_EQ(localArray.m_ShapeID, adios2::ShapeID::LocalArray); // Make a 3D selection to describe the local dimensions of the // variable we write - adios2::SelectionBoundingBox sel({}, {10, n / 2, 30}); - localarray.SetSelection(sel); + adios2::SelectionBoundingBox sel({}, {Nx, Ny, Nz}); + localArray.SetSelection(sel); - adios2::SelectionBoundingBox selbad({50, n / 2, 0}, {10, n / 2, 30}); - EXPECT_THROW(localarray.SetSelection(selbad), std::invalid_argument); + adios2::SelectionBoundingBox selbad(start, count); + EXPECT_THROW(localArray.SetSelection(selbad), std::invalid_argument); // Verify the dimensions, name, and type are correct - ASSERT_EQ(localarray.m_Shape.size(), 0); - EXPECT_EQ(localarray.m_Start.size(), 0); - EXPECT_EQ(localarray.m_Count.size(), 3); - EXPECT_EQ(localarray.m_Count[0], 10); - EXPECT_EQ(localarray.m_Count[1], n / 2); - EXPECT_EQ(localarray.m_Count[2], 30); - EXPECT_EQ(localarray.m_Name, "localarray"); - EXPECT_EQ(localarray.m_Type, "int"); - EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray); + ASSERT_EQ(localArray.m_Shape.size(), 0); + EXPECT_EQ(localArray.m_Start.size(), 0); + EXPECT_EQ(localArray.m_Count.size(), 3); + EXPECT_EQ(localArray.m_Count[0], Nx); + EXPECT_EQ(localArray.m_Count[1], Ny); + EXPECT_EQ(localArray.m_Count[2], Nz); + EXPECT_EQ(localArray.m_Name, "localArray"); + EXPECT_EQ(localArray.m_Type, "int"); + EXPECT_EQ(localArray.m_ShapeID, adios2::ShapeID::LocalArray); } TEST_F(ADIOSDefineVariableTest, DefineLocalArrayConstantDims) { - // Define ADIOS local array with locked down dimensions - std::size_t n = 50; - auto &localarray = - io.DefineVariable<int>("localarray", {}, {}, {10, n / 2, 30}, true); + int mpiRank = 0, mpiSize = 1; +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + const std::size_t Nx(10), Ny(20), Nz(30); + + adios2::Dims count{static_cast<unsigned int>(Nx), + static_cast<unsigned int>(Ny), + static_cast<unsigned int>(Nz)}; + // Define ADIOS global array + auto &localArray = + io.DefineVariable<int>("localArray", {}, {}, count, true); // Verify the return type is as expected - ::testing::StaticAssertTypeEq<decltype(localarray), + ::testing::StaticAssertTypeEq<decltype(localArray), adios2::Variable<int> &>(); - adios2::SelectionBoundingBox sel({}, {10, n / 2, 30}); - EXPECT_THROW(localarray.SetSelection(sel), std::invalid_argument); - - // Verify the dimensions, name, and type are correct - ASSERT_EQ(localarray.m_Shape.size(), 0); - EXPECT_EQ(localarray.m_Start.size(), 0); - EXPECT_EQ(localarray.m_Count.size(), 3); - EXPECT_EQ(localarray.m_Count[0], 10); - EXPECT_EQ(localarray.m_Count[1], n / 2); - EXPECT_EQ(localarray.m_Count[2], 30); - EXPECT_EQ(localarray.m_Name, "localarray"); - EXPECT_EQ(localarray.m_Type, "int"); - EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray); + adios2::SelectionBoundingBox sel({}, count); + EXPECT_THROW(localArray.SetSelection(sel), std::invalid_argument); + + ASSERT_EQ(localArray.m_Shape.size(), 0); + EXPECT_EQ(localArray.m_Start.size(), 0); + EXPECT_EQ(localArray.m_Count.size(), 3); + EXPECT_EQ(localArray.m_Count[0], Nx); + EXPECT_EQ(localArray.m_Count[1], Ny); + EXPECT_EQ(localArray.m_Count[2], Nz); + EXPECT_EQ(localArray.m_Name, "localArray"); + EXPECT_EQ(localArray.m_Type, "int"); + EXPECT_EQ(localArray.m_ShapeID, adios2::ShapeID::LocalArray); } TEST_F(ADIOSDefineVariableTest, DefineLocalArrayInvalidOffsets) diff --git a/testing/adios2/interface/TestADIOSInterfaceWrite.cpp b/testing/adios2/interface/TestADIOSInterfaceWrite.cpp index 03f3132640587da5b8912fa3ff92060cb9c65e0d..ff5513afe6235ae2907ed947101dc804deae8f45 100644 --- a/testing/adios2/interface/TestADIOSInterfaceWrite.cpp +++ b/testing/adios2/interface/TestADIOSInterfaceWrite.cpp @@ -21,347 +21,544 @@ protected: adios2::IO &io; }; -TEST_F(ADIOSInterfaceWriteTest, DefineVarChar1x10) +// 1x10 +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int8_t_1x10) { + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i8_") + std::to_string(mpiRank); + // Define ADIOS variables for each type - auto &var_i8 = io.DefineVariable<char>("i8", {}, {}, adios2::Dims{10}); + + auto &var_int8_t = + io.DefineVariable<int8_t>(name, {}, {}, adios2::Dims{10}); // Verify the return type is as expected - ::testing::StaticAssertTypeEq<decltype(var_i8), adios2::Variable<char> &>(); + ::testing::StaticAssertTypeEq<decltype(var_int8_t), + adios2::Variable<int8_t> &>(); // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW(auto &foo = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{10}), + io.DefineVariable<int8_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); // Verify the dimensions, name, and type are correct - ASSERT_EQ(var_i8.m_Shape.size(), 0); - EXPECT_EQ(var_i8.m_Start.size(), 0); - EXPECT_EQ(var_i8.m_Count.size(), 1); - EXPECT_EQ(var_i8.m_Count[0], 10); - EXPECT_EQ(var_i8.m_Name, "i8"); - EXPECT_EQ(var_i8.m_Type, "char"); + ASSERT_EQ(var_int8_t.m_Shape.size(), 0); + EXPECT_EQ(var_int8_t.m_Start.size(), 0); + EXPECT_EQ(var_int8_t.m_Count.size(), 1); + EXPECT_EQ(var_int8_t.m_Count[0], 10); + EXPECT_EQ(var_int8_t.m_Name, name); + EXPECT_EQ(var_int8_t.m_Type, "signed char"); } -// Rinse and repeat for remaining types -TEST_F(ADIOSInterfaceWriteTest, DefineVarShort1x10) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int16_t_1x10) { - auto &var_i16 = io.DefineVariable<short>("i16", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_i16), - adios2::Variable<short> &>(); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i16_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int16_t = + io.DefineVariable<int16_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int16_t), + adios2::Variable<int16_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW(auto &foo = - io.DefineVariable<short>("i16", {}, {}, adios2::Dims{10}), + io.DefineVariable<int16_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); - ASSERT_EQ(var_i16.m_Shape.size(), 0); - EXPECT_EQ(var_i16.m_Start.size(), 0); - EXPECT_EQ(var_i16.m_Count.size(), 1); - EXPECT_EQ(var_i16.m_Count[0], 10); - EXPECT_EQ(var_i16.m_Name, "i16"); - EXPECT_EQ(var_i16.m_Type, "short"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int16_t.m_Shape.size(), 0); + EXPECT_EQ(var_int16_t.m_Start.size(), 0); + EXPECT_EQ(var_int16_t.m_Count.size(), 1); + EXPECT_EQ(var_int16_t.m_Count[0], 10); + EXPECT_EQ(var_int16_t.m_Name, name); + EXPECT_EQ(var_int16_t.m_Type, "short"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarInt1x10) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int32_t_1x10) { - auto &var_i32 = io.DefineVariable<int>("i32", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_i32), adios2::Variable<int> &>(); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i32_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int32_t = + io.DefineVariable<int32_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int32_t), + adios2::Variable<int32_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW(auto &foo = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{10}), + io.DefineVariable<int32_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); - ASSERT_EQ(var_i32.m_Shape.size(), 0); - EXPECT_EQ(var_i32.m_Start.size(), 0); - EXPECT_EQ(var_i32.m_Count.size(), 1); - EXPECT_EQ(var_i32.m_Count[0], 10); - EXPECT_EQ(var_i32.m_Name, "i32"); - EXPECT_EQ(var_i32.m_Type, "int"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int32_t.m_Shape.size(), 0); + EXPECT_EQ(var_int32_t.m_Start.size(), 0); + EXPECT_EQ(var_int32_t.m_Count.size(), 1); + EXPECT_EQ(var_int32_t.m_Count[0], 10); + EXPECT_EQ(var_int32_t.m_Name, name); + EXPECT_EQ(var_int32_t.m_Type, "int"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarLong1x10) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int64_t_1x10) { - auto &var_u16 = io.DefineVariable<long>("u16", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_u16), - adios2::Variable<long> &>(); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i64_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int64_t = + io.DefineVariable<int64_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int64_t), + adios2::Variable<int64_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW(auto &foo = - io.DefineVariable<long>("u16", {}, {}, adios2::Dims{10}), + io.DefineVariable<int64_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); - ASSERT_EQ(var_u16.m_Shape.size(), 0); - EXPECT_EQ(var_u16.m_Start.size(), 0); - EXPECT_EQ(var_u16.m_Count.size(), 1); - EXPECT_EQ(var_u16.m_Count[0], 10); - EXPECT_EQ(var_u16.m_Name, "u16"); - EXPECT_EQ(var_u16.m_Type, "long int"); -} -TEST_F(ADIOSInterfaceWriteTest, DefineVarUChar1x10) -{ - auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_u8), - adios2::Variable<unsigned char> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned char>("u8", {}, {}, - adios2::Dims{10}), - std::invalid_argument); - ASSERT_EQ(var_u8.m_Shape.size(), 0); - EXPECT_EQ(var_u8.m_Start.size(), 0); - EXPECT_EQ(var_u8.m_Count.size(), 1); - EXPECT_EQ(var_u8.m_Count[0], 10); - EXPECT_EQ(var_u8.m_Name, "u8"); - EXPECT_EQ(var_u8.m_Type, "unsigned char"); + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int64_t.m_Shape.size(), 0); + EXPECT_EQ(var_int64_t.m_Start.size(), 0); + EXPECT_EQ(var_int64_t.m_Count.size(), 1); + EXPECT_EQ(var_int64_t.m_Count[0], 10); + EXPECT_EQ(var_int64_t.m_Name, name); + EXPECT_EQ(var_int64_t.m_ElementSize, 8); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarUShort1x10) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint8_t_1x10) { - auto &var_u16 = - io.DefineVariable<unsigned short>("u16", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_u16), - adios2::Variable<unsigned short> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{10}), - std::invalid_argument); - ASSERT_EQ(var_u16.m_Shape.size(), 0); - EXPECT_EQ(var_u16.m_Start.size(), 0); - EXPECT_EQ(var_u16.m_Count.size(), 1); - EXPECT_EQ(var_u16.m_Count[0], 10); - EXPECT_EQ(var_u16.m_Name, "u16"); - EXPECT_EQ(var_u16.m_Type, "unsigned short"); -} + int mpiRank = 0, mpiSize = 1; -TEST_F(ADIOSInterfaceWriteTest, DefineVarUInt1x10) -{ - auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_u32), - adios2::Variable<unsigned int> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned int>("u32", {}, {}, - adios2::Dims{10}), - std::invalid_argument); - ASSERT_EQ(var_u32.m_Shape.size(), 0); - EXPECT_EQ(var_u32.m_Start.size(), 0); - EXPECT_EQ(var_u32.m_Count.size(), 1); - EXPECT_EQ(var_u32.m_Count[0], 10); - EXPECT_EQ(var_u32.m_Name, "u32"); - EXPECT_EQ(var_u32.m_Type, "unsigned int"); -} +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u8_") + std::to_string(mpiRank); -TEST_F(ADIOSInterfaceWriteTest, DefineVarULong1x10) -{ - auto &var_u64 = - io.DefineVariable<unsigned long>("u64", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_u64), - adios2::Variable<unsigned long> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned long>("u64", {}, {}, - adios2::Dims{10}), - std::invalid_argument); - ASSERT_EQ(var_u64.m_Shape.size(), 0); - EXPECT_EQ(var_u64.m_Start.size(), 0); - EXPECT_EQ(var_u64.m_Count.size(), 1); - EXPECT_EQ(var_u64.m_Count[0], 10); - EXPECT_EQ(var_u64.m_Name, "u64"); - EXPECT_EQ(var_u64.m_Type, "unsigned long int"); -} + // Define ADIOS variables for each type -TEST_F(ADIOSInterfaceWriteTest, DefineVarFloat1x10) -{ - auto &var_r32 = io.DefineVariable<float>("r32", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_r32), - adios2::Variable<float> &>(); + auto &var_uint8_t = + io.DefineVariable<uint8_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint8_t), + adios2::Variable<uint8_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW(auto &foo = - io.DefineVariable<float>("r32", {}, {}, adios2::Dims{10}), + io.DefineVariable<uint8_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); - ASSERT_EQ(var_r32.m_Shape.size(), 0); - EXPECT_EQ(var_r32.m_Start.size(), 0); - EXPECT_EQ(var_r32.m_Count.size(), 1); - EXPECT_EQ(var_r32.m_Count[0], 10); - EXPECT_EQ(var_r32.m_Name, "r32"); - EXPECT_EQ(var_r32.m_Type, "float"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint8_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint8_t.m_Start.size(), 0); + EXPECT_EQ(var_uint8_t.m_Count.size(), 1); + EXPECT_EQ(var_uint8_t.m_Count[0], 10); + EXPECT_EQ(var_uint8_t.m_Name, name); + EXPECT_EQ(var_uint8_t.m_Type, "unsigned char"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarDouble1x10) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint16_t_1x10) { - auto &var_r64 = io.DefineVariable<double>("r64", {}, {}, adios2::Dims{10}); - ::testing::StaticAssertTypeEq<decltype(var_r64), - adios2::Variable<double> &>(); - EXPECT_THROW(auto &foo = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{10}), - std::invalid_argument); - ASSERT_EQ(var_r64.m_Shape.size(), 0); - EXPECT_EQ(var_r64.m_Start.size(), 0); - EXPECT_EQ(var_r64.m_Count.size(), 1); - EXPECT_EQ(var_r64.m_Count[0], 10); - EXPECT_EQ(var_r64.m_Name, "r64"); - EXPECT_EQ(var_r64.m_Type, "double"); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u16_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint16_t = + io.DefineVariable<uint16_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint16_t), + adios2::Variable<uint16_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW( + auto &foo = io.DefineVariable<uint16_t>(name, {}, {}, adios2::Dims{10}), + std::invalid_argument); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint16_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint16_t.m_Start.size(), 0); + EXPECT_EQ(var_uint16_t.m_Count.size(), 1); + EXPECT_EQ(var_uint16_t.m_Count[0], 10); + EXPECT_EQ(var_uint16_t.m_Name, name); + EXPECT_EQ(var_uint16_t.m_Type, "unsigned short"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarChar2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint32_t_1x10) { - auto &var_i8 = io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_i8), adios2::Variable<char> &>(); - EXPECT_THROW(auto &foo = - io.DefineVariable<char>("i8", {}, {}, adios2::Dims{2, 5}), - std::invalid_argument); - ASSERT_EQ(var_i8.m_Shape.size(), 0); - EXPECT_EQ(var_i8.m_Start.size(), 0); - EXPECT_EQ(var_i8.m_Count.size(), 2); - EXPECT_EQ(var_i8.m_Count[0], 2); - EXPECT_EQ(var_i8.m_Count[1], 5); - EXPECT_EQ(var_i8.m_Name, "i8"); - EXPECT_EQ(var_i8.m_Type, "char"); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u32_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint32_t = + io.DefineVariable<uint32_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint32_t), + adios2::Variable<uint32_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW( + auto &foo = io.DefineVariable<uint32_t>(name, {}, {}, adios2::Dims{10}), + std::invalid_argument); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint32_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint32_t.m_Start.size(), 0); + EXPECT_EQ(var_uint32_t.m_Count.size(), 1); + EXPECT_EQ(var_uint32_t.m_Count[0], 10); + EXPECT_EQ(var_uint32_t.m_Name, name); + EXPECT_EQ(var_uint32_t.m_Type, "unsigned int"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarShort2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint64_t_1x10) { - auto &var_i16 = io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_i16), - adios2::Variable<short> &>(); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u64_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint64_t = + io.DefineVariable<uint64_t>(name, {}, {}, adios2::Dims{10}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint64_t), + adios2::Variable<uint64_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names EXPECT_THROW( - auto &foo = io.DefineVariable<short>("i16", {}, {}, adios2::Dims{2, 5}), + auto &foo = io.DefineVariable<uint64_t>(name, {}, {}, adios2::Dims{10}), std::invalid_argument); - ASSERT_EQ(var_i16.m_Shape.size(), 0); - EXPECT_EQ(var_i16.m_Start.size(), 0); - EXPECT_EQ(var_i16.m_Count.size(), 2); - EXPECT_EQ(var_i16.m_Count[0], 2); - EXPECT_EQ(var_i16.m_Count[1], 5); - EXPECT_EQ(var_i16.m_Name, "i16"); - EXPECT_EQ(var_i16.m_Type, "short"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint64_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint64_t.m_Start.size(), 0); + EXPECT_EQ(var_uint64_t.m_Count.size(), 1); + EXPECT_EQ(var_uint64_t.m_Count[0], 10); + EXPECT_EQ(var_uint64_t.m_Name, name); + EXPECT_EQ(var_uint64_t.m_ElementSize, 8); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarInt2x5) +// Rinse and repeat for remaining types + +// 2x5 +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int8_t_2x5) { - auto &var_i32 = io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_i32), adios2::Variable<int> &>(); - EXPECT_THROW(auto &foo = - io.DefineVariable<int>("i32", {}, {}, adios2::Dims{2, 5}), - std::invalid_argument); - ASSERT_EQ(var_i32.m_Shape.size(), 0); - EXPECT_EQ(var_i32.m_Start.size(), 0); - EXPECT_EQ(var_i32.m_Count.size(), 2); - EXPECT_EQ(var_i32.m_Count[0], 2); - EXPECT_EQ(var_i32.m_Count[1], 5); - EXPECT_EQ(var_i32.m_Name, "i32"); - EXPECT_EQ(var_i32.m_Type, "int"); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i8_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int8_t = + io.DefineVariable<int8_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int8_t), + adios2::Variable<int8_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW( + auto &foo = io.DefineVariable<int8_t>(name, {}, {}, adios2::Dims{2, 5}), + std::invalid_argument); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int8_t.m_Shape.size(), 0); + EXPECT_EQ(var_int8_t.m_Start.size(), 0); + EXPECT_EQ(var_int8_t.m_Count.size(), 2); + EXPECT_EQ(var_int8_t.m_Count[0], 2); + EXPECT_EQ(var_int8_t.m_Count[1], 5); + EXPECT_EQ(var_int8_t.m_Name, name); + EXPECT_EQ(var_int8_t.m_Type, "signed char"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarLong2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int16_t_2x5) { - auto &var_u16 = io.DefineVariable<long>("u16", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_u16), - adios2::Variable<long> &>(); - EXPECT_THROW(auto &foo = - io.DefineVariable<long>("u16", {}, {}, adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i16_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int16_t = + io.DefineVariable<int16_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int16_t), + adios2::Variable<int16_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<int16_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_u16.m_Shape.size(), 0); - EXPECT_EQ(var_u16.m_Start.size(), 0); - EXPECT_EQ(var_u16.m_Count.size(), 2); - EXPECT_EQ(var_u16.m_Count[0], 2); - EXPECT_EQ(var_u16.m_Count[1], 5); - EXPECT_EQ(var_u16.m_Name, "u16"); - EXPECT_EQ(var_u16.m_Type, "long int"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int16_t.m_Shape.size(), 0); + EXPECT_EQ(var_int16_t.m_Start.size(), 0); + EXPECT_EQ(var_int16_t.m_Count.size(), 2); + EXPECT_EQ(var_int16_t.m_Count[0], 2); + EXPECT_EQ(var_int16_t.m_Count[1], 5); + EXPECT_EQ(var_int16_t.m_Name, name); + EXPECT_EQ(var_int16_t.m_Type, "short"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarUChar2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int32_t_2x5) { - auto &var_u8 = - io.DefineVariable<unsigned char>("u8", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_u8), - adios2::Variable<unsigned char> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned char>( - "u8", {}, {}, adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i32_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int32_t = + io.DefineVariable<int32_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int32_t), + adios2::Variable<int32_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<int32_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_u8.m_Shape.size(), 0); - EXPECT_EQ(var_u8.m_Start.size(), 0); - EXPECT_EQ(var_u8.m_Count.size(), 2); - EXPECT_EQ(var_u8.m_Count[0], 2); - EXPECT_EQ(var_u8.m_Count[1], 5); - EXPECT_EQ(var_u8.m_Name, "u8"); - EXPECT_EQ(var_u8.m_Type, "unsigned char"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int32_t.m_Shape.size(), 0); + EXPECT_EQ(var_int32_t.m_Start.size(), 0); + EXPECT_EQ(var_int32_t.m_Count.size(), 2); + EXPECT_EQ(var_int32_t.m_Count[0], 2); + EXPECT_EQ(var_int32_t.m_Count[1], 5); + EXPECT_EQ(var_int32_t.m_Name, name); + EXPECT_EQ(var_int32_t.m_Type, "int"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarUShort2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_int64_t_2x5) { - auto &var_u16 = - io.DefineVariable<unsigned short>("u16", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_u16), - adios2::Variable<unsigned short> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned short>( - "u16", {}, {}, adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("i64_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_int64_t = + io.DefineVariable<int64_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_int64_t), + adios2::Variable<int64_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<int64_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_u16.m_Shape.size(), 0); - EXPECT_EQ(var_u16.m_Start.size(), 0); - EXPECT_EQ(var_u16.m_Count.size(), 2); - EXPECT_EQ(var_u16.m_Count[0], 2); - EXPECT_EQ(var_u16.m_Count[1], 5); - EXPECT_EQ(var_u16.m_Name, "u16"); - EXPECT_EQ(var_u16.m_Type, "unsigned short"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_int64_t.m_Shape.size(), 0); + EXPECT_EQ(var_int64_t.m_Start.size(), 0); + EXPECT_EQ(var_int64_t.m_Count.size(), 2); + EXPECT_EQ(var_int64_t.m_Count[0], 2); + EXPECT_EQ(var_int64_t.m_Count[1], 5); + EXPECT_EQ(var_int64_t.m_Name, name); + EXPECT_EQ(var_int64_t.m_ElementSize, 8); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarUInt2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint8_t_2x5) { - auto &var_u32 = - io.DefineVariable<unsigned int>("u32", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_u32), - adios2::Variable<unsigned int> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned int>( - "u32", {}, {}, adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u8_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint8_t = + io.DefineVariable<uint8_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint8_t), + adios2::Variable<uint8_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<uint8_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_u32.m_Shape.size(), 0); - EXPECT_EQ(var_u32.m_Start.size(), 0); - EXPECT_EQ(var_u32.m_Count.size(), 2); - EXPECT_EQ(var_u32.m_Count[0], 2); - EXPECT_EQ(var_u32.m_Count[1], 5); - EXPECT_EQ(var_u32.m_Name, "u32"); - EXPECT_EQ(var_u32.m_Type, "unsigned int"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint8_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint8_t.m_Start.size(), 0); + EXPECT_EQ(var_uint8_t.m_Count.size(), 2); + EXPECT_EQ(var_uint8_t.m_Count[0], 2); + EXPECT_EQ(var_uint8_t.m_Count[1], 5); + EXPECT_EQ(var_uint8_t.m_Name, name); + EXPECT_EQ(var_uint8_t.m_Type, "unsigned char"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarULong2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint16_t_2x5) { - auto &var_u64 = - io.DefineVariable<unsigned long>("u64", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_u64), - adios2::Variable<unsigned long> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<unsigned long>( - "u64", {}, {}, adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u16_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint16_t = + io.DefineVariable<uint16_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint16_t), + adios2::Variable<uint16_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<uint16_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_u64.m_Shape.size(), 0); - EXPECT_EQ(var_u64.m_Start.size(), 0); - EXPECT_EQ(var_u64.m_Count.size(), 2); - EXPECT_EQ(var_u64.m_Count[0], 2); - EXPECT_EQ(var_u64.m_Count[1], 5); - EXPECT_EQ(var_u64.m_Name, "u64"); - EXPECT_EQ(var_u64.m_Type, "unsigned long int"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint16_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint16_t.m_Start.size(), 0); + EXPECT_EQ(var_uint16_t.m_Count.size(), 2); + EXPECT_EQ(var_uint16_t.m_Count[0], 2); + EXPECT_EQ(var_uint16_t.m_Count[1], 5); + EXPECT_EQ(var_uint16_t.m_Name, name); + EXPECT_EQ(var_uint16_t.m_Type, "unsigned short"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarFloat2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint32_t_2x5) { - auto &var_r32 = io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_r32), - adios2::Variable<float> &>(); - EXPECT_THROW( - auto &foo = io.DefineVariable<float>("r32", {}, {}, adios2::Dims{2, 5}), - std::invalid_argument); - ASSERT_EQ(var_r32.m_Shape.size(), 0); - EXPECT_EQ(var_r32.m_Start.size(), 0); - EXPECT_EQ(var_r32.m_Count.size(), 2); - EXPECT_EQ(var_r32.m_Count[0], 2); - EXPECT_EQ(var_r32.m_Count[1], 5); - EXPECT_EQ(var_r32.m_Name, "r32"); - EXPECT_EQ(var_r32.m_Type, "float"); + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u32_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint32_t = + io.DefineVariable<uint32_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint32_t), + adios2::Variable<uint32_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<uint32_t>(name, {}, {}, + adios2::Dims{2, 5}), + std::invalid_argument); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint32_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint32_t.m_Start.size(), 0); + EXPECT_EQ(var_uint32_t.m_Count.size(), 2); + EXPECT_EQ(var_uint32_t.m_Count[0], 2); + EXPECT_EQ(var_uint32_t.m_Count[1], 5); + EXPECT_EQ(var_uint32_t.m_Name, name); + EXPECT_EQ(var_uint32_t.m_Type, "unsigned int"); } -TEST_F(ADIOSInterfaceWriteTest, DefineVarDouble2x5) +TEST_F(ADIOSInterfaceWriteTest, DefineVar_uint64_t_2x5) { - auto &var_r64 = - io.DefineVariable<double>("r64", {}, {}, adios2::Dims{2, 5}); - ::testing::StaticAssertTypeEq<decltype(var_r64), - adios2::Variable<double> &>(); - EXPECT_THROW(auto &foo = io.DefineVariable<double>("r64", {}, {}, - adios2::Dims{2, 5}), + int mpiRank = 0, mpiSize = 1; + +#ifdef ADIOS2_HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank); + MPI_Comm_size(MPI_COMM_WORLD, &mpiSize); +#endif + std::string name = std::string("u64_") + std::to_string(mpiRank); + + // Define ADIOS variables for each type + + auto &var_uint64_t = + io.DefineVariable<uint64_t>(name, {}, {}, adios2::Dims{2, 5}); + + // Verify the return type is as expected + ::testing::StaticAssertTypeEq<decltype(var_uint64_t), + adios2::Variable<uint64_t> &>(); + + // Verify exceptions are thrown upon duplicate variable names + EXPECT_THROW(auto &foo = io.DefineVariable<uint64_t>(name, {}, {}, + adios2::Dims{2, 5}), std::invalid_argument); - ASSERT_EQ(var_r64.m_Shape.size(), 0); - EXPECT_EQ(var_r64.m_Start.size(), 0); - EXPECT_EQ(var_r64.m_Count.size(), 2); - EXPECT_EQ(var_r64.m_Count[0], 2); - EXPECT_EQ(var_r64.m_Count[1], 5); - EXPECT_EQ(var_r64.m_Name, "r64"); - EXPECT_EQ(var_r64.m_Type, "double"); + + // Verify the dimensions, name, and type are correct + ASSERT_EQ(var_uint64_t.m_Shape.size(), 0); + EXPECT_EQ(var_uint64_t.m_Start.size(), 0); + EXPECT_EQ(var_uint64_t.m_Count.size(), 2); + EXPECT_EQ(var_uint64_t.m_Count[0], 2); + EXPECT_EQ(var_uint64_t.m_Count[1], 5); + EXPECT_EQ(var_uint64_t.m_Name, name); + EXPECT_EQ(var_uint64_t.m_ElementSize, 8); } int main(int argc, char **argv) diff --git a/testing/adios2/xml/TestXMLConfig.cpp b/testing/adios2/xml/TestXMLConfig.cpp index 5d3cb161b01080cd33a19083516deba70d3caaaa..72bbdffe52e229c78536220221a52d0058064dfb 100644 --- a/testing/adios2/xml/TestXMLConfig.cpp +++ b/testing/adios2/xml/TestXMLConfig.cpp @@ -25,6 +25,7 @@ protected: TEST_F(XMLConfigTest, TwoIOs) { std::string configFile = configDir + "/config1.xml"; + #ifdef ADIOS2_HAVE_MPI adios2::ADIOS adios(configFile, MPI_COMM_WORLD, adios2::DebugON); #else diff --git a/testing/adios2/xml/config1.xml b/testing/adios2/xml/config1.xml index 9afe2d91037b232930a37ad48ad962d88dd27d07..f4d644631d02988df4d6c31248f3bab323e3c415 100644 --- a/testing/adios2/xml/config1.xml +++ b/testing/adios2/xml/config1.xml @@ -9,7 +9,7 @@ <parameter key="BufferGrowthFactor" value="2"/> </engine> <transport type="File"> - <parameter key="Library" value="POSIX"/> + <parameter key="Library" value="fstream"/> <parameter key="ProfileUnits" value="Milliseconds"/> </transport> </io> diff --git a/thirdparty/GTest/CMakeLists.txt b/thirdparty/GTest/CMakeLists.txt index bdac080ca6617d26fd27180c2420717e5f8d152b..8e7b4e21bf144f336ebf4acb2bec6f9f79a2fb33 100644 --- a/thirdparty/GTest/CMakeLists.txt +++ b/thirdparty/GTest/CMakeLists.txt @@ -1,5 +1,6 @@ -set(BUILD_GTEST ON) -set(BUILD_GMOCK OFF) +set(BUILD_GTEST ON CACHE INTERNAL "") +set(BUILD_GMOCK OFF CACHE INTERNAL "") set(gtest_disable_pthreads ON) +set(CMAKE_POLICY_DEFAULT_CMP0042 NEW) add_subdirectory(googletest EXCLUDE_FROM_ALL) diff --git a/thirdparty/KWSys/CMakeLists.txt b/thirdparty/KWSys/CMakeLists.txt index 600c5c9b4b33e07316486b5f2aaba8ac85d00fe8..952fd5e0ca8ce201a9e7c17ee9e6365574e32f2e 100644 --- a/thirdparty/KWSys/CMakeLists.txt +++ b/thirdparty/KWSys/CMakeLists.txt @@ -2,9 +2,14 @@ set(KWSYS_NAMESPACE adios2sys) set(KWSYS_USE_DynamicLoader ON) set(KWSYS_USE_RegularExpression ON) set(KWSYS_USE_SystemTools ON) -set(KWSYS_BUILD_SHARED ${ADIOS2_BUILD_SHARED_LIBS}) +if(WIN32) + set(KWSYS_BUILD_SHARED OFF) +else() + set(KWSYS_BUILD_SHARED ${BUILD_SHARED_LIBS}) +endif() set(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE ON) set(KWSYS_INSTALL_EXPORT_NAME adios2Exports) set(KWSYS_INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR}) add_subdirectory(adios2sys) +add_library(adios2sys_interface ALIAS adios2sys_private) diff --git a/thirdparty/KWSys/adios2sys/CMakeLists.txt b/thirdparty/KWSys/adios2sys/CMakeLists.txt index e9bae831c62bfbac1020833ef1cae45303be1a67..13375df81790e5f5589220f749a171d9a920624e 100644 --- a/thirdparty/KWSys/adios2sys/CMakeLists.txt +++ b/thirdparty/KWSys/adios2sys/CMakeLists.txt @@ -23,18 +23,18 @@ # KWSYS_SPLIT_OBJECTS_FROM_INTERFACE # = Instead of creating a single ${KWSYS_NAMESPACE} library # target, create three separate targets: +# ${KWSYS_NAMESPACE} +# - An INTERFACE library only containing usage +# requirements. # ${KWSYS_NAMESPACE}_objects # - An OBJECT library for the built kwsys objects. -# ${KWSYS_NAMESPACE}_interface -# - An INTERFACE library for the usage requirements. -# ${KWSYS_NAMESPACE} +# Note: This is omitted from the install rules +# ${KWSYS_NAMESPACE}_private # - An INTERFACE library combining both that is # appropriate for use with PRIVATE linking in # target_link_libraries. Because of how interface # properties propagate, this target is not suitable # for use with PUBLIC or INTERFACE linking. -# Note: only the ${KWSYS_NAMESPACE}_interface library will -# be installed # # Example: # @@ -438,6 +438,10 @@ ELSE() SET(KWSYS_LIBRARY_TYPE STATIC) ENDIF() +IF(NOT KWSYS_DEFINE_SYMBOL) + SET(KWSYS_DEFINE_SYMBOL ${KWSYS_NAMESPACE}_EXPORTS) +ENDIF() + #----------------------------------------------------------------------------- # Configure some implementation details. @@ -449,6 +453,11 @@ SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}" ) +IF(DEFINED KWSYS_PROCESS_USE_SELECT) + GET_PROPERTY(ProcessUNIX_FLAGS SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS) + SET_PROPERTY(SOURCE ProcessUNIX.c PROPERTY COMPILE_FLAGS "${ProcessUNIX_FLAGS} -DKWSYSPE_USE_SELECT=${KWSYSPE_USE_SELECT}") +ENDIF() + IF(KWSYS_USE_DynamicLoader) GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) IF(KWSYS_SUPPORTS_SHARED_LIBS) @@ -815,15 +824,18 @@ ENDFOREACH() # Add the library with the configured name and list of sources. IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}_interface) + SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}_objects) - SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) + SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}_private) + SET(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_INTERFACE} ${KWSYS_TARGET_LINK}) SET(KWSYS_LINK_DEPENDENCY INTERFACE) ADD_LIBRARY(${KWSYS_TARGET_OBJECT} OBJECT ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) IF(KWSYS_BUILD_SHARED) SET_PROPERTY(TARGET ${KWSYS_TARGET_OBJECT} PROPERTY POSITION_INDEPENDENT_CODE TRUE) + TARGET_COMPILE_DEFINITIONS(${KWSYS_TARGET_OBJECT} PRIVATE + ${KWSYS_DEFINE_SYMBOL}) ENDIF() ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} INTERFACE) ADD_LIBRARY(${KWSYS_TARGET_LINK} INTERFACE) @@ -835,6 +847,7 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) SET(KWSYS_TARGET_INTERFACE ${KWSYS_NAMESPACE}) SET(KWSYS_TARGET_OBJECT ${KWSYS_NAMESPACE}) SET(KWSYS_TARGET_LINK ${KWSYS_NAMESPACE}) + set(KWSYS_TARGET_INSTALL ${KWSYS_TARGET_LINK}) SET(KWSYS_LINK_DEPENDENCY PUBLIC) ADD_LIBRARY(${KWSYS_TARGET_INTERFACE} ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS} ${KWSYS_CXX_SRCS}) @@ -895,21 +908,25 @@ IF(KWSYS_C_SRCS OR KWSYS_CXX_SRCS) # Create an install target for the library. IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_LINK} ${KWSYS_TARGET_INTERFACE} ${KWSYS_INSTALL_LIBRARY_RULE}) + INSTALL(TARGETS ${KWSYS_TARGET_INSTALL} ${KWSYS_INSTALL_LIBRARY_RULE}) ENDIF() ENDIF() # Add a C-only library if requested. IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) IF(KWSYS_SPLIT_OBJECTS_FROM_INTERFACE) - SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c_interface) - SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_object) - SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c_objects) + SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c_private) + SET(KWSYS_TARGET_C_INSTALL + ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_TARGET_C_LINK}) SET(KWSYS_LINK_DEPENDENCY INTERFACE) ADD_LIBRARY(${KWSYS_TARGET_C_OBJECT} OBJECT ${KWSYS_C_SRCS}) IF(KWSYS_BUILD_SHARED) SET_PROPERTY(TARGET ${KWSYS_TARGET_C_OBJECT} PROPERTY POSITION_INDEPENDENT_CODE TRUE) + TARGET_COMPILE_DEFINITIONS(${KWSYS_TARGET_C_OBJECT} PRIVATE + ${KWSYS_DEFINE_SYMBOL}) ENDIF() ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} INTERFACE) ADD_LIBRARY(${KWSYS_TARGET_C_LINK} INTERFACE) @@ -921,6 +938,7 @@ IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) SET(KWSYS_TARGET_C_INTERFACE ${KWSYS_NAMESPACE}_c) SET(KWSYS_TARGET_C_OBJECT ${KWSYS_NAMESPACE}_c) SET(KWSYS_TARGET_C_LINK ${KWSYS_NAMESPACE}_c) + SET(KWSYS_TARGET_C_INSTALL ${KWSYS_TARGET_C_LINK}) SET(KWSYS_LINK_DEPENDENCY PUBLIC) ADD_LIBRARY(${KWSYS_TARGET_C_INTERFACE} ${KWSYS_LIBRARY_TYPE} ${KWSYS_C_SRCS}) @@ -946,8 +964,8 @@ IF(KWSYS_ENABLE_C AND KWSYS_C_SRCS) # Create an install target for the library. IF(KWSYS_INSTALL_LIBRARY_RULE) - INSTALL(TARGETS ${KWSYS_TARGET_C_INTERFACE} ${KWSYS_INSTALL_LIBRARY_RULE}) - ENDIF() + INSTALL(TARGETS ${KWSYS_TARGET_C_INSTALL}) + ENDIF() ENDIF() # For building kwsys itself, we use a macro defined on the command @@ -1022,6 +1040,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) testSystemTools testCommandLineArguments testCommandLineArguments1 + testDirectory ) IF(KWSYS_STL_HAS_WSTRING) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} diff --git a/thirdparty/KWSys/adios2sys/Configure.h.in b/thirdparty/KWSys/adios2sys/Configure.h.in index 0afcae781d6ae46d6e27b3864948e6915119e542..921e1ae599a414a66ed05ee4c72dd1e8a9205d9b 100644 --- a/thirdparty/KWSys/adios2sys/Configure.h.in +++ b/thirdparty/KWSys/adios2sys/Configure.h.in @@ -71,7 +71,7 @@ /* Setup the export macro. */ #if @KWSYS_BUILD_SHARED@ #if defined(_WIN32) || defined(__CYGWIN__) -#if defined(@KWSYS_NAMESPACE@_EXPORTS) +#if defined(@KWSYS_DEFINE_SYMBOL@) #define @KWSYS_NAMESPACE@_EXPORT __declspec(dllexport) #else #define @KWSYS_NAMESPACE@_EXPORT __declspec(dllimport) diff --git a/thirdparty/KWSys/adios2sys/Directory.cxx b/thirdparty/KWSys/adios2sys/Directory.cxx index 5141d451929bc2499fa1e45e046b25063ff479a5..69068aaf88d7e96ae159430d0644bedd8f391d69 100644 --- a/thirdparty/KWSys/adios2sys/Directory.cxx +++ b/thirdparty/KWSys/adios2sys/Directory.cxx @@ -118,8 +118,8 @@ bool Directory::Load(const std::string& name) struct _wfinddata_t data; // data of current file // Now put them into the file array - srchHandle = - _wfindfirst_func((wchar_t*)Encoding::ToWide(buf).c_str(), &data); + srchHandle = _wfindfirst_func( + (wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data); delete[] buf; if (srchHandle == -1) { diff --git a/thirdparty/KWSys/adios2sys/ProcessUNIX.c b/thirdparty/KWSys/adios2sys/ProcessUNIX.c index 9ebcfce592759922ce8fdb5cc02882ea2aae5e10..3b32ca7d0a26b388e7a88cebb2e2e76747157b9e 100644 --- a/thirdparty/KWSys/adios2sys/ProcessUNIX.c +++ b/thirdparty/KWSys/adios2sys/ProcessUNIX.c @@ -99,7 +99,8 @@ static inline void kwsysProcess_usleep(unsigned int msec) * pipes' file handles to be non-blocking and just poll them directly * without select(). */ -#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__) +#if !defined(__BEOS__) && !defined(__VMS) && !defined(__MINT__) && \ + !defined(KWSYSPE_USE_SELECT) #define KWSYSPE_USE_SELECT 1 #endif diff --git a/thirdparty/KWSys/adios2sys/RegularExpression.cxx b/thirdparty/KWSys/adios2sys/RegularExpression.cxx index 6d7f832955911e5352e6f60e246b743c37c3ebdb..26e84e04eb1a98912aeee699f6f3d80f23bed3b6 100644 --- a/thirdparty/KWSys/adios2sys/RegularExpression.cxx +++ b/thirdparty/KWSys/adios2sys/RegularExpression.cxx @@ -258,11 +258,6 @@ const unsigned char MAGIC = 0234; #define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0] -#define FAIL(m) \ - { \ - regerror(m); \ - return (0); \ - } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') #define META "^$.[()|?+*\\" diff --git a/thirdparty/KWSys/adios2sys/SystemTools.cxx b/thirdparty/KWSys/adios2sys/SystemTools.cxx index c5bbd416a39e4ee92ad9e08b4cac7a77c85b00f9..560c19c0292ee01d3fc9dc18f2f129cc7fa0dc6a 100644 --- a/thirdparty/KWSys/adios2sys/SystemTools.cxx +++ b/thirdparty/KWSys/adios2sys/SystemTools.cxx @@ -847,6 +847,8 @@ void SystemTools::ReplaceString(std::string& source, const char* replace, free(orig); } +#if defined(_WIN32) && !defined(__CYGWIN__) + #if defined(KEY_WOW64_32KEY) && defined(KEY_WOW64_64KEY) #define KWSYS_ST_KEY_WOW64_32KEY KEY_WOW64_32KEY #define KWSYS_ST_KEY_WOW64_64KEY KEY_WOW64_64KEY @@ -855,7 +857,6 @@ void SystemTools::ReplaceString(std::string& source, const char* replace, #define KWSYS_ST_KEY_WOW64_64KEY 0x0100 #endif -#if defined(_WIN32) && !defined(__CYGWIN__) static bool SystemToolsParseRegistryKey(const std::string& key, HKEY& primaryKey, std::string& second, std::string& valuename) @@ -2268,11 +2269,7 @@ bool SystemTools::CopyADirectory(const std::string& source, const std::string& destination, bool always) { Directory dir; -#ifdef _WIN32 - dir.Load(Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source))); -#else dir.Load(source); -#endif size_t fileNum; if (!SystemTools::MakeDirectory(destination)) { return false; @@ -2625,11 +2622,7 @@ bool SystemTools::RemoveADirectory(const std::string& source) } Directory dir; -#ifdef _WIN32 - dir.Load(Encoding::ToNarrow(Encoding::ToWindowsExtendedPath(source))); -#else dir.Load(source); -#endif size_t fileNum; for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) { if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") && @@ -3796,11 +3789,7 @@ std::string SystemTools::GetFilenamePath(const std::string& filename) */ std::string SystemTools::GetFilenameName(const std::string& filename) { -#if defined(_WIN32) std::string::size_type slash_pos = filename.find_last_of("/\\"); -#else - std::string::size_type slash_pos = filename.rfind('/'); -#endif if (slash_pos != std::string::npos) { return filename.substr(slash_pos + 1); } else { diff --git a/thirdparty/KWSys/adios2sys/testDirectory.cxx b/thirdparty/KWSys/adios2sys/testDirectory.cxx new file mode 100644 index 0000000000000000000000000000000000000000..983f2c6314aed869954606ca82c8ae0c13014cdd --- /dev/null +++ b/thirdparty/KWSys/adios2sys/testDirectory.cxx @@ -0,0 +1,79 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Directory.hxx) +#include KWSYS_HEADER(Encoding.hxx) +#include KWSYS_HEADER(SystemTools.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +#include "Directory.hxx.in" +#include "Encoding.hxx.in" +#include "SystemTools.hxx.in" +#endif + +#include <fstream> +#include <iostream> +#include <sstream> + +#include <testSystemTools.h> + +int _doLongPathTest() +{ + using namespace kwsys; + static const int LONG_PATH_THRESHOLD = 512; + int res = 0; + std::string topdir(TEST_SYSTEMTOOLS_BINARY_DIR "/directory_testing/"); + std::stringstream testpathstrm; + std::string testdirpath; + std::string extendedtestdirpath; + + testpathstrm << topdir; + size_t pathlen = testpathstrm.str().length(); + testpathstrm.seekp(0, std::ios_base::end); + while (pathlen < LONG_PATH_THRESHOLD) { + testpathstrm << "0123456789/"; + pathlen = testpathstrm.str().length(); + } + + testdirpath = testpathstrm.str(); +#ifdef _WIN32 + extendedtestdirpath = + Encoding::ToNarrow(SystemTools::ConvertToWindowsExtendedPath(testdirpath)); +#else + extendedtestdirpath = testdirpath; +#endif + + if (SystemTools::MakeDirectory(extendedtestdirpath)) { + std::ofstream testfile1( + (extendedtestdirpath + "longfilepathtest1.txt").c_str()); + std::ofstream testfile2( + (extendedtestdirpath + "longfilepathtest2.txt").c_str()); + testfile1 << "foo"; + testfile2 << "bar"; + testfile1.close(); + testfile2.close(); + + Directory testdir; + // Set res to failure if the directory doesn't load + res += !testdir.Load(testdirpath); + // Increment res failure if the directory appears empty + res += testdir.GetNumberOfFiles() == 0; + // Increment res failures if the path has changed from + // what was provided. + res += testdirpath != testdir.GetPath(); + + SystemTools::RemoveADirectory(topdir); + } else { + std::cerr << "Failed to create directory with long path: " + << extendedtestdirpath << std::endl; + res += 1; + } + return res; +} + +int testDirectory(int, char* []) +{ + return _doLongPathTest(); +} diff --git a/thirdparty/KWSys/adios2sys/testSystemTools.cxx b/thirdparty/KWSys/adios2sys/testSystemTools.cxx index e6fbf6cdafb8ae2197ac3b815ff8b3e5c6535b72..1871f5dd0d81767d9cab71863184000d92cfd7de 100644 --- a/thirdparty/KWSys/adios2sys/testSystemTools.cxx +++ b/thirdparty/KWSys/adios2sys/testSystemTools.cxx @@ -758,6 +758,30 @@ static bool CheckGetPath() return res; } +static bool CheckGetFilenameName() +{ + const char* windowsFilepath = "C:\\somewhere\\something"; + const char* unixFilepath = "/somewhere/something"; + + std::string expectedFilename = "something"; + + bool res = true; + std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath); + if (filename != expectedFilename) { + std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded " + << filename << " instead of " << expectedFilename << std::endl; + res = false; + } + + filename = kwsys::SystemTools::GetFilenameName(unixFilepath); + if (filename != expectedFilename) { + std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename + << " instead of " << expectedFilename << std::endl; + res = false; + } + return res; +} + static bool CheckFind() { bool res = true; @@ -875,5 +899,7 @@ int testSystemTools(int, char* []) res &= CheckGetLineFromStream(); + res &= CheckGetFilenameName(); + return res ? 0 : 1; } diff --git a/thirdparty/KWSys/update.sh b/thirdparty/KWSys/update.sh index 53d24129ec3b2b9962517cc603e15079c74e8441..c10e61e75e4381a284d56b3432088c37dfb3232d 100755 --- a/thirdparty/KWSys/update.sh +++ b/thirdparty/KWSys/update.sh @@ -7,13 +7,8 @@ shopt -s dotglob readonly name="KWSys" readonly ownership="KWSys Upstream <kwrobot@kitware.com>" readonly subtree="thirdparty/KWSys/adios2sys" -#readonly repo="https://gitlab.kitware.com/utils/kwsys.git" -#readonly tag="master" - -# This commit contains a patch to allow object libraries for kwsys. -# Use 'master' off the main repo instead once its been merged -readonly repo="https://gitlab.kitware.com/chuck.atkins/kwsys.git" -readonly tag="ab645c9" +readonly repo="https://gitlab.kitware.com/utils/kwsys.git" +readonly tag="master" readonly shortlog="true" readonly paths="