Skip to content

Commit 0ff04ad

Browse files
committed
Reviewer comments
1 parent c3ba25e commit 0ff04ad

File tree

4 files changed

+35
-47
lines changed

4 files changed

+35
-47
lines changed

lib/python/picongpu/picmi/simulation.py

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def get_as_pypicongpu(self) -> pypicongpu.simulation.Simulation:
369369
typical_ppc = (
370370
self.picongpu_typical_ppc
371371
if self.picongpu_typical_ppc is not None
372-
else mid_window(map(lambda op: op.layout.ppc, filter(lambda op: hasattr(op, "layout"), init_operations)))
372+
else _mid_window(map(lambda op: op.layout.ppc, filter(lambda op: hasattr(op, "layout"), init_operations)))
373373
)
374374
moving_window = (
375375
None
@@ -402,23 +402,6 @@ def get_as_pypicongpu(self) -> pypicongpu.simulation.Simulation:
402402
)
403403

404404
def _get_base_density(self) -> float:
405-
# There's supposed to be some heuristics here along the lines of
406-
# num_grid = (
407-
# np.reshape([grid.cell_size_x_si, grid.cell_size_y_si, grid.cell_size_z_si], (-1, 1, 1, 1))
408-
# * np.mgrid[: grid.cell_cnt_x, : grid.cell_cnt_y, : grid.cell_cnt_z]
409-
# )
410-
# return float(
411-
# np.max(
412-
# np.fromiter(
413-
# (
414-
# operation.profile(*num_grid)
415-
# for operation in self.all_operations
416-
# if isinstance(operation, SimpleDensity)
417-
# ),
418-
# dtype=float,
419-
# )
420-
# )
421-
# )
422405
return self.picongpu_base_density or 1.0e25
423406

424407
def picongpu_run(self) -> None:
@@ -456,6 +439,14 @@ def organise_init_operations(operations):
456439
return [run_construction(op) for op in cleaned]
457440

458441

459-
def mid_window(iterable):
460-
mi, ma = reduce(lambda lhs, rhs: (min(lhs[0], rhs), max(lhs[1], rhs)), iterable, (1000, 0))
461-
return (ma - mi) // 2 + mi
442+
def _mid_window(iterable):
443+
"""Compute the integer in the middle between min(iterable), max(iterable), return 1 if empty."""
444+
iterable = iter(iterable)
445+
446+
try:
447+
start = next(iterable)
448+
except StopIteration:
449+
return 1
450+
451+
mi, ma = reduce(lambda lhs, rhs: (min(lhs[0], rhs), max(lhs[1], rhs)), iterable, (start, start))
452+
return int((ma - mi) // 2 + mi)

lib/python/picongpu/picmi/species.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import re
1010
from typing import Any
1111

12-
from pydantic import BaseModel, PrivateAttr, computed_field, model_validator
12+
from pydantic import BaseModel, PrivateAttr, computed_field, model_validator, field_validator
1313

1414
from picongpu.picmi.distribution import AnyDistribution
1515
from picongpu.picmi.species_requirements import resolving_add, evaluate_requirements, run_construction
@@ -54,7 +54,7 @@ class PusherMethod(Enum):
5454

5555

5656
class Species(BaseModel):
57-
name: str | None = None
57+
name: str
5858
particle_type: str | None = None
5959
initial_distribution: AnyDistribution | None = None
6060
picongpu_fixed_charge: bool = False
@@ -71,21 +71,22 @@ class Species(BaseModel):
7171
# For now, we add them to all species. Refinements might be necessary in the future.
7272
_requirements: list[Any] = PrivateAttr(default_factory=lambda: [Position(), Weighting(), Momentum()])
7373

74+
@field_validator("name", mode="before")
75+
@classmethod
76+
def _validate_name(cls, value, values):
77+
if value is None:
78+
if values["particle_type"] is None:
79+
raise ValueError(
80+
"Can't come up with a proper name for your species because neither name nor particle type are given."
81+
)
82+
value = values["particle_type"]
83+
return value
84+
7485
class Config:
7586
arbitrary_types_allowed = True
7687

7788
@model_validator(mode="after")
7889
def check(self):
79-
if self.name is None and self.particle_type is None:
80-
raise ValueError(
81-
"Can't come up with a proper name for your species because neither name nor particle type are given."
82-
)
83-
if self.name is None:
84-
self.name = self.particle_type
85-
try:
86-
is_element = self.particle_type is not None and Element.is_element(self.particle_type)
87-
except ValueError:
88-
is_element = False
8990
if self.particle_type is None:
9091
assert self.charge_state is None, (
9192
f"Species {self.name} specified initial charge state via charge_state without also specifying particle "
@@ -94,7 +95,8 @@ def check(self):
9495
assert self.picongpu_fixed_charge is False, (
9596
f"Species {self.name} specified fixed charge without also specifying particle_type"
9697
)
97-
elif is_element:
98+
# Returns None if it is not an element, so is False-y in those cases, and True-y otherwise:
99+
elif self.picongpu_element:
98100
if self.charge_state is not None:
99101
assert Element(self.particle_type).get_atomic_number() >= self.charge_state, (
100102
f"Species {self.name} intial charge state is unphysical"

lib/python/picongpu/picmi/species_requirements.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ def __init__(self, /, species):
261261
def constructor(self):
262262
species = self.metadata.kwargs["species"].get_as_pypicongpu()
263263
particle_mass_si = species.get_constant_by_type(Mass).mass_si
264-
rms_velocity_si_squared = np.linalg.norm(self.metadata.kwargs["rms_velocity"]) ** 2 / 3
265-
temperature_kev = particle_mass_si * rms_velocity_si_squared * electron_volt**-1 * 10**-3
264+
rms_velocity_si_squared = np.linalg.norm(self.metadata.kwargs["rms_velocity"]) ** 2
265+
temperature_kev = particle_mass_si * rms_velocity_si_squared / 3 * electron_volt**-1 * 10**-3
266266
temperature = Temperature(temperature_kev=temperature_kev) if temperature_kev > 0 else None
267267
return SimpleMomentum(species=species, drift=self.metadata.kwargs["drift"], temperature=temperature)
268268

test/python/picongpu/quick/picmi/species.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,29 @@
2020
from picongpu.pypicongpu.species.constant.mass import Mass
2121

2222

23-
def subset_of(subset, superset):
24-
superset = list(superset)
25-
return all(any(e1 == e2 for e2 in superset) for e1 in subset)
26-
27-
28-
def count_all_one(subset, superset):
29-
superset = list(superset)
30-
return all(superset.count(e) == 1 for e in subset)
23+
def unique_in(elements, collection):
24+
collection = list(collection)
25+
return (collection.count(e) == 1 for e in elements)
3126

3227

3328
class TestSpeciesRequirementResolution(TestCase):
3429
def test_deduplicate_attributes(self):
3530
species = Species(name="dummy")
3631
requirements = [Weighting()]
3732
species.register_requirements(2 * requirements)
38-
assert count_all_one(requirements, species.get_as_pypicongpu().attributes)
33+
assert all(unique_in(requirements, species.get_as_pypicongpu().attributes))
3934

4035
def test_deduplicate_constants(self):
4136
species = Species(name="dummy")
4237
requirements = [Mass(mass_si=1.0)]
4338
species.register_requirements(2 * requirements)
44-
assert count_all_one(requirements, species.get_as_pypicongpu().constants)
39+
assert all(unique_in(requirements, species.get_as_pypicongpu().constants))
4540

4641
def test_deduplicate_delayed_construction(self):
4742
species = Species(name="dummy", particle_type="H", charge_state=1)
4843
requirements = [SetChargeStateOperation(species)]
4944
species.register_requirements(2 * requirements)
50-
assert count_all_one(requirements, species.get_operation_requirements())
45+
assert all(unique_in(requirements, species.get_operation_requirements()))
5146

5247
def test_conflicting_constants(self):
5348
species = Species(name="dummy")

0 commit comments

Comments
 (0)