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

JP-3848 MIRI LRS s_region and resample WCS #9193

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

jemorrison
Copy link
Collaborator

@jemorrison jemorrison commented Feb 14, 2025

This PR replaces: #9104

NOT TO BE MERGED until change to MIRI LRS specwcs reference file is made:spacetelescope/stdatamodels#393

Resolves JP-3848

Closes #9072

This PR corrects the s_region for MIRI LRS output from assign_wcs and resample. In addition an error was found in the WCS of resampled MIRI LRS data.
In assign_wcs the s_region is determined using the V2,V3 corners of the slit. These values are provided by a new
reference file.

Tasks

  • request a review from someone specific, to avoid making the maintainers review every PR
  • add a build milestone, i.e. Build 11.3 (use the latest build if not sure)
  • Does this PR change user-facing code / API? (if not, label with no-changelog-entry-needed)
    • write news fragment(s) in changes/: echo "changed something" > changes/<PR#>.<changetype>.rst (see below for change types)
    • update or add relevant tests
    • update relevant docstrings and / or docs/ page
    • start a regression test and include a link to the running job (click here for instructions)
      • Do truth files need to be updated ("okified")?
        • after the reviewer has approved these changes, run okify_regtests to update the truth files
  • if a JIRA ticket exists, make sure it is resolved properly
news fragment change types...
  • changes/<PR#>.general.rst: infrastructure or miscellaneous change
  • changes/<PR#>.docs.rst
  • changes/<PR#>.stpipe.rst
  • changes/<PR#>.datamodels.rst
  • changes/<PR#>.scripts.rst
  • changes/<PR#>.set_telescope_pointing.rst
  • changes/<PR#>.pipeline.rst

stage 1

  • changes/<PR#>.group_scale.rst
  • changes/<PR#>.dq_init.rst
  • changes/<PR#>.emicorr.rst
  • changes/<PR#>.saturation.rst
  • changes/<PR#>.ipc.rst
  • changes/<PR#>.firstframe.rst
  • changes/<PR#>.lastframe.rst
  • changes/<PR#>.reset.rst
  • changes/<PR#>.superbias.rst
  • changes/<PR#>.refpix.rst
  • changes/<PR#>.linearity.rst
  • changes/<PR#>.rscd.rst
  • changes/<PR#>.persistence.rst
  • changes/<PR#>.dark_current.rst
  • changes/<PR#>.charge_migration.rst
  • changes/<PR#>.jump.rst
  • changes/<PR#>.clean_flicker_noise.rst
  • changes/<PR#>.ramp_fitting.rst
  • changes/<PR#>.gain_scale.rst

stage 2

  • changes/<PR#>.assign_wcs.rst
  • changes/<PR#>.badpix_selfcal.rst
  • changes/<PR#>.msaflagopen.rst
  • changes/<PR#>.nsclean.rst
  • changes/<PR#>.imprint.rst
  • changes/<PR#>.background.rst
  • changes/<PR#>.extract_2d.rst
  • changes/<PR#>.master_background.rst
  • changes/<PR#>.wavecorr.rst
  • changes/<PR#>.srctype.rst
  • changes/<PR#>.straylight.rst
  • changes/<PR#>.wfss_contam.rst
  • changes/<PR#>.flatfield.rst
  • changes/<PR#>.fringe.rst
  • changes/<PR#>.pathloss.rst
  • changes/<PR#>.barshadow.rst
  • changes/<PR#>.photom.rst
  • changes/<PR#>.pixel_replace.rst
  • changes/<PR#>.resample_spec.rst
  • changes/<PR#>.residual_fringe.rst
  • changes/<PR#>.cube_build.rst
  • changes/<PR#>.extract_1d.rst
  • changes/<PR#>.resample.rst

stage 3

  • changes/<PR#>.assign_mtwcs.rst
  • changes/<PR#>.mrs_imatch.rst
  • changes/<PR#>.tweakreg.rst
  • changes/<PR#>.skymatch.rst
  • changes/<PR#>.exp_to_source.rst
  • changes/<PR#>.outlier_detection.rst
  • changes/<PR#>.tso_photometry.rst
  • changes/<PR#>.stack_refs.rst
  • changes/<PR#>.align_refs.rst
  • changes/<PR#>.klip.rst
  • changes/<PR#>.spectral_leak.rst
  • changes/<PR#>.source_catalog.rst
  • changes/<PR#>.combine_1d.rst
  • changes/<PR#>.ami.rst

other

  • changes/<PR#>.wfs_combine.rst
  • changes/<PR#>.white_light.rst
  • changes/<PR#>.cube_skymatch.rst
  • changes/<PR#>.engdb_tools.rst
  • changes/<PR#>.guider_cds.rst

Copy link

codecov bot commented Feb 14, 2025

Codecov Report

Attention: Patch coverage is 99.15254% with 1 line in your changes missing coverage. Please review.

Project coverage is 73.72%. Comparing base (16aa8b0) to head (7c4c40f).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
jwst/resample/resample_spec.py 94.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9193      +/-   ##
==========================================
+ Coverage   73.66%   73.72%   +0.05%     
==========================================
  Files         368      368              
  Lines       36392    36464      +72     
==========================================
+ Hits        26808    26882      +74     
+ Misses       9584     9582       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

pyproject.toml Outdated
@@ -34,7 +34,8 @@ dependencies = [
"scikit-image>=0.20.0",
"scipy>=1.14.1",
"spherical-geometry>=1.2.22",
"stdatamodels @ git+https://github.com/spacetelescope/stdatamodels.git@main",
#"stdatamodels @ git+https://github.com/spacetelescope/stdatamodels.git@main",
"stdatamodels @ stdatamodels-2.2.1.dev20+gf85885d",
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
"stdatamodels @ stdatamodels-2.2.1.dev20+gf85885d",
"stdatamodels @ git+https://github.com/jemorrison/stdatamodels.git@MIRI_LRS_Specwcs",

@jemorrison jemorrison requested review from nden, drdavella and drlaw1558 and removed request for drdavella February 14, 2025 18:10

# single model: use size of x_tan_array
# to be consistent with method before
if len(input_models) == 1:
x_size = int(np.ceil(xstop))
ny = int(np.ceil(xstop))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we want to remove this IF statement; see general comments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Made this change and it does make the s_regions look better

@drlaw1558
Copy link
Collaborator

drlaw1558 commented Feb 17, 2025

@jemorrison This is looking much better, but a few thoughts:

  • The across-slice positioning now looks good, both for S_REGIONs and for individual pixels. The along-slice is still a little weird though; from poking at this I think it's because the rotation that's being applied can change what the 'edge' pixels are slightly between cal and s2d frames (actual SOURCE positions look ok). One thing that I think we should fix though- in the individual s2d files it looks like the right edge of the resampled array is getting cut off; if I remove the ny = int(np.ceil(xstop)) and corresponding IF statement (see comment above) though then this looks better.
  • For some reason the pipeline log says again that there are NaNs in the bounding box during the assign_wcs step and that the S_REGIONS are not being updated. As a result I can't tell whether the new S_REGION code there is doing the right thing or if it's simply not changing the S_REGION from the rate files again. I'd thought that the latest pipeline was running this recalculation though, which is what kicked off much of this work in the first place?
  • I've got the new reference file ready to go as soon as the datamodels PR is merged.

@jemorrison
Copy link
Collaborator Author

@drlaw1558 are you supplying the new reference file when you run assign_wcs (spec2) in the override method ?

@drlaw1558
Copy link
Collaborator

@jemorrison Hm, I thought I had been but it looks like the new ref file wasn't getting picked up properly. With that fixed the assign_wcs indeed runs and results look good.

@jemorrison jemorrison force-pushed the JP-3848_MIRI_LRS_Second branch from 1eae471 to 1743b60 Compare February 17, 2025 15:19
@drlaw1558
Copy link
Collaborator

drlaw1558 commented Feb 17, 2025

LG2M now:
LRSwcs_new

Copy link
Collaborator

@drlaw1558 drlaw1558 left a comment

Choose a reason for hiding this comment

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

Looks good from the science side.

@@ -0,0 +1 @@
Fix MIRI LRS s_region and WCS in resample_spec
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
Fix MIRI LRS s_region and WCS in resample_spec
Fix MIRI LRS s_region and WCS in resample_spec

nitpick, but I think there's an accidental double-space here

@@ -72,8 +73,13 @@ def load_wcs(input_model, reference_files={}, nrs_slit_y_range=None):

if output_model.meta.exposure.type.lower() not in exclude_types:
imaging_types = IMAGING_TYPES.copy()
imaging_types.update(['mir_lrs-fixedslit', 'mir_lrs-slitless'])
if output_model.meta.exposure.type.lower() in imaging_types:
imaging_lrs_types = ['mir_lrs-fixedslit'] # keep it separate
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
imaging_lrs_types = ['mir_lrs-fixedslit'] # keep it separate
imaging_lrs_types = ['mir_lrs-fixedslit']

Copy link
Collaborator

Choose a reason for hiding this comment

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

once the PR has been merged, this comment seems like it might be more confusing than helpful

Comment on lines +79 to +80
# uses slits corners in V2, V3 that are read in from the
# lrs specwcs reference file
Copy link
Collaborator

Choose a reason for hiding this comment

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

can this information be placed in the docstring of update_s_region_lrs()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you mean something different than:

Determine S_REGION using V2,V3 of the slit corners from reference file

Copy link
Collaborator

Choose a reason for hiding this comment

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

no that's fine if it's already there, I just didn't find the comment here to be particularly helpful, in the sense that someone who wanted to know how the s_region for LRS was computed would look in the docstring of the function dedicated to that. i.e. IMO the comment here could be removed

Comment on lines 310 to 312
# remove commented out how after testing
#if input_model.meta.exposure.type.lower() == 'mir_lrs-fixedslit':
# bb_sub = (bb_sub[0], (dxmodel.points[0].min(), dxmodel.points[0].max()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

don't forget to remove this before merge

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

thanks I had forgotten

[a[3], b[3]]])

update_s_region_keyword(model, footprint)
print('in assign_wcs util.py',model.meta.wcsinfo.s_region)
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove print

log.info("The s_region will not be updated")

lam = 7.0 # wavelength does not matter for s region assign a value in
# wavelength of MIRI LRS
Copy link
Collaborator

Choose a reason for hiding this comment

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

keep on a single line if possible


# turn the size into a numpy shape in (y, x) order
output_wcs.array_shape = output_array_size[::-1]
output_wcs.pixel_shape = output_array_size
bounding_box = wcs_bbox_from_shape(output_array_size[::-1])
output_wcs.bounding_box = bounding_box

return output_wcs
s_region = find_miri_lrs_sregion(sregion_list,output_wcs)
Copy link
Collaborator

Choose a reason for hiding this comment

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

is MIRI LRS the only mode that uses the build_interpolated_output_wcs function? It looks like this is being applied to any data that ends up here. If it applies to more than just MIRI LRS, I suggest changing the name of this function to be more generic. If build_interpolated_output_wcs only applies to MIRI LRS, then I might suggest adding a line to the docstring of that function specifying that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@melanieclarke I wanted to double check that build_interpolated_output_wcs - is only applied to MIRI LRS data.

Copy link
Collaborator

Choose a reason for hiding this comment

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

It is currently used only for MIRI LRS FS but it's written to be more generally applicable, to any instrument other than NIRSpec. There is internal handling for dispersion directions that MIRI doesn't use, for example. It might be worthwhile to keep the implementation general for these new changes, in case we wanted to use it to try resampling for other spectral modes.

@@ -1011,3 +1025,85 @@ def compute_spectral_pixel_scale(wcs, fiducial=None, disp_axis=1):

pixel_scale = compute_scale(wcs, fiducial, disp_axis=disp_axis)
return float(pixel_scale)

def find_miri_lrs_sregion(sregion_list,wcs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This appears to only need sregion_list[0] and not all the s_regions from all the models. Is there a way to leverage that fact to move the call to this function closer to the end of the step, so that we don't need to add a _s_region attribute to ResampleSpec?

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 can check if I'm == 0 and only set the s_region to the one case. Is that what you would like ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess it doesn't really matter, I just thought it might be cleaner if it received only a single reference model.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm a bit concerned about the increasing spaghettification of the code with respect to how the s_region is handled for different modes, as follows:

This PR adds an _s_region attribute to the ResampleSpec class but only updates it for MIRI LRS data. Then the output gets the s_region applied to it inside the update_output_model method. This lives within an if _s_region is not None to apply it only to the appropriate data.

Other spectroscopic data have their s_region computed on this line basically right at the end of ResampleSpecStep in _process_slit() and not within any kind of update_output_model or similar function.

Imaging data get their s_region on this line inside the finalize method, which is also accessible to, and called by, ResampleSpec. This, too, needs an if statement around it to ensure it only gets applied to imaging data.

Is there any way to put these three in the same place so the code is easier to understand?

I know they're all computed slightly differently, but is there really no way to compute the LRS s_region closer to the end of the step? I noticed that the computation really only needs the zeroth s_region, not an entire list, perhaps that helps achieve this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well I need this first input model s_region to determine the slit width and I need to output wcs also.
Would you prefer that I move the 'find_miri_lrs_region' to resample_spec_step ?

Copy link
Collaborator

@emolter emolter Feb 17, 2025

Choose a reason for hiding this comment

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

@melanieclarke
Copy link
Collaborator

@jemorrison - there are some unit test failures that need attention when the code structure has settled. In particular, it looks like some of the tests I wrote to make sure flux is conserved are failing with the updates to the MIRI WCS.

self.update_slit_metadata(result)
update_s_region_spectral(result)
if result.meta.exposure.type.lower() != 'mir_lrs-fixedslit':
update_s_region_spectral(result)

Copy link
Collaborator

@emolter emolter Feb 17, 2025

Choose a reason for hiding this comment

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

Per my other comment, I assume the reason you put this if statement here is because the LRS data in question also follow this path. Could you put the call to find_miri_lrs_sregion() here? It appears to me that all the necessary inputs are already here, and it would make it so all spectral data get their s_region updated in the same place. Plus you wouldn't have to have ResampleSpec._s_region

e.g.,

if result.meta.exposure.type.lower() == 'mir_lrs-fixedslit':
    result.meta.wcsinfo.s_region = find_miri_lrs_sregion(input_models[0], result.meta.wcs)
else:
    update_s_region_spectral(result)

@jemorrison jemorrison force-pushed the JP-3848_MIRI_LRS_Second branch from 3280f74 to 7c4c40f Compare February 25, 2025 17:26
Copy link
Collaborator

@emolter emolter left a comment

Choose a reason for hiding this comment

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

This looks much cleaner now from an overall code design standpoint - this is exactly the flow I had in mind. I made a few additional small comments, but overall this looks great and I'm happy for it to be merged

Comment on lines +258 to +259
zero_point = refmodel.meta.x_ref_slitless - 1, \
refmodel.meta.y_ref_slitless - 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this fit on one line?

Comment on lines +820 to +825

Returns
-------
None
s_region for model is updated in place .

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
Returns
-------
None
s_region for model is updated in place .

Copy link
Collaborator

Choose a reason for hiding this comment

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

if you think it's useful to specify the update is done in-place, it can be put in the "extended summary"

log.info("The V2,V3 coordinates of the MIRI LRS-Fixed slit contains NaN values.")
log.info("The s_region will not be updated")

lam = 7.0 # wavelength does not matter for s region assign a value in range of LRS
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
lam = 7.0 # wavelength does not matter for s region assign a value in range of LRS
lam = 7.0 # wavelength does not matter for s_region so just assign a value in range of LRS

s_region for the resample data.
"""
# use the first sregion to set the width of the slit

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

@@ -482,6 +489,7 @@ def test_pixel_scale_ratio_spec_miri(miri_cal, ratio, units):
assert result1.data.shape[0] == result2.data.shape[0]

# spatial dimension is scaled
print(result1.data.shape[1], result2.data.shape[1])
Copy link
Collaborator

Choose a reason for hiding this comment

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

don't forget to remove print statement before merge

Copy link
Collaborator

Choose a reason for hiding this comment

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

I know you already have an s_region test in the regtest, but would it be straightforward to write a unit test for just the find_miri_lrs_sregion function on its own?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error in computation of MIRI LRS fixed slit S_REGION footprint
4 participants