Source code for lasy.profiles.profile

import numpy as np
from scipy.constants import c


[docs] class Profile(object): """ Base class for all laser profiles. Any new laser profile should inherit from this class, and define its own `evaluate` method, using the same signature as the method below. For most cases, use derived classes instead of this base class. Common operators (addition and multiplication by a scalar) are provided as part of this base class. For such operations, the user is responsible for handling the complex phase and weights of summed profiles. In particular, summing between different types of profiles is not recommended. Parameters ---------- wavelength : scalar Central wavelength for which the laser pulse envelope is defined. pol : list of 2 complex numbers Polarization vector that multiplies array_in to get the Ex and Ey fields. The envelope of each component of the electric field is given by: - Ex_env = array_in*pol(0) - Ey_env = array_in*pol(1) Standard polarizations can be obtained from: - Linear polarization in x: pol = (1,0) - Linear polarization in y: pol = (0,1) - Circular polarization: pol = (1,j)/sqrt(2) (j is the imaginary number) The polarization vector is normalized to have a unitary magnitude. """ def __init__(self, wavelength, pol): assert len(pol) == 2 norm_pol = np.sqrt(np.abs(pol[0]) ** 2 + np.abs(pol[1]) ** 2) self.pol = np.array([pol[0] / norm_pol, pol[1] / norm_pol]) self.lambda0 = wavelength self.omega0 = 2 * np.pi * c / self.lambda0 self.k0 = 2.0 * np.pi / wavelength self.is_cw = False self.is_plane_wave = False
[docs] def evaluate(self, x, y, t): """ Return the envelope field of the laser. Parameters ---------- x, y, t : ndarrays of floats Define points on which to evaluate the envelope These arrays need to all have the same shape. Returns ------- envelope : ndarray of complex numbers Contains the value of the envelope at the specified points This array has the same shape as the arrays x, y, t """ # The base class only defines dummy fields # (This should be replaced by any class that inherits from this one.) return np.zeros_like(x, dtype="complex128")
def __add__(self, other): """Return the sum of two profiles.""" return SummedProfile(self, other) def __mul__(self, factor): """Return the scaled profile.""" return ScaledProfile(self, factor) def __rmul__(self, factor): """Return the scaled profile.""" return ScaledProfile(self, factor) def __update_is_cw__(self, value): """Update state of is_cw variable.""" self.is_cw = value def __update_is_plane_wave__(self, value): """Update state of is_plane_wave variable.""" self.is_plane_wave = value
class SummedProfile(Profile): """ Base class for profiles that are the sum of several other profiles. Profile class that represents the sum of multiple profiles. Parameters ---------- profiles : list of Profile objects List of profiles to be summed. """ def __init__(self, *profiles): """Initialize the summed profile.""" # Check that all profiles are Profile objects assert all([isinstance(p, Profile) for p in profiles]), ( "All summands must be Profile objects." ) self.profiles = profiles # Get the wavelength values from each profile lambda0s = [p.lambda0 for p in self.profiles] pols = [p.pol for p in self.profiles] # Check that all wavelengths are the same assert np.allclose(lambda0s, lambda0s[0]), ( "Added profiles must have the same wavelength." ) lambda0 = profiles[0].lambda0 # Check that all polarizations are the same assert np.allclose(pols, pols[0]), ( "Added profiles must have the same polarization." ) pol = profiles[0].pol # Initialize the parent class super().__init__(lambda0, pol) def evaluate(self, x, y, t): """Return the envelope field of the summed profile.""" # Sum the fields of each profile return sum([p.evaluate(x, y, t) for p in self.profiles]) class ScaledProfile(Profile): """ Base class for profiles that are scaled by a factor. Profile class that represents scaled profiles. Parameters ---------- profiles : Profile object Profile to be scaled. factor : int or float Factor by which to scale the profile. """ def __init__(self, profile, factor): """Initialize the summed profile.""" # Check that the factor is a number assert isinstance(factor, (int, float)), "The factor must be a number." # Check that the profile is a Profile object assert isinstance(profile, Profile), "The profile must be a Profile object." self.profile = profile self.factor = factor # Get the wavelength and polarization from the profile lambda0 = profile.lambda0 pol = profile.pol # Initialize the parent class super().__init__(lambda0, pol) def evaluate(self, x, y, t): """Return the envelope field of the scaled profile.""" # Sum the fields of each profile return self.profile.evaluate(x, y, t) * self.factor