lsst.afw  21.0.0-31-g2bc2b1e0a+8935f19055
testUtils.py
Go to the documentation of this file.
1 # This file is part of afw.
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 __all__ = ["DetectorWrapper", "CameraWrapper"]
23 
24 import os
25 
26 import numpy as np
27 
28 import lsst.utils
29 import lsst.geom
30 import lsst.afw.geom as afwGeom
31 from lsst.utils.tests import inTestCase
32 from ._cameraGeom import CameraSys, PIXELS, TAN_PIXELS, FIELD_ANGLE, FOCAL_PLANE, ACTUAL_PIXELS, Orientation
33 from ._cameraGeom import Amplifier, ReadoutCorner
34 from ._camera import Camera
35 from ._cameraGeom import DetectorType
36 from .cameraConfig import DetectorConfig, CameraConfig
37 from ._cameraFactory import makeCameraFromAmpLists
38 from ._makePixelToTanPixel import makePixelToTanPixel
39 from ._transformConfig import TransformMapConfig
40 
41 
43  """A Detector and the data used to construct it
44 
45  Intended for use with unit tests, thus saves a copy of all input parameters.
46  Does not support setting details of amplifiers.
47 
48  Parameters
49  ----------
50  name : `str` (optional)
51  Detector name.
52  id : `int` (optional)
53  Detector ID.
54  detType : `lsst.afw.cameraGeom.DetectorType` (optional)
55  Detector type.
56  serial : `str` (optional)
57  Serial "number".
58  bbox : `lsst.geom.Box2I` (optional)
59  Bounding box; defaults to (0, 0), (1024x1024).
60  numAmps : `int` (optional)
61  Number of amplifiers.
62  pixelSize : `lsst.geom.Point2D` (optional)
63  Pixel size (mm).
64  ampExtent : `lsst.geom.Extent2I` (optional)
65  Dimensions of amplifier image bbox.
66  orientation : `lsst.afw.cameraGeom.Orientation` (optional)
67  Orientation of CCC in focal plane.
68  plateScale : `float` (optional)
69  Plate scale in arcsec/mm; 20.0 is for LSST.
70  radialDistortion : `float` (optional)
71  Radial distortion, in mm/rad^2.
72  The r^3 coefficient of the radial distortion polynomial
73  that converts FIELD_ANGLE in radians to FOCAL_PLANE in mm;
74  0.925 is the value Dave Monet measured for lsstSim data
75  crosstalk : `iterable` (optional)
76  Crosstalk coefficient matrix. If None, then no crosstalk correction
77  can be performed.
78  modFunc : `callable` (optional)
79  A function that can modify attributes just before constructing the
80  detector; modFunc receives one argument: a DetectorWrapper with all
81  attributes except detector set.
82  physicalType : `str` (optional)
83  The physical type of the device, e.g. CCD, E2V, HgCdTe
84  """
85 
86  def __init__(self,
87  name="detector 1",
88  id=1,
89  detType=DetectorType.SCIENCE,
90  serial="xkcd722",
91  bbox=None, # do not use mutable objects as defaults
92  numAmps=3,
93  pixelSize=(0.02, 0.02),
94  ampExtent=(5, 6),
95  orientation=Orientation(),
96  plateScale=20.0,
97  radialDistortion=0.925,
98  crosstalk=None,
99  modFunc=None,
100  physicalType="CCD",
101  cameraBuilder=None
102  ):
103  # note that (0., 0.) for the reference position is the center of the
104  # first pixel
105  self.namename = name
106  self.idid = int(id)
107  self.typetype = detType
108  self.serialserial = serial
109  if bbox is None:
110  bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, 0), lsst.geom.Extent2I(1024, 1048))
111  self.bboxbbox = bbox
112  self.pixelSizepixelSize = lsst.geom.Extent2D(*pixelSize)
113  self.ampExtentampExtent = lsst.geom.Extent2I(*ampExtent)
114  self.plateScaleplateScale = float(plateScale)
115  self.orientationorientation = orientation
116  self.radialDistortionradialDistortion = float(radialDistortion)
117 
118  # compute TAN_PIXELS transform
119  pScaleRad = lsst.geom.arcsecToRad(self.plateScaleplateScale)
120  radialDistortCoeffs = [0.0, 1.0/pScaleRad,
121  0.0, self.radialDistortionradialDistortion/pScaleRad]
122  focalPlaneToField = afwGeom.makeRadialTransform(radialDistortCoeffs)
123  pixelToTanPixel = makePixelToTanPixel(
124  bbox=self.bboxbbox,
125  orientation=self.orientationorientation,
126  focalPlaneToField=focalPlaneToField,
127  pixelSizeMm=self.pixelSizepixelSize,
128  )
129  tanPixelSys = CameraSys(TAN_PIXELS, self.namename)
130  actualPixelSys = CameraSys(ACTUAL_PIXELS, self.namename)
131  self.transMaptransMap = {
132  FOCAL_PLANE: self.orientationorientation.makePixelFpTransform(self.pixelSizepixelSize),
133  tanPixelSys: pixelToTanPixel,
134  actualPixelSys: afwGeom.makeRadialTransform([0, 0.95, 0.01]),
135  }
136  if crosstalk is None:
137  crosstalk = [[0.0 for _ in range(numAmps)] for _ in range(numAmps)]
138  self.crosstalkcrosstalk = crosstalk
139  self.physicalTypephysicalType = physicalType
140  if cameraBuilder is None:
141  cameraBuilder = Camera.Builder("CameraForDetectorWrapper")
142  self.ampListampList = []
143  for i in range(numAmps):
144  ampBuilder = Amplifier.Builder()
145  ampName = f"amp {i + 1}"
146  ampBuilder.setName(ampName)
147  ampBuilder.setBBox(lsst.geom.Box2I(lsst.geom.Point2I(-1, 1), self.ampExtentampExtent))
148  ampBuilder.setGain(1.71234e3)
149  ampBuilder.setReadNoise(0.521237e2)
150  ampBuilder.setReadoutCorner(ReadoutCorner.LL)
151  self.ampListampList.append(ampBuilder)
152  if modFunc:
153  modFunc(self)
154  detectorBuilder = cameraBuilder.add(self.namename, self.idid)
155  detectorBuilder.setType(self.typetype)
156  detectorBuilder.setSerial(self.serialserial)
157  detectorBuilder.setPhysicalType(self.physicalTypephysicalType)
158  detectorBuilder.setBBox(self.bboxbbox)
159  detectorBuilder.setOrientation(self.orientationorientation)
160  detectorBuilder.setPixelSize(self.pixelSizepixelSize)
161  detectorBuilder.setTransformFromPixelsTo(tanPixelSys, self.transMaptransMap[tanPixelSys])
162  detectorBuilder.setTransformFromPixelsTo(actualPixelSys, self.transMaptransMap[actualPixelSys])
163  detectorBuilder.setCrosstalk(np.array(self.crosstalkcrosstalk, dtype=np.float32))
164  for ampBuilder in self.ampListampList:
165  detectorBuilder.append(ampBuilder)
166  camera = cameraBuilder.finish()
167  self.detectordetector = camera[self.namename]
168 
169 
171  """A simple Camera and the data used to construct it
172 
173  Intended for use with unit tests, thus saves some interesting information.
174 
175  Parameters
176  ----------
177  plateScale : `float`
178  Plate scale in arcsec/mm; 20.0 is for LSST.
179  radialDistortion : `float`
180  Radial distortion, in mm/rad^2.
181  The r^3 coefficient of the radial distortion polynomial
182  that converts FIELD_ANGLE in radians to FOCAL_PLANE in mm;
183  0.925 is the value Dave Monet measured for lsstSim data.
184  isLsstLike : `bool`.
185  Make repository products with one raw image per amplifier (True)
186  or with one raw image per detector (False).
187  """
188 
189  def __init__(self, plateScale=20.0, radialDistortion=0.925, isLsstLike=False):
190  afwDir = lsst.utils.getPackageDir("afw")
191  self._afwTestDataDir_afwTestDataDir = os.path.join(afwDir, "python", "lsst", "afw",
192  "cameraGeom", "testData")
193 
194  # Info to store for unit tests
195  self.plateScaleplateScale = float(plateScale)
196  self.radialDistortionradialDistortion = float(radialDistortion)
197  self.detectorNameListdetectorNameList = []
198  self.detectorIdListdetectorIdList = []
199  self.ampDataDictampDataDict = {} # ampData[Dict]: raw dictionaries of test data fields
200 
201  # ampList[Dict]: actual cameraGeom.Amplifier objects
202  self.camConfig, self.ampListDictampListDict = self.makeTestRepositoryItemsmakeTestRepositoryItems(
203  isLsstLike)
205  self.camConfig, self.ampListDictampListDict)
206 
207  @property
208  def nDetectors(self):
209  """Return the number of detectors"""
210  return len(self.detectorNameListdetectorNameList)
211 
212  def makeDetectorConfigs(self, detFile):
213  """Construct a list of DetectorConfig, one per detector
214  """
215  detectors = []
216  self.detectorNameListdetectorNameList = []
217  self.detectorIdListdetectorIdList = []
218  with open(detFile) as fh:
219  names = fh.readline().rstrip().lstrip("#").split("|")
220  for line in fh:
221  els = line.rstrip().split("|")
222  detectorProps = dict([(name, el)
223  for name, el in zip(names, els)])
224  detectors.append(detectorProps)
225  detectorConfigs = []
226  for i, detector in enumerate(detectors):
227  detectorId = (i + 1) * 10 # to avoid simple 0, 1, 2...
228  detectorName = detector['name']
229  detConfig = DetectorConfig()
230  detConfig.name = detectorName
231  detConfig.id = detectorId
232  detConfig.bbox_x0 = 0
233  detConfig.bbox_y0 = 0
234  detConfig.bbox_x1 = int(detector['npix_x']) - 1
235  detConfig.bbox_y1 = int(detector['npix_y']) - 1
236  detConfig.serial = str(detector['serial'])
237  detConfig.detectorType = int(detector['detectorType'])
238  detConfig.offset_x = float(detector['x'])
239  detConfig.offset_y = float(detector['y'])
240  detConfig.refpos_x = float(detector['refPixPos_x'])
241  detConfig.refpos_y = float(detector['refPixPos_y'])
242  detConfig.yawDeg = float(detector['yaw'])
243  detConfig.pitchDeg = float(detector['pitch'])
244  detConfig.rollDeg = float(detector['roll'])
245  detConfig.pixelSize_x = float(detector['pixelSize'])
246  detConfig.pixelSize_y = float(detector['pixelSize'])
247  detConfig.transposeDetector = False
248  detConfig.transformDict.nativeSys = PIXELS.getSysName()
249  detectorConfigs.append(detConfig)
250  self.detectorNameListdetectorNameList.append(detectorName)
251  self.detectorIdListdetectorIdList.append(detectorId)
252  return detectorConfigs
253 
254  def makeAmpLists(self, ampFile, isLsstLike=False):
255  """Construct a dict of list of Amplifer, one list per detector.
256 
257  Parameters
258  ----------
259  ampFile : `str`
260  Path to amplifier data file.
261  isLsstLike : `bool`
262  If True then there is one raw image per amplifier;
263  if False then there is one raw image per detector.
264  """
265  readoutMap = {
266  'LL': ReadoutCorner.LL,
267  'LR': ReadoutCorner.LR,
268  'UR': ReadoutCorner.UR,
269  'UL': ReadoutCorner.UL,
270  }
271  ampDataList = []
272  with open(ampFile) as fh:
273  names = fh.readline().rstrip().lstrip("#").split("|")
274  for line in fh:
275  els = line.rstrip().split("|")
276  ampProps = dict([(name, el) for name, el in zip(names, els)])
277  ampDataList.append(ampProps)
278  ampListDict = {}
279  self.ampDataDictampDataDict = {}
280  for ampData in ampDataList:
281  if ampData['ccd_name'] in ampListDict:
282  ampList = ampListDict[ampData['ccd_name']]
283  self.ampDataDictampDataDict[ampData['ccd_name']]['namps'] += 1
284  else:
285  ampList = []
286  ampListDict[ampData['ccd_name']] = ampList
287  self.ampDataDictampDataDict[ampData['ccd_name']] = {'namps': 1, 'linInfo': {}}
288  builder = Amplifier.Builder()
289  bbox = lsst.geom.Box2I(lsst.geom.Point2I(int(ampData['trimmed_xmin']),
290  int(ampData['trimmed_ymin'])),
291  lsst.geom.Point2I(int(ampData['trimmed_xmax']),
292  int(ampData['trimmed_ymax'])))
293  rawBbox = lsst.geom.Box2I(lsst.geom.Point2I(int(ampData['raw_xmin']),
294  int(ampData['raw_ymin'])),
295  lsst.geom.Point2I(int(ampData['raw_xmax']),
296  int(ampData['raw_ymax'])))
297  rawDataBbox = lsst.geom.Box2I(
298  lsst.geom.Point2I(int(ampData['raw_data_xmin']),
299  int(ampData['raw_data_ymin'])),
300  lsst.geom.Point2I(int(ampData['raw_data_xmax']),
301  int(ampData['raw_data_ymax'])))
302  rawHOverscanBbox = lsst.geom.Box2I(
303  lsst.geom.Point2I(int(ampData['hoscan_xmin']),
304  int(ampData['hoscan_ymin'])),
305  lsst.geom.Point2I(int(ampData['hoscan_xmax']),
306  int(ampData['hoscan_ymax'])))
307  rawVOverscanBbox = lsst.geom.Box2I(
308  lsst.geom.Point2I(int(ampData['voscan_xmin']),
309  int(ampData['voscan_ymin'])),
310  lsst.geom.Point2I(int(ampData['voscan_xmax']),
311  int(ampData['voscan_ymax'])))
312  rawPrescanBbox = lsst.geom.Box2I(
313  lsst.geom.Point2I(int(ampData['pscan_xmin']),
314  int(ampData['pscan_ymin'])),
315  lsst.geom.Point2I(int(ampData['pscan_xmax']),
316  int(ampData['pscan_ymax'])))
317  xoffset = int(ampData['x_offset'])
318  yoffset = int(ampData['y_offset'])
319  flipx = bool(int(ampData['flipx']))
320  flipy = bool(int(ampData['flipy']))
321  readcorner = 'LL'
322  if not isLsstLike:
323  offext = lsst.geom.Extent2I(xoffset, yoffset)
324  if flipx:
325  xExt = rawBbox.getDimensions().getX()
326  rawBbox.flipLR(xExt)
327  rawDataBbox.flipLR(xExt)
328  rawHOverscanBbox.flipLR(xExt)
329  rawVOverscanBbox.flipLR(xExt)
330  rawPrescanBbox.flipLR(xExt)
331  if flipy:
332  yExt = rawBbox.getDimensions().getY()
333  rawBbox.flipTB(yExt)
334  rawDataBbox.flipTB(yExt)
335  rawHOverscanBbox.flipTB(yExt)
336  rawVOverscanBbox.flipTB(yExt)
337  rawPrescanBbox.flipTB(yExt)
338  if not flipx and not flipy:
339  readcorner = 'LL'
340  elif flipx and not flipy:
341  readcorner = 'LR'
342  elif flipx and flipy:
343  readcorner = 'UR'
344  elif not flipx and flipy:
345  readcorner = 'UL'
346  else:
347  raise RuntimeError("Couldn't find read corner")
348 
349  flipx = False
350  flipy = False
351  rawBbox.shift(offext)
352  rawDataBbox.shift(offext)
353  rawHOverscanBbox.shift(offext)
354  rawVOverscanBbox.shift(offext)
355  rawPrescanBbox.shift(offext)
356  xoffset = 0
357  yoffset = 0
358  offset = lsst.geom.Extent2I(xoffset, yoffset)
359  builder.setBBox(bbox)
360  builder.setRawXYOffset(offset)
361  builder.setName(str(ampData['name']))
362  builder.setReadoutCorner(readoutMap[readcorner])
363  builder.setGain(float(ampData['gain']))
364  builder.setReadNoise(float(ampData['readnoise']))
365  linCoeffs = np.array([float(ampData['lin_coeffs']), ], dtype=float)
366  builder.setLinearityCoeffs(linCoeffs)
367  builder.setLinearityType(str(ampData['lin_type']))
368  builder.setRawFlipX(flipx)
369  builder.setRawFlipY(flipy)
370  builder.setRawBBox(rawBbox)
371  builder.setRawDataBBox(rawDataBbox)
372  builder.setRawHorizontalOverscanBBox(rawHOverscanBbox)
373  builder.setRawVerticalOverscanBBox(rawVOverscanBbox)
374  builder.setRawPrescanBBox(rawPrescanBbox)
375  builder.setLinearityThreshold(float(ampData['lin_thresh']))
376  builder.setLinearityMaximum(float(ampData['lin_max']))
377  builder.setLinearityUnits(str(ampData['lin_units']))
378  self.ampDataDictampDataDict[ampData['ccd_name']]['linInfo'][ampData['name']] = \
379  {'lincoeffs': linCoeffs, 'lintype': str(ampData['lin_type']),
380  'linthresh': float(ampData['lin_thresh']), 'linmax': float(ampData['lin_max']),
381  'linunits': str(ampData['lin_units'])}
382  ampList.append(builder)
383  return ampListDict
384 
385  def makeTestRepositoryItems(self, isLsstLike=False):
386  """Make camera config and amp catalog dictionary, using default
387  detector and amp files.
388 
389  Parameters
390  ----------
391  isLsstLike : `bool`
392  If True then there is one raw image per amplifier;
393  if False then there is one raw image per detector.
394  """
395  detFile = os.path.join(self._afwTestDataDir_afwTestDataDir, "testCameraDetectors.dat")
396  detectorConfigs = self.makeDetectorConfigsmakeDetectorConfigs(detFile)
397  ampFile = os.path.join(self._afwTestDataDir_afwTestDataDir, "testCameraAmps.dat")
398  ampListDict = self.makeAmpListsmakeAmpLists(ampFile, isLsstLike=isLsstLike)
399  camConfig = CameraConfig()
400  camConfig.name = "testCamera%s"%('LSST' if isLsstLike else 'SC')
401  camConfig.detectorList = dict((i, detConfig)
402  for i, detConfig in enumerate(detectorConfigs))
403  camConfig.plateScale = self.plateScaleplateScale
404  pScaleRad = lsst.geom.arcsecToRad(self.plateScaleplateScale)
405  radialDistortCoeffs = [0.0, 1.0/pScaleRad,
406  0.0, self.radialDistortionradialDistortion/pScaleRad]
407  tConfig = afwGeom.TransformConfig()
408  tConfig.transform.name = 'inverted'
409  radialClass = afwGeom.transformRegistry['radial']
410  tConfig.transform.active.transform.retarget(radialClass)
411  tConfig.transform.active.transform.coeffs = radialDistortCoeffs
412  tmc = TransformMapConfig()
413  tmc.nativeSys = FOCAL_PLANE.getSysName()
414  tmc.transforms = {FIELD_ANGLE.getSysName(): tConfig}
415  camConfig.transformDict = tmc
416  return camConfig, ampListDict
417 
418 
419 @inTestCase
420 def compare2DFunctions(self, func1, func2, minVal=-10, maxVal=None, nVal=5):
421  """Compare two Point2D(Point2D) functions by evaluating them over a
422  range of values.
423  """
424  if maxVal is None:
425  maxVal = -minVal
426  dVal = (maxVal - minVal) / (nVal - 1)
427  for xInd in range(nVal):
428  x = minVal + (xInd * dVal)
429  for yInd in range(nVal):
430  y = minVal + (yInd * dVal)
431  fromPoint = lsst.geom.Point2D(x, y)
432  res1 = func1(fromPoint)
433  res2 = func2(fromPoint)
434  self.assertPairsAlmostEqual(res1, res2)
435 
436 
437 @inTestCase
438 def assertTransformMapsEqual(self, map1, map2, **kwds):
439  """Compare two TransformMaps.
440  """
441  self.assertEqual(list(map1), list(map2)) # compares the sets of CameraSys
442  for sysFrom in map1:
443  for sysTo in map1:
444  with self.subTest(sysFrom=sysFrom, sysTo=sysTo):
445  transform1 = map1.getTransform(sysFrom, sysTo)
446  transform2 = map2.getTransform(sysFrom, sysTo)
447  self.compare2DFunctions(transform1.applyForward, transform2.applyForward, **kwds)
448  self.compare2DFunctions(transform1.applyInverse, transform2.applyInverse, **kwds)
449 
450 
451 @inTestCase
452 def assertAmplifiersEqual(self, amp1, amp2):
453  self.assertEqual(amp1.getName(), amp2.getName())
454  self.assertEqual(amp1.getBBox(), amp2.getBBox())
455  self.assertEqual(amp1.getGain(), amp2.getGain())
456  self.assertEqual(amp1.getReadNoise(), amp2.getReadNoise())
457  self.assertEqual(amp1.getSaturation(), amp2.getSaturation())
458  self.assertEqual(amp1.getReadoutCorner(), amp2.getReadoutCorner())
459  self.assertEqual(amp1.getSuspectLevel(), amp2.getSuspectLevel())
460  self.assertEqual(amp1.getLinearityCoeffs().shape, amp2.getLinearityCoeffs().shape)
461  self.assertFloatsEqual(amp1.getLinearityCoeffs(), amp2.getLinearityCoeffs())
462  self.assertEqual(amp1.getLinearityType(), amp2.getLinearityType())
463  self.assertEqual(amp1.getLinearityThreshold(), amp2.getLinearityThreshold())
464  self.assertEqual(amp1.getLinearityMaximum(), amp2.getLinearityMaximum())
465  self.assertEqual(amp1.getLinearityUnits(), amp2.getLinearityUnits())
466  self.assertEqual(amp1.getRawBBox(), amp2.getRawBBox())
467  self.assertEqual(amp1.getRawDataBBox(), amp2.getRawDataBBox())
468  self.assertEqual(amp1.getRawFlipX(), amp2.getRawFlipX())
469  self.assertEqual(amp1.getRawFlipY(), amp2.getRawFlipY())
470  self.assertEqual(amp1.getRawHorizontalOverscanBBox(), amp2.getRawHorizontalOverscanBBox())
471  self.assertEqual(amp1.getRawVerticalOverscanBBox(), amp2.getRawVerticalOverscanBBox())
472  self.assertEqual(amp1.getRawPrescanBBox(), amp2.getRawPrescanBBox())
473 
474 
475 @inTestCase
476 def assertDetectorsEqual(self, detector1, detector2, **kwds):
477  """Compare two Detectors.
478  """
479  self.assertEqual(detector1.getName(), detector2.getName())
480  self.assertEqual(detector1.getId(), detector2.getId())
481  self.assertEqual(detector1.getSerial(), detector2.getSerial())
482  self.assertEqual(detector1.getPhysicalType(), detector2.getPhysicalType())
483  self.assertEqual(detector1.getBBox(), detector2.getBBox())
484  self.assertEqual(detector1.getPixelSize(), detector2.getPixelSize())
485  orientationIn = detector1.getOrientation()
486  orientationOut = detector2.getOrientation()
487  self.assertEqual(orientationIn.getFpPosition(), orientationOut.getFpPosition())
488  self.assertEqual(orientationIn.getReferencePoint(), orientationOut.getReferencePoint())
489  self.assertEqual(orientationIn.getYaw(), orientationOut.getYaw())
490  self.assertEqual(orientationIn.getPitch(), orientationOut.getPitch())
491  self.assertEqual(orientationIn.getRoll(), orientationOut.getRoll())
492  self.assertFloatsEqual(detector1.getCrosstalk(), detector2.getCrosstalk())
493  self.assertTransformMapsEqual(detector1.getTransformMap(), detector2.getTransformMap(), **kwds)
494  self.assertEqual(len(detector1.getAmplifiers()), len(detector2.getAmplifiers()))
495  for amp1, amp2 in zip(detector1.getAmplifiers(), detector2.getAmplifiers()):
496  self.assertAmplifiersEqual(amp1, amp2)
497 
498 
499 @inTestCase
500 def assertDetectorCollectionsEqual(self, collection1, collection2, **kwds):
501  """Compare two DetectorCollections.
502  """
503  self.assertCountEqual(list(collection1.getNameIter()), list(collection2.getNameIter()))
504  for k in collection1.getNameIter():
505  self.assertDetectorsEqual(collection1[k], collection2[k], **kwds)
506 
507 
508 @inTestCase
509 def assertCamerasEqual(self, camera1, camera2, **kwds):
510  """Compare two Camers.
511  """
512  self.assertDetectorCollectionsEqual(camera1, camera2, **kwds)
513  self.assertTransformMapsEqual(camera1.getTransformMap(), camera2.getTransformMap())
514  self.assertEqual(camera1.getName(), camera2.getName())
515  self.assertEqual(camera1.getPupilFactoryName(), camera2.getPupilFactoryName())
A mutable Amplifier subclass class that can be used to incrementally construct or modify Amplifiers.
Definition: Amplifier.h:276
A helper class for creating and modifying cameras.
Definition: Camera.h:208
def makeTestRepositoryItems(self, isLsstLike=False)
Definition: testUtils.py:385
def makeAmpLists(self, ampFile, isLsstLike=False)
Definition: testUtils.py:254
def __init__(self, plateScale=20.0, radialDistortion=0.925, isLsstLike=False)
Definition: testUtils.py:189
def __init__(self, name="detector 1", id=1, detType=DetectorType.SCIENCE, serial="xkcd722", bbox=None, numAmps=3, pixelSize=(0.02, 0.02), ampExtent=(5, 6), orientation=Orientation(), plateScale=20.0, radialDistortion=0.925, crosstalk=None, modFunc=None, physicalType="CCD", cameraBuilder=None)
Definition: testUtils.py:102
daf::base::PropertyList * list
Definition: fits.cc:913
def makeCameraFromAmpLists(cameraConfig, ampListDict, pupilFactoryClass=PupilFactory)
def makePixelToTanPixel(bbox, orientation, focalPlaneToField, pixelSizeMm)
def assertAmplifiersEqual(self, amp1, amp2)
Definition: testUtils.py:452
def compare2DFunctions(self, func1, func2, minVal=-10, maxVal=None, nVal=5)
Definition: testUtils.py:420
def assertTransformMapsEqual(self, map1, map2, **kwds)
Definition: testUtils.py:438
def assertDetectorsEqual(self, detector1, detector2, **kwds)
Definition: testUtils.py:476
def assertCamerasEqual(self, camera1, camera2, **kwds)
Definition: testUtils.py:509
def assertDetectorCollectionsEqual(self, collection1, collection2, **kwds)
Definition: testUtils.py:500
constexpr double arcsecToRad(double x) noexcept
std::string getPackageDir(std::string const &packageName)