diff --git a/CMakeLists.txt b/CMakeLists.txt index bf9972177f..a1bdfb4b62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -608,7 +608,6 @@ if(openPMD_HAVE_PYTHON) src/binding/python/BaseRecord.cpp src/binding/python/BaseRecordComponent.cpp src/binding/python/ChunkInfo.cpp - src/binding/python/Container.cpp src/binding/python/Dataset.cpp src/binding/python/Datatype.cpp src/binding/python/Error.cpp diff --git a/src/binding/python/Container.cpp b/include/openPMD/binding/python/Container.H similarity index 80% rename from src/binding/python/Container.cpp rename to include/openPMD/binding/python/Container.H index ef0a194637..86f98e74cf 100644 --- a/src/binding/python/Container.cpp +++ b/include/openPMD/binding/python/Container.H @@ -23,6 +23,8 @@ * * BSD-style license, see pybind11 LICENSE file. */ +#pragma once + #include "openPMD/backend/Container.hpp" #include "openPMD/binding/python/Common.hpp" @@ -33,7 +35,7 @@ #include #include -namespace detail +namespace openPMD { /* based on std_bind.h in pybind11 * @@ -46,7 +48,7 @@ template < typename holder_type = std::unique_ptr, typename... Args> py::class_ -bind_container(py::handle scope, std::string const &name, Args &&...args) +declare_container(py::handle scope, std::string const &name, Args &&...args) { using KeyType = typename Map::key_type; using MappedType = typename Map::mapped_type; @@ -101,6 +103,20 @@ bind_container(py::handle scope, std::string const &name, Args &&...args) return stream.str(); }); + return cl; +} + +template < + typename Map, + typename holder_type = std::unique_ptr, + typename... Args> +py::class_ +finalize_container(py::class_ cl) +{ + using KeyType = typename Map::key_type; + using MappedType = typename Map::mapped_type; + using Class_ = py::class_; + cl.def( "items", [](Map &m) { return py::make_iterator(m.begin(), m.end()); }, @@ -137,23 +153,4 @@ bind_container(py::handle scope, std::string const &name, Args &&...args) return cl; } -} // namespace detail - -void init_Container(py::module &m) -{ - ::detail::bind_container(m, "Iteration_Container"); - ::detail::bind_container(m, "Mesh_Container"); - ::detail::bind_container(m, "Particle_Container"); - ::detail::bind_container(m, "Particle_Patches_Container"); - ::detail::bind_container(m, "Record_Container"); - ::detail::bind_container( - m, "Patch_Record_Container"); - ::detail::bind_container( - m, "Record_Component_Container"); - ::detail::bind_container( - m, "Mesh_Record_Component_Container"); - ::detail::bind_container( - m, "Patch_Record_Component_Container"); - ::detail::bind_container( - m, "Base_Record_Component_Container"); -} +} // namespace openPMD diff --git a/src/binding/python/BaseRecord.cpp b/src/binding/python/BaseRecord.cpp index 7aeee2d38a..233ad90512 100644 --- a/src/binding/python/BaseRecord.cpp +++ b/src/binding/python/BaseRecord.cpp @@ -47,11 +47,13 @@ Returns true if this record only contains a single component. m, "Base_Record_Record_Component") .def_property_readonly( "scalar", &BaseRecord::scalar, doc_scalar); + py::class_< BaseRecord, Container >(m, "Base_Record_Mesh_Record_Component") .def_property_readonly( "scalar", &BaseRecord::scalar, doc_scalar); + py::class_< BaseRecord, Container >( diff --git a/src/binding/python/BaseRecordComponent.cpp b/src/binding/python/BaseRecordComponent.cpp index 95be596560..cf6f2d829c 100644 --- a/src/binding/python/BaseRecordComponent.cpp +++ b/src/binding/python/BaseRecordComponent.cpp @@ -22,12 +22,16 @@ #include "openPMD/Datatype.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" #include void init_BaseRecordComponent(py::module &m) { + auto py_brc_cont = declare_container( + m, "Base_Record_Component_Container"); + py::class_(m, "Base_Record_Component") .def( "__repr__", @@ -46,4 +50,6 @@ void init_BaseRecordComponent(py::module &m) .def_property_readonly("dtype", [](BaseRecordComponent &brc) { return dtype_to_numpy(brc.getDatatype()); }); + + finalize_container(py_brc_cont); } diff --git a/src/binding/python/Helper.cpp b/src/binding/python/Helper.cpp index e0aef84e0d..a7e6f209b4 100644 --- a/src/binding/python/Helper.cpp +++ b/src/binding/python/Helper.cpp @@ -38,7 +38,7 @@ void init_Helper(py::module &m) py::print(s.str()); }, py::arg("series"), - py::arg_v("longer", false, "Print more verbose output."), + py::arg("longer") = false, "List information about an openPMD data series") // CLI entry point .def( diff --git a/src/binding/python/Iteration.cpp b/src/binding/python/Iteration.cpp index 22e51aa974..a9dc2c23c8 100644 --- a/src/binding/python/Iteration.cpp +++ b/src/binding/python/Iteration.cpp @@ -21,6 +21,7 @@ #include "openPMD/Iteration.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include #include @@ -28,6 +29,9 @@ void init_Iteration(py::module &m) { + auto py_it_cont = + declare_container(m, "Iteration_Container"); + py::class_(m, "Iteration") .def(py::init()) @@ -93,4 +97,6 @@ void init_Iteration(py::module &m) py::return_value_policy::copy, // garbage collection: return value must be freed before Iteration py::keep_alive<1, 0>()); + + finalize_container(py_it_cont); } diff --git a/src/binding/python/Mesh.cpp b/src/binding/python/Mesh.cpp index e883e5e496..506e1bba70 100644 --- a/src/binding/python/Mesh.cpp +++ b/src/binding/python/Mesh.cpp @@ -23,6 +23,7 @@ #include "openPMD/backend/MeshRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" @@ -31,7 +32,17 @@ void init_Mesh(py::module &m) { + auto py_m_cont = declare_container(m, "Mesh_Container"); + py::class_ > cl(m, "Mesh"); + + py::enum_(m, "Geometry") // TODO: m -> cl + .value("cartesian", Mesh::Geometry::cartesian) + .value("thetaMode", Mesh::Geometry::thetaMode) + .value("cylindrical", Mesh::Geometry::cylindrical) + .value("spherical", Mesh::Geometry::spherical) + .value("other", Mesh::Geometry::other); + cl.def(py::init()) .def( @@ -107,10 +118,5 @@ void init_Mesh(py::module &m) return series.iterations[n_it].meshes[group.at(3)]; }); - py::enum_(m, "Geometry") - .value("cartesian", Mesh::Geometry::cartesian) - .value("thetaMode", Mesh::Geometry::thetaMode) - .value("cylindrical", Mesh::Geometry::cylindrical) - .value("spherical", Mesh::Geometry::spherical) - .value("other", Mesh::Geometry::other); + finalize_container(py_m_cont); } diff --git a/src/binding/python/MeshRecordComponent.cpp b/src/binding/python/MeshRecordComponent.cpp index 120fe00da2..e2e5e7b42a 100644 --- a/src/binding/python/MeshRecordComponent.cpp +++ b/src/binding/python/MeshRecordComponent.cpp @@ -24,6 +24,7 @@ #include "openPMD/Series.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include @@ -31,6 +32,9 @@ void init_MeshRecordComponent(py::module &m) { + auto py_mrc_cnt = declare_container( + m, "Mesh_Record_Component_Container"); + py::class_ cl( m, "Mesh_Record_Component"); cl.def( @@ -79,4 +83,6 @@ void init_MeshRecordComponent(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].meshes[group.at(3)][group.at(4)]; }); + + finalize_container(py_mrc_cnt); } diff --git a/src/binding/python/ParticlePatches.cpp b/src/binding/python/ParticlePatches.cpp index 326162191d..f04f36bf09 100644 --- a/src/binding/python/ParticlePatches.cpp +++ b/src/binding/python/ParticlePatches.cpp @@ -23,11 +23,15 @@ #include "openPMD/backend/PatchRecord.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include void init_ParticlePatches(py::module &m) { + auto py_pp_cnt = + declare_container(m, "Particle_Patches_Container"); + py::class_ >(m, "Particle_Patches") .def( "__repr__", @@ -40,4 +44,6 @@ void init_ParticlePatches(py::module &m) }) .def_property_readonly("num_patches", &ParticlePatches::numPatches); + + finalize_container(py_pp_cnt); } diff --git a/src/binding/python/ParticleSpecies.cpp b/src/binding/python/ParticleSpecies.cpp index 349ea8c689..7c3112029a 100644 --- a/src/binding/python/ParticleSpecies.cpp +++ b/src/binding/python/ParticleSpecies.cpp @@ -24,6 +24,7 @@ #include "openPMD/backend/Container.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include @@ -32,6 +33,9 @@ void init_ParticleSpecies(py::module &m) { + auto py_ps_cnt = + declare_container(m, "Particle_Container"); + py::class_ > cl(m, "ParticleSpecies"); cl.def( "__repr__", @@ -49,4 +53,6 @@ void init_ParticleSpecies(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].particles[group.at(3)]; }); + + finalize_container(py_ps_cnt); } diff --git a/src/binding/python/PatchRecord.cpp b/src/binding/python/PatchRecord.cpp index aaef39546c..efeea08a97 100644 --- a/src/binding/python/PatchRecord.cpp +++ b/src/binding/python/PatchRecord.cpp @@ -24,10 +24,14 @@ #include "openPMD/backend/PatchRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/UnitDimension.hpp" void init_PatchRecord(py::module &m) { + auto py_pr_cnt = + declare_container(m, "Patch_Record_Container"); + py::class_ >( m, "Patch_Record") .def_property( @@ -38,4 +42,6 @@ void init_PatchRecord(py::module &m) // TODO remove in future versions (deprecated) .def("set_unit_dimension", &PatchRecord::setUnitDimension); + + finalize_container(py_pr_cnt); } diff --git a/src/binding/python/PatchRecordComponent.cpp b/src/binding/python/PatchRecordComponent.cpp index e668f7a1d9..08059826e7 100644 --- a/src/binding/python/PatchRecordComponent.cpp +++ b/src/binding/python/PatchRecordComponent.cpp @@ -24,6 +24,7 @@ #include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" namespace @@ -42,6 +43,9 @@ struct Prc_Load void init_PatchRecordComponent(py::module &m) { + auto py_prc_cnt = declare_container( + m, "Patch_Record_Component_Container"); + py::class_( m, "Patch_Record_Component") .def_property( @@ -195,4 +199,6 @@ void init_PatchRecordComponent(py::module &m) // TODO remove in future versions (deprecated) .def("set_unit_SI", &PatchRecordComponent::setUnitSI); + + finalize_container(py_prc_cnt); } diff --git a/src/binding/python/Record.cpp b/src/binding/python/Record.cpp index d97641bbce..4b16088268 100644 --- a/src/binding/python/Record.cpp +++ b/src/binding/python/Record.cpp @@ -23,6 +23,7 @@ #include "openPMD/backend/BaseRecord.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" @@ -31,6 +32,8 @@ void init_Record(py::module &m) { + auto py_r_cnt = declare_container(m, "Record_Container"); + py::class_ > cl(m, "Record"); cl.def(py::init()) @@ -71,4 +74,6 @@ void init_Record(py::module &m) uint64_t const n_it = std::stoull(group.at(1)); return series.iterations[n_it].particles[group.at(3)][group.at(4)]; }); + + finalize_container(py_r_cnt); } diff --git a/src/binding/python/RecordComponent.cpp b/src/binding/python/RecordComponent.cpp index ee8bb7d3bd..f5ef98f6f6 100644 --- a/src/binding/python/RecordComponent.cpp +++ b/src/binding/python/RecordComponent.cpp @@ -25,6 +25,7 @@ #include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Container.H" #include "openPMD/binding/python/Numpy.hpp" #include "openPMD/binding/python/Pickle.hpp" @@ -757,6 +758,9 @@ void init_RecordComponent(py::module &m) return view.currentView(); }); + auto py_rc_cnt = declare_container( + m, "Record_Component_Container"); + py::class_ cl(m, "Record_Component"); cl.def( "__repr__", @@ -1122,6 +1126,8 @@ void init_RecordComponent(py::module &m) .particles[group.at(3)][group.at(4)][group.at(5)]; }); + finalize_container(py_rc_cnt); + py::enum_(m, "Allocation") .value("USER", RecordComponent::Allocation::USER) .value("API", RecordComponent::Allocation::API) diff --git a/src/binding/python/Series.cpp b/src/binding/python/Series.cpp index 241e14d69f..1a163e3a4f 100644 --- a/src/binding/python/Series.cpp +++ b/src/binding/python/Series.cpp @@ -67,6 +67,9 @@ struct SeriesIteratorPythonAdaptor : SeriesIterator void init_Series(py::module &m) { + py::class_(m, "IndexedIteration") + .def_readonly("iteration_index", &IndexedIteration::iterationIndex); + py::class_(m, "WriteIterations", R"END( Writing side of the streaming API. @@ -100,8 +103,6 @@ not possible once it has been closed. &WriteIterations::currentIteration, "Return the iteration that is currently being written to, if it " "exists."); - py::class_(m, "IndexedIteration") - .def_readonly("iteration_index", &IndexedIteration::iterationIndex); py::class_(m, "SeriesIterator") .def( diff --git a/src/binding/python/openPMD.cpp b/src/binding/python/openPMD.cpp index 28b56b7d9c..da6ebb0ebd 100644 --- a/src/binding/python/openPMD.cpp +++ b/src/binding/python/openPMD.cpp @@ -33,7 +33,6 @@ void init_Attributable(py::module &); void init_BaseRecord(py::module &); void init_BaseRecordComponent(py::module &); void init_Chunk(py::module &m); -void init_Container(py::module &); void init_Dataset(py::module &); void init_Datatype(py::module &); void init_Error(py::module &); @@ -86,25 +85,29 @@ PYBIND11_MODULE(openpmd_api_cxx, m) init_UnitDimension(m); init_Attributable(m); init_Chunk(m); - init_Container(m); init_Error(m); - init_BaseRecord(m); - init_Dataset(m); + init_Datatype(m); - init_Helper(m); - init_Iteration(m); - init_IterationEncoding(m); - init_Mesh(m); + init_Dataset(m); + init_BaseRecordComponent(m); init_RecordComponent(m); init_MeshRecordComponent(m); - init_ParticlePatches(m); - init_PatchRecord(m); init_PatchRecordComponent(m); - init_ParticleSpecies(m); + + init_BaseRecord(m); init_Record(m); + init_PatchRecord(m); + init_ParticlePatches(m); + init_ParticleSpecies(m); + init_Mesh(m); + + init_Iteration(m); + init_IterationEncoding(m); init_Series(m); + init_Helper(m); + // API runtime version m.attr("__version__") = openPMD::getVersion();