Coverage for python/lsst/pipe/tasks/snapCombine.py: 49%

37 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-14 10:04 +0000

1# This file is part of pipe_tasks. 

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 

22__all__ = ["SnapCombineConfig", "SnapCombineTask"] 

23 

24import lsst.pex.config as pexConfig 

25import lsst.daf.base as dafBase 

26import lsst.afw.image as afwImage 

27import lsst.pipe.base as pipeBase 

28from lsst.coadd.utils import addToCoadd, setCoaddEdgeBits 

29from lsst.utils.timer import timeMethod 

30 

31 

32class SnapCombineConfig(pexConfig.Config): 

33 bad_mask_planes = pexConfig.ListField( 

34 dtype=str, 

35 doc="Mask planes that, if set, the associated pixels are not included in the combined exposure.", 

36 default=(), 

37 ) 

38 

39 

40class SnapCombineTask(pipeBase.Task): 

41 """Combine two snaps into a single visit image. 

42 """ 

43 

44 ConfigClass = SnapCombineConfig 

45 _DefaultName = "snapCombine" 

46 

47 def __init__(self, *args, **kwargs): 

48 pipeBase.Task.__init__(self, *args, **kwargs) 

49 

50 @timeMethod 

51 def run(self, snap0, snap1): 

52 """Combine two snaps, returning the combined image. 

53 

54 Parameters 

55 ---------- 

56 snap0 : `lsst.afw.image.Exposure` 

57 Snapshot exposure 0. 

58 snap1 : `lsst.afw.image.Exposure` 

59 Snapshot exposure 1. 

60 

61 Returns 

62 ------- 

63 result : `lsst.pipe.base.Struct` 

64 Results as a struct with attributes: 

65 

66 ``exposure`` 

67 Snap-combined exposure. 

68 """ 

69 self.log.info("Merging two snaps with exposure ids: %s, %s", snap0.visitInfo.id, snap1.visitInfo.id) 

70 combined = self._add_snaps(snap0, snap1) 

71 

72 return pipeBase.Struct( 

73 exposure=combined, 

74 ) 

75 

76 def _add_snaps(self, snap0, snap1): 

77 """Add two snap exposures together, returning a new exposure. 

78 

79 Parameters 

80 ---------- 

81 snap0 : `lsst.afw.image.Exposure` 

82 Snap exposure 0. 

83 snap1 : `lsst.afw.image.Exposure` 

84 Snap exposure 1. 

85 

86 Returns 

87 ------- 

88 combined : `lsst.afw.image.Exposure` 

89 Combined exposure. 

90 """ 

91 combined = snap0.Factory(snap0, True) 

92 combined.maskedImage.set(0) 

93 

94 weights = combined.maskedImage.image.Factory(combined.maskedImage.getBBox()) 

95 weight = 1.0 

96 bad_mask = afwImage.Mask.getPlaneBitMask(self.config.bad_mask_planes) 

97 addToCoadd(combined.maskedImage, weights, snap0.maskedImage, bad_mask, weight) 

98 addToCoadd(combined.maskedImage, weights, snap1.maskedImage, bad_mask, weight) 

99 

100 # pre-scaling the weight map instead of post-scaling the combined.maskedImage saves a bit of time 

101 # because the weight map is a simple Image instead of a MaskedImage 

102 weights *= 0.5 # so result is sum of both images, instead of average 

103 combined.maskedImage /= weights 

104 setCoaddEdgeBits(combined.maskedImage.getMask(), weights) 

105 

106 combined.info.setVisitInfo(self._merge_visit_info(snap0.visitInfo, snap1.visitInfo)) 

107 

108 return combined 

109 

110 def _merge_visit_info(self, info0, info1): 

111 """Merge the visitInfo values from the two exposures. 

112 

113 In particular: 

114 * id will be the id of snap 0. 

115 * date will be the average of the dates. 

116 * exposure time will be the sum of the times. 

117 

118 Parameters 

119 ---------- 

120 info0, info1 : `lsst.afw.image.VisitInfo` 

121 Metadata to combine. 

122 

123 Returns 

124 ------- 

125 info : `lsst.afw.image.VisitInfo` 

126 Combined metadata. 

127 

128 """ 

129 time = info0.exposureTime + info1.exposureTime 

130 date = (info0.date.get() + info1.date.get()) / 2.0 

131 result = info0.copyWith(exposureTime=time, 

132 date=dafBase.DateTime(date) 

133 ) 

134 return result