Skip to content

Commit

Permalink
Fix & Replace Python Data_Order
Browse files Browse the repository at this point in the history
The `Data_Order` enum in python and thus `Mesh::data_order` are
broken due to an upstream bug in pybind11 with non-int enums.

Replace the setter and read-only property with a unified property
and remove the enum for the sake of simplicity (just compare to a
char in popular Python "enums are strings, better spell it right"-
manner).
  • Loading branch information
ax3l committed Dec 20, 2020
1 parent 940bb5d commit af9161f
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 13 deletions.
19 changes: 19 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@ Upgrade Guide
Building openPMD-api now requires a compiler that supports C++14 or newer.
Supported Python version are now 3.6 to 3.9.

Python
^^^^^^

Reading the ``data_order`` of a mesh was broken.
The old setter function (``set_data_order``) and read-only property (``data_order``) are now unified in a single, writable property:

.. code-block:: python3
import openpmd_api as io
series = io.Series("data%T.h5", io.Access.read_only)
rho = series.iterations[0].meshes["rho"]
rho.data_order = 'C' # or 'F'
print(rho.data_order == 'C') # True
Note: we recommend using ``'C'`` order since version 2 of the openPMD-standard will simplify this option to ``'C'``, too.
For Fortran-ordered indices, please just invert the attributes ``axis_labels``, ``grid_spacing`` and ``grid_global_offset`` accordingly.


0.12.0-alpha
------------
Expand Down
2 changes: 1 addition & 1 deletion examples/3a_write_thetaMode_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
E = series.iterations[0].meshes["E"]
E.set_geometry(io.Geometry.thetaMode)
E.set_geometry_parameters(geometry_parameters)
E.set_data_order(io.Data_Order.C)
E.set_grid_spacing([1.0, 1.0])
E.set_grid_global_offset([0.0, 0.0])
E.set_grid_unit_SI(1.0)
E.set_axis_labels(["r", "z"])
E.data_order = "C"
E.unit_dimension = {io.Unit_Dimension.I: 1.0,
io.Unit_Dimension.J: 2.0}

Expand Down
12 changes: 5 additions & 7 deletions src/binding/python/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,11 @@ void init_Mesh(py::module &m) {
.def("set_geometry", &Mesh::setGeometry)
.def_property_readonly("geometry_parameters", &Mesh::geometryParameters)
.def("set_geometry_parameters", &Mesh::setGeometryParameters)
.def_property_readonly("data_order", &Mesh::dataOrder)
.def("set_data_order", &Mesh::setDataOrder)
.def_property("data_order",
[](Mesh const & mesh){ return static_cast< char >(mesh.dataOrder()); },
[](Mesh & mesh, char d){ mesh.setDataOrder(Mesh::DataOrder(d)); },
"Data Order of the Mesh (deprecated and set to C in openPMD 2)"
)
.def_property_readonly("axis_labels", &Mesh::axisLabels)
.def("set_axis_labels", &Mesh::setAxisLabels)
.def_property_readonly("grid_spacing", &Mesh::gridSpacing<float>)
Expand Down Expand Up @@ -80,9 +83,4 @@ void init_Mesh(py::module &m) {
.value("cylindrical", Mesh::Geometry::cylindrical)
.value("spherical", Mesh::Geometry::spherical)
;

py::enum_<Mesh::DataOrder>(m, "Data_Order")
.value("C", Mesh::DataOrder::C)
.value("F", Mesh::DataOrder::F)
;
}
15 changes: 10 additions & 5 deletions test/python/unittest/API/APITest.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,12 @@ def makeConstantRoundTrip(self, file_ending):
ms["pybool"][SCALAR].reset_dataset(DS(DT.BOOL, extent))
ms["pybool"][SCALAR].make_constant(False)

# just testing the data_order attribute
ms["char"].data_order = 'C'
ms["pyint"].data_order = 'F'
self.assertEqual(ms["char"].data_order, 'C')
self.assertEqual(ms["pyint"].data_order, 'F')

# staggering meta data
ms["pyint"][SCALAR].position = [0.25, 0.5]
ms["pyfloat"][SCALAR].position = [0.5, 0.75]
Expand Down Expand Up @@ -457,6 +463,9 @@ def makeConstantRoundTrip(self, file_ending):
o = [1, 2, 3]
e = [1, 1, 1]

self.assertEqual(ms["char"].data_order, 'C')
self.assertEqual(ms["pyint"].data_order, 'F')

self.assertTrue(ms["char"].scalar)
self.assertTrue(ms["pyint"].scalar)
self.assertTrue(ms["pyfloat"].scalar)
Expand Down Expand Up @@ -1267,11 +1276,6 @@ def testParticles(self):
# self.assertIsInstance(ps, str)
self.assertIsInstance(i.particles[ps], io.ParticleSpecies)

def testData_Order(self):
""" Test Data_Order. """
obj = io.Data_Order('C')
del obj

def testDatatype(self):
""" Test Datatype. """
data_type = io.Datatype(1)
Expand Down Expand Up @@ -1320,6 +1324,7 @@ def testMesh(self):
self.assertRaises(TypeError, io.Mesh)
mesh = self.__series.iterations[100].meshes['E']
copy_mesh = io.Mesh(mesh)
self.assertEqual(mesh.data_order, 'C')

self.assertIsInstance(copy_mesh, io.Mesh)

Expand Down

0 comments on commit af9161f

Please sign in to comment.