Source code for caustics.lenses.external_shear

# mypy: disable-error-code="dict-item"
from typing import Optional, Union, Annotated, Literal
from warnings import warn

from caskade import forward, Param

from ..backend_obj import ArrayLike, backend
from .base import ThinLens, CosmologyType, NameType, ZType
from . import func

__all__ = ("ExternalShear",)


[docs] class ExternalShear(ThinLens): """ Represents an external shear effect in a gravitational lensing system. Attributes ---------- name: str Identifier for the lens instance. cosmology: Cosmology The cosmological model used for lensing calculations. z_l: Optional[Union[ArrayLike, float]] The redshift of the lens. *Unit: unitless* z_s: Optional[Union[ArrayLike, float]] The redshift of the source. *Unit: unitless* x0, y0: Optional[Union[ArrayLike, float]] Coordinates of the shear center in the lens plane. *Unit: arcsec* gamma_1, gamma_2: Optional[Union[ArrayLike, float]] Shear components. *Unit: unitless* Notes ------ The shear components gamma_1 and gamma_2 represent an external shear, a gravitational distortion that can be caused by nearby structures outside of the main lens galaxy. """ _null_params = { "x0": 0.0, "y0": 0.0, "gamma_1": 0.1, "gamma_2": 0.1, } def __init__( self, cosmology: CosmologyType, z_l: ZType = None, z_s: ZType = None, x0: Annotated[ Optional[Union[ArrayLike, float]], "x-coordinate of the shear center in the lens plane", True, ] = None, y0: Annotated[ Optional[Union[ArrayLike, float]], "y-coordinate of the shear center in the lens plane", True, ] = None, gamma_1: Annotated[ Optional[Union[ArrayLike, float]], "Shear component in the x-direction", True, ] = None, gamma_2: Annotated[ Optional[Union[ArrayLike, float]], "Shear component in the y-direction", True, ] = None, parametrization: Literal["cartesian", "angular"] = "cartesian", s: Annotated[ float, "Softening length for the elliptical power-law profile" ] = 0.0, name: NameType = None, **kwargs, ): super().__init__(cosmology=cosmology, z_l=z_l, name=name, z_s=z_s) self.x0 = Param("x0", x0, shape=(), units="arcsec") self.y0 = Param("y0", y0, shape=(), units="arcsec") self.gamma_1 = Param("gamma_1", gamma_1, shape=(), units="unitless") self.gamma_2 = Param("gamma_2", gamma_2, shape=(), units="unitless") self._parametrization = "cartesian" self.parametrization = parametrization if self.parametrization == "angular": self.gamma.value = kwargs.get("gamma", None) self.phi.value = kwargs.get("phi", None) self.s = s @property def parametrization(self) -> str: return self._parametrization @parametrization.setter def parametrization(self, value: str): if value not in ["cartesian", "angular"]: raise ValueError( f"Invalid parametrization: {value}. Must be 'cartesian' or 'angular'." ) if value == "angular" and self._parametrization != "angular": self.gamma = Param( "gamma", shape=self.gamma_1.shape if self.gamma_1.static else (), units="unitless", ) self.phi = Param( "phi", shape=self.gamma_1.shape if self.gamma_1.static else (), units="radians", ) if self.gamma_1.static: warn( f"Parameter {self.gamma_1.name} was static, value now overridden by new {value} parametrization. To remove this warning, have {self.gamma_1.name} be dynamic when changing parametrizations.", ) self.gamma_1.value = lambda p: func.gamma_phi_to_gamma1( p["gamma"].value, p["phi"].value ) if self.gamma_2.static: warn( f"Parameter {self.gamma_2.name} was static, value now overridden by new {value} parametrization. To remove this warning, have {self.gamma_2.name} be dynamic when changing parametrizations.", ) self.gamma_2.value = lambda p: func.gamma_phi_to_gamma2( p["gamma"].value, p["phi"].value ) self.gamma_1.link(self.gamma) self.gamma_1.link(self.phi) self.gamma_2.link(self.gamma) self.gamma_2.link(self.phi) if value == "cartesian" and self._parametrization != "cartesian": self.gamma_1.value = None self.gamma_2.value = None try: if self.gamma.static: warn( f"Parameter {self.gamma.name} was static, value now overridden by new {value} parametrization. To remove this warning, have {self.gamma.name} be dynamic when changing parametrizations.", ) self.gamma_1.unlink(self.gamma) self.gamma_2.unlink(self.gamma) del self.gamma except AttributeError: pass try: if self.phi.static: warn( f"Parameter {self.phi.name} was static, value now overridden by new {value} parametrization. To remove this warning, have {self.phi.name} be dynamic when changing parametrizations.", ) self.gamma_1.unlink(self.phi) self.gamma_2.unlink(self.phi) del self.phi except AttributeError: pass self._parametrization = value
[docs] @forward def reduced_deflection_angle( self, x: ArrayLike, y: ArrayLike, x0: Annotated[ArrayLike, "Param"], y0: Annotated[ArrayLike, "Param"], gamma_1: Annotated[ArrayLike, "Param"], gamma_2: Annotated[ArrayLike, "Param"], ) -> tuple[ArrayLike, ArrayLike]: """ Calculates the reduced deflection angle. Parameters ---------- x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* Returns ------- x_component: ArrayLike Deflection Angle in x-direction. *Unit: arcsec* y_component: ArrayLike Deflection Angle in y-direction. *Unit: arcsec* """ return func.reduced_deflection_angle_external_shear( x0, y0, gamma_1, gamma_2, x, y )
[docs] @forward def potential( self, x: ArrayLike, y: ArrayLike, x0: Annotated[ArrayLike, "Param"], y0: Annotated[ArrayLike, "Param"], gamma_1: Annotated[ArrayLike, "Param"], gamma_2: Annotated[ArrayLike, "Param"], ) -> ArrayLike: """ Calculates the lensing potential. Parameters ---------- x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* Returns ------- ArrayLike The lensing potential. *Unit: arcsec^2* """ return func.potential_external_shear(x0, y0, gamma_1, gamma_2, x, y)
[docs] @forward def convergence( self, x: ArrayLike, y: ArrayLike, ) -> ArrayLike: """ The convergence is undefined for an external shear. Parameters ---------- x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* Returns ------- ArrayLike Convergence for an external shear. *Unit: unitless* Raises ------ NotImplementedError This method is not implemented as the convergence is not defined for an external shear. """ return backend.zeros_like(x)