MC Model#

The array of imaging atmospheric Cherenkov telescopes is abstracted in the simulation model and divided into the following components:

  • [telescope_model] representing a telescope. Defined by its telescope name, allowing model parameters to be selected by telescope.

  • sub-elements of the telescope represented by the modules [mirrors] and [camera]

  • an array of telescopes (especially the telescope arrangement) represented by [array_model].

array_model#

Array model represents an observatory consisting of site, telescopes, and further devices.

class model.array_model.ArrayModel(model_version, label=None, site=None, layout_name=None, array_elements=None, calibration_device_types=None, overwrite_model_parameters=None, ignore_software_version=False, model_directory_subdir=None, model_reader=None, context=None)[source]#

Representation of an observatory consisting of site, telescopes, and further devices.

Parameters:
model_version: str

Model version.

label: str, optional

Instance label. Used for output file naming.

site: str, optional

Site name.

layout_name: str, optional

Layout name.

array_elements: Union[str, Path, List[str]], optional

Array element definitions (list of array element or path to file with the array element positions).

calibration_device_types: List[str], optional

List of calibration device types (e.g., ‘flat_fielding’) attached to each telescope.

overwrite_model_parameters: dict or str, optional

Dictionary with model parameters to overwrite, or file path to YAML file.

property config_file_path#

Return the path of the array config file for sim_telarray.

Returns:
Path

Path of the exported config file for sim_telarray.

export_all_simtel_config_files()[source]#

Export sim_telarray config file for the array and for each individual telescope.

Config files are exported into the output model directory.

export_array_elements_as_table(coordinate_system='ground', include_calibration_array_elements=False)[source]#

Export array elements positions to astropy table.

Parameters:
coordinate_system: str

Positions are exported in this coordinate system.

include_calibration_array_elements: bool

Include calibration array elements in output table.

Returns:
astropy.table.QTable

Astropy table with the array-elements layout information.

export_config_files(simulation_software='sim_telarray')[source]#

Export array and telescope configurations for selected software.

Parameters:
simulation_softwarestr

Registered configuration format.

export_sim_telarray_config_file()[source]#

Export sim_telarray configuration file for the array into the model directory.

export_simtel_telescope_config_files()[source]#

Export sim_telarray configuration files for all telescopes into the model directory.

get_config_directory()[source]#

Get the path of the array config directory for sim_telarray.

Returns:
Path

Path of the config directory path for sim_telarray.

initialize_seeds(zenith_angle=None, azimuth_angle=None)[source]#

Initialize sim_telarray seeds for instrument and shower simulations.

property number_of_telescopes#

Return the number of telescopes.

Returns:
int

Number of telescopes.

pack_model_files()[source]#

Pack all model files into a tar.gz archive.

Returns:
Path

Path of the packed model files archive.

print_telescope_list()[source]#

Print list of telescopes.

property site#

Return site.

Returns:
str

Site name.

to_simulation_metadata_dict()[source]#

Export the resolved array model as a compact metadata dictionary.

The export contains resolved parameter records and references, but never model-file contents or private runtime state.

Returns:
dict

JSON-compatible array model metadata.

calibration_model#

Definition and modeling of a calibration device.

class model.calibration_model.CalibrationModel(site, calibration_device_model_name, model_version, label=None, overwrite_model_parameter_dict=None, model_reader=None, model_directory=None, context=None)[source]#

CalibrationModel represents the MC model of an individual calibration device.

It provides functionality to read the required parameters from the simulation-model repository.

Parameters:
site: str

Site name (e.g., South or North).

calibration_device_model_name: str

Calibration device model name (ex. ILLS-01, ILLN-01, …).

model_version: str

Model version.

label: str, optional

Instance label. Important for output file naming.

overwrite_model_parameter_dict: dict, optional

Dictionary to overwrite model parameters with provided values.

model_directory: pathlib.Path or str, optional

Directory for generated model assets and sim_telarray configuration files.

illuminator_visibility#

Module for reading and parsing illuminator-telescope visibility tables.

class model.illuminator_visibility.IlluminatorTelescopeVisibility(visibility_data)[source]#

Reader and parser for illuminator-telescope visibility tables.

Parses visibility data defining which telescopes can be illuminated by each illuminator, accounting for shadowing, blocking, topography, and distance constraints.

The input is a list of structured records. Schema version 0.1.0 model records store the same data as a columns/rows mapping and are normalized before parsing. The record structure is:

[
    {"illuminator_id": "ILLN-01", "telescope_id": "LSTN-01", "visible": false},
    {"illuminator_id": "ILLN-01", "telescope_id": "MSTN-02", "visible": true},
]
Parameters:
visibility_datalist of dict

One record per illuminator-telescope combination.

Raises:
ValueError

If the data format is invalid or missing required columns.

get_telescopes()[source]#

Get list of all telescopes in the visibility table.

Returns:
list of str

List of telescope identifiers.

get_valid_pairs()[source]#

Get all valid illuminator-telescope pairs.

A pair is valid if the visibility value is True (telescope is illuminated and not shadowed/blocked).

Returns:
list of tuple

List of (illuminator_id, telescope_id) tuples for all valid pairs.

property n_telescopes#

Get the number of telescopes in the table.

property n_valid_pairs#

Get the total number of valid illuminator-telescope pairs.

camera#

Definition and modeling of camera.

class model.camera.Camera(telescope_name, camera_config_file, focal_length, camera_config_dict=None)[source]#

Camera class, defining pixel layout.

This includes rotation, finding neighbor pixels, calculating FoV and plotting the camera. Assume that all pixels have the same shape and size.

Parameters:
telescope_name: str

Telescope name (e.g., LSTN-01)

camera_config_file: str or Path

The sim_telarray camera configuration file.

focal_length: float

The focal length of the camera in (preferably the effective focal length), assumed to be in the same unit as the pixel positions in the camera_config_file, usually cm.

camera_config_dict: dict, optional

Dictionary (as provided by eventio) with camera configuration information. Used alternatively to camera_config_file, which is ignored when this is provided.

calc_fov()[source]#

Calculate the FOV of the camera in degrees, taking into account the focal length.

Returns:
fov: float

The FOV of the camera in the degrees.

average_edge_distance: float

The average edge distance of the camera.

Notes

The x,y pixel positions and focal length are assumed to have the same unit (usually cm)

classmethod from_configuration(telescope_name, configuration, focal_length)[source]#

Build a camera from resolved, validated component model parameters.

Parameters:
telescope_namestr

Telescope name.

configurationdict

Resolved camera components. The mapping contains rotate, pixel_types, pixels, triggers and trigger_members.

focal_lengthfloat

Camera focal length in the same unit as the layout positions.

get_camera_fill_factor()[source]#

Calculate the fill factor of the camera, defined as (pixel_diameter/pixel_spacing)**2.

Returns:
float

The camera fill factor.

get_edge_pixels(pixels=None, neighbors=None)[source]#

Get the indices of the edge pixels of the camera.

Parameters:
pixels: dict

The dictionary produced by the read_pixel_list method of this class.

neighbors: list of lists

Array of neighbor indices in a list for each pixel.

Returns:
edge_pixel_indices: list

Array of edge pixel indices.

get_neighbor_pixels(pixels=None)[source]#

Get a list of neighbor pixels by calling calc_neighbor_pixels() when necessary.

The purpose of this function is to ensure the calculation occurs only once and only when necessary.

Parameters:
pixels: dict

The dictionary produced by the read_pixel_list method of this class.

Returns:
neighbors: list of lists

Array of neighbor indices in a list for each pixel.

get_number_of_pixels()[source]#

Get the number of pixels in the camera (all pixels, including those defined as “off”).

Returns:
int

number of pixels.

get_pixel_active_solid_angle()[source]#

Get the active solid angle of a pixel in sr.

Returns:
float

active solid angle of a pixel in sr.

get_pixel_diameter()[source]#

Get pixel diameter contained in _pixels.

Returns:
float

Pixel diameter (usually in cm).

get_pixel_shape()[source]#

Get pixel shape code 1, 2 or 3.

Where 1 and 3 are hexagonal pixels, where one is rotated by 30 degrees with respect to the other. A square pixel is denoted as 2.

Returns:
int (1, 2 or 3)

Pixel shape.

static initialize_pixel_dict()[source]#

Initialize the pixel dictionary with default values.

Returns:
dict

A dictionary with default pixel properties.

static process_line(line, pixels)[source]#

Process a line from the camera config file and update the pixels dictionary.

Parameters:
line: str

A line from the camera config file.

pixels: dict

The dictionary to update with pixel information.

static read_pixel_list(camera_config_file)[source]#

Read the pixel layout from the camera config file, assumed to be in a sim_telarray format.

Parameters:
camera_config_file: str or Path

The sim_telarray file name.

Returns:
dict: pixels

A dictionary with the pixel positions, the camera rotation angle, the pixel shape, the pixel diameter, the pixel IDs and their “on” status.

Notes

The pixel shape can be hexagonal (denoted as 1 or 3) or a square (denoted as 2). The hexagonal shapes differ in their orientation, where those denoted as 3 are rotated clockwise by 30 degrees with respect to those denoted as 1.

static read_pixel_list_from_dict(camera_config_dict)[source]#

Read pixel list from pyeventio camera configuration dictionary.

Parameters:
camera_config_dict: dict

Dictionary (as provided by eventio) with camera configuration information.

Returns:
dict: pixels

A dictionary with the pixel positions, the camera rotation angle, the pixel shape, the pixel diameter, the pixel IDs and their “on” status.

static validate_pixels(pixels, camera_config_file)[source]#

Validate the pixel dictionary to ensure all required fields are present.

Parameters:
pixels: dict

The pixel dictionary to validate.

camera_config_file: string

The sim_telarray file name for error messages.

Raises:
ValueError

If the pixel diameter or pixel shape is invalid.

mirrors#

Definition and modeling of mirror panels.

exception model.mirrors.InvalidMirrorListFileError[source]#

Exception for invalid mirror list file.

class model.mirrors.Mirrors(mirror_list_file, parameters=None)[source]#

Mirrors class, created from a mirror list file.

Parameters:
mirror_list_file: Union[str, Path]

Mirror list in ECSV format (with panel focal length only).

parameters: dict, optional

Dictionary of parameters from the model repository.

get_single_mirror_parameters(number)[source]#

Get parameters for a single mirror given by number.

Parameters:
number: int

Mirror number of desired parameters.

Returns:
tuple

(pos_x, pos_y, mirror_diameter, focal_length, shape_type): tuple of float X, Y positions, mirror_diameter, focal length and shape_type.

plot_mirror_layout()[source]#

Plot the mirror layout (not implemented yet).

model.mirrors.uses_segmented_dual_mirror_geometry(parameters)[source]#

Return whether sim_telarray derives primary-mirror geometry from segmentation.

model_parameter#

Base class for simulation model parameters (e.g., for SiteModel or TelescopeModel).

exception model.model_parameter.InvalidModelParameterError[source]#

Exception for invalid model parameter.

class model.model_parameter.ModelParameter(model_version, site=None, array_element_name=None, collection='telescopes', label=None, overwrite_model_parameter_dict=None, ignore_software_version=False, model_reader=None, model_directory=None, parameter_names=None, load_simulation_software_parameters=True, context=None)[source]#

Base class for simulation model parameters.

Provides methods to read and manipulate parameters from the model repository. Writing of sim_telarray configuration files and model exports is done by the model writers (see simulation.configuration.get_model_writer).

Parameters:
model_version: str

Version of the model (ex. 5.0.0).

site: str

Site name (e.g., South or North).

array_element_name: str

Array element name (e.g., LSTN-01, LSTN-design, ILLN-01).

collection: str

instrument class (e.g. telescopes, calibration_devices) as stored under collection in the model repository.

label: str

Instance label. Used for output file naming.

overwrite_model_parameter_dict: dict, optional

Dictionary to overwrite model parameters from the model repository with provided values.

ignore_software_version: bool

If True, ignore software version checks for deprecated parameters. Useful for documentation generation.

model_directory: pathlib.Path or str, optional

Directory for generated model assets and sim_telarray configuration files.

parameter_names: iterable of str, optional

If supplied, load only these model parameters.

load_simulation_software_parameters: bool

If False, do not load CORSIKA and sim_telarray configuration parameters.

property config_file_directory#

Directory for configuration files. Configure if not yet set.

property config_file_path#

Path of the config file. Configure, if necessary.

get_parameter_table(par_name)[source]#

Return the validated ECSV table associated with a model parameter.

get_parameter_type(par_name)[source]#

Get the type of an existing model parameter (the type field).

Parameters:
par_name: str

Name of the parameter.

Returns:
str

type of the parameter

get_parameter_value(par_name)[source]#

Get the value of a model parameter.

List of values stored in strings are returns as lists, so that no knowledge of the model repository structure is needed when accessing the model parameters.

Parameters:
par_name: str

Name of the parameter.

Returns:
Value of the parameter.
Raises:
InvalidModelParameterError

If par_name does not match any parameter in this model.

get_parameter_value_with_unit(par_name)[source]#

Get the value of an existing parameter of the model as an Astropy Quantity with its unit.

Parameters:
par_name: str

Name of the parameter.

Returns:
Astropy quantity with the value of the parameter multiplied by its unit.
If no unit is provided in the model, the value is returned without a unit.
get_parameter_version(par_name)[source]#

Get version for a given parameter used in the model.

Parameters:
par_name: str

Name of the parameter.

Returns:
str

parameter version used in the model (eg. ‘1.0.0’)

get_simulation_software_parameters(simulation_software)[source]#

Get simulation software parameters.

Parameters:
simulation_software: str

Simulation software name.

Returns:
dict

Simulation software parameters.

overwrite_model_parameter(par_name, value, parameter_version=None, metadata=None)[source]#

Overwrite a parameter of this model in memory (the model repository is not modified).

If only the parameter version is given (value None), the parameter is taken from the model repository for that version.

Parameters:
par_name: str

Name of the parameter.

value:

New value for the parameter.

parameter_version: str, optional

New version for the parameter.

metadata: dict, optional

Additional metadata (unit, model_parameter_schema_version).

Raises:
InvalidModelParameterError

If the parameter to be changed does not exist in this model.

model_repository#

Utilities for managing the simulation models repository.

Verify production tables against model parameters, and generate new production tables and model parameters from the changes defined in info.yml.

model_repository.maintenance.generate_new_production(model_version, simulation_models_path, setting_workflows_git_tag=None, context=None)[source]#

Generate a new production definition (production tables and model parameters).

Production tables are copied from the base model version and updated with the changes in ‘info.yml’ (full or patch update). New model parameter entries are generated for the changed parameters.

Parameters:
model_version: str

Model version to be created or updated.

simulation_models_path: str

Path to the simulation models repository.

setting_workflows_git_tag: str, optional

Branch or tag used to download parameters from the simulation workflow repository. Overrides setting_workflows_git_tag from info.yml if given; defaults to "main" if neither is set.

contextRunContext, optional

Run configuration and model reader used to write model parameters.

model_repository.maintenance.get_model_parameter_file_path(simulation_models_path, array_element, parameter_name, parameter_version)[source]#

Get the file path for a model parameter.

Null-instrument parameters are stored below the explicit global scope.

Parameters:
simulation_models_pathstr

Path to the simulation models repository.

array_elementstr

Name of the array element (e.g., ‘telescope’), or None for a global parameter.

parameter_namestr

Name of the parameter.

parameter_versionstr

Version of the parameter.

Returns:
Path

The file path to the model parameter JSON file.

model_repository.maintenance.get_production_directory(simulation_models_path, model_version=None)[source]#

Get the production directory for a model version.

Parameters:
simulation_models_pathstr

Path to the simulation models repository.

model_versionstr, optional

Model version. If None, the productions root directory is returned.

Returns:
Path

Production directory.

model_repository.maintenance.initialize_production(simulation_models_path, model_version, base_model_version, update_type='patch_update')[source]#

Create an initial production info file based on an existing model version.

Parameters:
simulation_models_pathstr or Path

Path to the simulation models repository.

model_versionstr

Version to initialize.

base_model_versionstr

Existing production version used as the starting point.

update_typestr, optional

Production update type to write to the new info file.

Raises:
FileExistsError

If the target production directory already exists.

FileNotFoundError

If the base production info file does not exist.

ValueError

If the update type is not supported.

model_repository.maintenance.verify_simulation_model_production_tables(simulation_models_path)[source]#

Verify that all model parameters referenced by the production tables exist.

Parameters:
simulation_models_pathstr

Path to the simulation models repository.

Returns:
bool

True if all parameters found, False if any missing.

telescope sphere#

Derive a CORSIKA enclosure from the main optical telescope elements.

model.telescope_sphere.derive_telescope_sphere_radius(model, zenith_range=<Quantity [ 0., 90.] deg>, margin=<Quantity 0. m>)[source]#

Return a conservative CORSIKA entrance sphere radius for the model’s mirrors.

Parameters:
modelTelescopeModel

Simulation model with primary and optional secondary reflector geometry.

zenith_rangeastropy.units.Quantity, optional

Minimum and maximum telescope zenith angles.

marginastropy.units.Quantity, optional

Extra radial clearance.

Returns:
astropy.units.Quantity

Fiducial sphere radius in metres.

Raises:
ValueError

If required model geometry is missing or invalid.

model utilities#

Helper functions related to model parameters.

model.model_utils.compute_telescope_transmission(pars, off_axis)[source]#

Compute telescope transmission (0 < T < 1) for a given off-axis angle.

The telescope transmission depends on the MC model used.

Parameters:
pars: list of float

Parameters of the telescope transmission. Len(pars) should be 5 or 6.

off_axis: float

Off-axis angle in deg.

Returns:
float

Telescope transmission.

model.model_utils.get_array_elements_for_layout(layout_name, site=None, model_version=None, model_reader=None, context=None)[source]#

Get array elements for a given array layout.

Parameters:
layout_name: str

Name of the array layout.

site: str, optional

Site name (use central configuration if not provided).

model_version: str, optional

Model version (use central configuration if not provided).

Returns:
list

List of array elements for the given array layout.

model.model_utils.initialize_simulation_models(label, model_version, site, telescope_name, calibration_device_name=None, calibration_device_type=None, model_reader=None, model_directory=None, context=None)[source]#

Initialize simulation models for a single telescope, site, and calibration device model.

Parameters:
label: str

Label for the simulation.

model_version: str

Version of the simulation model

site: str

Name of the site.

telescope_name: str

Name of the telescope.

calibration_device_name: str, optional

Name of the calibration device.

calibration_device_type: str, optional

Type of the calibration device.

model_directory: pathlib.Path or str, optional

Directory for generated model assets and sim_telarray configuration files.

Returns:
Tuple

Tuple containing the telescope site, (optional) calibration device model.

model.model_utils.read_overwrite_model_parameter_dict(overwrite_model_parameters=None, context=None)[source]#

Read overwrite model parameters dictionary.

Parameters:
overwrite_model_parameters: dict or str, optional

Either a dictionary with model parameters to overwrite, or a file path.

Returns:
dict

Dictionary with model parameters to overwrite.

site_model#

Definition of site model.

class model.site_model.SiteModel(site, model_version, label=None, overwrite_model_parameter_dict=None, ignore_software_version=False, model_reader=None, context=None, model_directory=None, parameter_names=None, load_simulation_software_parameters=True)[source]#

Representation of an observatory site model.

The site model includes (among others):

  • Reference point coordinates

  • Array elements

  • Geomagnetic field parameters

  • Atmospheric parameters

  • NSB parameters

Parameters:
site: str

Site name (e.g., South or North).

model_version: str or list

Model version or list of model versions (in which case only the first one is used).

label: str, optional

Instance label.

overwrite_model_parameter_dict: dict, optional

Dictionary to overwrite model parameters from the model repository with provided values.

ignore_software_version: bool, optional

If True, ignore software version checks for deprecated parameters.

model_directory: pathlib.Path or str, optional

Directory for generated model assets and sim_telarray configuration files.

parameter_names: iterable of str, optional

If supplied, load only these site parameters.

load_simulation_software_parameters: bool

If False, do not load CORSIKA and sim_telarray configuration parameters.

export_atmospheric_transmission_file(model_directory)[source]#

Export the atmospheric profile source and sim_telarray table files.

Parameters:
model_directory: Path

Model directory to export the file to.

get_array_elements_for_layout(layout_name)[source]#

Return list of array elements for a given array layout.

If layout_name is not found in the model repository but is a valid, concrete telescope name (e.g., MSTN-05) belonging to this site, a single-telescope layout is returned automatically.

Parameters:
layout_name: str

Name of the array layout or a single telescope name (e.g., MSTN-05).

Returns:
list

List of array elements.

get_array_elements_of_type(array_element_type)[source]#

Get all array elements of a given type.

Parameters:
array_element_typestr

Type of the array element (e.g. LSTN, MSTS)

Returns:
list

List with array elements.

get_corsika_site_parameters(config_file_style=False, model_directory=None)[source]#

Get site-related CORSIKA parameters.

Parameters are returned with units wherever possible (‘config_file_style=False’) or in CORSIKA-expected coordinates.

Parameters:
config_file_style: bool

Return using CORSIKA config file syntax

model_directory: Path, optional

Model directory to use for file paths

Returns:
dict

Site-related CORSIKA parameters.

get_list_of_array_layouts()[source]#

Get list of available array layouts.

Returns:
list

List of available array layouts

get_nsb_integrated_flux(wavelength_min=<Quantity 300. nm>, wavelength_max=<Quantity 650. nm>)[source]#

Get the integrated flux for the NSB (Night Sky Background) model.

Returns:
float

Integrated flux value.

get_reference_point()[source]#

Get reference point coordinates.

Ground coordinates are calculated relative to this point.

Returns:
dict

Reference point coordinates.

telescope_model#

MC model of a telescope.

class model.telescope_model.TelescopeModel(site, telescope_name, model_version, label=None, overwrite_model_parameter_dict=None, ignore_software_version=False, model_reader=None, model_directory=None, context=None)[source]#

TelescopeModel represents the MC model of an individual telescope.

TelescopeModel contains parameter names and values for a specific telescope model.

Parameters:
site: str

Site name (e.g., South or North).

telescope_name: str

Telescope name (ex. LSTN-01, LSTN-design, …).

model_version: str

Model version.

label: str, optional

Instance label.

overwrite_model_parameter_dict: dict, optional

Dictionary to overwrite model parameters from the model repository with provided values.

ignore_software_version: bool, optional

If True, ignore software version checks for deprecated parameters.

model_directory: pathlib.Path or str, optional

Directory for generated model assets and sim_telarray configuration files.

property camera#

Load the camera information if the class instance hasn’t done it yet.

export_single_mirror_list_file(mirror_number, set_focal_length_to_zero)[source]#

Export a mirror list file with a single mirror in it.

Parameters:
mirror_number: int

Number index of the mirror.

set_focal_length_to_zero: bool

Set the focal length to zero if True.

get_calibration_device_name(device_type)[source]#

Get the calibration device name for this telescope.

Parameters:
device_type: str

Type of the calibration device (e.g., ‘flasher’, ‘illuminator’)

Returns:
str or None

Calibration device name or None if not defined.

get_on_axis_eff_optical_area()[source]#

Return the on-axis effective optical area (derived previously for this telescope).

get_single_mirror_list_file(mirror_number, set_focal_length_to_zero=False)[source]#

Get the path to the single mirror list file.

Parameters:
mirror_number: int

Mirror number.

set_focal_length_to_zero: bool

Flag to set the focal length to zero.

Returns:
Path

Path of the single mirror list file.

get_telescope_effective_focal_length(unit='m', return_focal_length_if_zero=False)[source]#

Return effective focal length.

The function ensures backwards compatibility with older sim-telarray versions.

Parameters:
unit: str

Unit of the effective focal length. Default is ‘m’.

return_focal_length_if_zero: bool

If True, return the focal length if the effective focal length is 0.

Returns:
float:

Effective focal length.

property mirrors#

Load the mirror information if the class instance hasn’t done it yet.

position(coordinate_system='ground')[source]#

Get coordinates in the given system.

Parameters:
coordinate_system: str

Coordinates system. Default is ‘ground’.

Returns:
list

List of telescope position in the requested coordinate system.

Raises:
KeyError

If the coordinate system is not found.

telescope_geometry#

Nominal optical geometry derived from telescope model data.

class model.telescope_geometry.Element(name, group, points, diameter=0.0, kind='polygon', side_only=False)[source]#

Element of the telescope in its frame, with positions in metres.

A cylinder has two points (the end points of its axis) and a diameter. A polygon is given by its corners (a mirror aperture, a camera plate, or the corners of a structure element whose convex hull is drawn). A wire is drawn as its polylines.

property is_cylinder#

Whether the element is a cylinder.

class model.telescope_geometry.TelescopeGeometry(name, mirrors=<factory>, camera=<factory>, structure=<factory>)[source]#

Elements to draw: mirrors, camera housing and telescope structure.

model.telescope_geometry.telescope_geometry(tel_model)[source]#

Nominal geometry of a telescope model, for plotting.

Parameters:
tel_model: TelescopeModel

Telescope model with exported model files (model_reader.export_model_files).

Returns:
TelescopeGeometry

Mirrors (facets, or the apertures of a dual-mirror telescope), camera housing, and telescope structure (empty if the model has none).