Coverage for python/lsst/ip/isr/photodiodeCorrection.py: 18%

71 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-25 02:52 -0800

1# This file is part of ip_isr. 

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""" 

22PhotodiodeCorrection storage class. 

23""" 

24 

25__all__ = ["PhotodiodeCorrection"] 

26 

27import numpy as np 

28from astropy.table import Table 

29from .calibType import IsrCalib 

30 

31 

32class PhotodiodeCorrection(IsrCalib): 

33 """Parameter set for photodiode correction. 

34 

35 These parameters are included in cameraGeom.Amplifier, but 

36 should be accessible externally to allow for testing. 

37 

38 Parameters 

39 ---------- 

40 table : `numpy.array`, optional 

41 Lookup table; a 2-dimensional array of floats: 

42 

43 - one row for each row index (value of coef[0] in the amplifier) 

44 - one column for each image value. 

45 

46 To avoid copying the table the last index should vary fastest 

47 (numpy default "C" order) 

48 log : `logging.Logger`, optional 

49 Logger to handle messages. 

50 kwargs : `dict`, optional 

51 Other keyword arguments to pass to the parent init. 

52 

53 Raises 

54 ------ 

55 RuntimeError 

56 Raised if the supplied table is not 2D, or if the table has fewer 

57 columns than rows (indicating that the indices are swapped). 

58 

59 Notes 

60 ----- 

61 The photodiode correction attributes stored are: 

62 abscissaCorrections : `dict` : [`str`, `float`] 

63 Correction value indexed by exposure pair 

64 """ 

65 _OBSTYPE = "PHOTODIODE_CORRECTION" 

66 _SCHEMA = 'PhotodiodeCorrection' 

67 _VERSION = 1.1 

68 

69 def __init__(self, table=None, **kwargs): 

70 self.abscissaCorrections = dict() 

71 self.tableData = None 

72 if table is not None: 

73 if len(table.shape) != 2: 

74 raise RuntimeError("table shape = %s; must have two dimensions" % (table.shape,)) 

75 if table.shape[1] < table.shape[0]: 

76 raise RuntimeError("table shape = %s; indices are switched" % (table.shape,)) 

77 self.tableData = np.array(table, order="C") 

78 

79 super().__init__(**kwargs) 

80 self.requiredAttributes.update(['abscissaCorrections']) 

81 

82 def updateMetadata(self, setDate=False, **kwargs): 

83 """Update metadata keywords with new values. 

84 

85 This calls the base class's method after ensuring the required 

86 calibration keywords will be saved. 

87 

88 Parameters 

89 ---------- 

90 setDate : `bool`, optional 

91 Update the CALIBDATE fields in the metadata to the current 

92 time. Defaults to False. 

93 kwargs : 

94 Other keyword parameters to set in the metadata. 

95 """ 

96 

97 super().updateMetadata(setDate=setDate, **kwargs) 

98 

99 @classmethod 

100 def fromDict(cls, dictionary): 

101 """Construct a PhotodiodeCorrection from a dictionary of properties. 

102 

103 Parameters 

104 ---------- 

105 dictionary : `dict` 

106 Dictionary of properties. 

107 

108 Returns 

109 ------- 

110 calib : `lsst.ip.isr.PhotodiodeCorrection` 

111 Constructed photodiode data. 

112 

113 Raises 

114 ------ 

115 RuntimeError 

116 Raised if the supplied dictionary is for a different 

117 calibration type. 

118 """ 

119 calib = cls() 

120 

121 if calib._OBSTYPE != dictionary['metadata']['OBSTYPE']: 

122 raise RuntimeError(f"Incorrect photodiode correction supplied. Expected {calib._OBSTYPE}, " 

123 f"found {dictionary['metadata']['OBSTYPE']}") 

124 

125 calib.setMetadata(dictionary['metadata']) 

126 for pair in dictionary['pairs']: 

127 correction = dictionary['pairs'][pair] 

128 calib.abscissaCorrections[pair] = correction 

129 

130 calib.tableData = dictionary.get('tableData', None) 

131 if calib.tableData: 

132 calib.tableData = np.array(calib.tableData) 

133 

134 return calib 

135 

136 def toDict(self): 

137 """Return a dictionary containing the photodiode correction properties. 

138 

139 The dictionary should be able to be round-tripped through. 

140 `fromDict`. 

141 

142 Returns 

143 ------- 

144 dictionary : `dict` 

145 Dictionary of properties. 

146 """ 

147 self.updateMetadata() 

148 

149 outDict = dict() 

150 outDict['pairs'] = dict() 

151 outDict['metadata'] = self.getMetadata() 

152 for pair in self.abscissaCorrections.keys(): 

153 outDict['pairs'][pair] = self.abscissaCorrections[pair] 

154 

155 if self.tableData is not None: 

156 outDict['tableData'] = self.tableData.tolist() 

157 

158 return outDict 

159 

160 @classmethod 

161 def fromTable(cls, tableList): 

162 """Construct calibration from a list of tables. 

163 

164 This method uses the `fromDict` method to create the 

165 calibration after constructing an appropriate dictionary from 

166 the input tables. 

167 

168 Parameters 

169 ---------- 

170 tableList : `list` [`astropy.table.Table`] 

171 List of tables to use to construct the crosstalk 

172 calibration. 

173 

174 Returns 

175 ------- 

176 calib : `lsst.ip.isr.PhotodiodeCorrection` 

177 The calibration defined in the tables. 

178 """ 

179 dataTable = tableList[0] 

180 

181 metadata = dataTable.meta 

182 inDict = dict() 

183 inDict['metadata'] = metadata 

184 inDict['pairs'] = dict() 

185 

186 for record in dataTable: 

187 pair = record['PAIR'] 

188 inDict['pairs'][pair] = record['PD_CORR'] 

189 

190 if len(tableList) > 1: 

191 tableData = tableList[1] 

192 inDict['tableData'] = [record['LOOKUP_VALUES'] for record in tableData] 

193 

194 return cls().fromDict(inDict) 

195 

196 def toTable(self): 

197 """Construct a list of tables containing the information in this 

198 calibration. 

199 

200 The list of tables should create an identical calibration 

201 after being passed to this class's fromTable method. 

202 

203 Returns 

204 ------- 

205 tableList : `list` [`astropy.table.Table`] 

206 List of tables containing the photodiode correction 

207 information. 

208 """ 

209 tableList = [] 

210 self.updateMetadata() 

211 catalog = Table([{'PAIR': key, 

212 'PD_CORR': self.abscissaCorrections[key]} 

213 for key in self.abscissaCorrections.keys()]) 

214 catalog.meta = self.getMetadata().toDict() 

215 tableList.append(catalog) 

216 

217 if self.tableData is not None: 

218 catalog = Table([{'LOOKUP_VALUES': value} for value in self.tableData]) 

219 tableList.append(catalog) 

220 

221 return(tableList) 

222 

223 def validate(self): 

224 """Validate photodiode correction""" 

225 return