LSSTApplications  20.0.0
LSSTDataManagementBasePackage
testCamera.py
Go to the documentation of this file.
1 # This file is part of obs_test.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://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 <http://www.gnu.org/licenses/>.
21 #
22 __all__ = ["TestCamera"]
23 
24 import numpy as np
25 
26 import lsst.afw.cameraGeom as cameraGeom
27 import lsst.geom as geom
28 import lsst.afw.geom as afwGeom
29 
30 
31 class TestCamera(cameraGeom.Camera):
32  """A simple test Camera.
33 
34  Notes
35  -----
36  The camera has one ccd with name "0".
37  That CCD has four amplifiers with names "00", "01", "10", and "11".
38 
39  The camera is modeled after a small portion of the LSST sim
40  Summer 2012 camera: a single detector with four amplifiers,
41  consisting of raft 2,2 sensor 0,0, half of channels 0,0 0,1 1,0 and 1,1
42  (the half closest to the Y centerline).
43 
44  Note that the Summer 2012 camera has one very weird feature:
45  the bias region (rawHOverscanBbox) is actually a prescan
46  (it appears before the data pixels).
47 
48  A raw image has the sky in the same orientation on all amplifier
49  subregions, so no amplifier subregions need their pixels to be flipped.
50 
51  Standard keys are:
52 
53  * ``amp``: amplifier number: one of 00, 01, 10, 11
54  * ``ccd``: ccd number: always 0
55  * ``visit``: exposure number; test data includes one exposure
56  with visit=1
57  """
58  def __new__(cls):
59  plateScale = geom.Angle(20, geom.arcseconds) # plate scale, in angle on sky/mm
60  # Radial distortion is modeled as a radial polynomial that converts from focal plane (in mm)
61  # to field angle (in radians). Thus the coefficients are:
62  # C0: always 0, for continuity at the center of the focal plane; units are rad
63  # C1: 1/plateScale; units are rad/mm
64  # C2: usually 0; units are rad/mm^2
65  # C3: radial distortion; units are rad/mm^3
66  radialCoeff = np.array([0.0, 1.0, 0.0, 0.925]) / plateScale.asRadians()
67  fieldAngleToFocalPlane = afwGeom.makeRadialTransform(radialCoeff)
68  focalPlaneToFieldAngle = fieldAngleToFocalPlane.inverted()
69 
70  camera = cameraGeom.Camera.Builder("test")
71  cls._makeDetectors(camera, focalPlaneToFieldAngle)
72  camera.setTransformFromFocalPlaneTo(cameraGeom.FIELD_ANGLE, focalPlaneToFieldAngle)
73  return camera.finish()
74 
75  def __init__(self):
76  pass
77 
78  @classmethod
79  def _makeDetectors(cls, camera, focalPlaneToFieldAngle):
80  """Make a list of detectors
81 
82  Parameters
83  ----------
84  camera : `lsst.afw.cameraGeom.camera.Builder`
85  Camera to append detectors to.
86  focalPlaneToFieldAngle : `lsst.afw.geom.TransformPoint2ToPoint2`
87  Transform from ``FOCAL_PLANE`` to ``FIELD_ANGLE`` coordinates
88  in the forward direction.
89  """
90  detectorConfigList = cls._makeDetectorConfigList()
91  for detectorConfig in detectorConfigList:
92  amplifiers = cls._makeAmplifierCatalog()
93  detBuilder = cameraGeom.addDetectorBuilderFromConfig(
94  camera,
95  detectorConfig,
96  amplifiers,
97  focalPlaneToFieldAngle,
98  )
99  if detBuilder is None:
100  raise RuntimeError("Could not add detector!")
101 
102  @classmethod
103  def _makeDetectorConfigList(cls):
104  """Make a list of detector configs
105 
106  Returns
107  -------
108  detectorConfigList : `list` of `lsst.afw.cameraGeom.DetectorConfig`
109  List of detector configs.
110  """
111  # this camera has one detector that corresponds to a subregion of lsstSim detector R:2,2 S:0,0
112  # with lower left corner 0, 1000 and dimensions 1018 x 2000
113  # i.e. half of each of the following channels: 0,0, 0,1, 1,0 and 1,1
114  detector0Config = cameraGeom.DetectorConfig()
115  detector0Config.name = '0'
116  detector0Config.id = 0
117  detector0Config.serial = '0000011'
118  detector0Config.detectorType = 0
119  detector0Config.bbox_x0 = 0
120  detector0Config.bbox_x1 = 1017
121  detector0Config.bbox_y0 = 0
122  detector0Config.bbox_y1 = 1999
123  detector0Config.pixelSize_x = 0.01
124  detector0Config.pixelSize_y = 0.01
125  detector0Config.transformDict.nativeSys = 'Pixels'
126  detector0Config.transformDict.transforms = None
127  detector0Config.refpos_x = 2035.5
128  detector0Config.refpos_y = 999.5
129  detector0Config.offset_x = -42.26073
130  detector0Config.offset_y = -42.21914
131  detector0Config.transposeDetector = False
132  detector0Config.pitchDeg = 0.0
133  detector0Config.yawDeg = 90.0
134  detector0Config.rollDeg = 0.0
135  return [detector0Config]
136 
137  @classmethod
138  def _makeAmplifierCatalog(cls):
139  """Construct an amplifier info catalog
140 
141  Returns
142  -------
143  ampCatalog : `List` of `lsst.afw.cameraGeom.Amplifier.Builder()
144  Amplifier information catalog.
145 
146  Notes
147  -----
148  The LSSTSim S12 amplifiers are unusual in that they start with 4 pixels
149  of usable bias region (which is used to set rawHOverscanBbox, despite the name),
150  followed by the data. There is no other underscan or overscan.
151  """
152  xDataExtent = 509 # trimmed
153  yDataExtent = 1000
154  xBiasExtent = 4
155  xRawExtent = xDataExtent + xBiasExtent
156  yRawExtent = yDataExtent
157  readNoise = 3.975 # amplifier read noise, in e-
158  saturationLevel = 65535
159  linearityType = cameraGeom.NullLinearityType
160  linearityCoeffs = [0, 0, 0, 0]
161 
162  ampCatalog = []
163  for ampX in (0, 1):
164  for ampY in (0, 1):
165  # amplifier gain (e-/ADU) and read noiuse (ADU/pixel) from lsstSim raw data
166  # note that obs_test amp <ampX><ampY> = lsstSim amp C<ampY>,<ampX> (axes are swapped)
167  gain = {
168  (0, 0): 1.7741, # C0,0
169  (0, 1): 1.65881, # C1,0
170  (1, 0): 1.74151, # C0,1
171  (1, 1): 1.67073, # C1,1
172  }[(ampX, ampY)]
173  readNoise = {
174  (0, 0): 3.97531706217237, # C0,0
175  (0, 1): 4.08263755342685, # C1,0
176  (1, 0): 4.02753931932633, # C0,1
177  (1, 1): 4.1890610691135, # C1,1
178  }[(ampX, ampY)]
179  amplifier = cameraGeom.Amplifier.Builder()
180  amplifier.setName("%d%d" % (ampX, ampY))
181  amplifier.setBBox(geom.Box2I(
182  geom.Point2I(ampX * xDataExtent, ampY * yDataExtent),
183  geom.Extent2I(xDataExtent, yDataExtent),
184  ))
185 
186  x0Raw = ampX * xRawExtent
187  y0Raw = ampY * yRawExtent
188 
189  # bias region (which is prescan, in this case) is before the data
190  readCorner = cameraGeom.ReadoutCorner.LL
191  x0Bias = x0Raw
192  x0Data = x0Bias + xBiasExtent
193 
194  amplifier.setRawBBox(geom.Box2I(
195  geom.Point2I(x0Raw, y0Raw),
196  geom.Extent2I(xRawExtent, yRawExtent),
197  ))
198  amplifier.setRawDataBBox(geom.Box2I(
199  geom.Point2I(x0Data, y0Raw),
200  geom.Extent2I(xDataExtent, yDataExtent),
201  ))
202  amplifier.setRawHorizontalOverscanBBox(geom.Box2I(
203  geom.Point2I(x0Bias, y0Raw),
204  geom.Extent2I(xBiasExtent, yRawExtent),
205  ))
206  amplifier.setRawXYOffset(geom.Extent2I(x0Raw, y0Raw))
207  amplifier.setReadoutCorner(readCorner)
208  amplifier.setGain(gain)
209  amplifier.setReadNoise(readNoise)
210  amplifier.setSaturation(saturationLevel)
211  amplifier.setSuspectLevel(float("nan"))
212  amplifier.setLinearityCoeffs([float(val) for val in linearityCoeffs])
213  amplifier.setLinearityType(linearityType)
214  # amplifier.setHasRawInfo(True)
215  amplifier.setRawFlipX(False)
216  amplifier.setRawFlipY(False)
217  amplifier.setRawVerticalOverscanBBox(geom.Box2I()) # no vertical overscan
218  amplifier.setRawPrescanBBox(geom.Box2I()) # no horizontal prescan
219  ampCatalog.append(amplifier)
220  return ampCatalog
lsst.obs.test.testCamera.TestCamera._makeDetectorConfigList
def _makeDetectorConfigList(cls)
Definition: testCamera.py:103
lsst.obs.test.testCamera.TestCamera.__new__
def __new__(cls)
Definition: testCamera.py:58
lsst::afw::geom::makeRadialTransform
std::shared_ptr< TransformPoint2ToPoint2 > makeRadialTransform(std::vector< double > const &forwardCoeffs, std::vector< double > const &inverseCoeffs)
A purely radial polynomial distortion.
Definition: transformFactory.cc:183
lsst.obs.test.testCamera.TestCamera.__init__
def __init__(self)
Definition: testCamera.py:75
lsst.obs.test.testCamera.TestCamera
Definition: testCamera.py:31
lsst::geom
Definition: geomOperators.dox:4
lsst::afw::cameraGeom
Definition: Amplifier.h:33
lsst.obs.test.testCamera.TestCamera._makeAmplifierCatalog
def _makeAmplifierCatalog(cls)
Definition: testCamera.py:138
lsst::geom::Point< int, 2 >
lsst::geom::Angle
A class representing an angle.
Definition: Angle.h:127
lsst::geom::Box2I
An integer coordinate rectangle.
Definition: Box.h:55
lsst.obs.test.testCamera.TestCamera._makeDetectors
def _makeDetectors(cls, camera, focalPlaneToFieldAngle)
Definition: testCamera.py:79
lsst::geom::Extent< int, 2 >
lsst::afw::geom
Definition: frameSetUtils.h:40