-
Notifications
You must be signed in to change notification settings - Fork 225
openpmd.py plugin for PICMI #5353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
mafshari64
wants to merge
15
commits into
ComputationalRadiationPhysics:dev
from
mafshari64:topic-openpmd
Closed
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e4273b1
adding openpmd.py and charge_density.py
mafshari64 79478af
common interface for all the current sources of the openPMD plugin
mafshari64 62d4c43
adding species to openpmd sources
mafshari64 abcc8ac
adding other openpmd picongpu sources
mafshari64 2517139
providing openpmd sources for pypicongpu
mafshari64 584e3a1
adding schema for openpmd plugin
mafshari64 4e5b3f3
updating openpmd files
mafshari64 0cba2e5
finalizing openpmd plugin
mafshari64 4f7a275
adding rangespec class to openpmd
mafshari64 b44bf96
editing pypicongpu/output/openpmd.py
mafshari64 f2da5e4
removing Default simulation_box to fix CI LWFA
mafshari64 e914825
add simulation_box to s.plugin in picmi.simulation.py
mafshari64 9f6e5a1
Fix TypeError in PhaseSpace and Auto by adding simulation_box parameter
mafshari64 8f94e58
Fix TypeError for openpmd plugin
mafshari64 b7c3c53
Fix simulation_box usage in simulation.py to resolve ruff F841 error
mafshari64 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
""" | ||
This file is part of PIConGPU. | ||
Copyright 2025-2025 PIConGPU contributors | ||
Authors: Masoud Afshari | ||
License: GPLv3+ | ||
""" | ||
|
||
from ...pypicongpu.output.openpmd import OpenPMD as PyPIConGPUOpenPMD | ||
from ...pypicongpu.output.openpmd_sources.source_base import SourceBase as PyPIConGPUSource | ||
from .timestepspec import TimeStepSpec | ||
from .rangespec import RangeSpec | ||
from .openpmd_sources.source_base import SourceBase | ||
|
||
import typeguard | ||
from typing import Optional, Dict, Union, List, Literal, Tuple | ||
|
||
|
||
@typeguard.typechecked | ||
class OpenPMD: | ||
""" | ||
openPMD diagnostic output | ||
|
||
This diagnostic writes simulation data (base fields, derived fields and/or particles) to disk using the openPMD | ||
standard, with configurable periods, data sources and backend settings. | ||
|
||
@param period specification of the time steps for data output, outputs will always be written at the end of a PIC time step. | ||
@param source list of data source objects to include in the dump (e.g., [ChargeDensity(filter="all")]), | ||
Setting this to None will cause an empty dump | ||
@param range contiguous range of cells to dump the base- and derived field for, specified as a RangeSpec object | ||
or a string in the format "begin:end" (1D), "begin:end,begin:end" (2D), or "begin:end,begin:end,begin:end" (3D). | ||
Example: "0:10,5:15,2:8" specifies cells 0 to 10 (x), 5 to 15 (y), 2 to 8 (z). | ||
Notes: Values are clipped to the simulation box. Begin and/or end may be omitted (":") to indicate the full extent | ||
of the dimension. Negative indices are supported (e.g., "-5:-1" for last 5 cells). The default ":,:,:," (3D), | ||
":,:" (2D), or ":" (1D) includes all cells in the simulation box. | ||
@param file relative or absolute file path prefix for openPMD output files. Relative paths are interpreted as relative to the simulation output directory, the default value None indicates the PIC code's default. | ||
@param ext file extension controlling the openPMD backend, options are "bp" (default backend ADIOS2), "h5" (HDF5), "sst" (ADIOS2/SST for streaming). | ||
@param infix filename infix for the iteration layout (e.g., "_%06T"), use "NULL" for the group-based layout, ext="sst" requires infix="NULL". | ||
@param json openPMD backend configuration as a JSON string, dictionary, or filename (filename must be prepended with "@"). | ||
@param json_restart backend-specific parameters for restarting, as a JSON string, dictionary, or filename (filenames must be prepended with "@"). | ||
@param data_preparation_strategy strategy for particle data preparation, options: "doubleBuffer" or "adios" (ADIOS2-based), "mappedMemory" or "hdf5" (HDF5-based), the default value None indicates the PIC code default | ||
@param toml path to a TOML file for openPMD configuration. Replaces the JSON or keyword configuration. | ||
@param particle_io_chunk_size size of particle data chunks used in writing (in MiB), reduces host memory footprint for certain backends, default "None" indicates the PIC code default. | ||
@param file_writing file writing mode for writing, options: "create" (new files), "append" (for checkpoint-restart workflows). | ||
""" | ||
|
||
def check(self): | ||
""" | ||
Validate the provided parameters. | ||
""" | ||
if self.particle_io_chunk_size is not None and self.particle_io_chunk_size < 1: | ||
raise ValueError("particle_io_chunk_size (in MiB) must be positive") | ||
if self.ext == "sst" and self.infix is not None and self.infix != "NULL": | ||
raise ValueError("infix must be 'NULL' when ext is 'sst'") | ||
if self.source is not None and not all(isinstance(s, SourceBase) for s in self.source): | ||
raise ValueError("source must be a list of SourceBase objects") | ||
|
||
def __init__( | ||
self, | ||
period: TimeStepSpec, | ||
source: Optional[List[SourceBase]] = None, | ||
range: Optional[Union[str, RangeSpec]] = ":,:,:", | ||
file: Optional[str] = None, | ||
ext: Optional[Literal["bp", "h5", "sst"]] = "bp", | ||
infix: Optional[str] = "NULL", | ||
json: Optional[Union[str, Dict]] = None, | ||
json_restart: Optional[Union[str, Dict]] = None, | ||
data_preparation_strategy: Optional[Literal["doubleBuffer", "adios", "mappedMemory", "hdf5"]] = None, | ||
toml: Optional[str] = None, | ||
particle_io_chunk_size: Optional[int] = None, | ||
file_writing: Optional[Literal["create", "append"]] = "create", | ||
): | ||
self.period = period | ||
self.source = source | ||
self.range = RangeSpec(range) if isinstance(range, str) else range | ||
self.file = file | ||
self.ext = ext | ||
self.infix = infix | ||
self.json = json if json is not None else {} | ||
self.json_restart = json_restart if json_restart is not None else {} | ||
self.data_preparation_strategy = data_preparation_strategy | ||
self.toml = toml | ||
self.particle_io_chunk_size = particle_io_chunk_size | ||
self.file_writing = file_writing | ||
|
||
self.check() | ||
|
||
def get_as_pypicongpu( | ||
self, | ||
pypicongpu_by_picmi_species: Dict, | ||
time_step_size: float, | ||
num_steps: int, | ||
simulation_box: Tuple[int, ...], | ||
) -> PyPIConGPUOpenPMD: | ||
self.check() | ||
pypicongpu_openpmd = PyPIConGPUOpenPMD( | ||
period=self.period.get_as_pypicongpu(time_step_size, num_steps), | ||
source=PyPIConGPUSource([s.get_as_pypicongpu() for s in self.source]) if self.source is not None else None, | ||
range=self.range.get_as_pypicongpu(simulation_box), | ||
file=self.file, | ||
ext=self.ext, | ||
infix=self.infix, | ||
json=self.json, | ||
json_restart=self.json_restart, | ||
data_preparation_strategy=self.data_preparation_strategy, | ||
toml=self.toml, | ||
particle_io_chunk_size=self.particle_io_chunk_size, | ||
file_writing=self.file_writing, | ||
) | ||
return pypicongpu_openpmd |
35 changes: 35 additions & 0 deletions
35
lib/python/picongpu/picmi/diagnostics/openpmd_sources/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from .auto import Auto | ||
from .bound_electron_density import BoundElectronDensity | ||
from .charge_density import ChargeDensity | ||
from .counter import Counter | ||
from .density import Density | ||
from .derived_attributes import DerivedAttributes | ||
from .energy import Energy | ||
from .energy_density import EnergyDensity | ||
from .energy_density_cutoff import EnergyDensityCutoff | ||
from .larmor_power import LarmorPower | ||
from .macro_counter import MacroCounter | ||
from .mid_current_density_component import MidCurrentDensityComponent | ||
from .momentum import Momentum | ||
from .momentum_density import MomentumDensity | ||
from .weighted_velocity import WeightedVelocity | ||
from .source_base import SourceBase | ||
|
||
__all__ = [ | ||
"Auto", | ||
"BoundElectronDensity", | ||
"ChargeDensity", | ||
"Counter", | ||
"Density", | ||
"DerivedAttributes", | ||
"Energy", | ||
"EnergyDensity", | ||
"EnergyDensityCutoff", | ||
"LarmorPower", | ||
"MacroCounter", | ||
"MidCurrentDensityComponent", | ||
"Momentum", | ||
"MomentumDensity", | ||
"WeightedVelocity", | ||
"SourceBase", | ||
] |
49 changes: 49 additions & 0 deletions
49
lib/python/picongpu/picmi/diagnostics/openpmd_sources/auto.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
""" | ||
This file is part of PIConGPU. | ||
Copyright 2025-2025 PIConGPU contributors | ||
Authors: Masoud Afshari | ||
License: GPLv3+ | ||
""" | ||
|
||
from .source_base import SourceBase | ||
from ....pypicongpu.output.openpmd_sources import Auto as PyPIConGPUAuto | ||
import typeguard | ||
import typing | ||
|
||
|
||
@typeguard.typechecked | ||
class Auto(SourceBase): | ||
""" | ||
Default data source for openPMD output | ||
|
||
This class provides a convenient way to dump default simulation data (e.g., all | ||
particle species and fields) using the openPMD standard, with defaults determined | ||
by the PIC code in particle-in-cell simulations. | ||
|
||
@param filter Name of a filter to select data contributing to the source. | ||
Default: None (PIC code-dependent). | ||
""" | ||
|
||
# filter = util.build_typesafe_property(typing.Optional[str]) | ||
|
||
def __init__(self, filter: typing.Optional[str] = None): | ||
self.filter = filter | ||
self.check() | ||
|
||
def check(self) -> None: | ||
""" | ||
Validate the filter parameter. | ||
|
||
@throw ValueError If the filter is not a string or None. | ||
""" | ||
if self.filter is not None and not isinstance(self.filter, str): | ||
raise ValueError(f"Filter must be a string or None, got {type(self.filter)}") | ||
|
||
def get_as_pypicongpu(self) -> PyPIConGPUAuto: | ||
""" | ||
Convert this Auto source to a PyPIConGPU Auto source. | ||
|
||
@return A PyPIConGPU Auto instance with the same filter. | ||
""" | ||
self.check() | ||
return PyPIConGPUAuto(filter=self.filter) |
65 changes: 65 additions & 0 deletions
65
lib/python/picongpu/picmi/diagnostics/openpmd_sources/bound_electron_density.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
""" | ||
This file is part of PIConGPU. | ||
Copyright 2025-2025 PIConGPU contributors | ||
Authors: Masoud Afshari | ||
License: GPLv3+ | ||
""" | ||
|
||
from .source_base import SourceBase | ||
from ....pypicongpu.output.openpmd_sources import BoundElectronDensity as PyPIConGPUBoundElectronDensity | ||
from ...species import Species as PICMISpecies | ||
import typeguard | ||
import typing | ||
|
||
|
||
@typeguard.typechecked | ||
class BoundElectronDensity(SourceBase): | ||
""" | ||
Bound electron density data source for openPMD output | ||
|
||
This source calculates the density of bound electrons from a specified particle species, | ||
optionally filtered by a selection criterion, for particle-in-cell simulations. | ||
|
||
@param species Particle species contributing to the bound electron density (e.g., ions). | ||
@param filter Name of a filter to select particles contributing to the source. | ||
Default: "all" (includes all particles of the specified species). | ||
""" | ||
|
||
def __init__(self, species: PICMISpecies, filter: str = "all"): | ||
self.species = species | ||
self.filter = filter | ||
self.check() | ||
|
||
def check(self) -> None: | ||
""" | ||
Validate the parameters. | ||
|
||
@throw ValueError If filter is not a string or species is not a PICMISpecies. | ||
""" | ||
if not isinstance(self.filter, str): | ||
raise ValueError(f"Filter must be a string, got {type(self.filter)}") | ||
if not isinstance(self.species, PICMISpecies): | ||
raise ValueError(f"Species must be a PICMISpecies, got {type(self.species)}") | ||
|
||
def get_as_pypicongpu( | ||
self, | ||
dict_species_picmi_to_pypicongpu: dict[PICMISpecies, typing.Any], | ||
) -> PyPIConGPUBoundElectronDensity: | ||
""" | ||
Convert this BoundElectronDensity source to a PyPIConGPU BoundElectronDensity source. | ||
|
||
@param dict_species_picmi_to_pypicongpu Mapping of PICMI species to PyPIConGPU species. | ||
@return A PyPIConGPU BoundElectronDensity instance with the same filter and species. | ||
@throw ValueError If the species is not known to the simulation or not mapped to a PyPIConGPUSpecies. | ||
""" | ||
self.check() | ||
|
||
if self.species not in dict_species_picmi_to_pypicongpu.keys(): | ||
raise ValueError(f"Species {self.species} is not known to Simulation") | ||
|
||
pypicongpu_species = dict_species_picmi_to_pypicongpu.get(self.species) | ||
|
||
if pypicongpu_species is None: | ||
raise ValueError(f"Species {self.species} is not mapped to a PyPIConGPUSpecies.") | ||
|
||
return PyPIConGPUBoundElectronDensity(filter=self.filter, species=pypicongpu_species) |
65 changes: 65 additions & 0 deletions
65
lib/python/picongpu/picmi/diagnostics/openpmd_sources/charge_density.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
""" | ||
This file is part of PIConGPU. | ||
Copyright 2025-2025 PIConGPU contributors | ||
Authors: Masoud Afshari | ||
License: GPLv3+ | ||
""" | ||
|
||
from .source_base import SourceBase | ||
from ....pypicongpu.output.openpmd_sources import ChargeDensity as PyPIConGPUChargeDensity | ||
from ...species import Species as PICMISpecies | ||
import typeguard | ||
import typing | ||
|
||
|
||
@typeguard.typechecked | ||
class ChargeDensity(SourceBase): | ||
""" | ||
Charge density data source for openPMD output | ||
|
||
This source calculates the charge density from a specified particle species, optionally | ||
filtered by a selection criterion, for particle-in-cell simulations. | ||
|
||
@param species Particle species contributing to the charge density (e.g., electrons, protons). | ||
@param filter Name of a filter to select particles contributing to the source. | ||
Default: "all" (includes all particles of the specified species). | ||
""" | ||
|
||
def __init__(self, species: PICMISpecies, filter: str = "all"): | ||
self.species = species | ||
self.filter = filter | ||
self.check() | ||
|
||
def check(self) -> None: | ||
""" | ||
Validate the parameters. | ||
|
||
@throw ValueError If filter is not a string or species is not a PICMISpecies. | ||
""" | ||
if not isinstance(self.filter, str): | ||
raise ValueError(f"Filter must be a string, got {type(self.filter)}") | ||
if not isinstance(self.species, PICMISpecies): | ||
raise ValueError(f"Species must be a PICMISpecies, got {type(self.species)}") | ||
|
||
def get_as_pypicongpu( | ||
self, | ||
dict_species_picmi_to_pypicongpu: dict[PICMISpecies, typing.Any], | ||
) -> PyPIConGPUChargeDensity: | ||
""" | ||
Convert this ChargeDensity source to a PyPIConGPU ChargeDensity source. | ||
|
||
@param dict_species_picmi_to_pypicongpu Mapping of PICMI species to PyPIConGPU species. | ||
@return A PyPIConGPU ChargeDensity instance with the same filter and species. | ||
@throw ValueError If the species is not known to the simulation or not mapped to a PyPIConGPUSpecies. | ||
""" | ||
self.check() | ||
|
||
if self.species not in dict_species_picmi_to_pypicongpu.keys(): | ||
raise ValueError(f"Species {self.species} is not known to Simulation") | ||
|
||
pypicongpu_species = dict_species_picmi_to_pypicongpu.get(self.species) | ||
|
||
if pypicongpu_species is None: | ||
raise ValueError(f"Species {self.species} is not mapped to a PyPIConGPUSpecies.") | ||
|
||
return PyPIConGPUChargeDensity(filter=self.filter, species=pypicongpu_species) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that this should be here. We don't want to expose this to the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so delete it?