# -*- 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 for base PST Simulator."""
from __future__ import annotations
import logging
from random import randint
from typing import Any, Dict, Generic, TypeVar, cast
from overrides import EnforceOverrides, final
from .monitor_data_handler import MonitorDataStore
DataStore = TypeVar("DataStore", bound=MonitorDataStore)
SubbandMonitorDataType = TypeVar("SubbandMonitorDataType")
[docs]class PstSimulator(EnforceOverrides, Generic[SubbandMonitorDataType, DataStore]):
"""
A base class for simulators used when the BEAM is in simulation mode.
A simulator class is needed for each subcomponent. This class
is generic over the subband monitoring data type and a monitoring
data store.
This is an abstract class and sub-classes of this are expected to
implement the :py:meth:`_update` method.
"""
def __init__(
self: PstSimulator,
*,
data_store: DataStore,
num_subbands: int | None = None,
logger: logging.Logger | None = None,
**kwargs: Any,
) -> None:
"""Initialise the base PST simulator.
:param data_store: the data store to use within the base simulator
:type data_store: DataStore
:param num_subbands: number of subbands, if None a random number is used.
:type num_subbands: int
:param logger: the logger to use within the simulator, defaults to None
:type logger: logging.Logger | None, optional
"""
self.num_subbands = num_subbands if num_subbands else randint(1, 4)
self.logger = logger or logging.getLogger(__name__)
self._scan = False
self._data_store = data_store
@final
def deconfigure_scan(self: PstSimulator) -> None:
"""Simulate deconfiguring of a scan."""
self._scan = False
@final
def start_scan(self: PstSimulator, **kwargs: Any) -> None:
"""
Simulate start scanning.
:param: the scan arguments.
"""
self._scan = True
@final
def stop_scan(self: PstSimulator) -> None:
"""Simulate stop scanning."""
self._scan = False
@final
def abort(self: PstSimulator) -> None:
"""Tell the component to abort whatever it was doing."""
self._scan = False
def _update(self: PstSimulator) -> None:
"""Simulate the update of monitoring data."""
raise NotImplementedError("PstSimulator is abstract")
@final
def get_subband_data(self: PstSimulator) -> Dict[int, SubbandMonitorDataType]:
"""Get simulated subband data."""
if self._scan:
self._update()
return {**cast(MonitorDataStore, self._data_store)._subband_data}
[docs] def get_env(self: PstSimulator) -> dict:
"""Get the simulated environment variables."""
return {}