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

non-standard pixel sizes for distortion #669

Merged
merged 8 commits into from
Jul 27, 2023
Merged

Conversation

JarronL
Copy link
Collaborator

@JarronL JarronL commented May 12, 2023

Previously, distortion code assumed that webbpsf detector pixels and pysiaf apertures had similar pixel scales. However, it is possible to specify any non-standard pixel size (e.g., inst.pixelscale = whatever) when generating a PSF. This fix correctly applies the pysiaf distortion model for any arbitrary pixel size.

Previously, distortion code assumed that webbpsf and pysiaf apertures had similar pixel sizes. However, it is possible to request any non-standard pixel size when generated a PSF. This fix correctly applies distortion for any arbitrary pixel size.
@JarronL JarronL requested a review from mperrin May 12, 2023 20:26
Need to apply the same pixel sampling along the x- and y- axis, otherwise test_apply_distortion_pixel_scale() fails.

May need to update test?
@JarronL JarronL added the bug Something isn't working label May 12, 2023
@codecov
Copy link

codecov bot commented May 12, 2023

Codecov Report

Patch coverage: 71.42% and project coverage change: -0.79% ⚠️

Comparison is base (427b93d) 55.97% compared to head (b4fdee2) 55.18%.

❗ Current head b4fdee2 differs from pull request most recent head 5685897. Consider uploading reports for the commit 5685897 to get more accurate results

Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #669      +/-   ##
===========================================
- Coverage    55.97%   55.18%   -0.79%     
===========================================
  Files           15       14       -1     
  Lines         6280     6123     -157     
===========================================
- Hits          3515     3379     -136     
+ Misses        2765     2744      -21     
Files Changed Coverage Δ
webbpsf/distortion.py 80.64% <71.42%> (+3.85%) ⬆️

... and 5 files with indirect coverage changes

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

@mperrin
Copy link
Collaborator

mperrin commented May 13, 2023

I'm trying to follow the logic behind this change - can you give me an example for some calculation or setup that doesn't work currently but does work properly with this change?

Copy link
Collaborator

@mperrin mperrin left a comment

Choose a reason for hiding this comment

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

Couple questions & comments after a first quick skim.

@@ -63,7 +63,7 @@ def distort_image(hdulist_or_filename, ext=0, to_frame='sci', fill_value=0,
Value used to fill in any blank space by the skewed PSF. Default = 0.
If set to None, values outside the domain are extrapolated.
to_frame : str
Type of input coordinates.
Requested of output coordinate frame.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Minor: Clarify/rephrase. "Requested of" doesn't make sense...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right. Accidentally removed "type"

Comment on lines 139 to 141
# Choose conversion function
func_convert = getattr(aper, f'sci_to_{to_frame}')
xnew_cen, ynew_cen = func_convert(xsci_cen, ysci_cen)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain the motivation behind this change? It appears to me that this code is just replicating what the aper.convert function already does: check for a null transformation and if so return the input x,y; otherwise look up the correct X_to_Y function and then call it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, indeed. I had looked at the pysiaf convert function a long time ago and (perhaps erroneously) recall it making additional unnecessary transformations, so have always written my own set of if statements to minimize the number of calls. But looks like the logic now is much improved.

Comment on lines 182 to 187
if to_frame=='idl':
xnew_idl, ynew_idl = (xnew, ynew)
else:
# Choose conversion function
func_convert = getattr(aper, f'{to_frame}_to_idl')
xnew_idl, ynew_idl = func_convert(xnew, ynew)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment as above; this appears redundant with what aper.convert already does?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reverting to aper.convert.

@JarronL
Copy link
Collaborator Author

JarronL commented May 16, 2023

I'm trying to follow the logic behind this change - can you give me an example for some calculation or setup that doesn't work currently but does work properly with this change?

A colleague wanted to generate a MIRI PSF with a non-standard pixel size in order to match to the NIRCam PSF. So, by setting miri.pixelscale=0.061 (for instance), the distortion calculation would not correctly generate the new coordinates to perform the regular grid transformation onto. One symptom was that the total sum of a distorted PSF would be something like 30% of the sum from an undistorted PSF (ie., undistorted PSF is close to 1.0, while distorted PSF sum was 0.3).

I realized that when I originally authored this code, I made an assumptions about pixels scales and the meaning of oversample that were only applicable when the PSF pixel scale equals the SIAF pixel scale.

The updated code now generalizes the pixel scales such that I can still use SIAF to perform various coordinate transformations, but also making sure that I'm preserving the intended pixel scale when calculating the new set of coordinates.

Comment on lines 146 to 150
osamp_x = aper.XSciScale / pixelscale
osamp_y = aper.YSciScale / pixelscale
osamp = (osamp_x + osamp_y) / 2
xnew = xarr / osamp + xnew_cen
ynew = yarr / osamp + ynew_cen
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain the logic here for averaging osamp? This computes first a distinct oversampling factor in each of X and Y, but then computes xnew and ynew using the average oversampling factor. Wouldn't it be more precise to calculate using the distinct oversampling factors per axis, like xnew = xarr / osamp_x + xnew_cen?

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 originally tried doing it per-axis, but test_apply_distortion_pixel_scale() would fail. I did not have time to look into why the test was failing, as I didn't quite understand the logic behind the test. Reverting to a single oversampling applied across both axes fixed the issue. Need to investigate further.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Huh, yeah, now that I look at that test... I do not understand the logic either. 🤣

Copy link
Collaborator

@mperrin mperrin left a comment

Choose a reason for hiding this comment

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

I can replicate the bug you describe, and confirm this fixes it. I added a unit test that demonstrates/verifies that fix.

I do have the one question about oversampling per axis versus averaged; I'm honestly not sure which is the more precise/rigorous way to treat that, and would need to think through the math to double check. Apart from that clarification, this is ready to go.

@mperrin
Copy link
Collaborator

mperrin commented Jun 1, 2023

@JarronL FYI I tried to look at the test test_apply_distortion_pixel_scale and I can't really figure out the logic of that test and how it is supposed to work. It certainly is not doing what the docstring comment says it should do.

I am inclined to say just to delete that test, and you can edit this PR back to what you tried first, to treat the X and Y scales separately/

But really I should probably hand this off to @obi-wan76 to look at and think about, or to @Skyhawk172 who has been looking at the distortion code in the context of Roman.

@Skyhawk172
Copy link
Collaborator

I don't understand test_apply_distortion_pixel_scale either. First, the test doesn't seem to do exactly what the docstring states; second, I'm not sure the "linear skew" assumption is perfectly valid.

With that said, I'd have to think hard about another more intuitive test... So I'm also inclined to reinstate Jarron's per-axis approach at the expense of removing this test (at least for the time being).

@obi-wan76
Copy link
Collaborator

@JarronL what do you think? do you want to go back to doing it per-axis and removing test_apply_distortion_pixel_scale() ? Unless you have found the reason why the test is failing.

@JarronL
Copy link
Collaborator Author

JarronL commented Jul 26, 2023

Yes, I'm onboard with removing test_apply_distortion_pixel_scale() and reverting to per-axis:

        osamp_x = aper.XSciScale / pixelscale
        osamp_y = aper.YSciScale / pixelscale
        xnew = xarr / osamp_x + xnew_cen
        ynew = yarr / osamp_y + ynew_cen

@JarronL
Copy link
Collaborator Author

JarronL commented Jul 26, 2023

Would you like me to perform the change in this branch?

@obi-wan76
Copy link
Collaborator

Yes, that would be great! Thanks!

JarronL and others added 3 commits July 26, 2023 15:42
test_apply_distortion_pixel_scale() now follows what its description

Also updated test_apply_distortion_skew() so it actually creates a downsampled version of the data (previously was just creating a copy of the oversampled data).
@BradleySappington BradleySappington merged commit 90dba3f into develop Jul 27, 2023
12 checks passed
@BradleySappington BradleySappington deleted the distortion_update branch July 27, 2023 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants