Coverage for python/lsst/meas/algorithms/makePsfCandidates.py: 27%

47 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-06 10:39 +0000

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2017 AURA/LSST. 

5# 

6# This product includes software developed by the 

7# LSST Project (http://www.lsst.org/). 

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 LSST License Statement and 

20# the GNU General Public License along with this program. If not, 

21# see <https://www.lsstcorp.org/LegalNotices/>. 

22# 

23__all__ = ["MakePsfCandidatesConfig", "MakePsfCandidatesTask"] 

24 

25import numpy as np 

26 

27from lsst.afw.table import SourceCatalog 

28import lsst.afw.math as afwMath 

29import lsst.pex.config as pexConfig 

30import lsst.pex.exceptions 

31import lsst.pipe.base as pipeBase 

32from . import makePsfCandidate 

33 

34 

35class MakePsfCandidatesConfig(pexConfig.Config): 

36 kernelSize = pexConfig.Field[int]( 

37 doc="Size of the postage stamp in pixels (excluding the border) around each star that is extracted " 

38 "for fitting. Should be odd and preferably at least 25.", 

39 default=25, 

40 ) 

41 borderWidth = pexConfig.Field[int]( 

42 doc="Number of pixels to ignore around the edge of PSF candidate postage stamps", 

43 default=0, 

44 ) 

45 

46 

47class MakePsfCandidatesTask(pipeBase.Task): 

48 """Create PSF candidates given an input catalog. 

49 """ 

50 ConfigClass = MakePsfCandidatesConfig 

51 _DefaultName = "makePsfCandidates" 

52 

53 def run(self, starCat, exposure, psfCandidateField=None): 

54 """Make a list of PSF candidates from a star catalog. 

55 

56 Parameters 

57 ---------- 

58 starCat : `lsst.afw.table.SourceCatalog` 

59 Catalog of stars, as returned by 

60 ``lsst.meas.algorithms.starSelector.run()``. 

61 exposure : `lsst.afw.image.Exposure` 

62 The exposure containing the sources. 

63 psfCandidateField : `str`, optional 

64 Name of flag field to set True for PSF candidates, or None to not 

65 set a field; the field is left unchanged for non-candidates. 

66 

67 Returns 

68 ------- 

69 struct : `lsst.pipe.base.Struct` 

70 Results struct containing: 

71 

72 - ``psfCandidates`` : List of PSF candidates 

73 (`list` of `lsst.meas.algorithms.PsfCandidate`). 

74 - ``goodStarCat`` : Subset of ``starCat`` that was successfully made 

75 into PSF candidates (`lsst.afw.table.SourceCatalog`). 

76 

77 """ 

78 psfResult = self.makePsfCandidates(starCat, exposure) 

79 

80 if psfCandidateField is not None: 

81 isStarKey = starCat.schema[psfCandidateField].asKey() 

82 for star in psfResult.goodStarCat: 

83 star.set(isStarKey, True) 

84 

85 return psfResult 

86 

87 def makePsfCandidates(self, starCat, exposure): 

88 """Make a list of PSF candidates from a star catalog. 

89 

90 Parameters 

91 ---------- 

92 starCat : `lsst.afw.table.SourceCatalog` 

93 Catalog of stars, as returned by 

94 ``lsst.meas.algorithms.starSelector.run()``. 

95 exposure : `lsst.afw.image.Exposure` 

96 The exposure containing the sources. 

97 

98 Returns 

99 ------- 

100 struct : `lsst.pipe.base.Struct` 

101 Results struct containing: 

102 

103 - ``psfCandidates`` : List of PSF candidates 

104 (`list` of `lsst.meas.algorithms.PsfCandidate`). 

105 - ``goodStarCat`` : Subset of ``starCat`` that was successfully made 

106 into PSF candidates (`lsst.afw.table.SourceCatalog`). 

107 """ 

108 goodStarCat = SourceCatalog(starCat.schema) 

109 

110 psfCandidateList = [] 

111 didSetSize = False 

112 for star in starCat: 

113 psfCandidate = makePsfCandidate(star, exposure) 

114 try: 

115 # The setXXX methods are class static, but it's convenient to call them on 

116 # an instance as we don't know exposures's pixel type 

117 # (and hence psfCandidate's exact type) 

118 if not didSetSize: 

119 psfCandidate.setBorderWidth(self.config.borderWidth) 

120 psfCandidate.setWidth(self.config.kernelSize + 2*self.config.borderWidth) 

121 psfCandidate.setHeight(self.config.kernelSize + 2*self.config.borderWidth) 

122 didSetSize = True 

123 

124 im = psfCandidate.getMaskedImage().getImage() 

125 except lsst.pex.exceptions.LengthError: 

126 self.log.warning("Could not get stamp for psfCandidate with source id=%s: %s", 

127 star.getId(), psfCandidate) 

128 continue 

129 except lsst.pex.exceptions.Exception as e: 

130 self.log.error("%s raised making psfCandidate from source id=%s: %s", 

131 e.__class__.__name__, star.getId(), psfCandidate) 

132 self.log.error("psfCandidate exception: %s", e) 

133 continue 

134 

135 vmax = afwMath.makeStatistics(im, afwMath.MAX).getValue() 

136 if not np.isfinite(vmax): 

137 continue 

138 psfCandidateList.append(psfCandidate) 

139 goodStarCat.append(star) 

140 

141 return pipeBase.Struct( 

142 psfCandidates=psfCandidateList, 

143 goodStarCat=goodStarCat, 

144 )