From 1a4a634ffe1c4879272ce82aa1fddfc02cb70f12 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Thu, 30 Jan 2025 15:04:18 +0100 Subject: [PATCH 01/10] add phase_space.json --- .../pypicongpu/schema/output/phase_space.json | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 share/picongpu/pypicongpu/schema/output/phase_space.json diff --git a/share/picongpu/pypicongpu/schema/output/phase_space.json b/share/picongpu/pypicongpu/schema/output/phase_space.json new file mode 100644 index 0000000000..6f77941f48 --- /dev/null +++ b/share/picongpu/pypicongpu/schema/output/phase_space.json @@ -0,0 +1,40 @@ +{ + "$id": "https://registry.hzdr.de/crp/picongpu/schema/output/phase_space.json", + "type": "object", + "description": "Phase space output configuration for PIConGPU", + "unevaluatedProperties": false, + "required": ["phase_space_species_name", "phase_space_period", "phase_space_space", "phase_space_momentum"], + "properties": { + "phase_space_species_name": { + "type": "string", + "description": "Species name for phase space output (e.g., electron, ion)." + }, + "phase_space_period": { + "type": "integer", + "minimum": 1, + "description": "Time period for phase space output." + }, + "phase_space_space": { + "type": "string", + "enum": ["x", "y", "z"], + "description": "Spatial coordinate for phase space analysis." + }, + "phase_space_momentum": { + "type": "string", + "enum": ["px", "py", "pz"], + "description": "Momentum component for phase space analysis." + }, + "phase_space_min": { + "type": "number", + "description": "Minimum value for phase space filtering." + }, + "phase_space_max": { + "type": "number", + "description": "Maximum value for phase space filtering." + }, + "phase_space_filter": { + "type": "string", + "description": "Filter type for phase space output." + } + } +} From f142364ddd1012ab03150fe5c097e9dc663cfee6 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Thu, 30 Jan 2025 15:55:53 +0100 Subject: [PATCH 02/10] Fix formatting issues and add pypicongpu phase_space.py --- .../picongpu/pypicongpu/output/phase_space.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 lib/python/picongpu/pypicongpu/output/phase_space.py diff --git a/lib/python/picongpu/pypicongpu/output/phase_space.py b/lib/python/picongpu/pypicongpu/output/phase_space.py new file mode 100644 index 0000000000..e8bdbb01ca --- /dev/null +++ b/lib/python/picongpu/pypicongpu/output/phase_space.py @@ -0,0 +1,54 @@ +""" +This file is part of PIConGPU. +Copyright 2021-2024 PIConGPU contributors +Authors: Masoud Afshari +License: GPLv3+ +""" + +from pypicongpu import util +from pypicongpu.rendering import RenderedObject + + +import typeguard +from typing import Dict + + +@typeguard.typechecked +class PhaseSpace(RenderedObject): + phase_space_species_name = util.build_typesafe_property(str) + phase_space_period = util.build_typesafe_property(int) + phase_space_space = util.build_typesafe_property(str) + phase_space_momentum = util.build_typesafe_property(str) + phase_space_min = util.build_typesafe_property(float) + phase_space_max = util.build_typesafe_property(float) + phase_space_filter = util.build_typesafe_property(str) + + def __init__( + self, + species_name: str, + period: int, + space: str, + momentum: str, + min_value: float, + max_value: float, + filter_type: str, + ): + self.phase_space_species_name = species_name + self.phase_space_period = period + self.phase_space_space = space + self.phase_space_momentum = momentum + self.phase_space_min = min_value + self.phase_space_max = max_value + self.phase_space_filter = filter_type + + def _get_serialized(self) -> Dict: + """Return the serialized representation of the object.""" + return { + "phase_space_species_name": self.phase_space_species_name, + "phase_space_period": self.phase_space_period, + "phase_space_space": self.phase_space_space, + "phase_space_momentum": self.phase_space_momentum, + "phase_space_min": self.phase_space_min, + "phase_space_max": self.phase_space_max, + "phase_space_filter": self.phase_space_filter, + } From a4437a1c51572d7290d27632f64f865a81e50ace Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 31 Jan 2025 17:45:03 +0100 Subject: [PATCH 03/10] adding PIConGPU PICMI interface for phase_space after ruff CRLF improvement --- lib/python/picongpu/picmi/phase_space.py | 56 +++++++++++++++++++ .../picongpu/pypicongpu/output/phase_space.py | 22 +------- 2 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 lib/python/picongpu/picmi/phase_space.py diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py new file mode 100644 index 0000000000..51d2955410 --- /dev/null +++ b/lib/python/picongpu/picmi/phase_space.py @@ -0,0 +1,56 @@ +""" +This file is part of PIConGPU. +Copyright 2021-2024 PIConGPU contributors +Authors: Masoud Afshari +License: GPLv3+ +""" + +from ..pypicongpu import util, phase_space +import picmistandard +import typeguard + + +@typeguard.typechecked +class PhaseSpace(picmistandard.PICMI_PhaseSpace): + """PICMI object for Phase Space diagnostics""" + + def __init__( + self, + species_name: str, + period: int, + space: str, + momentum: str, + min_value: float, + max_value: float, + filter_type: str, + **kw, + ): + if period <= 0: + raise ValueError("Period must be > 0") + if min_value >= max_value: + raise ValueError("min_value must be less than max_value") + + self.species_name = species_name + self.period = period + self.space = space + self.momentum = momentum + self.min_value = min_value + self.max_value = max_value + self.filter_type = filter_type + + super().__init__(**kw) + + def get_as_pypicongpu(self) -> phase_space.PhaseSpace: + util.unsupported("extra attributes", self.__dict__.keys()) + + pypicongpu_phase_space = phase_space.PhaseSpace( + species_name=self.species_name, + period=self.period, + space=self.space, + momentum=self.momentum, + min_value=self.min_value, + max_value=self.max_value, + filter_type=self.filter_type, + ) + + return pypicongpu_phase_space diff --git a/lib/python/picongpu/pypicongpu/output/phase_space.py b/lib/python/picongpu/pypicongpu/output/phase_space.py index e8bdbb01ca..29131ecdfd 100644 --- a/lib/python/picongpu/pypicongpu/output/phase_space.py +++ b/lib/python/picongpu/pypicongpu/output/phase_space.py @@ -10,7 +10,7 @@ import typeguard -from typing import Dict +import typing @typeguard.typechecked @@ -23,25 +23,7 @@ class PhaseSpace(RenderedObject): phase_space_max = util.build_typesafe_property(float) phase_space_filter = util.build_typesafe_property(str) - def __init__( - self, - species_name: str, - period: int, - space: str, - momentum: str, - min_value: float, - max_value: float, - filter_type: str, - ): - self.phase_space_species_name = species_name - self.phase_space_period = period - self.phase_space_space = space - self.phase_space_momentum = momentum - self.phase_space_min = min_value - self.phase_space_max = max_value - self.phase_space_filter = filter_type - - def _get_serialized(self) -> Dict: + def _get_serialized(self) -> typing.Dict: """Return the serialized representation of the object.""" return { "phase_space_species_name": self.phase_space_species_name, From 2c8d69af7eb186a29e5e3aed981eba861d754fc8 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 14 Feb 2025 13:39:05 +0100 Subject: [PATCH 04/10] improving phase_space parameter names --- lib/python/picongpu/picmi/phase_space.py | 31 +++++++++---------- .../picongpu/pypicongpu/output/phase_space.py | 28 ++++++++--------- .../pypicongpu/schema/output/phase_space.json | 29 ++++++++--------- 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py index 51d2955410..75b2f5e9e2 100644 --- a/lib/python/picongpu/picmi/phase_space.py +++ b/lib/python/picongpu/picmi/phase_space.py @@ -16,27 +16,25 @@ class PhaseSpace(picmistandard.PICMI_PhaseSpace): def __init__( self, - species_name: str, + species: str, period: int, - space: str, + spatial_coordinate: str, momentum: str, - min_value: float, - max_value: float, - filter_type: str, + min_momentum: float, + max_momentum: float, **kw, ): if period <= 0: raise ValueError("Period must be > 0") - if min_value >= max_value: - raise ValueError("min_value must be less than max_value") + if min_momentum >= max_momentum: + raise ValueError("min_momentum must be less than max_momentum") - self.species_name = species_name + self.species = species self.period = period - self.space = space + self.spatial_coordinate = spatial_coordinate self.momentum = momentum - self.min_value = min_value - self.max_value = max_value - self.filter_type = filter_type + self.min_momentum = min_momentum + self.max_momentum = max_momentum super().__init__(**kw) @@ -44,13 +42,12 @@ def get_as_pypicongpu(self) -> phase_space.PhaseSpace: util.unsupported("extra attributes", self.__dict__.keys()) pypicongpu_phase_space = phase_space.PhaseSpace( - species_name=self.species_name, + species=self.species, period=self.period, - space=self.space, + spatial_coordinate=self.spatial_coordinate, momentum=self.momentum, - min_value=self.min_value, - max_value=self.max_value, - filter_type=self.filter_type, + min_momentum=self.min_momentum, + max_momentum=self.max_momentum, ) return pypicongpu_phase_space diff --git a/lib/python/picongpu/pypicongpu/output/phase_space.py b/lib/python/picongpu/pypicongpu/output/phase_space.py index 29131ecdfd..4556f0ae1b 100644 --- a/lib/python/picongpu/pypicongpu/output/phase_space.py +++ b/lib/python/picongpu/pypicongpu/output/phase_space.py @@ -7,30 +7,30 @@ from pypicongpu import util from pypicongpu.rendering import RenderedObject +from pypicongpu.species import Species import typeguard import typing +from typing import Literal @typeguard.typechecked class PhaseSpace(RenderedObject): - phase_space_species_name = util.build_typesafe_property(str) - phase_space_period = util.build_typesafe_property(int) - phase_space_space = util.build_typesafe_property(str) - phase_space_momentum = util.build_typesafe_property(str) - phase_space_min = util.build_typesafe_property(float) - phase_space_max = util.build_typesafe_property(float) - phase_space_filter = util.build_typesafe_property(str) + species = util.build_typesafe_property(Species) + period = util.build_typesafe_property(int) + spatial_coordinate = util.build_typesafe_property(Literal["x", "y", "z"]) + momentum = util.build_typesafe_property(Literal["px", "py", "pz"]) + min_momentum = util.build_typesafe_property(float) + max_momentum = util.build_typesafe_property(float) def _get_serialized(self) -> typing.Dict: """Return the serialized representation of the object.""" return { - "phase_space_species_name": self.phase_space_species_name, - "phase_space_period": self.phase_space_period, - "phase_space_space": self.phase_space_space, - "phase_space_momentum": self.phase_space_momentum, - "phase_space_min": self.phase_space_min, - "phase_space_max": self.phase_space_max, - "phase_space_filter": self.phase_space_filter, + "species": self.species.get_generic_profile_rendering_context(), + "period": self.period, + "spatial_coordinate": self.spatial_coordinate, + "momentum": self.momentum, + "min_momentum": self.min_momentum, + "max_momentum": self.max_momentum, } diff --git a/share/picongpu/pypicongpu/schema/output/phase_space.json b/share/picongpu/pypicongpu/schema/output/phase_space.json index 6f77941f48..3ec7063523 100644 --- a/share/picongpu/pypicongpu/schema/output/phase_space.json +++ b/share/picongpu/pypicongpu/schema/output/phase_space.json @@ -3,38 +3,35 @@ "type": "object", "description": "Phase space output configuration for PIConGPU", "unevaluatedProperties": false, - "required": ["phase_space_species_name", "phase_space_period", "phase_space_space", "phase_space_momentum"], + "required": ["species", "period", "spatial_coordinate", "momentum","min_momentum","max_momentum"], "properties": { - "phase_space_species_name": { - "type": "string", - "description": "Species name for phase space output (e.g., electron, ion)." - }, - "phase_space_period": { + "species": + { + "$ref": "https://registry.hzdr.de/crp/picongpu/schema/picongpu.pypicongpu.species.Species" + } + , + "period": { "type": "integer", "minimum": 1, "description": "Time period for phase space output." }, - "phase_space_space": { + "spatial_coordinate": { "type": "string", "enum": ["x", "y", "z"], "description": "Spatial coordinate for phase space analysis." }, - "phase_space_momentum": { + "momentum": { "type": "string", "enum": ["px", "py", "pz"], "description": "Momentum component for phase space analysis." }, - "phase_space_min": { + "min_momentum": { "type": "number", - "description": "Minimum value for phase space filtering." + "description": "Minimum momentum value for phase space filtering." }, - "phase_space_max": { + "max_momentum": { "type": "number", - "description": "Maximum value for phase space filtering." - }, - "phase_space_filter": { - "type": "string", - "description": "Filter type for phase space output." + "description": "Maximum momentum value for phase space filtering." } } } From e978d45c3a82494170f12f7b6ebb053783c694db Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 14 Feb 2025 13:45:58 +0100 Subject: [PATCH 05/10] correct path to phase_space interface --- lib/python/picongpu/picmi/phase_space.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py index 75b2f5e9e2..acc3881fe0 100644 --- a/lib/python/picongpu/picmi/phase_space.py +++ b/lib/python/picongpu/picmi/phase_space.py @@ -5,7 +5,9 @@ License: GPLv3+ """ -from ..pypicongpu import util, phase_space +from ..pypicongpu import util +from ..pypicongpu.output import phase_space + import picmistandard import typeguard From 2f76a5f6a4e16377f405da249446abc07fb7965c Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 14 Feb 2025 14:55:31 +0100 Subject: [PATCH 06/10] adding phase_space block to picmi python script for lwfa --- .../examples/laser_wakefield/main.py | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py index 53c9c2719d..3a8c91583a 100644 --- a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py +++ b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py @@ -1,6 +1,6 @@ """ This file is part of PIConGPU. -Copyright 2024-2024 PIConGPU contributors +Copyright 2024 PIConGPU contributors Authors: Masoud Afshari, Brian Edward Marre License: GPLv3+ """ @@ -19,10 +19,10 @@ ENABLE_IONS = True ENABLE_IONIZATION = True ADD_CUSTOM_INPUT = True -OUTPUT_DIRECTORY_PATH = "LWFA" +OUTPUT_DIRECTORY_PATH = "lwfa_phase_space" numberCells = np.array([192, 2048, 192]) -cellSize = np.array([0.1772e-6, 0.4430e-7, 0.1772e-6]) # unit: meter) +cellSize = np.array([0.1772e-6, 0.4430e-7, 0.1772e-6]) # unit: meter # Define the simulation grid based on grid.param grid = picmi.Cartesian3DGrid( @@ -45,10 +45,7 @@ vacuum_cells_front=50, ) -solver = picmi.ElectromagneticSolver( - grid=grid, - method="Yee", -) +solver = picmi.ElectromagneticSolver(grid=grid, method="Yee") laser = picmi.GaussianLaser( wavelength=0.8e-6, @@ -73,8 +70,8 @@ if not ENABLE_IONIZATION: interaction = None - electron_placed = picmi.Species(particle_type="electron", name="electron", initial_distribution=gaussianProfile) - species_list.append((electron_placed, random_layout)) + primary_electrons = picmi.Species(particle_type="electron", name="electron", initial_distribution=gaussianProfile) + species_list.append((primary_electrons, random_layout)) if ENABLE_IONS: hydrogen_fully_ionized = picmi.Species( @@ -90,20 +87,22 @@ ) species_list.append((hydrogen_with_ionization, random_layout)) - electron_not_placed = picmi.Species(particle_type="electron", name="electron", initial_distribution=None) - species_list.append((electron_not_placed, None)) + secondary_electrons_from_ionization = picmi.Species( + particle_type="electron", name="electron", initial_distribution=None + ) + species_list.append((secondary_electrons_from_ionization, None)) adk_ionization_model = picmi.ADK( ADK_variant=picmi.ADKVariant.CircularPolarization, ion_species=hydrogen_with_ionization, - ionization_electron_species=electron_not_placed, + ionization_electron_species=secondary_electrons_from_ionization, ionization_current=None, ) bsi_effectiveZ_ionization_model = picmi.BSI( BSI_extensions=[picmi.BSIExtension.EffectiveZ], ion_species=hydrogen_with_ionization, - ionization_electron_species=electron_not_placed, + ionization_electron_species=secondary_electrons_from_ionization, ionization_current=None, ) @@ -111,13 +110,24 @@ ground_state_ionization_model_list=[adk_ionization_model, bsi_effectiveZ_ionization_model] ) + phase_space = picmi.PhaseSpace( + phase_space_species_name="electron", + phase_space_period=100, + phase_space_space="y", + phase_space_momentum="py", + phase_space_min=-1.0, + phase_space_max=1.0, + ) + sim = picmi.Simulation( solver=solver, max_steps=4000, time_step_size=1.39e-16, picongpu_moving_window_move_point=0.9, picongpu_interaction=interaction, + picongpu_template_dir="./customTemplates", ) + for species, layout in species_list: sim.add_species(species, layout=layout) @@ -129,29 +139,28 @@ # for generating setup with custom input see standard implementation, # see https://picongpu.readthedocs.io/en/latest/usage/picmi/custom_template.html if ADD_CUSTOM_INPUT: - min_weight_input = pypicongpu.customuserinput.CustomUserInput() + min_weight_input = pypicongpu.customuserinput.CustomUserInput() # particle.param.mustache min_weight_input.addToCustomInput({"minimum_weight": 10.0}, "minimum_weight") sim.picongpu_add_custom_user_input(min_weight_input) output_configuration = pypicongpu.customuserinput.CustomUserInput() output_configuration.addToCustomInput( { - "png_plugin_data_list": "['Ex', 'Ey', 'Ez', 'Bx', 'By', 'Bz', 'Jx', 'Jy', 'Jz']", "png_plugin_SCALE_IMAGE": 1.0, - "png_plugin_SCALE_TO_CELLSIZE": True, - "png_plugin_WHITE_BOX_PER_GPU": False, + "png_plugin_SCALE_TO_CELLSIZE": "true", + "png_plugin_WHITE_BOX_PER_GPU": "false", "png_plugin_EM_FIELD_SCALE_CHANNEL1": 7, "png_plugin_EM_FIELD_SCALE_CHANNEL2": -1, "png_plugin_EM_FIELD_SCALE_CHANNEL3": -1, - "png_plugin_CUSTOM_NORMALIZATION_SI": "5.0e12 / constants.c, 5.0e12, 15.0", + "png_plugin_CUSTOM_NORMALIZATION_SI": "{5.0e12 / SI::SPEED_OF_LIGHT_SI, 5.0e12, 15.0}", "png_plugin_PRE_PARTICLE_DENS_OPACITY": 0.25, "png_plugin_PRE_CHANNEL1_OPACITY": 1.0, "png_plugin_PRE_CHANNEL2_OPACITY": 1.0, "png_plugin_PRE_CHANNEL3_OPACITY": 1.0, "png_plugin_preParticleDensCol": "colorScales::grayInv", - "png_plugin_preChannel1Col": "colorScales::green", - "png_plugin_preChannel2Col": "colorScales::none", - "png_plugin_preChannel3Col": "colorScales::none", + "png_plugin_preChannel1_colorScale": "colorScales::green", + "png_plugin_preChannel2_colorScale": "colorScales::none", + "png_plugin_preChannel3_colorScale": "colorScales::none", "png_plugin_preChannel1": "field_E.x() * field_E.x();", "png_plugin_preChannel2": "field_E.y()", "png_plugin_preChannel3": "-1.0_X * field_E.y()", @@ -170,25 +179,12 @@ "energy_histogram_period": 100, "energy_histogram_bin_count": 1024, "energy_histogram_min_energy": 0.0, - "energy_histogram_maxEnergy": 1000.0, + "energy_histogram_max_energy": 1000.0, "energy_histogram_filter": "all", }, "energy histogram plugin configuration", ) - output_configuration.addToCustomInput( - { - "phase_space_species_name": "electron", - "phase_space_period": 100, - "phase_space_space": "y", - "phase_space_momentum": "py", - "phase_space_min": -1.0, - "phase_space_max": 1.0, - "phase_space_filter": "all", - }, - "phase space plugin configuration", - ) - output_configuration.addToCustomInput( {"openPMD_period": 100, "openPMD_file": "simData", "openPMD_extension": "bp"}, "openPMD plugin configuration" ) From 6b6bee260c550fece9b7574d4bd3e6e9c23d3af3 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 14 Feb 2025 15:00:49 +0100 Subject: [PATCH 07/10] correcting phase_space block param names --- share/picongpu/pypicongpu/examples/laser_wakefield/main.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py index 3a8c91583a..26ebe9d48f 100644 --- a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py +++ b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py @@ -111,12 +111,7 @@ ) phase_space = picmi.PhaseSpace( - phase_space_species_name="electron", - phase_space_period=100, - phase_space_space="y", - phase_space_momentum="py", - phase_space_min=-1.0, - phase_space_max=1.0, + species="electron", period=100, spatial_coordinate="y", momentum="py", min_momentum=-1.0, max_momentum=1.0 ) sim = picmi.Simulation( From de3c459189af365a1d69b96c5f2d62f8f593e053 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Fri, 14 Feb 2025 17:02:53 +0100 Subject: [PATCH 08/10] pass species object instead of species name --- lib/python/picongpu/picmi/phase_space.py | 11 +++++--- lib/python/picongpu/picmi/simulation.py | 9 +++++-- .../picongpu/pypicongpu/output/phase_space.py | 6 ++--- .../picongpu/pypicongpu/output/plugin.py | 15 +++++++++++ lib/python/picongpu/pypicongpu/simulation.py | 3 +++ .../examples/laser_wakefield/main.py | 25 +++++++++++-------- 6 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 lib/python/picongpu/pypicongpu/output/plugin.py diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py index acc3881fe0..9f9a072754 100644 --- a/lib/python/picongpu/picmi/phase_space.py +++ b/lib/python/picongpu/picmi/phase_space.py @@ -7,6 +7,9 @@ from ..pypicongpu import util from ..pypicongpu.output import phase_space +from ..pypicongpu.species.species import Species as PyPIConGPUSpecies + +from .species import Species as PICMISpecies import picmistandard import typeguard @@ -18,7 +21,7 @@ class PhaseSpace(picmistandard.PICMI_PhaseSpace): def __init__( self, - species: str, + species: PICMISpecies, period: int, spatial_coordinate: str, momentum: str, @@ -40,11 +43,13 @@ def __init__( super().__init__(**kw) - def get_as_pypicongpu(self) -> phase_space.PhaseSpace: + def get_as_pypicongpu( + self, dict_species_picmi_to_pypicongpu: dict[PICMISpecies, PyPIConGPUSpecies] + ) -> phase_space.PhaseSpace: util.unsupported("extra attributes", self.__dict__.keys()) pypicongpu_phase_space = phase_space.PhaseSpace( - species=self.species, + species=dict_species_picmi_to_pypicongpu[self.species], period=self.period, spatial_coordinate=self.spatial_coordinate, momentum=self.momentum, diff --git a/lib/python/picongpu/picmi/simulation.py b/lib/python/picongpu/picmi/simulation.py index 7f9a780e3a..35852ad956 100644 --- a/lib/python/picongpu/picmi/simulation.py +++ b/lib/python/picongpu/picmi/simulation.py @@ -373,7 +373,7 @@ def __get_init_manager(self) -> pypicongpu.species.InitManager: initmgr.all_operations += self.__get_operations_not_placed(pypicongpu_by_picmi_species) initmgr.all_operations += self.__get_operations_from_individual_species(pypicongpu_by_picmi_species) - return initmgr + return initmgr, pypicongpu_by_picmi_species def write_input_file( self, file_name: str, pypicongpu_simulation: typing.Optional[pypicongpu.simulation.Simulation] = None @@ -455,7 +455,12 @@ def get_as_pypicongpu(self) -> pypicongpu.simulation.Simulation: # explictly disable laser (as required by pypicongpu) s.laser = None - s.init_manager = self.__get_init_manager() + s.init_manager, pypicongpu_by_picmi_species = self.__get_init_manager() + + pypicongpu_particle_plugins = [] + for entry in self.diagnostics: + pypicongpu_particle_plugins.append(entry.get_as_pypicongpu(pypicongpu_by_picmi_species)) + s.plugins = pypicongpu_particle_plugins # set typical ppc if not set explicitly by user if self.picongpu_typical_ppc is None: diff --git a/lib/python/picongpu/pypicongpu/output/phase_space.py b/lib/python/picongpu/pypicongpu/output/phase_space.py index 4556f0ae1b..c234089e2f 100644 --- a/lib/python/picongpu/pypicongpu/output/phase_space.py +++ b/lib/python/picongpu/pypicongpu/output/phase_space.py @@ -6,9 +6,9 @@ """ from pypicongpu import util -from pypicongpu.rendering import RenderedObject from pypicongpu.species import Species +from .plugin import Plugin import typeguard import typing @@ -16,7 +16,7 @@ @typeguard.typechecked -class PhaseSpace(RenderedObject): +class PhaseSpace(Plugin): species = util.build_typesafe_property(Species) period = util.build_typesafe_property(int) spatial_coordinate = util.build_typesafe_property(Literal["x", "y", "z"]) @@ -27,7 +27,7 @@ class PhaseSpace(RenderedObject): def _get_serialized(self) -> typing.Dict: """Return the serialized representation of the object.""" return { - "species": self.species.get_generic_profile_rendering_context(), + "species": self.species.get_cxx_typename(), "period": self.period, "spatial_coordinate": self.spatial_coordinate, "momentum": self.momentum, diff --git a/lib/python/picongpu/pypicongpu/output/plugin.py b/lib/python/picongpu/pypicongpu/output/plugin.py new file mode 100644 index 0000000000..7c3f1aff02 --- /dev/null +++ b/lib/python/picongpu/pypicongpu/output/plugin.py @@ -0,0 +1,15 @@ +""" +This file is part of PIConGPU. +Copyright 2021-2024 PIConGPU contributors +Authors: Brian Edward Marre, Masoud Afshari +License: GPLv3+ +""" + +from pypicongpu.rendering import RenderedObject + +import typeguard + + +@typeguard.typechecked +class Plugin(RenderedObject): + """general interface for all plugins""" diff --git a/lib/python/picongpu/pypicongpu/simulation.py b/lib/python/picongpu/pypicongpu/simulation.py index 9ecbd5779c..6ba7ccba4e 100644 --- a/lib/python/picongpu/pypicongpu/simulation.py +++ b/lib/python/picongpu/pypicongpu/simulation.py @@ -14,6 +14,7 @@ from . import output from .rendering import RenderedObject from .customuserinput import InterfaceCustomUserInput +from .output.plugin import Plugin import typing import typeguard @@ -66,6 +67,8 @@ class Simulation(RenderedObject): moving_window = util.build_typesafe_property(typing.Optional[MovingWindow]) """used moving Window, set to None to disable""" + plugins = util.build_typesafe_property(typing.Optional[Plugin]) + def __get_output_context(self) -> dict: """retrieve all output objects""" auto = output.Auto() diff --git a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py index 26ebe9d48f..63ee6dab52 100644 --- a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py +++ b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py @@ -70,8 +70,8 @@ if not ENABLE_IONIZATION: interaction = None - primary_electrons = picmi.Species(particle_type="electron", name="electron", initial_distribution=gaussianProfile) - species_list.append((primary_electrons, random_layout)) + electrons = picmi.Species(particle_type="electron", name="electron", initial_distribution=gaussianProfile) + species_list.append((electrons, random_layout)) if ENABLE_IONS: hydrogen_fully_ionized = picmi.Species( @@ -87,22 +87,20 @@ ) species_list.append((hydrogen_with_ionization, random_layout)) - secondary_electrons_from_ionization = picmi.Species( - particle_type="electron", name="electron", initial_distribution=None - ) - species_list.append((secondary_electrons_from_ionization, None)) + electrons = picmi.Species(particle_type="electron", name="electron", initial_distribution=None) + species_list.append((electrons, None)) adk_ionization_model = picmi.ADK( ADK_variant=picmi.ADKVariant.CircularPolarization, ion_species=hydrogen_with_ionization, - ionization_electron_species=secondary_electrons_from_ionization, + ionization_electron_species=electrons, ionization_current=None, ) bsi_effectiveZ_ionization_model = picmi.BSI( BSI_extensions=[picmi.BSIExtension.EffectiveZ], ion_species=hydrogen_with_ionization, - ionization_electron_species=secondary_electrons_from_ionization, + ionization_electron_species=electrons, ionization_current=None, ) @@ -110,9 +108,12 @@ ground_state_ionization_model_list=[adk_ionization_model, bsi_effectiveZ_ionization_model] ) - phase_space = picmi.PhaseSpace( - species="electron", period=100, spatial_coordinate="y", momentum="py", min_momentum=-1.0, max_momentum=1.0 +diagnostics_list = [] +diagnostics_list.append( + picmi.PhaseSpace( + species=electrons, period=100, spatial_coordinate="y", momentum="py", min_momentum=-1.0, max_momentum=1.0 ) +) sim = picmi.Simulation( solver=solver, @@ -126,8 +127,12 @@ for species, layout in species_list: sim.add_species(species, layout=layout) +for entry in diagnostics_list: + sim.add_diagnostic(entry) + sim.add_laser(laser, None) + # additional non standardized custom user input # only active if custom templates are used From a8572268e9464c18e241b18bd4f57e262af087ab Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Thu, 20 Feb 2025 11:31:48 +0100 Subject: [PATCH 09/10] fix buges-picmi to picongpu conversion in picongpu-picmi-phase_space.py --- lib/python/picongpu/picmi/__init__.py | 2 + lib/python/picongpu/picmi/debug.py | 5 +++ lib/python/picongpu/picmi/phase_space.py | 41 +++++++++++++++---- lib/python/picongpu/picmi/simulation.py | 8 +++- lib/python/picongpu/pypicongpu/__init__.py | 2 + .../picongpu/pypicongpu/output/phase_space.py | 4 +- .../picongpu/pypicongpu/output/plugin.py | 5 ++- 7 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 lib/python/picongpu/picmi/debug.py diff --git a/lib/python/picongpu/picmi/__init__.py b/lib/python/picongpu/picmi/__init__.py index 3873f2d73f..9863119ea1 100644 --- a/lib/python/picongpu/picmi/__init__.py +++ b/lib/python/picongpu/picmi/__init__.py @@ -8,6 +8,7 @@ from .species import Species from .layout import PseudoRandomLayout from . import constants +from .phase_space import PhaseSpace from .distribution import FoilDistribution, UniformDistribution, GaussianDistribution from .interaction import Interaction @@ -38,6 +39,7 @@ "Keldysh", "ThomasFermi", "Interaction", + "PhaseSpace", ] diff --git a/lib/python/picongpu/picmi/debug.py b/lib/python/picongpu/picmi/debug.py new file mode 100644 index 0000000000..241b67d9f3 --- /dev/null +++ b/lib/python/picongpu/picmi/debug.py @@ -0,0 +1,5 @@ +import picmistandard +# print(dir(picmistandard)) # Check if PICMI_PhaseSpace is listed + +print(picmistandard.__file__) +# /home/afshar87/.local/lib/python3.10/site-packages/picmistandard diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py index 9f9a072754..c06c5e3f71 100644 --- a/lib/python/picongpu/picmi/phase_space.py +++ b/lib/python/picongpu/picmi/phase_space.py @@ -6,9 +6,10 @@ """ from ..pypicongpu import util -from ..pypicongpu.output import phase_space +from ..pypicongpu.output.phase_space import PhaseSpace from ..pypicongpu.species.species import Species as PyPIConGPUSpecies + from .species import Species as PICMISpecies import picmistandard @@ -21,7 +22,7 @@ class PhaseSpace(picmistandard.PICMI_PhaseSpace): def __init__( self, - species: PICMISpecies, + species: PyPIConGPUSpecies, period: int, spatial_coordinate: str, momentum: str, @@ -41,15 +42,41 @@ def __init__( self.min_momentum = min_momentum self.max_momentum = max_momentum - super().__init__(**kw) + super().__init__( + species, + period, + spatial_coordinate, + momentum, + min_momentum, + max_momentum, + **kw, + ) def get_as_pypicongpu( - self, dict_species_picmi_to_pypicongpu: dict[PICMISpecies, PyPIConGPUSpecies] - ) -> phase_space.PhaseSpace: + # to get the corresponding PyPIConGPUSpecies instance for the given PICMISpecies. + self, + dict_species_picmi_to_pypicongpu: dict[PICMISpecies, PyPIConGPUSpecies], + ) -> PhaseSpace: + print(f"dict_species_picmi_to_pypicongpu keys: {list(dict_species_picmi_to_pypicongpu.keys())}") + print(f"self.species: {self.species}") + + if self.species not in dict_species_picmi_to_pypicongpu: + raise ValueError(f"Species {self.species} is not mapped in dict_species_picmi_to_pypicongpu!") + + # checks if PICMISpecies instance exists in the dictionary. If yes, it returns the corresponding PyPIConGPUSpecies instance. + # self.species refers to the species attribute of the class PhaseSpace(picmistandard.PICMI_PhaseSpace). + 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.") + + # Print type before passing to PhaseSpace + print(f"DEBUG: Mapped species: {pypicongpu_species}, Type: {type(pypicongpu_species)}") + util.unsupported("extra attributes", self.__dict__.keys()) - pypicongpu_phase_space = phase_space.PhaseSpace( - species=dict_species_picmi_to_pypicongpu[self.species], + pypicongpu_phase_space = PhaseSpace( + species=pypicongpu_species, period=self.period, spatial_coordinate=self.spatial_coordinate, momentum=self.momentum, diff --git a/lib/python/picongpu/picmi/simulation.py b/lib/python/picongpu/picmi/simulation.py index 35852ad956..b1ee96f0c0 100644 --- a/lib/python/picongpu/picmi/simulation.py +++ b/lib/python/picongpu/picmi/simulation.py @@ -10,6 +10,8 @@ from .species import Species from .interaction.ionization import IonizationModel +from picongpu.pypicongpu.species.initmanager import InitManager + from . import constants from .grid import Cartesian3DGrid from .interaction import Interaction @@ -340,7 +342,8 @@ def __fill_in_ionization_electrons( pypicongpu_by_picmi_species, ionization_model_conversion_by_species ) - def __get_init_manager(self) -> pypicongpu.species.InitManager: + # def __get_init_manager(self) -> pypicongpu.species.InitManager: + def __get_init_manager(self) -> tuple[InitManager, typing.Dict[Species, pypicongpu.species.Species]]: """ create & fill an Initmanager @@ -361,7 +364,8 @@ def __get_init_manager(self) -> pypicongpu.species.InitManager: self.__fill_in_ionization_electrons(pypicongpu_by_picmi_species, ionization_model_conversion_by_species) # init PyPIConGPU init manager - initmgr = pypicongpu.species.InitManager() + # initmgr = pypicongpu.species.InitManager() + initmgr = InitManager() # This works because InitManager is imported for pypicongpu_species in pypicongpu_by_picmi_species.values(): initmgr.all_species.append(pypicongpu_species) diff --git a/lib/python/picongpu/pypicongpu/__init__.py b/lib/python/picongpu/pypicongpu/__init__.py index aa78f9b954..1f54cc0e7a 100644 --- a/lib/python/picongpu/pypicongpu/__init__.py +++ b/lib/python/picongpu/pypicongpu/__init__.py @@ -4,6 +4,7 @@ from .simulation import Simulation from .runner import Runner +from .output.phase_space import PhaseSpace from . import laser from . import grid @@ -25,6 +26,7 @@ "util", "grid", "customuserinput", + "PhaseSpace", ] # note: put down here b/c linter complains if imports are not at top diff --git a/lib/python/picongpu/pypicongpu/output/phase_space.py b/lib/python/picongpu/pypicongpu/output/phase_space.py index c234089e2f..6ea094c7f0 100644 --- a/lib/python/picongpu/pypicongpu/output/phase_space.py +++ b/lib/python/picongpu/pypicongpu/output/phase_space.py @@ -5,8 +5,8 @@ License: GPLv3+ """ -from pypicongpu import util -from pypicongpu.species import Species +from .. import util +from ..species import Species from .plugin import Plugin diff --git a/lib/python/picongpu/pypicongpu/output/plugin.py b/lib/python/picongpu/pypicongpu/output/plugin.py index 7c3f1aff02..269c0afe8b 100644 --- a/lib/python/picongpu/pypicongpu/output/plugin.py +++ b/lib/python/picongpu/pypicongpu/output/plugin.py @@ -5,7 +5,7 @@ License: GPLv3+ """ -from pypicongpu.rendering import RenderedObject +from ..rendering import RenderedObject import typeguard @@ -13,3 +13,6 @@ @typeguard.typechecked class Plugin(RenderedObject): """general interface for all plugins""" + + def __init__(self): + raise NotImplementedError("abstract base class only") From 7801e5dc1bacf5407a0ff26230fea52d45e34b08 Mon Sep 17 00:00:00 2001 From: mafshari64 Date: Thu, 20 Feb 2025 11:48:47 +0100 Subject: [PATCH 10/10] fix 2 buges-picmi to picongpu conversion in picongpu-picmi-phase_space.py --- lib/python/picongpu/picmi/phase_space.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/python/picongpu/picmi/phase_space.py b/lib/python/picongpu/picmi/phase_space.py index c06c5e3f71..261e2da9c6 100644 --- a/lib/python/picongpu/picmi/phase_space.py +++ b/lib/python/picongpu/picmi/phase_space.py @@ -22,7 +22,7 @@ class PhaseSpace(picmistandard.PICMI_PhaseSpace): def __init__( self, - species: PyPIConGPUSpecies, + species: PICMISpecies, period: int, spatial_coordinate: str, momentum: str, @@ -57,8 +57,10 @@ def get_as_pypicongpu( self, dict_species_picmi_to_pypicongpu: dict[PICMISpecies, PyPIConGPUSpecies], ) -> PhaseSpace: - print(f"dict_species_picmi_to_pypicongpu keys: {list(dict_species_picmi_to_pypicongpu.keys())}") - print(f"self.species: {self.species}") + # print(f"dict_species_picmi_to_pypicongpu keys: {list(dict_species_picmi_to_pypicongpu.keys())}") + # print(f"self.species: {self.species}") + + util.unsupported("extra attributes", self.__dict__.keys()) if self.species not in dict_species_picmi_to_pypicongpu: raise ValueError(f"Species {self.species} is not mapped in dict_species_picmi_to_pypicongpu!") @@ -73,8 +75,6 @@ def get_as_pypicongpu( # Print type before passing to PhaseSpace print(f"DEBUG: Mapped species: {pypicongpu_species}, Type: {type(pypicongpu_species)}") - util.unsupported("extra attributes", self.__dict__.keys()) - pypicongpu_phase_space = PhaseSpace( species=pypicongpu_species, period=self.period,