Coverage for middle_layer/allocate/domain_layer/entities/allocated_reference_target.py: 84.44%
45 statements
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
1# Copyright 2024 Associated Universities, Inc.
2#
3# This file is part of Telescope Time Allocation Tools (TTAT).
4#
5# TTAT is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# any later version.
9#
10# TTAT is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with TTAT. If not, see <https://www.gnu.org/licenses/>.
17#
18from typing import TYPE_CHECKING, override
20import astropy.units as u
21from astropy.coordinates import SkyCoord
22from astropy.units import Quantity
23from sqlalchemy import Enum as SAEnum
24from sqlalchemy import ForeignKey
25from sqlalchemy.orm import Mapped, mapped_column, relationship
27from common.application_layer.orm_repositories.orm_types import QuantitySeconds
28from common.domain_layer import JSON
29from common.domain_layer.entities.base import Base
30from propose.domain_layer.entities import HasSkyCoord
31from propose.domain_layer.entities.hardware_configuration import HardwareConfiguration
32from propose.domain_layer.entities.reference_target import ReferenceTarget
33from propose.domain_layer.entities.scan import ScanIntent, Subscan
34from propose.domain_layer.entities.source import Source
36if TYPE_CHECKING:
37 from allocate.domain_layer.entities.allocation_disposition import AllocationDisposition
40time = u.get_physical_type("time")
43class AllocatedReferenceTarget(Base, HasSkyCoord):
44 __tablename__ = "allocated_reference_targets"
46 allocated_reference_target_id: Mapped[int] = mapped_column(primary_key=True)
48 source_id: Mapped[int] = mapped_column(ForeignKey("sources.source_id"), nullable=False)
49 source: Mapped[Source] = relationship(Source)
51 hardware_configuration_id: Mapped[int] = mapped_column(
52 ForeignKey("hardware_configurations.hardware_configuration_id"), nullable=False
53 )
54 hardware_configuration: Mapped[HardwareConfiguration] = relationship()
56 requested_time: Mapped[Quantity["time"]] = mapped_column(QuantitySeconds, nullable=False, default=0 * u.s)
57 # intent_name: Mapped[str] = mapped_column("intent", ForeignKey("scan_intents.name"), nullable=False)
58 intent_name: Mapped[str] = mapped_column(ForeignKey("scan_intents.name"), nullable=False)
60 intent: Mapped[ScanIntent] = relationship()
61 subscans: Mapped[list["Subscan"]] = relationship("Subscan", back_populates="allocated_reference_target")
63 # The remaining columns here are unique to the AST and not copied from the ST
64 allocation_disposition_id: Mapped[int] = mapped_column(
65 ForeignKey("allocation_dispositions.allocation_disposition_id", ondelete="CASCADE"),
66 nullable=False,
67 )
68 allocation_disposition: Mapped["AllocationDisposition"] = relationship(
69 "AllocationDisposition", back_populates="allocated_reference_targets"
70 )
72 def __json__(self) -> JSON:
73 overrides: JSON = {
74 "source": self.source.__json__() if self.source else None,
75 "hardwareConfiguration": self.hardware_configuration.__json__() if self.hardware_configuration else None,
76 "intent": self.intent.__json__() if self.intent else None,
77 }
78 return super().__json__() | overrides
80 def __eq__(self, other: object) -> bool:
81 return isinstance(other, AllocatedReferenceTarget) and (
82 self.source,
83 self.hardware_configuration,
84 self.requested_time,
85 self.intent_name,
86 ) == (
87 other.source,
88 other.hardware_configuration,
89 other.requested_time,
90 other.intent_name,
91 )
93 def clone(self) -> "AllocatedReferenceTarget":
94 return AllocatedReferenceTarget(
95 source=self.source.clone(),
96 hardware_configuration=self.hardware_configuration.clone(),
97 requested_time=self.requested_time,
98 intent_name=self.intent_name,
99 )
101 @classmethod
102 def from_reference_target(
103 cls: type["AllocatedReferenceTarget"], original: ReferenceTarget, ad: "AllocationDisposition"
104 ) -> "AllocatedReferenceTarget":
105 return cls(
106 source=original.source.clone(),
107 hardware_configuration=original.hardware_configuration.clone(),
108 requested_time=original.requested_time,
109 intent_name=original.intent_name,
110 intent=original.intent,
111 allocation_disposition=ad,
112 )
114 @property
115 @override
116 def sky_coord(self) -> SkyCoord:
117 return SkyCoord(ra=self.long * u.deg, dec=self.lat * u.deg)