-
-
Notifications
You must be signed in to change notification settings - Fork 67
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
Flag out NaN weights in coadd & allow for weights to have different WCS than data #474
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #474 +/- ##
==========================================
+ Coverage 91.00% 91.46% +0.45%
==========================================
Files 25 25
Lines 1078 1089 +11
==========================================
+ Hits 981 996 +15
+ Misses 97 93 -4 ☔ View full report in Codecov by Sentry. |
2f67e7d
to
280472f
Compare
Currently broken:
|
Tests now pass locally (w/o sunpy installed...) |
@astrofrog could you review this? There are several critical fixes for spectral-cube's cube mosaicking. Major changes are:
|
For coverage checks: Do we have a dask fits reader, or could we add that in? The byte swapping does get tested in spectral-cube tests, since those sometimes load different endian arrays, but I don't see a simple way to do that here. |
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.
This looks mostly good to me, but one thing I'm not sure about is whether the byteswapping is happening too early here. Could you explain what issues you have been seeing here related to this? The byteswapping should probably ideally happen inside each individual reprojection chunk in case the input isn't a dask array and to avoid doubling memory usage?
Technically I think this might be needed for numpy arrays too, but the FITS reader for numpy arrays already handles that? In any case, I'll report the issues and see if we can move the byteswapping. I haven't worked up a minimal example for the dask byteswapped data; iirc, it was any dask array loaded with a fits reader |
@keflavich - just to check though, why is the byteswapping needed at all? Where does it crash if we don't byteswap? |
it doesn't crash. It interprets the data as having the wrong endianness and all values end up as 2e-205 and similar. |
Ok interesting, is that making use of reproject_interp? |
yes |
so, I didn't figure out how to build a MWE within reproject, but if you comment out the
|
Ok perfect, thanks! |
Ok I have a MWE with just import numpy as np
from astropy.io import fits
from astropy.wcs import WCS
from astropy.utils.data import get_pkg_data_filename
from reproject import reproject_interp
from dask import array as da
hdu1 = fits.open(get_pkg_data_filename("galactic_center/gc_2mass_k.fits"))[0]
hdu2 = fits.open(get_pkg_data_filename("galactic_center/gc_msx_e.fits"))[0]
output_array = np.zeros(
shape=(hdu1.header["NAXIS2"], hdu1.header["NAXIS1"]), dtype=">f8"
)
data = da.from_array(hdu2.data)
wcs = WCS(hdu2.header)
reproject_interp(
(data, wcs), hdu1.header, output_array=output_array, block_size=(50, 50)
)
print(np.nanmin(output_array), np.nanmax(output_array)) and it happens for |
Ok I've spotted the bug, I will open a separate PR shortly |
@keflavich - see #487 |
a28250a
to
0201830
Compare
You should be able to rebase against main now as I have merged the other PR |
(Once you rebase this I will review and merge ASAP) |
…e very rare, but it did happen.
0201830
to
8e42fba
Compare
rebase done |
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.
This looks mostly good but a couple of comments - in particular we shouldn't break APE-14 support. I don't think you need to check has_celestial
, if the weight's WCS isn't compatible with the mosaic WCS then an error will happen during reprojection anyway. We shouldn't ignore the WCS just because it's not celestial?
reproject/mosaicking/coadd.py
Outdated
weights_in, weights_wcs = parse_input_weights( | ||
input_weights[idata], hdu_weights=hdu_weights, return_wcs=True | ||
) | ||
if weights_wcs is None or not weights_wcs.has_celestial: |
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.
weights_wcs.has_celestial
breaks support for APE 14 WCS
reproject/mosaicking/coadd.py
Outdated
@@ -211,7 +211,12 @@ def reproject_and_coadd( | |||
if input_weights is None: | |||
weights_in = None | |||
else: | |||
weights_in = parse_input_weights(input_weights[idata], hdu_weights=hdu_weights) | |||
weights_in, weights_wcs = parse_input_weights( | |||
input_weights[idata], hdu_weights=hdu_weights, return_wcs=True |
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 think this is the only place parse_input_weights is used so I don't think we need the kwarg, we can just always return the WCS
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.
fine by me, i can remove the kwarg
reproject/utils.py
Outdated
return input_weights.data | ||
if return_wcs: | ||
ww = WCS(input_weights.header) | ||
ww = ww if ww.has_celestial else None |
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.
Here we again break compatibility with APE 14 WCS - why is it needed?
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.
This check is serving a critical role and cannot be removed, so we have to think of a replacement.
This check is asking whether the FITS header contains a WCS that should be interpreted as the WCS for the weights. Since WCS()
(i.e., WCS
with an empty dict as input) is still a valid WCS object but contains no transforms, we need some check here whether the WCS exists. Annoyingly, you can't just check that naxis
matches ndim
, since naxis
defaults to 2.
Maybe...
ww = ww if ww.array_shape == input_weights.data.shape
...I'll check this...
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.
no, I don't think that works because the shape comes from the data when reading.
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.
what is the APE14 way to check if there is a transformation associated with an axis?
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 don't think there's any general way to get at this. All WCSes contain valid transforms, so the only solution is to use the full WCS validation. I've added that now. It's less clear for specific cases, but at least it solves the general case.
|
Your suggestion seems to be to just let it break downstream if there is an invalid WCS? That's fine, I guess. I'm not a fan of that strategy in general; I like to catch obvious errors where I know they'll occur. |
@keflavich - I think |
right.... the cube modifications made that possible. OK, I'll get rid of has_celestial, but I think the error messages may be opaque |
This fails now with:
should we just skip these tests? |
Also, |
pre-commit.ci autofix |
for more information, see https://pre-commit.ci
I encountered a severe error case in which the weights array became NaN after reprojection. Flagging out locations where weights is NaN solved the issue.
I cannot come up with an MWE; this occurs deep in the guts of a complicated mosaicking attempt, and it happened for only 1 field out of 270. I think it might be the consequence of a numerical error that occurs only under unique conditions, but it also looks logically like this fix should work.