Skip to content

Commit 387adb5

Browse files
authored
Fix readnoise pixfrac scaling (#350)
* Make astropy times use isot under-the-hood. * Fix read noise scaling with pixscalefrac in L3 generation.
1 parent b054234 commit 387adb5

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

romanisim/l3.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,10 @@ def simulate(shape, wcs, efftimes, filter_name, catalog, nexposures=1,
398398
# Set effective read noise
399399
if effreadnoise is None:
400400
readnoise = np.median(romanisim.parameters.reference_data['readnoise'])
401+
# read noise in DN
401402
gain = np.median(romanisim.parameters.reference_data['gain'])
402403
effreadnoise = (
403-
np.sqrt(2) * readnoise * gain)
404+
np.sqrt(2) * readnoise * gain) # electron, difference of two reads
404405
# sqrt(2) from subtracting one read from another
405406
effreadnoise /= (np.median(efftimes * pixscalefrac ** 2) / nexposures)
406407
# divided by the typical exposure length
@@ -412,10 +413,10 @@ def simulate(shape, wcs, efftimes, filter_name, catalog, nexposures=1,
412413
# note that we are ignoring all of the individual reads, which also
413414
# contribute to reducing the effective read noise. Pass --effreadnoise
414415
# if you want to do better than this!
415-
effreadnoise = effreadnoise * etomjysr # electron -> MJy/sr
416+
effreadnoise = effreadnoise * etomjysr * pixscalefrac ** 2 # electron -> MJy/sr
417+
# factor of pixfrac ** 2 because etomjysr is per L3 pixel, but
418+
# this effreadnoise calculation is per native pixel
416419
# converting to MJy/sr units
417-
else:
418-
effreadnoise = 0
419420

420421
chromatic = False
421422
if (len(catalog) > 0 and not isinstance(catalog, astropy.table.Table)
@@ -481,7 +482,7 @@ def simulate_cps(image, filter_name, efftimes, objlist=None, psf=None,
481482
xpos=None, ypos=None, coord=None, sky=0, bandpass=None,
482483
effreadnoise=None, maggytoes=None, etomjysr=None,
483484
rng=None, seed=None, ignore_distant_sources=10,):
484-
"""Simulate average MegaJanskies per steradian in a single SCA.
485+
"""Simulate average MJy/sr in a single SCA.
485486
486487
Parameters
487488
----------
@@ -507,10 +508,10 @@ def simulate_cps(image, filter_name, efftimes, objlist=None, psf=None,
507508
effreadnoise : float
508509
Effective read noise for mosaic (MJy / sr)
509510
maggytoes: float
510-
Factor to convert electrons to MJy / sr; one maggy makes
511+
Factor to convert e/s to MJy / sr; one maggy makes
511512
this many e/s.
512513
etomjysr : float
513-
Factor to convert electron to MJy/sr; one e/s/pix corresponds
514+
Factor to convert e/s to MJy / sr; one e/s/coadd pix corresponds
514515
to this MJy/sr.
515516
rng : galsim.BaseDeviate
516517
random number generator

romanisim/tests/test_l3.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ def test_scaling():
532532
twcs1 = romanisim.wcs.create_tangent_plane_gwcs(
533533
(npix / 2, npix / 2), pscale, coord)
534534
twcs2 = romanisim.wcs.create_tangent_plane_gwcs(
535-
(npix / 2, npix / 2), pscale / 2, coord)
535+
(npix, npix), pscale / 2, coord)
536536

537537
im1, extras1 = l3.simulate(
538538
(npix, npix), twcs1, exptime, imdict['filter_name'],
@@ -600,3 +600,24 @@ def test_scaling():
600600

601601
# these all match to a few percent; worst case in initial test run
602602
# was err3fracdiff of 0.039.
603+
604+
# test read noise scaling
605+
im1, extras1 = l3.simulate(
606+
(npix, npix), twcs1, exptime, imdict['filter_name'],
607+
imdict['tabcatalog'], seed=rng_seed, effreadnoise=None, sky=0)
608+
609+
# half pixel scale
610+
im2, extras2 = l3.simulate(
611+
(npix * 2, npix * 2), twcs2, exptime, imdict['filter_name'],
612+
imdict['tabcatalog'], seed=rng_seed, effreadnoise=None, sky=0)
613+
614+
for im in [im1, im2]:
615+
assert np.abs(mad_std(im1.data) / np.median(im1.err) - 1) < 0.1
616+
assert np.abs(np.median(im1.err) /
617+
np.median(np.sqrt(im1.var_rnoise)) - 1) < 0.1
618+
assert np.abs(np.median(im2.err) / np.median(im1.err) / 4 - 1) < 0.1
619+
# 2x finer sampling -> 4x higher read noise in per-unit-time units
620+
# because constant read noise is divided by 4x smaller exposure time
621+
# the 2x finer sampling effectively means that you need to take the
622+
# four exposures and interleave them, each using 1/4 of the exposure
623+
# time

0 commit comments

Comments
 (0)