LSST Applications g180d380827+0f66a164bb,g2079a07aa2+86d27d4dc4,g2305ad1205+7d304bc7a0,g29320951ab+500695df56,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+e42ea45bea,g48712c4677+36a86eeaa5,g487adcacf7+2dd8f347ac,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+c70619cc9d,g5a732f18d5+53520f316c,g5ea96fc03c+341ea1ce94,g64a986408d+f7cd9c7162,g858d7b2824+f7cd9c7162,g8a8a8dda67+585e252eca,g99cad8db69+469ab8c039,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+c92fc63c7e,gbd866b1f37+f7cd9c7162,gc120e1dc64+02c66aa596,gc28159a63d+0e5473021a,gc3e9b769f7+b0068a2d9f,gcf0d15dbbd+e42ea45bea,gdaeeff99f8+f9a426f77a,ge6526c86ff+84383d05b3,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+f7cd9c7162,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
_cameraFactory.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__ = ["addDetectorBuilderFromConfig",
23 "makeCameraFromPath", "makeCameraFromAmpLists"]
24
25import os.path
26from lsst.afw.table import BaseCatalog
27from ._cameraGeom import FOCAL_PLANE, FIELD_ANGLE, PIXELS, TAN_PIXELS, ACTUAL_PIXELS, CameraSys
28from ._cameraGeom import Amplifier
29from ._camera import Camera
30from ._makePixelToTanPixel import makePixelToTanPixel
31from .pupil import PupilFactory
32
33cameraSysList = [FIELD_ANGLE, FOCAL_PLANE, PIXELS, TAN_PIXELS, ACTUAL_PIXELS]
34cameraSysMap = dict((sys.getSysName(), sys) for sys in cameraSysList)
35
36
37def addDetectorBuilderFromConfig(cameraBuilder, detectorConfig, amplifiers, focalPlaneToField):
38 """Build a dictionary of Detector constructor keyword arguments.
39
40 The returned dictionary can be passed as keyword arguments to the Detector
41 constructor, providing all required arguments. However, using these
42 arguments directly constructs a Detector with knowledge of only the
43 coordinate systems that are *directly* mapped to its own PIXELS coordinate
44 system. To construct Detectors with a shared TransformMap for the full
45 Camera, use makeCameraFromCatalogs or makeCameraFromPath instead of
46 calling this function or makeDetector directly.
47
48 Parameters
49 ----------
50 cameraBuilder : `lsst.afw.cameraGeonm.Camera.Builder`
51 Camera builder object to which the new Detector Builder
52 should be added.
53 detectorConfig : `lsst.pex.config.Config`
54 Configuration for this detector.
55 amplifiers : `list` [`~lsst.afw.cameraGeom.Amplifier`]
56 amplifier information for this detector
57 focalPlaneToField : `lsst.afw.geom.TransformPoint2ToPoint2`
58 FOCAL_PLANE to FIELD_ANGLE Transform
59
60 Returns
61 -------
62 detectorBuilder : `lsst.afw.cameraGeom.Detector.InCameraBuilder`
63 A builder object for a detector corresponding to the given config,
64 associated with the given camera builder object.
65 """
66 detectorBuilder = cameraBuilder.add(detectorConfig.name, detectorConfig.id)
67 detectorBuilder.fromConfig(detectorConfig)
68
69 for ampBuilder in amplifiers:
70 detectorBuilder.append(ampBuilder)
71
72 transforms = makeTransformDict(detectorConfig.transformDict.transforms)
73
74 # It seems the C++ code has always assumed that the "nativeSys" for
75 # detectors is PIXELS, despite the configs here giving the illusion of
76 # choice. We'll use PIXELS if the config value is None, and assert that
77 # the value is PIXELS otherwise. Note that we can't actually get rid of
78 # the nativeSys config option without breaking lots of on-disk camera
79 # configs.
80 detectorNativeSysPrefix = cameraSysMap.get(detectorConfig.transformDict.nativeSys, PIXELS)
81 assert detectorNativeSysPrefix == PIXELS, "Detectors with nativeSys != PIXELS are not supported."
82
83 for toSys, transform in transforms.items():
84 detectorBuilder.setTransformFromPixelsTo(toSys, transform)
85 tanPixSys = CameraSys(TAN_PIXELS, detectorConfig.name)
86 transforms[tanPixSys] = makePixelToTanPixel(
87 bbox=detectorBuilder.getBBox(),
88 orientation=detectorBuilder.getOrientation(),
89 focalPlaneToField=focalPlaneToField,
90 pixelSizeMm=detectorBuilder.getPixelSize(),
91 )
92
93 for toSys, transform in transforms.items():
94 detectorBuilder.setTransformFromPixelsTo(toSys, transform)
95
96 detectorBuilder.setCrosstalk(detectorConfig.getCrosstalk(len(amplifiers)))
97
98 return detectorBuilder
99
100
101def makeTransformDict(transformConfigDict):
102 """Make a dictionary of CameraSys: lsst.afw.geom.Transform from a config dict.
103
104 Parameters
105 ----------
106 transformConfigDict : value obtained from a `lsst.pex.config.ConfigDictField`
107 registry; keys are camera system names.
108
109 Returns
110 -------
111 transforms : `dict` [`CameraSys` or `CameraSysPrefix`, `lsst.afw.geom.Transform`]
112 A dict of CameraSys or CameraSysPrefix: lsst.afw.geom.Transform
113 """
114 resMap = dict()
115 if transformConfigDict is not None:
116 for key in transformConfigDict:
117 transform = transformConfigDict[key].transform.apply()
118 resMap[CameraSys(key)] = transform
119 return resMap
120
121
122def makeCameraFromPath(cameraConfig, ampInfoPath, shortNameFunc,
123 pupilFactoryClass=PupilFactory):
124 """Make a Camera instance from a directory of ampInfo files
125
126 The directory must contain one ampInfo fits file for each detector in cameraConfig.detectorList.
127 The name of each ampInfo file must be shortNameFunc(fullDetectorName) + ".fits".
128
129 Parameters
130 ----------
131 cameraConfig : `CameraConfig`
132 Config describing camera and its detectors.
133 ampInfoPath : `str`
134 Path to ampInfo data files.
135 shortNameFunc : callable
136 A function that converts a long detector name to a short one.
137 pupilFactoryClass : `type`, optional
138 Class to attach to camera; default is `lsst.afw.cameraGeom.PupilFactory`.
139
140 Returns
141 -------
142 camera : `lsst.afw.cameraGeom.Camera`
143 New Camera instance.
144 """
145 ampListDict = dict()
146 for detectorConfig in cameraConfig.detectorList.values():
147 shortName = shortNameFunc(detectorConfig.name)
148 ampCatPath = os.path.join(ampInfoPath, shortName + ".fits")
149 catalog = BaseCatalog.readFits(ampCatPath)
150 ampListDict[detectorConfig.name] = [Amplifier.Builder.fromRecord(record)
151 for record in catalog]
152
153 return makeCameraFromAmpLists(cameraConfig, ampListDict, pupilFactoryClass)
154
155
156def makeCameraFromAmpLists(cameraConfig, ampListDict,
157 pupilFactoryClass=PupilFactory):
158 """Construct a Camera instance from a dictionary of detector name: list of
159 Amplifier.Builder
160
161 Parameters
162 ----------
163 cameraConfig : `CameraConfig`
164 Config describing camera and its detectors.
165 ampListDict : `dict` [`str`, `list` [`Amplifier.Builder`]]
166 A dictionary of detector name: list of Amplifier.Builder
167 pupilFactoryClass : `type`, optional
168 Class to attach to camera; `lsst.default afw.cameraGeom.PupilFactory`.
169
170 Returns
171 -------
172 camera : `lsst.afw.cameraGeom.Camera`
173 New Camera instance.
174 """
175 nativeSys = cameraSysMap[cameraConfig.transformDict.nativeSys]
176
177 # nativeSys=FOCAL_PLANE seems is baked into the camera class definition,
178 # despite CameraConfig providing the illusion that it's configurable. Note
179 # that we can't actually get rid of the nativeSys config option without
180 # breaking lots of on-disk camera configs.
181 assert nativeSys == FOCAL_PLANE, "Cameras with nativeSys != FOCAL_PLANE are not supported."
182
183 cameraBuilder = Camera.Builder(cameraConfig.name)
184 cameraBuilder.setPupilFactoryClass(pupilFactoryClass)
185
186 transformDict = makeTransformDict(cameraConfig.transformDict.transforms)
187 focalPlaneToField = transformDict[FIELD_ANGLE]
188
189 for toSys, transform in transformDict.items():
190 cameraBuilder.setTransformFromFocalPlaneTo(toSys, transform)
191
192 for detectorConfig in cameraConfig.detectorList.values():
194 cameraBuilder,
195 detectorConfig=detectorConfig,
196 amplifiers=ampListDict[detectorConfig.name],
197 focalPlaneToField=focalPlaneToField,
198 )
199
200 return cameraBuilder.finish()
A helper class for creating and modifying cameras.
Definition Camera.h:208
addDetectorBuilderFromConfig(cameraBuilder, detectorConfig, amplifiers, focalPlaneToField)
makeCameraFromPath(cameraConfig, ampInfoPath, shortNameFunc, pupilFactoryClass=PupilFactory)
makeCameraFromAmpLists(cameraConfig, ampListDict, pupilFactoryClass=PupilFactory)