diff --git a/docs/physics/est_and_conv/estimators.ipynb b/docs/physics/est_and_conv/estimators.ipynb index 92dce68147d..78199f795e7 100644 --- a/docs/physics/est_and_conv/estimators.ipynb +++ b/docs/physics/est_and_conv/estimators.ipynb @@ -36,7 +36,7 @@ "\n", "\n", "\n", - "These estimators allow us to calculate the [radiative temperature](../setup/model.ipynb#Radiative-Temperature) $T_\\mathrm{rad}$ and [dilution factor](../setup/model.ipynb#Dilution-Factor) $W$ in each shell using\n", + "These estimators allow us to calculate the [radiative temperature](../setup/model.ipynb#Temperatures) $T_\\mathrm{rad}$ and [dilution factor](../setup/model.ipynb#Dilution-Factor) $W$ in each shell using\n", "\n", "$$T_{\\mathrm{rad}} = \\frac{h}{k_{\\mathrm{B}}} \\frac{\\pi^4}{360 \\zeta(5)} \\frac{\\bar \\nu}{J}$$\n", "\n", @@ -86,7 +86,7 @@ "\n", "\n", "\n", - "If set to detailed mode (see [plasma configuration](../../io/configuration/components/plasma.rst)), the `J_blue` plasma property will will be replaced with the value of the $J^b_{lu}$ estimator (the raw estimator times the factor of $\\frac{ct_\\mathrm{explosion}}{4\\pi V \\Delta t}$). Otherwise, the `J_blue` in the plasma are calculated as they typically are in the plasma calculations, and the $J^b_{lu}$ estimator is only used for the [formal integral](../spectrum/sourceintegration.rst)." + "If set to detailed mode (see [plasma configuration](../../io/configuration/components/plasma.rst)), the `J_blue` plasma property will will be replaced with the value of the $J^b_{lu}$ estimator (the raw estimator times the factor of $\\frac{ct_\\mathrm{explosion}}{4\\pi V \\Delta t}$). Otherwise, the `J_blue` in the plasma are calculated as they typically are in the plasma calculations, and the $J^b_{lu}$ estimator is only used for the [formal integral](../spectrum/formal_integral.rst)." ] }, { diff --git a/docs/physics/images/formal_integral_2d.ggb b/docs/physics/images/formal_integral_2d.ggb new file mode 100644 index 00000000000..12db84d6364 Binary files /dev/null and b/docs/physics/images/formal_integral_2d.ggb differ diff --git a/docs/physics/images/formal_integral_2d_above.png b/docs/physics/images/formal_integral_2d_above.png new file mode 100644 index 00000000000..16499cea231 Binary files /dev/null and b/docs/physics/images/formal_integral_2d_above.png differ diff --git a/docs/physics/images/formal_integral_2d_below.png b/docs/physics/images/formal_integral_2d_below.png new file mode 100644 index 00000000000..c0c24c82fe7 Binary files /dev/null and b/docs/physics/images/formal_integral_2d_below.png differ diff --git a/docs/physics/images/formal_integral_sphere.ggb b/docs/physics/images/formal_integral_sphere.ggb new file mode 100644 index 00000000000..184b0c588f7 Binary files /dev/null and b/docs/physics/images/formal_integral_sphere.ggb differ diff --git a/docs/physics/images/formal_integral_sphere.jpg b/docs/physics/images/formal_integral_sphere.jpg new file mode 100644 index 00000000000..c49adb77327 Binary files /dev/null and b/docs/physics/images/formal_integral_sphere.jpg differ diff --git a/docs/physics/montecarlo/propagation.rst b/docs/physics/montecarlo/propagation.rst index 345643f0828..ccd76671077 100644 --- a/docs/physics/montecarlo/propagation.rst +++ b/docs/physics/montecarlo/propagation.rst @@ -155,6 +155,7 @@ When a packet is moved into a new cell, as mentioned before, it is moved to the boundary, the plasma properties are recalculated, and the propagation direction of the packet is updated (using :math:`\mu_f = \frac{l + r_i \mu_i}{r_f}`). +.. _physical-interactions: Physical Interactions --------------------- diff --git a/docs/physics/spectrum/basic.ipynb b/docs/physics/spectrum/basic.ipynb index 86f5e4bacca..5760fe826a1 100644 --- a/docs/physics/spectrum/basic.ipynb +++ b/docs/physics/spectrum/basic.ipynb @@ -422,7 +422,7 @@ "source": [ "You may notice that the bins are not uniformly spaced with respect to wavelength. This is because we use the same bins for both wavelength and frequency, and thus the bins which are uniformly spaced with respect to frequency are not uniformly spaced with respect to wavelength. This is okay though, since luminosity density allows us to alter the bins without significantly altering the graph!\n", "\n", - "Another thing you may notice in these graphs is the lack of a smooth curve. This is due to **noise**: the effects of the random nature of Monte Carlo simulations. This makes it very difficult to get a precise spectrum without drastically increasing the number of Monte Carlo packets. To solve this problem, TARDIS uses [virtual packets](virtualpackets.rst) and [the formal integral method](sourceintegration.rst) to generate a spectrum with less noise." + "Another thing you may notice in these graphs is the lack of a smooth curve. This is due to **noise**: the effects of the random nature of Monte Carlo simulations. This makes it very difficult to get a precise spectrum without drastically increasing the number of Monte Carlo packets. To solve this problem, TARDIS uses [virtual packets](virtualpackets.rst) and [the formal integral method](formal_integral.rst) to generate a spectrum with less noise." ] } ], diff --git a/docs/physics/spectrum/formal_integral.rst b/docs/physics/spectrum/formal_integral.rst new file mode 100644 index 00000000000..9e0c850a7eb --- /dev/null +++ b/docs/physics/spectrum/formal_integral.rst @@ -0,0 +1,150 @@ +.. _formal_integral: + +******************************************** +Spectrum Generation with the Formal Integral +******************************************** + +:cite:`Lucy1999a` describes an alternative method for calculating the TARDIS spectrum while eliminating nearly all Monte Carlo noise. Instead of calculating the spectrum directly from the Monte Carlo (or virtual) packets, we use information from the Monte Carlo simulation to build an analytical solution for the supernova spectrum. + +.. warning:: + + The current implementation of the formal integral has several limitations. + Please consult the corresponding section below to ensure that these + limitations do not apply to your TARDIS. + + +Deriving the Integral +===================== + +The spectrum generated by TARDIS includes light that is released in all directions. However, we approximate the supernova as spherically symmetric, meaning the light is released isotropically (equally in all directions). Thus, it will suffice to calculate the spectrum of light propagating in a single direction, call it the positive z-direction, and then sum over every direction. Specifically, we have + +.. math:: L_\nu = \int L_{\nu z} d\Omega = L_{\nu z} \int d\Omega = 4\pi L_{\nu z} + +where :math:`L_\nu` is the luminosity density at a frequency :math:`\nu`, :math:`L_{\nu z}` is the luminosity density at a frequency :math:`\nu` for light propagating in the positive z-direction, and :math:`\Omega` is the solid angle. + +We now must calculate :math:`L_{\nu z}`, starting with more symmetry considerations. The figures below show various rays of light (in black) coming out of the supernova at various values of :math:`p`, the impact parameter (defined as the distance from the x-axis, and can be seen as the value along the blue :math:`p`-axis). By symmetry, the intensity :math:`I_\nu` (luminosity density per unit area) along the ray will be identical anywhere on the blue circles shown (each of which has a constant impact parameter). Each circle has a circumference of :math:`2\pi p`. The luminosity density per unit distance on any given circle would then be :math:`I_\nu(p)\times 2\pi p` (specifically, we are integrating the constant intensity around the circumference of the circle). Finally, to get :math:`L_{\nu z}`, we must integrate :math:`I_\nu(p)\times 2\pi p` over every possible impact parameter, whose values range from zero to the outer radius of the supernova, :math:`r_\mathrm{boundary\_outer}`. So, + +.. math:: L_{\nu z} = \int_0^{r_\mathrm{boundary\_outer}} I_\nu(p)\times 2\pi p dp = 2\pi \int_0^{r_\mathrm{boundary\_outer}} I_\nu(p) p dp. + +Putting this all together, we get + +.. math:: L_\nu = 8\pi^2 \int_0^{r_\mathrm{boundary\_outer}} I_\nu(p) p dp. + +.. note:: + + A separate integral must be done for each frequency. + +.. image:: ../images/formal_integral_sphere.jpg + :width: 1000 + + +Summary of Implementation +========================= + +Since there is a continuum of frequencies represented in a spectrum, the formal integral cannot calculate the luminosity density at *every* frequency. Instead, we calculate :math:`L_\nu` at a finite number of frequencies between the ``start`` and ``stop`` wavelengths provided in the :ref:`spectrum-config` (converting between frequency and wavelength using :math:`\nu=\frac{c}{\lambda}` where :math:`\lambda` is wavelength and :math:`c` is the speed of light) to give us an approximate spectrum. The number of frequencies we use is the ``num`` argument in the configuration. The frequencies are evenly spaced **in wavelength space** (exactly like histogram bins in :doc:`basic` -- see near the bottom of that page for more information). + +Similarly, when doing the integral for a particular frequency, there is a continuum of impact parameters, so we cannot calculate :math:`I_\nu(p)` for every single one. We instead use a finite list of impact parameters between 0 and the supernova's outer boundary. The number of impact parameters we use is the value of ``points`` provided in the ``integrated`` section of the spectrum configuration. + +For each frequency in our list of frequencies, TARDIS calculates :math:`I_\nu(p)` for each :math:`p` in the list of impact parameters, and then performs the integral :math:`\int_0^{r_\mathrm{boundary\_outer}} I_\nu(p) p dp` using `trapezoid integration `_. Our result is then multiplied by :math:`8\pi^2` to get the correct luminosity density. The most involved part of the calculation is calculating :math:`I_\nu(p)` for every combination of :math:`\nu` in the list of frequencies and :math:`p` in the list of impact parameters. This step is described in detail in the following section: + + +Calculating :math:`I_\nu(p)` +============================ + +Setting Up +---------- + +We now calculate :math:`I_\nu(p)`, which is the intensity of the light with a **lab frame** (see :ref:`referenceframes`) frequency :math:`\nu` exiting a the supernova along a ray with impact parameter :math:`p`, as shown in the diagram below (we use the lab frame frequency as that is the frame in which the spectrum is observed). Specifically, we are looking for the intensity of light with a frequency :math:`\nu` traveling to the right on the right side of the ray. We start by discussing the case where :math:`p>r_\mathrm{boundary\_inner}` (where the ray does not intersect the photosphere). After, we will comment on what occurs when :math:`p`. + + +Rays Intersecting the Photosphere +--------------------------------- + +Since the photosphere is modeled as being optically thick, if a ray intersects the photosphere, anything that happens prior to the photosphere does not matter -- the photosphere absorbs all light that hits it. Because of this, to calculate :math:`I_\nu(p)` over a ray that starts by exiting the photosphere, we must slightly adjust our approach, as shown in the diagram below. In this case, we now have that the minimum z-coordinate is :math:`z_\mathrm{min}=\sqrt{r_\mathrm{boundary\_inner}^2-p^2}`, and we use this to determine the lowest possible resonant frequency on the ray as before, which will then give us :math:`z_0`, as it did before. Finally, since light along this ray is released from the photosphere, we have + +.. math:: I_0^b = B_\nu(T_\mathrm{inner})= \frac{2h}{c^2}\frac{\nu^3}{e^{h\nu/k_BT}-1}. + +which is the Planck function (see :doc:`../montecarlo/initialization`). After making those small adjustments, we increment the intensity exactly as in the other case. + +.. image:: ../images/formal_integral_2d_below.png + :width: 700 + + +Current Limitations +=================== + +The current implementation of the formal integral has some limitations: + +* Once electron scattering is included, the scheme only produces accurate results when many resonances occur on the rays. This is simply because otherwise the average of :math:`J^b` and :math:`J^r` does not provide an accurate representation of the mean intensity between successive resonance points. Also, :math:`d\tau` can become large which can create unphysical, negative intensities. + +It is always advised to check the results of the formal integration against the +spectrum constructed from the emerging Monte Carlo packets. diff --git a/docs/physics/spectrum/index.rst b/docs/physics/spectrum/index.rst index aaa7a9b242d..3de45aaa376 100644 --- a/docs/physics/spectrum/index.rst +++ b/docs/physics/spectrum/index.rst @@ -17,4 +17,4 @@ below. .. toctree:: basic virtualpackets - sourceintegration \ No newline at end of file + formal_integral \ No newline at end of file diff --git a/docs/physics/spectrum/sourceintegration.rst b/docs/physics/spectrum/sourceintegration.rst deleted file mode 100644 index c06a621feae..00000000000 --- a/docs/physics/spectrum/sourceintegration.rst +++ /dev/null @@ -1,191 +0,0 @@ -.. _formal_integral: - -***************************************** -Direct integration of the radiation field -***************************************** - -:cite:`Lucy1999a` describes an alternative method for the generation of -synthetic supernova spectra. Instead of using the frequency and energy of -virtual Monte Carlo (MC) packets to create a spectrum through binning, one can -formally integrate the line source functions which can be calculated from -volume-based estimators collected during the MC simulation. Spectra generated -using this method are virtually noise-free. However, statistical fluctuations -inherent to Monte Carlo calculations still affect the determination of the -source functions and thus indirectly introduce an uncertainty in the spectral -synthesis process. - -.. warning:: - - The current implementation of the formal integral has several limitations. - Please consult the corresponding section below to ensure that these - limitations do not apply to your application. - - -Estimators -========== - -The procedure relies on determining line absorption rates, which are calculated -during the Monte Carlo simulation by incrementing the volume-based estimator - -.. math:: - - \dot E_{lu} = \frac{1}{\Delta t V} \left( 1- e^{-\tau_{lu}}\right) \sum - \epsilon - -Here, the sum involves all packages in a given shell that come into resonance -with the transition :math:`u \rightarrow l`, :math:`\epsilon` denotes the -energy of one such packet, and :math:`\tau_{lu}` the Sobolev optical depth of -the line transition. - -After the Monte Carlo radiative transfer step, a level absorption estimator is -calculated by summing up all absorption rates for transitions which lead to the -target level - -.. math:: - - \dot E_u = \sum_{i < u} \dot E_{iu} - -Finally, the line source function for each transition can be derived with - -.. math:: - - \left( 1- e^{-\tau_{lu}}\right) S_{ul} = \frac{\lambda_{ul} t}{4 \pi} q_{ul} - \dot E_u - -Here, :math:`\lambda_{ul}` is the wavelength of the line :math:`u \rightarrow -l`, and :math:`q_{ul}` is the corresponding branching ratio, i.e. the fraction -of de-excitations of level :math:`u` proceeding via the transition -:math:`u\rightarrow l`. For convenience, the attenuating factor is kept on the -left-hand side because it is the product of the two that will appear in later -formulae. - -Finally, if the contribution by electron-scattering has to be taken into -account, estimators for the diffuse radiation field in the blue and red wings -of the different transitions are needed. These can again be determined with -volume-based estimators according to - -.. math:: - - J_{lu}^b = \frac{\lambda_{lu}}{4 \pi \Delta t V} \sum \varepsilon - - -and - -.. math:: - - J_{lu}^r = J_{lu}^b e^{-\tau_{lu}} + S_{ul} (1 + e^{-\tau_{lu}}) - - -Integration -=========== - -Calculating the emergent spectrum proceeds by casting rays parallel to the line -of sight to the observer through the ejecta. The distance along these rays will -be measured by :math:`z` and the offset to ejecta centre by the impact -parameter :math:`p`. The following figure illustrates this "impact geometry": - -.. image:: https://i.imgur.com/WwVHp5c.png - -The emergent monochromatic luminosity can then be obtained by integrating over -the limiting specific intensities of these rays - -.. math:: - - L_\nu = 8 \pi^2 \int_0^\infty I_\nu (p) p dp - -To obtain the limiting intensity, we have to consider the different line -resonances along the ray and calculate how much radiation is added and removed. -At the resonance point with the :math:`k`-th line transition, the intensity -increment is - -.. math:: - - I_k^r = I_k^b e^{-\tau_k} + \left( 1- e^{-\tau_k}\right) S_{k} - -In the absence of continuum interactions, the relation - -.. math:: - - I_{k+1}^b = I_k^r - -establishes the connection to the next resonance point. If electron-scattering -is taken into account its contribution between successive resonances has to be -considered - -.. math:: - - I_{k+1}^b = I_k^r + \Delta \tau_k \left[ \frac 1 2(J_k^r + J_{k+1}^b) - - I_k^r \right] - - -Thus, by recursively applying the above relations for all resonances occurring -on the ray, the limiting specific intensity for the final integration can be -calculated. The boundary conditions for this process are either :math:`I_0^r = -B_\nu(T)` if the ray intersects the photosphere or :math:`I_0^r = 0` otherwise. - -Implementation Details -====================== - -We seek to integrate all emissions at a certain wavelength :math:`\nu` along a -ray with impact parameter :math:`p`. Because the supernova ejecta is expanding -homologously, the co-moving frame frequency is continuously shifted to longer -wavelengths due to the relativistic Doppler effect as the packet/photon -propagates. - -To find out which lines can shift into the target frequency, we need to -calculate the maximum Doppler shift along a given ray. At any point, the -Doppler effect in our coordinates is - -.. math:: - - \nu = \nu_0 \left( 1 + \beta \mu \right) - -where :math:`\beta = \frac v c`, and :math:`\mu = \cos \theta`. Here -:math:`\theta` is the angle between the radial direction and the ray to the -observer, as shown in the figure below. Because we are in the homologous -expansion regime :math:`v = \frac r t`. Solving for :math:`\nu_0` in the above -gives the relation we seek, but we require an expression for :math:`\mu`. -Examining the figure, we see that for positive :math:`z` the angle -:math:`\theta_2` can be related to the :math:`z` coordinate of the point C by - -.. math:: - - \cos \theta_2 = \frac{z_c}{r} = \mu - - -and in turn :math:`z_c` can be given as - -.. math:: - - z_c = \sqrt{r_c^2 + p_c^2} - -where the subscripts indicate the value at point C. By symmetry, the -intersection point for negative :math:`z` is simply :math:`-z_c`. - -Using the expression for :math:`\mu`, :math:`\beta` above leads to the -dependence on :math:`r` cancelling, and solving for :math:`\nu_0` gives - -.. math:: - - \nu_0 = \frac{\nu}{1 + \frac{z}{ct}} - -For any given shell and impact parameter, we can thus find the maximum and -minimum co-moving frequency that will give the specified lab frame frequency. -This allows us to find the section of the line list with the transitions whose -resonances have to be considered in the calculation of the limiting specific -intensity. - -Current Limitations -=================== - -The current implementation of the formal integral has some limitations: - -* once electron scattering is included, the scheme only produces accurate - results when multiple resonances occur on the rays. This is simply because - otherwise the :math:`J^b` and :math:`J^r` do not provide an accurate - representation of the diffuse radiation field at the current location on the - ray. Also, :math:`d\tau` can become large which can create unphysical, - negative intensities. - -It is always advised to check the results of the formal integration against the -spectrum constructed from the emerging Monte Carlo packets. diff --git a/tardis/montecarlo/montecarlo_numba/formal_integral.py b/tardis/montecarlo/montecarlo_numba/formal_integral.py index 70f82ef626d..dd2f8b78a24 100644 --- a/tardis/montecarlo/montecarlo_numba/formal_integral.py +++ b/tardis/montecarlo/montecarlo_numba/formal_integral.py @@ -18,7 +18,9 @@ NumbaModel, NumbaPlasma, ) -from tardis.montecarlo.montecarlo_numba.formal_integral_cuda import CudaFormalIntegrator +from tardis.montecarlo.montecarlo_numba.formal_integral_cuda import ( + CudaFormalIntegrator, +) from tardis.montecarlo.spectrum import TARDISSpectrum @@ -49,6 +51,7 @@ def numba_formal_integral( """ model, plasma, and estimator are the numba variants """ + # todo: add all the original todos # Initialize the output which is shared among threads L = np.zeros(inu_size, dtype=np.float64) @@ -194,14 +197,14 @@ def numba_formal_integral( return L -#integrator_spec = [ +# integrator_spec = [ # ("model", NumbaModel.class_type.instance_type), # ("plasma", NumbaPlasma.class_type.instance_type), # ("points", int64), -#] +# ] -#@jitclass(integrator_spec) +# @jitclass(integrator_spec) class NumbaFormalIntegrator(object): """ Helper class for performing the formal integral @@ -246,15 +249,15 @@ def formal_integral( class FormalIntegrator(object): """ - Class containing the formal integrator. - - If there is a NVIDIA CUDA GPU available, - the formal integral will automatically run - on it. If multiple GPUs are available, it will - choose the first one that it sees. You can - read more about selecting different GPUs on + Class containing the formal integrator. + + If there is a NVIDIA CUDA GPU available, + the formal integral will automatically run + on it. If multiple GPUs are available, it will + choose the first one that it sees. You can + read more about selecting different GPUs on Numba's CUDA documentation. - + Parameters ---------- model : tardis.model.Radial1DModel @@ -383,9 +386,9 @@ def make_source_function(self): model = self.model runner = self.runner - #macro_ref = self.atomic_data.macro_atom_references + # macro_ref = self.atomic_data.macro_atom_references macro_ref = self.atomic_data.macro_atom_references - #macro_data = self.atomic_data.macro_atom_data + # macro_data = self.atomic_data.macro_atom_data macro_data = self.original_plasma.macro_atom_data no_lvls = len(self.levels_index)