Skip to content

Commit

Permalink
Merge pull request #258 from LSSTDESC/u/jchiang/importing_cameras_fro…
Browse files Browse the repository at this point in the history
…m_obs_lsst

importing cameras from obs lsst
  • Loading branch information
jchiang87 authored Nov 10, 2021
2 parents 214dee0 + 1ff4be5 commit c8e87bd
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 31 deletions.
5 changes: 3 additions & 2 deletions config/imsim-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ eval_variables:
# updated for each output file.
# Also includes things that need some set up at the start of an exposure, like the atmospheric PSF.
input:
camera_geometry: {}

instance_catalog:
# This enables InstCat types
file_name: default_catalog_file.txt # This should be overridden in either the user config file or
Expand Down Expand Up @@ -105,6 +103,7 @@ image:
type: Batoid

# These are required:
camera: "@output.camera"
boresight: "@input.atm_psf.boresight"
rotTelPos:
type: Degrees
Expand Down Expand Up @@ -230,6 +229,8 @@ output:
nproc: 1 # Change this to work on multiple CCDs at once.
nfiles: 1 # Default is all 189 CCDs. Set to 1 while testing.

camera: LsstCam

exp_time: 30

cosmic_ray_rate: 0.2
Expand Down
6 changes: 4 additions & 2 deletions imsim/batoid_wcs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

# These need conda (via stackvana). Not pip-installable
import lsst.afw.cameraGeom as cameraGeom
from lsst.obs.lsst import LsstCamMapper

# This is not on conda yet, but is pip installable.
# We'll need to get Matt to add this to conda-forge probably.
Expand All @@ -13,6 +12,7 @@
import astropy.time
import galsim
from galsim.config import WCSBuilder, RegisterWCSType
from .camera import get_camera


# There are 5 coordinate systems to handle. In order:
Expand Down Expand Up @@ -482,7 +482,7 @@ def __init__(self):
@property
def camera(self):
if self._camera is None:
self._camera = LsstCamMapper().camera
self._camera = get_camera(self._camera_class)
return self._camera

def buildWCS(self, config, base, logger):
Expand All @@ -497,6 +497,7 @@ def buildWCS(self, config, base, logger):
the constructed WCS object (a galsim.GSFitsWCS instance)
"""
req = {
"camera": str,
"boresight": galsim.CelestialCoord,
"rotTelPos": galsim.Angle,
"obstime": None, # Either str or astropy.time.Time instance
Expand All @@ -520,6 +521,7 @@ def buildWCS(self, config, base, logger):
base['bandpass'] = bp

kwargs, safe = galsim.config.GetAllParams(config, base, req=req, opt=opt)
self._camera_class = kwargs.pop('camera')
logger.info("Building Batoid WCS for %s", kwargs['det_name'])

# If a string, convert it to astropy.time.Time.
Expand Down
33 changes: 27 additions & 6 deletions imsim/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import numpy as np
import galsim
from galsim.config import RegisterInputType, InputLoader
import lsst.obs.lsst
import lsst.utils


__all__ = ['get_camera', 'Camera']


# Crosstalk cofficients from lsst.obs.lsst.imsim.ImsimMapper. These
Expand Down Expand Up @@ -198,17 +201,38 @@ def __getattr__(self, attr):
"""Provide access to the attributes of the underlying lsst_ccd."""
return getattr(self.lsst_ccd, attr)


def get_camera(camera):
"""
Return an lsst camera object.
Parameters
----------
camera : str
The class name of the LSST camera object. Valid names
are 'LsstCam', 'LsstComCam', 'Latiss'.
Returns
-------
lsst.afw.cameraGeom.Camera
"""
valid_cameras = ('LsstCam', 'LsstComCam', 'Latiss')
if camera not in valid_cameras:
raise ValueError('Invalid camera: %s', camera)
return lsst.utils.doImport('lsst.obs.lsst.' + camera)().getCamera()


class Camera(dict):
"""
Class to represent the LSST Camera as a dictionary of CCD objects,
keyed by the CCD name in the focal plane, e.g., 'R01_S00'.
"""
def __init__(self, instrument_class=lsst.obs.lsst.LsstCam, logger=None):
def __init__(self, camera_class='LsstCam'):
"""
Initialize a Camera object from the lsst instrument class.
"""
super().__init__()
self.lsst_camera = instrument_class().getCamera()
self.lsst_camera = get_camera(camera_class)
for lsst_ccd in self.lsst_camera:
self[lsst_ccd.getName()] = CCD.make_ccd_from_lsst(lsst_ccd)

Expand All @@ -226,6 +250,3 @@ def update(self, other):
def __getattr__(self, attr):
"""Provide access to the attributes of the underlying lsst_camera."""
return getattr(self.lsst_camera, attr)


RegisterInputType('camera_geometry', InputLoader(Camera, takes_logger=True))
22 changes: 4 additions & 18 deletions imsim/ccd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,13 @@
from galsim.config import OutputBuilder, RegisterOutputType
from .cosmic_rays import CosmicRays
from .meta_data import data_dir
from .camera import get_camera

class LSST_CCDBuilder(OutputBuilder):
"""This runs the overall generation of an LSST CCD file.
Most of the defaults work fine. There are a few extra things we do that are LSST-specific.
"""
rafts = [ 'R01', 'R02', 'R03',
'R10', 'R11', 'R12', 'R13', 'R14',
'R20', 'R21', 'R22', 'R23', 'R24',
'R30', 'R31', 'R32', 'R33', 'R34',
'R41', 'R42', 'R43'
]
sensors = [ 'S00', 'S01', 'S02',
'S10', 'S11', 'S12',
'S20', 'S21', 'S22'
]

def setup(self, config, base, file_num, logger):
"""Do any necessary setup at the start of processing a file.
Expand All @@ -35,13 +26,8 @@ def setup(self, config, base, file_num, logger):

# Figure out the detector name for the file name.
detnum = galsim.config.ParseValue(config, 'det_num', base, int)[0]
# Detectors have names Rij_Smn
# We need to run through them in a predictable way for detnum = 0..188
raft = detnum // 9 # 0..20
sensor = detnum % 9 # 0..8
raft = self.rafts[raft]
sensor = self.sensors[sensor]
det_name = raft + '_' + sensor
camera = get_camera(config['camera'])
det_name = camera[detnum].getName()
base['det_name'] = det_name
if 'eval_variables' not in base:
base['eval_variables'] = {}
Expand Down Expand Up @@ -88,7 +74,7 @@ def buildImages(self, config, base, file_num, image_num, obj_num, ignore, logger
# This is basically the same as the base class version. Just a few extra things to
# add to the ignore list.
ignore += [ 'file_name', 'dir', 'nfiles', 'checkpoint', 'det_num',
'readout', 'exp_time' ]
'readout', 'exp_time', 'camera' ]

opt = {
'cosmic_ray_rate': float,
Expand Down
6 changes: 3 additions & 3 deletions imsim/readout.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import galsim
from galsim.config import ExtraOutputBuilder, RegisterExtraOutput
from .bleed_trails import bleed_eimage
from .camera import Camera

def section_keyword(bounds, flipx=False, flipy=False):
"""Package image bounds as a NOAO image section keyword value."""
Expand Down Expand Up @@ -110,9 +111,8 @@ def __init__(self, config, base, rng=None):
if self.rng is None:
seed = galsim.config.SetupConfigRNG(base)
self.rng = galsim.BaseDeviate(seed)
self.det_name = base['det_name'].replace('-', '_')
camera = galsim.config.GetInputObj('camera_geometry', config, base,
'Camera')
self.det_name = base['det_name']
camera = Camera(base['output']['camera'])
self.ccd = camera[self.det_name]
amp = list(self.ccd.values())[0]
scti = config['scti']
Expand Down

0 comments on commit c8e87bd

Please sign in to comment.