diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4262c09075..82119873ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ exclude: '^share/openPMD/thirdParty' # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] @@ -66,7 +66,7 @@ repos: # clang-format v13 # to run manually, use .github/workflows/clang-format/clang-format.sh - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v16.0.6 + rev: v17.0.4 hooks: - id: clang-format # By default, the clang-format hook configures: @@ -80,7 +80,7 @@ repos: # Autoremoves unused Python imports - repo: https://github.com/hadialqattan/pycln - rev: v2.2.2 + rev: v2.3.0 hooks: - id: pycln name: pycln (python) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3aaad3b1b..a1bdfb4b62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -608,7 +608,6 @@ if(openPMD_HAVE_PYTHON) src/binding/python/BaseRecord.cpp src/binding/python/BaseRecordComponent.cpp src/binding/python/ChunkInfo.cpp - src/binding/python/Container.cpp src/binding/python/Dataset.cpp src/binding/python/Datatype.cpp src/binding/python/Error.cpp @@ -1356,17 +1355,22 @@ if(openPMD_BUILD_TESTING) add_test(NAME CLI.pipe.py COMMAND sh -c "${MPI_TEST_EXE} ${Python_EXECUTABLE} \ - ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ + ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ --infile ../samples/git-sample/data%T.h5 \ --outfile ../samples/git-sample/data%T.bp && \ \ ${MPI_TEST_EXE} ${Python_EXECUTABLE} \ - ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ + ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ + --infile ../samples/git-sample/data00000100.h5 \ + --outfile ../samples/git-sample/single_iteration.bp && \ + \ + ${MPI_TEST_EXE} ${Python_EXECUTABLE} \ + ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ --infile ../samples/git-sample/thetaMode/data%T.h5 \ --outfile ../samples/git-sample/thetaMode/data.bp && \ \ ${Python_EXECUTABLE} \ - ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ + ${openPMD_RUNTIME_OUTPUT_DIRECTORY}/openpmd-pipe \ --infile ../samples/git-sample/thetaMode/data.bp \ --outfile ../samples/git-sample/thetaMode/data%T.json \ " diff --git a/Dockerfile b/Dockerfile index 5f08b571c0..a6d1fcbfbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,8 +5,8 @@ FROM quay.io/pypa/manylinux2010_x86_64 as build-env # FROM quay.io/pypa/manylinux1_x86_64 as build-env ENV DEBIAN_FRONTEND noninteractive -# Python 3.8-3.11 via "38 39 311" -ARG PY_VERSIONS="38 39 310 311" +# Python 3.8-3.12 via "38 39 311 312" +ARG PY_VERSIONS="38 39 310 311 312" # static libs need relocatable symbols for linking to shared python lib ENV CFLAGS="-fPIC ${CFLAGS}" @@ -162,7 +162,7 @@ FROM debian:bullseye ENV DEBIAN_FRONTEND noninteractive COPY --from=build-env /wheelhouse/openPMD_api-*-cp311-cp311-manylinux2010_x86_64.whl . RUN apt-get update \ - && apt-get install -y --no-install-recommends python3.10 python3-distutils ca-certificates curl \ + && apt-get install -y --no-install-recommends python3.11 python3-distutils ca-certificates curl \ && rm -rf /var/lib/apt/lists/* RUN python3.11 --version \ && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \ @@ -172,6 +172,21 @@ RUN python3.11 -c "import openpmd_api as io; print(io.__version__); print RUN python3.11 -m openpmd_api.ls --help RUN openpmd-ls --help +# test in fresh env: Debian:Bullseye + Python 3.12 +FROM debian:bullseye +ENV DEBIAN_FRONTEND noninteractive +COPY --from=build-env /wheelhouse/openPMD_api-*-cp312-cp312-manylinux2010_x86_64.whl . +RUN apt-get update \ + && apt-get install -y --no-install-recommends python3.12 python3-distutils ca-certificates curl \ + && rm -rf /var/lib/apt/lists/* +RUN python3.12 --version \ + && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \ + && python3.12 get-pip.py \ + && python3.12 -m pip install openPMD_api-*-cp312-cp312-manylinux2010_x86_64.whl +RUN python3.12 -c "import openpmd_api as io; print(io.__version__); print(io.variants)" +RUN python3.12 -m openpmd_api.ls --help +RUN openpmd-ls --help + # copy binary artifacts (wheels) FROM quay.io/pypa/manylinux2010_x86_64 MAINTAINER Axel Huebl diff --git a/README.md b/README.md index a2983def96..5576107d83 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ while those can be built either with or without: Optional language bindings: * Python: - * Python 3.8 - 3.11 + * Python 3.8 - 3.12 * pybind11 2.11.1+ * numpy 1.15+ * mpi4py 2.1+ (optional, for MPI) @@ -195,7 +195,7 @@ python3 -m pip install openpmd-api If MPI-support shall be enabled, we always have to recompile: ```bash # optional: --user -python3 -m pip install -U pip setuptools wheel +python3 -m pip install -U pip packaging setuptools wheel python3 -m pip install -U cmake # optional: --user diff --git a/docs/requirements.txt b/docs/requirements.txt index 62f525b92c..9f3c2ba702 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -6,7 +6,7 @@ numpy>=1.15 pygments recommonmark scipy -sphinx>=5.3 +sphinx>=5.3,<7.2 sphinx-copybutton sphinx-design sphinx_rtd_theme>=1.1.1 diff --git a/docs/source/citation.rst b/docs/source/citation.rst index 2291d8a3a9..88c00133df 100644 --- a/docs/source/citation.rst +++ b/docs/source/citation.rst @@ -14,7 +14,7 @@ The most general reference to openPMD is: .. tip:: - Axel Huebl, Remi Lehe, Jean-Luc Vay, David P. Grote, Ivo F. Sbalzarini, Stephan Kuschel, David Sagan, Christopher Mayes, Frederic Perez, Fabian Koller, and Michael Bussmann. + Axel Huebl, Remi Lehe, Jean-Luc Vay, David P. Grote, Ivo F. Sbalzarini, Stephan Kuschel, David Sagan, Christopher Mayes, Frederic Perez, Fabian Koller, Franz Poeschel, Carsten Fortmann-Grote, Angel Ferran Pousa, Juncheng E, Maxence Thevenet and Michael Bussmann. *"openPMD: A meta data standard for particle and mesh based data,"* `DOI:10.5281/zenodo.591699 `_ (2015) @@ -33,6 +33,11 @@ The equivalent BibTeX code is: Mayes, Christopher and P{\'e}rez, Fr{\'e}d{\'e}ric and Koller, Fabian and + Poeschel, Franz and + Fortmann-Grote, Carsten and + Ferran Pousa, Angel and + E, Juncheng and + Th{\'e}venet, Maxence and Bussmann, Michael}, title = {{openPMD: A meta data standard for particle and mesh based data}}, year = 2015, diff --git a/docs/source/conf.py b/docs/source/conf.py index a97f5e03b1..668ef4c8ae 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,6 +17,7 @@ import subprocess from recommonmark.parser import CommonMarkParser +import sphinx_rtd_theme # import sys # sys.path.insert(0, os.path.abspath('.')) @@ -58,8 +59,6 @@ shell=True) if not on_rtd: - import sphinx_rtd_theme - html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Add any paths that contain templates here, relative to this directory. @@ -117,7 +116,9 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -# html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' + +numfig = True # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/source/dev/dependencies.rst b/docs/source/dev/dependencies.rst index cc66b85587..00629fc58a 100644 --- a/docs/source/dev/dependencies.rst +++ b/docs/source/dev/dependencies.rst @@ -39,7 +39,7 @@ Optional: language bindings * Python: - * Python 3.8 - 3.11 + * Python 3.8 - 3.12 * pybind11 2.11.1+ * numpy 1.15+ * mpi4py 2.1+ (optional, for MPI) diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index 48b9f6c3e9..a0268a2a99 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -101,7 +101,7 @@ If MPI-support shall be enabled, we always have to recompile: .. code-block:: bash # optional: --user - python3 -m pip install -U pip setuptools wheel + python3 -m pip install -U pip packaging setuptools wheel python3 -m pip install -U cmake # optional: --user diff --git a/include/openPMD/DatatypeMacros.hpp b/include/openPMD/DatatypeMacros.hpp new file mode 100644 index 0000000000..aa78879aab --- /dev/null +++ b/include/openPMD/DatatypeMacros.hpp @@ -0,0 +1,113 @@ +/* Copyright 2023 Franz Poeschel + * + * This file is part of openPMD-api. + * + * openPMD-api is free software: you can redistribute it and/or modify + * it under the terms of of either the GNU General Public License or + * the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * openPMD-api 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with openPMD-api. + * If not, see . + */ +#pragma once + +#include +#include +#include + +// Need to alias this to avoid the comma +// Cannot use a namespace, otherwise the macro will work either only within +// or outside the namespace +// Defining macros means polluting the global namespace anyway +using openpmd_array_double_7 = std::array; + +#define OPENPMD_FOREACH_DATATYPE(MACRO) \ + MACRO(char) \ + MACRO(unsigned char) \ + MACRO(signed char) \ + MACRO(short) \ + MACRO(int) \ + MACRO(long) \ + MACRO(long long) \ + MACRO(unsigned short) \ + MACRO(unsigned int) \ + MACRO(unsigned long) \ + MACRO(unsigned long long) \ + MACRO(float) \ + MACRO(double) \ + MACRO(long double) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::string) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(std::vector>) \ + MACRO(std::vector>) \ + MACRO(std::vector>) \ + MACRO(std::vector) \ + MACRO(std::vector) \ + MACRO(openpmd_array_double_7) \ + MACRO(bool) + +#define OPENPMD_FOREACH_NONVECTOR_DATATYPE(MACRO) \ + MACRO(char) \ + MACRO(unsigned char) \ + MACRO(signed char) \ + MACRO(short) \ + MACRO(int) \ + MACRO(long) \ + MACRO(long long) \ + MACRO(unsigned short) \ + MACRO(unsigned int) \ + MACRO(unsigned long) \ + MACRO(unsigned long long) \ + MACRO(float) \ + MACRO(double) \ + MACRO(long double) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::string) \ + MACRO(array_double_7) \ + MACRO(bool) + +#define OPENPMD_FOREACH_DATASET_DATATYPE(MACRO) \ + MACRO(char) \ + MACRO(unsigned char) \ + MACRO(signed char) \ + MACRO(short) \ + MACRO(int) \ + MACRO(long) \ + MACRO(long long) \ + MACRO(unsigned short) \ + MACRO(unsigned int) \ + MACRO(unsigned long) \ + MACRO(unsigned long long) \ + MACRO(float) \ + MACRO(double) \ + MACRO(long double) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::complex) \ + MACRO(std::array) diff --git a/include/openPMD/UndefDatatypeMacros.hpp b/include/openPMD/UndefDatatypeMacros.hpp new file mode 100644 index 0000000000..f55303ca11 --- /dev/null +++ b/include/openPMD/UndefDatatypeMacros.hpp @@ -0,0 +1,24 @@ +/* Copyright 2023 Franz Poeschel + * + * This file is part of openPMD-api. + * + * openPMD-api is free software: you can redistribute it and/or modify + * it under the terms of of either the GNU General Public License or + * the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * openPMD-api 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser General Public License along with openPMD-api. + * If not, see . + */ + +#undef OPENPMD_FOREACH_DATATYPE +#undef OPENPMD_FOREACH_NONVECTOR_DATATYPE +#undef OPENPMD_FOREACH_DATASET_DATATYPE diff --git a/include/openPMD/auxiliary/UniquePtr.hpp b/include/openPMD/auxiliary/UniquePtr.hpp index 4b99f36790..6a64763b13 100644 --- a/include/openPMD/auxiliary/UniquePtr.hpp +++ b/include/openPMD/auxiliary/UniquePtr.hpp @@ -30,24 +30,14 @@ namespace auxiliary public: using deleter_type = std::function; - deleter_type const &get_deleter() const - { - return *this; - } - deleter_type &get_deleter() - { - return *this; - } - /* * Default constructor: Use std::default_delete. * This ensures correct destruction of arrays by using delete[]. */ CustomDelete() - : deleter_type{[](T_decayed *ptr) { + : deleter_type{[]([[maybe_unused]] T_decayed *ptr) { if constexpr (std::is_void_v) { - (void)ptr; std::cerr << "[Warning] Cannot standard-delete a void-type " "pointer. Please specify a custom destructor. " "Will let the memory leak." @@ -144,12 +134,25 @@ UniquePtrWithLambda::UniquePtrWithLambda(std::unique_ptr stdPtr) template template UniquePtrWithLambda::UniquePtrWithLambda(std::unique_ptr ptr) - : BasePtr{ - ptr.release(), - auxiliary::CustomDelete{ - [deleter = std::move(ptr.get_deleter())](T_decayed *del_ptr) { - deleter.get_deleter()(del_ptr); - }}} + : BasePtr{ptr.release(), auxiliary::CustomDelete{[&]() { + if constexpr (std::is_copy_constructible_v) + { + return [deleter = std::move(ptr.get_deleter())]( + T_decayed *del_ptr) { deleter(del_ptr); }; + } + else + { + /* + * The constructor of std::function requires a copyable + * lambda. Since Del is not a copyable type, we cannot + * capture it directly, but need to put it into a + * shared_ptr to make it copyable. + */ + return [deleter = std::make_shared( + std::move(ptr.get_deleter()))]( + T_decayed *del_ptr) { (*deleter)(del_ptr); }; + } + }()}} {} template @@ -170,7 +173,7 @@ UniquePtrWithLambda UniquePtrWithLambda::static_cast_() && return UniquePtrWithLambda{ static_cast(this->release()), [deleter = std::move(this->get_deleter())](other_type *ptr) { - deleter.get_deleter()(static_cast(ptr)); + deleter(static_cast(ptr)); }}; } } // namespace openPMD diff --git a/include/openPMD/backend/Attribute.hpp b/include/openPMD/backend/Attribute.hpp index b2cee727ae..c34d7c1847 100644 --- a/include/openPMD/backend/Attribute.hpp +++ b/include/openPMD/backend/Attribute.hpp @@ -21,6 +21,7 @@ #pragma once #include "openPMD/Datatype.hpp" +#include "openPMD/DatatypeMacros.hpp" #include "openPMD/auxiliary/TypeTraits.hpp" #include "openPMD/auxiliary/Variant.hpp" @@ -85,9 +86,9 @@ class Attribute std::vector, std::vector, std::vector, - std::vector >, - std::vector >, - std::vector >, + std::vector>, + std::vector>, + std::vector>, std::vector, std::vector, std::array, @@ -106,10 +107,15 @@ class Attribute * * Fix by explicitly instantiating resource */ - template - Attribute(T &&val) : Variant(resource(std::forward(val))) + +#define OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT(TYPE) \ + Attribute(TYPE val) : Variant(resource(std::move(val))) \ {} + OPENPMD_FOREACH_DATATYPE(OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT) + +#undef OPENPMD_ATTRIBUTE_CONSTRUCTOR_FROM_VARIANT + /** Retrieve a stored specific Attribute and cast if convertible. * * @note This performs a static_cast and might introduce precision loss if @@ -297,3 +303,5 @@ std::optional Attribute::getOptional() const std::move(eitherValueOrError)); } } // namespace openPMD + +#include "openPMD/UndefDatatypeMacros.hpp" diff --git a/src/binding/python/Container.cpp b/include/openPMD/binding/python/Container.H similarity index 80% rename from src/binding/python/Container.cpp rename to include/openPMD/binding/python/Container.H index ef0a194637..724d24c435 100644 --- a/src/binding/python/Container.cpp +++ b/include/openPMD/binding/python/Container.H @@ -23,6 +23,8 @@ * * BSD-style license, see pybind11 LICENSE file. */ +#pragma once + #include "openPMD/backend/Container.hpp" #include "openPMD/binding/python/Common.hpp" @@ -33,7 +35,7 @@ #include #include -namespace detail +namespace openPMD { /* based on std_bind.h in pybind11 * @@ -46,7 +48,7 @@ template < typename holder_type = std::unique_ptr, typename... Args> py::class_ -bind_container(py::handle scope, std::string const &name, Args &&...args) +declare_container(py::handle scope, std::string const &name, Args &&...args) { using KeyType = typename Map::key_type; using MappedType = typename Map::mapped_type; @@ -101,6 +103,19 @@ bind_container(py::handle scope, std::string const &name, Args &&...args) return stream.str(); }); + return cl; +} + +template < + typename Map, + typename holder_type = std::unique_ptr> +py::class_ +finalize_container(py::class_ cl) +{ + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = py::class_; + cl.def( "items", [](Map &m) { return py::make_iterator(m.begin(), m.end()); }, @@ -137,23 +152,4 @@ bind_container(py::handle scope, std::string const &name, Args &&...args) return cl; } -} // namespace detail - -void init_Container(py::module &m) -{ - ::detail::bind_container(m, "Iteration_Container"); - ::detail::bind_container(m, "Mesh_Container"); - ::detail::bind_container(m, "Particle_Container"); - ::detail::bind_container(m, "Particle_Patches_Container"); - ::detail::bind_container(m, "Record_Container"); - ::detail::bind_container( - m, "Patch_Record_Container"); - ::detail::bind_container( - m, "Record_Component_Container"); - ::detail::bind_container( - m, "Mesh_Record_Component_Container"); - ::detail::bind_container( - m, "Patch_Record_Component_Container"); - ::detail::bind_container( - m, "Base_Record_Component_Container"); -} +} // namespace openPMD diff --git a/pyproject.toml b/pyproject.toml index bbbc3636e5..0b739cebcc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ requires = [ "setuptools>=42", "wheel", "cmake>=3.15.0,<4.0.0", + "packaging>=23", "pybind11>=2.11.1,<3.0.0" ] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index 8d3a7e3348..2053f1bd22 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -from distutils.version import LooseVersion import os import platform import re @@ -17,6 +16,8 @@ def __init__(self, name, sourcedir=''): class CMakeBuild(build_ext): def run(self): + from packaging.version import parse + try: out = subprocess.check_output(['cmake', '--version']) except OSError: @@ -25,11 +26,11 @@ def run(self): "extensions: " + ", ".join(e.name for e in self.extensions)) - cmake_version = LooseVersion(re.search( + cmake_version = parse(re.search( r'version\s*([\d.]+)', out.decode() ).group(1)) - if cmake_version < '3.15.0': + if cmake_version < parse('3.15.0'): raise RuntimeError("CMake >= 3.15.0 is required") for ext in self.extensions: @@ -225,6 +226,7 @@ def build_extension(self, ext): 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', ('License :: OSI Approved :: ' 'GNU Lesser General Public License v3 or later (LGPLv3+)'), ], diff --git a/share/openPMD/thirdParty/pybind11/tools/pybind11Tools.cmake b/share/openPMD/thirdParty/pybind11/tools/pybind11Tools.cmake index 66ad00a478..48050966a4 100644 --- a/share/openPMD/thirdParty/pybind11/tools/pybind11Tools.cmake +++ b/share/openPMD/thirdParty/pybind11/tools/pybind11Tools.cmake @@ -43,7 +43,7 @@ endif() # A user can set versions manually too set(Python_ADDITIONAL_VERSIONS - "3.11;3.10;3.9;3.8;3.7;3.6" + "3.12;3.11;3.10;3.9;3.8" CACHE INTERNAL "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/src/Iteration.cpp b/src/Iteration.cpp index c3b8b27869..9e402f419d 100644 --- a/src/Iteration.cpp +++ b/src/Iteration.cpp @@ -592,7 +592,6 @@ void Iteration::readMeshes(std::string const &meshesPath) IOHandler()->flush(internal::defaultFlushParams); mrc.get().m_isConstant = true; } - m.read(); try { m.read(); diff --git a/src/ReadIterations.cpp b/src/ReadIterations.cpp index ed31886ffd..9457a22421 100644 --- a/src/ReadIterations.cpp +++ b/src/ReadIterations.cpp @@ -88,7 +88,20 @@ void SeriesIterator::initSeriesInLinearReadMode() case PP::UpFront: series.readGorVBased( /* do_always_throw_errors = */ false, /* init = */ true); - series.advance(AdvanceMode::BEGINSTEP); + /* + * In linear read mode (where no parsing at all is done upon + * constructing the Series), it might turn out after parsing + * that what we expected to be a group-based Series was in fact + * a single file of a file-based Series. + * (E.g. when opening "data00000100.h5" directly instead of + * "data%T.h5") + * So we need to check the current value of + * `iterationEncoding()` once more. + */ + if (series.iterationEncoding() != IterationEncoding::fileBased) + { + series.advance(AdvanceMode::BEGINSTEP); + } break; } data.parsePreference = *fOpen.out_parsePreference; diff --git a/src/binding/python/BaseRecord.cpp b/src/binding/python/BaseRecord.cpp index 7aeee2d38a..233ad90512 100644 --- a/src/binding/python/BaseRecord.cpp +++ b/src/binding/python/BaseRecord.cpp @@ -47,11 +47,13 @@ Returns true if this record only contains a single component. m, "Base_Record_Record_Component") .def_property_readonly( "scalar", &BaseRecord::scalar, doc_scalar); + py::class_< BaseRecord, Container >(m, "Base_Record_Mesh_Record_Component") .def_property_readonly( "scalar", &BaseRecord::scalar, doc_scalar); + py::class_< BaseRecord, Container >( diff --git a/src/binding/python/BaseRecordComponent.cpp b/src/binding/python/BaseRecordComponent.cpp index 95be596560..cf6f2d829c 100644 --- a/src/binding/python/BaseRecordComponent.cpp +++ b/src/binding/python/BaseRecordComponent.cpp @@ -22,12 +22,16 @@ #include "openPMD/Datatype.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" #include void init_BaseRecordComponent(py::module &m) { + auto py_brc_cont = declare_container( + m, "Base_Record_Component_Container"); + py::class_(m, "Base_Record_Component") .def( "__repr__", @@ -46,4 +50,6 @@ void init_BaseRecordComponent(py::module &m) .def_property_readonly("dtype", [](BaseRecordComponent &brc) { return dtype_to_numpy(brc.getDatatype()); }); + + finalize_container(py_brc_cont); } diff --git a/src/binding/python/Helper.cpp b/src/binding/python/Helper.cpp index e0aef84e0d..a7e6f209b4 100644 --- a/src/binding/python/Helper.cpp +++ b/src/binding/python/Helper.cpp @@ -38,7 +38,7 @@ void init_Helper(py::module &m) py::print(s.str()); }, py::arg("series"), - py::arg_v("longer", false, "Print more verbose output."), + py::arg("longer") = false, "List information about an openPMD data series") // CLI entry point .def( diff --git a/src/binding/python/Iteration.cpp b/src/binding/python/Iteration.cpp index 22e51aa974..a9dc2c23c8 100644 --- a/src/binding/python/Iteration.cpp +++ b/src/binding/python/Iteration.cpp @@ -21,6 +21,7 @@ #include "openPMD/Iteration.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include #include @@ -28,6 +29,9 @@ void init_Iteration(py::module &m) { + auto py_it_cont = + declare_container(m, "Iteration_Container"); + py::class_(m, "Iteration") .def(py::init()) @@ -93,4 +97,6 @@ void init_Iteration(py::module &m) py::return_value_policy::copy, // garbage collection: return value must be freed before Iteration py::keep_alive<1, 0>()); + + finalize_container(py_it_cont); } diff --git a/src/binding/python/Mesh.cpp b/src/binding/python/Mesh.cpp index e883e5e496..506e1bba70 100644 --- a/src/binding/python/Mesh.cpp +++ b/src/binding/python/Mesh.cpp @@ -23,6 +23,7 @@ #include "openPMD/backend/MeshRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" @@ -31,7 +32,17 @@ void init_Mesh(py::module &m) { + auto py_m_cont = declare_container(m, "Mesh_Container"); + py::class_ > cl(m, "Mesh"); + + py::enum_(m, "Geometry") // TODO: m -> cl + .value("cartesian", Mesh::Geometry::cartesian) + .value("thetaMode", Mesh::Geometry::thetaMode) + .value("cylindrical", Mesh::Geometry::cylindrical) + .value("spherical", Mesh::Geometry::spherical) + .value("other", Mesh::Geometry::other); + cl.def(py::init()) .def( @@ -107,10 +118,5 @@ void init_Mesh(py::module &m) return series.iterations[n_it].meshes[group.at(3)]; }); - py::enum_(m, "Geometry") - .value("cartesian", Mesh::Geometry::cartesian) - .value("thetaMode", Mesh::Geometry::thetaMode) - .value("cylindrical", Mesh::Geometry::cylindrical) - .value("spherical", Mesh::Geometry::spherical) - .value("other", Mesh::Geometry::other); + finalize_container(py_m_cont); } diff --git a/src/binding/python/MeshRecordComponent.cpp b/src/binding/python/MeshRecordComponent.cpp index 120fe00da2..e2e5e7b42a 100644 --- a/src/binding/python/MeshRecordComponent.cpp +++ b/src/binding/python/MeshRecordComponent.cpp @@ -24,6 +24,7 @@ #include "openPMD/Series.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include @@ -31,6 +32,9 @@ void init_MeshRecordComponent(py::module &m) { + auto py_mrc_cnt = declare_container( + m, "Mesh_Record_Component_Container"); + py::class_ cl( m, "Mesh_Record_Component"); cl.def( @@ -79,4 +83,6 @@ void init_MeshRecordComponent(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].meshes[group.at(3)][group.at(4)]; }); + + finalize_container(py_mrc_cnt); } diff --git a/src/binding/python/ParticlePatches.cpp b/src/binding/python/ParticlePatches.cpp index 326162191d..f04f36bf09 100644 --- a/src/binding/python/ParticlePatches.cpp +++ b/src/binding/python/ParticlePatches.cpp @@ -23,11 +23,15 @@ #include "openPMD/backend/PatchRecord.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include void init_ParticlePatches(py::module &m) { + auto py_pp_cnt = + declare_container(m, "Particle_Patches_Container"); + py::class_ >(m, "Particle_Patches") .def( "__repr__", @@ -40,4 +44,6 @@ void init_ParticlePatches(py::module &m) }) .def_property_readonly("num_patches", &ParticlePatches::numPatches); + + finalize_container(py_pp_cnt); } diff --git a/src/binding/python/ParticleSpecies.cpp b/src/binding/python/ParticleSpecies.cpp index 349ea8c689..7c3112029a 100644 --- a/src/binding/python/ParticleSpecies.cpp +++ b/src/binding/python/ParticleSpecies.cpp @@ -24,6 +24,7 @@ #include "openPMD/backend/Container.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include @@ -32,6 +33,9 @@ void init_ParticleSpecies(py::module &m) { + auto py_ps_cnt = + declare_container(m, "Particle_Container"); + py::class_ > cl(m, "ParticleSpecies"); cl.def( "__repr__", @@ -49,4 +53,6 @@ void init_ParticleSpecies(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].particles[group.at(3)]; }); + + finalize_container(py_ps_cnt); } diff --git a/src/binding/python/PatchRecord.cpp b/src/binding/python/PatchRecord.cpp index aaef39546c..efeea08a97 100644 --- a/src/binding/python/PatchRecord.cpp +++ b/src/binding/python/PatchRecord.cpp @@ -24,10 +24,14 @@ #include "openPMD/backend/PatchRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/UnitDimension.hpp" void init_PatchRecord(py::module &m) { + auto py_pr_cnt = + declare_container(m, "Patch_Record_Container"); + py::class_ >( m, "Patch_Record") .def_property( @@ -38,4 +42,6 @@ void init_PatchRecord(py::module &m) // TODO remove in future versions (deprecated) .def("set_unit_dimension", &PatchRecord::setUnitDimension); + + finalize_container(py_pr_cnt); } diff --git a/src/binding/python/PatchRecordComponent.cpp b/src/binding/python/PatchRecordComponent.cpp index e537f60538..33b04e733c 100644 --- a/src/binding/python/PatchRecordComponent.cpp +++ b/src/binding/python/PatchRecordComponent.cpp @@ -24,6 +24,7 @@ #include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" namespace @@ -42,6 +43,9 @@ struct Prc_Load void init_PatchRecordComponent(py::module &m) { + auto py_prc_cnt = declare_container( + m, "Patch_Record_Component_Container"); + py::class_( m, "Patch_Record_Component") .def_property( @@ -195,4 +199,6 @@ void init_PatchRecordComponent(py::module &m) // TODO remove in future versions (deprecated) .def("set_unit_SI", &PatchRecordComponent::setUnitSI); + + finalize_container(py_prc_cnt); } diff --git a/src/binding/python/Record.cpp b/src/binding/python/Record.cpp index d97641bbce..4b16088268 100644 --- a/src/binding/python/Record.cpp +++ b/src/binding/python/Record.cpp @@ -23,6 +23,7 @@ #include "openPMD/backend/BaseRecord.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" @@ -31,6 +32,8 @@ void init_Record(py::module &m) { + auto py_r_cnt = declare_container(m, "Record_Container"); + py::class_ > cl(m, "Record"); cl.def(py::init()) @@ -71,4 +74,6 @@ void init_Record(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].particles[group.at(3)][group.at(4)]; }); + + finalize_container(py_r_cnt); } diff --git a/src/binding/python/RecordComponent.cpp b/src/binding/python/RecordComponent.cpp index a9b1174389..9b8154e906 100644 --- a/src/binding/python/RecordComponent.cpp +++ b/src/binding/python/RecordComponent.cpp @@ -25,6 +25,7 @@ #include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" #include "openPMD/binding/python/Pickle.hpp" @@ -757,6 +758,9 @@ void init_RecordComponent(py::module &m) return view.currentView(); }); + auto py_rc_cnt = declare_container( + m, "Record_Component_Container"); + py::class_ cl(m, "Record_Component"); cl.def( "__repr__", @@ -1123,6 +1127,8 @@ void init_RecordComponent(py::module &m) .particles[group.at(3)][group.at(4)][group.at(5)]; }); + finalize_container(py_rc_cnt); + py::enum_(m, "Allocation") .value("USER", RecordComponent::Allocation::USER) .value("API", RecordComponent::Allocation::API) diff --git a/src/binding/python/Series.cpp b/src/binding/python/Series.cpp index 241e14d69f..1a163e3a4f 100644 --- a/src/binding/python/Series.cpp +++ b/src/binding/python/Series.cpp @@ -67,6 +67,9 @@ struct SeriesIteratorPythonAdaptor : SeriesIterator void init_Series(py::module &m) { + py::class_(m, "IndexedIteration") + .def_readonly("iteration_index", &IndexedIteration::iterationIndex); + py::class_(m, "WriteIterations", R"END( Writing side of the streaming API. @@ -100,8 +103,6 @@ not possible once it has been closed. &WriteIterations::currentIteration, "Return the iteration that is currently being written to, if it " "exists."); - py::class_(m, "IndexedIteration") - .def_readonly("iteration_index", &IndexedIteration::iterationIndex); py::class_(m, "SeriesIterator") .def( diff --git a/src/binding/python/openPMD.cpp b/src/binding/python/openPMD.cpp index 28b56b7d9c..da6ebb0ebd 100644 --- a/src/binding/python/openPMD.cpp +++ b/src/binding/python/openPMD.cpp @@ -33,7 +33,6 @@ void init_Attributable(py::module &); void init_BaseRecord(py::module &); void init_BaseRecordComponent(py::module &); void init_Chunk(py::module &m); -void init_Container(py::module &); void init_Dataset(py::module &); void init_Datatype(py::module &); void init_Error(py::module &); @@ -86,25 +85,29 @@ PYBIND11_MODULE(openpmd_api_cxx, m) init_UnitDimension(m); init_Attributable(m); init_Chunk(m); - init_Container(m); init_Error(m); - init_BaseRecord(m); - init_Dataset(m); + init_Datatype(m); - init_Helper(m); - init_Iteration(m); - init_IterationEncoding(m); - init_Mesh(m); + init_Dataset(m); + init_BaseRecordComponent(m); init_RecordComponent(m); init_MeshRecordComponent(m); - init_ParticlePatches(m); - init_PatchRecord(m); init_PatchRecordComponent(m); - init_ParticleSpecies(m); + + init_BaseRecord(m); init_Record(m); + init_PatchRecord(m); + init_ParticlePatches(m); + init_ParticleSpecies(m); + init_Mesh(m); + + init_Iteration(m); + init_IterationEncoding(m); init_Series(m); + init_Helper(m); + // API runtime version m.attr("__version__") = openPMD::getVersion(); diff --git a/src/binding/python/openpmd_api/pipe/__main__.py b/src/binding/python/openpmd_api/pipe/__main__.py index b3bcc6f068..f226bbb51a 100644 --- a/src/binding/python/openpmd_api/pipe/__main__.py +++ b/src/binding/python/openpmd_api/pipe/__main__.py @@ -245,19 +245,22 @@ def __copy(self, src, dest, current_path="/data/"): ignored_attributes = { io.Series: ["basePath", "iterationEncoding", "iterationFormat", "openPMD"], - io.Iteration: ["snapshot"] + io.Iteration: ["snapshot"], + io.Record_Component: ["value", "shape"] if isinstance( + src, io.Record_Component) and src.constant else [] } + # filter the map for relevant openpmd object model types + from itertools import chain + ignored_attributes = set(chain.from_iterable(value for ( + key, value) in ignored_attributes.items() if isinstance(src, key))) + for key in src.attributes: - ignore_this_attribute = False - for openpmd_group, to_ignore_list in ignored_attributes.items(): - if isinstance(src, openpmd_group): - for to_ignore in to_ignore_list: - if key == to_ignore: - ignore_this_attribute = True + ignore_this_attribute = key in ignored_attributes if not ignore_this_attribute: attr = src.get_attribute(key) attr_type = attribute_dtypes[key] dest.set_attribute(key, attr, attr_type) + container_types = [ io.Mesh_Container, io.Particle_Container, io.ParticleSpecies, io.Record, io.Mesh, io.Particle_Patches, io.Patch_Record diff --git a/test/CoreTest.cpp b/test/CoreTest.cpp index d660e29ec4..f6f93e065c 100644 --- a/test/CoreTest.cpp +++ b/test/CoreTest.cpp @@ -47,6 +47,14 @@ TEST_CASE("attribute_dtype_test", "[core]") { Attribute a = Attribute(static_cast(' ')); REQUIRE(Datatype::CHAR == a.dtype); + { + // check that copy constructor works + [[maybe_unused]] Attribute b = a; + } + { + // check that move constructor works + [[maybe_unused]] Attribute b = std::move(a); + } a = Attribute(static_cast(' ')); REQUIRE(Datatype::UCHAR == a.dtype); a = Attribute(static_cast(0)); diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp index c4e22d894c..814d1fef05 100644 --- a/test/SerialIOTest.cpp +++ b/test/SerialIOTest.cpp @@ -578,6 +578,29 @@ TEST_CASE("close_iteration_interleaved_test", "[serial]") } } +namespace detail +{ +template +struct CopyableDeleter : std::function +{ + CopyableDeleter() + : std::function{[](T const *ptr) { delete[] ptr; }} + {} +}; + +template +struct NonCopyableDeleter : std::function +{ + NonCopyableDeleter() + : std::function{[](T const *ptr) { delete[] ptr; }} + {} + NonCopyableDeleter(NonCopyableDeleter const &) = delete; + NonCopyableDeleter &operator=(NonCopyableDeleter const &) = delete; + NonCopyableDeleter(NonCopyableDeleter &&) = default; + NonCopyableDeleter &operator=(NonCopyableDeleter &&) = default; +}; +} // namespace detail + void close_and_copy_attributable_test(std::string const &file_ending) { using position_t = int; @@ -684,6 +707,27 @@ void close_and_copy_attributable_test(std::string const &file_ending) {0}, {global_extent}); + // UniquePtrWithLambda from unique_ptr with custom delete type + auto pos_v = electronPositions["v"]; + pos_v.resetDataset(dataset); + std::unique_ptr> + ptr_v_copyable_deleter(new int[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + pos_v.storeChunk( + UniquePtrWithLambda(std::move(ptr_v_copyable_deleter)), + {0}, + {global_extent}); + + // UniquePtrWithLambda from unique_ptr with non-copyable custom delete + // type + auto posOff_v = electronPositionsOffset["v"]; + posOff_v.resetDataset(dataset); + std::unique_ptr> + ptr_v_noncopyable_deleter(new int[10]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + posOff_v.storeChunk( + UniquePtrWithLambda(std::move(ptr_v_noncopyable_deleter)), + {0}, + {global_extent}); + iteration_ptr->close(); // force re-flush of previous iterations series.flush(); @@ -939,7 +983,7 @@ inline void constant_scalar(std::string const &file_ending) s.iterations[1] .meshes["rho"][MeshRecordComponent::SCALAR] .getAttribute("shape") - .get >() == Extent{1, 2, 3}); + .get>() == Extent{1, 2, 3}); REQUIRE(s.iterations[1] .meshes["rho"][MeshRecordComponent::SCALAR] .containsAttribute("value")); @@ -961,7 +1005,7 @@ inline void constant_scalar(std::string const &file_ending) s.iterations[1] .meshes["E"]["x"] .getAttribute("shape") - .get >() == Extent{1, 2, 3}); + .get>() == Extent{1, 2, 3}); REQUIRE(s.iterations[1].meshes["E"]["x"].containsAttribute("value")); REQUIRE( s.iterations[1] @@ -989,7 +1033,7 @@ inline void constant_scalar(std::string const &file_ending) s.iterations[1] .particles["e"]["position"][RecordComponent::SCALAR] .getAttribute("shape") - .get >() == Extent{3, 2, 1}); + .get>() == Extent{3, 2, 1}); REQUIRE(s.iterations[1] .particles["e"]["position"][RecordComponent::SCALAR] .containsAttribute("value")); @@ -1013,7 +1057,7 @@ inline void constant_scalar(std::string const &file_ending) s.iterations[1] .particles["e"]["positionOffset"][RecordComponent::SCALAR] .getAttribute("shape") - .get >() == Extent{3, 2, 1}); + .get>() == Extent{3, 2, 1}); REQUIRE(s.iterations[1] .particles["e"]["positionOffset"][RecordComponent::SCALAR] .containsAttribute("value")); @@ -1035,7 +1079,7 @@ inline void constant_scalar(std::string const &file_ending) s.iterations[1] .particles["e"]["velocity"]["x"] .getAttribute("shape") - .get >() == Extent{3, 2, 1}); + .get>() == Extent{3, 2, 1}); REQUIRE( s.iterations[1].particles["e"]["velocity"]["x"].containsAttribute( "value")); @@ -1387,55 +1431,55 @@ inline void dtype_test(const std::string &backend) REQUIRE(s.getAttribute("emptyString").get().empty()); } REQUIRE( - s.getAttribute("vecChar").get >() == + s.getAttribute("vecChar").get>() == std::vector({'c', 'h', 'a', 'r'})); REQUIRE( - s.getAttribute("vecInt16").get >() == + s.getAttribute("vecInt16").get>() == std::vector({32766, 32767})); REQUIRE( - s.getAttribute("vecInt32").get >() == + s.getAttribute("vecInt32").get>() == std::vector({2147483646, 2147483647})); REQUIRE( - s.getAttribute("vecInt64").get >() == + s.getAttribute("vecInt64").get>() == std::vector({9223372036854775806, 9223372036854775807})); REQUIRE( - s.getAttribute("vecUchar").get >() == + s.getAttribute("vecUchar").get>() == std::vector({'u', 'c', 'h', 'a', 'r'})); REQUIRE( - s.getAttribute("vecSchar").get >() == + s.getAttribute("vecSchar").get>() == std::vector({'s', 'c', 'h', 'a', 'r'})); REQUIRE( - s.getAttribute("vecUint16").get >() == + s.getAttribute("vecUint16").get>() == std::vector({65534u, 65535u})); REQUIRE( - s.getAttribute("vecUint32").get >() == + s.getAttribute("vecUint32").get>() == std::vector({4294967294u, 4294967295u})); REQUIRE( - s.getAttribute("vecUint64").get >() == + s.getAttribute("vecUint64").get>() == std::vector({18446744073709551614u, 18446744073709551615u})); REQUIRE( - s.getAttribute("vecFloat").get >() == + s.getAttribute("vecFloat").get>() == std::vector({0.f, 3.40282e+38f})); REQUIRE( - s.getAttribute("vecDouble").get >() == + s.getAttribute("vecDouble").get>() == std::vector({0., 1.79769e+308})); if (test_long_double) { REQUIRE( - s.getAttribute("vecLongdouble").get >() == + s.getAttribute("vecLongdouble").get>() == std::vector( {0.L, std::numeric_limits::max()})); } REQUIRE( - s.getAttribute("vecString").get >() == + s.getAttribute("vecString").get>() == std::vector({"vector", "of", "strings"})); if (!adios1) { REQUIRE( - s.getAttribute("vecEmptyString").get >() == + s.getAttribute("vecEmptyString").get>() == std::vector({"", "", ""})); REQUIRE( - s.getAttribute("vecMixedString").get >() == + s.getAttribute("vecMixedString").get>() == std::vector({"hi", "", "ho"})); } REQUIRE(s.getAttribute("bool").get() == true); @@ -1647,7 +1691,7 @@ void test_complex(const std::string &backend) "longDoublesYouSay", std::complex(5.5, -4.55)); auto Cflt = o.iterations[0].meshes["Cflt"][RecordComponent::SCALAR]; - std::vector > cfloats(3); + std::vector> cfloats(3); cfloats.at(0) = {1., 2.}; cfloats.at(1) = {-3., 4.}; cfloats.at(2) = {5., -6.}; @@ -1655,14 +1699,14 @@ void test_complex(const std::string &backend) Cflt.storeChunk(cfloats, {0}); auto Cdbl = o.iterations[0].meshes["Cdbl"][RecordComponent::SCALAR]; - std::vector > cdoubles(3); + std::vector> cdoubles(3); cdoubles.at(0) = {2., 1.}; cdoubles.at(1) = {-4., 3.}; cdoubles.at(2) = {6., -5.}; Cdbl.resetDataset(Dataset(Datatype::CDOUBLE, {cdoubles.size()})); Cdbl.storeChunk(cdoubles, {0}); - std::vector > cldoubles(3); + std::vector> cldoubles(3); if (o.backend() != "ADIOS2" && o.backend() != "ADIOS1" && o.backend() != "MPI_ADIOS1") { @@ -1683,26 +1727,26 @@ void test_complex(const std::string &backend) Series i = Series( "../samples/serial_write_complex." + backend, Access::READ_ONLY); REQUIRE( - i.getAttribute("lifeIsComplex").get >() == + i.getAttribute("lifeIsComplex").get>() == std::complex(4.56, 7.89)); REQUIRE( - i.getAttribute("butComplexFloats").get >() == + i.getAttribute("butComplexFloats").get>() == std::complex(42.3, -99.3)); if (i.backend() != "ADIOS2" && i.backend() != "ADIOS1" && i.backend() != "MPI_ADIOS1") { REQUIRE( i.getAttribute("longDoublesYouSay") - .get >() == + .get>() == std::complex(5.5, -4.55)); } auto rcflt = i.iterations[0] .meshes["Cflt"][RecordComponent::SCALAR] - .loadChunk >(); + .loadChunk>(); auto rcdbl = i.iterations[0] .meshes["Cdbl"][RecordComponent::SCALAR] - .loadChunk >(); + .loadChunk>(); i.flush(); REQUIRE(rcflt.get()[1] == std::complex(-3., 4.)); @@ -1713,7 +1757,7 @@ void test_complex(const std::string &backend) { auto rcldbl = i.iterations[0] .meshes["Cldbl"][RecordComponent::SCALAR] - .loadChunk >(); + .loadChunk>(); i.flush(); REQUIRE(rcldbl.get()[2] == std::complex(7., -6.)); } @@ -4956,7 +5000,7 @@ void bp4_steps( auto E_x = E["x"]; REQUIRE( E.getAttribute("vector_of_string") - .get >() == + .get>() == std::vector{"vector", "of", "string"}); REQUIRE(E_x.getDimensionality() == 1); REQUIRE(E_x.getExtent()[0] == 10); @@ -5190,7 +5234,7 @@ struct AreEqual }; template -struct AreEqual > +struct AreEqual> { static bool areEqual(std::vector v1, std::vector v2) {