# -*- 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.
"""This module provides an implementation of the STAT PST component manager."""
from __future__ import annotations
import logging
from typing import Any
from overrides import override
from ska_pst.lmc.component import PstProcessApiSubcomponentManager
from ska_pst.lmc.stat.stat_model import StatMonitorData, StatMonitorDataStore
from ska_pst.lmc.stat.stat_process_api import (
PstStatProcessApi,
PstStatProcessApiGrpc,
PstStatProcessApiSimulator,
)
from ska_pst.lmc.stat.stat_util import calculate_stat_subband_resources
__all__ = ["PstStatComponentManager"]
[docs]class PstStatComponentManager(
PstProcessApiSubcomponentManager[
StatMonitorData, StatMonitorData, PstStatProcessApi, StatMonitorDataStore
]
):
"""Component manager for the STAT component for the PST.LMC subsystem."""
def __init__(
self: PstStatComponentManager,
*,
device_name: str,
process_api_endpoint: str,
api: PstStatProcessApi | None = None,
logger: logging.Logger | None = None,
**kwargs: Any,
):
"""
Initialise instance of the component manager.
:param device_interface: an abstract interface of the TANGO device.
:type device_interface: PstApiDeviceInterface[StatMonitorData]
:param api: an API object used to delegate functionality to.
:type api: `PstProcessApi`
:param logger: a logger for this object to use
:type logger: `logging.Logger`
"""
logger = logger or logging.getLogger(__name__)
logger.debug(
f"Setting up STAT component manager with device_name='{device_name}'"
+ f"and api_endpoint='{process_api_endpoint}'"
)
api = api or PstStatProcessApiSimulator(
logger=logger,
)
super().__init__(
device_name=device_name,
subcomponent_name="stat",
process_api_endpoint=process_api_endpoint,
api=api,
logger=logger,
data_store=StatMonitorDataStore(),
**kwargs,
)
@property
def real_pol_a_mean_freq_avg(self: PstStatComponentManager) -> float:
"""Get the mean of the real data for pol A, averaged over all channels."""
return self.monitor_data.real_pol_a_mean_freq_avg
@property
def real_pol_a_variance_freq_avg(self: PstStatComponentManager) -> float:
"""Get the variance of the real data for pol A, averaged over all channels."""
return self.monitor_data.real_pol_a_variance_freq_avg
@property
def real_pol_a_num_clipped_samples(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the real data for pol A."""
return self.monitor_data.real_pol_a_num_clipped_samples
@property
def imag_pol_a_mean_freq_avg(self: PstStatComponentManager) -> float:
"""Get the mean of the imaginary data for pol A, averaged over all channels."""
return self.monitor_data.imag_pol_a_mean_freq_avg
@property
def imag_pol_a_variance_freq_avg(self: PstStatComponentManager) -> float:
"""Get the variance of the imaginary data for pol A, averaged over all channels."""
return self.monitor_data.imag_pol_a_variance_freq_avg
@property
def imag_pol_a_num_clipped_samples(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the imaginary data for pol A."""
return self.monitor_data.imag_pol_a_num_clipped_samples
@property
def real_pol_a_mean_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the mean of the real data for pol A, averaged over channels not flagged for RFI."""
return self.monitor_data.real_pol_a_mean_freq_avg_rfi_excised
@property
def real_pol_a_variance_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the variance of the real data for pol A, averaged over channels not flagged for RFI."""
return self.monitor_data.real_pol_a_variance_freq_avg_rfi_excised
@property
def real_pol_a_num_clipped_samples_rfi_excised(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the real data for pol A in channels not flagged for RFI."""
return self.monitor_data.real_pol_a_num_clipped_samples_rfi_excised
@property
def imag_pol_a_mean_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the mean of the imaginary data for pol A, averaged over channels not flagged for RFI."""
return self.monitor_data.imag_pol_a_mean_freq_avg_rfi_excised
@property
def imag_pol_a_variance_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the variance of the imaginary data for pol A, averaged over channels not flagged for RFI."""
return self.monitor_data.imag_pol_a_variance_freq_avg_rfi_excised
@property
def imag_pol_a_num_clipped_samples_rfi_excised(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the imaginary data for pol A in channels not flagged for RFI."""
return self.monitor_data.imag_pol_a_num_clipped_samples_rfi_excised
@property
def real_pol_b_mean_freq_avg(self: PstStatComponentManager) -> float:
"""Get the mean of the real data for pol B, averaged over all channels."""
return self.monitor_data.real_pol_b_mean_freq_avg
@property
def real_pol_b_variance_freq_avg(self: PstStatComponentManager) -> float:
"""Get the variance of the real data for pol B, averaged over all channels."""
return self.monitor_data.real_pol_b_variance_freq_avg
@property
def real_pol_b_num_clipped_samples(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the real data for pol B."""
return self.monitor_data.real_pol_b_num_clipped_samples
@property
def imag_pol_b_mean_freq_avg(self: PstStatComponentManager) -> float:
"""Get the mean of the imaginary data for pol B, averaged over all channels."""
return self.monitor_data.imag_pol_b_mean_freq_avg
@property
def imag_pol_b_variance_freq_avg(self: PstStatComponentManager) -> float:
"""Get the variance of the imaginary data for pol B, averaged over all channels."""
return self.monitor_data.imag_pol_b_variance_freq_avg
@property
def imag_pol_b_num_clipped_samples(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the imaginary data for pol B."""
return self.monitor_data.imag_pol_b_num_clipped_samples
@property
def real_pol_b_mean_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the mean of the real data for pol B, averaged over channels not flagged for RFI."""
return self.monitor_data.real_pol_b_mean_freq_avg_rfi_excised
@property
def real_pol_b_variance_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the variance of the real data for pol B, averaged over channels not flagged for RFI."""
return self.monitor_data.real_pol_b_variance_freq_avg_rfi_excised
@property
def real_pol_b_num_clipped_samples_rfi_excised(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the real data for pol B in channels not flagged for RFI."""
return self.monitor_data.real_pol_b_num_clipped_samples_rfi_excised
@property
def imag_pol_b_mean_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the mean of the imaginary data for pol B, averaged over channels not flagged for RFI."""
return self.monitor_data.imag_pol_b_mean_freq_avg_rfi_excised
@property
def imag_pol_b_variance_freq_avg_rfi_excised(self: PstStatComponentManager) -> float:
"""Get the variance of the imaginary data for pol B, averaged over channels not flagged for RFI."""
return self.monitor_data.imag_pol_b_variance_freq_avg_rfi_excised
@property
def imag_pol_b_num_clipped_samples_rfi_excised(self: PstStatComponentManager) -> int:
"""Get the num of clipped samples of the imaginary data for pol B in channels not flagged for RFI."""
return self.monitor_data.imag_pol_b_num_clipped_samples_rfi_excised
@override
def _simulator_api(self: PstStatComponentManager) -> PstStatProcessApi:
"""Get instance of the simulator API."""
self.logger.debug("STAT component manager setting up simulated API")
return PstStatProcessApiSimulator(
logger=self.logger,
)
@override
def _grpc_api(self: PstStatComponentManager) -> PstStatProcessApi:
"""Get instance of a gRPC API."""
self.logger.debug("STAT component manager setting up gRPC API")
return PstStatProcessApiGrpc(
client_id=self.subcomponent_id,
grpc_endpoint=self.process_api_endpoint,
logger=self.logger,
)
@override
def validate_configure_scan(self: PstStatComponentManager, configuration: dict) -> None:
"""
Validate a ConfigureScan request sent from CSP.LMC to the STAT sub-component.
This asserts the request can be converted to STAT resources and then calls the process API to perform
the validation.
:param configuration: configuration that would be used when the configure_beam and configure_scan
methods are called.
:type configuration: dict
"""
stat_resources = calculate_stat_subband_resources(beam_id=self.beam_id, **configuration)
self._api.validate_configure_beam(configuration=stat_resources[1])
self._api.validate_configure_scan(configuration=configuration)
@override
def _configure_beam(self: PstStatComponentManager, configuration: dict) -> None:
"""
Configure beam resources in the component.
:param configuration: configuration for beam
:type configuration: dict
"""
stat_resources = calculate_stat_subband_resources(beam_id=self.beam_id, **configuration)
# deal only with subband 1 for now.
self.logger.debug(f"Submitting API with stat_resources={stat_resources[1]}")
self._api.configure_beam(configuration=stat_resources[1])