Coverage for python/lsst/obs/sdss/makeCamera.py : 10%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3# Copyright 2008, 2009, 2010 LSST Corporation.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <http://www.lsstcorp.org/LegalNotices/>.
21#
22import os
24import lsst.utils
25import lsst.afw.geom as afwGeom
26import lsst.afw.cameraGeom.utils as cameraGeomUtils
27from lsst.afw.cameraGeom import makeCameraFromAmpLists, CameraConfig, DetectorConfig, \
28 TransformMapConfig, DetectorType, PIXELS, FIELD_ANGLE, FOCAL_PLANE, NullLinearityType
29import lsst.afw.table as afwTable
30import lsst.geom as geom
31from lsst.obs.sdss.convertOpECalib import SdssCameraState
33#
34# Make an Amp
35#
38def addAmp(ampCatalog, i, eparams):
39 """ Add an amplifier to an AmpInfoCatalog
41 @param ampCatalog: An instance of an AmpInfoCatalog object to fill with amp properties
42 @param i which amplifier? (i == 0 ? left : right)
43 @param eparams: Electronic parameters. This is a list of tuples with (i, params),
44 where params is a dictionary of electronic parameters.
45 """
46 #
47 # Layout of active and overclock pixels in the as-readout data The layout is:
48 # Amp0 || extended | overclock | data || data | overclock | extended || Amp1
49 # for each row; all rows are identical in drift-scan data
50 #
51 height = 1361 # number of rows in a frame
52 width = 1024 # number of data pixels read out through one amplifier
53 nExtended = 8 # number of pixels in the extended register
54 nOverclock = 32 # number of (horizontal) overclock pixels
55 #
56 # Construct the needed bounding boxes given that geometrical information.
57 #
58 # Note that all the offsets are relative to the origin of this amp, not to its eventual
59 # position in the CCD
60 #
61 record = ampCatalog.addNew()
62 xtot = width + nExtended + nOverclock
63 allPixels = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(xtot, height))
64 biasSec = geom.BoxI(geom.PointI(nExtended if i == 0 else width, 0),
65 geom.ExtentI(nOverclock, height))
66 dataSec = geom.BoxI(geom.PointI(nExtended + nOverclock if i == 0 else 0, 0),
67 geom.ExtentI(width, height))
68 emptyBox = geom.BoxI()
69 bbox = geom.BoxI(geom.PointI(0, 0), geom.ExtentI(width, height))
70 bbox.shift(geom.Extent2I(width*i, 0))
72 shiftp = geom.Extent2I(xtot*i, 0)
73 allPixels.shift(shiftp)
74 biasSec.shift(shiftp)
75 dataSec.shift(shiftp)
77 record.setBBox(bbox)
78 record.setRawXYOffset(geom.ExtentI(0, 0))
79 record.setName('left' if i == 0 else 'right')
80 record.setReadoutCorner(afwTable.LL if i == 0 else afwTable.LR)
81 record.setGain(eparams['gain'])
82 record.setReadNoise(eparams['readNoise'])
83 record.setSaturation(eparams['fullWell'])
84 record.setSuspectLevel(float("nan"))
85 record.setLinearityType(NullLinearityType)
86 record.setLinearityCoeffs([1., ])
87 record.setHasRawInfo(True)
88 record.setRawFlipX(False)
89 record.setRawFlipY(False)
90 record.setRawBBox(allPixels)
91 record.setRawDataBBox(dataSec)
92 record.setRawHorizontalOverscanBBox(biasSec)
93 record.setRawVerticalOverscanBBox(emptyBox)
94 record.setRawPrescanBBox(emptyBox)
96#
97# Make a Ccd out of 2 Amps
98#
101def makeCcd(ccdName, ccdId, offsetPoint):
102 """make the information necessary to build a set detector
103 @param ccdName: string name of the ccd
104 @param ccdId: Integer id of the ccd
105 @param offsetPoint: Point2D position of the center of the ccd in mm
106 @return a dict of a DetectorConfig and an AmpInfoCatalog
107 """
108 obsSdssDir = lsst.utils.getPackageDir('obs_sdss')
109 opDir = os.path.join(obsSdssDir, "etc")
110 sc = SdssCameraState(opDir, "opConfig-50000.par", "opECalib-50000.par")
111 eparams = sc.getEParams(ccdName)
112 width = 1024*2
113 height = 1361
115 pixelSize = 24e-3 # pixel size in mm
116 schema = afwTable.AmpInfoTable.makeMinimalSchema()
117 ampCatalog = afwTable.AmpInfoCatalog(schema)
118 for i in range(2):
119 addAmp(ampCatalog, i, eparams[i][1])
120 detConfig = DetectorConfig()
121 detConfig.name = ccdName
122 detConfig.id = ccdId
123 detConfig.bbox_x0 = 0
124 detConfig.bbox_y0 = 0
125 detConfig.bbox_x1 = width - 1
126 detConfig.bbox_y1 = height - 1
127 detConfig.serial = ccdName
128 detConfig.detectorType = DetectorType.SCIENCE
129 detConfig.offset_x = offsetPoint.getX()
130 detConfig.offset_y = offsetPoint.getY()
131 detConfig.refpos_x = (width-1)/2.
132 detConfig.refpos_y = (height-1)/2.
133 detConfig.yawDeg = 0.
134 detConfig.pitchDeg = 0.
135 detConfig.rollDeg = 0.
136 detConfig.pixelSize_x = pixelSize
137 detConfig.pixelSize_y = pixelSize
138 detConfig.transposeDetector = False
139 detConfig.transformDict.nativeSys = PIXELS.getSysName()
140 return {'ccdConfig': detConfig, 'ampInfo': ampCatalog}
142#
143# Make a Camera out of 6 dewars and 5 chips per dewar
144#
147def makeCamera(name="SDSS", outputDir=None):
148 """Make a camera
149 @param name: name of the camera
150 @param outputDir: If not None, write the objects used to make the camera to this location
151 @return a camera object
152 """
153 camConfig = CameraConfig()
154 camConfig.name = name
155 camConfig.detectorList = {}
156 camConfig.plateScale = 16.5 # arcsec/mm
157 pScaleRad = geom.arcsecToRad(camConfig.plateScale)
158 radialDistortCoeffs = [0.0, 1.0/pScaleRad]
159 tConfig = afwGeom.TransformConfig()
160 tConfig.transform.name = 'inverted'
161 radialClass = afwGeom.transformRegistry['radial']
162 tConfig.transform.active.transform.retarget(radialClass)
163 tConfig.transform.active.transform.coeffs = radialDistortCoeffs
164 tmc = TransformMapConfig()
165 tmc.nativeSys = FOCAL_PLANE.getSysName()
166 tmc.transforms = {FIELD_ANGLE.getSysName(): tConfig}
167 camConfig.transformDict = tmc
169 ccdId = 0
170 ampInfoCatDict = {}
171 for i in range(6):
172 dewarName = str(i+1)
173 filters = "riuzg"
174 for j, c in enumerate(reversed(filters)):
175 ccdName = "%s%s" % (c, dewarName)
176 offsetPoint = geom.Point2D(25.4*2.5*(2.5-i), 25.4*2.1*(2.0 - j))
177 ccdInfo = makeCcd(ccdName, ccdId, offsetPoint)
178 ampInfoCatDict[ccdName] = ccdInfo['ampInfo']
179 camConfig.detectorList[ccdId] = ccdInfo['ccdConfig']
180 ccdId += 1
181 if outputDir is not None:
182 camConfig.save(os.path.join(outputDir, 'camera.py'))
183 for k in ampInfoCatDict:
184 ampInfoCatDict[k].writeFits(os.path.join(outputDir, "%s.fits"%(k)))
185 return makeCameraFromAmpLists(camConfig, ampInfoCatDict)
187#
188# Print a Ccd
189#
192def printCcd(title, ccd, trimmed=True, indent=""):
193 """Print info about a ccd
194 @param title: title for the ccd
195 @param ccd: Detector object to interrogate
196 @param trimmed: Find out information about a trimmed ccd?
197 @param indent: Prefix to each output line
198 """
199 print(indent, title, "CCD: ", ccd.getName())
200 if trimmed:
201 allPixels = ccd.getBBox()
202 else:
203 allPixels = cameraGeomUtils.calcRawCcdBBox(ccd)
204 print(indent, "Total size: %dx%d" % (allPixels.getWidth(), allPixels.getHeight()))
205 for i, amp in enumerate(ccd):
206 biasSec = amp.getRawHorizontalOverscanBBox()
207 dataSec = amp.getRawDataBBox()
209 print(indent, " Amp: %s gain: %g" % (amp.getName(),
210 amp.getGain()))
212 print(indent, " bias sec: %dx%d+%d+%d" % (biasSec.getWidth(), biasSec.getHeight(),
213 biasSec.getMinX(), biasSec.getMinY()))
215 print(indent, " data sec: %dx%d+%d+%d" % (dataSec.getWidth(), dataSec.getHeight(),
216 dataSec.getMinX(), dataSec.getMinY()))
217 if i == 0:
218 print()
220#
221# Print a Camera
222#
225def printCamera(title, camera):
226 """Print information about a camera
227 @param title: title for camera output
228 @param camera: Camera object to use to print the information
229 """
230 print(title, "Camera:", camera.getName())
232 for det in camera:
233 print("%s %dx%d centre (mm): %s" %
234 (det.getName(),
235 det.getBBox().getWidth(), det.getBBox().getHeight(),
236 det.getCenter(FOCAL_PLANE)))
239def main():
240 camera = makeCamera("SDSS")
242 print()
243 printCamera("", camera)
245 ccd = camera["r1"]
247 printCcd("Raw ", ccd, trimmed=False)
249 print()
250 printCcd("Trimmed ", ccd, trimmed=True)
253if __name__ == "__main__": 253 ↛ 254line 253 didn't jump to line 254, because the condition on line 253 was never true
254 main()