-
Notifications
You must be signed in to change notification settings - Fork 63
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
Conversation
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.
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?
Codecov ReportPatch coverage:
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
☔ View full report in Codecov by Sentry. |
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? |
There was a problem hiding this 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.
webbpsf/distortion.py
Outdated
@@ -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. |
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. Accidentally removed "type"
webbpsf/distortion.py
Outdated
# Choose conversion function | ||
func_convert = getattr(aper, f'sci_to_{to_frame}') | ||
xnew_cen, ynew_cen = func_convert(xsci_cen, ysci_cen) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
webbpsf/distortion.py
Outdated
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverting to aper.convert
.
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 I realized that when I originally authored this code, I made an assumptions about pixels scales and the meaning of 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. |
webbpsf/distortion.py
Outdated
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 |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. 🤣
There was a problem hiding this 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.
@JarronL FYI I tried to look at the test 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. |
I don't understand 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). |
@JarronL what do you think? do you want to go back to doing it per-axis and removing |
Yes, I'm onboard with removing osamp_x = aper.XSciScale / pixelscale
osamp_y = aper.YSciScale / pixelscale
xnew = xarr / osamp_x + xnew_cen
ynew = yarr / osamp_y + ynew_cen |
Would you like me to perform the change in this branch? |
Yes, that would be great! Thanks! |
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).
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.