Source code for ctapipe.instrument.optics

"""
Classes and functions related to telescope Optics
"""

import logging

import astropy.units as u
import numpy as np

from ..utils import get_table_dataset

logger = logging.getLogger(__name__)


[docs]class OpticsDescription: """ Describes the optics of a Cherenkov Telescope mirror The string representation of an `OpticsDescription` will be a combination of the telescope-type and sub-type as follows: "type-subtype". You can also get each individually. Parameters ---------- num_mirrors: int Number of mirrors, i. e. 2 for Schwarzschild-Couder else 1 equivalent_focal_length: Quantity(float) effective focal-length of telescope, independent of which type of optics (as in the Monte-Carlo) mirror_area: float total reflective surface area of the optical system (in m^2) num_mirror_tiles: int number of mirror facets Raises ------ ValueError: if tel_type or mirror_type are not one of the accepted values TypeError, astropy.units.UnitsError: if the units of one of the inputs are missing or incompatible """ @u.quantity_input(mirror_area=u.m ** 2, equivalent_focal_length=u.m) def __init__( self, name, num_mirrors, equivalent_focal_length, mirror_area=None, num_mirror_tiles=None, ): self.name = name self.equivalent_focal_length = equivalent_focal_length.to(u.m) self.mirror_area = mirror_area self.num_mirrors = num_mirrors self.num_mirror_tiles = num_mirror_tiles def __hash__(self): """Make this hashable, so it can be used as dict keys or in sets""" return hash( ( self.equivalent_focal_length.to_value(u.m), self.mirror_area, self.num_mirrors, self.num_mirror_tiles, ) ) def __eq__(self, other): """Make this hashable, so it can be used as dict keys or in sets""" return hash(self) == hash(other)
[docs] @classmethod def from_name(cls, name, optics_table="optics"): """ Construct an OpticsDescription from the name. This needs the ``optics`` table dataset to be accessible via ``~ctapipe.utils.get_table_dataset``. Parameters ---------- name: str string representation of optics (MST, LST, SST-1M, SST-ASTRI,...) optics_table: str base filename of optics table if not 'optics.*' Returns ------- OpticsDescription """ if isinstance(optics_table, str): table = get_table_dataset(optics_table, role="OpticsDescription.from_name") else: table = optics_table version = table.meta.get("TAB_VER") # we introduced the TAB_VER after switching to the second version # of this table, so when the version is missing, it can be either 1 or 2 # we guess the version by looking for the mirror_type attribute. if version is None: if "mirror_type" in table.colnames: version = "1.0" else: version = "2.0" if version not in {"1.0", "2.0"}: raise ValueError(f"Unsupported version of optics table: {version}") if version == "1.0": mask = table["tel_description"] == name elif version == "2.0": mask = table["description"] == name if np.count_nonzero(mask) == 0: raise ValueError(f"Unknown telescope name {name}") if version == "1.0": num_mirrors = 1 if table["mirror_type"][mask][0] == "DC" else 2 elif version == "2.0": num_mirrors = table["num_mirrors"][mask][0] flen = table["equivalent_focal_length"][mask].quantity[0] optics = cls( name=name, num_mirrors=num_mirrors, equivalent_focal_length=flen, mirror_area=table["mirror_area"][mask].quantity[0], num_mirror_tiles=table["num_mirror_tiles"][mask][0], ) return optics
[docs] @classmethod def get_known_optics_names(cls, optics_table="optics"): """ return the list of optics names from ctapipe resources, i.e. those that can be constructed by name (this does not return the list of known names from an already open Monte-Carlo file) Parameters ---------- optics_table: str or astropy Table table where to read the optics description from. If a string, this is opened with `ctapipe.utils.get_table_dataset()` """ if isinstance(optics_table, str): table = get_table_dataset(optics_table, role="get_known_optics_names") else: table = optics_table return np.array(table["tel_description"])
def __repr__(self): return ( f"{self.__class__.__name__}" f"(name={self.name}" f", equivalent_focal_length={self.equivalent_focal_length:.2f}" f", num_mirrors={self.num_mirrors}" f", mirror_area={self.mirror_area:.2f}" ")" ) def __str__(self): return self.name