LSST Applications g00d0e8bbd7+edbf708997,g03191d30f7+9ce8016dbd,g1955dfad08+0bd186d245,g199a45376c+5137f08352,g1fd858c14a+a888a50aa2,g262e1987ae+45f9aba685,g29ae962dfc+1c7d47a24f,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3fd5ace14f+eed17d2c67,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+c4107e45b5,g67b6fd64d1+6dc8069a4c,g74acd417e5+f452e9c21a,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+2025e9ce17,g7cc15d900a+2d158402f9,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d4809ba88+c4107e45b5,g8d7436a09f+e96c132b44,g8ea07a8fe4+db21c37724,g98df359435+aae6d409c1,ga2180abaac+edbf708997,gac66b60396+966efe6077,gb632fb1845+88945a90f8,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gca7fc764a6+6dc8069a4c,gd7ef33dd92+6dc8069a4c,gda68eeecaf+7d1e613a8d,gdab6d2f7ff+f452e9c21a,gdbb4c4dda9+c4107e45b5,ge410e46f29+6dc8069a4c,ge41e95a9f2+c4107e45b5,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
factorized_component.py
Go to the documentation of this file.
1from __future__ import annotations
2
3from dataclasses import dataclass
4from typing import TYPE_CHECKING
5
6import numpy as np
7from numpy.typing import DTypeLike
8
9from ..bbox import Box
10from ..observation import Observation
11from ..parameters import FixedParameter
12from .component import ScarletComponentBaseData
13from .migration import PRE_SCHEMA, MigrationRegistry, migration
14
15if TYPE_CHECKING:
16 from ..component import FactorizedComponent
17
18__all__ = ["ScarletFactorizedComponentData"]
19
20CURRENT_SCHEMA = "1.0.0"
21COMPONENT_TYPE = "factorized"
22MigrationRegistry.set_current(COMPONENT_TYPE, CURRENT_SCHEMA)
23
24
25@dataclass(kw_only=True)
27 """Data for a factorized component
28
29 Attributes
30 ----------
31 component_type :
32 The type of component being stored.
33 origin :
34 The lower bound of the component's bounding box.
35 peak :
36 The ``(y, x)`` peak of the component.
37 spectrum :
38 The SED of the component.
39 morph :
40 The 2D morphology of the component.
41 version :
42 The schema version of the stored data.
43 """
44
45 component_type: str = COMPONENT_TYPE
46 origin: tuple[int, int]
47 peak: tuple[float, float]
48 spectrum: np.ndarray
49 morph: np.ndarray
50 version: str = CURRENT_SCHEMA
51
52 @property
53 def shape(self):
54 """The shape of the component's morphology"""
55 return self.morph.shape
56
57 def to_component(self, observation: Observation) -> FactorizedComponent:
58 """Convert the storage data model into a scarlet FactorizedComponent
59
60 Parameters
61 ----------
62 observation :
63 The observation that the component is associated with
64
65 Returns
66 -------
67 factorized_component :
68 A scarlet factorized component extracted from persisted data.
69 """
70 from ..component import FactorizedComponent
71
72 bbox = Box(self.shape, origin=self.origin)
73 spectrum = self.spectrum
74 morph = self.morph
75 if self.peak is None:
76 peak = None
77 else:
78 peak = (int(np.round(self.peak[0])), int(np.round(self.peak[1])))
79 assert peak is not None
80 # Note: since we aren't fitting a model, we don't need to
81 # set the RMS of the background.
82 # We set it to NaN just to be safe.
83 component = FactorizedComponent(
84 bands=observation.bands,
85 spectrum=FixedParameter(spectrum),
86 morph=FixedParameter(morph),
87 peak=peak,
88 bbox=bbox,
89 bg_rms=np.full((len(observation.bands),), np.nan),
90 )
91 return component
92
93 def as_dict(self) -> dict:
94 """Return the object encoded into a dict for JSON serialization
95
96 Returns
97 -------
98 result :
99 The object encoded as a JSON compatible dict
100 """
101 return {
102 "origin": tuple(int(o) for o in self.origin),
103 "shape": tuple(int(s) for s in self.morph.shape),
104 "peak": tuple(int(p) for p in self.peak),
105 "spectrum": tuple(self.spectrum.astype(float)),
106 "morph": tuple(self.morph.flatten().astype(float)),
107 "component_type": self.component_type,
108 "version": self.version,
109 }
110
111 @classmethod
112 def from_dict(cls, data: dict, dtype: DTypeLike = np.float32) -> ScarletFactorizedComponentData:
113 """Reconstruct `ScarletFactorizedComponentData` from JSON compatible
114 dict.
115
116 Parameters
117 ----------
118 data :
119 Dictionary representation of the object
120 dtype :
121 Datatype of the resulting model.
122
123 Returns
124 -------
125 result :
126 The reconstructed object
127 """
128 data = MigrationRegistry.migrate(COMPONENT_TYPE, data)
129 shape = tuple(data["shape"])
130 return cls(
131 origin=tuple(data["origin"]), # type: ignore
132 peak=data["peak"],
133 spectrum=np.array(data["spectrum"]).astype(dtype),
134 morph=np.array(data["morph"]).reshape(shape).astype(dtype),
135 )
136
137
138ScarletFactorizedComponentData.register()
139
140
141@migration(COMPONENT_TYPE, PRE_SCHEMA)
142def _to_1_0_0(data: dict) -> dict:
143 """Migrate a pre-schema factorized component to schema version 1.0.0
144
145 There were no changes to this data model in v1.0.0 but we need
146 to provide a way to migrate pre-schema data.
147
148 Parameters
149 ----------
150 data :
151 The data to migrate.
152
153 Returns
154 -------
155 result :
156 The migrated data.
157 """
158 data["version"] = "1.0.0"
159 return data
ScarletFactorizedComponentData from_dict(cls, dict data, DTypeLike dtype=np.float32)
FactorizedComponent to_component(self, Observation observation)