Source code for einsteinpy.rays.shadow

import warnings

import numpy as np
from astropy import units as u
from scipy.integrate import fixed_quad
from scipy.interpolate import interp1d
from scipy.optimize import newton


[docs] class Shadow: """ Class for plotting the shadow of Schwarzschild Black Hole surrounded by a thin accreting emission disk as seen by a distant observer. """ @u.quantity_input(mass=u.kg, fov=u.km) def __init__(self, mass, n_rays, fov, limit=0.001): self.mass = mass.to(u.kg) self.limit = limit self.n_rays = n_rays self.fov = fov.to(u.km) self.horizon = 2 * self.mass.value # To be changed after 0.3.0 self.b_crit = 3 * np.sqrt(3) * self.mass self.b = self._compute_B() self.z = list() self.bfin = list() for i in self.b: root = newton(self._root_equation, 0.1, args=(i,)) if np.isreal(root): self.bfin.append(i) self.z.append([i, np.real(root)]) self.z = np.array(self.z) self.k0 = self._intensity() self.k1 = self._intensity_from_event_horizon() self.intensity = self.k1 + self.k0 # Just to make the plot symmetric on -x axis self.fb1 = list(self.b2) + list(self.bfin) self.fb2 = np.asarray(list(-np.asarray(self.b2)) + list(-np.asarray(self.bfin))) def _compute_B(self): """ Returns an array of impact parameters """ return np.linspace(self.b_crit.value, self.fov.value, self.n_rays) def _root_equation(self, r_tp, i): """ Returns the root of the equation for ``r_tp`` (turning points) for some impact parameter """ # emath.sqrt is domain-agnostic and this is a complex equation return r_tp / np.emath.sqrt(1 - (2 * int(self.mass.value) / r_tp)) - i def _intensity_blue_sch(self, r, b): """ Returns the integrand for the blue shifted intensity to be integrated. Reference : Cosimo Bambi, 10.1103/PhysRevD.87.107501 """ GTT = 1 - (2 * self.mass.value / r) GRR = (1 - (2 * self.mass.value / r)) ** (-1) KRKText = ((GTT / GRR) * (1 - (b**2 * GTT / (r**2)))) ** 0.5 Gblue = ( (1 / GTT) - KRKText * (GRR / GTT) * ((1 - GTT) / (GTT * GRR)) ** 0.5 ) ** (-1) Iblue = -(Gblue**3) * (GTT / (r**2)) * (1 / KRKText) return Iblue def _intensity_red_sch(self, r, b): """ Returns the integrand for the red shifted intensity to be integrated. Reference : Cosimo Bambi, 10.1103/PhysRevD.87.107501 """ GTT = 1 - (2 * self.mass.value / r) GRR = (1 - (2 * self.mass.value / r)) ** (-1) KRKText = ((GTT / GRR) * (1 - (b**2 * GTT / (r**2)))) ** 0.5 Gred = ( (1 / GTT) + KRKText * (GRR / GTT) * ((1 - GTT) / (GTT * GRR)) ** 0.5 ) ** (-1) Ired = (Gred**3) * (GTT / (r**2)) * (1 / KRKText) return Ired def _intensity(self): """ Returns an array of the integrated values using ~scipy.integrate.quadrature as the intensities for the blue shifted and red shifted rays above the critical impact paratmeter from the distance to the emitter """ intensity = [] for i in np.arange(len(self.z)): b = self.z[i][0] val1, _ = fixed_quad( self._intensity_blue_sch, self.fov.value, self.z[i][1], args=(b,) ) val2, _ = fixed_quad( self._intensity_red_sch, self.z[i][1], self.fov.value, args=(b,) ) intensity.append(val1 + val2) return intensity def _intensity_from_event_horizon(self): """ Returns an array of the integrated values using ~scipy.integrate.quadrature as the intensities for the blue shifted and red shifted rays below the critical impact paratmeter from the event horizon to the distance given. """ self.b2 = np.linspace(self.limit, self.b_crit.value, len(self.bfin)) k1 = list() for i in self.b2: arg = i val3, _ = fixed_quad( self._intensity_red_sch, self.horizon, self.fov.value, args=(arg,) ) k1.append(val3) return k1
[docs] def smoothen(self, points=500): """ Sets the interpolated values for the intensities for smoothening of the plot using ~scipy.interpolate.interp1d """ b_new = np.linspace(np.min(self.fb1), np.max(self.fb1), points) interpolation = interp1d(self.fb1, self.intensity, kind="cubic") smoothened = interpolation(b_new) self.intensity = smoothened self.fb1 = b_new self.fb2 = -1 * b_new