Coverage for python / lsst / scarlet / lite / io / factorized_component.py: 62%
48 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 23:28 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 23:28 +0000
1from __future__ import annotations
3from dataclasses import dataclass
4from typing import TYPE_CHECKING
6import numpy as np
7from numpy.typing import DTypeLike
9from ..bbox import Box
10from ..observation import Observation
11from ..parameters import FixedParameter
12from .component import ScarletComponentBaseData
13from .migration import PRE_SCHEMA, MigrationRegistry, migration
15if TYPE_CHECKING:
16 from ..component import FactorizedComponent
18__all__ = ["ScarletFactorizedComponentData"]
20CURRENT_SCHEMA = "1.0.0"
21COMPONENT_TYPE = "factorized"
22MigrationRegistry.set_current(COMPONENT_TYPE, CURRENT_SCHEMA)
25@dataclass(kw_only=True)
26class ScarletFactorizedComponentData(ScarletComponentBaseData):
27 """Data for a factorized component
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 """
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
52 @property
53 def shape(self):
54 """The shape of the component's morphology"""
55 return self.morph.shape
57 def to_component(self, observation: Observation) -> FactorizedComponent:
58 """Convert the storage data model into a scarlet FactorizedComponent
60 Parameters
61 ----------
62 observation :
63 The observation that the component is associated with
65 Returns
66 -------
67 factorized_component :
68 A scarlet factorized component extracted from persisted data.
69 """
70 from ..component import FactorizedComponent
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
93 def as_dict(self) -> dict:
94 """Return the object encoded into a dict for JSON serialization
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 }
111 @classmethod
112 def from_dict(cls, data: dict, dtype: DTypeLike = np.float32) -> ScarletFactorizedComponentData:
113 """Reconstruct `ScarletFactorizedComponentData` from JSON compatible
114 dict.
116 Parameters
117 ----------
118 data :
119 Dictionary representation of the object
120 dtype :
121 Datatype of the resulting model.
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 )
138ScarletFactorizedComponentData.register()
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
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.
148 Parameters
149 ----------
150 data :
151 The data to migrate.
153 Returns
154 -------
155 result :
156 The migrated data.
157 """
158 data["version"] = "1.0.0"
159 return data