diff --git a/lib/python/picongpu/picmi/gaussian_laser.py b/lib/python/picongpu/picmi/gaussian_laser.py index f8778a32e4..72de3f9ae6 100644 --- a/lib/python/picongpu/picmi/gaussian_laser.py +++ b/lib/python/picongpu/picmi/gaussian_laser.py @@ -1,7 +1,7 @@ """ This file is part of PIConGPU. Copyright 2021-2024 PIConGPU contributors -Authors: Hannes Troepgen, Brian Edward Marre, Alexander Debus +Authors: Hannes Troepgen, Brian Edward Marre, Alexander Debus, Richard Pausch License: GPLv3+ """ @@ -13,6 +13,7 @@ import typeguard import typing +import logging @typeguard.typechecked @@ -87,21 +88,15 @@ def __init__( **kw, ) - def get_as_pypicongpu(self) -> laser.GaussianLaser: - util.unsupported("laser name", self.name) - util.unsupported("laser zeta", self.zeta) - util.unsupported("laser beta", self.beta) - util.unsupported("laser phi2", self.phi2) - # unsupported: fill_in (do not warn, b/c we don't know if it has been - # set explicitly, and always warning is bad) - + def check(self) -> None: + # polarization direction is normalized assert self.testRelativeError( 1, self.scalarProduct(self.polarization_direction, self.polarization_direction), 1e-9, ), "the polarization direction vector must be normalized" - # check for excessive phase values to avoid numerical precision errors + # phase values not excessive to avoid numerical precision errors assert abs(self.picongpu_phase) <= 2 * math.pi, "abs(phase) must be < 2*pi" # check that initialising from y_min-plane only is sensible @@ -110,36 +105,41 @@ def get_as_pypicongpu(self) -> laser.GaussianLaser: ), "laser propagation parallel to the y-plane or pointing outside \ from the inside of the simulation box is not supported by this \ laser in PIConGPU" + + # propagation direction is normalized assert self.testRelativeError( 1, - ( - self.propagation_direction[0] ** 2 - + self.propagation_direction[1] ** 2 - + self.propagation_direction[2] ** 2 - ), + self.scalarProduct(self.propagation_direction, self.propagation_direction), 1e-9, ), "propagation vector must be normalized" - # check centroid outside box + # centroid outside box assert self.centroid_position[1] <= 0, "the laser maximum must be \ outside of the \ simulation box, otherwise it is impossible to correctly initialize\ it using a huygens surface in the box, centroid_y <= 0" + # @todo implement check that laser field strength sufficiently small # at simulation box boundary + # @todo extend this to other propagation directions than +y - # check polarization vector normalization - + # polarization vector normalization assert self.testRelativeError( 1, - ( - self.propagation_direction[0] ** 2 - + self.propagation_direction[1] ** 2 - + self.propagation_direction[2] ** 2 - ), + self.scalarProduct(self.propagation_direction, self.propagation_direction), 1e-9, ), "polarization vector must be normalized" + def get_as_pypicongpu(self) -> laser.GaussianLaser: + util.unsupported("laser name", self.name) + util.unsupported("laser zeta", self.zeta) + util.unsupported("laser beta", self.beta) + util.unsupported("laser phi2", self.phi2) + # unsupported: fill_in (do not warn, b/c we don't know if it has been + # set explicitly, and always warning is bad) + + self.check() + pypicongpu_laser = laser.GaussianLaser() pypicongpu_laser.wavelength = self.wavelength pypicongpu_laser.waist = self.waist @@ -148,11 +148,18 @@ def get_as_pypicongpu(self) -> laser.GaussianLaser: pypicongpu_laser.phase = self.picongpu_phase pypicongpu_laser.E0 = self.E0 - pypicongpu_laser.pulse_init = max( - -2 * self.centroid_position[1] / (self.propagation_direction[1] * constants.c) / self.duration, - 15, + # unit: multiple of laser pulse duration + pypicongpu_laser.pulse_init = ( + -2.0 * self.centroid_position[1] / (self.propagation_direction[1] * constants.c) / self.duration ) - # unit: duration + + # @todo extend this to other propagation directions than +y + if pypicongpu_laser.pulse_init < 3.0: + logging.warning( + "set centroid_position and propagation_direction indicate that laser " + + "initalization might be too short.\n" + + f"Details: laser.pulse_init = {pypicongpu_laser.pulse_init} < 3" + ) pypicongpu_laser.polarization_type = self.picongpu_polarization_type pypicongpu_laser.polarization_direction = self.polarization_direction diff --git a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py index 4047ea0232..bc8c62b437 100644 --- a/share/picongpu/pypicongpu/examples/laser_wakefield/main.py +++ b/share/picongpu/pypicongpu/examples/laser_wakefield/main.py @@ -1,7 +1,7 @@ """ This file is part of PIConGPU. Copyright 2024 PIConGPU contributors -Authors: Masoud Afshari, Brian Edward Marre +Authors: Masoud Afshari, Brian Edward Marre, Richard Pausch License: GPLv3+ """ @@ -51,10 +51,12 @@ solver = picmi.ElectromagneticSolver(grid=grid, method="Yee") +laser_duration = 5.0e-15 +pulse_init = 15.0 laser = picmi.GaussianLaser( wavelength=0.8e-6, waist=5.0e-6 / 1.17741, - duration=5.0e-15, + duration=laser_duration, propagation_direction=[0.0, 1.0, 0.0], polarization_direction=[1.0, 0.0, 0.0], focal_position=[ @@ -64,7 +66,7 @@ ], centroid_position=[ float(numberCells[0] * cellSize[0] / 2.0), - 0.0, + -0.5 * pulse_init * laser_duration, float(numberCells[2] * cellSize[2] / 2.0), ], picongpu_polarization_type=pypicongpu.laser.GaussianLaser.PolarizationType.CIRCULAR,