From 9bb7976b03585868aaa5cccb3d9f2db0bd6b43bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Tue, 21 Jan 2025 15:44:46 +0100 Subject: [PATCH 1/4] CMake: Re-order interface targets --- CMakeLists.txt | 349 ++++++++++++++++++++++++++----------------------- 1 file changed, 183 insertions(+), 166 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b20dcbe0e..7cb98f657e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,6 +298,183 @@ if(ESPRESSO_BUILD_WITH_PYTHON) set(ESPRESSO_INSTALL_LIBDIR "${ESPRESSO_INSTALL_PYTHON}/espressomd") endif() +# +# Compiler flags: must be added to all ESPResSo targets +# + +add_library(espresso_cpp_flags INTERFACE) +add_library(espresso::cpp_flags ALIAS espresso_cpp_flags) + +# +# Compiler diagnostics +# + +target_compile_options( + espresso_cpp_flags + INTERFACE + -Wall + -Wextra + -pedantic + # add extra warnings + $<$:-Wextern-initializer> + $<$:-Wrange-loop-analysis> + -Wfloat-conversion + $<$:-Wimplicit-float-conversion> + $<$:-Wunused-exception-parameter> + $<$:-Wmissing-variable-declarations> + $<$:-Wnon-c-typedef-for-linkage> + $<$>:-Wdelete-non-virtual-dtor> + # disable warnings from -Wall and -Wextra + -Wno-sign-compare + -Wno-unused-function + -Wno-unused-parameter + -Wno-array-bounds + $<$:-Wno-restrict> + $<$:-Wno-clobbered> + $<$:-Wno-cast-function-type> + $<$:-diag-disable=592> + $<$:-Wno-gnu-zero-variadic-macro-arguments> + $<$>:-Wno-implicit-fallthrough> + $<$>:-Wno-unused-private-field> + # warnings are errors + $<$:-Werror>) + +if(ESPRESSO_BUILD_WITH_CUDA) + target_compile_options( + espresso_cuda_flags + INTERFACE + -Wall + -Wextra + -Wno-sign-compare + -Wno-unused-parameter + $<$>:-Wno-implicit-fallthrough> + # warnings are errors + $<$,$>:--Werror=all-warnings> + $<$,$>:-Werror> + ) +endif() + +# disable warning from -Wextra on ARM processors +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_PROCESSOR MATCHES + "arm") + target_compile_options(espresso_cpp_flags INTERFACE -Wno-psabi) +endif() + +# +# Code coverage +# + +add_library(espresso_coverage_flags INTERFACE) +add_library(espresso::coverage_flags ALIAS espresso_coverage_flags) +if(ESPRESSO_BUILD_WITH_COVERAGE) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + target_compile_options( + espresso_coverage_flags INTERFACE -g -fprofile-instr-generate + -fcoverage-mapping) + else() + target_compile_options(espresso_coverage_flags INTERFACE -g --coverage + -fprofile-abs-path) + target_link_libraries(espresso_coverage_flags INTERFACE gcov) + endif() +endif() + +# +# Portability options +# + +# prevent 80-bit arithmetic on old Intel processors +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SIZEOF_VOID_P EQUAL 4 + AND CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86") + target_compile_options(espresso_cpp_flags INTERFACE -ffloat-store) +endif() + +# +# Sanitizers +# + +if(ESPRESSO_BUILD_WITH_ASAN AND ESPRESSO_BUILD_WITH_MSAN) + message( + FATAL_ERROR + "Address sanitizer and memory sanitizer cannot be enabled simultaneously") +endif() +if(ESPRESSO_BUILD_WITH_ASAN) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1") + target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=address + -fno-omit-frame-pointer) + target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=address) + if(ESPRESSO_BUILD_WITH_CUDA) + target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=address) + endif() +endif() +if(ESPRESSO_BUILD_WITH_MSAN) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1") + target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=memory + -fno-omit-frame-pointer) + target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=memory) + if(ESPRESSO_BUILD_WITH_CUDA) + target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=memory) + endif() +endif() +if(ESPRESSO_BUILD_WITH_UBSAN) + target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=undefined) + target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=undefined) + if(ESPRESSO_BUILD_WITH_CUDA) + target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=undefined) + endif() +endif() + +target_link_libraries(espresso_cpp_flags INTERFACE espresso::coverage_flags) + +# +# Static analysis +# + +if(ESPRESSO_BUILD_WITH_CLANG_TIDY) + find_package(ClangTidy "${CMAKE_CXX_COMPILER_VERSION}" EXACT REQUIRED) + set(ESPRESSO_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") + set(ESPRESSO_CUDA_CLANG_TIDY "${CLANG_TIDY_EXE};--extra-arg=--cuda-host-only") + set(SKIP_CLANG_TIDY_CHECKS "") + set(SKIP_CLANG_TIDY_CHECKS_CXX "") + set(SKIP_CLANG_TIDY_CHECKS_CUDA "") + if(ESPRESSO_BUILD_WITH_CALIPER) + # Clang-Tidy sometimes emits diagnostics in code enclosed in `extern "C"` + # that are not always actionable, since they may rely on keywords only + # available in the C++ language. While some checks have an extra flag + # 'IgnoreExternC' to disable them inside C code, not all affected checks + # have been fixed yet. For an in-depth discussion on this topic, see + # https://github.com/llvm/llvm-project/issues/35272 + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-nullptr") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-deprecated-headers") + endif() + if(ESPRESSO_BUILD_WITH_CUDA) + # silence casts in cuda_runtime.h (for both C++ and CUDA source files) + list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-casting-through-void") + # silence nullptr dereference in cuda::thrust + list(APPEND SKIP_CLANG_TIDY_CHECKS_CUDA + "-clang-analyzer-core.NonNullParamChecker") + endif() + espresso_override_clang_tidy_checks( + ESPRESSO_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" + "${SKIP_CLANG_TIDY_CHECKS_CXX}") + espresso_override_clang_tidy_checks( + ESPRESSO_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" + "${SKIP_CLANG_TIDY_CHECKS_CUDA}") +endif() + +if(ESPRESSO_BUILD_WITH_CPPCHECK) + find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) + if(NOT CMAKE_CXX_CPPCHECK) + message(FATAL_ERROR "Could not find the program cppcheck.") + endif() + list(APPEND CMAKE_CXX_CPPCHECK "--enable=all" + "--std=c++${CMAKE_CXX_STANDARD}" "--quiet" "--inline-suppr" + "--suppressions-list=${CMAKE_CURRENT_SOURCE_DIR}/.cppcheck") + if(ESPRESSO_WARNINGS_ARE_ERRORS) + list(APPEND CMAKE_CXX_CPPCHECK "--error-exitcode=2") + endif() +endif() + # # Libraries # @@ -453,6 +630,11 @@ endif() find_package(Boost 1.74.0 REQUIRED ${BOOST_COMPONENTS}) +# enable boost::variant with more than 20 types +target_compile_options( + espresso_cpp_flags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS + -DBOOST_MPL_LIMIT_LIST_SIZE=30) + # # Paths # @@ -460,180 +642,15 @@ find_package(Boost 1.74.0 REQUIRED ${BOOST_COMPONENTS}) set(CMAKE_INSTALL_RPATH "${ESPRESSO_INSTALL_LIBDIR}") # -# Flags +# Packaging # # drop 'lib' prefix from all libraries set(ESPRESSO_SHARED_LIBRARY_PREFIX "") set(CMAKE_SHARED_LIBRARY_PREFIX "${ESPRESSO_SHARED_LIBRARY_PREFIX}") -add_library(espresso_coverage_flags INTERFACE) -add_library(espresso::coverage_flags ALIAS espresso_coverage_flags) -if(ESPRESSO_BUILD_WITH_COVERAGE) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - target_compile_options( - espresso_coverage_flags INTERFACE -g -fprofile-instr-generate - -fcoverage-mapping) - else() - target_compile_options(espresso_coverage_flags INTERFACE -g --coverage - -fprofile-abs-path) - target_link_libraries(espresso_coverage_flags INTERFACE gcov) - endif() -endif() - -add_library(espresso_cpp_flags INTERFACE) -add_library(espresso::cpp_flags ALIAS espresso_cpp_flags) -target_compile_options( - espresso_cpp_flags - INTERFACE - -Wall - -Wextra - -pedantic - # add extra warnings - $<$:-Wextern-initializer> - $<$:-Wrange-loop-analysis> - -Wfloat-conversion - $<$:-Wimplicit-float-conversion> - $<$:-Wunused-exception-parameter> - $<$:-Wmissing-variable-declarations> - $<$:-Wnon-c-typedef-for-linkage> - $<$>:-Wdelete-non-virtual-dtor> - # disable warnings from -Wall and -Wextra - -Wno-sign-compare - -Wno-unused-function - -Wno-unused-parameter - -Wno-array-bounds - $<$:-Wno-restrict> - $<$:-Wno-clobbered> - $<$:-Wno-cast-function-type> - $<$:-diag-disable=592> - $<$:-Wno-gnu-zero-variadic-macro-arguments> - $<$>:-Wno-implicit-fallthrough> - $<$>:-Wno-unused-private-field> - # warnings are errors - $<$:-Werror>) - -if(ESPRESSO_BUILD_WITH_CUDA) - target_compile_options( - espresso_cuda_flags - INTERFACE - -Wall - -Wextra - -Wno-sign-compare - -Wno-unused-parameter - $<$>:-Wno-implicit-fallthrough> - # warnings are errors - $<$,$>:--Werror=all-warnings> - $<$,$>:-Werror> - ) -endif() - -# disable warning from -Wextra on ARM processors -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_PROCESSOR MATCHES - "arm") - target_compile_options(espresso_cpp_flags INTERFACE -Wno-psabi) -endif() - -# prevent 80-bit arithmetic on old Intel processors -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SIZEOF_VOID_P EQUAL 4 - AND CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86") - target_compile_options(espresso_cpp_flags INTERFACE -ffloat-store) -endif() - -# enable boost::variant with more than 20 types -target_compile_options( - espresso_cpp_flags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS - -DBOOST_MPL_LIMIT_LIST_SIZE=30) - set(CMAKE_MACOSX_RPATH TRUE) -# -# Sanitizers -# - -if(ESPRESSO_BUILD_WITH_ASAN AND ESPRESSO_BUILD_WITH_MSAN) - message( - FATAL_ERROR - "Address sanitizer and memory sanitizer cannot be enabled simultaneously") -endif() -if(ESPRESSO_BUILD_WITH_ASAN) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1") - target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=address - -fno-omit-frame-pointer) - target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=address) - if(ESPRESSO_BUILD_WITH_CUDA) - target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=address) - endif() -endif() -if(ESPRESSO_BUILD_WITH_MSAN) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g -O1") - target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=memory - -fno-omit-frame-pointer) - target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=memory) - if(ESPRESSO_BUILD_WITH_CUDA) - target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=memory) - endif() -endif() -if(ESPRESSO_BUILD_WITH_UBSAN) - target_compile_options(espresso_cpp_flags INTERFACE -fsanitize=undefined) - target_link_libraries(espresso_cpp_flags INTERFACE -fsanitize=undefined) - if(ESPRESSO_BUILD_WITH_CUDA) - target_link_libraries(espresso_cuda_flags INTERFACE -fsanitize=undefined) - endif() -endif() - -target_link_libraries(espresso_cpp_flags INTERFACE espresso::coverage_flags) - -# -# Static analysis -# - -if(ESPRESSO_BUILD_WITH_CLANG_TIDY) - find_package(ClangTidy "${CMAKE_CXX_COMPILER_VERSION}" EXACT REQUIRED) - set(ESPRESSO_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") - set(ESPRESSO_CUDA_CLANG_TIDY "${CLANG_TIDY_EXE};--extra-arg=--cuda-host-only") - set(SKIP_CLANG_TIDY_CHECKS "") - set(SKIP_CLANG_TIDY_CHECKS_CXX "") - set(SKIP_CLANG_TIDY_CHECKS_CUDA "") - if(ESPRESSO_BUILD_WITH_CALIPER) - # Clang-Tidy sometimes emits diagnostics in code enclosed in `extern "C"` - # that are not always actionable, since they may rely on keywords only - # available in the C++ language. While some checks have an extra flag - # 'IgnoreExternC' to disable them inside C code, not all affected checks - # have been fixed yet. For an in-depth discussion on this topic, see - # https://github.com/llvm/llvm-project/issues/35272 - list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto") - list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-nullptr") - list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-deprecated-headers") - endif() - if(ESPRESSO_BUILD_WITH_CUDA) - # silence casts in cuda_runtime.h (for both C++ and CUDA source files) - list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-casting-through-void") - # silence nullptr dereference in cuda::thrust - list(APPEND SKIP_CLANG_TIDY_CHECKS_CUDA - "-clang-analyzer-core.NonNullParamChecker") - endif() - espresso_override_clang_tidy_checks( - ESPRESSO_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" - "${SKIP_CLANG_TIDY_CHECKS_CXX}") - espresso_override_clang_tidy_checks( - ESPRESSO_CUDA_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" - "${SKIP_CLANG_TIDY_CHECKS_CUDA}") -endif() - -if(ESPRESSO_BUILD_WITH_CPPCHECK) - find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) - if(NOT CMAKE_CXX_CPPCHECK) - message(FATAL_ERROR "Could not find the program cppcheck.") - endif() - list(APPEND CMAKE_CXX_CPPCHECK "--enable=all" - "--std=c++${CMAKE_CXX_STANDARD}" "--quiet" "--inline-suppr" - "--suppressions-list=${CMAKE_CURRENT_SOURCE_DIR}/.cppcheck") - if(ESPRESSO_WARNINGS_ARE_ERRORS) - list(APPEND CMAKE_CXX_CPPCHECK "--error-exitcode=2") - endif() -endif() - # # Testing # From b2c5d2676b86825ccb619a8812bd66c75021ce85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Tue, 21 Jan 2025 16:29:19 +0100 Subject: [PATCH 2/4] CMake: Improve compiler and libraries support Drop support for Intel Classic. Provide a clear error message when an unsupported compiler is detected. Also update C++ code to leverage C++20 and address build issues with Clang compiler toolchains. --- CMakeLists.txt | 48 ++++++++++++--------- src/core/bond_breakage/actions.hpp | 25 +++-------- src/python/espressomd/CMakeLists.txt | 8 ++-- src/script_interface/walberla/EKSpecies.hpp | 16 +++---- src/script_interface/walberla/LBFluid.hpp | 16 +++---- 5 files changed, 51 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cb98f657e..9d1fc4920a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,9 +51,13 @@ endmacro() espresso_minimal_compiler_version("GNU" 10.5.0) espresso_minimal_compiler_version("Clang" 14.0.0) espresso_minimal_compiler_version("AppleClang" 14.0.0) -espresso_minimal_compiler_version("Intel" 2021.9) espresso_minimal_compiler_version("IntelLLVM" 2023.1) +set(UNSUPPORTED_COMPILERS "Intel;MSVC") +if(CMAKE_CXX_COMPILER_ID IN_LIST UNSUPPORTED_COMPILERS) + message(FATAL_ERROR "Unsupported compiler ${CMAKE_CXX_COMPILER_ID}") +endif() + include(FeatureSummary) include(GNUInstallDirs) include(FetchContent) @@ -323,7 +327,7 @@ target_compile_options( $<$:-Wunused-exception-parameter> $<$:-Wmissing-variable-declarations> $<$:-Wnon-c-typedef-for-linkage> - $<$>:-Wdelete-non-virtual-dtor> + -Wdelete-non-virtual-dtor # disable warnings from -Wall and -Wextra -Wno-sign-compare -Wno-unused-function @@ -332,10 +336,11 @@ target_compile_options( $<$:-Wno-restrict> $<$:-Wno-clobbered> $<$:-Wno-cast-function-type> - $<$:-diag-disable=592> + $<$:-diag-disable=592> $<$:-Wno-gnu-zero-variadic-macro-arguments> - $<$>:-Wno-implicit-fallthrough> - $<$>:-Wno-unused-private-field> + $<$>:-Wno-implicit-fallthrough> + $<$>:-Wno-unused-private-field> + $<$,$>:-Wno-psabi> # warnings are errors $<$:-Werror>) @@ -347,34 +352,26 @@ if(ESPRESSO_BUILD_WITH_CUDA) -Wextra -Wno-sign-compare -Wno-unused-parameter - $<$>:-Wno-implicit-fallthrough> + $<$>:-Wno-implicit-fallthrough> # warnings are errors $<$,$>:--Werror=all-warnings> $<$,$>:-Werror> ) endif() -# disable warning from -Wextra on ARM processors -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_PROCESSOR MATCHES - "arm") - target_compile_options(espresso_cpp_flags INTERFACE -Wno-psabi) -endif() - # # Code coverage # -add_library(espresso_coverage_flags INTERFACE) -add_library(espresso::coverage_flags ALIAS espresso_coverage_flags) if(ESPRESSO_BUILD_WITH_COVERAGE) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options( - espresso_coverage_flags INTERFACE -g -fprofile-instr-generate - -fcoverage-mapping) + espresso_cpp_flags INTERFACE -g -fprofile-instr-generate + -fcoverage-mapping) else() - target_compile_options(espresso_coverage_flags INTERFACE -g --coverage - -fprofile-abs-path) - target_link_libraries(espresso_coverage_flags INTERFACE gcov) + target_compile_options(espresso_cpp_flags INTERFACE -g --coverage + -fprofile-abs-path) + target_link_libraries(espresso_cpp_flags INTERFACE gcov) endif() endif() @@ -423,8 +420,6 @@ if(ESPRESSO_BUILD_WITH_UBSAN) endif() endif() -target_link_libraries(espresso_cpp_flags INTERFACE espresso::coverage_flags) - # # Static analysis # @@ -630,6 +625,17 @@ endif() find_package(Boost 1.74.0 REQUIRED ${BOOST_COMPONENTS}) +# Patches for older Boost releases compiled with C++17 or above; while +# originally meant for MSVC, the Clang compiler is also affected. +# https://boost-users.boost.narkive.com/h2eXAUzU +# https://devblogs.microsoft.com/cppblog/c17-feature-removals-and-deprecations/ +# https://github.com/PixarAnimationStudios/OpenUSD/issues/2634 +target_compile_options( + espresso_cpp_flags + INTERFACE + $<$:-D_HAS_AUTO_PTR_ETC=0> + $<$:-DBOOST_NO_CXX98_FUNCTION_BASE>) + # enable boost::variant with more than 20 types target_compile_options( espresso_cpp_flags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS diff --git a/src/core/bond_breakage/actions.hpp b/src/core/bond_breakage/actions.hpp index 4e5e0352d8..cfdabc9f36 100644 --- a/src/core/bond_breakage/actions.hpp +++ b/src/core/bond_breakage/actions.hpp @@ -39,12 +39,8 @@ struct DeleteBond { boost::hash_combine(seed, bond_type); return seed; } - bool operator==(DeleteBond const &rhs) const { - return rhs.particle_id == particle_id and - rhs.bond_partner_id == bond_partner_id and - rhs.bond_type == bond_type; - } - bool operator!=(DeleteBond const &rhs) const { return not(*this == rhs); } + bool operator==(DeleteBond const &) const = default; + bool operator!=(DeleteBond const &) const = default; }; struct DeleteAngleBond { @@ -58,14 +54,8 @@ struct DeleteAngleBond { boost::hash_combine(seed, bond_type); return seed; } - bool operator==(DeleteAngleBond const &rhs) const { - return rhs.particle_id == particle_id and - rhs.bond_partner_id == bond_partner_id and - rhs.bond_type == bond_type; - } - bool operator!=(DeleteAngleBond const &rhs) const { - return not(*this == rhs); - } + bool operator==(DeleteAngleBond const &) const = default; + bool operator!=(DeleteAngleBond const &) const = default; }; struct DeleteAllBonds { @@ -77,11 +67,8 @@ struct DeleteAllBonds { boost::hash_combine(seed, particle_id_2); return seed; } - bool operator==(DeleteAllBonds const &rhs) const { - return rhs.particle_id_1 == particle_id_1 and - rhs.particle_id_2 == particle_id_2; - } - bool operator!=(DeleteAllBonds const &rhs) const { return not(*this == rhs); } + bool operator==(DeleteAllBonds const &) const = default; + bool operator!=(DeleteAllBonds const &) const = default; }; } // namespace BondBreakage diff --git a/src/python/espressomd/CMakeLists.txt b/src/python/espressomd/CMakeLists.txt index 36996be03a..633fa73cc8 100644 --- a/src/python/espressomd/CMakeLists.txt +++ b/src/python/espressomd/CMakeLists.txt @@ -48,10 +48,10 @@ add_library(espresso::pyx_flags ALIAS espresso_pyx_flags) target_compile_options( espresso_pyx_flags INTERFACE - $<$>:-Wno-pedantic> - $<$>:-Wno-cast-qual> - $<$>:-Wno-deprecated-declarations> - $<$:-diag-disable=1224> + $<$>:-Wno-pedantic> + $<$>:-Wno-cast-qual> + $<$>:-Wno-deprecated-declarations> + $<$:-diag-disable=1224> $<$:-Wno-cpp> $<$:-Wno-strict-aliasing> $<$:-Wno-maybe-uninitialized> diff --git a/src/script_interface/walberla/EKSpecies.hpp b/src/script_interface/walberla/EKSpecies.hpp index 0075ef7677..8199eff52f 100644 --- a/src/script_interface/walberla/EKSpecies.hpp +++ b/src/script_interface/walberla/EKSpecies.hpp @@ -42,7 +42,13 @@ namespace ScriptInterface::walberla { -class EKVTKHandle; +class EKVTKHandle : public VTKHandleBase<::EKinWalberlaBase> { + static std::unordered_map const obs_map; + + std::unordered_map const &get_obs_map() const override { + return obs_map; + } +}; class EKSpecies : public LatticeModel<::EKinWalberlaBase, EKVTKHandle> { protected: @@ -156,14 +162,6 @@ class EKSpecies : public LatticeModel<::EKinWalberlaBase, EKVTKHandle> { void save_checkpoint(std::string const &filename, int mode); }; -class EKVTKHandle : public VTKHandleBase<::EKinWalberlaBase> { - static std::unordered_map const obs_map; - - std::unordered_map const &get_obs_map() const override { - return obs_map; - } -}; - } // namespace ScriptInterface::walberla #endif // WALBERLA diff --git a/src/script_interface/walberla/LBFluid.hpp b/src/script_interface/walberla/LBFluid.hpp index d8a9fab22f..8da4753858 100644 --- a/src/script_interface/walberla/LBFluid.hpp +++ b/src/script_interface/walberla/LBFluid.hpp @@ -44,7 +44,13 @@ namespace ScriptInterface::walberla { -class LBVTKHandle; +class LBVTKHandle : public VTKHandleBase<::LBWalberlaBase> { + static std::unordered_map const obs_map; + + std::unordered_map const &get_obs_map() const override { + return obs_map; + } +}; class LBFluid : public LatticeModel<::LBWalberlaBase, LBVTKHandle> { protected: @@ -148,14 +154,6 @@ class LBFluidGPU : public LBFluid { }; #endif // CUDA -class LBVTKHandle : public VTKHandleBase<::LBWalberlaBase> { - static std::unordered_map const obs_map; - - std::unordered_map const &get_obs_map() const override { - return obs_map; - } -}; - } // namespace ScriptInterface::walberla #endif // WALBERLA From cb95fb99b35e9dcb54d8ddf35edb3ddb1b507dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Wed, 22 Jan 2025 16:16:20 +0100 Subject: [PATCH 3/4] Replace h5xx submodule by FetchContent --- .gitlab-ci.yml | 6 -- .gitmodules | 3 - CMakeLists.txt | 82 ++++++++++++++++++----- doc/sphinx/installation.rst | 29 ++------ libs/CMakeLists.txt | 23 +++++-- libs/h5xx | 1 - src/core/io/writer/CMakeLists.txt | 25 ++++--- src/core/io/writer/h5md_core.cpp | 29 ++++---- src/core/io/writer/h5md_core.hpp | 4 +- src/core/io/writer/h5md_specification.cpp | 3 +- src/core/io/writer/h5md_specification.hpp | 17 +++-- src/script_interface/h5md/CMakeLists.txt | 18 +++-- src/script_interface/h5md/h5md.hpp | 4 +- testsuite/python/h5md.py | 1 - 14 files changed, 153 insertions(+), 92 deletions(-) delete mode 160000 libs/h5xx diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 459293e192..741c73f29b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,6 @@ stages: - trying.tmp before_script: - git config --global --add safe.directory ${CI_PROJECT_DIR} - - git config --global --add safe.directory ${CI_PROJECT_DIR}/libs/h5xx timeout: 1h interruptible: true @@ -20,7 +19,6 @@ stages: <<: *global_job_definition image: ghcr.io/espressomd/docker/fedora:f7f8ef2c0ca93c67aa16b9f91785492fb04ecc1b variables: - GIT_SUBMODULE_STRATEGY: none GET_SOURCES_ATTEMPTS: 3 before_script: - git config --global --add safe.directory ${CI_PROJECT_DIR} @@ -32,7 +30,6 @@ stages: - no-cuda variables: - GIT_SUBMODULE_STRATEGY: recursive GET_SOURCES_ATTEMPTS: 3 CCACHE_DIR: /cache CCACHE_MAXSIZE: 100G @@ -49,14 +46,11 @@ style: dependencies: [] before_script: - git config --global --add safe.directory ${CI_PROJECT_DIR} - - git submodule deinit . script: - sh maintainer/CI/fix_style.sh tags: - espresso - no-cuda - variables: - GIT_SUBMODULE_STRATEGY: none artifacts: paths: - style.patch diff --git a/.gitmodules b/.gitmodules index 112a0edd3e..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "libs/h5xx"] - path = libs/h5xx - url = https://github.com/h5md/h5xx.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d1fc4920a..64f7ff7e13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2009-2022 The ESPResSo project +# Copyright (C) 2009-2025 The ESPResSo project # Copyright (C) 2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # @@ -109,6 +109,11 @@ FetchContent_Declare( GIT_REPOSITORY https://github.com/hmenke/espresso-stokesian-dynamics.git GIT_TAG 862a7537a366f0c32f0c25e46bd107bea590faea ) +FetchContent_Declare( + h5xx + GIT_REPOSITORY https://github.com/h5md/h5xx.git + GIT_TAG 0.9.1 +) FetchContent_Declare( caliper GIT_REPOSITORY https://github.com/LLNL/Caliper.git @@ -494,23 +499,68 @@ if(ESPRESSO_BUILD_WITH_HDF5) set(HDF5_FOUND FALSE) message(FATAL_ERROR "HDF5 parallel version not found.") endif() - endif() -endif() - -# Check for the h5xx submodule and try to check it out if not found or update it -# if found. -if(ESPRESSO_BUILD_WITH_HDF5 AND EXISTS "${CMAKE_SOURCE_DIR}/.git") - # Try to find git - find_package(Git) - if(GIT_FOUND) - if(NOT EXISTS "${CMAKE_SOURCE_DIR}/libs/h5xx/.git") - execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init -- - libs/h5xx WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - else() - execute_process(COMMAND ${GIT_EXECUTABLE} submodule update -- libs/h5xx - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + if(${HDF5_VERSION} VERSION_GREATER_EQUAL 1.13.0) + message( + WARNING + "Library hdf5 >= 1.13.0 is incompatible with h5xx 0.9.1 on some platforms (https://github.com/fhoefling/h5xx/issues/11)" + ) endif() endif() + # We need to define our own h5xx target, since the project version we depend + # on is not fully compatible with modern CMake. + FetchContent_GetProperties(h5xx) + if(NOT h5xx_POPULATED) + FetchContent_Populate(h5xx) + endif() + add_library(h5xx INTERFACE) + add_library(hdf5 INTERFACE) + target_link_libraries(hdf5 INTERFACE $) + target_include_directories(hdf5 + INTERFACE $) + target_include_directories(h5xx + INTERFACE $) + target_compile_features(h5xx INTERFACE cxx_std_11) + target_compile_definitions(h5xx INTERFACE H5XX_USE_MPI) + add_library(espresso_h5xx_cpp_flags INTERFACE) + add_library(espresso::h5xx_cpp_flags ALIAS espresso_h5xx_cpp_flags) + target_compile_options( + espresso_h5xx_cpp_flags + INTERFACE + $<$:-Wno-terminate> + $<$:-Wno-exceptions> + $<$:-Wno-unused-but-set-variable> + $<$:-Wno-delete-non-abstract-non-virtual-dtor> + ) + if(ESPRESSO_BUILD_WITH_CLANG_TIDY) + set(H5XX_CXX_CLANG_TIDY "${ESPRESSO_CXX_CLANG_TIDY}") + set(SKIP_CLANG_TIDY_CHECKS "") + set(SKIP_CLANG_TIDY_CHECKS_CXX "") + # silence hdf5 and h5xx diagnostics + list(APPEND SKIP_CLANG_TIDY_CHECKS "-clang-analyzer-deadcode.DeadStores") + list(APPEND SKIP_CLANG_TIDY_CHECKS + "-clang-analyzer-optin.performance.Padding") + list(APPEND SKIP_CLANG_TIDY_CHECKS + "-clang-diagnostic-unused-but-set-variable") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-clang-diagnostic-exceptions") + list(APPEND SKIP_CLANG_TIDY_CHECKS + "-bugprone-multi-level-implicit-pointer-conversion") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-assignment-in-if-condition") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-exception-escape") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-bugprone-narrowing-conversions") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-auto") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-nullptr") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-noexcept") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-override") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-use-equals-default") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-loop-convert") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-pass-by-value") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-modernize-redundant-void-arg") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-else-after-return") + list(APPEND SKIP_CLANG_TIDY_CHECKS "-readability-container-size-empty") + espresso_override_clang_tidy_checks( + H5XX_CXX_CLANG_TIDY "${SKIP_CLANG_TIDY_CHECKS}" + "${SKIP_CLANG_TIDY_CHECKS_CXX}") + endif() endif() if(ESPRESSO_BUILD_WITH_SCAFACOS) diff --git a/doc/sphinx/installation.rst b/doc/sphinx/installation.rst index adb639a6c5..142c96146c 100644 --- a/doc/sphinx/installation.rst +++ b/doc/sphinx/installation.rst @@ -886,28 +886,7 @@ external libraries that are downloaded automatically by CMake. When a network connection cannot be established due to firewall restrictions, the CMake logic needs editing. -.. _Git submodules without a network connection: - -Git submodules without a network connection -""""""""""""""""""""""""""""""""""""""""""" - -* ``ESPRESSO_BUILD_WITH_HDF5``: when cloning |es|, the :file:`libs/h5xx` folder - will be a git submodule containing a :file:`.git` subfolder. To prevent CMake - from updating this submodule with git, delete the corresponding command with: - - .. code-block:: bash - - sed -i '/execute_process(COMMAND ${GIT_EXECUTABLE} submodule update -- libs\/h5xx/,+1 d' CMakeLists.txt - - When installing a release version of |es|, no network communication - is needed for HDF5. - -.. _CMake subprojects without a network connection: - -CMake subprojects without a network connection -"""""""""""""""""""""""""""""""""""""""""""""" - -Several libraries are downloaded and included into the CMake project using +External libraries are downloaded and included into the CMake project using `FetchContent `__. The repository URLs can be found in the ``GIT_REPOSITORY`` field of the corresponding ``FetchContent_Declare()`` commands. The ``GIT_TAG`` field @@ -921,6 +900,12 @@ the clone. You can automate this task by adapting the following commands: sed -ri 's|GIT_REPOSITORY +.+/walberla.git|GIT_REPOSITORY /work/username/walberla|' CMakeLists.txt +* ``ESPRESSO_BUILD_WITH_HDF5`` + + .. code-block:: bash + + sed -ri 's|GIT_REPOSITORY +.+h5xx.git|GIT_REPOSITORY /work/username/h5xx|' CMakeLists.txt + * ``ESPRESSO_BUILD_WITH_STOKESIAN_DYNAMICS`` .. code-block:: bash diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 2e876e3dbb..69b851d4e8 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -1,8 +1,23 @@ +# +# Copyright (C) 2018-2025 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + add_library(Random123 INTERFACE) target_include_directories( Random123 SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/Random123-1.09/include) target_compile_definitions(Random123 INTERFACE R123_USE_MULHILO64_C99) - -add_library(h5xx INTERFACE) -target_include_directories(h5xx SYSTEM - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/h5xx) diff --git a/libs/h5xx b/libs/h5xx deleted file mode 160000 index 89d8d43587..0000000000 --- a/libs/h5xx +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 89d8d435872ec77dd931e709df98eefac8cbc925 diff --git a/src/core/io/writer/CMakeLists.txt b/src/core/io/writer/CMakeLists.txt index c1165a14ac..0ed250de40 100644 --- a/src/core/io/writer/CMakeLists.txt +++ b/src/core/io/writer/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2016-2022 The ESPResSo project +# Copyright (C) 2016-2025 The ESPResSo project # # This file is part of ESPResSo. # @@ -18,14 +18,17 @@ # if(ESPRESSO_BUILD_WITH_HDF5) - target_link_libraries(espresso_core PUBLIC ${HDF5_LIBRARIES} - Boost::filesystem h5xx) - target_include_directories(espresso_core PUBLIC ${CMAKE_CURRRENT_SOURCE_DIR} - ${HDF5_INCLUDE_DIRS}) - - target_compile_definitions(espresso_core PUBLIC H5XX_USE_MPI) - - target_sources( - espresso_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/h5md_core.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/h5md_specification.cpp) + add_library(espresso_hdf5 STATIC h5md_core.cpp h5md_specification.cpp) + add_library(espresso::hdf5 ALIAS espresso_hdf5) + if(ESPRESSO_BUILD_WITH_CLANG_TIDY) + set_target_properties(espresso_hdf5 PROPERTIES CXX_CLANG_TIDY + "${H5XX_CXX_CLANG_TIDY}") + endif() + target_include_directories(espresso_hdf5 PRIVATE ${CMAKE_SOURCE_DIR}/src/core) + target_link_libraries( + espresso_hdf5 + PRIVATE h5xx hdf5 espresso::cpp_flags espresso::h5xx_cpp_flags MPI::MPI_CXX + Boost::mpi Boost::filesystem espresso::utils espresso::config + espresso::instrumentation) + target_link_libraries(espresso_core PRIVATE espresso_hdf5) endif() diff --git a/src/core/io/writer/h5md_core.cpp b/src/core/io/writer/h5md_core.cpp index 54c7017f39..2cba43452e 100644 --- a/src/core/io/writer/h5md_core.cpp +++ b/src/core/io/writer/h5md_core.cpp @@ -30,7 +30,10 @@ #include +#include +#include #include +#include #include @@ -71,7 +74,7 @@ static void extend_dataset(h5xx::dataset &dataset, auto const rank = static_cast(dataset).rank(); auto extents = static_cast(dataset).extents(); /* Extend the dataset for another timestep */ - for (int i = 0; i < rank; i++) { + for (auto i = 0u; i < rank; i++) { extents[i] += change_extent[i]; } H5Dset_extent(dataset.hid(), extents.data()); // extend all dims is collective @@ -151,11 +154,11 @@ void File::create_groups() { static std::vector create_dims(hsize_t rank, hsize_t data_dim) { switch (rank) { - case 3: - return std::vector{0, 0, data_dim}; - case 2: - return std::vector{0, data_dim}; - case 1: + case 3ul: + return std::vector{0ul, 0ul, data_dim}; + case 2ul: + return std::vector{0ul, data_dim}; + case 1ul: return std::vector{data_dim}; default: throw std::runtime_error( @@ -164,13 +167,13 @@ static std::vector create_dims(hsize_t rank, hsize_t data_dim) { } static std::vector create_chunk_dims(hsize_t rank, hsize_t data_dim) { - hsize_t chunk_size = (rank > 1) ? 1000 : 1; + hsize_t chunk_size = (rank > 1ul) ? 1000ul : 1ul; switch (rank) { - case 3: - return {1, chunk_size, data_dim}; - case 2: - return {1, chunk_size}; - case 1: + case 3ul: + return {1ul, chunk_size, data_dim}; + case 2ul: + return {1ul, chunk_size}; + case 1ul: return {chunk_size}; default: throw std::runtime_error( @@ -200,7 +203,7 @@ void File::load_file(const std::string &file_path) { static void write_attributes(h5xx::file &h5md_file) { auto h5md_group = h5xx::group(h5md_file, "h5md"); h5xx::write_attribute(h5md_group, "version", - boost::array{{1, 1}}); + boost::array{{1ul, 1ul}}); auto h5md_creator_group = h5xx::group(h5md_group, "creator"); h5xx::write_attribute(h5md_creator_group, "name", "ESPResSo"); h5xx::write_attribute(h5md_creator_group, "version", ESPRESSO_VERSION); diff --git a/src/core/io/writer/h5md_core.hpp b/src/core/io/writer/h5md_core.hpp index ab4861b9ea..e6ee2c6433 100644 --- a/src/core/io/writer/h5md_core.hpp +++ b/src/core/io/writer/h5md_core.hpp @@ -19,8 +19,7 @@ * along with this program. If not, see . */ -#ifndef CORE_IO_WRITER_H5MD_CORE_HPP -#define CORE_IO_WRITER_H5MD_CORE_HPP +#pragma once #include "BoxGeometry.hpp" #include "ParticleRange.hpp" @@ -293,4 +292,3 @@ struct left_backupfile : public std::exception { } /* namespace H5md */ } /* namespace Writer */ -#endif diff --git a/src/core/io/writer/h5md_specification.cpp b/src/core/io/writer/h5md_specification.cpp index 9447225df6..4df53cc88e 100644 --- a/src/core/io/writer/h5md_specification.cpp +++ b/src/core/io/writer/h5md_specification.cpp @@ -21,7 +21,8 @@ #include "h5md_specification.hpp" #include "h5md_core.hpp" -#include "hdf5.h" + +#include #include diff --git a/src/core/io/writer/h5md_specification.hpp b/src/core/io/writer/h5md_specification.hpp index 8745548c91..c7277d35dc 100644 --- a/src/core/io/writer/h5md_specification.hpp +++ b/src/core/io/writer/h5md_specification.hpp @@ -18,8 +18,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef CORE_IO_WRITER_H5MD_SPECIFICATION_HPP -#define CORE_IO_WRITER_H5MD_SPECIFICATION_HPP + +#pragma once + +// guard for hdf5.h +#if not defined(_H5public_H) +#ifdef OMPI_SKIP_MPICXX +#undef OMPI_SKIP_MPICXX +#endif +#ifdef MPICH_SKIP_MPICXX +#undef MPICH_SKIP_MPICXX +#endif +#endif // not defined(_H5public_H) +#include #include @@ -73,5 +84,3 @@ struct H5MD_Specification { } // namespace H5md } // namespace Writer - -#endif diff --git a/src/script_interface/h5md/CMakeLists.txt b/src/script_interface/h5md/CMakeLists.txt index 2a3c363dac..ae798e5ef7 100644 --- a/src/script_interface/h5md/CMakeLists.txt +++ b/src/script_interface/h5md/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2020-2022 The ESPResSo project +# Copyright (C) 2020-2025 The ESPResSo project # # This file is part of ESPResSo. # @@ -18,7 +18,17 @@ # if(ESPRESSO_BUILD_WITH_HDF5) - target_sources( - espresso_script_interface PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/initialize.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/h5md.cpp) + add_library(espresso_si_hdf5 STATIC initialize.cpp h5md.cpp) + add_library(espresso::si_hdf5 ALIAS espresso_si_hdf5) + if(ESPRESSO_BUILD_WITH_CLANG_TIDY) + set_target_properties(espresso_si_hdf5 PROPERTIES CXX_CLANG_TIDY + "${H5XX_CXX_CLANG_TIDY}") + endif() + target_include_directories(espresso_si_hdf5 PRIVATE ${CMAKE_SOURCE_DIR}/src) + target_link_libraries( + espresso_si_hdf5 + PRIVATE h5xx hdf5 espresso::hdf5 espresso::cpp_flags + espresso::h5xx_cpp_flags espresso::core espresso::config + espresso::utils espresso::instrumentation) + target_link_libraries(espresso_script_interface PRIVATE espresso_si_hdf5) endif() diff --git a/src/script_interface/h5md/h5md.hpp b/src/script_interface/h5md/h5md.hpp index 6b7ed939fb..946cdbec0f 100644 --- a/src/script_interface/h5md/h5md.hpp +++ b/src/script_interface/h5md/h5md.hpp @@ -19,8 +19,7 @@ * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_SCRIPT_INTERFACE_H5MD_H5MD_HPP -#define ESPRESSO_SRC_SCRIPT_INTERFACE_H5MD_H5MD_HPP +#pragma once #include "config/config.hpp" @@ -86,4 +85,3 @@ class H5md : public AutoParameters { } // namespace ScriptInterface #endif // H5MD -#endif diff --git a/testsuite/python/h5md.py b/testsuite/python/h5md.py index 6fdbe90fd5..2ce61beda2 100644 --- a/testsuite/python/h5md.py +++ b/testsuite/python/h5md.py @@ -291,7 +291,6 @@ def test_bonds(self): self.assertEqual(bond[1], i + 1) def test_script(self): - assert sys.argv[0] == __file__ # case #1: running a pypresso script with open(sys.argv[0], 'r') as f: ref = f.read() From a4a31f284a081a3450301ad88c5a4a57044ddaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-No=C3=ABl=20Grad?= Date: Thu, 23 Jan 2025 21:40:34 +0100 Subject: [PATCH 4/4] Encapsulate HDF5 module Rewrite h5xx and hdf5 bindings such that they no longer propagate their compiler flags to the entire codebase. --- src/core/io/writer/CMakeLists.txt | 6 +- src/core/io/writer/h5md_core.cpp | 99 ++++++++++++++++------- src/core/io/writer/h5md_core.hpp | 33 +++----- src/core/io/writer/h5md_dataset.hpp | 45 +++++++++++ src/core/io/writer/h5md_specification.cpp | 27 ++++++- src/core/io/writer/h5md_specification.hpp | 48 ++--------- src/core/io/writer/hdf5_patches.hpp | 32 ++++++++ src/script_interface/h5md/CMakeLists.txt | 16 +--- src/script_interface/h5md/h5md.cpp | 42 +++++++++- src/script_interface/h5md/h5md.hpp | 47 +++-------- 10 files changed, 245 insertions(+), 150 deletions(-) create mode 100644 src/core/io/writer/h5md_dataset.hpp create mode 100644 src/core/io/writer/hdf5_patches.hpp diff --git a/src/core/io/writer/CMakeLists.txt b/src/core/io/writer/CMakeLists.txt index 0ed250de40..8184e947e5 100644 --- a/src/core/io/writer/CMakeLists.txt +++ b/src/core/io/writer/CMakeLists.txt @@ -18,7 +18,7 @@ # if(ESPRESSO_BUILD_WITH_HDF5) - add_library(espresso_hdf5 STATIC h5md_core.cpp h5md_specification.cpp) + add_library(espresso_hdf5 SHARED h5md_core.cpp h5md_specification.cpp) add_library(espresso::hdf5 ALIAS espresso_hdf5) if(ESPRESSO_BUILD_WITH_CLANG_TIDY) set_target_properties(espresso_hdf5 PROPERTIES CXX_CLANG_TIDY @@ -30,5 +30,7 @@ if(ESPRESSO_BUILD_WITH_HDF5) PRIVATE h5xx hdf5 espresso::cpp_flags espresso::h5xx_cpp_flags MPI::MPI_CXX Boost::mpi Boost::filesystem espresso::utils espresso::config espresso::instrumentation) - target_link_libraries(espresso_core PRIVATE espresso_hdf5) + target_link_libraries(espresso_core PUBLIC espresso_hdf5) + install(TARGETS espresso_hdf5 + LIBRARY DESTINATION ${ESPRESSO_INSTALL_PYTHON}/espressomd) endif() diff --git a/src/core/io/writer/h5md_core.cpp b/src/core/io/writer/h5md_core.cpp index 2cba43452e..ebe5d6643f 100644 --- a/src/core/io/writer/h5md_core.cpp +++ b/src/core/io/writer/h5md_core.cpp @@ -19,11 +19,14 @@ * along with this program. If not, see . */ +#include "hdf5_patches.hpp" // must appear first + #include "h5md_core.hpp" +#include "h5md_dataset.hpp" +#include "h5md_specification.hpp" #include "BoxGeometry.hpp" #include "Particle.hpp" -#include "h5md_specification.hpp" #include "lees_edwards/LeesEdwardsBC.hpp" #include "config/version.hpp" @@ -35,6 +38,8 @@ #include #include +#include + #include #include @@ -42,10 +47,16 @@ #include #include #include +#include #include #include #include +namespace h5xx { +template +struct is_array> : std::true_type {}; +} // namespace h5xx + namespace Writer { namespace H5md { @@ -138,17 +149,18 @@ void File::init_file(std::string const &file_path) { } void File::load_datasets() { - for (auto const &d : m_h5md_specification.get_datasets()) { - if (d.is_link) + auto &datasets = *m_datasets; + for (auto const &ds : m_h5md_specification.get_datasets()) { + if (ds.is_link) continue; - datasets[d.path()] = h5xx::dataset(m_h5md_file, d.path()); + datasets[ds.path()] = h5xx::dataset(*m_h5md_file, ds.path()); } } void File::create_groups() { - h5xx::group group(m_h5md_file); - for (auto const &d : m_h5md_specification.get_datasets()) { - h5xx::group new_group(group, d.group); + h5xx::group group(*m_h5md_file); + for (auto const &ds : m_h5md_specification.get_datasets()) { + h5xx::group new_group(group, ds.group); } } @@ -183,20 +195,23 @@ static std::vector create_chunk_dims(hsize_t rank, hsize_t data_dim) { void File::create_datasets() { namespace hps = h5xx::policy::storage; - for (const auto &d : m_h5md_specification.get_datasets()) { - if (d.is_link) + auto &datasets = *m_datasets; + for (auto const &ds : m_h5md_specification.get_datasets()) { + if (ds.is_link) continue; - auto maxdims = std::vector(d.rank, H5S_UNLIMITED); - auto dataspace = h5xx::dataspace(create_dims(d.rank, d.data_dim), maxdims); - auto storage = hps::chunked(create_chunk_dims(d.rank, d.data_dim)) + auto maxdims = std::vector(ds.rank, H5S_UNLIMITED); + auto dataspace = + h5xx::dataspace(create_dims(ds.rank, ds.data_dim), maxdims); + auto storage = hps::chunked(create_chunk_dims(ds.rank, ds.data_dim)) .set(hps::fill_value(-10)); - datasets[d.path()] = h5xx::dataset(m_h5md_file, d.path(), d.type, dataspace, - storage, H5P_DEFAULT, H5P_DEFAULT); + datasets[ds.path()] = + h5xx::dataset(*m_h5md_file, ds.path(), ds.type, dataspace, storage, + H5P_DEFAULT, H5P_DEFAULT); } } void File::load_file(const std::string &file_path) { - m_h5md_file = h5xx::file(file_path, m_comm, MPI_INFO_NULL, h5xx::file::out); + *m_h5md_file = h5xx::file(file_path, m_comm, MPI_INFO_NULL, h5xx::file::out); load_datasets(); } @@ -215,34 +230,36 @@ static void write_attributes(h5xx::file &h5md_file) { } void File::write_units() { + auto const &datasets = *m_datasets; if (!mass_unit().empty() and (m_fields & H5MD_OUT_MASS)) { - h5xx::write_attribute(datasets["particles/atoms/mass/value"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/mass/value"), "unit", mass_unit()); } if (!charge_unit().empty() and (m_fields & H5MD_OUT_CHARGE)) { - h5xx::write_attribute(datasets["particles/atoms/charge/value"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/charge/value"), "unit", charge_unit()); } if (!length_unit().empty() and (m_fields & H5MD_OUT_BOX_L)) { - h5xx::write_attribute(datasets["particles/atoms/position/value"], "unit", - length_unit()); - h5xx::write_attribute(datasets["particles/atoms/box/edges/value"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/position/value"), "unit", length_unit()); + h5xx::write_attribute(datasets.at("particles/atoms/box/edges/value"), + "unit", length_unit()); } if (!length_unit().empty() and (m_fields & H5MD_OUT_LE_OFF)) { - h5xx::write_attribute(datasets["particles/atoms/lees_edwards/offset/value"], - "unit", length_unit()); + h5xx::write_attribute( + datasets.at("particles/atoms/lees_edwards/offset/value"), "unit", + length_unit()); } if (!velocity_unit().empty() and (m_fields & H5MD_OUT_VEL)) { - h5xx::write_attribute(datasets["particles/atoms/velocity/value"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/velocity/value"), "unit", velocity_unit()); } if (!force_unit().empty() and (m_fields & H5MD_OUT_FORCE)) { - h5xx::write_attribute(datasets["particles/atoms/force/value"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/force/value"), "unit", force_unit()); } if (!time_unit().empty()) { - h5xx::write_attribute(datasets["particles/atoms/id/time"], "unit", + h5xx::write_attribute(datasets.at("particles/atoms/id/time"), "unit", time_unit()); } } @@ -259,7 +276,7 @@ void File::create_hard_links() { from = path_time.c_str(); } assert(from != nullptr); - if (H5Lcreate_hard(m_h5md_file.hid(), from, m_h5md_file.hid(), + if (H5Lcreate_hard(m_h5md_file->hid(), from, m_h5md_file->hid(), ds.path().c_str(), H5P_DEFAULT, H5P_DEFAULT) < 0) { throw std::runtime_error("Error creating hard link for " + ds.path()); } @@ -271,10 +288,11 @@ void File::create_file(const std::string &file_path) { if (m_comm.rank() == 0) write_script(file_path, m_absolute_script_path); m_comm.barrier(); - m_h5md_file = h5xx::file(file_path, m_comm, MPI_INFO_NULL, h5xx::file::out); + m_h5md_file = std::make_unique(file_path, m_comm, MPI_INFO_NULL, + h5xx::file::out); create_groups(); create_datasets(); - write_attributes(m_h5md_file); + write_attributes(*m_h5md_file); write_units(); create_hard_links(); } @@ -358,6 +376,7 @@ static void write_le_normal(LeesEdwardsBC const &lebc, h5xx::dataset &dataset) { void File::write(const ParticleRange &particles, double time, int step, BoxGeometry const &box_geo) { + auto &datasets = *m_datasets; if (m_fields & H5MD_OUT_BOX_L) { write_box(box_geo, datasets["particles/atoms/box/edges/value"]); } @@ -461,6 +480,7 @@ void File::write_connectivity(const ParticleRange &particles) { } auto const n_bonds_local = static_cast(bond.shape()[1]); + auto &datasets = *m_datasets; int prefix_bonds = 0; BOOST_MPI_CHECK_RESULT( MPI_Exscan, (&n_bonds_local, &prefix_bonds, 1, MPI_INT, MPI_SUM, m_comm)); @@ -478,7 +498,28 @@ void File::write_connectivity(const ParticleRange &particles) { offset_bonds, count_bonds); } -void File::flush() { m_h5md_file.flush(); } +void File::flush() { m_h5md_file->flush(); } + +std::string File::file_path() const { return m_h5md_file->name(); } + +File::File(std::string file_path, std::string script_path, + std::vector const &output_fields, std::string mass_unit, + std::string length_unit, std::string time_unit, + std::string force_unit, std::string velocity_unit, + std::string charge_unit) + : m_script_path(std::move(script_path)), m_mass_unit(std::move(mass_unit)), + m_length_unit(std::move(length_unit)), m_time_unit(std::move(time_unit)), + m_force_unit(std::move(force_unit)), + m_velocity_unit(std::move(velocity_unit)), + m_charge_unit(std::move(charge_unit)), m_comm(boost::mpi::communicator()), + m_fields(fields_list_to_bitfield(output_fields)), + m_h5md_file(std::make_unique()), + m_datasets(std::make_unique()), + m_h5md_specification(m_fields) { + init_file(file_path); +} + +File::~File() = default; } /* namespace H5md */ } /* namespace Writer */ diff --git a/src/core/io/writer/h5md_core.hpp b/src/core/io/writer/h5md_core.hpp index e6ee2c6433..2e73c83b79 100644 --- a/src/core/io/writer/h5md_core.hpp +++ b/src/core/io/writer/h5md_core.hpp @@ -30,9 +30,8 @@ #include #include -#include - #include +#include #include #include #include @@ -40,8 +39,8 @@ #include namespace h5xx { -template -struct is_array> : std::true_type {}; +class file; +class dataset; } // namespace h5xx namespace Writer { @@ -88,7 +87,7 @@ static std::unordered_map const fields_map = { inline auto fields_list_to_bitfield(std::vector const &fields) { unsigned int bitfield = H5MD_OUT_NONE; for (auto const &field_name : fields) { - if (fields_map.count(field_name) == 0) { + if (not fields_map.contains(field_name)) { throw std::invalid_argument("Unknown field '" + field_name + "'"); } bitfield |= fields_map.at(field_name); @@ -112,24 +111,12 @@ class File { * @param force_unit The unit for force. * @param velocity_unit The unit for velocity. * @param charge_unit The unit for charge. - * @param comm The MPI communicator. */ File(std::string file_path, std::string script_path, std::vector const &output_fields, std::string mass_unit, std::string length_unit, std::string time_unit, std::string force_unit, - std::string velocity_unit, std::string charge_unit, - boost::mpi::communicator comm = boost::mpi::communicator()) - : m_script_path(std::move(script_path)), - m_mass_unit(std::move(mass_unit)), - m_length_unit(std::move(length_unit)), - m_time_unit(std::move(time_unit)), m_force_unit(std::move(force_unit)), - m_velocity_unit(std::move(velocity_unit)), - m_charge_unit(std::move(charge_unit)), m_comm(std::move(comm)), - m_fields(fields_list_to_bitfield(output_fields)), - m_h5md_specification(m_fields) { - init_file(file_path); - } - ~File() = default; + std::string velocity_unit, std::string charge_unit); + ~File(); /** * @brief Method to perform the renaming of the temporary file from @@ -151,7 +138,7 @@ class File { * @brief Retrieve the path to the hdf5 file. * @return The path as a string. */ - auto file_path() const { return m_h5md_file.name(); } + std::string file_path() const; /** * @brief Retrieve the path to the simulation script. @@ -272,9 +259,9 @@ class File { unsigned int m_fields; std::string m_backup_filename; boost::filesystem::path m_absolute_script_path; - h5xx::file m_h5md_file; - std::unordered_map datasets; - H5MD_Specification m_h5md_specification; + std::unique_ptr m_h5md_file; + std::unique_ptr> m_datasets; + Specification m_h5md_specification; }; struct incompatible_h5mdfile : public std::exception { diff --git a/src/core/io/writer/h5md_dataset.hpp b/src/core/io/writer/h5md_dataset.hpp new file mode 100644 index 0000000000..b1b3b1aaaf --- /dev/null +++ b/src/core/io/writer/h5md_dataset.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010-2025 The ESPResSo project + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + * Max-Planck-Institute for Polymer Research, Theory Group + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "hdf5_patches.hpp" + +#include + +#include + +namespace Writer { +namespace H5md { + +struct Dataset { + std::string path() const { return group + "/" + name; } + + std::string group; + std::string name; + hsize_t rank; + hid_t type; + hsize_t data_dim; + bool is_link; +}; + +} // namespace H5md +} // namespace Writer diff --git a/src/core/io/writer/h5md_specification.cpp b/src/core/io/writer/h5md_specification.cpp index 4df53cc88e..50bf5d781e 100644 --- a/src/core/io/writer/h5md_specification.cpp +++ b/src/core/io/writer/h5md_specification.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022 The ESPResSo project + * Copyright (C) 2010-2025 The ESPResSo project * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 * Max-Planck-Institute for Polymer Research, Theory Group * @@ -19,17 +19,24 @@ * along with this program. If not, see . */ -#include "h5md_specification.hpp" +#include "hdf5_patches.hpp" // must appear first + #include "h5md_core.hpp" +#include "h5md_dataset.hpp" +#include "h5md_specification.hpp" + +#include #include +#include +#include #include namespace Writer { namespace H5md { -H5MD_Specification::H5MD_Specification(unsigned int fields) { +Specification::Specification(unsigned int fields) { auto const add_time_series = [this](Dataset &&dataset, bool link = true) { auto const group = dataset.group; m_datasets.push_back(std::move(dataset)); @@ -89,5 +96,19 @@ H5MD_Specification::H5MD_Specification(unsigned int fields) { } } +bool Specification::is_compliant(std::string const &filename) const { + h5xx::file h5md_file(filename, h5xx::file::in); + + auto const all_groups_exist = + std::ranges::all_of(m_datasets, [&h5md_file](auto const &d) { + return h5xx::exists_group(h5md_file, d.group); + }); + auto const all_datasets_exist = + std::ranges::all_of(m_datasets, [&h5md_file](auto const &d) { + return h5xx::exists_dataset(h5md_file, d.path()); + }); + return all_groups_exist and all_datasets_exist; +} + } // namespace H5md } // namespace Writer diff --git a/src/core/io/writer/h5md_specification.hpp b/src/core/io/writer/h5md_specification.hpp index c7277d35dc..5713da857f 100644 --- a/src/core/io/writer/h5md_specification.hpp +++ b/src/core/io/writer/h5md_specification.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022 The ESPResSo project + * Copyright (C) 2010-2025 The ESPResSo project * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 * Max-Planck-Institute for Polymer Research, Theory Group * @@ -21,62 +21,26 @@ #pragma once -// guard for hdf5.h -#if not defined(_H5public_H) -#ifdef OMPI_SKIP_MPICXX -#undef OMPI_SKIP_MPICXX -#endif -#ifdef MPICH_SKIP_MPICXX -#undef MPICH_SKIP_MPICXX -#endif -#endif // not defined(_H5public_H) -#include - -#include - -#include #include #include namespace Writer { namespace H5md { +struct Dataset; + /** * @brief Layout information for H5MD files. * In order to add a new particle property you have to add an entry to the * H5MD_Specification::DATASETS member and extend the File::write() and the * File::write_units() functions accordingly. */ -struct H5MD_Specification { - - struct Dataset { - std::string path() const { return group + "/" + name; } - - std::string group; - std::string name; - hsize_t rank; - hid_t type; - hsize_t data_dim; - bool is_link; - }; - - H5MD_Specification(unsigned int fields); +struct Specification { + Specification(unsigned int fields); auto const &get_datasets() const { return m_datasets; } - bool is_compliant(std::string const &filename) const { - h5xx::file h5md_file(filename, h5xx::file::in); - - auto const all_groups_exist = std::all_of( - m_datasets.begin(), m_datasets.end(), [&h5md_file](auto const &d) { - return h5xx::exists_group(h5md_file, d.group); - }); - auto const all_datasets_exist = std::all_of( - m_datasets.begin(), m_datasets.end(), [&h5md_file](auto const &d) { - return h5xx::exists_dataset(h5md_file, d.path()); - }); - return all_groups_exist and all_datasets_exist; - } + bool is_compliant(std::string const &filename) const; private: std::vector m_datasets; diff --git a/src/core/io/writer/hdf5_patches.hpp b/src/core/io/writer/hdf5_patches.hpp new file mode 100644 index 0000000000..edae3dc126 --- /dev/null +++ b/src/core/io/writer/hdf5_patches.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +// guard for hdf5.h +#if not defined(_H5public_H) +#ifdef OMPI_SKIP_MPICXX +#undef OMPI_SKIP_MPICXX +#endif +#ifdef MPICH_SKIP_MPICXX +#undef MPICH_SKIP_MPICXX +#endif +#endif // not defined(_H5public_H) + +#include diff --git a/src/script_interface/h5md/CMakeLists.txt b/src/script_interface/h5md/CMakeLists.txt index ae798e5ef7..3713023e8d 100644 --- a/src/script_interface/h5md/CMakeLists.txt +++ b/src/script_interface/h5md/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2020-2025 The ESPResSo project +# Copyright (C) 2020-2022 The ESPResSo project # # This file is part of ESPResSo. # @@ -18,17 +18,5 @@ # if(ESPRESSO_BUILD_WITH_HDF5) - add_library(espresso_si_hdf5 STATIC initialize.cpp h5md.cpp) - add_library(espresso::si_hdf5 ALIAS espresso_si_hdf5) - if(ESPRESSO_BUILD_WITH_CLANG_TIDY) - set_target_properties(espresso_si_hdf5 PROPERTIES CXX_CLANG_TIDY - "${H5XX_CXX_CLANG_TIDY}") - endif() - target_include_directories(espresso_si_hdf5 PRIVATE ${CMAKE_SOURCE_DIR}/src) - target_link_libraries( - espresso_si_hdf5 - PRIVATE h5xx hdf5 espresso::hdf5 espresso::cpp_flags - espresso::h5xx_cpp_flags espresso::core espresso::config - espresso::utils espresso::instrumentation) - target_link_libraries(espresso_script_interface PRIVATE espresso_si_hdf5) + target_sources(espresso_script_interface PRIVATE initialize.cpp h5md.cpp) endif() diff --git a/src/script_interface/h5md/h5md.cpp b/src/script_interface/h5md/h5md.cpp index e3218ce870..81456e776b 100644 --- a/src/script_interface/h5md/h5md.cpp +++ b/src/script_interface/h5md/h5md.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022 The ESPResSo project + * Copyright (C) 2010-2025 The ESPResSo project * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 * Max-Planck-Institute for Polymer Research, Theory Group * @@ -25,15 +25,53 @@ #include "h5md.hpp" -#include "cell_system/CellStructure.hpp" +#include "core/MpiCallbacks.hpp" +#include "core/cell_system/CellStructure.hpp" +#include "core/communication.hpp" +#include "core/io/writer/h5md_core.hpp" #include "core/system/System.hpp" +#include #include #include +#include namespace ScriptInterface { namespace Writer { +H5md::H5md() { + add_parameters( + {{"file_path", m_h5md, &::Writer::H5md::File::file_path}, + {"script_path", m_h5md, &::Writer::H5md::File::script_path}, + {"fields", AutoParameter::read_only, + [this]() { return make_vector_of_variants(m_output_fields); }}, + {"mass_unit", m_h5md, &::Writer::H5md::File::mass_unit}, + {"length_unit", m_h5md, &::Writer::H5md::File::length_unit}, + {"time_unit", m_h5md, &::Writer::H5md::File::time_unit}, + {"force_unit", m_h5md, &::Writer::H5md::File::force_unit}, + {"velocity_unit", m_h5md, &::Writer::H5md::File::velocity_unit}, + {"charge_unit", m_h5md, &::Writer::H5md::File::charge_unit}}); +}; + +void H5md::do_construct(VariantMap const ¶ms) { + m_output_fields = get_value>(params, "fields"); + m_h5md = + make_shared_from_args<::Writer::H5md::File, std::string, std::string, + std::vector, std::string, std::string, + std::string, std::string, std::string, std::string>( + params, "file_path", "script_path", "fields", "mass_unit", + "length_unit", "time_unit", "force_unit", "velocity_unit", + "charge_unit"); + // MPI communicator is needed to close parallel file handles + m_mpi_env_lock = ::Communication::mpiCallbacksHandle()->share_mpi_env(); +} + +H5md::~H5md() { + m_h5md.reset(); + assert(m_h5md.use_count() == 0u); + m_mpi_env_lock.reset(); +} + Variant H5md::do_call_method(const std::string &name, const VariantMap ¶meters) { if (name == "write") { diff --git a/src/script_interface/h5md/h5md.hpp b/src/script_interface/h5md/h5md.hpp index 946cdbec0f..728158f61e 100644 --- a/src/script_interface/h5md/h5md.hpp +++ b/src/script_interface/h5md/h5md.hpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2022 The ESPResSo project + * Copyright (C) 2010-2025 The ESPResSo project * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 * Max-Planck-Institute for Polymer Research, Theory Group * @@ -25,57 +25,34 @@ #ifdef H5MD -#include "core/MpiCallbacks.hpp" -#include "core/communication.hpp" -#include "io/writer/h5md_core.hpp" - #include "script_interface/ScriptInterface.hpp" #include "script_interface/auto_parameters/AutoParameters.hpp" +#include + #include #include #include +namespace Writer::H5md { +class File; +} // namespace Writer::H5md + namespace ScriptInterface { namespace Writer { + class H5md : public AutoParameters { public: - H5md() { - add_parameters( - {{"file_path", m_h5md, &::Writer::H5md::File::file_path}, - {"script_path", m_h5md, &::Writer::H5md::File::script_path}, - {"fields", AutoParameter::read_only, - [this]() { return make_vector_of_variants(m_output_fields); }}, - {"mass_unit", m_h5md, &::Writer::H5md::File::mass_unit}, - {"length_unit", m_h5md, &::Writer::H5md::File::length_unit}, - {"time_unit", m_h5md, &::Writer::H5md::File::time_unit}, - {"force_unit", m_h5md, &::Writer::H5md::File::force_unit}, - {"velocity_unit", m_h5md, &::Writer::H5md::File::velocity_unit}, - {"charge_unit", m_h5md, &::Writer::H5md::File::charge_unit}}); - }; + H5md(); -private: Variant do_call_method(const std::string &name, const VariantMap ¶meters) override; - void do_construct(VariantMap const ¶ms) override { - m_output_fields = get_value>(params, "fields"); - m_h5md = make_shared_from_args<::Writer::H5md::File, std::string, - std::string, std::vector, - std::string, std::string, std::string, - std::string, std::string, std::string>( - params, "file_path", "script_path", "fields", "mass_unit", - "length_unit", "time_unit", "force_unit", "velocity_unit", - "charge_unit"); - // MPI communicator is needed to close parallel file handles - m_mpi_env_lock = ::Communication::mpiCallbacksHandle()->share_mpi_env(); - } + void do_construct(VariantMap const ¶ms) override; - ~H5md() override { - m_h5md.reset(); - m_mpi_env_lock.reset(); - } + ~H5md() override; +private: std::shared_ptr m_mpi_env_lock; std::shared_ptr<::Writer::H5md::File> m_h5md; std::vector m_output_fields;