Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rcal 406 science array quantities #616

Merged
merged 22 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jump

- Update default input CR thresholds to give reasonable results [#625]

- Added support for Quantities for data arrays. [#613]




0.9.0 (2022-11-14)
0.9.0 (2022-11-14)
==================

general
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ classifiers = [
'Programming Language :: Python :: 3',
]
dependencies = [
'asdf >=2.12.1',
'asdf >=2.13.0',
'astropy >=5.0.4',
'crds >=11.16.16',
'gwcs >=0.18.1',
'jsonschema >=3.0.2',
'numpy >=1.20',
'pyparsing >=2.4.7',
'requests >=2.22',
'rad>=0.14.0, <0.14.1',
'roman_datamodels>=0.14.0, <0.14.1',
'rad>=0.14.1',
'roman_datamodels >=0.14.1',
#'roman_datamodels @ git+https://github.com/spacetelescope/roman_datamodels.git@main',
'stcal >=1.2.1, <2.0',
'stpipe >=0.4.2, <1.0',
]
Expand Down
8 changes: 5 additions & 3 deletions romancal/dark_current/dark_current_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from roman_datamodels import datamodels as rdd
from stcal.dark_current import dark_sub
from roman_datamodels.testing import utils as testutil
from astropy import units as u
from roman_datamodels import units as ru


__all__ = ["DarkCurrentStep"]
Expand Down Expand Up @@ -43,7 +45,7 @@ def process(self, input):
dark_model.meta.exposure['groupgap'] = input_model.meta.exposure.groupgap

# Reshaping data variables for stcal compatibility
input_model.data = input_model.data.astype(np.float32)[np.newaxis, :]
input_model.data = input_model.data[np.newaxis, :]
input_model.groupdq = input_model.groupdq[np.newaxis, :]
input_model.err = input_model.err[np.newaxis, :]

Expand Down Expand Up @@ -133,10 +135,10 @@ def dark_output_data_as_ramp_model(out_data, input_model):
# Removing integration dimension from variables (added for stcal
# compatibility)
# Roman 3D
out_model.data = out_data.data[0]
out_model.data = u.Quantity(out_data.data[0], ru.DN, dtype=out_data.data.dtype)
out_model.groupdq = out_data.groupdq[0]
# Roman 2D
out_model.pixeldq = out_data.pixeldq
out_model.err = out_data.err[0]
out_model.err = u.Quantity(out_data.err[0], ru.DN, dtype=out_data.err.dtype)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Staring at this; does it make more sense to add these units onto out_data in process(...) following the do_correction call? Harping on my usual imagination that our ideal model should be: units everywhere, except around the calls to stcal, where there's a step beforehand removing units and afterward adding them back?


return out_model
11 changes: 7 additions & 4 deletions romancal/dark_current/tests/test_dark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
import pytest
import numpy as np
import os
from astropy import units as u

from romancal.dark_current import DarkCurrentStep

from roman_datamodels.datamodels import RampModel, DarkRefModel
import roman_datamodels as rdm
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru



@pytest.mark.parametrize(
Expand Down Expand Up @@ -71,17 +74,17 @@ def test_dark_step_subtraction(instrument, exptype):

# populate data array of science cube
for i in range(0, 20):
ramp_model.data[0, 0, i] = i
ramp_model.data.value[0, 0, i] = i
darkref_model.data[0, 0, i] = i * 0.1

# Perform Dark Current subtraction step
result = DarkCurrentStep.call(ramp_model, override_dark=darkref_model)

# check that the dark file is subtracted frame by frame from the science data
diff = ramp_model.data - darkref_model.data
diff = ramp_model.data.value - darkref_model.data

# test that the output data file is equal to the difference found when subtracting reffile from sci file
np.testing.assert_array_equal(result.data, diff, err_msg='dark file should be subtracted from sci file ')
np.testing.assert_array_equal(result.data.value, diff, err_msg='dark file should be subtracted from sci file ')


@pytest.mark.parametrize(
Expand Down Expand Up @@ -127,7 +130,7 @@ def create_ramp_and_dark(shape, instrument, exptype):
ramp.meta.instrument.detector = 'WFI01'
ramp.meta.instrument.optical_element = 'F158'
ramp.meta.exposure.type = exptype
ramp.data = np.ones(shape, dtype=np.float32)
ramp.data = u.Quantity(np.ones(shape, dtype=np.float32) , ru.DN, dtype=np.float32)
ramp_model = RampModel(ramp)

# Create dark model
Expand Down
8 changes: 5 additions & 3 deletions romancal/dq_init/tests/test_dq_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import numpy as np
import pytest
import warnings
from astropy import units as u

from roman_datamodels import stnode
from roman_datamodels.datamodels import MaskRefModel, ScienceRawModel
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru

from romancal.lib import dqflags
from romancal.dq_init import DQInitStep
Expand Down Expand Up @@ -196,7 +198,7 @@ def test_dqinit_step_interface(instrument, exptype):
wfi_sci_raw.meta['guidestar']['gw_window_xstart'] = 1012
wfi_sci_raw.meta['guidestar']['gw_window_xsize'] = 16
wfi_sci_raw.meta.exposure.type = exptype
wfi_sci_raw.data = np.ones(shape, dtype=np.uint16)
wfi_sci_raw.data = u.Quantity(np.ones(shape, dtype=np.uint16), ru.DN, dtype=np.uint16)
wfi_sci_raw_model = ScienceRawModel(wfi_sci_raw)

# Create mask model
Expand Down Expand Up @@ -248,7 +250,7 @@ def test_dqinit_refpix(instrument, exptype):
wfi_sci_raw.meta['guidestar']['gw_window_xstart'] = 1012
wfi_sci_raw.meta['guidestar']['gw_window_xsize'] = 16
wfi_sci_raw.meta.exposure.type = exptype
wfi_sci_raw.data = np.ones(shape, dtype=np.uint16)
wfi_sci_raw.data = u.Quantity(np.ones(shape, dtype=np.uint16), ru.DN, dtype=np.uint16)
wfi_sci_raw_model = ScienceRawModel(wfi_sci_raw)

# Create mask model
Expand All @@ -270,7 +272,7 @@ def test_dqinit_refpix(instrument, exptype):

# check if reference pixels are correct
assert result.data.shape == (2, 20, 20) # no pixels should be trimmed
assert result.amp33.shape == (2, 4096 ,128)
assert result.amp33.value.shape == (2, 4096 ,128)
assert result.border_ref_pix_right.shape == (2, 20, 4)
assert result.border_ref_pix_left.shape == (2, 20, 4)
assert result.border_ref_pix_top.shape == (2, 4, 20)
Expand Down
24 changes: 13 additions & 11 deletions romancal/flatfield/flat_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import logging
import numpy as np
from astropy import units as u
from roman_datamodels import units as ru

from romancal.lib import dqflags

Expand Down Expand Up @@ -109,21 +111,21 @@ def apply_flat_field(science, flat):
flat_data[np.where(flat_bad)] = 1.0
# Now let's apply the correction to science data and error arrays. Rely
# on array broadcasting to handle the cubes
science.data /= flat_data
science.data = u.Quantity((science.data.value / flat_data), ru.electron / u.s, dtype=science.data.dtype)

# Update the variances using BASELINE algorithm. For guider data, it has
# not gone through ramp fitting so there is no Poisson noise or readnoise
flat_data_squared = flat_data**2
science.var_poisson /= flat_data_squared
science.var_rnoise /= flat_data_squared
try:
science.var_flat = science.data**2 / flat_data_squared * flat_err**2
except AttributeError:
science['var_flat'] = np.zeros(shape=science.data.shape,
dtype=np.float32)
science.var_flat = science.data**2 / flat_data_squared * flat_err**2
science.err = np.sqrt(science.var_poisson +
science.var_rnoise + science.var_flat)
science.var_poisson = u.Quantity((science.var_poisson.value / flat_data_squared), ru.electron**2 / u.s**2,
dtype = science.var_poisson.dtype)
science.var_rnoise = u.Quantity((science.var_rnoise / flat_data_squared), ru.electron**2 / u.s**2,
dtype = science.var_rnoise.dtype)

science['var_flat'] = u.Quantity((science.data.value ** 2 / flat_data_squared * flat_err ** 2),
ru.electron ** 2 / u.s ** 2, dtype=science.data.value.dtype)

err_sqrt = np.sqrt(science.var_poisson.value + science.var_rnoise.value + science.var_flat)
science.err = u.Quantity(err_sqrt, ru.electron / u.s, dtype=err_sqrt.dtype)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we don't need to touch most of this section, since flat_data is unitless so things like science.data /= flat_data should do the right thing? What am I missing? One would only need to touch the except: AttributeError stanza, which was deleted here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted


# Combine the science and flat DQ arrays
science.dq = np.bitwise_or(science.dq, flat_dq)
18 changes: 12 additions & 6 deletions romancal/flatfield/tests/test_flatfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from roman_datamodels import stnode
from roman_datamodels.datamodels import ImageModel, FlatRefModel
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru
from romancal.flatfield import FlatFieldStep
from astropy.time import Time

from astropy import units as u

@pytest.mark.parametrize(
"instrument, exptype",
Expand All @@ -31,12 +32,17 @@ def test_flatfield_step_interface(instrument, exptype):
wfi_image.meta.instrument.detector = 'WFI01'
wfi_image.meta.instrument.optical_element = 'F158'
wfi_image.meta.exposure.type = exptype
wfi_image.data = np.ones(shape, dtype=np.float32)
wfi_image.data = u.Quantity(np.ones(shape, dtype=np.float32),
ru.electron / u.s, dtype=np.float32)
wfi_image.dq = np.zeros(shape, dtype=np.uint32)
wfi_image.err = np.zeros(shape, dtype=np.float32)
wfi_image.var_poisson = np.zeros(shape, dtype=np.float32)
wfi_image.var_rnoise = np.zeros(shape, dtype=np.float32)
wfi_image.var_flat = np.zeros(shape, dtype=np.float32)
wfi_image.err = u.Quantity(np.zeros(shape, dtype=np.float32),
ru.electron / u.s, dtype=np.float32)
wfi_image.var_poisson = u.Quantity(np.zeros(shape, dtype=np.float32),
ru.electron**2 / u.s**2, dtype=np.float32)
wfi_image.var_rnoise = u.Quantity(np.zeros(shape, dtype=np.float32),
ru.electron**2 / u.s**2, dtype=np.float32)
wfi_image.var_flat = u.Quantity(np.zeros(shape, dtype=np.float32),
ru.electron**2 / u.s**2, dtype=np.float32)
wfi_image_model = ImageModel(wfi_image)
flatref = stnode.FlatRef()
meta = {}
Expand Down
4 changes: 2 additions & 2 deletions romancal/jump/jump_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ def process(self, input):
frames_per_group = meta.exposure.nframes

# Modify the arrays for input into the 'common' jump (4D)
data = np.copy(r_data[np.newaxis, :])
data = np.copy(r_data[np.newaxis, :].value)
gdq = r_gdq[np.newaxis, :]
pdq = r_pdq[np.newaxis, :]
err = np.copy(r_err[np.newaxis, :])
err = np.copy(r_err[np.newaxis, :].value)

tstart = time.time()

Expand Down
26 changes: 14 additions & 12 deletions romancal/jump/tests/test_jump_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
import pytest
import numpy as np
from astropy.time import Time
from astropy import units as u

import roman_datamodels.stnode as rds
from roman_datamodels import datamodels as rdm
from roman_datamodels.datamodels import GainRefModel
from roman_datamodels.datamodels import ReadnoiseRefModel
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru

from romancal.jump import JumpStep

Expand Down Expand Up @@ -49,7 +51,7 @@ def generate_wfi_reffiles(tmpdir_factory):
gain_ref['meta'] = meta
gain_ref['data'] = np.ones(shape, dtype=np.float32) * ingain
gain_ref['dq'] = np.zeros(shape, dtype=np.uint16)
gain_ref['err'] = (np.random.random(shape) * 0.05).astype(np.float64)
gain_ref['err'] = (np.random.random(shape) * 0.05).astype(np.float32)

gain_ref_model = GainRefModel(gain_ref)
gain_ref_model.save(gainfile)
Expand All @@ -72,7 +74,7 @@ def generate_wfi_reffiles(tmpdir_factory):
rn_ref['meta'] = meta
rn_ref['data'] = np.ones(shape, dtype=np.float32)
rn_ref['dq'] = np.zeros(shape, dtype=np.uint16)
rn_ref['err'] = (np.random.random(shape) * 0.05).astype(np.float64)
rn_ref['err'] = (np.random.random(shape) * 0.05).astype(np.float32)

rn_ref_model = ReadnoiseRefModel(rn_ref)
rn_ref_model.save(readnoisefile)
Expand Down Expand Up @@ -101,10 +103,10 @@ def _setup(ngroups=10, readnoise=10, nrows=20, ncols=20,
dm_ramp.meta.instrument.name = 'WFI'
dm_ramp.meta.instrument.optical_element = 'F158'

dm_ramp.data = data + 6.
dm_ramp.data = u.Quantity(data + 6., ru.DN, dtype=data.dtype)
dm_ramp.pixeldq = pixdq
dm_ramp.groupdq = gdq
dm_ramp.err = err
dm_ramp.err = u.Quantity(err, ru.DN, dtype=err.dtype)

dm_ramp.meta.exposure.type = 'WFI_IMAGE'
dm_ramp.meta.exposure.group_time = deltatime
Expand Down Expand Up @@ -142,7 +144,7 @@ def test_one_CR(generate_wfi_reffiles, max_cores, setup_inputs):
deltatime=grouptime)

for i in range(ngroups):
model1.data[i, :, :] = deltaDN * i
model1.data.value[i, :, :] = deltaDN * i
first_CR_group_locs = [x for x in range(1, 7) if x % 5 == 0]

CR_locs = [x for x in range(xsize * ysize) if x % CR_fraction == 0]
Expand All @@ -153,8 +155,8 @@ def test_one_CR(generate_wfi_reffiles, max_cores, setup_inputs):
# Add CRs to the SCI data
for i in range(len(CR_x_locs)):
CR_group = next(CR_pool)
model1.data[CR_group:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data[CR_group:, CR_y_locs[i], CR_x_locs[i]] + 500.
model1.data.value[CR_group:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data.value[CR_group:, CR_y_locs[i], CR_x_locs[i]] + 500.

out_model = JumpStep.call(model1, override_gain=override_gain,
override_readnoise=override_readnoise,
Expand Down Expand Up @@ -190,7 +192,7 @@ def test_two_CRs(generate_wfi_reffiles, max_cores, setup_inputs):
deltatime=grouptime)

for i in range(ngroups):
model1.data[i, :, :] = deltaDN * i
model1.data.value[i, :, :] = deltaDN * i

first_CR_group_locs = [x for x in range(1, 7) if x % 5 == 0]
CR_locs = [x for x in range(xsize * ysize) if x % CR_fraction == 0]
Expand All @@ -201,10 +203,10 @@ def test_two_CRs(generate_wfi_reffiles, max_cores, setup_inputs):
for i in range(len(CR_x_locs)):
CR_group = next(CR_pool)

model1.data[CR_group:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data[CR_group:, CR_y_locs[i], CR_x_locs[i]] + 500
model1.data[CR_group + 8:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data[CR_group + 8:, CR_y_locs[i], CR_x_locs[i]] + 700
model1.data.value[CR_group:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data.value[CR_group:, CR_y_locs[i], CR_x_locs[i]] + 500
model1.data.value[CR_group + 8:, CR_y_locs[i], CR_x_locs[i]] = \
model1.data.value[CR_group + 8:, CR_y_locs[i], CR_x_locs[i]] + 700

out_model = JumpStep.call(model1, override_gain=override_gain,
override_readnoise=override_readnoise,
Expand Down
5 changes: 3 additions & 2 deletions romancal/linearity/linearity_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from romancal.stpipe import RomanStep
from romancal.lib import dqflags
from stcal.linearity.linearity import linearity_correction
from astropy import units as u

__all__ = ["LinearityStep"]

Expand Down Expand Up @@ -56,11 +57,11 @@ def process(self, input):
# Call linearity correction function in stcal
# The third return value is the procesed zero frame which
# Roman does not use.
new_data, new_pdq, _ = linearity_correction(output_model.data,
new_data, new_pdq, _ = linearity_correction(output_model.data.value,
gdq, pdq, lin_coeffs,
lin_dq, dqflags.pixel)

output_model.data = new_data[0, :, :, :]
output_model.data = u.Quantity(new_data[0, :, :, :], u.DN, dtype=new_data.dtype)
output_model.pixeldq = new_pdq

# Close the reference file and update the step status
Expand Down
Loading