Skip to content

Commit

Permalink
Merge pull request #224 from LSSTDESC/u/jchiang/disable_read_noise_an…
Browse files Browse the repository at this point in the history
…d_bias_option

add options to disable sky model, and read noise, bias level, and dark current
  • Loading branch information
jchiang87 committed Aug 2, 2019
2 parents 9950955 + 4b3e1f0 commit c7654ac
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 8 deletions.
4 changes: 4 additions & 0 deletions data/default_imsim_configs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ dark_current = 0.02
bias_level = 1000.
pcti = 1e-6
scti = 1e-6
disable_readnoise_bias_darkcurrent = False

[sky_model]
disable_sky_model = False

[ccd]
full_well = 1e5
Expand Down
4 changes: 3 additions & 1 deletion python/desc/imsim/ImageSimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ def _make_gs_interpreters(self, seed, sensor_list, file_id):
InstCatTrimmer object in gs_obj_dict can be recovered.
"""
bp_dict = BandpassDict.loadTotalBandpassesFromFiles(bandpassNames=self.obs_md.bandpass)
disable_sky_model = self.config['sky_model']['disable_sky_model']
noise_and_background \
= make_sky_model(self.obs_md, self.phot_params, seed=seed,
apply_sensor_model=self.apply_sensor_model)
apply_sensor_model=self.apply_sensor_model,
disable_sky_model=disable_sky_model)
self.gs_interpreters = dict()
for det in self.camera_wrapper.camera:
det_type = det.getType()
Expand Down
19 changes: 13 additions & 6 deletions python/desc/imsim/camera_readout.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
from .camera_info import CameraInfo, getHourAngle
from .imSim import get_logger, get_config, airmass
from .cosmic_rays import CosmicRays
from .version import __version__ as imsim_version

__all__ = ['ImageSource', 'set_itl_bboxes', 'set_e2v_bboxes',
'set_phosim_bboxes', 'set_noao_keywords', 'cte_matrix']

config = get_config()
class ImageSource(object):
'''
Class to create single segment images based on the pixel geometry
Expand Down Expand Up @@ -85,6 +85,8 @@ def __init__(self, image_array, exptime, sensor_id, visit=42, logger=None):
else:
self.logger = logger

self.config = get_config()

self.eimage = fits.HDUList()
self.eimage.append(fits.PrimaryHDU(image_array))
self.eimage_data = self.eimage[0].data.transpose()
Expand Down Expand Up @@ -259,6 +261,9 @@ def _make_amp_images(self):
for amp_name in amp_names:
self._make_amp_image(amp_name)
self._apply_crosstalk()
if self.config['electronics_readout']\
['disable_readnoise_bias_darkcurrent']:
return
for amp_name in amp_names:
self._add_read_noise_and_bias(amp_name)

Expand Down Expand Up @@ -291,8 +296,9 @@ def _make_amp_image(self, amp_name):
imaging_segment.getArray()[:] = data

# Add dark current.
if self.exptime > 0:
dark_current = config['electronics_readout']['dark_current']
if (self.exptime > 0 and not self.config['electronics_readout']
['disable_readnoise_bias_darkcurrent']):
dark_current = self.config['electronics_readout']['dark_current']
imaging_arr = imaging_segment.getArray()
rng = galsim.PoissonDeviate(seed=self.rng,
mean=dark_current*self.exptime)
Expand All @@ -304,12 +310,12 @@ def _make_amp_image(self, amp_name):

# Apply CTE.
full_arr = full_segment.getArray()
pcti = config['electronics_readout']['pcti']
pcti = self.config['electronics_readout']['pcti']
pcte_matrix = cte_matrix(full_arr.shape[0], pcti)
for col in range(0, full_arr.shape[1]):
full_arr[:, col] = np.dot(pcte_matrix, full_arr[:, col])

scti = config['electronics_readout']['scti']
scti = self.config['electronics_readout']['scti']
scte_matrix = cte_matrix(full_arr.shape[1], scti)
for row in range(0, full_arr.shape[0]):
full_arr[row, :] = np.dot(scte_matrix, full_arr[row, :])
Expand All @@ -336,7 +342,7 @@ def _add_read_noise_and_bias(self, amp_name):
rn_data = np.zeros(np.prod(full_arr.shape))
rng.generate(rn_data)
full_arr += rn_data.reshape(full_arr.shape)
full_arr += config['electronics_readout']['bias_level']
full_arr += self.config['electronics_readout']['bias_level']

@property
def rng(self):
Expand Down Expand Up @@ -470,6 +476,7 @@ def write_fits_file(self, outfile, overwrite=True, run_number=None,
output[0].header.insert(5, ('WCSAXES', wcsaxes, ''))
if run_number is None:
run_number = self.visit
output[0].header['IMSIMVER'] = imsim_version
output[0].header['RUNNUM'] = str(run_number)
output[0].header['DARKTIME'] = output[0].header['EXPTIME']
output[0].header['TIMESYS'] = 'TAI'
Expand Down
24 changes: 23 additions & 1 deletion python/desc/imsim/skyModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

def make_sky_model(obs_metadata, photParams, seed=None, bandpassDict=None,
addNoise=True, addBackground=True, apply_sensor_model=False,
logger=None, fast_silicon=True):
logger=None, fast_silicon=True, disable_sky_model=False):
"Function to provide ESOSkyModel object."
if disable_sky_model:
return NullSkyModel()
if apply_sensor_model:
if fast_silicon:
return FastSiliconSkyModel(obs_metadata, photParams,
Expand Down Expand Up @@ -118,6 +120,26 @@ def get_chip_center(chip_name, camera):
return center_x, center_y


class NullSkyModel(NoiseAndBackgroundBase):
"""
Class to disable the sky model entirely. Can be used to produce
FITS file for object injection or for testing individual object
rendering.
"""
def __init__(self):
pass

def addNoiseAndBackground(self, image, **kwds):
"""
Return the image as-is, i.e., without adding any sky background
photons.
"""
return image

def sky_counts(self, chipName):
"""Return zero sky background counts."""
return 0

class ESOSkyModel(NoiseAndBackgroundBase):
"""
This class wraps the GalSim class CCDNoise. This derived class returns
Expand Down
Binary file modified tests/data/lsst_e_161899_R22_S11_r.fits.gz
Binary file not shown.
8 changes: 8 additions & 0 deletions tests/test_camera_readout.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ def test_get_amp_image(self):
image = self.image_source.get_amp_image(amp_info_record)
self.assertTupleEqual(image.getArray().shape, (2048, 544))

def test_raw_file_headers(self):
"Test contents of raw file headers."
outfile = 'raw_file_test.fits'
self.image_source.write_fits_file(outfile)
with fits.open(outfile) as hdus:
self.assertEqual(hdus[0].header['IMSIMVER'], desc.imsim.__version__)
os.remove(outfile)


class NoaoKeywordTestCase(unittest.TestCase):
"TestCase class for raft-level NOAO mosaicking keywords"
Expand Down
13 changes: 13 additions & 0 deletions tests/test_skyModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,18 @@ def test_skycounts_function(self):
skycounts_persec_u = skycounts_persec('u', 24)
self.assertAlmostEqual(skycounts_persec_u.value, self.zp_u)

def test_NullSkyModel(self):
"""Test that the NullSkyModel adds zero photons."""
commands = copy.deepcopy(self.commands)
photParams = desc.imsim.photometricParameters(commands)
null_sky_model = desc.imsim.make_sky_model(self.obs_md, photParams,
disable_sky_model=True)
nx, ny = 30, 30
image = galsim.Image(nx, ny)
image = null_sky_model.addNoiseAndBackground(image,
photParams=photParams,
detector=self.detector())
self.assertEqual(0, np.sum(image.array.ravel()))

if __name__ == '__main__':
unittest.main()

0 comments on commit c7654ac

Please sign in to comment.