# -*- coding: utf-8 -*-
#
# This file is part of the SKA PST project
#
# Distributed under the terms of the BSD 3-clause new license.
# See LICENSE for more info.
"""
Module is designed to be an abstraction for getting telescope specific configuration.
Current implementation uses a configuration file but the ``get_telescope_config``
can but reimplemented to get configuration for the SKA Telemodel or other sources.
The configuration also includes the CBF/PST configuration values that are specific
for different frequency bands.
"""
from __future__ import annotations
import dataclasses
import pathlib
from typing import Any, Dict, List
import yaml
from dacite import from_dict
from ska_pst.common.constants import SKA_PST_LOW_SUBSYSTEM_ID, SKA_PST_SUBSYSTEM_IDS
from .cbf_pst_config import CbfPstConfig
__all__ = [
"TelescopeConfig",
"FrequencyBandConfig",
"ReceiverConfig",
]
[docs]@dataclasses.dataclass(kw_only=True, frozen=True)
class TelescopeConfig:
"""A data class used to model telescope specific configuration used by PST."""
name: str
"""
The name of the telescope.
This should be either ``SKALow`` or ``SKAMid``.
"""
frequency_bands: Dict[str, FrequencyBandConfig] = dataclasses.field(default_factory=dict)
"""
Configuration specific to the frequency bands for a given telescope.
For SKALow there is only 1 frequency band, "low", while SKAMid has multiple frequency bands.
The configuration that should be used for a given scan request will depend on what
telescope the scan is for and the frequency band if the telescope is SKAMid.
"""
[docs] def get_cbf_pst_config(
self: TelescopeConfig, frequency_band: str | None = None, **kwargs: Any
) -> CbfPstConfig:
"""
Get the configuration specific for a frequency band.
This will return the configuration that is specific to a frequency band.
The standard for SKA is that if the frequency_band is not set or is "low"
then it corresponds to the Low telescope, which has only one band. Frequency
bands of 1, 2, 3, 4, 5a, or 5b will return specific configuration.
:param frequency_band: the frequency band to get configuration for, defaults to None
:type frequency_band: str | None, optional
:return: configuration for the frequency band.
:rtype: CbfPstConfig
"""
frequency_band = frequency_band or "low"
return self.frequency_bands[frequency_band].cbf_pst_config
[docs]@dataclasses.dataclass(kw_only=True, frozen=True)
class FrequencyBandConfig:
"""A data class used to model specific configuration for a given frequency band."""
receiver_config: ReceiverConfig
"""Configuration specific to the receiver for a given frequency band."""
cbf_pst_config: CbfPstConfig
"""Configuration specific to the CBF/PST interface for a given frequency band."""
[docs]@dataclasses.dataclass(kw_only=True, frozen=True)
class ReceiverConfig:
"""A data class used to model specific configuration of a receiver."""
receiver_id: str
"""
The name/id of the receiver.
This value should match the ``receiver_id`` in the CSP/PST scan configuration.
"""
feed_polarization: str
"""The native polarisation of the feed for the receiver."""
feed_handedness: int
"""
The handedness of the feed of the receiver.
For value of +1 for XYZ forming RH set with Z in the direction of propagation.
Looking up into the feed of a prime-focus receiver or at the sky).
For FD_HAND = +1, the rotation from A (or X) to B (or Y) is counter clockwise
or in the direction of increasing Feed Angle (FA) or Position Angle (PA).
For circular feeds, FD_HAND = +1 for IEEE LCP on the A (or X) probe.
"""
feed_angle: float
"""
The feed angle of the receiver.
Feed angle of the E-vector of the receiver for an equal in-phase response from
the A(X) and B(Y) probes, measured in the direction of increasing feed angle or
position angle (clockwise when looking down on a prime focus receiver).
"""
feed_tracking_mode: str
"""
The tracking mode for the feed of the receiver.
* FA - constant feed angle and that the feed stays fixed with respect to the
telescope's reference frame.
* CPA - the feed rotates to maintain a constant phase angle (i.e. it tracks
the variation of the parallactic angle.). When the coordinate mode is GALACTIC,
PA is with respect to Galactic north and similarly for coordinate mode ECLIPTIC
then PA is with respect to ecliptic north.
* SPA - the feed angle is held fixed at an angle such that the requested PA is
obtained at the mid-point of the observation.
* TPA - is only relevant for scan observations - the feed is rotated to maintain a
constant angle with respect to the scan direction.
"""
feed_position_angle: float
"""
The requested angle of feed reference.
For feed_mode = 'FA' this is respect to the telescope's reference frame (feed_angle = 0),
and for feed_mode = 'CPA' this is with respect to the celestial north (parallactic angle = 0)
or with respect to the Galactic north for coordinate_mode = 'GALACTIC'.
"""
def _load_telescope_configs() -> Dict[str, TelescopeConfig]:
file = pathlib.Path(__file__).parent / "telescope_config.yaml"
assert file.exists(), f"expected {file} to exist"
with open(file, "r") as f:
config: List[dict] = yaml.safe_load(f)
return {d["name"]: from_dict(data_class=TelescopeConfig, data=d) for d in config}
TELESCOPE_CONFIGS: Dict[str, TelescopeConfig] = _load_telescope_configs()
[docs]def get_telescope_config(telescope: str) -> TelescopeConfig:
"""
Get the telescope configuration for a given telescope.
:param telescope: the name of the telescope.
:type telescope: str
:return: the configuration specific to the telescope.
:rtype: TelescopeConfig
"""
return TELESCOPE_CONFIGS[telescope]
[docs]def get_telescope_config_by_pst_subsystem(subsystem_id: str) -> TelescopeConfig:
"""
Get the telescope configuration for a given PST subsystem.
This will map subsystem to to the corresponding SKA telescope and
then call ``get_telescope_config`` for the telescope.
:param subsystem_id: the PST subsystem to get the telescope configuration for.
:type subsystem_id: str
:return: the telescope configuration for a given PST subsystem.
:rtype: TelescopeConfig
"""
assert (
subsystem_id in SKA_PST_SUBSYSTEM_IDS
), f"expected '{subsystem_id}' to be in {SKA_PST_SUBSYSTEM_IDS}"
if subsystem_id == SKA_PST_LOW_SUBSYSTEM_ID:
return get_telescope_config("SKALow")
else:
return get_telescope_config("SKAMid")