-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Good for representing images from unknown instruments.
- Loading branch information
1 parent
ea833d9
commit bb74daa
Showing
6 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import astropy.units as u | ||
import astropy.coordinates | ||
from astropy.wcs import WCS | ||
from sunpy.coordinates.frameattributes import ObserverCoordinateAttribute | ||
from sunpy.coordinates.frames import HeliographicStonyhurst, SunPyBaseCoordinateFrame | ||
from sunpy.sun.constants import radius as _RSUN | ||
|
||
__all__ = ["Projective"] | ||
|
||
|
||
X_CTYPE = "PJLN-TAN" | ||
Y_CTYPE = "PJLT-TAN" | ||
|
||
|
||
class Projective(SunPyBaseCoordinateFrame): | ||
"""A generic projective coordinate frame for a imaging taken by an arbitrary imager.""" | ||
observer = ObserverCoordinateAttribute(HeliographicStonyhurst) | ||
rsun = astropy.coordinates.QuantityAttribute(default=_RSUN, unit=u.km) | ||
frame_specific_representation_info = { | ||
astropy.coordinates.SphericalRepresentation: [ | ||
astropy.coordinates.RepresentationMapping("lon", "Tx", u.arcsec), | ||
astropy.coordinates.RepresentationMapping("lat", "Ty", u.arcsec), | ||
astropy.coordinates.RepresentationMapping("distance", "distance"), | ||
], | ||
astropy.coordinates.UnitSphericalRepresentation: [ | ||
astropy.coordinates.RepresentationMapping("lon", "Tx", u.arcsec), | ||
astropy.coordinates.RepresentationMapping("lat", "Ty", u.arcsec), | ||
], | ||
} | ||
|
||
|
||
def projective_wcs_to_frame(wcs): | ||
r""" | ||
This function registers the coordinate frames to their FITS-WCS coordinate | ||
type values in the `astropy.wcs.utils.wcs_to_celestial_frame` registry. | ||
Parameters | ||
---------- | ||
wcs : `astropy.wcs.WCS` | ||
Returns | ||
------- | ||
: `Projective` | ||
""" | ||
if hasattr(wcs, "coordinate_frame"): | ||
return wcs.coordinate_frame | ||
|
||
# Not a lat,lon coordinate system bail out early | ||
if set(wcs.wcs.ctype) != {X_CTYPE, Y_CTYPE}: | ||
return None | ||
|
||
dateavg = wcs.wcs.dateobs | ||
|
||
rsun = wcs.wcs.aux.rsun_ref | ||
if rsun is not None: | ||
rsun *= u.m | ||
|
||
hgs_longitude = wcs.wcs.aux.hgln_obs | ||
hgs_latitude = wcs.wcs.aux.hglt_obs | ||
hgs_distance = wcs.wcs.aux.dsun_obs | ||
|
||
observer = HeliographicStonyhurst( | ||
lat=hgs_latitude * u.deg, lon=hgs_longitude * u.deg, radius=hgs_distance * u.m, obstime=dateavg, rsun=rsun | ||
) | ||
|
||
frame_args = {"obstime": dateavg, "observer": observer, "rsun": rsun} | ||
|
||
return Projective(**frame_args) | ||
|
||
|
||
def projective_frame_to_wcs(frame, projection="TAN"): | ||
r""" | ||
For a given frame, this function returns the corresponding WCS object. | ||
It registers the WCS coordinates types from their associated frame in the | ||
`astropy.wcs.utils.celestial_frame_to_wcs` registry. | ||
Parameters | ||
---------- | ||
frame : `Projective` | ||
projection : `str`, optional | ||
Returns | ||
------- | ||
`astropy.wcs.WCS` | ||
""" | ||
# Bail out early if not STIXImaging frame | ||
if not isinstance(frame, Projective): | ||
return None | ||
|
||
wcs = WCS(naxis=2) | ||
wcs.wcs.aux.rsun_ref = frame.rsun.to_value(u.m) | ||
|
||
# Sometimes obs_coord can be a SkyCoord, so convert down to a frame | ||
obs_frame = frame.observer | ||
if hasattr(obs_frame, "frame"): | ||
obs_frame = frame.observer.frame | ||
|
||
wcs.wcs.aux.hgln_obs = obs_frame.lon.to_value(u.deg) | ||
wcs.wcs.aux.hglt_obs = obs_frame.lat.to_value(u.deg) | ||
wcs.wcs.aux.dsun_obs = obs_frame.radius.to_value(u.m) | ||
|
||
wcs.wcs.dateobs = frame.obstime.utc.iso | ||
wcs.wcs.cunit = ["arcsec", "arcsec"] | ||
wcs.wcs.ctype = [X_CTYPE, Y_CTYPE] | ||
|
||
return wcs | ||
|
||
|
||
# Remove once min version of sunpy has https://github.com/sunpy/sunpy/pull/7594 | ||
astropy.wcs.utils.WCS_FRAME_MAPPINGS.insert(1, [projective_wcs_to_frame]) | ||
astropy.wcs.utils.FRAME_WCS_MAPPINGS.insert(1, [projective_frame_to_wcs]) | ||
|
||
PROJECTIVE_CTYPE_TO_UCD1 = { | ||
"SXLT": "custom:pos.projective.lat", | ||
"SXLN": "custom:pos.projective.lon", | ||
"SXRZ": "custom:pos.projective.z", | ||
} | ||
astropy.wcs.wcsapi.fitswcs.CTYPE_TO_UCD1.update(PROJECTIVE_CTYPE_TO_UCD1) |
Binary file not shown.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import astropy.units as u | ||
import numpy as np | ||
import pytest | ||
from astropy.wcs import WCS | ||
from sunpy.coordinates import HeliographicStonyhurst | ||
from xrayvision.coordinates.frames import Projective, projective_frame_to_wcs, projective_wcs_to_frame | ||
|
||
|
||
@pytest.fixture | ||
def projective_wcs(): | ||
w = WCS(naxis=2) | ||
|
||
w.wcs.dateobs = "2024-01-01 00:00:00.000" | ||
w.wcs.crpix = [10, 20] | ||
w.wcs.cdelt = np.array([2, 2]) | ||
w.wcs.crval = [0, 0] | ||
w.wcs.ctype = ["PJLN-TAN", "PJLT-TAN"] | ||
|
||
w.wcs.aux.hgln_obs = 10 | ||
w.wcs.aux.hglt_obs = 20 | ||
w.wcs.aux.dsun_obs = 1.5e11 | ||
|
||
return w | ||
|
||
|
||
@pytest.fixture | ||
def projective_frame(): | ||
obstime = "2024-01-01" | ||
observer = HeliographicStonyhurst(10 * u.deg, 20 * u.deg, 1.5e11 * u.m, obstime=obstime) | ||
|
||
frame_args = {"obstime": obstime, "observer": observer, "rsun": 695_700_000 * u.m} | ||
|
||
frame = Projective(**frame_args) | ||
return frame | ||
|
||
|
||
def test_projective_wcs_to_frame(projective_wcs): | ||
frame = projective_wcs_to_frame(projective_wcs) | ||
assert isinstance(frame, Projective) | ||
|
||
assert frame.obstime.isot == "2024-01-01T00:00:00.000" | ||
assert frame.rsun == 695700 * u.km | ||
assert frame.observer == HeliographicStonyhurst( | ||
10 * u.deg, 20 * u.deg, 1.5e11 * u.m, obstime="2024-01-01T00:00:00.000" | ||
) | ||
|
||
|
||
def test_projective_wcs_to_frame_none(): | ||
w = WCS(naxis=2) | ||
w.wcs.ctype = ["ham", "cheese"] | ||
frame = projective_wcs_to_frame(w) | ||
|
||
assert frame is None | ||
|
||
|
||
def test_projective_frame_to_wcs(projective_frame): | ||
wcs = projective_frame_to_wcs(projective_frame) | ||
|
||
assert isinstance(wcs, WCS) | ||
assert wcs.wcs.ctype[0] == "PJLN-TAN" | ||
assert wcs.wcs.cunit[0] == "arcsec" | ||
assert wcs.wcs.dateobs == "2024-01-01 00:00:00.000" | ||
|
||
assert wcs.wcs.aux.rsun_ref == projective_frame.rsun.to_value(u.m) | ||
assert wcs.wcs.aux.dsun_obs == 1.5e11 | ||
assert wcs.wcs.aux.hgln_obs == 10 | ||
assert wcs.wcs.aux.hglt_obs == 20 | ||
|
||
|
||
def test_projective_frame_to_wcs_none(): | ||
wcs = projective_frame_to_wcs(HeliographicStonyhurst()) | ||
assert wcs is None |