Skip to content

Commit 6d9b9da

Browse files
authored
AMReX SoA Named Components (#382)
Replace our own named SoA particle components implementation with the now upstream support in AMReX. Early draft, unfinished. - [x] add new APIs from AMReX-Codes/amrex#4300 - [x] rebase after #404 --------- Signed-off-by: Axel Huebl <[email protected]>
1 parent 7657e08 commit 6d9b9da

File tree

5 files changed

+66
-96
lines changed

5 files changed

+66
-96
lines changed

src/Particle/ParticleContainer.H

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ void make_ParticleContainer_and_Iterators (py::module &m, std::string allocstr)
204204
.def_property_readonly("num_position_components", [](const py::object&){ return AMREX_SPACEDIM; })
205205
.def_property_readonly("byte_spread", &ParticleContainerType::ByteSpread)
206206

207+
// compile-time components
208+
.def("set_soa_compile_time_names", &ParticleContainerType::SetSoACompileTimeNames)
209+
207210
// runtime components
208211
.def("add_real_comp", py::overload_cast<int>(&ParticleContainerType::AddRealComp),
209212
py::arg("communicate")=1,
@@ -224,6 +227,33 @@ void make_ParticleContainer_and_Iterators (py::module &m, std::string allocstr)
224227
"add a new runtime component with type Int"
225228
)
226229

230+
.def_property_readonly("real_soa_names",
231+
&ParticleContainerType::GetRealSoANames,
232+
"Get the names for the Real SoA components"
233+
)
234+
.def_property_readonly("int_soa_names",
235+
&ParticleContainerType::GetIntSoANames,
236+
"Get the names for the int SoA components"
237+
)
238+
239+
.def("has_real_comp",
240+
&ParticleContainerType::HasRealComp,
241+
"Check if a container has an ParticleReal component"
242+
)
243+
.def("has_int_comp",
244+
&ParticleContainerType::HasIntComp,
245+
"Check if a container has an Integer component"
246+
)
247+
248+
.def("get_real_comp_index",
249+
&ParticleContainerType::GetRealCompIndex,
250+
"Get the ParticleReal SoA index of a component"
251+
)
252+
.def("get_int_comp_index",
253+
&ParticleContainerType::GetIntCompIndex,
254+
"Get the Integer SoA index of a component"
255+
)
256+
227257
.def_property_readonly("finest_level", &ParticleContainerBase::finestLevel)
228258

229259
// ParticleContainer ( const ParticleContainer &) = delete;

src/Particle/StructOfArrays.H

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ void make_StructOfArrays(py::module &m, std::string allocstr)
5656
py::arg("index"),
5757
"Get access to a particle Real component Array (compile-time and runtime component)")
5858

59+
// names
60+
.def_property_readonly("real_names",
61+
&SOAType::GetRealNames,
62+
"Names for the Real SoA components"
63+
)
64+
.def_property_readonly("int_names",
65+
&SOAType::GetIntNames,
66+
"Names for the int SoA components"
67+
)
68+
5969
.def("__len__", &SOAType::size,
6070
"Get the number of particles")
6171
.def_property_readonly("size", &SOAType::size,

src/amrex/extensions/ParticleComponentNames.py

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/amrex/extensions/StructOfArrays.py

Lines changed: 12 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -9,71 +9,6 @@
99
from collections import namedtuple
1010

1111

12-
def soa_real_comps(self, num_comps, spacedim=3, rotate=True):
13-
"""
14-
Name the ParticleReal components in SoA.
15-
16-
Parameters
17-
----------
18-
self : SoA Type
19-
maybe unused, depending on implementation
20-
num_comps : int
21-
number of components to generate names for.
22-
spacedim : int
23-
AMReX dimensionality
24-
rotate : bool = True
25-
start with "x", "y", "z", "a", "b", ...
26-
27-
Returns
28-
-------
29-
A list of length num_comps with values
30-
rotate=True (for pure SoA layout):
31-
- 3D: "x", "y", "z", "a", "b", ... "w", "r0", "r1", ...
32-
- 2D: "x", "y", "a", "b", ... "w", "r0", "r1", ...
33-
- 1D: "x", "a", "b", ... "w", "r0", "r1", ...
34-
rotate=False (for legacy layout):
35-
- 1D-3D: "a", "b", ... "w", "r0", "r1", ...
36-
"""
37-
import string
38-
39-
# x, y, z, a, b, ...
40-
comp_names = list(string.ascii_lowercase)
41-
if rotate:
42-
# rotate x, y, z to be beginning (positions)
43-
comp_names = comp_names[-3:] + comp_names[:-3]
44-
else:
45-
# cut off x, y, z to avoid confusion
46-
comp_names = comp_names[:-3]
47-
48-
num_named = len(comp_names)
49-
if num_comps < num_named:
50-
comp_names = list(comp_names)[0:num_comps]
51-
elif num_comps > num_named:
52-
comp_names.extend(["r" + str(i) for i in range(num_comps - num_named)])
53-
54-
return comp_names
55-
56-
57-
def soa_int_comps(self, num_comps):
58-
"""
59-
Name the int components in SoA.
60-
61-
Parameters
62-
----------
63-
self : SoA Type
64-
maybe unused, depending on implementation
65-
num_comps : int
66-
number of components to generate names for.
67-
68-
Returns
69-
-------
70-
A list of length num_comps with values "i1", "i2", "i3", ...
71-
"""
72-
comp_names = ["i" + str(i) for i in range(num_comps)]
73-
74-
return comp_names
75-
76-
7712
def soa_to_numpy(self, copy=False):
7813
"""
7914
Provide NumPy views into a StructOfArrays.
@@ -107,18 +42,17 @@ def soa_to_numpy(self, copy=False):
10742
else:
10843
soa_view = SoA_np({}, {}, None)
10944

110-
# for the legacy data layout, do not start with x, y, z but with a, b, c, ...
111-
if self.has_idcpu:
112-
real_comp_names = self.soa_real_comps(self.num_real_comps)
113-
else:
114-
real_comp_names = self.soa_real_comps(self.num_real_comps, rotate=False)
115-
45+
real_comp_names = self.real_names
46+
if len(real_comp_names) != self.num_real_comps:
47+
raise ValueError("Missing names for SoA Real components.")
11648
for idx_real in range(self.num_real_comps):
11749
soa_view.real[real_comp_names[idx_real]] = self.get_real_data(
11850
idx_real
11951
).to_numpy(copy=copy)
12052

121-
int_comp_names = self.soa_int_comps(self.num_int_comps)
53+
int_comp_names = self.int_names
54+
if len(int_comp_names) != self.num_int_comps:
55+
raise ValueError("Missing names for SoA int components.")
12256
for idx_int in range(self.num_int_comps):
12357
soa_view.int[int_comp_names[idx_int]] = self.get_int_data(idx_int).to_numpy(
12458
copy=copy
@@ -165,18 +99,17 @@ def soa_to_cupy(self, copy=False):
16599
else:
166100
soa_view = SoA_cp({}, {}, None)
167101

168-
# for the legacy data layout, do not start with x, y, z but with a, b, c, ...
169-
if self.has_idcpu:
170-
real_comp_names = self.soa_real_comps(self.num_real_comps)
171-
else:
172-
real_comp_names = self.soa_real_comps(self.num_real_comps, rotate=False)
173-
102+
real_comp_names = self.real_names
103+
if len(real_comp_names) != self.num_real_comps:
104+
raise ValueError("Missing names for SoA Real components.")
174105
for idx_real in range(self.num_real_comps):
175106
soa_view.real[real_comp_names[idx_real]] = self.get_real_data(idx_real).to_cupy(
176107
copy=copy
177108
)
178109

179-
int_comp_names = self.soa_int_comps(self.num_int_comps)
110+
int_comp_names = self.int_names
111+
if len(int_comp_names) != self.num_int_comps:
112+
raise ValueError("Missing names for SoA int components.")
180113
for idx_int in range(self.num_int_comps):
181114
soa_view.int[int_comp_names[idx_int]] = self.get_int_data(idx_int).to_cupy(
182115
copy=copy
@@ -226,10 +159,6 @@ def register_SoA_extension(amr):
226159
and member.__module__ == amr.__name__
227160
and member.__name__.startswith("StructOfArrays_"),
228161
):
229-
# name providers
230-
SoA_type.soa_real_comps = soa_real_comps
231-
SoA_type.soa_int_comps = soa_int_comps
232-
233162
# converters
234163
SoA_type.to_numpy = soa_to_numpy
235164
SoA_type.to_cupy = soa_to_cupy

tests/test_particleContainer.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ def particle_container(Npart, std_geometry, distmap, boxarr, std_real_box):
5757
pc.init_random(Npart, iseed, myt, False, std_real_box)
5858

5959
# add runtime components: 1 real 2 int
60-
pc.add_real_comp(True)
61-
pc.add_int_comp(True)
62-
pc.add_int_comp(True)
60+
pc.add_real_comp("b", True)
61+
pc.add_int_comp("i1", True)
62+
pc.add_int_comp("i2", True)
6363

6464
# assign some values to runtime components
6565
for lvl in range(pc.finest_level + 1):
@@ -79,13 +79,21 @@ def soa_particle_container(Npart, std_geometry, distmap, boxarr, std_real_box):
7979
myt.real_array_data = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
8080
myt.int_array_data = []
8181

82+
with pytest.raises(Exception):
83+
pc.set_soa_compile_time_names(
84+
["x", "y", "z", "z", "b", "c", "d", "e"], []
85+
) # error: z added twice
86+
pc.set_soa_compile_time_names(["x", "y", "z", "a", "b", "c", "d", "e"], [])
87+
8288
iseed = 1
8389
pc.init_random(Npart, iseed, myt, False, std_real_box)
8490

8591
# add runtime components: 1 real 2 int
86-
pc.add_real_comp(True)
87-
pc.add_int_comp(True)
88-
pc.add_int_comp(True)
92+
with pytest.raises(Exception):
93+
pc.add_real_comp("a", True) # already used as a compile-time component
94+
pc.add_real_comp("f", True)
95+
pc.add_int_comp("i1", True)
96+
pc.add_int_comp("i2", True)
8997

9098
# assign some values to runtime components
9199
for lvl in range(pc.finest_level + 1):

0 commit comments

Comments
 (0)