from typing import List
from pydantic.dataclasses import dataclass
from ska_oso_pdm._shared.target import (
EquatorialCoordinates,
FivePointParameters,
PointingKind,
PointingPattern,
)
from ska_oso_pdm._shared.target import SolarSystemObject as pdmSolarSystemObject
from ska_oso_pdm._shared.target import SolarSystemObjectName, Target
from ska_oso_pdm.builders.mccs_builder import MCCSAllocationBuilder
from ska_oso_pdm.builders.sb_builder import (
LowSBDefinitionBuilder,
MidSBDefinitionBuilder,
)
from ska_oso_pdm.builders.utils import (
DISH_ALLOCATION_ID,
add_scan_for_each_target,
target_id,
)
from ska_oso_pdm.sb_definition import DishAllocation, SBDefinition
@dataclass
class _TargetBase:
name: str
ra: str
dec: str
[docs]
@dataclass
class ICRSObject(_TargetBase):
"""
Specifies a target using ICRS coordinates.
:param name: Name of the object, will be used as the target ID
:param ra: Right ascension of the object
:param dec: Declination of the object
"""
[docs]
@dataclass
class ICRSObjectFivePoint(ICRSObject):
"""
*** NOTE: Not yet implemented, the current builders do not support five-point
observing patterns. ***
Specifies a target using ICRS coordinates using a five-point observing pattern.
:param name: Name of the object, will be used as the target ID
:param ra: Right ascension of the object
:param dec: Declination of the object
:param offset: Offset from the reference position
"""
offset: float
def __post_init__(self):
raise NotImplementedError(
"Five-point targets are not yet supported by the builders."
)
[docs]
@dataclass
class SolarSystemObject:
"""
Specifies a target using the Solar System Object name.
:param name: Name of the object, must be one of the predefined
PDM SolarSystemObjectName enumerations
"""
name: SolarSystemObjectName
[docs]
def mid_imaging_sb(
dishes: List[str] | None = None,
targets: List[ICRSObject | ICRSObjectFivePoint | SolarSystemObject] | None = None,
scan_duration: float | List[float] | None = None,
) -> SBDefinition:
"""
Creates an SBDefinition PDM object for SKA-Mid with a single scan and AA0.5-compatible
Dish and CSP set-ups by default. The default configuration can be modified by passing
in additional parameters.
:param dishes: A list of dish IDs to include in the receptor ID list for the SB.
:param targets: A list of targets for the observation. For each specified target, a
scan referencing the target ID is added to the SB.
:param scan_duration: Either a single value to set for all scans or multiple values
to specify different duration for each specified target. If multiple values are
specified, the number of values should match the number of specified targets.
"""
sbd_kwargs = dict(
targets=[_convert_target(target) for target in targets] if targets else None,
dish_allocations=(
DishAllocation(
dish_ids=frozenset(dishes), dish_allocation_id=DISH_ALLOCATION_ID
)
if dishes
else None
),
)
sb = MidSBDefinitionBuilder(
**{k: v for k, v in sbd_kwargs.items() if v is not None}
)
return add_scan_for_each_target(sb, scan_durations=scan_duration)
[docs]
def low_imaging_sb(
stations: List[int] | None = None,
targets: List[ICRSObject | SolarSystemObject] | None = None,
scan_duration: float | List[float] | None = None,
) -> SBDefinition:
"""
Creates an SBDefinition PDM object for SKA-Low with a single scan and
AA0.5-compatible MCCS and CSP set-ups by default. The default configuration
can be modified by passing in additional parameters.
:param stations: A list of integer station IDs to include in the MCCS allocation.
One aperture will be created for each station for subarray beam ID 1 with
'uniform' weighting key and sub-station ID 1.
:param targets: A list of targets for the observation. For each specified target, a
scan referencing the target ID is added to the SB.
:param scan_duration: Either a single value to set for all scans or multiple values
to specify different duration for each specified target. If multiple values are
specified, the number of values should match the number of specified targets.
"""
sbd_kwargs = dict(
targets=[_convert_target(target) for target in targets] if targets else None,
mccs_allocation=(
MCCSAllocationBuilder(stations=stations) if stations else None
),
)
sb = LowSBDefinitionBuilder(
**{k: v for k, v in sbd_kwargs.items() if v is not None}
)
return add_scan_for_each_target(sb, scan_durations=scan_duration)
def _convert_target(
target: ICRSObject | ICRSObjectFivePoint | SolarSystemObject,
) -> Target:
match target:
case ICRSObjectFivePoint():
return Target(
target_id=target_id(),
name=target.name,
reference_coordinate=EquatorialCoordinates(
ra=target.ra, dec=target.dec
),
pointing_pattern=PointingPattern(
active=PointingKind.FIVE_POINT,
parameters=[
FivePointParameters(offset_arcsec=target.offset),
],
),
)
case ICRSObject():
return Target(
target_id=target_id(),
name=target.name,
reference_coordinate=EquatorialCoordinates(
ra=target.ra, dec=target.dec
),
)
case SolarSystemObject():
return Target(
target_id=target_id(),
name=target.name,
reference_coordinate=pdmSolarSystemObject(
name=SolarSystemObjectName(target.name)
),
)
case _:
raise ValueError(f"Unknown target type: {target}")