Source code for caustics.angle_mixin

# mypy: disable-error-code="has-type,attr-defined,assignment"
from caskade import Param

from .backend_obj import backend


[docs] def e1e2_to_q(e1, e2): c = backend.clamp(backend.sqrt(e1**2 + e2**2), 0, 1) return (1 - c) / (1 + c)
[docs] def e1e2_to_phi(e1, e2): phi = 0.5 * backend.arctan2(e2, e1) return phi
[docs] def e1e2_to_qphi(e1, e2): q = e1e2_to_q(e1, e2) phi = e1e2_to_phi(e1, e2) return q, phi
[docs] def qphi_to_e1e2(q, phi): e1 = (1 - q) * backend.cos(2 * phi) / (1 + q) e2 = (1 - q) * backend.sin(2 * phi) / (1 + q) return e1, e2
[docs] def c1c2_to_q(c1, c2): c = backend.sqrt(c1**2 + c2**2) # torch.clamp(, 0, 1) return 1 - c / (1 + c)
[docs] def c1c2_to_phi(c1, c2): phi = 0.5 * backend.arctan2(c2, c1) return phi
[docs] def c1c2_to_qphi(c1, c2): q = c1c2_to_q(c1, c2) phi = c1c2_to_phi(c1, c2) return q, phi
[docs] def qphi_to_c1c2(q, phi): c1 = (1 - q) * backend.cos(2 * phi) / q c2 = (1 - q) * backend.sin(2 * phi) / q return c1, c2
[docs] class Angle_Mixin: def __init__( self, *args, **kwargs, ): super().__init__(*args, **kwargs) self._angle_system = "q_phi" @property def angle_system(self) -> str: return self._angle_system @angle_system.setter def angle_system(self, value: str): if value not in ["q_phi", "e1_e2", "c1_c2"]: raise ValueError( "angle_system must be either 'q_phi', 'e1_e2', or 'c1_c2'." ) if value == "e1_e2" and self._angle_system != "e1_e2": self.e1 = Param( "e1", shape=self.q.shape if self.q.static else (), units="unitless" ) self.e2 = Param( "e2", shape=self.q.shape if self.q.static else (), units="unitless" ) self.q = lambda p: e1e2_to_q(p["e1"].value, p["e2"].value) self.q.link(self.e1) self.q.link(self.e2) self.phi = lambda p: e1e2_to_phi(p["e1"].value, p["e2"].value) self.phi.link(self.e1) self.phi.link(self.e2) try: self.q.unlink(self.c1) self.phi.unlink(self.c1) self.q.unlink(self.c2) self.phi.unlink(self.c2) del self.c1 del self.c2 except AttributeError: pass elif value == "c1_c2" and self._angle_system != "c1_c2": self.c1 = Param( "c1", shape=self.q.shape if self.q.static else (), units="unitless" ) self.c2 = Param( "c2", shape=self.q.shape if self.q.static else (), units="unitless" ) self.q = lambda p: c1c2_to_q(p["c1"].value, p["c2"].value) self.q.link(self.c1) self.q.link(self.c2) self.phi = lambda p: c1c2_to_phi(p["c1"].value, p["c2"].value) self.phi.link(self.c1) self.phi.link(self.c2) try: self.q.unlink(self.e1) self.phi.unlink(self.e1) self.q.unlink(self.e2) self.phi.unlink(self.e2) del self.e1 del self.e2 except AttributeError: pass elif value == "q_phi" and self._angle_system != "q_phi": self.q = None self.phi = None try: self.q.shape = self.e1.shape self.phi.shape = self.e1.shape self.q.unlink(self.e1) self.phi.unlink(self.e1) self.q.unlink(self.e2) self.phi.unlink(self.e2) del self.e1 del self.e2 except AttributeError: pass try: self.q.shape = self.c1.shape self.phi.shape = self.c1.shape self.q.unlink(self.c1) self.phi.unlink(self.c1) self.q.unlink(self.c2) self.phi.unlink(self.c2) del self.c1 del self.c2 except AttributeError: pass self._angle_system = value