Source code for ctapipe.instrument.telescope
"""
Classes pertaining to the description of a Cherenkov Telescope
Todo:
-----
- add more info in OpticsDescription (mirror area, facets, etc). How to guess
this?
- add ability to write to/from tables (like that written by
ctapipe-dump-instrument)
- add ability to construct by names TelescopeDescription.from_name(
camera='LSTCam', optics=('SST','1M')) (which would create a very unbalanced
telescope :-))
"""
from ..coordinates import CameraFrame
from .camera import CameraDescription
from .guess import guess_telescope, unknown_telescope
from .optics import OpticsDescription
from .warnings import warn_from_name
__all__ = ["TelescopeDescription"]
[docs]
class TelescopeDescription:
"""
Describes a Cherenkov Telescope and its associated
`~ctapipe.instrument.OpticsDescription` and `~ctapipe.instrument.CameraDescription`
Attributes
----------
name: str
Telescope name
tel_type: str
Telescope type
optics: OpticsDescription
the optics associated with this telescope
camera: CameraDescription
the camera associated with this telescope
"""
__slots__ = (
"name",
"optics",
"camera",
)
def __init__(
self,
name: str,
optics: OpticsDescription,
camera: CameraDescription,
):
if not isinstance(name, str):
raise TypeError("`name` must be a str")
if not isinstance(optics, OpticsDescription):
raise TypeError("`optics` must be an instance of `OpticsDescription`")
if not isinstance(camera, CameraDescription):
raise TypeError("`camera` must be an instance of `CameraDescription`")
self.name = name
self.optics = optics
self.camera = camera
def __hash__(self):
"""Make this hashable, so it can be used as dict keys or in sets"""
return hash((self.optics, self.camera))
def __eq__(self, other):
return self.optics == other.optics and self.camera == other.camera
[docs]
@classmethod
def from_name(cls, optics_name, camera_name):
"""
construct a TelescopeDescription from a name (telescope description
string)
Parameters
----------
camera_name : str
camera name
optics_name : str
optics name (e.g. LST, or SST-ASTRI), also called
telescope_description
Notes
-----
Warning: This method loads a pre-generated ``TelescopeDescription`` and is
thus not guaranteed to be the same pixel ordering or even positions that
correspond with event data! Therefore if you are analysing data, you
should not rely on this method, but rather open the data with an
``EventSource`` and use the ``TelescopeDescription`` that is provided by
``source.subarray.tel[i]`` or by
``source.subarray.telescope_types[type_name]``. This will guarantee that
the pixels in the event data correspond with the ``TelescopeDescription``
Returns
-------
TelescopeDescription
"""
warn_from_name()
camera = CameraDescription.from_name(camera_name)
optics = OpticsDescription.from_name(optics_name)
camera.geometry.frame = CameraFrame(focal_length=optics.equivalent_focal_length)
try:
result = guess_telescope(
camera.geometry.n_pixels, optics.equivalent_focal_length
)
except ValueError:
result = unknown_telescope(optics.mirror_area, camera.geometry.n_pixels)
return cls(name=result.name, optics=optics, camera=camera)
@property
def camera_name(self):
"""Name of the camera"""
return self.camera.name
@property
def optics_name(self):
"""Name of the optics"""
return self.optics.name
@property
def type(self):
"""Size classification"""
return self.optics.size_type
def __str__(self):
return f"{self.type}_{self.optics_name}_{self.camera_name}"
def __repr__(self):
return (
f"{self.__class__.__name__}("
f"type={self.type.value!r}"
f", optics_name={self.optics_name!r}"
f", camera_name={self.camera_name!r}"
")"
)