Coverage for python/lsst/meas/base/transforms.py: 45%

34 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-03-04 10:24 +0000

1# This file is part of meas_base. 

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"""Measurement transformations. 

23 

24When a measurement plugin is run, it provides raw, uncalibrated outputs such 

25as pixel positions. A transformation may be run as a post-processing step to 

26convert those outputs to calibrated quantities, such as celestial coordinates. 

27 

28At construction, the transformation is passed the configuration and name of 

29the plugin whose outputs it will be transformaing (all fields in the input 

30table produced by that plugin will have their field names prefixed by the 

31plugin name) and a `~lsst.afw.table.SchemaMapper` which holds the schemata for 

32the input and output catalogs and which may be used to directly map fields 

33between the catalogs. 

34 

35When a transformer is called, it is handed a `~lsst.afw.table.SourceCatalog` 

36containing the measurements to be transformed, a `~lsst.afw.table.BaseCatalog` 

37in which to store results, and information about the WCS and calibration of 

38the data. It may be safely assumed that both are contiguous in memory, thus a 

39``ColumnView`` may be used for efficient processing. If the transformation is 

40not possible, it should be aborted by throwing an exception; if this happens, 

41the caller should assume that the contents of the output catalog are 

42inconsistent. 

43 

44Transformations can be defined in Python or in C++. Python code should inherit 

45from `MeasurementTransform`, following its interface. 

46""" 

47 

48from lsst.afw.table import CoordKey 

49from lsst.pex.exceptions import LengthError 

50from ._measBaseLib import CentroidResultKey 

51 

52__all__ = ("MeasurementTransform", "NullTransform", "PassThroughTransform", "SimpleCentroidTransform") 

53 

54 

55class MeasurementTransform: 

56 """Base class for measurement transformations. 

57 

58 Parameters 

59 ---------- 

60 config : subclass of `BasePluginConfig` 

61 The configuration of the measurement plugin whose outputs are being 

62 transformed. 

63 name : `str` 

64 The name of the measurement plugin whose outputs are being 

65 transformed. 

66 mapper : `lsst.afw.table.SchemaMapper` 

67 Mapping between the input (pre-transformation) and output 

68 (transformed) catalogs. 

69 

70 Notes 

71 ----- 

72 Create transformations by deriving from this class, implementing 

73 `__call__()` and (optionally) augmenting `__init__()`. 

74 """ 

75 

76 def __init__(self, config, name, mapper): 

77 self.name = name 

78 self.config = config 

79 

80 def __call__(self, inputCatalog, outputCatalog, wcs, photoCalib): 

81 raise NotImplementedError() 

82 

83 @staticmethod 

84 def _checkCatalogSize(cat1, cat2): 

85 if len(cat1) != len(cat2): 

86 raise LengthError("Catalog size mismatch") 

87 

88 

89class NullTransform(MeasurementTransform): 

90 """Null transform which transfers no data from input to output. 

91 

92 This is intended as the default for measurements for which no other 

93 transformation is specified. 

94 

95 Parameters 

96 ---------- 

97 config : subclass of `BasePluginConfig` 

98 The configuration of the measurement plugin whose outputs are being 

99 transformed. 

100 name : `str` 

101 The name of the measurement plugin whose outputs are being 

102 transformed. 

103 mapper : `lsst.afw.table.SchemaMapper` 

104 Mapping between the input (pre-transformation) and output 

105 (transformed) catalogs. 

106 """ 

107 

108 def __call__(self, inputCatalog, outputCatalog, wcs, photoCalib): 

109 self._checkCatalogSize(inputCatalog, outputCatalog) 

110 

111 

112class PassThroughTransform(MeasurementTransform): 

113 """Copy fields from input to output without transformation. 

114 

115 Parameters 

116 ---------- 

117 config : subclass of `BasePluginConfig` 

118 The configuration of the measurement plugin whose outputs are being 

119 transformed. 

120 name : `str` 

121 The name of the measurement plugin whose outputs are being 

122 transformed. 

123 mapper : `lsst.afw.table.SchemaMapper` 

124 Mapping between the input (pre-transformation) and output 

125 (transformed) catalogs. 

126 """ 

127 

128 def __init__(self, config, name, mapper): 

129 MeasurementTransform.__init__(self, config, name, mapper) 

130 for key, field in mapper.getInputSchema().extract(name + "*").values(): 

131 mapper.addMapping(key) 

132 

133 def __call__(self, inputCatalog, outputCatalog, wcs, photoCalib): 

134 self._checkCatalogSize(inputCatalog, outputCatalog) 

135 

136 

137class SimpleCentroidTransform(MeasurementTransform): 

138 """Transform pixel centroid, without uncertainty, to celestial coordinates. 

139 

140 Parameters 

141 ---------- 

142 config : subclass of `BasePluginConfig` 

143 The configuration of the measurement plugin whose outputs are being 

144 transformed. 

145 name : `str` 

146 The name of the measurement plugin whose outputs are being 

147 transformed. 

148 mapper : `lsst.afw.table.SchemaMapper` 

149 Mapping between the input (pre-transformation) and output 

150 (transformed) catalogs. 

151 """ 

152 

153 def __init__(self, config, name, mapper): 

154 MeasurementTransform.__init__(self, config, name, mapper) 

155 self.coordKey = CoordKey.addFields(mapper.editOutputSchema(), name, "Position from " + name) 

156 

157 def __call__(self, inputCatalog, outputCatalog, wcs, photoCalib): 

158 self._checkCatalogSize(inputCatalog, outputCatalog) 

159 centroidResultKey = CentroidResultKey(inputCatalog.schema[self.name]) 

160 for inSrc, outSrc in zip(inputCatalog, outputCatalog): 

161 self.coordKey.set(outSrc, wcs.pixelToSky(centroidResultKey.get(inSrc).getCentroid()))