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 all 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
13 changes: 5 additions & 8 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ general
- Update the suffix for the stored filename to match the filename [#609]

- DQ step flags science data affected by guide window read [#599]

- Fix deprecation warnings introduced by ``pytest`` ``7.2`` ahead of ``8.0`` [#597]

- Implemented support for quantities in reference files. Updated unit tests for these changes. [#624]

jump
----

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

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



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

general
Expand Down Expand Up @@ -308,7 +308,7 @@ general
general
-------

- Added regressions tests for ``dq_ini``t utilizing ``mask`` file in CRDS. [#290]
- Added regressions tests for ``dq_init`` utilizing ``mask`` file in CRDS. [#290]

- Updates for requirements & pip changes [#286]

Expand Down Expand Up @@ -409,9 +409,6 @@ datamodels

- Update output_ext in the base Step class to .asdf from .fits [#127]


=======

- Added ``RampModel``, ``GLS_RampFitModel``, ``RampFitOutputModel`` and
schemas. [#110]

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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',
Expand Down
7 changes: 4 additions & 3 deletions romancal/dark_current/dark_current_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from roman_datamodels import datamodels as rdd
from stcal.dark_current import dark_sub
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru


__all__ = ["DarkCurrentStep"]
Expand Down Expand Up @@ -45,7 +46,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 @@ -135,10 +136,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 = u.Quantity(out_data.data[0], out_model.data.unit, dtype=out_model.data.dtype)
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 = u.Quantity(out_data.err[0], out_model.err.unit, dtype=out_model.err.dtype)
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
6 changes: 2 additions & 4 deletions romancal/dark_current/tests/test_dark.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import os
from astropy import units as u


from romancal.dark_current import DarkCurrentStep

from roman_datamodels.datamodels import RampModel, DarkRefModel
Expand Down Expand Up @@ -81,10 +80,10 @@ def test_dark_step_subtraction(instrument, exptype):
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.value

# 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 @@ -130,7 +129,6 @@ 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 = u.Quantity(np.ones(shape, dtype=np.float32), ru.DN, dtype=np.float32)
ramp_model = RampModel(ramp)

Expand Down
2 changes: 1 addition & 1 deletion romancal/dq_init/tests/test_dq_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,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
9 changes: 6 additions & 3 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,19 +111,20 @@ 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
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.var_flat = science.data ** 2 / flat_data_squared * flat_err ** 2

science.err = np.sqrt(science.var_poisson +
science.var_rnoise + science.var_flat)

Expand Down
20 changes: 13 additions & 7 deletions romancal/flatfield/tests/test_flatfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import pytest
import numpy as np
from astropy import units as u

from astropy.time import Time

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


@pytest.mark.parametrize(
Expand All @@ -33,12 +33,18 @@ 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 = u.Quantity(np.ones(shape, dtype=np.float32), wfi_image.data.unit, wfi_image.data.dtype)
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 = u.Quantity(np.zeros(shape, dtype=np.float32), wfi_image.err.unit, wfi_image.err.dtype)
wfi_image.var_poisson = u.Quantity(np.zeros(shape, dtype=np.float32), wfi_image.var_poisson.unit, wfi_image.var_poisson.dtype)
wfi_image.var_rnoise = u.Quantity(np.zeros(shape, dtype=np.float32), wfi_image.var_rnoise.unit, wfi_image.var_rnoise.dtype)
wfi_image.var_flat = u.Quantity(np.zeros(shape, dtype=np.float32), wfi_image.var_flat.unit, wfi_image.var_flat.dtype)
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
1 change: 1 addition & 0 deletions romancal/jump/tests/test_jump_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def test_one_CR(generate_wfi_reffiles, max_cores, setup_inputs):

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

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 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
22 changes: 13 additions & 9 deletions romancal/ramp_fitting/ramp_fit_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ def create_optional_results_model(input_model, opt_info):
crmag.dtype = np.float32

inst = {'meta': meta,
'slope': np.squeeze(slope),
'sigslope': np.squeeze(sigslope),
'var_poisson': np.squeeze(var_poisson),
'var_rnoise': np.squeeze(var_rnoise),
'yint': np.squeeze(yint),
'sigyint': np.squeeze(sigyint),
'pedestal': np.squeeze(pedestal),
'slope': u.Quantity(np.squeeze(slope), ru.electron / u.s, dtype=slope.dtype),
'sigslope': u.Quantity(np.squeeze(sigslope), ru.electron / u.s, dtype=sigslope.dtype),
'var_poisson': u.Quantity(np.squeeze(var_poisson), ru.electron**2 / u.s**2, dtype=var_poisson.dtype),
'var_rnoise': u.Quantity(np.squeeze(var_rnoise), ru.electron**2 / u.s**2, dtype=var_rnoise.dtype),
'yint': u.Quantity(np.squeeze(yint), ru.electron, dtype=yint.dtype),
'sigyint': u.Quantity(np.squeeze(sigyint), ru.electron, dtype=sigyint.dtype),
'pedestal': u.Quantity(np.squeeze(pedestal), ru.electron, dtype=pedestal.dtype),
'weights': np.squeeze(weights),
'crmag': crmag
'crmag': u.Quantity(crmag, ru.electron, dtype=pedestal.dtype),
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we added these units back at the opt_info stage instead of here, we wouldn't need to repeat adding these units in create_image_model?


out_node = rds.RampFitOutput(inst)
Expand Down Expand Up @@ -82,6 +82,11 @@ def create_image_model(input_model, image_info):
"""
data, dq, var_poisson, var_rnoise, err = image_info

data = u.Quantity(data, ru.electron / u.s, dtype=data.dtype)
var_poisson = u.Quantity(var_poisson, ru.electron**2 / u.s**2, dtype=var_poisson.dtype)
var_rnoise = u.Quantity(var_rnoise, ru.electron**2 / u.s**2, dtype=var_rnoise.dtype)
err = u.Quantity(err, ru.electron / u.s, dtype=err.dtype)

# Create output datamodel
# ... and add all keys from input
meta = {}
Expand Down Expand Up @@ -144,7 +149,6 @@ def process(self, input):
readnoise_filename = self.get_reference_file(input_model, 'readnoise')
gain_filename = self.get_reference_file(input_model, 'gain')
input_model.data = input_model.data[np.newaxis, :]
input_model.data.dtype=np.float32
input_model.groupdq = input_model.groupdq[np.newaxis, :]
input_model.err = input_model.err[np.newaxis, :]

Expand Down
15 changes: 6 additions & 9 deletions romancal/ramp_fitting/tests/test_ramp_fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from astropy.time import Time
from astropy import units as u


from roman_datamodels.datamodels import RampModel, GainRefModel, ReadnoiseRefModel, ImageModel
from roman_datamodels.testing import utils as testutil
from roman_datamodels import units as ru
Expand Down Expand Up @@ -32,12 +31,10 @@ def generate_ramp_model(shape, deltatime=1):
gdq = np.zeros(shape=shape, dtype=np.uint8)

dm_ramp = testutil.mk_ramp(shape)
dm_ramp.data = data
dm_ramp.data = u.Quantity(data, ru.DN, dtype=np.float32)
dm_ramp.pixeldq = pixdq
dm_ramp.groupdq = gdq
dm_ramp.err = err

#dm_ramp.meta['photometry'] = testutil.mk_photometry()
dm_ramp.err = u.Quantity(err, ru.DN, dtype=np.float32)

dm_ramp.meta.exposure.frame_time = deltatime
dm_ramp.meta.exposure.ngroups = shape[0]
Expand Down Expand Up @@ -183,10 +180,10 @@ def test_saturated_ramp_fit(max_cores):
maximum_cores=max_cores)

# Test data and error arrays are zeroed out
np.testing.assert_array_equal(out_model.data, 0)
np.testing.assert_array_equal(out_model.err, 0)
np.testing.assert_array_equal(out_model.var_poisson, 0)
np.testing.assert_array_equal(out_model.var_rnoise, 0)
np.testing.assert_array_equal(out_model.data.value, 0)
np.testing.assert_array_equal(out_model.err.value, 0)
np.testing.assert_array_equal(out_model.var_poisson.value, 0)
np.testing.assert_array_equal(out_model.var_rnoise.value, 0)

# Test that all pixels are flagged saturated
assert np.all(np.bitwise_and(out_model.dq, SATURATED) == SATURATED)
Expand Down
2 changes: 1 addition & 1 deletion romancal/saturation/saturation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def flag_saturation(input_model, ref_model):
the GROUPDQ array
"""

data = input_model.data.value[np.newaxis, :]
data = input_model.data[np.newaxis, :].value

# Create the output model as a copy of the input
output_model = input_model
Expand Down
6 changes: 3 additions & 3 deletions romancal/saturation/tests/test_saturation.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,14 @@ def test_dq_propagation(setup_wfi_datamodels):
dqval1 = 5
dqval2 = 10

data, satmap = setup_wfi_datamodels(ngroups, nrows, ncols)
ramp, satmap = setup_wfi_datamodels(ngroups, nrows, ncols)

# Add DQ values to the data and reference file
data.pixeldq[5, 5] = dqval1
ramp.pixeldq[5, 5] = dqval1
satmap.dq[5, 5] = dqval2

# Run the pipeline
output = flag_saturation(data, satmap)
output = flag_saturation(ramp, satmap)

# Make sure DQ values from data and reference file are added in the output
assert output.pixeldq[5, 5] == dqval1 + dqval2
Expand Down