Skip to content

Commit e7ddd89

Browse files
committed
Add simple Python bindings and an example
1 parent 8704c1c commit e7ddd89

File tree

6 files changed

+101
-15
lines changed

6 files changed

+101
-15
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ if(openPMD_HAVE_PYTHON)
602602
src/binding/python/BaseRecordComponent.cpp
603603
src/binding/python/ChunkInfo.cpp
604604
src/binding/python/Container.cpp
605+
src/binding/python/CustomHierarchy.cpp
605606
src/binding/python/Dataset.cpp
606607
src/binding/python/Datatype.cpp
607608
src/binding/python/Error.cpp
@@ -773,6 +774,7 @@ set(openPMD_PYTHON_EXAMPLE_NAMES
773774
11_particle_dataframe
774775
12_span_write
775776
13_write_dynamic_configuration
777+
14_custom_hierarchy
776778
)
777779

778780
if(openPMD_USE_INVASIVE_TESTS)

examples/14_custom_hierarchy.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import numpy as np
2+
import openpmd_api as io
3+
4+
5+
def main():
6+
if "bp" in io.file_extensions:
7+
filename = "../samples/custom_hierarchy.bp"
8+
else:
9+
filename = "../samples/custom_hierarchy.json"
10+
s = io.Series(filename, io.Access.create)
11+
it = s.write_iterations()[100]
12+
13+
# write openPMD part
14+
temp = it.meshes["temperature"]
15+
temp.axis_labels = ["x", "y"]
16+
temp.unit_dimension = {io.Unit_Dimension.T: 1}
17+
temp.position = [0.5, 0.5]
18+
temp.grid_spacing = [1, 1]
19+
temp.grid_global_offset = [0, 0]
20+
temp.reset_dataset(io.Dataset(np.dtype("double"), [5, 5]))
21+
temp[()] = np.zeros((5, 5))
22+
23+
# write NeXus part
24+
nxentry = it["Scan"]
25+
nxentry.set_attribute("NX_class", "NXentry")
26+
nxentry.set_attribute("default", "data")
27+
28+
data = nxentry["data"]
29+
data.set_attribute("NX_class", "NXdata")
30+
data.set_attribute("signal", "counts")
31+
data.set_attribute("axes", ["two_theta"])
32+
data.set_attribute("two_theta_indices", [0])
33+
34+
counts = data.as_container_of_datasets()["counts"]
35+
counts.set_attribute("units", "counts")
36+
counts.set_attribute("long_name", "photodiode counts")
37+
counts.reset_dataset(io.Dataset(np.dtype("int"), [15]))
38+
counts[()] = np.zeros(15, dtype=np.dtype("int"))
39+
40+
two_theta = data.as_container_of_datasets()["two_theta"]
41+
two_theta.set_attribute("units", "degrees")
42+
two_theta.set_attribute("long_name", "two_theta (degrees)")
43+
two_theta.reset_dataset(io.Dataset(np.dtype("double"), [15]))
44+
two_theta[()] = np.zeros(15)
45+
46+
47+
if __name__ == "__main__":
48+
main()

src/binding/python/Container.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <pybind11/pybind11.h>
2828

29+
#include "openPMD/CustomHierarchy.hpp"
2930
#include "openPMD/Iteration.hpp"
3031
#include "openPMD/Mesh.hpp"
3132
#include "openPMD/ParticlePatches.hpp"
@@ -52,6 +53,7 @@ using PyPatchRecordContainer = Container<PatchRecord>;
5253
using PyRecordComponentContainer = Container<RecordComponent>;
5354
using PyMeshRecordComponentContainer = Container<MeshRecordComponent>;
5455
using PyPatchRecordComponentContainer = Container<PatchRecordComponent>;
56+
using PyCustomHierarchyContainer = Container<CustomHierarchy>;
5557
PYBIND11_MAKE_OPAQUE(PyIterationContainer)
5658
PYBIND11_MAKE_OPAQUE(PyMeshContainer)
5759
PYBIND11_MAKE_OPAQUE(PyPartContainer)
@@ -61,6 +63,7 @@ PYBIND11_MAKE_OPAQUE(PyPatchRecordContainer)
6163
PYBIND11_MAKE_OPAQUE(PyRecordComponentContainer)
6264
PYBIND11_MAKE_OPAQUE(PyMeshRecordComponentContainer)
6365
PYBIND11_MAKE_OPAQUE(PyPatchRecordComponentContainer)
66+
PYBIND11_MAKE_OPAQUE(PyCustomHierarchyContainer)
6467

6568
void init_Container(py::module &m)
6669
{
@@ -85,4 +88,7 @@ void init_Container(py::module &m)
8588
::detail::create_and_bind_container<
8689
PyPatchRecordComponentContainer,
8790
Attributable>(m, "Patch_Record_Component_Container");
91+
::detail::
92+
create_and_bind_container<PyCustomHierarchyContainer, Attributable>(
93+
m, "Custom_Hierarchy_Container");
8894
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
3+
#include "openPMD/CustomHierarchy.hpp"
4+
#include "openPMD/ParticleSpecies.hpp"
5+
#include "openPMD/RecordComponent.hpp"
6+
#include "openPMD/backend/Attributable.hpp"
7+
#include <pybind11/pybind11.h>
8+
9+
namespace py = pybind11;
10+
using namespace openPMD;
11+
12+
void init_CustomHierarchy(py::module &m)
13+
{
14+
py::class_<CustomHierarchy, Container<CustomHierarchy>, Attributable>(
15+
m, "CustomHierarchy")
16+
.def(
17+
"as_container_of_datasets",
18+
&CustomHierarchy::asContainerOf<RecordComponent>)
19+
.def("as_container_of_meshes", &CustomHierarchy::asContainerOf<Mesh>)
20+
.def(
21+
"as_container_of_particles",
22+
&CustomHierarchy::asContainerOf<ParticleSpecies>)
23+
24+
.def_readwrite(
25+
"meshes",
26+
&CustomHierarchy::meshes,
27+
py::return_value_policy::copy,
28+
// garbage collection: return value must be freed before Iteration
29+
py::keep_alive<1, 0>())
30+
.def_readwrite(
31+
"particles",
32+
&CustomHierarchy::particles,
33+
py::return_value_policy::copy,
34+
// garbage collection: return value must be freed before Iteration
35+
py::keep_alive<1, 0>());
36+
}

src/binding/python/Iteration.cpp

+7-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <pybind11/pybind11.h>
2222
#include <pybind11/stl.h>
2323

24+
#include "openPMD/CustomHierarchy.hpp"
2425
#include "openPMD/Iteration.hpp"
2526

2627
#include <ios>
@@ -32,7 +33,11 @@ using namespace openPMD;
3233

3334
void init_Iteration(py::module &m)
3435
{
35-
py::class_<Iteration, Attributable>(m, "Iteration")
36+
py::class_<
37+
Iteration,
38+
CustomHierarchy,
39+
Container<CustomHierarchy>,
40+
Attributable>(m, "Iteration")
3641
.def(py::init<Iteration const &>())
3742

3843
.def(
@@ -83,18 +88,5 @@ void init_Iteration(py::module &m)
8388
// TODO remove in future versions (deprecated)
8489
.def("set_time", &Iteration::setTime<double>)
8590
.def("set_dt", &Iteration::setDt<double>)
86-
.def("set_time_unit_SI", &Iteration::setTimeUnitSI)
87-
88-
.def_readwrite(
89-
"meshes",
90-
&Iteration::meshes,
91-
py::return_value_policy::copy,
92-
// garbage collection: return value must be freed before Iteration
93-
py::keep_alive<1, 0>())
94-
.def_readwrite(
95-
"particles",
96-
&Iteration::particles,
97-
py::return_value_policy::copy,
98-
// garbage collection: return value must be freed before Iteration
99-
py::keep_alive<1, 0>());
91+
.def("set_time_unit_SI", &Iteration::setTimeUnitSI);
10092
}

src/binding/python/openPMD.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ void init_Dataset(py::module &);
4141
void init_Datatype(py::module &);
4242
void init_Error(py::module &);
4343
void init_Helper(py::module &);
44+
void init_CustomHierarchy(py::module &);
4445
void init_Iteration(py::module &);
4546
void init_IterationEncoding(py::module &);
4647
void init_Mesh(py::module &);
@@ -94,6 +95,7 @@ PYBIND11_MODULE(openpmd_api_cxx, m)
9495
init_Dataset(m);
9596
init_Datatype(m);
9697
init_Helper(m);
98+
init_CustomHierarchy(m);
9799
init_Iteration(m);
98100
init_IterationEncoding(m);
99101
init_BaseRecordComponent(m);

0 commit comments

Comments
 (0)