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-919: Formalize the patches (sky cells) file (e.g., add a data model to support it as a reference fiel) #441

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions changes/441.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for skycell reference file
4 changes: 4 additions & 0 deletions src/roman_datamodels/datamodels/_datamodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@ class ReadnoiseRefModel(_DataModel):
_node_type = stnode.ReadnoiseRef


class RomanSkycellsRefModel(_DataModel):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
class RomanSkycellsRefModel(_DataModel):
class SkycellsRefModel(_DataModel):

Do we need the Roman prefix?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I mulled over that, more for the filename than for the class (which is clearly associated with Roman in its context). I worry that the reference file by itself may need a clear association with Roman in the event skycells end up being used for other telescopes (like JWST). It is a good question.

_node_type = stnode.RomanSkycellsRef


class SuperbiasRefModel(_DataModel):
_node_type = stnode.SuperbiasRef

Expand Down
18 changes: 18 additions & 0 deletions src/roman_datamodels/maker_utils/_common_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,24 @@ def mk_ref_readnoise_meta(**kwargs):
return meta


def mk_ref_skycells_meta(**kwargs):
"""
Create dummy metadata for skycells reference file instances.

Returns
-------
dict (follows reference_file/ref_common-1.0.0 schema + skycell reference file meta data)
"""
meta = mk_ref_common("SKYCELLS", **kwargs)
del meta["instrument"]["detector"]
del meta["instrument"]["optical_element"]
meta["nxy_skycell"] = 5000
meta["skycell_border_pixels"] = 100
meta["plate_scale"] = 0.055
Comment on lines +768 to +770
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
meta["nxy_skycell"] = 5000
meta["skycell_border_pixels"] = 100
meta["plate_scale"] = 0.055
meta["nxy_skycell"] = kwargs.get("nxy_skycell", 5000)
meta["skycell_border_pixels"] = kwargs.get("skycell_border_pixels", 100)
meta["plate_scale"] = kwargs.get("plate_scale", 0.055)

Any reason to not use kwargs here like in the other mk_* functions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Probably not, but I'm loathe to make changes until the naming stuff and file structure is settled.


return meta


def mk_mosaic_basic(**kwargs):
"""
Create a dummy mosaic basic instance with valid values for attributes
Expand Down
165 changes: 165 additions & 0 deletions src/roman_datamodels/maker_utils/_ref_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
mk_ref_epsf_meta,
mk_ref_pixelarea_meta,
mk_ref_readnoise_meta,
mk_ref_skycells_meta,
mk_ref_units_dn_meta,
)

Expand All @@ -32,6 +33,7 @@
"mk_pixelarea",
"mk_readnoise",
"mk_refpix",
"mk_roman_skycells",
"mk_saturation",
"mk_superbias",
"mk_wfi_img_photom",
Expand Down Expand Up @@ -565,6 +567,169 @@ def mk_saturation(*, shape=(4096, 4096), filepath=None, **kwargs):
return save_node(saturationref, filepath=filepath)


def mk_roman_skycells(*, filepath=None, **kwargs):
skycellref = stnode.RomanSkycellsRef()
skycellref["meta"] = mk_ref_skycells_meta(**kwargs)
proj_dtype = np.dtype(
[
("index", "<i4"),
("ra_tangent", "<f8"),
("dec_tangent", "<f8"),
("ra_min", "<f8"),
("ra_max", "<f8"),
("dec_min", "<f8"),
("dec_max", "<f8"),
("orientat", "<f4"),
("x_tangent", "<f8"),
("y_tangent", "<f8"),
("nx", "<i4"),
("ny", "<i4"),
("skycell_start", "<i4"),
("skycell_end", "<i4"),
("nxy_skycell", "<i4"),
("skycell_border_pixels", "<i4"),
("pixel_scale", "<f4"),
]
)
skycell_dtype = np.dtype(
[
("name", "<U16"),
("ra_center", "<f8"),
("dec_center", "<f8"),
("orientat", "<f4"),
("x_tangent", "<f8"),
("y_tangent", "<f8"),
("ra_corn1", "<f8"),
("dec_corn1", "<f8"),
("ra_corn2", "<f8"),
("dec_corn2", "<f8"),
("ra_corn3", "<f8"),
("dec_corn3", "<f8"),
("ra_corn4", "<f8"),
("dec_corn4", "<f8"),
]
)
proj_tab = np.array(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it possible to fill these with empty arrays with the structured dtype rather than hard-coding data 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.

I think so, though there is a minor benefit for showing realistic values. I'm happy to change it though (after this whole name business is settled.

[
(
0,
225.0,
90.0,
0.0,
360.0,
88.20062575,
90.0,
0.0,
117776.5,
117776.5,
235554,
235554,
0,
1985,
5000,
100,
1.5277777e-05,
),
(
1,
0.0,
86.40080763,
-22.5,
22.5,
84.60010081,
88.20062575,
0.0,
138592.5,
117834.5,
277186,
235670,
1985,
3986,
5000,
100,
1.5277777e-05,
),
(
2,
45.0,
86.40080763,
22.5,
67.5,
84.60010081,
88.20062575,
0.0,
138592.5,
117834.5,
277186,
235670,
3986,
5987,
5000,
100,
1.5277777e-05,
),
],
dtype=proj_dtype,
)
skycell_tab = np.array(
[
(
"a225dp90xm25yp01",
317.2901524,
88.16584325,
-92.29015,
122499.5,
7299.5,
318.40988935,
88.12583697,
318.55462778,
88.20200659,
316.1209133,
88.20512017,
316.07517233,
88.12882346,
),
(
"a225dp90xm25yp00",
314.99952253,
88.16730723,
-89.99952,
122499.5,
2499.5,
316.16868134,
88.1287637,
316.2183982,
88.20505786,
313.78062699,
88.20505721,
313.8303836,
88.12876307,
),
(
"a225dp90xm25yp01",
312.70889418,
88.16584203,
-87.70889,
122499.5,
-2300.5,
313.92389255,
88.12882289,
313.87811182,
88.20511958,
311.44440071,
88.2020047,
311.58917851,
88.12583515,
),
],
dtype=skycell_dtype,
)
skycellref["projection_regions"] = proj_tab
skycellref["skycells"] = skycell_tab

return save_node(skycellref, filepath=filepath)


def mk_superbias(*, shape=(4096, 4096), filepath=None, **kwargs):
"""
Create a dummy Superbias instance (or file) with arrays and valid values for
Expand Down
55 changes: 55 additions & 0 deletions src/roman_datamodels/maker_utils/mk_skycell_ref.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import asdf
import numpy as np
from astropy.time import Time

import roman_datamodels.stnode as stnode


def mk_skycell(output_filename, projection_regions, skycells, author, useafter, plate_scale, border_pixels):
"""
Create a skycell reference file.


Parameters
----------
output_filename : string.
The name of the created reference file.
projection_regions : numpy structure array.
An array that defines the projection regions containing the fields as defined by
the schema.
skycells : numpy structure array.
An array that defines all skycells containing the fields as defined by the schema.
author : string.
The name of the person creating the reference file.
useafter : astropy.time.Time instance.
The useafter date that CRDS requires.
plate_scale: float.
The plate scale of the pixel at the tangent point.
border_pixels: integer.
The number of pixels the skycells within a projection region overlap with adjacent
skycells in the same projection region.
"""
meta = {
"reftype": "SKYCELLS",
"pedigree": "GROUND",
"description": "Skycells covering the celestial sphere",
"author": author,
"useafter": Time("2024-01-01T01:00:00.000"),
"telescope": "ROMAN",
"origin": "STSCI",
"instrument": {"name": "WFI"},
"nxy_skycell": 5000,
"skycell_border_pixels": border_pixels,
"plate_scale": plate_scale,
}
projection_regions = np.array(projection_regions)
skycells = np.array(skycells)
skycellref = stnode.RomanSkycellsRef()
skycellref["meta"] = meta
skycellref["projection_regions"] = projection_regions
skycellref["skycells"] = skycells
skycellref["datamodel_name"] = "RomanSkycellsRefModel"
with asdf.AsdfFile() as afout:
afout = asdf.AsdfFile()
afout.tree["roman"] = skycellref
afout.write_to(output_filename)
3 changes: 3 additions & 0 deletions tests/test_maker_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@
The purpose here is just to inject unique non-default data into the maker utility to override
its default values.
"""
# Skip the test if it is a RomanSkycellsRef class
if node_class.__name__ == "RomanSkycellsRef":
return

Check warning on line 149 in tests/test_maker_utils.py

View check run for this annotation

Codecov / codecov/patch

tests/test_maker_utils.py#L148-L149

Added lines #L148 - L149 were not covered by tests

def mutate_value(value):
"""
Expand Down
10 changes: 10 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@
# Get all reference file classes
tags = [t for t in stnode.NODE_EXTENSIONS[0].tags if "/reference_files/" in t.tag_uri]
for tag in tags:
# roman_skycells doesn't use EXPECTED_COMMON_REFERENCE
if repr(tag).find("roman_skycells") > 0:
return

Check warning on line 333 in tests/test_models.py

View check run for this annotation

Codecov / codecov/patch

tests/test_models.py#L332-L333

Added lines #L332 - L333 were not covered by tests
schema = asdf.schema.load_schema(tag.schema_uris[0])
# Check that schema references common reference schema
allofs = schema["properties"]["meta"]["allOf"]
Expand Down Expand Up @@ -612,6 +615,13 @@
assert refpix.meta.output_units == u.DN


# Skycells tests
def test_make_roman_skycells():
skycells_ref = utils.mk_roman_skycells()
assert skycells_ref.projection_regions["index"][2] == 2
assert skycells_ref.skycells["dec_corn2"][0] > 88

Check warning on line 622 in tests/test_models.py

View check run for this annotation

Codecov / codecov/patch

tests/test_models.py#L619-L622

Added lines #L619 - L622 were not covered by tests


# WFI Photom tests
def test_make_wfi_img_photom():
wfi_img_photom = utils.mk_wfi_img_photom()
Expand Down
6 changes: 5 additions & 1 deletion tests/test_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,11 @@
elif node_class in (stnode.MosaicSegmentationMap, stnode.MosaicSourceCatalog):
assert hasattr(model.meta, "basic")
else:
assert model.meta.instrument.optical_element == "F158"
# roman_skycells reference file does not contain optical_element. Skip this case
if hasattr(model.meta, "reftype") and model.meta.reftype == "SKYCELLS":

Check warning on line 220 in tests/test_open.py

View check run for this annotation

Codecov / codecov/patch

tests/test_open.py#L220

Added line #L220 was not covered by tests
pass
else:
assert model.meta.instrument.optical_element == "F158"

# Check that the model is the correct type
assert isinstance(model, datamodels.MODEL_REGISTRY[node_class])
Expand Down
Loading