Add SpectralCoord class to astropy.coordinates#10185
Conversation
|
Am hoping to have another look... But OK to merge if that doesn't happen before end of day. |
There was a problem hiding this comment.
Alright, I've finished a full review - it's almost all minor suggestion/nitpicks, and I'm approving because none are blockers. A few higher-level items that didn't have an obvious inline-location:
- Should
SpectralQuantitybe inunitsinstead ofcoordinates? - Somewhere in the docs this should say that it's the relativistic redshift to rv convention, not v=c*z . That is a convention, even if it's not the most "physical" one.
And two more items that could be follow-on items (i.e., could be done now or later depending on time left):
- Is a "quick start"/at-a-glance section needed for the SpectralCoord docs?
SpectrumQuantitywould be quite a bit more convenient if it had the spectral flux density equivalency as a semi-baked in option. To not delay anything I'll just try implementing that as a PR to this PR, but can always change it to against master and include it later.
| elif doppler_convention not in DOPPLER_CONVENTIONS: | ||
| raise ValueError("doppler_convention should be one of {0}".format('/'.join(sorted(DOPPLER_CONVENTIONS)))) | ||
|
|
||
| if self.unit.is_equivalent(si.km / si.s) and unit.is_equivalent(si.km / si.s): |
There was a problem hiding this comment.
minor (premature?) optimization you can take or ignore as you like: have a si.km/si.s computed at the global level do not have to make km/s every time to is called
| radial_velocity : `~astropy.units.Quantity`, optional | ||
| The radial velocity of the target with respect to the observer. | ||
| redshift : float, optional | ||
| The relativistic redshift of the target with respect to the observer. |
There was a problem hiding this comment.
Might be worth noting you can't give RV and redshift at the same time?
| return self.__class__(**default_kwargs) | ||
|
|
||
| @property | ||
| def quantity(self): |
There was a problem hiding this comment.
I preferred as_quantity, but maybe this ship has sailed... (couldn't find @mhvk's logic...)
EDIT by MHvK: It seems I cannot answer, so editing: the logic was to be similar to .value and .physical (from magnitudes, etc.), and also .si, .cgs, .degree (for angle).
Co-authored-by: Erik Tollerud <erik.tollerud@gmail.com>
|
@astrofrog - I don't think I'll get around to another round, but as others approved (and it looked very good), I'm fine with it being merged when you're done with implementing comments and CI passes, etc. |
|
@eteq - thanks for the review! A few quick notes:
It moved there temporarily during this PR, but it was suggested that it should be moved back, as other classes such as
I've added a note to the docs in the latest commit: 28197eb
I don't think it would be easy to add one in the
I'll check your PR - thanks! |
|
@eteq, @astrofrog - I'm not sure I understand the use for spectral flux density - would this be if combined with a |
|
@mhvk - here is @eteq's PR: astrofrog#100 - it's more a convenience property to get a spectral density equivalency for that spectral quantity. |
|
Ah, that property makes sense, though personally I'd first see what is useful in practice - after all, |
OK, I'll re-cast that into a PR against master since I don't want it to block this one. Since it's clearly had lots of great review at this point and everything as passing, I'm merging this now. Thanks everyone for all the great work on this! |
|
is specutils compatible with this one, or it's not in the plan to switch to using this straight away? (e.g. how much coordination should the release here wait, etc?) |
|
Is there a need to also document this in https://docs.astropy.org/en/latest/io/misc.html#schemas ? |
|
So this broke SunPy's astropy-dev build FYI. I will investigate. |
|
This broke #10154, though one might reasonably view things the other way round. I had to change a spectral coord test due to the strict definition of equality now: 3082a81. I do have to wonder if #10154 will break other tests of code that were explicitly or implicitly using |
|
Perhaps we should reconsider raising the exception and instead return |
About
This pull request implements a new class,
SpectralCoordwhich aims to represent spectral coordinates (wavelengths, frequencies, energies, velocities) and also encapsulates information about observer and target. This starts from the implementation @nmearl wrote in specutils. Also implemented here is aSpectralQuantityclass with default spectral equivalencies as well as a mechanism for keeping track of the doppler convention and rest value.The motivation behind this class was:
to provide a high-level object for use in APE 14 spectral WCSes when calling
WCS.pixel_to_world- currently we returned a Quantity with no meta-data, whereas now we can let the user know what frame of reference the spectral coordinate is for, the direction of the target, and Doppler rest frequencies/wavelengths and conventions used for spectral axes in velocity (this is all information that is part of the FITS WCS standard)to provide a class that could be used in specutils to represent spectral axes (in practice specutils will subclass SpectralCoord into SpectralAxis to provide axis-specific functionality too)
Developers are welcome to start reviewing this PR, but note that there are a few remaining to-dos listed lower down, so this is not at the 'final draft' stage. If you have limited time, you could consider just reviewing the docs to see if you are happy with the API.
Changes to astropy.coordinates
The first set of changes here is to astropy.coordinates - we add a new class
SpectralCoordwhich is a quantity sub-class with metadata and transformation methods. This also includes a new narrative docs page to describe it. This documentation page is not complete in the sense that some of the functionality is not described, but this provides a starting point, and what's there currently is ready for review.Note that
SpectralCoordis deliberately a Quantity sub-class rather than using a more complex infrastructure likeSkyCoordwith many layers of classes. Since we only care about a single coordinate here, this was found to be the simplest API, and also provides backward-compatibility with the current use of the APE 14 FITS WCS (which previously returned Quantity). We do use coordinate frames/SkyCoord to represent observers and targets though.I have included a test that does detailed numerical checks against SLALIB - I plan to include more details about how this was done. For a reason I don't understand our galactocentric results are different, and I will be delving into that. For other frames, we typically get ~20m/s agreement for now.
Changes to astropy.units
I've added a
SpectralQuantityclass which implements aQuantitysubclass that automatically includes spectral equivalencies, and keeps track of the doppler convention and rest value.Changes to astropy.wcs.wcsapi
The second set of changes is to the APE 14 FITS WCS implementation - here we now return
SpectralCoordforpixel_to_world- note that we stilll acceptQuantityas input forworld_to_pixelbut in this case we give a warning that there is no observer defined, so no velocity transformation will be carried out.One big caveat is that for now, the target on the
SpectralCoordis set to the reference celestial coordinate in the case of spectral cubes. For cubes with large fields of view, this won't be quite right away from the reference coordinate. But this is already better than the current situation of returning Quantity. So I am planning to add a caveat about this to the APE 14 WCS docs. Properly implementing this may be tricky because it requires interpreting the SSYSOBS keyword which many cubes lack, and in principle this means that even for an LSRK cube the spectral coordinate is actually intended to be constant across slices in the topocentric frame, which means the spectral axis is correlated with the celestial axes. I think this is a little known fact and many cubes may be produced not knowing this assumption, which I think is why the current implementation may actually reflect the way most people use cubes (and pragmatically, it's also a much easier starting point).git history
The git history was extracted from specutils (where an initial implementation of this class was added), and I've taken care to preserve the PR merge history so that we have references to the original PRs. I can also remove these merge commits if people would prefer, but I think it's quite nice to be able to see the original chunks of work that were done. I'm happy to go with majority opinion!
Remaining to-dos
Things that will be done later after this PR is merged
Add docs forwe discussed below that for now we can avoid overly advertising this, and leaving it to future to decide if we want to.SpectralQuantityAdd higher accuracy tests (currently limited by the starlink output precision)Add high accuracy reference tests for SpectralCoord #10248