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

45 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-31 04:34 -0700

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( 

37 doc="size of the kernel to create", 

38 dtype=int, 

39 default=25, 

40 ) 

41 borderWidth = pexConfig.Field( 

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

43 dtype=int, 

44 default=0, 

45 ) 

46 

47 

48class MakePsfCandidatesTask(pipeBase.Task): 

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

50 """ 

51 ConfigClass = MakePsfCandidatesConfig 

52 _DefaultName = "makePsfCandidates" 

53 

54 def __init__(self, **kwds): 

55 pipeBase.Task.__init__(self, **kwds) 

56 

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

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

59 

60 Parameters 

61 ---------- 

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

63 Catalog of stars, as returned by 

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

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

66 The exposure containing the sources. 

67 psfCandidateField : `str` or None 

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

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

70 

71 Returns 

72 ------- 

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

74 Results struct containing: 

75 

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

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

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

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

80 

81 """ 

82 psfResult = self.makePsfCandidates(starCat, exposure) 

83 

84 if psfCandidateField is not None: 

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

86 for star in psfResult.goodStarCat: 

87 star.set(isStarKey, True) 

88 

89 return psfResult 

90 

91 def makePsfCandidates(self, starCat, exposure): 

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

93 

94 Parameters 

95 ---------- 

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

97 Catalog of stars, as returned by 

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

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

100 The exposure containing the sources. 

101 

102 Returns 

103 ------- 

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

105 Results struct containing: 

106 

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

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

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

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

111 """ 

112 goodStarCat = SourceCatalog(starCat.schema) 

113 

114 psfCandidateList = [] 

115 didSetSize = False 

116 for star in starCat: 

117 try: 

118 psfCandidate = makePsfCandidate(star, exposure) 

119 

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

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

122 # (and hence psfCandidate's exact type) 

123 if not didSetSize: 

124 psfCandidate.setBorderWidth(self.config.borderWidth) 

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

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

127 didSetSize = True 

128 

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

130 except lsst.pex.exceptions.Exception as err: 

131 self.log.warning("Failed to make a psfCandidate from star %d: %s", star.getId(), err) 

132 continue 

133 

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

135 if not np.isfinite(vmax): 

136 continue 

137 psfCandidateList.append(psfCandidate) 

138 goodStarCat.append(star) 

139 

140 return pipeBase.Struct( 

141 psfCandidates=psfCandidateList, 

142 goodStarCat=goodStarCat, 

143 )