Hello community!
I’m in the process of designing a full-field optical PSF model for the LSST stack. One of the necessary ingredients for this is a model of the pupil obscuration function, i.e., which parts of the pupil (more-or-less the primary mirror) are visible and reflect sky as opposed to struts, camera, etc. This boolean function will vary with position on the focal plane and the camera rotator angle, and it is probably a good idea to make the size and resolution of the output array configurable as well.
Looking through the available LSST packages, and talking/slacking with @KSK, @jbosch, and @RHL, I think afw.cameraGeom.Camera
looks like the natural home for such a product. My understanding is that for a given data repository, cameras are uniquely accessible from the butler (i.e., there is exactly one Camera
per data repo). So the PSF modeling code could access the Pupil
through the repo Camera
which is accessible through the Butler
. Alternatively, the Pupil
could exist at the same level as the Camera
instead of being an attribute thereof, and directly accessible by the Butler
. I personally favor the former approach though as it prevents enabling incompatible Camera
/Pupil
combinations.
I have a few additional implementation questions:
-
Should the pupil obscuration function be persistable? The pupil model I have in mind consists of set operations on various 2D geometric objects – circles, rays-with-finite-width, rectangles, … The parameters of each geometric object depend (linearly for now) on the focal plane position and trigonometrically on the camera rotator angle, which means it may be possible to create a generic
PupilConfig
format that could be persisted, and used to represent different cameras, or possibly different levels of complexity for a given camera. I’m not convinced at the moment, however, that this is actually worth the effort. It would be much simpler to just implement a specific class for each camera (all derived from the same abstract base class), and then attach that to theCamera
object. -
I think it makes sense to split the input arguments into rotator angle, size/scale params (which will be held constant for a given exposure) and focal plane x/y which, of course, vary object to object. So it may make sense to attach a camera-specific
PupilFactory
to theCamera
object, which has agetPupil(VisitInfo, size, scale)
method that returns aPupil
object. ThePupil
object itself would then be callable or have a callable method as a function of focal plane x/y, returning a boolean array. -
As for actually attaching the
PupilFactory
to theCamera
, I see that, at least for HSC in obs_subaru, theCamera
is constructed though the chain
HscMapper.__init__
CameraMapper.__init__
CameraMapper._makeCamera
cameraGeom.makeCameraFromPath
cameraGeom.Camera.__init__
So one possibility would be to add a pupilFactory
kwarg to Camera.__init__
and make sure makeCameraFromPath
(and any other camera factories) use it. CameraMapper
could have a class variable PupilFactoryClass
(similar to MakeRawVisitInfoClass
) pointing to a default PupilFactory
(possibly the ABC) and HscMapper.PupilFactoryClass
could override this by pointing to HscPupilFactory
. Then when _makeCamera
gets called, it uses self.PupilFactoryClass
to pass to makeCameraFromPath
.
Thoughts?
Also, does any of this require an RFC?
Thanks,
-Josh