Coverage for python/lsst/cell_coadds/_exploded_coadd.py: 47%

64 statements  

« prev     ^ index     » next       coverage.py v7.4.3, created at 2024-03-06 10:50 +0000

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__ = ("ExplodedCoadd",) 

25 

26from collections.abc import Iterator, Set 

27from functools import partial 

28from typing import TYPE_CHECKING 

29 

30from lsst.afw.image import ImageF 

31 

32from ._image_planes import ImagePlanes, ViewImagePlanes 

33from ._stitched_image_planes import StitchedImagePlanes 

34from ._uniform_grid import UniformGrid 

35from .typing_helpers import ImageLike 

36 

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

38 from lsst.geom import Box2I, Point2I 

39 

40 from ._multiple_cell_coadd import MultipleCellCoadd 

41 

42 

43class ExplodedCoadd(StitchedImagePlanes): 

44 """A lazy-evaluation coadd that stitches together the outer regions of the 

45 cells in a `MultipleCellCoadd` (including multiple values for most pixels). 

46 

47 Parameters 

48 ---------- 

49 cell_coadd : `MultipleCellCoadd` 

50 Cell-based coadd to stitch together. 

51 pad_psfs_with : `float` or `None`, optional 

52 A floating-point value to pad PSF images with so each PSF-image cell 

53 has the same dimensions as the image (outer) cell it corresponds to. 

54 If `None`, PSF images will not be padded and the full PSF image will 

55 generally be smaller than the exploded image it corresponds to. 

56 

57 Notes 

58 ----- 

59 An `ExplodedCoadd` cannot be serialized in FITS format directly. Instead, 

60 the recommended way is to serialize the `MultipleCellCoadd` instance that 

61 was used to construct the object and reconstruct the `ExplodedCoadd` by 

62 calling the `explode` method on it. 

63 """ 

64 

65 def __init__(self, cell_coadd: MultipleCellCoadd, *, pad_psfs_with: float | None = None): 

66 super().__init__() 

67 self._grid = UniformGrid(cell_coadd.outer_cell_size, cell_coadd.grid.shape) 

68 if pad_psfs_with is None: 

69 self._psf_grid = UniformGrid(cell_coadd.psf_image_size, cell_coadd.grid.shape) 

70 elif (cell_coadd.psf_image_size.x > cell_coadd.outer_cell_size.x) or ( 

71 cell_coadd.psf_image_size.y > cell_coadd.outer_cell_size.y 

72 ): 

73 raise ValueError( 

74 f"PSF image dimensions {cell_coadd.psf_image_size} are larger than " 

75 f"outer cell dimensions {cell_coadd.outer_cell_size}; cannot pad." 

76 ) 

77 else: 

78 self._psf_grid = self._grid 

79 self._cell_coadd = cell_coadd 

80 self._pad_psfs_with = pad_psfs_with 

81 self._psf_image: ImageF | None = None 

82 

83 @property 

84 def bbox(self) -> Box2I: 

85 # Docstring inherited. 

86 return self._grid.bbox 

87 

88 @property 

89 def grid(self) -> UniformGrid: 

90 """Object that defines the piecewise grid (of outer cell regions) that 

91 this object stitches together. 

92 

93 This grid always starts at `(0, 0)`; because there is no way to align 

94 this "exploded" grid with the inner cell grid over more than one cell, 

95 no attempt is made to align it with the inner cell grid's overall 

96 offset. 

97 """ 

98 return self._grid 

99 

100 @property 

101 def psf_grid(self) -> UniformGrid: 

102 """Object that describes the grid on which PSF model images are 

103 stitched together. 

104 """ 

105 return self._psf_grid 

106 

107 @property 

108 def n_noise_realizations(self) -> int: 

109 # Docstring inherited. 

110 return self._cell_coadd.n_noise_realizations 

111 

112 @property 

113 def mask_fraction_names(self) -> Set[str]: 

114 # Docstring inherited. 

115 return self._cell_coadd.mask_fraction_names 

116 

117 @staticmethod 

118 def _make_view_with_xy0(original: ImageLike, xy0: Point2I) -> ImageLike: 

119 result = original[:, :] # copy bbox, share pixel data. 

120 result.setXY0(xy0) 

121 return result 

122 

123 def _iter_cell_planes(self) -> Iterator[ImagePlanes]: 

124 # Docstring inherited. 

125 for cell in self._cell_coadd.cells.values(): 

126 new_bbox = self._grid.bbox_of(cell.identifiers.cell.index) 

127 make_view = partial(self._make_view_with_xy0, xy0=new_bbox.getMin()) 

128 

129 yield ViewImagePlanes(cell.outer, make_view, bbox=new_bbox) 

130 

131 @property 

132 def psf_image(self) -> ImageF: 

133 """A stitched-together image of the PSF models for each cell.""" 

134 if self._psf_image is None: 

135 stitched_psf_image = ImageF(self.psf_grid.bbox) 

136 if self._pad_psfs_with is not None: 

137 stitched_psf_image.set(self._pad_psfs_with) 

138 for cell in self._cell_coadd.cells.values(): 

139 target_subimage = stitched_psf_image[self.psf_grid.bbox_of(cell.identifiers.cell)] 

140 target_dimensions = target_subimage.getDimensions() 

141 source_dimensions = cell.psf_image.getDimensions() 

142 offset = (target_dimensions - source_dimensions) // 2 

143 # Use numpy views instead of Image methods because the images 

144 # are not in the same coordinate system to begin with, so xy0 

145 # doesn't help us. 

146 target_subimage.array[ 

147 offset.y : offset.y + source_dimensions.y, offset.x : offset.x + source_dimensions.x 

148 ] = cell.psf_image.array 

149 self._psf_image = stitched_psf_image 

150 return self._psf_image