Coverage for tests / utils.py: 26%
52 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-06 08:46 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-06 08:46 +0000
1# This file is part of meas_extensions_scarlet.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22from typing import Sequence
24import lsst.scarlet.lite as scl
25import numpy as np
26import lsst.meas.extensions.scarlet as mes
29class DeblenderTestModel:
30 center: tuple[float, float]
31 spectrum: np.ndarray
32 morph: np.ndarray
33 bbox: scl.Box
34 bands: Sequence[str]
36 def render(self, psf: np.ndarray) -> scl.Image:
37 model = self.spectrum[:, None, None]*self.morph[None, :, :]
38 if len(psf.shape) == 2:
39 psf = np.repeat(psf[None, :, :], model.shape[0], axis=0)
40 model = mes.utils.multiband_convolve(model, psf)
41 return scl.Image(model, bands=self.bands, yx0=self.bbox.origin)
44class SersicModel(DeblenderTestModel):
45 def __init__(
46 self,
47 center: tuple[int, int],
48 major: float,
49 minor: float,
50 radius: int,
51 theta: float,
52 n: float,
53 spectrum: np.ndarray,
54 bands: Sequence[str],
55 ):
56 self.center = center
57 self.spectrum = spectrum.astype(np.float32)
58 self.bands = bands
59 bbox = scl.Box((2*radius+1, 2*radius+1), (center[0]-radius, center[1]-radius))
60 self.bbox = bbox
61 frame = scl.models.parametric.EllipseFrame(
62 center[0],
63 center[1],
64 major,
65 minor,
66 theta,
67 bbox,
68 )
69 morph = scl.models.parametric.sersic((n,), frame).astype(np.float32)
70 self.morph = morph/np.max(morph)
73class PsfModel(DeblenderTestModel):
74 def __init__(
75 self,
76 center,
77 spectrum: np.ndarray,
78 bands: Sequence[str],
79 radius: int = 7,
80 ):
81 self.center = center
82 self.spectrum = spectrum.astype(np.float32)
83 self.bands = bands
84 bbox = scl.Box((2*radius+1, 2*radius+1), (center[0]-radius, center[1]-radius))
85 self.bbox = bbox
86 self.morph = np.zeros(bbox.shape, dtype=np.float32)
87 _center = (self.morph.shape[0]-1)//2, (self.morph.shape[1]-1)//2
88 self.morph[*_center] = 1
91def initData(
92 models: list[DeblenderTestModel],
93 modelPsf: np.ndarray,
94 imagePsf: np.ndarray,
95) -> tuple[scl.Image, scl.Image]:
96 # Find the bounding box that contains all of the models
97 bbox = models[0].bbox
98 bands = models[0].bands
99 for model in models[1:]:
100 bbox = bbox | model.bbox
101 assert bands == model.bands
102 bbox = bbox.grow(5)
104 for dim in bbox.origin:
105 if dim < 0:
106 raise ValueError("Invalid setup, at least one source has a footprint below (0, 0)")
108 deconvolved = scl.Image.from_box(bbox, bands=bands, dtype=modelPsf.dtype)
109 convolved = scl.Image.from_box(bbox, bands=bands, dtype=imagePsf.dtype)
110 for model in models:
111 deconvolved += model.render(modelPsf)
112 convolved += model.render(imagePsf)
113 return deconvolved, convolved