LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
_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 
25 import os.path
26 from lsst.afw.table import BaseCatalog
27 from ._cameraGeom import FOCAL_PLANE, FIELD_ANGLE, PIXELS, TAN_PIXELS, ACTUAL_PIXELS, CameraSys
28 from ._cameraGeom import Amplifier
29 from ._camera import Camera
30 from ._makePixelToTanPixel import makePixelToTanPixel
31 from .pupil import PupilFactory
32 
33 cameraSysList = [FIELD_ANGLE, FOCAL_PLANE, PIXELS, TAN_PIXELS, ACTUAL_PIXELS]
34 cameraSysMap = dict((sys.getSysName(), sys) for sys in cameraSysList)
35 
36 
37 def 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 
101 def 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 
122 def 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 
156 def 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
def makeCameraFromAmpLists(cameraConfig, ampListDict, pupilFactoryClass=PupilFactory)
def makeTransformDict(transformConfigDict)
def makeCameraFromPath(cameraConfig, ampInfoPath, shortNameFunc, pupilFactoryClass=PupilFactory)
def addDetectorBuilderFromConfig(cameraBuilder, detectorConfig, amplifiers, focalPlaneToField)
def makePixelToTanPixel(bbox, orientation, focalPlaneToField, pixelSizeMm)