diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93f8f1a694..ba9a620d40 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,7 +59,7 @@ openpmd_option(MPI "Parallel, Multi-Node I/O for clusters" AUTO)
openpmd_option(JSON "JSON backend (.json files)" AUTO)
openpmd_option(HDF5 "HDF5 backend (.h5 files)" AUTO)
openpmd_option(ADIOS1 "ADIOS1 backend (.bp files)" AUTO)
-openpmd_option(ADIOS2 "ADIOS2 backend (.bp files)" OFF)
+openpmd_option(ADIOS2 "ADIOS2 backend (.bp files)" AUTO)
openpmd_option(PYTHON "Enable Python bindings" AUTO)
option(openPMD_HAVE_PKGCONFIG "Generate a .pc file for pkg-config" ON)
@@ -341,7 +341,10 @@ set(IO_SOURCE
src/IO/HDF5/ParallelHDF5IOHandler.cpp
src/IO/JSON/JSONIOHandler.cpp
src/IO/JSON/JSONIOHandlerImpl.cpp
- src/IO/JSON/JSONFilePosition.cpp)
+ src/IO/JSON/JSONFilePosition.cpp
+ src/IO/ADIOS/ADIOS2IOHandler.cpp
+ src/IO/ADIOS/ADIOS2Auxiliary.cpp
+ src/IO/InvalidatableFile.cpp)
set(IO_ADIOS1_SEQUENTIAL_SOURCE
src/auxiliary/Filesystem.cpp
src/IO/ADIOS/ADIOS1IOHandler.cpp)
diff --git a/README.md b/README.md
index 0adb9aa08b..783a7b7cc7 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ Optional I/O backends:
* [JSON](https://en.wikipedia.org/wiki/JSON)
* [HDF5](https://support.hdfgroup.org/HDF5) 1.8.13+
* [ADIOS1](https://www.olcf.ornl.gov/center-projects/adios) 1.13.1+
-* [ADIOS2](https://github.com/ornladios/ADIOS2) 2.4.0+ (*not yet implemented*)
+* [ADIOS2](https://github.com/ornladios/ADIOS2) 2.4.0+
while those can be built either with or without:
* MPI 2.1+, e.g. OpenMPI 1.6.5+ or MPICH2
@@ -212,15 +212,14 @@ CMake controls options with prefixed `-D`, e.g. `-DopenPMD_USE_MPI=OFF`:
| `openPMD_USE_JSON` | **AUTO**/ON/OFF | JSON backend (`.json` files) |
| `openPMD_USE_HDF5` | **AUTO**/ON/OFF | HDF5 backend (`.h5` files) |
| `openPMD_USE_ADIOS1` | **AUTO**/ON/OFF | ADIOS1 backend (`.bp` files) |
-| `openPMD_USE_ADIOS2` | AUTO/ON/**OFF** | ADIOS2 backend (`.bp` files) 1 |
+| `openPMD_USE_ADIOS2` | **AUTO**/ON/OFF | ADIOS2 backend (`.bp` files) |
| `openPMD_USE_PYTHON` | **AUTO**/ON/OFF | Enable Python bindings |
-| `openPMD_USE_INVASIVE_TESTS` | ON/**OFF** | Enable unit tests that modify source code 2 |
-| `openPMD_USE_VERIFY` | **ON**/OFF | Enable internal VERIFY (assert) macro independent of build type 3 |
+| `openPMD_USE_INVASIVE_TESTS` | ON/**OFF** | Enable unit tests that modify source code 1 |
+| `openPMD_USE_VERIFY` | **ON**/OFF | Enable internal VERIFY (assert) macro independent of build type 2 |
| `PYTHON_EXECUTABLE` | (first found) | Path to Python executable |
-1 *not yet implemented*
-2 *e.g. changes C++ visibility keywords, breaks MSVC*
-3 *this includes most pre-/post-condition checks, disabling without specific cause is highly discouraged*
+1 *e.g. changes C++ visibility keywords, breaks MSVC*
+2 *this includes most pre-/post-condition checks, disabling without specific cause is highly discouraged*
Additionally, the following libraries are shipped internally.
The following options allow to switch to external installs:
diff --git a/docs/source/backends/adios2.rst b/docs/source/backends/adios2.rst
new file mode 100644
index 0000000000..28d2c3a221
--- /dev/null
+++ b/docs/source/backends/adios2.rst
@@ -0,0 +1,77 @@
+.. _backends-adios2:
+
+ADIOS2 Backend
+==============
+
+openPMD supports writing to and reading from ADIOS2 ``.bp`` files.
+For this, the installed copy of openPMD must have been built with support for the ADIOS2 backend.
+To build openPMD with support for ADIOS2, use the CMake option ``-DopenPMD_USE_ADIOS2=ON``.
+For further information, check out the :ref:`installation guide `,
+:ref:`build dependencies ` and the :ref:`build options `.
+
+
+I/O Method
+----------
+
+ADIOS2 has several engines for alternative file formats and other kinds of backends, yet natively writes to ``.bp`` files. At the moment, the openPMD API exclusively uses the BPFile engine.
+We currently leverage the default ADIOS2 transport parameters, i.e. ``POSIX`` on Unix systems and ``FStream`` on Windows.
+
+
+Backend-Specific Controls
+-------------------------
+
+The following environment variables control ADIOS2 I/O behavior at runtime.
+Fine-tuning these is especially useful when running at large scale.
+
+===================================== ======= ===================================================================
+environment variable default description
+===================================== ======= ===================================================================
+``OPENPMD_ADIOS2_HAVE_PROFILING`` ``1`` Turns on/off profiling information right after a run.
+``OPENPMD_ADIOS2_HAVE_METADATA_FILE`` ``1`` Online creation of the adios journal file (``1``: yes, ``0``: no).
+``OPENPMD_ADIOS2_NUM_SUBSTREAMS`` ``0`` Number of files to be created, 0 indicates maximum number possible.
+===================================== ======= ===================================================================
+
+Please refer to the `ADIOS2 manual, section 5.1 `_ for details.
+
+
+Best Practice at Large Scale
+----------------------------
+
+A good practice at scale is to disable the online creation of the metadata file.
+After writing the data, run ``bpmeta`` on the (to-be-created) filename to generate the metadata file offline (repeat per iteration for file-based encoding).
+This metadata file is needed for reading, while the actual heavy data resides in ``.dir/`` directories.
+Note that such a tool is not yet available for ADIOS2, but the ``bpmeta`` utility provided by ADIOS1 is capable of processing files written by ADIOS2.
+
+Further options depend heavily on filesystem type, specific file striping, network infrastructure and available RAM on the aggregator nodes.
+A good number for substreams is usually the number of contributing nodes divided by four.
+
+For fine-tuning at extreme scale or for exotic systems, please refer to the ADIOS2 manual and talk to your filesystem admins and the ADIOS2 authors.
+Be aware that extreme-scale I/O is a research topic after all.
+
+Selected References
+-------------------
+
+* Hasan Abbasi, Matthew Wolf, Greg Eisenhauer, Scott Klasky, Karsten Schwan, and Fang Zheng.
+ *Datastager: scalable data staging services for petascale applications,*
+ Cluster Computing, 13(3):277–290, 2010.
+ `DOI:10.1007/s10586-010-0135-6 `_
+
+* Ciprian Docan, Manish Parashar, and Scott Klasky.
+ *DataSpaces: An interaction and coordination framework or coupled simulation workflows,*
+ In Proc. of 19th International Symposium on High Performance and Distributed Computing (HPDC’10), June 2010.
+ `DOI:10.1007/s10586-011-0162-y `_
+
+* Qing Liu, Jeremy Logan, Yuan Tian, Hasan Abbasi, Norbert Podhorszki, Jong Youl Choi, Scott Klasky, Roselyne Tchoua, Jay Lofstead, Ron Oldfield, Manish Parashar, Nagiza Samatova, Karsten Schwan, Arie Shoshani, Matthew Wolf, Kesheng Wu, and Weikuan Yu.
+ *Hello ADIOS: the challenges and lessons of developing leadership class I/O frameworks,*
+ Concurrency and Computation: Practice and Experience, 26(7):1453–1473, 2014.
+ `DOI:10.1002/cpe.3125 `_
+
+* Robert McLay, Doug James, Si Liu, John Cazes, and William Barth.
+ *A user-friendly approach for tuning parallel file operations,*
+ In Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis, SC'14, pages 229–236, IEEE Press, 2014.
+ `DOI:10.1109/SC.2014.24 `_
+
+* Axel Huebl, Rene Widera, Felix Schmitt, Alexander Matthes, Norbert Podhorszki, Jong Youl Choi, Scott Klasky, and Michael Bussmann.
+ *On the Scalability of Data Reduction Techniques in Current and Upcoming HPC Systems from an Application Perspective,*
+ ISC High Performance 2017: High Performance Computing, pp. 15-29, 2017.
+ `arXiv:1706.00522 `_, `DOI:10.1007/978-3-319-67630-2_2 `_
diff --git a/docs/source/dev/buildoptions.rst b/docs/source/dev/buildoptions.rst
index 6fdd4cc90f..11160fe3f7 100644
--- a/docs/source/dev/buildoptions.rst
+++ b/docs/source/dev/buildoptions.rst
@@ -18,18 +18,16 @@ CMake Option Values Description
``openPMD_USE_JSON`` **AUTO**/ON/OFF JSON backend (``.json`` files)
``openPMD_USE_HDF5`` **AUTO**/ON/OFF HDF5 backend (``.h5`` files)
``openPMD_USE_ADIOS1`` **AUTO**/ON/OFF ADIOS1 backend (``.bp`` files)
-``openPMD_USE_ADIOS2`` AUTO/ON/**OFF** ADIOS2 backend (``.bp`` files) :sup:`1`
+``openPMD_USE_ADIOS2`` **AUTO**/ON/OFF ADIOS2 backend (``.bp`` files)
``openPMD_USE_PYTHON`` **AUTO**/ON/OFF Enable Python bindings
-``openPMD_USE_INVASIVE_TESTS`` ON/**OFF** Enable unit tests that modify source code :sup:`2`
-``openPMD_USE_VERIFY`` **ON**/OFF Enable internal VERIFY (assert) macro independent of build type :sup:`3`
+``openPMD_USE_INVASIVE_TESTS`` ON/**OFF** Enable unit tests that modify source code :sup:`1`
+``openPMD_USE_VERIFY`` **ON**/OFF Enable internal VERIFY (assert) macro independent of build type :sup:`2`
``PYTHON_EXECUTABLE`` (first found) Path to Python executable
============================== =============== ========================================================================
-:sup:`1` *not yet implemented*
+:sup:`1` e.g. changes C++ visibility keywords, breaks MSVC
-:sup:`2` e.g. changes C++ visibility keywords, breaks MSVC
-
-:sup:`3` this includes most pre-/post-condition checks, disabling without specific cause is highly discouraged
+:sup:`2` this includes most pre-/post-condition checks, disabling without specific cause is highly discouraged
Shared or Static
diff --git a/docs/source/dev/dependencies.rst b/docs/source/dev/dependencies.rst
index 2147a3ef7d..5808fdd946 100644
--- a/docs/source/dev/dependencies.rst
+++ b/docs/source/dev/dependencies.rst
@@ -30,7 +30,7 @@ Optional: I/O backends
* `JSON `_
* `HDF5 `_ 1.8.13+
* `ADIOS1 `_ 1.13.1+
-* `ADIOS2 `_ 2.4.0+ (*not yet implemented*)
+* `ADIOS2 `_ 2.4.0+
while those can be build either with or without:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 0698c77346..5117f13c67 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -95,6 +95,7 @@ Backends
backends/json
backends/adios1
+ backends/adios2
Utilities
---------
@@ -104,4 +105,3 @@ Utilities
:hidden:
utilities/benchmark.rst
-
diff --git a/include/openPMD/Datatype.hpp b/include/openPMD/Datatype.hpp
index 22d982114b..f89d25c12b 100644
--- a/include/openPMD/Datatype.hpp
+++ b/include/openPMD/Datatype.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller and Franz Poeschel
*
* This file is part of openPMD-api.
*
@@ -65,6 +65,13 @@ enum class Datatype : int
UNDEFINED
}; // Datatype
+/**
+ * @brief All openPMD datatypes defined in Datatype,
+ * listed in order in a vector.
+ *
+ */
+extern std::vector< Datatype > openPMD_Datatypes;
+
/** @brief Fundamental equivalence check for two given types T and U.
*
* This checks whether the fundamental datatype (i.e. that of a single value
@@ -524,6 +531,7 @@ isSame( openPMD::Datatype const d, openPMD::Datatype const e )
#else
#define OPENPMD_TEMPLATE_OPERATOR template operator
#endif
+
/**
* Generalizes switching over an openPMD datatype.
*
@@ -541,151 +549,161 @@ isSame( openPMD::Datatype const d, openPMD::Datatype const e )
* the passed arguments and the template parameter type corresponding to the
* openPMD type.
*/
-template<
- typename ReturnType = void,
- typename Action,
- typename ...Args
->
-ReturnType switchType(
- Datatype dt,
- Action action,
- Args && ...args
-) {
-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
- auto f = &Action::OPENPMD_TEMPLATE_OPERATOR() < int >;
- using fun = decltype(f);
-#else
- using fun = decltype( &Action::OPENPMD_TEMPLATE_OPERATOR() < int > );
-#endif
- static std::map<
- Datatype,
- fun
- > funs {
- {
- Datatype::CHAR ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < char > },
- {
- Datatype::UCHAR ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < unsigned char > },
- {
- Datatype::SHORT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < short > },
- {
- Datatype::INT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < int > },
- {
- Datatype::LONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < long > },
- {
- Datatype::LONGLONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < long long > },
- {
- Datatype::USHORT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < unsigned short > },
- {
- Datatype::UINT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < unsigned int > },
- {
- Datatype::ULONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < unsigned long > },
- {
- Datatype::ULONGLONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < unsigned long long > },
- {
- Datatype::FLOAT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < float > },
- {
- Datatype::DOUBLE ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < double > },
- {
- Datatype::LONG_DOUBLE ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < long double > },
- {
- Datatype::STRING ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::string > },
- {
- Datatype::VEC_CHAR ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< char>>
- },
- {
- Datatype::VEC_SHORT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< short>>
- },
- {
- Datatype::VEC_INT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< int>>
- },
- {
- Datatype::VEC_LONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< long>>
- },
- {
- Datatype::VEC_LONGLONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< long long>>
- },
- {
- Datatype::VEC_UCHAR ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< unsigned char>>
- },
- {
- Datatype::VEC_USHORT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< unsigned short>>
- },
- {
- Datatype::VEC_UINT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< unsigned int>>
- },
- {
- Datatype::VEC_ULONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< unsigned long>>
- },
- {
- Datatype::VEC_ULONGLONG ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< unsigned long long>>
- },
- {
- Datatype::VEC_FLOAT ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< float>>
- },
- {
- Datatype::VEC_DOUBLE ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< double>>
- },
- {
- Datatype::VEC_LONG_DOUBLE ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< long double>>
- },
- {
- Datatype::VEC_STRING ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::vector< std::string>>
- },
- {
- Datatype::ARR_DBL_7 ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < std::array<
- double,
- 7>>
- },
- {
- Datatype::BOOL ,
- &Action::OPENPMD_TEMPLATE_OPERATOR() < bool > }
- };
- auto it = funs.find( dt );
- if( it != funs.end( ) )
- {
- return ( ( action ).*
- ( it->second ) )( std::forward< Args >( args )... );
- }
- else
+template < typename ReturnType = void, typename Action, typename... Args >
+ReturnType switchType( Datatype dt, Action action, Args &&... args )
+{
+ switch ( dt )
{
+ case Datatype::CHAR:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< char >(
+ std::forward< Args >( args )... );
+ case Datatype::UCHAR:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< unsigned char >(
+ std::forward< Args >( args )... );
+ case Datatype::SHORT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< short >(
+ std::forward< Args >( args )... );
+ case Datatype::INT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< int >(
+ std::forward< Args >( args )... );
+ case Datatype::LONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< long >(
+ std::forward< Args >( args )... );
+ case Datatype::LONGLONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< long long >(
+ std::forward< Args >( args )... );
+ case Datatype::USHORT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< unsigned short >(
+ std::forward< Args >( args )... );
+ case Datatype::UINT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< unsigned int >(
+ std::forward< Args >( args )... );
+ case Datatype::ULONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< unsigned long >(
+ std::forward< Args >( args )... );
+ case Datatype::ULONGLONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< unsigned long long >(
+ std::forward< Args >( args )... );
+ case Datatype::FLOAT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< float >(
+ std::forward< Args >( args )... );
+ case Datatype::DOUBLE:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< double >(
+ std::forward< Args >( args )... );
+ case Datatype::LONG_DOUBLE:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< long double >(
+ std::forward< Args >( args )... );
+ case Datatype::STRING:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::string >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_CHAR:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< char > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_SHORT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< short > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_INT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< int > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_LONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< long > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_LONGLONG:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< long long > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_UCHAR:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< unsigned char > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_USHORT:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< unsigned short > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_UINT:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< unsigned int > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_ULONG:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< unsigned long > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_ULONGLONG:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< unsigned long long > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_FLOAT:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< float > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_DOUBLE:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::vector< double > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_LONG_DOUBLE:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< long double > >(
+ std::forward< Args >( args )... );
+ case Datatype::VEC_STRING:
+ return action
+ .OPENPMD_TEMPLATE_OPERATOR( )< std::vector< std::string > >(
+ std::forward< Args >( args )... );
+ case Datatype::ARR_DBL_7:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< std::array< double, 7 > >(
+ std::forward< Args >( args )... );
+ case Datatype::BOOL:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< bool >(
+ std::forward< Args >( args )... );
+ case Datatype::DATATYPE:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< 1000 >(
+ std::forward< Args >( args )... );
+ case Datatype::UNDEFINED:
+ return action.OPENPMD_TEMPLATE_OPERATOR( )< 0 >(
+ std::forward< Args >( args )... );
+ default:
throw std::runtime_error(
"Internal error: Encountered unknown datatype (switchType) ->" +
- std::to_string( static_cast(dt) )
- );
+ std::to_string( static_cast< int >( dt ) ) );
}
}
#undef OPENPMD_TEMPLATE_OPERATOR
+namespace detail {
+ template
+ struct BasicDatatypeHelper {
+ Datatype m_dt = determineDatatype();
+ };
+
+ template
+ struct BasicDatatypeHelper> {
+ Datatype m_dt = BasicDatatypeHelper{}.m_dt;
+ };
+
+ template
+ struct BasicDatatypeHelper> {
+ Datatype m_dt = BasicDatatypeHelper{}.m_dt;
+ };
+
+ struct BasicDatatype {
+ template
+ Datatype operator()();
+
+ template
+ Datatype operator()();
+ };
+}
+
+/**
+ * @brief basicDatatype Strip openPMD Datatype of std::vector, std::array et. al.
+ * @param dt The "full" Datatype.
+ * @return The "inner" Datatype.
+ */
+Datatype basicDatatype(Datatype dt);
+
+Datatype toVectorType(Datatype dt);
+
+std::string datatypeToString( Datatype dt );
+
+Datatype stringToDatatype( std::string s );
+
std::string datatypeToString( Datatype dt );
Datatype stringToDatatype( std::string s );
diff --git a/include/openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp b/include/openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp
new file mode 100644
index 0000000000..57f7728adf
--- /dev/null
+++ b/include/openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp
@@ -0,0 +1,119 @@
+/* Copyright 2017-2019 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 "openPMD/config.hpp"
+#if openPMD_HAVE_ADIOS2
+#include "openPMD/Datatype.hpp"
+#include
+#include
+#include
+
+namespace openPMD
+{
+namespace detail
+{
+ // ADIOS2 does not natively support boolean values
+ // Since we need them for attributes,
+ // we represent booleans as unsigned chars
+ using bool_representation = unsigned char;
+
+ template < typename T > struct ToDatatypeHelper
+ {
+ static std::string type( );
+ };
+
+ template < typename T > struct ToDatatypeHelper< std::vector< T > >
+ {
+ static std::string type( );
+ };
+
+ template < typename T, size_t n >
+ struct ToDatatypeHelper< std::array< T, n > >
+ {
+ static std::string type( );
+ };
+
+ template <> struct ToDatatypeHelper< bool >
+ {
+ static std::string type( );
+ };
+
+ struct ToDatatype
+ {
+ template < typename T > std::string operator( )( );
+
+
+ template < int n > std::string operator( )( );
+ };
+
+ /**
+ * @brief Convert ADIOS2 datatype to openPMD type.
+ * @param dt
+ * @return
+ */
+ Datatype fromADIOS2Type( std::string const & dt );
+
+ template < typename T > struct AttributeInfoHelper
+ {
+ static typename std::vector< T >::size_type
+ getSize( adios2::IO &, std::string const & attributeName );
+ };
+
+ template < typename T > struct AttributeInfoHelper< std::vector< T > >
+ {
+ static typename std::vector< T >::size_type
+ getSize( adios2::IO &, std::string const & attributeName );
+ };
+
+ template < typename T, std::size_t n >
+ struct AttributeInfoHelper< std::array< T, n > >
+ {
+ static typename std::vector< T >::size_type
+ getSize( adios2::IO & IO, std::string const & attributeName )
+ {
+ return AttributeInfoHelper< T >::getSize( IO, attributeName );
+ }
+ };
+
+ template <> struct AttributeInfoHelper< bool >
+ {
+ static typename std::vector< bool_representation >::size_type
+ getSize( adios2::IO &, std::string const & attributeName );
+ };
+
+ struct AttributeInfo
+ {
+ template < typename T >
+ typename std::vector< T >::size_type
+ operator( )( adios2::IO &, std::string const & attributeName );
+
+ template < int n, typename... Params >
+ size_t operator( )( Params &&... );
+ };
+
+ Datatype attributeInfo( adios2::IO &, std::string const & attributeName );
+} // namespace detail
+
+} // namespace openPMD
+
+#endif // openPMD_HAVE_ADIOS2
diff --git a/include/openPMD/IO/ADIOS/ADIOS2FilePosition.hpp b/include/openPMD/IO/ADIOS/ADIOS2FilePosition.hpp
index 012e7fc05e..c47315d910 100644
--- a/include/openPMD/IO/ADIOS/ADIOS2FilePosition.hpp
+++ b/include/openPMD/IO/ADIOS/ADIOS2FilePosition.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller and Franz Poeschel
*
* This file is part of openPMD-api.
*
@@ -20,14 +20,50 @@
*/
#pragma once
+
#include "openPMD/IO/AbstractFilePosition.hpp"
+#include
+#include
namespace openPMD
{
-struct ADIOS2FilePosition : public AbstractFilePosition
-{
- ADIOS2FilePosition()
- { }
-}; // ADIOS2FilePosition
+ struct ADIOS2FilePosition :
+ public AbstractFilePosition
+ {
+ enum class GD
+ {
+ GROUP,
+ DATASET
+ };
+
+
+ ADIOS2FilePosition(
+ std::string s,
+ GD groupOrDataset
+ ) :
+ location { std::move( s ) },
+ gd { groupOrDataset }
+ {}
+
+
+ explicit ADIOS2FilePosition( GD groupOrDataset ) :
+ ADIOS2FilePosition {
+ "/",
+ groupOrDataset
+ }
+ {}
+
+
+ ADIOS2FilePosition( ) :
+ ADIOS2FilePosition{ GD::GROUP }
+ {}
+
+
+ /**
+ * Convention: Starts with slash '/', ends without.
+ */
+ std::string location;
+ GD gd;
+ }; // ADIOS2FilePosition
} // openPMD
diff --git a/include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp b/include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp
index 696809ba03..54bc13fcd1 100644
--- a/include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp
+++ b/include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller and Franz Poeschel
*
* This file is part of openPMD-api.
*
@@ -21,64 +21,594 @@
#pragma once
#include "openPMD/config.hpp"
+
+#include "ADIOS2FilePosition.hpp"
#include "openPMD/IO/AbstractIOHandler.hpp"
+#include "openPMD/IO/AbstractIOHandlerImpl.hpp"
+#include "openPMD/IO/AbstractIOHandlerImplCommon.hpp"
+#include "openPMD/IO/IOTask.hpp"
+#include "openPMD/IO/InvalidatableFile.hpp"
+#include "openPMD/backend/Writable.hpp"
+#include
#include
-#include
+#include // shared_ptr
#include
+#include
+#include // pair
+#include
+
+
+#if openPMD_HAVE_ADIOS2
+# include
+# include "openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp"
+#endif
+
+#if openPMD_HAVE_MPI
+# include
+#endif
namespace openPMD
{
#if openPMD_HAVE_ADIOS2
+
class ADIOS2IOHandler;
+namespace detail
+{
+ template < typename, typename > struct DatasetHelper;
+ struct DatasetReader;
+ struct AttributeReader;
+ struct AttributeWriter;
+ template < typename > struct AttributeTypes;
+ struct DatasetOpener;
+ template < typename > struct DatasetTypes;
+ struct WriteDataset;
+ struct BufferedActions;
+ struct BufferedPut;
+ struct BufferedGet;
+ struct BufferedAttributeRead;
+} // namespace detail
+
+
class ADIOS2IOHandlerImpl
+: public AbstractIOHandlerImplCommon< ADIOS2FilePosition >
{
+ template < typename, typename > friend struct detail::DatasetHelper;
+ friend struct detail::DatasetReader;
+ friend struct detail::AttributeReader;
+ friend struct detail::AttributeWriter;
+ template < typename > friend struct detail::AttributeTypes;
+ friend struct detail::DatasetOpener;
+ template < typename > friend struct detail::DatasetTypes;
+ friend struct detail::WriteDataset;
+ friend struct detail::BufferedActions;
+ friend struct detail::BufferedAttributeRead;
+
+ static constexpr bool ADIOS2_DEBUG_MODE = false;
+
+
public:
- ADIOS2IOHandlerImpl(AbstractIOHandler*);
- virtual ~ADIOS2IOHandlerImpl();
-
- virtual std::future< void > flush();
-
- using ArgumentMap = std::map< std::string, ParameterArgument >;
- virtual void createFile(Writable*, ArgumentMap const&);
- virtual void createPath(Writable*, ArgumentMap const&);
- virtual void createDataset(Writable*, ArgumentMap const&);
- virtual void extendDataset(Writable*, ArgumentMap const&);
- virtual void openFile(Writable*, ArgumentMap const&);
- virtual void openPath(Writable*, ArgumentMap const&);
- virtual void openDataset(Writable*, ArgumentMap &);
- virtual void deleteFile(Writable*, ArgumentMap const&);
- virtual void deletePath(Writable*, ArgumentMap const&);
- virtual void deleteDataset(Writable*, ArgumentMap const&);
- virtual void deleteAttribute(Writable*, ArgumentMap const&);
- virtual void writeDataset(Writable*, ArgumentMap const&);
- virtual void writeAttribute(Writable*, ArgumentMap const&);
- virtual void readDataset(Writable*, ArgumentMap &);
- virtual void readAttribute(Writable*, ArgumentMap &);
- virtual void listPaths(Writable*, ArgumentMap &);
- virtual void listDatasets(Writable*, ArgumentMap &);
- virtual void listAttributes(Writable*, ArgumentMap &);
-
- AbstractIOHandler* m_handler;
-}; //ADIOS2IOHandlerImpl
-#else
-class ADIOS2IOHandlerImpl
-{ };
-#endif
+
+#if openPMD_HAVE_MPI
+
+ ADIOS2IOHandlerImpl( AbstractIOHandler *, MPI_Comm );
+
+ MPI_Comm m_comm;
+
+#endif // openPMD_HAVE_MPI
+
+ explicit ADIOS2IOHandlerImpl( AbstractIOHandler * );
+
+
+ ~ADIOS2IOHandlerImpl( ) override;
+
+ std::future< void > flush( ) override;
+
+ void createFile( Writable *,
+ Parameter< Operation::CREATE_FILE > const & ) override;
+
+ void createPath( Writable *,
+ Parameter< Operation::CREATE_PATH > const & ) override;
+
+ void
+ createDataset( Writable *,
+ Parameter< Operation::CREATE_DATASET > const & ) override;
+
+ void
+ extendDataset( Writable *,
+ Parameter< Operation::EXTEND_DATASET > const & ) override;
+
+ void openFile( Writable *,
+ Parameter< Operation::OPEN_FILE > const & ) override;
+
+ void openPath( Writable *,
+ Parameter< Operation::OPEN_PATH > const & ) override;
+
+ void openDataset( Writable *,
+ Parameter< Operation::OPEN_DATASET > & ) override;
+
+ void deleteFile( Writable *,
+ Parameter< Operation::DELETE_FILE > const & ) override;
+
+ void deletePath( Writable *,
+ Parameter< Operation::DELETE_PATH > const & ) override;
+
+ void
+ deleteDataset( Writable *,
+ Parameter< Operation::DELETE_DATASET > const & ) override;
+
+ void deleteAttribute( Writable *,
+ Parameter< Operation::DELETE_ATT > const & ) override;
+
+ void writeDataset( Writable *,
+ Parameter< Operation::WRITE_DATASET > const & ) override;
+
+ void writeAttribute( Writable *,
+ Parameter< Operation::WRITE_ATT > const & ) override;
+
+ void readDataset( Writable *,
+ Parameter< Operation::READ_DATASET > & ) override;
+
+ void readAttribute( Writable *,
+ Parameter< Operation::READ_ATT > & ) override;
+
+ void listPaths( Writable *, Parameter< Operation::LIST_PATHS > & ) override;
+
+ void listDatasets( Writable *,
+ Parameter< Operation::LIST_DATASETS > & ) override;
+
+ void
+ listAttributes( Writable *,
+ Parameter< Operation::LIST_ATTS > & parameters ) override;
+
+
+
+ /**
+ * @brief The ADIOS2 access type to chose for Engines opened
+ * within this instance.
+ */
+ adios2::Mode adios2Accesstype( );
+
+
+private:
+ adios2::ADIOS m_ADIOS;
+
+ /*
+ * We need to give names to IO objects. These names are irrelevant
+ * within this application, since:
+ * 1) The name of the file written to is decided by the opened Engine's
+ * name.
+ * 2) The IOs are managed by the unordered_map m_fileData, so we do not
+ * need the ADIOS2 internal management.
+ * Since within one m_ADIOS object, the same IO name cannot be used more
+ * than once, we ensure different names by using the name counter.
+ * This allows to overwrite a file later without error.
+ */
+ int nameCounter{0};
+
+ /*
+ * IO-heavy actions are deferred to a later point. This map stores for
+ * each open file (identified by an InvalidatableFile object) an object
+ * that manages IO-heavy actions, as well as its ADIOS2 objects, i.e.
+ * IO and Engine object.
+ * Not to be accessed directly, use getFileData().
+ */
+ std::unordered_map< InvalidatableFile,
+ std::unique_ptr< detail::BufferedActions >
+ > m_fileData;
+
+ std::map< std::string, adios2::Operator > m_operators;
+
+ // Overrides from AbstractIOHandlerImplCommon.
+
+ std::string
+ filePositionToString( std::shared_ptr< ADIOS2FilePosition > ) override;
+
+ std::shared_ptr< ADIOS2FilePosition >
+ extendFilePosition( std::shared_ptr< ADIOS2FilePosition > const & pos,
+ std::string extend ) override;
+
+ // Helper methods.
+
+ std::unique_ptr< adios2::Operator >
+ getCompressionOperator( std::string const & compression );
+
+ /*
+ * The name of the ADIOS2 variable associated with this Writable.
+ * To be used for Writables that represent a dataset.
+ */
+ std::string nameOfVariable( Writable * writable );
+
+ /**
+ * @brief nameOfAttribute
+ * @param The Writable at whose level the attribute lies.
+ * @param The openPMD name of the attribute.
+ * @return The ADIOS2 name of the attribute, consisting of
+ * the variable that the attribute is associated with
+ * (possibly the empty string, representing no variable)
+ * and the actual name.
+ */
+ std::string nameOfAttribute( Writable * writable, std::string attribute );
+
+ /*
+ * Figure out whether the Writable corresponds with a
+ * group or a dataset.
+ */
+ ADIOS2FilePosition::GD groupOrDataset( Writable * );
+
+ detail::BufferedActions & getFileData( InvalidatableFile file );
+
+ void dropFileData( InvalidatableFile file );
+
+ /*
+ * Prepare a variable that already exists for an IO
+ * operation, including:
+ * (1) checking that its datatype matches T.
+ * (2) the offset and extent match the variable's shape
+ * (3) setting the offset and extent (ADIOS lingo: start
+ * and count)
+ */
+ template < typename T >
+ adios2::Variable< T > verifyDataset( Offset const & offset,
+ Extent const & extent, adios2::IO & IO,
+ std::string const & var );
+}; // ADIOS2IOHandlerImpl
+
+namespace detail
+{
+ // Helper structs for calls to the switchType function
+
+ struct DatasetReader
+ {
+ openPMD::ADIOS2IOHandlerImpl * m_impl;
+
+
+ explicit DatasetReader( openPMD::ADIOS2IOHandlerImpl * impl );
+
+
+ template < typename T >
+ void operator( )( BufferedGet & bp, adios2::IO & IO,
+ adios2::Engine & engine,
+ std::string const & fileName );
+
+ template < int T, typename... Params > void operator( )( Params &&... );
+ };
+
+ struct AttributeReader
+ {
+ template < typename T >
+ Datatype operator( )( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource );
+
+ template < int n, typename... Params >
+ Datatype operator( )( Params &&... );
+ };
+
+ struct AttributeWriter
+ {
+ template < typename T >
+ void
+ operator( )( ADIOS2IOHandlerImpl * impl, Writable * writable,
+ const Parameter< Operation::WRITE_ATT > & parameters );
+
+
+ template < int n, typename... Params > void operator( )( Params &&... );
+ };
+
+ struct DatasetOpener
+ {
+ ADIOS2IOHandlerImpl * m_impl;
+
+
+ explicit DatasetOpener( ADIOS2IOHandlerImpl * impl );
+
+
+ template < typename T >
+ void operator( )( InvalidatableFile, const std::string & varName,
+ Parameter< Operation::OPEN_DATASET > & parameters );
+
+
+ template < int n, typename... Params > void operator( )( Params &&... );
+ };
+
+ struct WriteDataset
+ {
+ ADIOS2IOHandlerImpl * m_handlerImpl;
+
+
+ WriteDataset( ADIOS2IOHandlerImpl * handlerImpl );
+
+
+ template < typename T >
+ void operator( )( BufferedPut & bp, adios2::IO & IO,
+ adios2::Engine & engine );
+
+ template < int n, typename... Params > void operator( )( Params &&... );
+ };
+
+ struct VariableDefiner
+ {
+
+ template < typename T >
+ void operator( )( adios2::IO & IO, const std::string & name,
+ std::unique_ptr< adios2::Operator > compression,
+ const adios2::Dims & shape = adios2::Dims( ),
+ const adios2::Dims & start = adios2::Dims( ),
+ const adios2::Dims & count = adios2::Dims( ),
+ bool constantDims = false );
+
+ template < int n, typename... Params >
+ void operator( )( adios2::IO & IO, Params &&... );
+ };
+
+
+
+ // Helper structs to help distinguish valid attribute/variable
+ // datatypes from invalid ones
+
+
+ /*
+ * This struct's purpose is to have specialisations
+ * for vector and array types, as well as the boolean
+ * type (which is not natively supported by ADIOS).
+ */
+ template < typename T > struct AttributeTypes
+ {
+ using Attr = adios2::Attribute< T >;
+ using BasicType = T;
+
+ static Attr createAttribute( adios2::IO & IO, std::string name,
+ BasicType value );
+
+ static void
+ readAttribute( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource );
+ };
+
+ template < typename T > struct AttributeTypes< std::vector< T > >
+ {
+ using Attr = adios2::Attribute< T >;
+ using BasicType = T;
+
+ static Attr createAttribute( adios2::IO & IO, std::string name,
+ const std::vector< T > & value );
+
+ static void
+ readAttribute( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource );
+ };
+
+ template < typename T, size_t n >
+ struct AttributeTypes< std::array< T, n > >
+ {
+ using Attr = adios2::Attribute< T >;
+ using BasicType = T;
+
+ static Attr createAttribute( adios2::IO & IO, std::string name,
+ const std::array< T, n > & value );
+
+ static void
+ readAttribute( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource );
+ };
+
+ template <> struct AttributeTypes< bool >
+ {
+ using rep = detail::bool_representation;
+ using Attr = adios2::Attribute< rep >;
+ using BasicType = rep;
+
+ static Attr createAttribute( adios2::IO & IO, std::string name,
+ bool value );
+
+ static void
+ readAttribute( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource );
+
+
+ static constexpr rep toRep( bool b )
+ {
+ return b ? 1U : 0U;
+ }
+
+
+ static constexpr bool fromRep( rep r )
+ {
+ return r != 0;
+ }
+ };
+
+
+ /**
+ * This struct's only field indicates whether the template
+ * parameter is a valid datatype to use for a dataset
+ * (ADIOS2 variable).
+ */
+ template < typename T > struct DatasetTypes
+ {
+ static constexpr bool validType = true;
+ };
+
+ template < typename T > struct DatasetTypes< std::vector< T > >
+ {
+ static constexpr bool validType = false;
+ };
+
+ template <> struct DatasetTypes< bool >
+ {
+ static constexpr bool validType = false;
+ };
+
+
+ template < typename T, size_t n > struct DatasetTypes< std::array< T, n > >
+ {
+ static constexpr bool validType = false;
+ };
+
+ /*
+ * This struct's purpose is to have exactly two specialisations:
+ * (1) for types that are legal to use in a dataset
+ * (2) for types that are not legal to use in a dataset
+ * The methods in the latter specialisation will fail at runtime.
+ */
+ template < typename, typename = void > struct DatasetHelper;
+
+ template < typename T >
+ struct DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >
+ {
+ openPMD::ADIOS2IOHandlerImpl * m_impl;
+
+
+ explicit DatasetHelper( openPMD::ADIOS2IOHandlerImpl * impl );
+
+
+ void openDataset( InvalidatableFile, const std::string & varName,
+ Parameter< Operation::OPEN_DATASET > & parameters );
+
+ void readDataset( BufferedGet &, adios2::IO &, adios2::Engine &,
+ std::string const & fileName );
+
+ static void
+ defineVariable( adios2::IO & IO, const std::string & name,
+ std::unique_ptr< adios2::Operator > compression,
+ const adios2::Dims & shape, const adios2::Dims & start,
+ const adios2::Dims & count, bool constantDims );
+
+ void writeDataset( BufferedPut &, adios2::IO &, adios2::Engine & );
+ };
+
+ template < typename T >
+ struct DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >
+ {
+ explicit DatasetHelper( openPMD::ADIOS2IOHandlerImpl * impl );
+
+
+ static void throwErr( );
+
+ template < typename... Params > void openDataset( Params &&... );
+
+ template < typename... Params > void readDataset( Params &&... );
+
+ template < typename... Params >
+ static void defineVariable( Params &&... );
+
+ template < typename... Params > void writeDataset( Params &&... );
+ };
+
+ // Other datatypes used in the ADIOS2IOHandler implementation
+
+
+ struct BufferedActions;
+
+ /*
+ * IO-heavy action to be executed upon flushing.
+ */
+ struct BufferedAction
+ {
+ virtual ~BufferedAction( ) = default;
+
+ virtual void run( BufferedActions & ) = 0;
+ };
+
+ struct BufferedGet : BufferedAction
+ {
+ std::string name;
+ Parameter< Operation::READ_DATASET > param;
+
+ void run( BufferedActions & ) override;
+ };
+
+ struct BufferedPut : BufferedAction
+ {
+ std::string name;
+ Parameter< Operation::WRITE_DATASET > param;
+
+ void run( BufferedActions & ) override;
+ };
+
+ struct BufferedAttributeRead : BufferedAction
+ {
+ Parameter< Operation::READ_ATT > param;
+ std::string name;
+
+ void run( BufferedActions & ) override;
+ };
+
+ /*
+ * Manages per-file information about
+ * (1) the file's IO and Engine objects
+ * (2) the file's deferred IO-heavy actions
+ */
+ struct BufferedActions
+ {
+ BufferedActions( BufferedActions const & ) = delete;
+
+ std::string m_file;
+ adios2::IO m_IO;
+ std::vector< std::unique_ptr< BufferedAction > > m_buffer;
+ /**
+ * @brief std::optional would be more idiomatic, but it's not in
+ * the C++11 standard
+ * @todo replace with std::optional upon switching to C++17
+ */
+ std::unique_ptr< adios2::Engine > m_engine;
+ adios2::Mode m_mode;
+ detail::WriteDataset m_writeDataset;
+ detail::DatasetReader m_readDataset;
+ detail::AttributeReader m_attributeReader;
+ ADIOS2IOHandlerImpl & m_impl;
+
+
+ BufferedActions( ADIOS2IOHandlerImpl & impl, InvalidatableFile file );
+
+ ~BufferedActions( );
+
+ adios2::Engine & getEngine( );
+
+ template < typename BA > void enqueue( BA && ba );
+
+
+ void flush( );
+
+ /*
+ * Delete all buffered actions without running them.
+ */
+ void drop( );
+ };
+
+
+} // namespace detail
+#endif // openPMD_HAVE_ADIOS2
+
class ADIOS2IOHandler : public AbstractIOHandler
{
- friend class ADIOS2IOHandlerImpl;
+#if openPMD_HAVE_ADIOS2
+
+friend class ADIOS2IOHandlerImpl;
+
+private:
+ ADIOS2IOHandlerImpl m_impl;
public:
- ADIOS2IOHandler(std::string path, AccessType);
- ~ADIOS2IOHandler() override;
+ ~ADIOS2IOHandler( ) override;
- std::future< void > flush() override;
+#else
+public:
+#endif
-private:
- std::unique_ptr< ADIOS2IOHandlerImpl > m_impl;
-}; //ADIOS2IOHandler
-} // openPMD
+#if openPMD_HAVE_MPI
+
+ ADIOS2IOHandler( std::string path, AccessType, MPI_Comm );
+
+#endif
+
+ ADIOS2IOHandler( std::string path, AccessType );
+
+ std::future< void > flush( ) override;
+}; // ADIOS2IOHandler
+} // namespace openPMD
diff --git a/include/openPMD/IO/AbstractIOHandlerImplCommon.hpp b/include/openPMD/IO/AbstractIOHandlerImplCommon.hpp
new file mode 100644
index 0000000000..4a9a2ea4d5
--- /dev/null
+++ b/include/openPMD/IO/AbstractIOHandlerImplCommon.hpp
@@ -0,0 +1,259 @@
+/* Copyright 2018-2019 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 "openPMD/IO/AbstractFilePosition.hpp"
+#include "openPMD/IO/AbstractIOHandler.hpp"
+#include "openPMD/IO/AbstractIOHandlerImpl.hpp"
+#include "openPMD/IO/InvalidatableFile.hpp"
+#include "openPMD/auxiliary/StringManip.hpp"
+#include "openPMD/backend/Writable.hpp"
+
+#include
+#include
+
+
+
+namespace openPMD
+{
+template < typename FilePositionType = AbstractFilePosition >
+class AbstractIOHandlerImplCommon : public AbstractIOHandlerImpl
+{
+ // friend struct detail::BufferedActions;
+public:
+ explicit AbstractIOHandlerImplCommon( AbstractIOHandler * handler );
+
+ ~AbstractIOHandlerImplCommon( ) override;
+
+protected:
+ /**
+ * map each Writable to its associated file contains only the filename,
+ * without the OS path
+ */
+ std::unordered_map< Writable *, InvalidatableFile > m_files;
+ std::unordered_set< InvalidatableFile > m_dirty;
+
+ enum PossiblyExisting
+ {
+ PE_InvalidatableFile = 0,
+ PE_Iterator,
+ PE_NewlyCreated,
+ };
+
+ std::tuple< InvalidatableFile,
+ std::unordered_map< Writable *, InvalidatableFile >::iterator,
+ bool
+ > getPossiblyExisting( std::string file );
+
+ void associateWithFile( Writable * writable, InvalidatableFile file );
+
+ /**
+ *
+ * @return Full OS path of the file.
+ */
+ std::string fullPath( InvalidatableFile );
+
+ std::string fullPath( std::string );
+
+ /**
+ * Get the writable's containing file.
+ * @param writable The writable whose containing file to figure out.
+ * @return The containing file of the writable. If its parent is associated
+ * with another file, update the writable to match its parent and return
+ * the refreshed file.
+ */
+ InvalidatableFile refreshFileFromParent( Writable * writable );
+
+ /**
+ * Figure out the file position of the writable.
+ * Only modify the writable's fileposition when specified.
+ * @param writable The writable.
+ * @param write Whether to refresh the writable's file position.
+ * @return The current file position.
+ */
+ std::shared_ptr< FilePositionType >
+ setAndGetFilePosition( Writable * writable, bool write = true );
+
+ /**
+ * Figure out the file position of the writable and extend it.
+ * @param writable The writable.
+ * @param write The extension string.
+ * @return The current file position.
+ */
+ virtual std::shared_ptr< FilePositionType >
+ setAndGetFilePosition( Writable * writable, std::string extend );
+
+ /**
+ * @return A string representation of the file position.
+ */
+ virtual std::string
+ filePositionToString( std::shared_ptr< FilePositionType > ) = 0;
+
+ /**
+ * @return A new file position that is extended with the given string.
+ */
+ virtual std::shared_ptr< FilePositionType >
+ extendFilePosition( std::shared_ptr< FilePositionType > const &,
+ std::string ) = 0;
+};
+
+template < typename FilePositionType >
+AbstractIOHandlerImplCommon< FilePositionType >::AbstractIOHandlerImplCommon(
+ AbstractIOHandler * handler )
+: AbstractIOHandlerImpl{handler}
+{
+}
+
+
+template < typename FilePositionType >
+AbstractIOHandlerImplCommon<
+ FilePositionType >::~AbstractIOHandlerImplCommon( ) = default;
+
+
+template < typename FilePositionType >
+std::tuple< InvalidatableFile,
+ std::unordered_map< Writable *, InvalidatableFile >::iterator,
+ bool >
+AbstractIOHandlerImplCommon< FilePositionType >::getPossiblyExisting(
+ std::string file )
+{
+
+ auto it = std::find_if(
+ m_files.begin( ), m_files.end( ),
+ [file]( std::unordered_map<
+ Writable *, InvalidatableFile >::value_type const & entry ) {
+ return *entry.second == file && entry.second.valid( );
+ } );
+
+ bool newlyCreated;
+ InvalidatableFile name;
+ if ( it == m_files.end( ) )
+ {
+ name = file;
+ newlyCreated = true;
+ }
+ else
+ {
+ name = it->second;
+ newlyCreated = false;
+ }
+ return std::tuple<
+ InvalidatableFile,
+ std::unordered_map< Writable *, InvalidatableFile >::iterator, bool >(
+ std::move( name ), it, newlyCreated );
+}
+
+
+template < typename FilePositionType >
+void AbstractIOHandlerImplCommon< FilePositionType >::associateWithFile(
+ Writable * writable, InvalidatableFile file )
+{
+ // make sure to overwrite
+ m_files[writable] = std::move( file );
+}
+
+
+template < typename FilePositionType >
+std::string AbstractIOHandlerImplCommon< FilePositionType >::fullPath(
+ InvalidatableFile fileName )
+{
+ return fullPath( *fileName );
+}
+
+
+template < typename FilePositionType >
+std::string AbstractIOHandlerImplCommon< FilePositionType >::fullPath(
+ std::string fileName )
+{
+ if ( auxiliary::ends_with( m_handler->directory, "/" ) )
+ {
+ return m_handler->directory + fileName;
+ }
+ else
+ {
+ return m_handler->directory + "/" + fileName;
+ }
+}
+
+
+template < typename FilePositionType >
+InvalidatableFile
+AbstractIOHandlerImplCommon< FilePositionType >::refreshFileFromParent(
+ Writable * writable )
+{
+ if ( writable->parent )
+ {
+ auto file = m_files.find( writable->parent )->second;
+ associateWithFile( writable, file );
+ return file;
+ }
+ else
+ {
+ return m_files.find( writable )->second;
+ }
+}
+
+
+template < typename FilePositionType >
+std::shared_ptr< FilePositionType >
+AbstractIOHandlerImplCommon< FilePositionType >::setAndGetFilePosition(
+ Writable * writable, bool write )
+{
+ std::shared_ptr< AbstractFilePosition > res;
+
+ if ( writable->abstractFilePosition )
+ {
+ res = writable->abstractFilePosition;
+ }
+ else if ( writable->parent )
+ {
+ res = writable->parent->abstractFilePosition;
+ }
+ else
+ { // we are root
+ res = std::make_shared< FilePositionType >( );
+ }
+ if ( write )
+ {
+ writable->abstractFilePosition = res;
+ }
+ return std::dynamic_pointer_cast< FilePositionType >( res );
+}
+
+
+template < typename FilePositionType >
+std::shared_ptr< FilePositionType >
+AbstractIOHandlerImplCommon< FilePositionType >::setAndGetFilePosition(
+ Writable * writable, std::string extend )
+{
+ if ( !auxiliary::starts_with( extend, '/' ) )
+ {
+ extend = "/" + extend;
+ }
+ auto oldPos = setAndGetFilePosition( writable, false );
+ auto res = extendFilePosition( oldPos, extend );
+
+ writable->abstractFilePosition = res;
+ return res;
+}
+} // namespace openPMD
diff --git a/include/openPMD/IO/AccessType.hpp b/include/openPMD/IO/AccessType.hpp
index ab8b43533a..38e903a414 100644
--- a/include/openPMD/IO/AccessType.hpp
+++ b/include/openPMD/IO/AccessType.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller and Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/IO/IOTask.hpp b/include/openPMD/IO/IOTask.hpp
index 22bf2ae16d..0e2ba0ce19 100644
--- a/include/openPMD/IO/IOTask.hpp
+++ b/include/openPMD/IO/IOTask.hpp
@@ -301,10 +301,18 @@ template<>
struct EXPORT Parameter< Operation::WRITE_DATASET > : public AbstractParameter
{
Parameter() = default;
- Parameter(Parameter const & p) : AbstractParameter(),
+ Parameter(Parameter const & p) : AbstractParameter(),
extent(p.extent), offset(p.offset), dtype(p.dtype),
data(p.data) {};
+ Parameter& operator=(const Parameter& p) {
+ this->extent = p.extent;
+ this->offset = p.offset;
+ this->dtype = p.dtype;
+ this->data = p.data;
+ return *this;
+ }
+
std::unique_ptr< AbstractParameter >
clone() const override
{
@@ -322,10 +330,18 @@ template<>
struct EXPORT Parameter< Operation::READ_DATASET > : public AbstractParameter
{
Parameter() = default;
- Parameter(Parameter const & p) : AbstractParameter(),
+ Parameter(Parameter const & p) : AbstractParameter(),
extent(p.extent), offset(p.offset), dtype(p.dtype),
data(p.data) {};
+ Parameter& operator=(const Parameter &p) {
+ this->extent = p.extent;
+ this->offset = p.offset;
+ this->dtype = p.dtype;
+ this->data = p.data;
+ return *this;
+ }
+
std::unique_ptr< AbstractParameter >
clone() const override
{
@@ -399,6 +415,13 @@ struct EXPORT Parameter< Operation::READ_ATT > : public AbstractParameter
Parameter(Parameter const & p) : AbstractParameter(),
name(p.name), dtype(p.dtype), resource(p.resource) {};
+ Parameter& operator=(const Parameter &p) {
+ this->name = p.name;
+ this->dtype = p.dtype;
+ this->resource = p.resource;
+ return *this;
+ }
+
std::unique_ptr< AbstractParameter >
clone() const override
{
diff --git a/include/openPMD/IO/InvalidatableFile.hpp b/include/openPMD/IO/InvalidatableFile.hpp
new file mode 100644
index 0000000000..ea824a4276
--- /dev/null
+++ b/include/openPMD/IO/InvalidatableFile.hpp
@@ -0,0 +1,96 @@
+/* Copyright 2018-2019 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
+
+
+namespace openPMD
+{
+ /**
+ * Wrapper around a shared pointer to:
+ * * a filename
+ * * and a boolean indicating whether the file still exists
+ * The wrapper adds no extra information, but some commodity functions.
+ * Invariant for any context within which this class shall be used:
+ * For any valid filename, there is at any time at most one
+ * such shared pointer (wrapper) known in said context's data structures
+ * (counting by pointer equality)
+ * This means, that a file can be invalidated (i.e. deleted or overwritten)
+ * by simply searching for one instance of the file among all known files and
+ * invalidating this instance
+ * A new instance may hence only be created after making sure that there are
+ * no valid instances in the data structures.
+ */
+ struct InvalidatableFile
+ {
+ explicit InvalidatableFile( std::string s );
+
+
+ InvalidatableFile( ) = default;
+
+
+ struct FileState
+ {
+ explicit FileState( std::string s );
+
+ std::string name;
+ bool valid = true;
+ };
+
+ std::shared_ptr< FileState > fileState;
+
+
+ void invalidate( );
+
+
+ bool valid( ) const;
+
+
+ InvalidatableFile & operator=( std::string s );
+
+
+ bool operator==( InvalidatableFile const & f ) const;
+
+
+ std::string & operator*( ) const;
+
+
+ std::string * operator->( ) const;
+
+
+ explicit operator bool( ) const;
+ };
+}
+
+namespace std
+{
+ template< >
+ struct hash< openPMD::InvalidatableFile >
+ {
+ using argument_type = openPMD::InvalidatableFile;
+ using result_type = std::size_t;
+
+ result_type operator()( argument_type const & s ) const noexcept;
+ };
+}
diff --git a/include/openPMD/IO/JSON/JSONFilePosition.hpp b/include/openPMD/IO/JSON/JSONFilePosition.hpp
index 70748b094a..41c6e5f97c 100644
--- a/include/openPMD/IO/JSON/JSONFilePosition.hpp
+++ b/include/openPMD/IO/JSON/JSONFilePosition.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Franz Pöschel
+/* Copyright 2017-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/IO/JSON/JSONIOHandler.hpp b/include/openPMD/IO/JSON/JSONIOHandler.hpp
index b657b9b534..b65b674ce8 100644
--- a/include/openPMD/IO/JSON/JSONIOHandler.hpp
+++ b/include/openPMD/IO/JSON/JSONIOHandler.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Franz Pöschel
+/* Copyright 2017-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp b/include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp
index 9038ccd0d8..86415787a5 100644
--- a/include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp
+++ b/include/openPMD/IO/JSON/JSONIOHandlerImpl.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Franz Pöschel
+/* Copyright 2017-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/auxiliary/Environment.hpp b/include/openPMD/auxiliary/Environment.hpp
new file mode 100644
index 0000000000..b0a3bdd01b
--- /dev/null
+++ b/include/openPMD/auxiliary/Environment.hpp
@@ -0,0 +1,53 @@
+/* Copyright 2018-2019 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
+#include
+
+namespace openPMD
+{
+namespace auxiliary
+{
+
+ inline int getEnvNum( std::string const & key, int defaultValue )
+ {
+ char const * env = std::getenv( key.c_str( ) );
+ if ( env != nullptr )
+ {
+ std::string env_string{env};
+ try
+ {
+ return std::stoi( env_string );
+ }
+ catch ( std::invalid_argument const & )
+ {
+ return defaultValue;
+ }
+ }
+ else
+ return defaultValue;
+ }
+} // namespace auxiliary
+} // namespace openPMD
diff --git a/include/openPMD/auxiliary/StringManip.hpp b/include/openPMD/auxiliary/StringManip.hpp
index fdbd32df05..c290a94740 100644
--- a/include/openPMD/auxiliary/StringManip.hpp
+++ b/include/openPMD/auxiliary/StringManip.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller, Franz Poeschel
*
* This file is part of openPMD-api.
*
@@ -105,6 +105,26 @@ replace_last(std::string s,
return s;
}
+inline std::string
+replace_all_nonrecursively(std::string s,
+ std::string const& target,
+ std::string const& replacement)
+{
+ std::string::size_type pos = 0;
+ auto tsize = target.size();
+ auto rsize = replacement.size();
+ while (true)
+ {
+ pos = s.find(target, pos);
+ if (pos == std::string::npos)
+ break;
+ s.replace(pos, tsize, replacement);
+ pos += rsize;
+ }
+ s.shrink_to_fit();
+ return s;
+}
+
inline std::string
replace_all(std::string s,
std::string const& target,
@@ -183,5 +203,40 @@ join(std::vector< std::string > const& vs, std::string const& delimiter)
return ss.str();
}
}
+
+/**
+ * @brief Remove surrounding slashes from a string.
+ *
+ * @param s A string, possibly with a slash as first and/or last letter.
+ * @return std::string The same string without those slashes.
+ */
+inline std::string
+removeSlashes( std::string s )
+{
+ if( auxiliary::starts_with(
+ s,
+ '/'
+ ) )
+ {
+ s = auxiliary::replace_first(
+ s,
+ "/",
+ ""
+ );
+ }
+ if( auxiliary::ends_with(
+ s,
+ '/'
+ ) )
+ {
+ s = auxiliary::replace_last(
+ s,
+ "/",
+ ""
+ );
+ }
+ return s;
+}
+
} // auxiliary
} // openPMD
diff --git a/include/openPMD/backend/BaseRecordComponent.hpp b/include/openPMD/backend/BaseRecordComponent.hpp
index 818f6d0a26..2c7777284c 100644
--- a/include/openPMD/backend/BaseRecordComponent.hpp
+++ b/include/openPMD/backend/BaseRecordComponent.hpp
@@ -81,6 +81,14 @@ struct DefaultValue
{
rc.makeConstant( T() );
}
+
+ template< unsigned n, typename... Args >
+ void
+ operator()( Args &&... )
+ {
+ throw std::runtime_error(
+ "makeEmpty: Datatype not supported by openPMD." );
+ }
};
} // namespace detail
} // namespace openPMD
diff --git a/include/openPMD/backend/Writable.hpp b/include/openPMD/backend/Writable.hpp
index 6f6b574381..ed881d4ac0 100644
--- a/include/openPMD/backend/Writable.hpp
+++ b/include/openPMD/backend/Writable.hpp
@@ -38,6 +38,10 @@ struct TestHelper;
class AbstractFilePosition;
class AbstractIOHandler;
class Attributable;
+struct ADIOS2FilePosition;
+template
+class AbstractIOHandlerImplCommon;
+
/** @brief Layer to mirror structure of logical data and persistent data in file.
*
@@ -69,6 +73,7 @@ class Writable
friend class ADIOS2IOHandlerImpl;
friend class HDF5IOHandlerImpl;
friend class ParallelHDF5IOHandlerImpl;
+ friend class AbstractIOHandlerImplCommon;
friend class JSONIOHandlerImpl;
friend struct test::TestHelper;
friend std::string concrete_h5_file_position(Writable*);
diff --git a/include/openPMD/benchmark/mpi/BlockSlicer.hpp b/include/openPMD/benchmark/mpi/BlockSlicer.hpp
index de70dc4eef..30cd63b6ce 100644
--- a/include/openPMD/benchmark/mpi/BlockSlicer.hpp
+++ b/include/openPMD/benchmark/mpi/BlockSlicer.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/benchmark/mpi/DatasetFiller.hpp b/include/openPMD/benchmark/mpi/DatasetFiller.hpp
index c1fb5f6b3b..731ff00621 100644
--- a/include/openPMD/benchmark/mpi/DatasetFiller.hpp
+++ b/include/openPMD/benchmark/mpi/DatasetFiller.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/benchmark/mpi/MPIBenchmark.hpp b/include/openPMD/benchmark/mpi/MPIBenchmark.hpp
index d9d517346d..c0214b6e43 100644
--- a/include/openPMD/benchmark/mpi/MPIBenchmark.hpp
+++ b/include/openPMD/benchmark/mpi/MPIBenchmark.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/benchmark/mpi/MPIBenchmarkReport.hpp b/include/openPMD/benchmark/mpi/MPIBenchmarkReport.hpp
index cea79f16f7..33fa4dc1cf 100644
--- a/include/openPMD/benchmark/mpi/MPIBenchmarkReport.hpp
+++ b/include/openPMD/benchmark/mpi/MPIBenchmarkReport.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/benchmark/mpi/OneDimensionalBlockSlicer.hpp b/include/openPMD/benchmark/mpi/OneDimensionalBlockSlicer.hpp
index 3067a48684..fde70c7ca3 100644
--- a/include/openPMD/benchmark/mpi/OneDimensionalBlockSlicer.hpp
+++ b/include/openPMD/benchmark/mpi/OneDimensionalBlockSlicer.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/include/openPMD/benchmark/mpi/RandomDatasetFiller.hpp b/include/openPMD/benchmark/mpi/RandomDatasetFiller.hpp
index 7648c4781e..edb959b24b 100644
--- a/include/openPMD/benchmark/mpi/RandomDatasetFiller.hpp
+++ b/include/openPMD/benchmark/mpi/RandomDatasetFiller.hpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/src/Datatype.cpp b/src/Datatype.cpp
index 2969bb0650..3b94f2fc25 100644
--- a/src/Datatype.cpp
+++ b/src/Datatype.cpp
@@ -303,4 +303,90 @@ namespace openPMD
os << dt;
return buf.str();
}
+
+ std::vector openPMD_Datatypes{
+ Datatype::CHAR ,
+ Datatype::UCHAR,
+ Datatype::SHORT,
+ Datatype::INT,
+ Datatype::LONG,
+ Datatype::LONGLONG,
+ Datatype::USHORT,
+ Datatype::UINT,
+ Datatype::ULONG,
+ Datatype::ULONGLONG,
+ Datatype::FLOAT,
+ Datatype::DOUBLE,
+ Datatype::LONG_DOUBLE,
+ Datatype::STRING,
+ Datatype::VEC_CHAR,
+ Datatype::VEC_SHORT,
+ Datatype::VEC_INT,
+ Datatype::VEC_LONG,
+ Datatype::VEC_LONGLONG,
+ Datatype::VEC_UCHAR,
+ Datatype::VEC_USHORT,
+ Datatype::VEC_UINT,
+ Datatype::VEC_ULONG,
+ Datatype::VEC_ULONGLONG,
+ Datatype::VEC_FLOAT,
+ Datatype::VEC_DOUBLE,
+ Datatype::VEC_LONG_DOUBLE,
+ Datatype::VEC_STRING,
+ Datatype::ARR_DBL_7,
+ Datatype::BOOL,
+ Datatype::DATATYPE,
+ Datatype::UNDEFINED
+ };
+
+
+ Datatype basicDatatype( Datatype dt )
+ {
+ return switchType(dt, detail::BasicDatatype{});
+ }
+
+
+ Datatype toVectorType( Datatype dt )
+ {
+ auto initializer = []() {
+ std::map res;
+ for (Datatype d: openPMD_Datatypes) {
+ if (d == Datatype::ARR_DBL_7
+ || d == Datatype::UNDEFINED
+ || d == Datatype::DATATYPE)
+ continue;
+ Datatype basic = basicDatatype(d);
+ if (basic == d)
+ continue;
+ res[basic] = d;
+ }
+ return res;
+ };
+ static auto map (initializer());
+ auto it = map.find(dt);
+ if (it != map.end()) {
+ return it->second;
+ } else {
+ std::cerr << "Encountered non-basice type " << dt << ", aborting."
+ << std::endl;
+ throw std::runtime_error("toVectorType: passed non-basic type.");
+ }
+ }
+
+
+ namespace detail {
+ template< typename T >
+ Datatype BasicDatatype::operator()()
+ {
+ static auto res = BasicDatatypeHelper{}.m_dt;
+ return res;
+ }
+
+
+ template< int n >
+ Datatype BasicDatatype::operator()()
+ {
+ throw std::runtime_error( "basicDatatype: received unknown datatype." );
+ }
+ }
}
diff --git a/src/IO/ADIOS/ADIOS2Auxiliary.cpp b/src/IO/ADIOS/ADIOS2Auxiliary.cpp
new file mode 100644
index 0000000000..46cdca5614
--- /dev/null
+++ b/src/IO/ADIOS/ADIOS2Auxiliary.cpp
@@ -0,0 +1,193 @@
+/* Copyright 2017-2019 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 .
+ */
+
+#include "openPMD/config.hpp"
+#if openPMD_HAVE_ADIOS2
+#include "openPMD/IO/ADIOS/ADIOS2Auxiliary.hpp"
+#include "openPMD/Datatype.hpp"
+#include
+
+namespace openPMD
+{
+namespace detail
+{
+ template< typename T >
+ std::string
+ ToDatatypeHelper< T >::type()
+ {
+ return adios2::GetType< T >();
+ }
+
+ template< typename T >
+ std::string
+ ToDatatypeHelper< std::vector< T > >::type()
+ {
+ return
+
+ adios2::GetType< T >();
+ }
+
+ template< typename T, size_t n >
+ std::string
+ ToDatatypeHelper< std::array< T, n > >::type()
+ {
+ return
+
+ adios2::GetType< T >();
+ }
+
+ std::string
+ ToDatatypeHelper< bool >::type()
+ {
+ return ToDatatypeHelper< bool_representation >::type();
+ }
+
+ template< typename T >
+ std::string
+ ToDatatype::operator()()
+ {
+ return ToDatatypeHelper< T >::type();
+ }
+
+ template< int n >
+ std::string
+ ToDatatype::operator()()
+ {
+ return "";
+ }
+
+ Datatype
+ fromADIOS2Type( std::string const & dt )
+ {
+ static std::map< std::string, Datatype > map{
+ { "string", Datatype::STRING },
+ { "char", Datatype::CHAR },
+ { "signed char", Datatype::CHAR },
+ { "unsigned char", Datatype::UCHAR },
+ { "short", Datatype::SHORT },
+ { "unsigned short", Datatype::USHORT },
+ { "int", Datatype::INT },
+ { "unsigned int", Datatype::UINT },
+ { "long int", Datatype::LONG },
+ { "unsigned long int", Datatype::ULONG },
+ { "long long int", Datatype::LONGLONG },
+ { "unsigned long long int", Datatype::ULONGLONG },
+ { "float", Datatype::FLOAT },
+ { "double", Datatype::DOUBLE },
+ { "long double", Datatype::LONG_DOUBLE },
+ { "uint8_t", Datatype::UCHAR },
+ { "int8_t", Datatype::CHAR },
+ { "uint16_t", determineDatatype< uint16_t >() },
+ { "int16_t", determineDatatype< int16_t >() },
+ { "uint32_t", determineDatatype< uint32_t >() },
+ { "int32_t", determineDatatype< int32_t >() },
+ { "uint64_t", determineDatatype< uint64_t >() },
+ { "int64_t", determineDatatype< int64_t >() }
+ };
+ auto it = map.find( dt );
+ if( it != map.end() )
+ {
+ return it->second;
+ }
+ else
+ {
+ std::cerr << "Warning: Encountered unknown ADIOS2 datatype,"
+ " defaulting to UNDEFINED." << std::endl;
+ return Datatype::UNDEFINED;
+ }
+ }
+
+ template< typename T >
+ typename std::vector< T >::size_type
+ AttributeInfoHelper< T >::getSize(
+ adios2::IO & IO,
+ std::string const & attributeName )
+ {
+ auto attribute = IO.InquireAttribute< T >( attributeName );
+ if( !attribute )
+ {
+ throw std::runtime_error(
+ "Internal error: Attribute not present." );
+ }
+ return attribute.Data().size();
+ }
+
+ template< typename T >
+ typename std::vector< T >::size_type
+ AttributeInfoHelper< std::vector< T > >::getSize(
+ adios2::IO & IO,
+ std::string const & attributeName )
+ {
+ return AttributeInfoHelper< T >::getSize( IO, attributeName );
+ }
+
+ typename std::vector< bool_representation >::size_type
+ AttributeInfoHelper< bool >::getSize(
+ adios2::IO & IO,
+ std::string const & attributeName )
+ {
+ return AttributeInfoHelper< bool_representation >::getSize(
+ IO, attributeName );
+ }
+
+ template< typename T >
+ typename std::vector< T >::size_type
+ AttributeInfo::operator()(
+ adios2::IO & IO,
+ std::string const & attributeName )
+ {
+ return AttributeInfoHelper< T >::getSize( IO, attributeName );
+ }
+
+ template< int n, typename... Params >
+ size_t
+ AttributeInfo::operator()( Params &&... )
+ {
+ return 0;
+ }
+
+ Datatype
+ attributeInfo( adios2::IO & IO, std::string const & attributeName )
+ {
+ std::string type = IO.AttributeType( attributeName );
+ if( type.empty() )
+ {
+ std::cerr << "Warning: Attribute with name " << attributeName
+ << " has no type in backend." << std::endl;
+ return Datatype::UNDEFINED;
+ }
+ else
+ {
+ static AttributeInfo ai;
+ Datatype basicType = fromADIOS2Type( type );
+ auto size =
+ switchType< size_t >( basicType, ai, IO, attributeName );
+ Datatype openPmdType = size == 1
+ ? basicType
+ : size == 7 && basicType == Datatype::DOUBLE
+ ? Datatype::ARR_DBL_7
+ : toVectorType( basicType );
+ return openPmdType;
+ }
+ }
+} // namespace detail
+} // namespace openPMD
+#endif
diff --git a/src/IO/ADIOS/ADIOS2IOHandler.cpp b/src/IO/ADIOS/ADIOS2IOHandler.cpp
index 55a727252e..24024876ed 100644
--- a/src/IO/ADIOS/ADIOS2IOHandler.cpp
+++ b/src/IO/ADIOS/ADIOS2IOHandler.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Fabian Koller
+/* Copyright 2017-2019 Fabian Koller and Franz Poeschel.
*
* This file is part of openPMD-api.
*
@@ -19,59 +19,1245 @@
* If not, see .
*/
#include "openPMD/IO/ADIOS/ADIOS2IOHandler.hpp"
+#include "openPMD/Datatype.hpp"
+#include "openPMD/IO/ADIOS/ADIOS2FilePosition.hpp"
+#include "openPMD/IO/ADIOS/ADIOS2IOHandler.hpp"
+#include "openPMD/auxiliary/Environment.hpp"
+#include "openPMD/auxiliary/Filesystem.hpp"
+#include "openPMD/auxiliary/StringManip.hpp"
-#include
-
+#include
+#include
+#include
namespace openPMD
{
+#if openPMD_USE_VERIFY
+#define VERIFY( CONDITION, TEXT ) \
+ { \
+ if ( !( CONDITION ) ) \
+ throw std::runtime_error( ( TEXT ) ); \
+ }
+#else
+#define VERIFY( CONDITION, TEXT ) \
+ do \
+ { \
+ (void)sizeof( CONDITION ); \
+ } while ( 0 );
+#endif
+
+#define VERIFY_ALWAYS( CONDITION, TEXT ) \
+ { \
+ if ( !( CONDITION ) ) \
+ throw std::runtime_error( ( TEXT ) ); \
+ }
+
#if openPMD_HAVE_ADIOS2
-ADIOS2IOHandler::ADIOS2IOHandler(std::string path, AccessType at)
- : AbstractIOHandler(std::move(path), at),
- m_impl{new ADIOS2IOHandlerImpl(this)}
-{ }
-ADIOS2IOHandler::~ADIOS2IOHandler()
-{ }
+#if openPMD_HAVE_MPI
-std::future< void >
-ADIOS2IOHandler::flush()
+ADIOS2IOHandlerImpl::ADIOS2IOHandlerImpl(
+ AbstractIOHandler * handler,
+ MPI_Comm communicator )
+ : AbstractIOHandlerImplCommon( handler )
+ , m_comm{ communicator }
+ , m_ADIOS{ communicator, ADIOS2_DEBUG_MODE }
{
- return m_impl->flush();
}
-#endif
+#endif // openPMD_HAVE_MPI
-#if openPMD_HAVE_ADIOS2 && !openPMD_HAVE_MPI
-ADIOS2IOHandler::ADIOS2IOHandler(std::string path, AccessType at)
- : AbstractIOHandler(std::move(path), at),
- m_impl{new ADIOS2IOHandlerImpl(this)}
-{ }
+ADIOS2IOHandlerImpl::ADIOS2IOHandlerImpl( AbstractIOHandler * handler )
+ : AbstractIOHandlerImplCommon( handler ), m_ADIOS{ ADIOS2_DEBUG_MODE }
+{
+}
-ADIOS2IOHandler::~ADIOS2IOHandler() = default;
+ADIOS2IOHandlerImpl::~ADIOS2IOHandlerImpl( )
+{
+ this->flush( );
+}
-std::future< void >
-ADIOS2IOHandler::flush()
+std::future< void > ADIOS2IOHandlerImpl::flush( )
{
- return m_impl->flush();
+ auto res = AbstractIOHandlerImpl::flush( );
+ for ( auto & p : m_fileData )
+ {
+ if ( m_dirty.find( p.first ) != m_dirty.end( ) )
+ {
+ p.second->flush( );
+ }
+ else
+ {
+ p.second->drop( );
+ }
+ }
+ return res;
}
-#else
-ADIOS2IOHandler::ADIOS2IOHandler(std::string path, AccessType at)
+
+void ADIOS2IOHandlerImpl::createFile(
+ Writable * writable,
+ Parameter< Operation::CREATE_FILE > const & parameters )
+{
+ VERIFY_ALWAYS( m_handler->accessTypeBackend != AccessType::READ_ONLY,
+ "Creating a file in read-only mode is not possible." );
+
+ if ( !writable->written )
+ {
+ std::string name = parameters.name;
+ if ( !auxiliary::ends_with( name, ".bp" ) )
+ {
+ name += ".bp";
+ }
+
+ auto res_pair = getPossiblyExisting( name );
+ InvalidatableFile shared_name = InvalidatableFile( name );
+ VERIFY_ALWAYS(
+ !( m_handler->accessTypeBackend == AccessType::READ_WRITE &&
+ ( !std::get< PE_NewlyCreated >( res_pair ) ||
+ auxiliary::file_exists( fullPath(
+ std::get< PE_InvalidatableFile >( res_pair ) ) ) ) ),
+ "Can only overwrite existing file in CREATE mode." );
+
+ if ( !std::get< PE_NewlyCreated >( res_pair ) )
+ {
+ auto file = std::get< PE_InvalidatableFile >( res_pair );
+ m_dirty.erase( file );
+ dropFileData( file );
+ file.invalidate( );
+ }
+
+ std::string const dir( m_handler->directory );
+ if ( !auxiliary::directory_exists( dir ) )
+ {
+ auto success = auxiliary::create_directories( dir );
+ VERIFY( success, "Could not create directory." );
+ }
+
+ associateWithFile( writable, shared_name );
+ this->m_dirty.emplace( shared_name );
+ getFileData( shared_name ).m_mode = adios2::Mode::Write; // WORKAROUND
+ // ADIOS2 does not yet implement ReadWrite Mode
+
+ writable->written = true;
+ writable->abstractFilePosition =
+ std::make_shared< ADIOS2FilePosition >( );
+ }
+}
+
+void ADIOS2IOHandlerImpl::createPath(
+ Writable * writable,
+ const Parameter< Operation::CREATE_PATH > & parameters )
+{
+ std::string path;
+ refreshFileFromParent( writable );
+
+ /* Sanitize path */
+ if ( !auxiliary::starts_with( parameters.path, '/' ) )
+ {
+ path = filePositionToString( setAndGetFilePosition( writable ) ) + "/" +
+ auxiliary::removeSlashes( parameters.path );
+ }
+ else
+ {
+ path = "/" + auxiliary::removeSlashes( parameters.path );
+ }
+
+ /* ADIOS has no concept for explicitly creating paths.
+ * They are implicitly created with the paths of variables/attributes. */
+
+ writable->written = true;
+ writable->abstractFilePosition = std::make_shared< ADIOS2FilePosition >(
+ path, ADIOS2FilePosition::GD::GROUP );
+}
+
+void ADIOS2IOHandlerImpl::createDataset(
+ Writable * writable,
+ const Parameter< Operation::CREATE_DATASET > & parameters )
+{
+ if ( m_handler->accessTypeBackend == AccessType::READ_ONLY )
+ {
+ throw std::runtime_error( "Creating a dataset in a file opened as read "
+ "only is not possible." );
+ }
+ if ( !writable->written )
+ {
+ /* Sanitize name */
+ std::string name = auxiliary::removeSlashes( parameters.name );
+
+ auto file = refreshFileFromParent( writable );
+ auto filePos = setAndGetFilePosition( writable, name );
+ filePos->gd = ADIOS2FilePosition::GD::DATASET;
+ auto varName = filePositionToString( filePos );
+ /*
+ * @brief std::optional would be more idiomatic, but it's not in
+ * the C++11 standard
+ * @todo replace with std::optional upon switching to C++17
+ */
+ std::unique_ptr< adios2::Operator > compression;
+ if ( !parameters.compression.empty( ) )
+ {
+ compression = getCompressionOperator( parameters.compression );
+ }
+ switchType( parameters.dtype, detail::VariableDefiner( ),
+ getFileData( file ).m_IO, varName,
+ std::move( compression ), parameters.extent );
+ writable->written = true;
+ m_dirty.emplace( file );
+ }
+}
+
+void ADIOS2IOHandlerImpl::extendDataset(
+ Writable *, const Parameter< Operation::EXTEND_DATASET > & )
+{
+ throw std::runtime_error(
+ "Dataset extension not implemented in ADIOS backend" );
+}
+
+void ADIOS2IOHandlerImpl::openFile(
+ Writable * writable, const Parameter< Operation::OPEN_FILE > & parameters )
+{
+ if ( !auxiliary::directory_exists( m_handler->directory ) )
+ {
+ throw no_such_file_error( "Supplied directory is not valid: " +
+ m_handler->directory );
+ }
+
+ std::string name = parameters.name;
+ if ( !auxiliary::ends_with( name, ".bp" ) )
+ {
+ name += ".bp";
+ }
+
+ auto file = std::get< PE_InvalidatableFile >( getPossiblyExisting( name ) );
+
+ associateWithFile( writable, file );
+
+ writable->written = true;
+ writable->abstractFilePosition = std::make_shared< ADIOS2FilePosition >( );
+}
+
+void ADIOS2IOHandlerImpl::openPath(
+ Writable * writable, const Parameter< Operation::OPEN_PATH > & parameters )
+{
+ /* Sanitize path */
+ refreshFileFromParent( writable );
+ std::string prefix =
+ filePositionToString( setAndGetFilePosition( writable->parent ) );
+ std::string suffix = auxiliary::removeSlashes( parameters.path );
+ std::string infix = auxiliary::ends_with( prefix, '/' ) ? "" : "/";
+
+ /* ADIOS has no concept for explicitly creating paths.
+ * They are implicitly created with the paths of variables/attributes. */
+
+ writable->abstractFilePosition = std::make_shared< ADIOS2FilePosition >(
+ prefix + infix + suffix, ADIOS2FilePosition::GD::GROUP );
+ writable->written = true;
+}
+
+void ADIOS2IOHandlerImpl::openDataset(
+ Writable * writable, Parameter< Operation::OPEN_DATASET > & parameters )
+{
+ auto name = auxiliary::removeSlashes( parameters.name );
+ writable->abstractFilePosition.reset( );
+ auto pos = setAndGetFilePosition( writable, name );
+ pos->gd = ADIOS2FilePosition::GD::DATASET;
+ auto file = refreshFileFromParent( writable );
+ auto varName = filePositionToString( pos );
+ *parameters.dtype = detail::fromADIOS2Type(
+ getFileData( file ).m_IO.VariableType( varName ) );
+ switchType( *parameters.dtype, detail::DatasetOpener( this ), file, varName,
+ parameters );
+ writable->written = true;
+}
+
+void ADIOS2IOHandlerImpl::deleteFile(
+ Writable *, const Parameter< Operation::DELETE_FILE > & )
+{
+ throw std::runtime_error( "ADIOS2 backend does not support deletion." );
+}
+
+void ADIOS2IOHandlerImpl::deletePath(
+ Writable *, const Parameter< Operation::DELETE_PATH > & )
+{
+ throw std::runtime_error( "ADIOS2 backend does not support deletion." );
+}
+
+void ADIOS2IOHandlerImpl::deleteDataset(
+ Writable *, const Parameter< Operation::DELETE_DATASET > & )
+{
+ throw std::runtime_error( "ADIOS2 backend does not support deletion." );
+}
+
+void ADIOS2IOHandlerImpl::deleteAttribute(
+ Writable *, const Parameter< Operation::DELETE_ATT > & )
+{
+ throw std::runtime_error( "ADIOS2 backend does not support deletion." );
+}
+
+void ADIOS2IOHandlerImpl::writeDataset(
+ Writable * writable,
+ const Parameter< Operation::WRITE_DATASET > & parameters )
+{
+ VERIFY_ALWAYS( m_handler->accessTypeBackend != AccessType::READ_ONLY,
+ "Cannot write data in read-only mode." );
+ setAndGetFilePosition( writable );
+ auto file = refreshFileFromParent( writable );
+ detail::BufferedActions & ba = getFileData( file );
+ detail::BufferedPut bp;
+ bp.name = nameOfVariable( writable );
+ bp.param = parameters;
+ ba.enqueue( std::move( bp ) );
+ m_dirty.emplace( std::move( file ) );
+ writable->written = true; // TODO erst nach dem Schreiben?
+}
+
+void ADIOS2IOHandlerImpl::writeAttribute(
+ Writable * writable, const Parameter< Operation::WRITE_ATT > & parameters )
+{
+ switchType( parameters.dtype, detail::AttributeWriter( ), this, writable,
+ parameters );
+}
+
+void ADIOS2IOHandlerImpl::readDataset(
+ Writable * writable, Parameter< Operation::READ_DATASET > & parameters )
+{
+ setAndGetFilePosition( writable );
+ auto file = refreshFileFromParent( writable );
+ detail::BufferedActions & ba = getFileData( file );
+ detail::BufferedGet bg;
+ bg.name = nameOfVariable( writable );
+ bg.param = parameters;
+ ba.enqueue( std::move( bg ) );
+ m_dirty.emplace( std::move( file ) );
+}
+
+void ADIOS2IOHandlerImpl::readAttribute(
+ Writable * writable, Parameter< Operation::READ_ATT > & parameters )
+{
+ auto file = refreshFileFromParent( writable );
+ auto pos = setAndGetFilePosition( writable );
+ detail::BufferedActions & ba = getFileData( file );
+ detail::BufferedAttributeRead bar;
+ bar.name = nameOfAttribute( writable, parameters.name );
+ bar.param = parameters;
+ ba.enqueue( std::move( bar ) );
+ m_dirty.emplace( std::move( file ) );
+}
+
+void ADIOS2IOHandlerImpl::listPaths(
+ Writable * writable, Parameter< Operation::LIST_PATHS > & parameters )
+{
+ VERIFY_ALWAYS(
+ writable->written,
+ "Internal error: Writable not marked written during path listing" );
+ auto file = refreshFileFromParent( writable );
+ auto pos = setAndGetFilePosition( writable );
+ // adios2::Engine & engine = getEngine( file );
+ std::string myName = filePositionToString( pos );
+ if ( !auxiliary::ends_with( myName, '/' ) )
+ {
+ myName = myName + '/';
+ }
+
+ /*
+ * since ADIOS does not have a concept of paths, restore them
+ * from variables and attributes.
+ * yes.
+ */
+
+ auto & IO = getFileData( file ).m_IO;
+
+ std::unordered_set< std::string > subdirs;
+ /*
+ * When reading an attribute, we cannot distinguish
+ * whether its containing "folder" is a group or a
+ * dataset. If we stumble upon a dataset at the current
+ * level (which can be distinguished via variables),
+ * we put in in the list 'delete_me' to remove them
+ * again later on.
+ * Note that the method 'listDatasets' does not have
+ * this problem since datasets can be restored solely
+ * from variables – attributes don't even need to be
+ * inspected.
+ */
+ std::vector< std::string > delete_me;
+ auto f = [myName, &subdirs, &delete_me](
+ std::vector< std::string > & varsOrAttrs, bool variables ) {
+ for ( auto var : varsOrAttrs )
+ {
+ if ( auxiliary::starts_with( var, myName ) )
+ {
+ var = auxiliary::replace_first( var, myName, "" );
+ auto firstSlash = var.find_first_of( '/' );
+ if ( firstSlash != std::string::npos )
+ {
+ var = var.substr( 0, firstSlash );
+ subdirs.emplace( std::move( var ) );
+ }
+ else if ( variables )
+ { // var is a dataset at the current level
+ delete_me.push_back( std::move( var ) );
+ }
+ }
+ }
+ };
+ std::vector< std::string > vars;
+ for ( auto const & p : IO.AvailableVariables( ) )
+ {
+ vars.emplace_back( p.first );
+ }
+
+ std::vector< std::string > attrs;
+ for ( auto const & p : IO.AvailableAttributes( ) )
+ {
+ attrs.emplace_back( p.first );
+ }
+ f( vars, true );
+ f( attrs, false );
+ for ( auto & d : delete_me )
+ {
+ subdirs.erase( d );
+ }
+ for ( auto & path : subdirs )
+ {
+ parameters.paths->emplace_back( std::move( path ) );
+ }
+}
+
+void ADIOS2IOHandlerImpl::listDatasets(
+ Writable * writable, Parameter< Operation::LIST_DATASETS > & parameters )
+{
+ VERIFY_ALWAYS(
+ writable->written,
+ "Internal error: Writable not marked written during path listing" );
+ auto file = refreshFileFromParent( writable );
+ auto pos = setAndGetFilePosition( writable );
+ // adios2::Engine & engine = getEngine( file );
+ std::string myName = filePositionToString( pos );
+ if ( !auxiliary::ends_with( myName, '/' ) )
+ {
+ myName = myName + '/';
+ }
+
+ /*
+ * since ADIOS does not have a concept of paths, restore them
+ * from variables and attributes.
+ * yes.
+ */
+
+ std::map< std::string, adios2::Params > vars =
+ getFileData( file ).m_IO.AvailableVariables( );
+
+ std::unordered_set< std::string > subdirs;
+ for ( auto & pair : vars )
+ {
+ std::string var = pair.first;
+ if ( auxiliary::starts_with( var, myName ) )
+ {
+ var = auxiliary::replace_first( var, myName, "" );
+ auto firstSlash = var.find_first_of( '/' );
+ if ( firstSlash == std::string::npos )
+ {
+ subdirs.emplace( std::move( var ) );
+ } // else: var is a path or a dataset in a group below the current
+ // group
+ }
+ }
+ for ( auto & dataset : subdirs )
+ {
+ parameters.datasets->emplace_back( std::move( dataset ) );
+ }
+}
+
+void ADIOS2IOHandlerImpl::listAttributes(
+ Writable * writable, Parameter< Operation::LIST_ATTS > & parameters )
+{
+ VERIFY_ALWAYS( writable->written,
+ "Internal error: Writable not marked "
+ "written during attribute writing" );
+ auto file = refreshFileFromParent( writable );
+ auto pos = setAndGetFilePosition( writable );
+ auto attributePrefix = filePositionToString( pos );
+ if ( attributePrefix == "/" )
+ {
+ attributePrefix = "";
+ }
+ auto & ba = getFileData( file );
+ ba.getEngine( ); // make sure that the attributes are present
+ auto attrs = ba.m_IO.AvailableAttributes( attributePrefix );
+ for ( auto & pair : attrs )
+ {
+ auto attr = auxiliary::removeSlashes( pair.first );
+ if ( attr.find_last_of( '/' ) == std::string::npos )
+ {
+ parameters.attributes->push_back( std::move( attr ) );
+ }
+ }
+}
+
+
+
+adios2::Mode ADIOS2IOHandlerImpl::adios2Accesstype( )
+{
+ switch ( m_handler->accessTypeBackend )
+ {
+ case AccessType::CREATE:
+ return adios2::Mode::Write;
+ case AccessType::READ_ONLY:
+ return adios2::Mode::Read;
+ case AccessType::READ_WRITE:
+ std::cerr << "ADIOS2 does currently not yet implement ReadWrite "
+ "(Append) mode."
+ << "Replacing with Read mode." << std::endl;
+ return adios2::Mode::Read;
+ default:
+ return adios2::Mode::Undefined;
+ }
+}
+
+std::string ADIOS2IOHandlerImpl::filePositionToString(
+ std::shared_ptr< ADIOS2FilePosition > filepos )
+{
+ return filepos->location;
+}
+
+std::shared_ptr< ADIOS2FilePosition > ADIOS2IOHandlerImpl::extendFilePosition(
+ std::shared_ptr< ADIOS2FilePosition > const & oldPos, std::string s )
+{
+ auto path = filePositionToString( oldPos );
+ if ( !auxiliary::ends_with( path, '/' ) &&
+ !auxiliary::starts_with( s, '/' ) )
+ {
+ path = path + "/";
+ }
+ else if ( auxiliary::ends_with( path, '/' ) &&
+ auxiliary::starts_with( s, '/' ) )
+ {
+ path = auxiliary::replace_last( path, "/", "" );
+ }
+ return std::make_shared< ADIOS2FilePosition >( path + std::move( s ),
+ oldPos->gd );
+}
+
+std::unique_ptr< adios2::Operator >
+ADIOS2IOHandlerImpl::getCompressionOperator( std::string const & compression )
+{
+ adios2::Operator res;
+ auto it = m_operators.find( compression );
+ if ( it == m_operators.end( ) )
+ {
+ try {
+ res = m_ADIOS.DefineOperator( compression, compression );
+ }
+ catch ( std::invalid_argument const & )
+ {
+ std::cerr << "Warning: ADIOS2 backend does not support compression "
+ "method " << compression << ". Continuing without compression."
+ << std::endl;
+ return std::unique_ptr< adios2::Operator >( );
+ }
+ m_operators.emplace( compression, res );
+
+ }
+ else
+ {
+ res = it->second;
+ }
+ return std::unique_ptr< adios2::Operator >(
+ new adios2::Operator( res ) );
+}
+
+std::string ADIOS2IOHandlerImpl::nameOfVariable( Writable * writable )
+{
+ return filePositionToString( setAndGetFilePosition( writable ) );
+}
+
+std::string ADIOS2IOHandlerImpl::nameOfAttribute( Writable * writable,
+ std::string attribute )
+{
+ auto pos = setAndGetFilePosition( writable );
+ return filePositionToString(
+ extendFilePosition( pos, auxiliary::removeSlashes( attribute ) ) );
+}
+
+ADIOS2FilePosition::GD
+ADIOS2IOHandlerImpl::groupOrDataset( Writable * writable )
+{
+ return setAndGetFilePosition( writable )->gd;
+}
+
+detail::BufferedActions &
+ADIOS2IOHandlerImpl::getFileData( InvalidatableFile file )
+{
+ VERIFY_ALWAYS( file.valid( ),
+ "Cannot retrieve file data for a file that has "
+ "been overwritten or deleted." )
+ auto it = m_fileData.find( file );
+ if ( it == m_fileData.end( ) )
+ {
+ return *m_fileData
+ .emplace( std::move( file ),
+ std::unique_ptr< detail::BufferedActions >{
+ new detail::BufferedActions{*this, file}} )
+ .first->second;
+ }
+ else
+ {
+ return *it->second;
+ }
+}
+
+void ADIOS2IOHandlerImpl::dropFileData( InvalidatableFile file )
+{
+ auto it = m_fileData.find( file );
+ if ( it != m_fileData.end( ) )
+ {
+ it->second->drop( );
+ m_fileData.erase( it );
+ }
+}
+
+template < typename T >
+adios2::Variable< T >
+ADIOS2IOHandlerImpl::verifyDataset( Offset const & offset,
+ Extent const & extent, adios2::IO & IO,
+ std::string const & varName )
+{
+ {
+ auto requiredType = adios2::GetType< T >( );
+ auto actualType = IO.VariableType( varName );
+ VERIFY_ALWAYS( requiredType == actualType,
+ "Trying to access a dataset with wrong type (trying to "
+ "access dataset with type " +
+ requiredType + ", but has type " + actualType + ")" )
+ }
+ adios2::Variable< T > var = IO.InquireVariable< T >( varName );
+ VERIFY_ALWAYS( var.operator bool( ),
+ "Internal error: Failed opening ADIOS2 variable." )
+ // TODO leave this check to ADIOS?
+ adios2::Dims shape = var.Shape( );
+ auto actualDim = shape.size( );
+ {
+ auto requiredDim = extent.size( );
+ VERIFY_ALWAYS( requiredDim == actualDim,
+ "Trying to access a dataset with wrong dimensionality "
+ "(trying to access dataset with dimensionality " +
+ std::to_string( requiredDim ) +
+ ", but has dimensionality " +
+ std::to_string( actualDim ) + ")" )
+ }
+ for ( unsigned int i = 0; i < actualDim; i++ )
+ {
+ VERIFY_ALWAYS( offset[i] + extent[i] <= shape[i],
+ "Dataset access out of bounds." )
+ }
+ var.SetSelection( {offset, extent} );
+ return var;
+}
+
+namespace detail
+{
+ DatasetReader::DatasetReader( openPMD::ADIOS2IOHandlerImpl * impl )
+ : m_impl{impl}
+ {
+ }
+
+ template < typename T >
+ void DatasetReader::operator( )( detail::BufferedGet & bp, adios2::IO & IO,
+ adios2::Engine & engine,
+ std::string const & fileName )
+ {
+ DatasetHelper< T >{m_impl}.readDataset( bp, IO, engine, fileName );
+ }
+
+ template < int n, typename... Params >
+ void DatasetReader::operator( )( Params &&... )
+ {
+ throw std::runtime_error(
+ "Internal error: Unknown datatype trying to read a dataset." );
+ }
+
+ template < typename T >
+ Datatype AttributeReader::
+ operator( )( adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource )
+ {
+ /*
+ * If we store an attribute of boolean type, we store an additional
+ * attribute prefixed with '__is_boolean__' to indicate this information
+ * that would otherwise be lost. Check whether this has been done.
+ */
+ using rep = AttributeTypes::rep;
+#if __cplusplus > 201402L
+ constexpr
+#endif
+ if( std::is_same< T, rep >::value )
+ {
+ std::string metaAttr = "__is_boolean__" + name;
+ auto type = attributeInfo( IO, "__is_boolean__" + name );
+ if ( type == determineDatatype() )
+ {
+ auto attr = IO.InquireAttribute< rep >( metaAttr );
+ if (attr.Data().size() == 1 && attr.Data()[0] == 1)
+ {
+ AttributeTypes< bool >::readAttribute( IO, name, resource );
+ return determineDatatype< bool >();
+ }
+ }
+ }
+ AttributeTypes< T >::readAttribute( IO, name, resource );
+ return determineDatatype< T >();
+ }
+
+ template < int n, typename... Params >
+ Datatype AttributeReader::operator( )( Params &&... )
+ {
+ throw std::runtime_error( "Internal error: Unknown datatype while "
+ "trying to read an attribute." );
+ }
+
+ template < typename T >
+ void AttributeWriter::
+ operator( )( ADIOS2IOHandlerImpl * impl, Writable * writable,
+ const Parameter< Operation::WRITE_ATT > & parameters )
+ {
+
+ VERIFY_ALWAYS( impl->m_handler->accessTypeBackend !=
+ AccessType::READ_ONLY,
+ "Cannot write attribute in read-only mode." );
+ auto pos = impl->setAndGetFilePosition( writable );
+ auto file = impl->refreshFileFromParent( writable );
+ auto fullName = impl->nameOfAttribute( writable, parameters.name );
+ auto prefix = impl->filePositionToString( pos );
+
+ adios2::IO IO = impl->getFileData( file ).m_IO;
+ impl->m_dirty.emplace( std::move( file ) );
+
+ std::string t = IO.AttributeType( fullName );
+ if ( !t.empty( ) ) // an attribute is present <=> it has a type
+ {
+ IO.RemoveAttribute( fullName );
+ }
+ typename AttributeTypes< T >::Attr attr =
+ AttributeTypes< T >::createAttribute(
+ IO, fullName, variantSrc::get< T >( parameters.resource ) );
+ VERIFY_ALWAYS( attr, "Failed creating attribute." )
+ }
+
+ template < int n, typename... Params >
+ void AttributeWriter::operator( )( Params &&... )
+ {
+ throw std::runtime_error( "Internal error: Unknown datatype while "
+ "trying to write an attribute." );
+ }
+
+ DatasetOpener::DatasetOpener( ADIOS2IOHandlerImpl * impl ) : m_impl{impl}
+ {
+ }
+
+ template < typename T >
+ void DatasetOpener::
+ operator( )( InvalidatableFile file, const std::string & varName,
+ Parameter< Operation::OPEN_DATASET > & parameters )
+ {
+ DatasetHelper< T >{m_impl}.openDataset( file, varName, parameters );
+ }
+
+ template < int n, typename... Params >
+ void DatasetOpener::operator( )( Params &&... )
+ {
+ throw std::runtime_error(
+ "Unknown datatype while trying to open dataset." );
+ }
+
+ WriteDataset::WriteDataset( ADIOS2IOHandlerImpl * handlerImpl )
+ : m_handlerImpl{handlerImpl}
+ {
+ }
+
+ template < typename T >
+ void WriteDataset::operator( )( detail::BufferedPut & bp, adios2::IO & IO,
+ adios2::Engine & engine )
+ {
+ DatasetHelper< T > dh{m_handlerImpl};
+ dh.writeDataset( bp, IO, engine );
+ }
+
+ template < int n, typename... Params >
+ void WriteDataset::operator( )( Params &&... )
+ {
+ throw std::runtime_error( "WRITE_DATASET: Invalid datatype." );
+ }
+
+ template < typename T >
+ void VariableDefiner::
+ operator( )( adios2::IO & IO, const std::string & name,
+ std::unique_ptr< adios2::Operator > compression,
+ const adios2::Dims & shape, const adios2::Dims & start,
+ const adios2::Dims & count, const bool constantDims )
+ {
+ DatasetHelper< T >::defineVariable( IO, name, std::move( compression ),
+ shape, start, count, constantDims );
+ }
+
+ template < int n, typename... Params >
+ void VariableDefiner::operator( )( adios2::IO &, Params &&... )
+ {
+ throw std::runtime_error( "Defining a variable with undefined type." );
+ }
+
+
+
+ template < typename T >
+ typename AttributeTypes< T >::Attr
+ AttributeTypes< T >::createAttribute( adios2::IO & IO, std::string name,
+ const T value )
+ {
+ auto attr = IO.DefineAttribute( name, value );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed defining attribute '" + name + "'." );
+ }
+ return attr;
+ }
+
+ template < typename T >
+ void AttributeTypes< T >::readAttribute(
+ adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource )
+ {
+ auto attr = IO.InquireAttribute< BasicType >( name );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed reading attribute '" + name + "'." );
+ }
+ *resource = attr.Data( )[0];
+ }
+
+ template < typename T >
+ typename AttributeTypes< std::vector< T > >::Attr
+ AttributeTypes< std::vector< T > >::createAttribute(
+ adios2::IO & IO, std::string name, const std::vector< T > & value )
+ {
+ auto attr = IO.DefineAttribute( name, value.data( ), value.size( ) );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed defining attribute '" + name + "'." );
+ }
+ return attr;
+ }
+
+ template < typename T >
+ void AttributeTypes< std::vector< T > >::readAttribute(
+ adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource )
+ {
+ auto attr = IO.InquireAttribute< BasicType >( name );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed reading attribute '" + name + "'." );
+ }
+ *resource = attr.Data( );
+ }
+
+ template < typename T, size_t n >
+ typename AttributeTypes< std::array< T, n > >::Attr
+ AttributeTypes< std::array< T, n > >::createAttribute(
+ adios2::IO & IO, std::string name, const std::array< T, n > & value )
+ {
+ auto attr = IO.DefineAttribute( name, value.data( ), n );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed defining attribute '" + name + "'." );
+ }
+ return attr;
+ }
+
+ template < typename T, size_t n >
+ void AttributeTypes< std::array< T, n > >::readAttribute(
+ adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource )
+ {
+ auto attr = IO.InquireAttribute< BasicType >( name );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed reading attribute '" + name + "'." );
+ }
+ auto data = attr.Data( );
+ std::array< T, n > res;
+ for ( size_t i = 0; i < n; i++ )
+ {
+ res[i] = data[i];
+ }
+ *resource = res;
+ }
+
+ typename AttributeTypes< bool >::Attr
+ AttributeTypes< bool >::createAttribute( adios2::IO & IO, std::string name,
+ const bool value )
+ {
+ IO.DefineAttribute< bool_representation >( "__is_boolean__" + name, 1 );
+ return AttributeTypes< bool_representation >::createAttribute(
+ IO, name, toRep( value ) );
+ }
+
+ void AttributeTypes< bool >::readAttribute(
+ adios2::IO & IO, std::string name,
+ std::shared_ptr< Attribute::resource > resource )
+ {
+ auto attr = IO.InquireAttribute< BasicType >( name );
+ if ( !attr )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed reading attribute '" + name + "'." );
+ }
+ *resource = fromRep( attr.Data( )[0] );
+ }
+
+ template < typename T >
+ DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >::
+ DatasetHelper( openPMD::ADIOS2IOHandlerImpl * impl )
+ : m_impl{impl}
+ {
+ }
+
+ template < typename T >
+ void DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >::
+ openDataset( InvalidatableFile file, const std::string & varName,
+ Parameter< Operation::OPEN_DATASET > & parameters )
+ {
+ auto & IO = m_impl->getFileData( file ).m_IO;
+ adios2::Variable< T > var = IO.InquireVariable< T >( varName );
+ if ( !var )
+ {
+ throw std::runtime_error(
+ "Failed retrieving ADIOS2 Variable with name '" + varName +
+ "' from file " + *file + "." );
+ }
+ *parameters.extent = var.Shape( );
+ }
+
+ template < typename T >
+ void DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >::
+ readDataset( detail::BufferedGet & bp, adios2::IO & IO,
+ adios2::Engine & engine, std::string const & fileName )
+ {
+ adios2::Variable< T > var = m_impl->verifyDataset< T >(
+ bp.param.offset, bp.param.extent, IO, bp.name );
+ if ( !var )
+ {
+ throw std::runtime_error(
+ "Failed retrieving ADIOS2 Variable with name '" + bp.name +
+ "' from file " + fileName + "." );
+ }
+ auto ptr = std::static_pointer_cast< T >( bp.param.data ).get( );
+ engine.Get( var, ptr );
+ }
+
+ template < typename T >
+ void DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >::
+ defineVariable( adios2::IO & IO, const std::string & name,
+ std::unique_ptr< adios2::Operator > compression,
+ const adios2::Dims & shape, const adios2::Dims & start,
+ const adios2::Dims & count, const bool constantDims )
+ {
+ adios2::Variable< T > var =
+ IO.DefineVariable< T >( name, shape, start, count, constantDims );
+ if ( !var )
+ {
+ throw std::runtime_error(
+ "Internal error: Could not create Variable '" + name + "'." );
+ }
+ // check whether the unique_ptr has an element
+ // and whether the held operator is valid
+ if ( compression && *compression )
+ {
+ var.AddOperation( *compression );
+ }
+ }
+
+ template < typename T >
+ void DatasetHelper<
+ T, typename std::enable_if< DatasetTypes< T >::validType >::type >::
+ writeDataset( detail::BufferedPut & bp, adios2::IO & IO,
+ adios2::Engine & engine )
+ {
+ VERIFY_ALWAYS( m_impl->m_handler->accessTypeBackend !=
+ AccessType::READ_ONLY,
+ "Cannot write data in read-only mode." );
+
+ auto ptr = std::static_pointer_cast< const T >( bp.param.data ).get( );
+
+ adios2::Variable< T > var = m_impl->verifyDataset< T >(
+ bp.param.offset, bp.param.extent, IO, bp.name );
+
+ engine.Put( var, ptr );
+ }
+
+ template < typename T >
+ DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >::
+ DatasetHelper( openPMD::ADIOS2IOHandlerImpl * )
+ {
+ }
+
+ template < typename T >
+ void DatasetHelper< T,
+ typename std::enable_if<
+ !DatasetTypes< T >::validType >::type >::throwErr( )
+ {
+ throw std::runtime_error(
+ "Trying to access dataset with unallowed datatype: " +
+ datatypeToString( determineDatatype< T >( ) ) );
+ }
+
+ template < typename T >
+ template < typename... Params >
+ void DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >::
+ openDataset( Params &&... )
+ {
+ throwErr( );
+ }
+
+ template < typename T >
+ template < typename... Params >
+ void DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >::
+ readDataset( Params &&... )
+ {
+ throwErr( );
+ }
+
+ template < typename T >
+ template < typename... Params >
+ void DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >::
+ defineVariable( Params &&... )
+ {
+ throwErr( );
+ }
+
+ template < typename T >
+ template < typename... Params >
+ void DatasetHelper<
+ T, typename std::enable_if< !DatasetTypes< T >::validType >::type >::
+ writeDataset( Params &&... )
+ {
+ throwErr( );
+ }
+
+ void BufferedGet::run( BufferedActions & ba )
+ {
+ switchType( param.dtype, ba.m_readDataset, *this, ba.m_IO,
+ ba.getEngine( ), ba.m_file );
+ }
+
+ void BufferedPut::run( BufferedActions & ba )
+ {
+ switchType( param.dtype, ba.m_writeDataset, *this, ba.m_IO,
+ ba.getEngine( ) );
+ }
+
+ void BufferedAttributeRead::run( BufferedActions & ba )
+ {
+ auto type = attributeInfo( ba.m_IO, name );
+
+ if ( type == Datatype::UNDEFINED )
+ {
+ throw std::runtime_error( "Requested attribute (" + name +
+ ") not found in backend." );
+ }
+
+ Datatype ret =
+ switchType< Datatype >(
+ type,
+ detail::AttributeReader{},
+ ba.m_IO,
+ name,
+ param.resource );
+ *param.dtype = ret;
+ }
+
+ BufferedActions::BufferedActions( ADIOS2IOHandlerImpl & impl,
+ InvalidatableFile file )
+ : m_file( impl.fullPath( std::move( file ) ) ),
+ m_IO( impl.m_ADIOS.DeclareIO( std::to_string( impl.nameCounter++ ) ) ),
+ m_mode( impl.adios2Accesstype( ) ), m_writeDataset( &impl ),
+ m_readDataset( &impl ), m_attributeReader( ), m_impl( impl )
+ {
+ if ( !m_IO )
+ {
+ throw std::runtime_error(
+ "Internal error: Failed declaring ADIOS2 IO object for file " +
+ m_file );
+ }
+ else
+ {
+ // read parameters from environment
+ if ( 1 ==
+ auxiliary::getEnvNum(
+ "OPENPMD_ADIOS2_HAVE_METADATA_FILE", 1 ) )
+ {
+ m_IO.SetParameter( "CollectiveMetadata", "On" );
+ }
+ else
+ {
+ m_IO.SetParameter( "CollectiveMetadata", "Off" );
+ }
+ if ( 1 ==
+ auxiliary::getEnvNum( "OPENPMD_ADIOS2_HAVE_PROFILING", 1 ) )
+ {
+ m_IO.SetParameter( "Profile", "On" );
+ }
+ else
+ {
+ m_IO.SetParameter( "Profile", "Off" );
+ }
#if openPMD_HAVE_MPI
- : AbstractIOHandler(std::move(path), at, MPI_COMM_NULL)
-#else
-: AbstractIOHandler(std::move(path), at)
+ {
+ auto num_substreams =
+ auxiliary::getEnvNum( "OPENPMD_ADIOS2_NUM_SUBSTREAMS", 0 );
+ if ( 0 != num_substreams )
+ {
+ m_IO.SetParameter( "SubStreams",
+ std::to_string( num_substreams ) );
+ }
+ }
#endif
+ }
+ }
+
+ BufferedActions::~BufferedActions( )
+ {
+ // if write accessing, ensure that the engine is opened
+ if ( !m_engine && m_mode != adios2::Mode::Read )
+ {
+ getEngine( );
+ }
+ if ( m_engine )
+ {
+ m_engine->Close( );
+ }
+ }
+
+ adios2::Engine & BufferedActions::getEngine( )
+ {
+ if ( !m_engine )
+ {
+ m_engine = std::unique_ptr< adios2::Engine >(
+ new adios2::Engine( m_IO.Open( m_file, m_mode ) ) );
+ if ( !m_engine )
+ {
+ throw std::runtime_error( "Failed opening ADIOS2 Engine." );
+ }
+ }
+ return *m_engine;
+ }
+
+ template < typename BA > void BufferedActions::enqueue( BA && ba )
+ {
+ using _BA = typename std::remove_reference< BA >::type;
+ m_buffer.emplace_back( std::unique_ptr< BufferedAction >(
+ new _BA( std::forward< BA >( ba ) ) ) );
+ }
+
+ void BufferedActions::flush( )
+ {
+ auto & eng = getEngine( );
+ {
+ for ( auto const & ba : m_buffer )
+ {
+ ba->run( *this );
+ }
+ // Flush() does not necessarily perform
+ // deferred actions....
+ switch ( m_mode )
+ {
+ case adios2::Mode::Write:
+ eng.PerformPuts( );
+ break;
+ case adios2::Mode::Read:
+ eng.PerformGets( );
+ break;
+ case adios2::Mode::Append:
+ // TODO order?
+ eng.PerformGets( );
+ eng.PerformPuts( );
+ break;
+ default:
+ break;
+ }
+ }
+ m_buffer.clear( );
+ }
+
+ void BufferedActions::drop( )
+ {
+ m_buffer.clear( );
+ }
+
+} // namespace detail
+
+#if openPMD_HAVE_MPI
+
+ADIOS2IOHandler::ADIOS2IOHandler( std::string path, openPMD::AccessType at,
+ MPI_Comm comm )
+: AbstractIOHandler( std::move( path ), at, comm ), m_impl{this, comm
+
+ }
+{
+}
+
+#endif
+
+ADIOS2IOHandler::ADIOS2IOHandler( std::string path, AccessType at )
+: AbstractIOHandler( std::move( path ), at ), m_impl{this}
{
- throw std::runtime_error("openPMD-api built without parallel ADIOS2 support");
}
-ADIOS2IOHandler::~ADIOS2IOHandler() = default;
-std::future< void >
-ADIOS2IOHandler::flush()
+ADIOS2IOHandler::~ADIOS2IOHandler( )
{
- return std::future< void >();
+ this->flush( );
}
+
+std::future< void > ADIOS2IOHandler::flush( )
+{
+ return m_impl.flush( );
+}
+
+#else // openPMD_HAVE_ADIOS2
+
+#if openPMD_HAVE_MPI
+ADIOS2IOHandler::ADIOS2IOHandler( std::string path, AccessType at,
+ MPI_Comm comm )
+: AbstractIOHandler( std::move( path ), at, comm )
+{
+}
+
+#endif
+
+ADIOS2IOHandler::ADIOS2IOHandler( std::string path, AccessType at )
+: AbstractIOHandler( std::move( path ), at )
+{
+}
+
+std::future< void > ADIOS2IOHandler::flush( )
+{
+ return std::future< void >( );
+}
+
#endif
-} // openPMD
+
+} // namespace openPMD
diff --git a/src/IO/AbstractIOHandlerHelper.cpp b/src/IO/AbstractIOHandlerHelper.cpp
index 856f4771e4..c1e31fad6b 100644
--- a/src/IO/AbstractIOHandlerHelper.cpp
+++ b/src/IO/AbstractIOHandlerHelper.cpp
@@ -17,7 +17,8 @@
* 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 .
- */
+ */
+#include
#include "openPMD/IO/AbstractIOHandlerHelper.hpp"
#include "openPMD/IO/DummyIOHandler.hpp"
#include "openPMD/IO/ADIOS/ADIOS1IOHandler.hpp"
@@ -50,7 +51,7 @@ namespace openPMD
return std::make_shared< DummyIOHandler >(path, accessTypeBackend);
# endif
case Format::ADIOS2:
- throw std::runtime_error("ADIOS2 backend not yet implemented");
+ return std::make_shared(path, accessTypeBackend, comm);
default:
return std::make_shared< DummyIOHandler >(path, accessTypeBackend);
}
@@ -74,8 +75,10 @@ namespace openPMD
throw std::runtime_error("openPMD-api built without ADIOS1 support");
return std::make_shared< DummyIOHandler >(path, accessType);
# endif
+#if openPMD_HAVE_ADIOS2
case Format::ADIOS2:
- throw std::runtime_error("ADIOS2 backend not yet implemented");
+ return std::make_shared(path, accessType);
+#endif
case Format::JSON:
return std::make_shared< JSONIOHandler >(path, accessType);
default:
diff --git a/src/IO/InvalidatableFile.cpp b/src/IO/InvalidatableFile.cpp
new file mode 100644
index 0000000000..c6ffe525a8
--- /dev/null
+++ b/src/IO/InvalidatableFile.cpp
@@ -0,0 +1,90 @@
+/* Copyright 2017-2019 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 .
+ */
+
+#include "openPMD/IO/InvalidatableFile.hpp"
+
+
+openPMD::InvalidatableFile::InvalidatableFile( std::string s ) :
+ fileState { std::make_shared< FileState >( s ) }
+{}
+
+
+void openPMD::InvalidatableFile::invalidate( )
+{
+ fileState->valid = false;
+}
+
+
+bool openPMD::InvalidatableFile::valid( ) const
+{
+ return fileState->valid;
+}
+
+
+openPMD::InvalidatableFile &
+openPMD::InvalidatableFile::operator=( std::string s )
+{
+ if( fileState )
+ {
+ fileState->name = s;
+ }
+ else
+ {
+ fileState = std::make_shared< FileState >( s );
+ }
+ return *this;
+}
+
+
+bool
+openPMD::InvalidatableFile::operator==( const openPMD::InvalidatableFile & f ) const
+{
+ return this->fileState == f.fileState;
+}
+
+
+std::string & openPMD::InvalidatableFile::operator*( ) const
+{
+ return fileState->name;
+}
+
+
+std::string * openPMD::InvalidatableFile::operator->( ) const
+{
+ return &fileState->name;
+}
+
+
+openPMD::InvalidatableFile::operator bool( ) const
+{
+ return fileState.operator bool( );
+}
+
+
+openPMD::InvalidatableFile::FileState::FileState( std::string s ) :
+ name { std::move( s ) }
+{}
+
+std::hash< openPMD::InvalidatableFile >::result_type
+std::hash< openPMD::InvalidatableFile >::operator()( const openPMD::InvalidatableFile & s ) const noexcept
+{
+ return std::hash< shared_ptr< openPMD::InvalidatableFile::FileState>> {}( s.fileState );
+}
diff --git a/src/IO/JSON/JSONIOHandler.cpp b/src/IO/JSON/JSONIOHandler.cpp
index d945e41ae9..797156e85f 100644
--- a/src/IO/JSON/JSONIOHandler.cpp
+++ b/src/IO/JSON/JSONIOHandler.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Franz Pöschel
+/* Copyright 2017-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/src/IO/JSON/JSONIOHandlerImpl.cpp b/src/IO/JSON/JSONIOHandlerImpl.cpp
index 25e6b7a271..901f76f917 100644
--- a/src/IO/JSON/JSONIOHandlerImpl.cpp
+++ b/src/IO/JSON/JSONIOHandlerImpl.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2017-2019 Franz Pöschel
+/* Copyright 2017-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/src/Series.cpp b/src/Series.cpp
index eb91ed5a50..de6d8d0c2d 100644
--- a/src/Series.cpp
+++ b/src/Series.cpp
@@ -865,10 +865,13 @@ determineFormat(std::string const& filename)
if( auxiliary::ends_with(filename, ".h5") )
return Format::HDF5;
if( auxiliary::ends_with(filename, ".bp") )
+#if openPMD_HAVE_ADIOS2
+ return Format::ADIOS2;
+#else
return Format::ADIOS1;
+#endif
if( auxiliary::ends_with(filename, ".json") )
return Format::JSON;
-
if( std::string::npos != filename.find('.') /* extension is provided */ )
throw std::runtime_error("Unknown file format. Did you append a valid filename extension?");
diff --git a/src/benchmark/mpi/OneDimensionalBlockSlicer.cpp b/src/benchmark/mpi/OneDimensionalBlockSlicer.cpp
index bd0b391e3e..39a3675bb0 100644
--- a/src/benchmark/mpi/OneDimensionalBlockSlicer.cpp
+++ b/src/benchmark/mpi/OneDimensionalBlockSlicer.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2018-2019 Franz Pöschel
+/* Copyright 2018-2019 Franz Poeschel
*
* This file is part of openPMD-api.
*
diff --git a/test/SerialIOTest.cpp b/test/SerialIOTest.cpp
index ee29e5ab74..971816bbb0 100644
--- a/test/SerialIOTest.cpp
+++ b/test/SerialIOTest.cpp
@@ -23,14 +23,14 @@ std::vector> getBackends() {
// first component: backend file ending
// second component: whether to test 128 bit values
std::vector> res;
-#if openPMD_HAVE_ADIOS1
+#if openPMD_HAVE_JSON
+ res.emplace_back("json", false);
+#endif
+#if openPMD_HAVE_ADIOS1 || openPMD_HAVE_ADIOS2
res.emplace_back("bp", true);
#endif
#if openPMD_HAVE_HDF5
res.emplace_back("h5", true);
-#endif
-#if openPMD_HAVE_JSON
- res.emplace_back("json", false);
#endif
return res;
}
@@ -718,9 +718,12 @@ void fileBased_write_test(const std::string & backend)
o.setOpenPMDextension(1);
o.iterations[3].setTime(static_cast< double >(3));
}
- REQUIRE(auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000001." + backend));
- REQUIRE(auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000002." + backend));
- REQUIRE(auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000003." + backend));
+ REQUIRE((auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000001." + backend)
+ || auxiliary::directory_exists("../samples/subdir/serial_fileBased_write00000001." + backend)));
+ REQUIRE((auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000002." + backend)
+ || auxiliary::directory_exists("../samples/subdir/serial_fileBased_write00000002." + backend)));
+ REQUIRE((auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000003." + backend)
+ || auxiliary::directory_exists("../samples/subdir/serial_fileBased_write00000003." + backend)));
{
Series o = Series("../samples/subdir/serial_fileBased_write%T." + backend, AccessType::READ_ONLY);
@@ -789,7 +792,8 @@ void fileBased_write_test(const std::string & backend)
o.iterations[4];
REQUIRE(o.iterations.size() == 4);
}
- REQUIRE(auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000004." + backend));
+ REQUIRE((auxiliary::file_exists("../samples/subdir/serial_fileBased_write00000004." + backend)
+ || auxiliary::directory_exists("../samples/subdir/serial_fileBased_write00000004." + backend)));
// additional iteration with different iteration padding but similar content
{
@@ -806,7 +810,8 @@ void fileBased_write_test(const std::string & backend)
REQUIRE(o.iterations.size() == 1);
}
- REQUIRE(auxiliary::file_exists("../samples/subdir/serial_fileBased_write10." + backend));
+ REQUIRE((auxiliary::file_exists("../samples/subdir/serial_fileBased_write10." + backend)
+ || auxiliary::directory_exists("../samples/subdir/serial_fileBased_write10." + backend)));
// read back with auto-detection and non-fixed padding
{