Skip to content

Commit 2e89f87

Browse files
Remove necessity for RecordComponent::SCALAR (#1154)
* Add helper: openPMD::auxiliary::overloaded * Prepare Attributable for virtual inheritance Use only zero-param constructors to avoid diamond initialization pitfalls * Fix default constructors/operators of Container and BaseRecordComponent These derive virtually from Attributable, and this avoids that pitfalls propagate to user code. * Add m_datasetDefined See in-code documentation. * Prepare class structure without applying logic yet BaseRecord is now derived by its contained RecordComponent type. If it is scalar, the idea is that the BaseRecord itself is used as a RecordComponent, without needing to retrieve the [SCALAR] entry. No logic implemented yet around this, this just prepares the class structure. Notice that this will write some unnecessary attributes since the RecordComponent types initialize some default attributes upon construction. * No longer use map entry SCALAR in application logic Not yet supported: Backward compatibility for still allowing legacy access to scalar entries * Remove KEEP_SYNCHRONOUS task No longer needed, as one object in the openPMD hierarchy is no longer represented by possibly multiple Writable objects. * Adapt Coretests * No virtual methods in Container class Either this way, or make all of them virtual * Fully override Container methods in BaseRecord Special care for legacy usage of SCALAR constant. Implement iteration API such that it works for scalar components as well. * Adapt Container API to C++17 insert() and reverse iterators * Adapt myPath() functionality * Factor out create_and_bind_container() function template Will later be called by Record-type classes, too * Factor out RecordComponent.__setitem__ and __getitem__ Similarly to the Container API, we will need to apply this to Record-type classes. Defining `__setitem__` and `__getitem__` for them is sufficient, as all other members are inherited from RecordComponent. `__setitem__` and `__getitem__` need special care, as they are inherited from Container AND from RecordComponent, so some conflict resolution is needed. * Consistently use copy semantics in Python API * Apply new class structure to Python API as well * Adapt openpmd-pipe to new design This somewhat demonstrates that this change is slightly API-breaking. Since openpmd-pipe acts directly on the class structure via `instanceof()`, fixes are necessary. * Safeguard: No scalar and vector components side by side "A scalar component can not be contained at the same time as one or more regular components." * Remove [SCALAR] from all examples * Avoid object slicing when using records as scalar components * Documentation * Adapt to refactored Python bindings after rebasing
1 parent e965f69 commit 2e89f87

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1572
-703
lines changed

CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,6 @@ set(CORE_SOURCE
462462
src/auxiliary/JSON.cpp
463463
src/backend/Attributable.cpp
464464
src/backend/BaseRecordComponent.cpp
465-
src/backend/Container.cpp
466465
src/backend/MeshRecordComponent.cpp
467466
src/backend/PatchRecord.cpp
468467
src/backend/PatchRecordComponent.cpp
@@ -605,7 +604,6 @@ if(openPMD_HAVE_PYTHON)
605604
src/binding/python/openPMD.cpp
606605
src/binding/python/Access.cpp
607606
src/binding/python/Attributable.cpp
608-
src/binding/python/BaseRecord.cpp
609607
src/binding/python/BaseRecordComponent.cpp
610608
src/binding/python/ChunkInfo.cpp
611609
src/binding/python/Dataset.cpp

docs/source/usage/concepts.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ A record is an data set with common properties, e.g. the electric field :math:`\
2020
A density field could be another record - which is scalar as it only has one component.
2121

2222
In general, openPMD allows records with arbitrary number of components (tensors), as well as vector records and scalar records.
23+
In the case of vector records, the single components are stored as datasets within the record.
24+
In the case of scalar records, the record and component are equivalent.
25+
In the API, the record can be directly used as a component, and in the standard a scalar record is represented by the scalar dataset with attributes.
2326

2427
Meshes and Particles
2528
--------------------

examples/10_streaming_write.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
temperature.axis_labels = ["x", "y"]
7070
temperature.grid_spacing = [1., 1.]
7171
# temperature has no x,y,z components, so skip the last layer:
72-
temperature_dataset = temperature[io.Mesh_Record_Component.SCALAR]
72+
temperature_dataset = temperature
7373
# let's say we are in a 3x3 mesh
7474
temperature_dataset.reset_dataset(
7575
io.Dataset(np.dtype("double"), [3, 3]))

examples/12_span_write.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ void span_write(std::string const &filename)
9090

9191
using mesh_type = position_t;
9292

93-
RecordComponent chargeDensity =
94-
iteration.meshes["e_chargeDensity"][RecordComponent::SCALAR];
93+
Mesh chargeDensity = iteration.meshes["e_chargeDensity"];
9594

9695
/*
9796
* A similar memory optimization is possible by using a unique_ptr type

examples/13_write_dynamic_configuration.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ chunks = "auto"
124124
Dataset differentlyCompressedDataset{Datatype::INT, {10}};
125125
differentlyCompressedDataset.options = differentCompressionSettings;
126126

127-
auto someMesh = iteration.meshes["differentCompressionSettings"]
128-
[RecordComponent::SCALAR];
127+
auto someMesh = iteration.meshes["differentCompressionSettings"];
129128
someMesh.resetDataset(differentlyCompressedDataset);
130129
std::vector<int> dataVec(10, i);
131130
someMesh.storeChunk(dataVec, {0}, {10});

examples/13_write_dynamic_configuration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def main():
130130
temperature.axis_labels = ["x", "y"]
131131
temperature.grid_spacing = [1., 1.]
132132
# temperature has no x,y,z components, so skip the last layer:
133-
temperature_dataset = temperature[io.Mesh_Record_Component.SCALAR]
133+
temperature_dataset = temperature
134134
# let's say we are in a 3x3 mesh
135135
dataset = io.Dataset(np.dtype("double"), [3, 3])
136136
dataset.options = json.dumps(config)

examples/1_structure.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ int main()
5454
* differently.
5555
* https://github.com/openPMD/openPMD-standard/blob/latest/STANDARD.md#scalar-vector-and-tensor-records*/
5656
Record mass = electrons["mass"];
57-
RecordComponent mass_scalar = mass[RecordComponent::SCALAR];
5857

5958
Dataset dataset = Dataset(Datatype::DOUBLE, Extent{1});
60-
mass_scalar.resetDataset(dataset);
59+
mass.resetDataset(dataset);
6160

6261
/* Required Records and RecordComponents are created automatically.
6362
* Initialization has to be done explicitly by the user. */

examples/2_read_serial.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ int main()
5858
}
5959

6060
openPMD::ParticleSpecies electrons = i.particles["electrons"];
61-
std::shared_ptr<double> charge =
62-
electrons["charge"][openPMD::RecordComponent::SCALAR]
63-
.loadChunk<double>();
61+
std::shared_ptr<double> charge = electrons["charge"].loadChunk<double>();
6462
series.flush();
6563
cout << "And the first electron particle has a charge = "
6664
<< charge.get()[0];

examples/2_read_serial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
# printing a scalar value
3636
electrons = i.particles["electrons"]
37-
charge = electrons["charge"][io.Mesh_Record_Component.SCALAR]
37+
charge = electrons["charge"]
3838
series.flush()
3939
print("And the first electron particle has a charge {}"
4040
.format(charge[0]))

examples/3_write_serial.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ int main(int argc, char *argv[])
4949
// in streaming setups, e.g. an iteration cannot be opened again once
5050
// it has been closed.
5151
// `Series::iterations` can be directly accessed in random-access workflows.
52-
MeshRecordComponent rho =
53-
series.writeIterations()[1].meshes["rho"][MeshRecordComponent::SCALAR];
52+
Mesh rho = series.writeIterations()[1].meshes["rho"];
5453
cout << "Created a scalar mesh Record with all required openPMD "
5554
"attributes\n";
5655

0 commit comments

Comments
 (0)