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

Add WFI footprint to Footprints plugin #3322

Merged
merged 2 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Imviz

* Orientation plugin API now exposes create_north_up_east_left and create_north_up_east_right methods. [#3308]

* Add Roman WFI and CGI footprints to the Footprints plugin. [#3322]

Mosviz
^^^^^^

Expand Down
18 changes: 15 additions & 3 deletions jdaviz/configs/imviz/plugins/footprints/footprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
__all__ = ['Footprints']


_available_instruments = {
display_name: {'label': display_name, 'siaf_name': siaf_name, 'observatory': observatory}
for observatory, instruments in preset_regions._instruments.items()
for display_name, siaf_name in instruments.items()
}


@tray_registry('imviz-footprints', label="Footprints")
class Footprints(PluginTemplateMixin, ViewerSelectMixin, HasFileImportSelect):
"""
Expand Down Expand Up @@ -119,11 +126,13 @@ def __init__(self, *args, **kwargs):
on_remove=self._on_overlay_remove)

if self.has_pysiaf:
preset_options = list(preset_regions._instruments.keys())
preset_options = list(_available_instruments.keys())
else:
preset_options = ['None']

if not self.app.state.settings.get('server_is_remote', False):
preset_options.append('From File...')

self.preset = FileImportSelectPluginComponent(self,
items='preset_items',
selected='preset_selected',
Expand Down Expand Up @@ -480,8 +489,11 @@ def overlay_regions(self):
regs = [regs]
overlay['regions'] = regs
regs = overlay.get('regions', [])
elif self.has_pysiaf and self.preset_selected in preset_regions._instruments:
regs = preset_regions.jwst_footprint(self.preset_selected, **callable_kwargs)
elif self.has_pysiaf and self.preset_selected in _available_instruments.keys():
regs = preset_regions.instrument_footprint(
_available_instruments[self.preset_selected]['observatory'],
self.preset_selected, **callable_kwargs
)
else: # pragma: no cover
regs = []
return regs
Expand Down
2 changes: 1 addition & 1 deletion jdaviz/configs/imviz/plugins/footprints/footprints.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

<j-plugin-section-header>Footprint Definition</j-plugin-section-header>
<v-alert v-if="!has_pysiaf" type="warning" style="margin-left: -12px; margin-right: -12px">
To use JWST footprints, install pysiaf and restart jdaviz.
To use JWST or Roman footprints, install pysiaf and restart jdaviz.
</v-alert>

<plugin-file-import-select
Expand Down
79 changes: 55 additions & 24 deletions jdaviz/configs/imviz/plugins/footprints/preset_regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,30 @@
"_instruments",
"_full_apertures",
"_all_apertures",
"jwst_footprint"
"instrument_footprint"
]

_instruments = {'NIRSpec': 'NIRSpec',
'NIRCam:short': 'NIRCam',
'NIRCam:long': 'NIRCam',
'NIRISS': 'NIRISS',
'MIRI': 'MIRI',
'FGS': 'FGS'
}
_instruments = {
'JWST': {
'NIRSpec': 'NIRSpec',
'NIRCam:short': 'NIRCam',
'NIRCam:long': 'NIRCam',
'NIRISS': 'NIRISS',
'MIRI': 'MIRI',
'FGS': 'FGS',
},
'Roman': {
'WFI': 'Roman',
'WFI+CGI': 'Roman',
}
}

_full_apertures = {'NIRSpec': 'NRS_FULL_MSA',
'NIRCam:short': 'NRCALL_FULL',
'NIRCam:long': 'NRCALL_FULL',
'NIRISS': 'NIS_AMIFULL',
'MIRI': 'MIRIM_FULL',
'FGS': 'FGS1_FULL'
'FGS': 'FGS1_FULL',
}

_all_apertures = {'NIRSpec': ["NRS_FULL_MSA1",
Expand All @@ -56,18 +63,27 @@
'NIRCam:long': ["NRCA5_FULL", "NRCB5_FULL"],
'NIRISS': ['NIS_AMIFULL'],
'MIRI': ['MIRIM_FULL'],
'FGS': ['FGS1_FULL', 'FGS2_FULL']
'FGS': ['FGS1_FULL', 'FGS2_FULL'],
'WFI': [f'WFI{i+1:02d}_FULL' for i in range(18)],
'WFI+CGI': [f'WFI{i+1:02d}_FULL' for i in range(18)] + ['CGI_CEN'],
}


def jwst_footprint(instrument, ra, dec, pa, v2_offset=0.0, v3_offset=0.0, apertures=None):
def instrument_footprint(
observatory, instrument, ra, dec, pa,
v2_offset=0.0, v3_offset=0.0, apertures=None
):
"""
Create footprint regions in sky coordinates from a jwst instrument.

Parameters
----------
observatory : string
Observatory, one of {"JWST", "Roman"}.
instrument : string
Instrument, one of 'nirspec', 'nircam:short', 'nircam:long'.
Instrument. For JWST, must be one of
{"NIRSpec", "NIRCam:short", "NIRCam:long", "NIRISS", "MIRI", "FGS"};
for Roman, must be one of {"WFI", "CGI"}.
ra : float
RA of NIRCam center, in degrees.
dec : float
Expand All @@ -92,17 +108,30 @@ def jwst_footprint(instrument, ra, dec, pa, v2_offset=0.0, v3_offset=0.0, apertu
if not _has_pysiaf:
raise ImportError('jwst_footprint requires pysiaf to be installed')

if instrument not in _instruments: # pragma: no cover
raise ValueError(f"instrument must be one of {', '.join(_instruments.keys())}")

siaf_interface = pysiaf.Siaf(_instruments.get(instrument))

# Get center and PA offset from full aperture
full = siaf_interface.apertures[_full_apertures.get(instrument)]
corners = full.corners("tel", rederive=False)
v2 = np.mean(corners[0]) - v2_offset
v3 = np.mean(corners[1]) + v3_offset
pa_offset = full.V3IdlYAngle
if observatory not in _instruments:
raise ValueError(f"observatory must be one of {', '.join(_instruments.keys())}")

if instrument not in _instruments[observatory]: # pragma: no cover
raise ValueError(f"instrument must be one of {', '.join(_instruments[observatory].keys())}")

siaf_interface = pysiaf.Siaf(_instruments.get(observatory).get(instrument))

# use different definitions of the center for JWST and Roman:
if observatory == "Roman":
if instrument.startswith("WFI"):
rosteen marked this conversation as resolved.
Show resolved Hide resolved
center = siaf_interface.apertures['WFI_CEN']
else:
center = siaf_interface.apertures['CGI_CEN']
v2 = center.V2Ref - v2_offset
v3 = center.V3Ref + v3_offset
pa_offset = center.V3IdlYAngle
else:
# Get center and PA offset from full aperture
full = siaf_interface.apertures[_full_apertures.get(instrument)]
corners = full.corners("tel", rederive=False)
v2 = np.mean(corners[0]) - v2_offset
v3 = np.mean(corners[1]) + v3_offset
pa_offset = full.V3IdlYAngle

# Attitude matrix for sky coordinates
attmat = pysiaf.utils.rotations.attitude(v2, v3, ra, dec, pa - pa_offset)
Expand All @@ -115,7 +144,9 @@ def jwst_footprint(instrument, ra, dec, pa, v2_offset=0.0, v3_offset=0.0, apertu
for aperture_name in apertures:
aperture = siaf_interface.apertures[aperture_name]
aperture.set_attitude_matrix(attmat)
poly_points = aperture.closed_polygon_points("sky")
poly_points = aperture.closed_polygon_points(
"sky", rederive='CGI' not in instrument
)

sky_coord = coordinates.SkyCoord(*poly_points, unit="deg")
reg = regions.PolygonSkyRegion(sky_coord)
Expand Down
Loading