Coverage for python/lsst/cell_coadds/_single_cell_coadd.py: 52%

57 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-10-09 04:19 -0700

1# This file is part of cell_coadds. 

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/>. 

21 

22from __future__ import annotations 

23 

24__all__ = ("SingleCellCoadd",) 

25 

26from collections.abc import Iterable, Set 

27from typing import TYPE_CHECKING 

28 

29from lsst.afw.image import ImageD, ImageF 

30from lsst.geom import Box2I 

31 

32from ._coadd_ap_corr_map import EMPTY_AP_CORR_MAP 

33from ._common_components import CommonComponents, CommonComponentsProperties 

34from ._image_planes import ViewImagePlanes 

35from .typing_helpers import ImageLike, SingleCellCoaddApCorrMap 

36 

37if TYPE_CHECKING: 37 ↛ 38line 37 didn't jump to line 38 because the condition on line 37 was never true

38 from ._identifiers import CellIdentifiers, ObservationIdentifiers 

39 from ._image_planes import ImagePlanes, OwnedImagePlanes 

40 

41 

42class SingleCellCoadd(CommonComponentsProperties): 

43 """A single coadd cell, built only from input images that completely 

44 overlap that cell. 

45 

46 Parameters 

47 ---------- 

48 outer : `OwnedImagePlanes` 

49 The actual coadded images. 

50 psf : `ImageD` 

51 The coadded PSF image. 

52 inner_bbox : `Box2I` 

53 The bounding box of the inner region of this cell; must be disjoint 

54 with but adjacent to all other cell inner regions. 

55 inputs : `Iterable` [`ObservationIdentifiers`] 

56 Identifiers of observations that contributed to this cell. 

57 common : `CommonComponents` 

58 Image attributes common to all cells in a patch. 

59 identifiers : `CellIdentifiers` 

60 Struct of identifiers for this cell. 

61 aperture_correction_map : `frozendict` [`str`, `float`], optional 

62 Mapping of algorithm name to aperture correction value for this cell. 

63 

64 Notes 

65 ----- 

66 At present we assume a single PSF image per cell is sufficient to capture 

67 spatial variability, which seems adequate given the results we have so far 

68 and the cell sizes we intend to use. 

69 """ 

70 

71 def __init__( 

72 self, 

73 outer: OwnedImagePlanes, 

74 *, 

75 psf: ImageD, 

76 inner_bbox: Box2I, 

77 inputs: Iterable[ObservationIdentifiers], 

78 common: CommonComponents, 

79 identifiers: CellIdentifiers, 

80 aperture_correction_map: SingleCellCoaddApCorrMap = EMPTY_AP_CORR_MAP, 

81 ): 

82 assert outer.bbox.contains( 

83 inner_bbox 

84 ), f"Cell inner bbox {inner_bbox} is not contained by outer bbox {outer.bbox}." 

85 self._outer = outer 

86 self._psf = psf 

87 self._inner_bbox = inner_bbox 

88 self._inner = ViewImagePlanes(outer, bbox=inner_bbox, make_view=self.make_view) 

89 self._common = common 

90 # Remove any duplicate elements in the input, sorted them and make 

91 # them an immutable sequence. 

92 # TODO: Remove support for inputs as None when bumping to v1.0 . 

93 self._inputs = tuple(sorted(set(inputs))) if inputs else () 

94 self._identifiers = identifiers 

95 self._aperture_correction_map = aperture_correction_map 

96 

97 @property 

98 def inner(self) -> ImagePlanes: 

99 """Image planes within the inner region of this cell that is disjoint 

100 with all other cell inner regions. 

101 """ 

102 return self._inner 

103 

104 @property 

105 def outer(self) -> ImagePlanes: 

106 """Image planes within the full outer region of this cell.""" 

107 return self._outer 

108 

109 @property 

110 def psf_image(self) -> ImageF: 

111 """The coadded PSF image.""" 

112 return self._psf 

113 

114 @property 

115 # TODO: Remove the option of returning empty tuple in v1.0. 

116 def inputs(self) -> tuple[ObservationIdentifiers, ...] | tuple[()]: 

117 """Identifiers for the input images that contributed to this cell, 

118 sorted by their `visit` attribute first, and then by `detector`. 

119 """ 

120 return self._inputs 

121 

122 @property 

123 def visit_count(self) -> int: 

124 """Number of visits that contributed to this cell.""" 

125 return len(self.inputs) 

126 

127 @property 

128 def identifiers(self) -> CellIdentifiers: 

129 """Struct of unique identifiers for this cell.""" 

130 # This overrides the patch-level property from 

131 # CommonComponentsProperties to provide cell-level information. 

132 return self._identifiers 

133 

134 @property 

135 def common(self) -> CommonComponents: 

136 # Docstring inherited. 

137 return self._common 

138 

139 @property 

140 def aperture_correction_map(self) -> SingleCellCoaddApCorrMap: 

141 """Mapping of algorithm name to aperture correction values. 

142 

143 Returns 

144 ------- 

145 aperture_correction_map : `frozendict` [`str`, float] 

146 Mapping of algorithm name to aperture correction values. 

147 """ 

148 return self._aperture_correction_map 

149 

150 @property 

151 def aperture_corrected_algorithms(self) -> Set[str]: 

152 """An iterable of algorithm names that have aperture correction values. 

153 

154 Returns 

155 ------- 

156 aperture_corrected_algorithms : `tuple` [`str`, ...] 

157 List of algorithms that have aperture correction values. 

158 """ 

159 if self._aperture_correction_map: 

160 return self._aperture_correction_map.keys() 

161 

162 return set() 

163 

164 def make_view(self, image: ImageLike, bbox: Box2I | None = None) -> ImageLike: 

165 """Make a view of an image, optionally within a given bounding box. 

166 

167 Parameters 

168 ---------- 

169 image : `ImageLike` 

170 The image to make a view of. 

171 bbox : `Box2I`, optional 

172 The bounding box within which to make the view. 

173 

174 Returns 

175 ------- 

176 image_view: `ImageLike` 

177 The view of the image. 

178 """ 

179 if bbox is None: 

180 bbox = self._inner_bbox 

181 return image[bbox]