Source code for exosim.tasks.instrument.computeSolidAngle

import astropy.units as u
import mpmath
import numpy as np

from exosim.tasks.task import Task
from exosim.utils.checks import check_units


[docs]class ComputeSolidAngle(Task): r""" It computes the solid angle given the system parameters. Returns -------- :class:`~astropy.units.Quantity` solid angle expressed as :math:`sr \cdot m^2` """ def __init__(self): """ Parameters __________ parameters: dict dictionary contained the channel parameters. This is usually parsed from :class:`~exosim.tasks.load.loadOptions.LoadOptions` other_parameters: dict additional dict accounting for signal metadata """ self.add_task_param("parameters", "channel parameters dict") self.add_task_param( "other_parameters", "additional dict accounting for signal metadata", None, )
[docs] def execute(self): parameters = self.get_task_param("parameters") other_parameters = self.get_task_param("other_parameters") # all solid angles validated against ArielRad2 on 07 Sept 2021. Exact match. if other_parameters and "solid_angle" in other_parameters.keys(): if other_parameters["solid_angle"] == "pi": omega_pix = np.pi * u.sr elif other_parameters["solid_angle"] == "pi-omega_pix": f_numx = parameters["Fnum_x"] if "Fnum_y" in parameters.keys(): f_numy = parameters["Fnum_y"] else: f_numy = None omega_pix = np.pi * u.sr - self._omega_pix(f_numx, f_numy) elif isinstance(other_parameters["solid_angle"], u.Quantity): omega_pix = check_units( other_parameters["solid_angle"], u.sr, self ) else: f_numx = parameters["Fnum_x"] if "Fnum_y" in parameters.keys(): f_numy = parameters["Fnum_y"] else: f_numy = None omega_pix = self._omega_pix(f_numx, f_numy) self.debug("omega pix: {}".format(omega_pix)) area_pix = (parameters["detector"]["delta_pix"] ** 2).to(u.m**2) self.debug("pixel area: {}".format(area_pix)) solid_angle = area_pix * omega_pix self.debug("solid angle: {}".format(solid_angle)) self.set_output(solid_angle)
def _omega_pix(self, Fnum_x, Fnum_y=None): """ Calculate the solid angle subtended by an elliptical aperture on-axis. Algorithm from "John T. Conway. Nuclear Instruments and Methods in Physics Research Section A: Accelerators, Spectrometers, Detectors and Associated Equipment, 614(1):17 ? 27, 2010. https://doi.org/10.1016/j.nima.2009.11.075 Equation n. 56 Parameters ---------- Fnum_x : scalar Input F-number along dispersion direction Fnum_y : scalar Optional, input F-number along cross-dispersion direction Returns ------- Omega : scalar The solid angle subtended by an elliptical aperture in units u.sr """ if not Fnum_y: Fnum_y = Fnum_x if Fnum_x > Fnum_y: a = 1.0 / (2 * Fnum_y) b = 1.0 / (2 * Fnum_x) else: a = 1.0 / (2 * Fnum_x) b = 1.0 / (2 * Fnum_y) h = 1.0 A = 4.0 * h * b / (a * np.sqrt(h * h + a * a)) k = np.sqrt((a * a - b * b) / (h * h + a * a)) alpha = np.sqrt(1 - (b / a) * (b / a)) Omega = 2.0 * np.pi - A * mpmath.ellippi(alpha * alpha, k * k) return Omega * u.sr