LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
overscanAmpConfig.py
Go to the documentation of this file.
1import lsst.pex.config as pexConfig
2import hashlib
3
4from .overscan import SerialOverscanCorrectionTaskConfig, ParallelOverscanCorrectionTaskConfig
5
6
7__all__ = [
8 "OverscanAmpConfig",
9 "OverscanDetectorConfig",
10 "OverscanCameraConfig",
11]
12
13
14class OverscanAmpConfig(pexConfig.Config):
15 """Overscan configurations applicable to a single amplifier."""
16 doSerialOverscan = pexConfig.Field(
17 dtype=bool,
18 doc="Do serial overscan subtraction?",
19 default=True,
20 )
21 serialOverscanConfig = pexConfig.ConfigField(
22 dtype=SerialOverscanCorrectionTaskConfig,
23 doc="Serial overscan configuration.",
24 )
25 doParallelOverscanCrosstalk = pexConfig.Field(
26 dtype=bool,
27 doc="Apply crosstalk correction in parallel overscan region?",
28 default=True,
29 )
30 doParallelOverscan = pexConfig.Field(
31 dtype=bool,
32 doc="Do parallel overscan subtraction?",
33 default=True,
34 )
35 parallelOverscanConfig = pexConfig.ConfigField(
36 dtype=ParallelOverscanCorrectionTaskConfig,
37 doc="Parallel overscan configuration.",
38 )
39 saturation = pexConfig.Field(
40 dtype=float,
41 doc="The saturation level to use to override any detector/calibration product value "
42 "(ignored if NaN). Units are ADU.",
43 default=float("NaN"),
44 )
45 suspectLevel = pexConfig.Field(
46 dtype=float,
47 doc="The ``suspect`` level to use to override any detector/calibration product value "
48 "(ignored if NaN). Units are ADU.",
49 default=float("NaN"),
50 )
51 gain = pexConfig.Field(
52 dtype=float,
53 doc="The gain to use to override any calibration product value (ignored if NaN). "
54 "Units are e-/ADU.",
55 default=float("NaN"),
56 )
57
58 def setDefaults(self):
59 super().setDefaults()
60
61 self.serialOverscanConfig.fitType = "MEDIAN_PER_ROW"
62 self.serialOverscanConfig.leadingToSkip = 3
63 self.serialOverscanConfig.trailingToSkip = 3
64 self.serialOverscanConfig.overscanIsInt = False
65 self.parallelOverscanConfig.fitType = "MEDIAN_PER_ROW"
66 self.parallelOverscanConfig.leadingToSkip = 3
67 self.parallelOverscanConfig.trailingToSkip = 3
68 self.parallelOverscanConfig.overscanIsInt = False
69 # We expect the parallel overscan to not deviate much
70 # after serial overscan subtraction and crosstalk correction.
71 self.parallelOverscanConfig.maxDeviation = 100.0
72
73 @property
74 def _stringForHash(self):
75 """Turn this config into a simple string for hashing.
76
77 Only essential data for tracking is returned.
78
79 Returns
80 -------
81 stringForHash : `str`
82 """
83 stringForHash = (f"doSerial={self.doSerialOverscan} "
84 f"serialFitType={self.serialOverscanConfig.fitType} "
85 f"doParallelCrosstalk={self.doParallelOverscanCrosstalk} "
86 f"doParallel={self.doParallelOverscan} "
87 f"parallelFitType={self.parallelOverscanConfig.fitType}")
88 return stringForHash
89
90
91class OverscanDetectorConfig(pexConfig.Config):
92 """Overscan configurations applicable to multiple amplifiers in
93 a single detector.
94 """
95 ampRules = pexConfig.ConfigDictField(
96 doc="Amplifier level rules for overscan, keyed by amp name.",
97 keytype=str,
98 itemtype=OverscanAmpConfig,
99 default={},
100 )
101 defaultAmpConfig = pexConfig.ConfigField(
102 dtype=OverscanAmpConfig,
103 doc="Default configuration for amplifiers.",
104 )
105 integerDitherMode = pexConfig.ChoiceField(
106 dtype=str,
107 doc="Dithering mode to cancel integerization of counts.",
108 default="SYMMETRIC",
109 allowed={
110 "POSITIVE": "Dithering is done with a uniform random in the range [0, 1).",
111 "NEGATIVE": "Dithering is done with a uniform random in the range [-1, 0).",
112 "SYMMETRIC": "Dithering is done with a uniform random in the range [-0.5, 0.5).",
113 "NONE": "No dithering is performed.",
114 },
115 )
116
117 @property
119 """Check if any of the amp configs have doSerialOverscan.
120
121 Returns
122 -------
123 doAnySerialOverscan : `bool`
124 """
125 if self.defaultAmpConfig.doSerialOverscan:
126 return True
127
128 for _, ampRule in self.ampRules.items():
129 if ampRule.doSerialOverscan:
130 return True
131
132 return False
133
134 @property
136 """Check if any of the amp configs have doParallelOverscan.
137
138 Returns
139 -------
140 doAnyParallelOverscan : `bool`
141 """
142 if self.defaultAmpConfig.doParallelOverscan:
143 return True
144
145 for _, ampRule in self.ampRules.items():
146 if ampRule.doParallelOverscan:
147 return True
148
149 return False
150
151 @property
153 """Check if any of the amp configs have doParallelOverscanCrosstalk.
154
155 Returns
156 -------
157 doAnyParallelOverscanCrosstalk : `bool`
158 """
159 if self.defaultAmpConfig.doParallelOverscanCrosstalk:
160 return True
161
162 for _, ampRule in self.ampRules.items():
163 if ampRule.doParallelOverscanCrosstalk:
164 return True
165
166 return False
167
168 def getOverscanAmpConfig(self, amplifier):
169 """Get the OverscanAmpConfig for a specific amplifier.
170
171 Parameters
172 ----------
173 amplifier : `lsst.afw.cameraGeom.Amplifier`
174
175 Returns
176 -------
177 overscanAmpConfig : `lsst.ip.isr.overscanAmpConfig.OverscanAmpConfig`
178 """
179 ampKey = amplifier.getName()
180
181 if ampKey in self.ampRules.keys():
182 overscanAmpConfig = self.ampRules[ampKey]
183 else:
184 overscanAmpConfig = self.defaultAmpConfig
185
186 return overscanAmpConfig
187
188 @property
189 def _stringForHash(self):
190 """Turn this config into a simple string for hashing.
191
192 Only the default and amps that are different than the
193 default are used in the string representation.
194
195 Returns
196 -------
197 stringForHash : `str`
198 """
199 defaultString = self.defaultAmpConfig._stringForHash
200
201 stringForHash = f"default: {defaultString}"
202 for ampName in self.ampRules:
203 ampString = self.ampRules[ampName]._stringForHash
204 if ampString != defaultString:
205 stringForHash += f" {ampName}: {ampString}"
206
207 return stringForHash
208
209 @property
210 def md5(self):
211 """Compute the MD5 hash of this config (detector + amps).
212
213 This can be used to ensure overscan configs are consistent.
214
215 Returns
216 -------
217 md5Hash : `str`
218 """
219 return hashlib.md5(self._stringForHash.encode("UTF-8")).hexdigest()
220
221
222class OverscanCameraConfig(pexConfig.Config):
223 """Overscan configurations applicable to multiple detectors in
224 a single camera.
225 """
226 detectorRules = pexConfig.ConfigDictField(
227 doc="Detector level rules for overscan",
228 keytype=str,
229 itemtype=OverscanDetectorConfig,
230 default={},
231 )
232 defaultDetectorConfig = pexConfig.ConfigField(
233 dtype=OverscanDetectorConfig,
234 doc="Default configuration for detectors.",
235 )
236 detectorRuleKeyType = pexConfig.ChoiceField(
237 doc="Detector rule key type.",
238 dtype=str,
239 default="NAME",
240 allowed={
241 "NAME": "DetectorRules has a key that is the detector name.",
242 "SERIAL": "DetectorRules has a key that is the detector serial number.",
243 "ID": "DetectorRules has a key that is the detector id number.",
244 },
245 )
246
247 @property
249 """Check if any of the detector/amp configs have doSerialOverscan.
250
251 Returns
252 -------
253 doAnySerialOverscan : `bool`
254 """
255 if self.defaultDetectorConfig.doAnySerialOverscan:
256 return True
257
258 for _, detectorRule in self.detectorRules.items():
259 if detectorRule.doAnySerialOverscan:
260 return True
261
262 return False
263
264 @property
266 """Check if any of the detector/amp configs have
267 doParallelOverscan.
268
269 Returns
270 -------
271 doAnyParallelOverscan : `bool`
272 """
273
274 if self.defaultDetectorConfig.doAnyParallelOverscan:
275 return True
276
277 for _, detectorRule in self.detectorRules.items():
278 if detectorRule.doAnyParallelOverscan:
279 return True
280
281 return False
282
283 @property
285 """Check if any of the detector/amp configs have
286 doParallelOverscanCrosstalk.
287
288 Returns
289 -------
290 doAnyParallelOverscanCrosstalk : `bool`
291 """
292
293 if self.defaultDetectorConfig.doAnyParallelOverscanCrosstalk:
294 return True
295
296 for _, detectorRule in self.detectorRules.items():
297 if detectorRule.doAnyParallelOverscanCrosstalk:
298 return True
299
300 return False
301
302 def getOverscanDetectorConfig(self, detector):
303 """Get the OverscanDetectorConfig for a specific detector.
304
305 Parameters
306 ----------
307 detector : `lsst.afw.cameraGeom.Detector`
308
309 Returns
310 -------
311 overscanDetectorConfig : `OverscanDetectorConfig`
312 """
313 match self.detectorRuleKeyType:
314 case "NAME":
315 key = detector.getName()
316 case "SERIAL":
317 key = detector.getSerial()
318 case "ID":
319 key = str(detector.getId())
320
321 if key in self.detectorRules.keys():
322 overscanDetectorConfig = self.detectorRules[key]
323 else:
324 overscanDetectorConfig = self.defaultDetectorConfig
325
326 return overscanDetectorConfig
std::vector< SchemaItem< Flag > > * items