SEP | 5 |
---|---|
title | Coordinates Module |
author(s) | Pritish Chakraborty Stuart Mumford |
contact email | chakrabortypritish@gmail.com, stuart@mumford.me.uk |
date-creation | 2014-05-18 |
type | standard |
discussion | Google Group Thread |
status | accepted |
This SEP describes the implementation of a new SunPy submodule
sunpy.coordinates
. This submodule will provide objects to
represent spatial coordinates in all of the common solar physics
coordinate systems.
This submodule will utilize the Astropy coordinates submodule and
integrate heavily with that module.
This new submodule will replace most of the functionality currently
present in sunpy.wcs
.
Astropy's new coordinates submodule (released as part of Astropy v0.4.0) provides a well designed and appropriate framework for implementing solar physics coordinate transformations. The details of this framework are described below.
The coordinates package is designed to provide transformations
between physical spatial coordinates, it does not provide the pixel
to world coordinate transformation framework. This is handled via
astropy.wcs
.
The following provide some definitions used in this document with regards to coordinates. These are based on the definitions in APE5.
-
Coordinate Representation: It is a particular way of describing a unique point in a vector space (usually 3D space). Some examples of significance to SunPy are the Cartesian and Cylindrical representations.
-
Reference System: It is a scheme used to orient points in a space. It is used to describe how a point is transformed from system to system. Examples from the Astropy codebase are the ICRS and equatorial coordinates (mean equinox) systems.
-
Coordinate Frame: This is a specific realization of a reference system. Some systems may have only one meaningful frame while yet others may have several different frames. A tentative example in the proposed SunPy subpackage would be that of the heliographic coordinates, with Stonyhurst and Carrington realizations.
The Astropy coordinate submodule has three sets of classes:
-
Data Representation: The representation of the coordinate point in 3D space. The representation can be considered as the coordinate vector, for example, in Cartesian, Cylindrical or Spherical systems. These classes are generally not used by the user, apart from in advanced use cases. These representations hold their data in
Quantity
objects or subclasses. -
Low-Level Frames: These classes are the objects that describe the coordinate system, origin, default representation etc. They also can hold the coordinate data (in a representation object), however, a frame does not have to hold coordinate information and can just represent the reference system.
-
High-Level Object: The high level object is the
astropy.coordinates.SkyCoord
object which provides the primary interface to both Astropy's coordinates submodule and SunPy's. This class can handle a wider variety of input and will sanitize this input and create aCoordinateFrame
class.
The four primary coordinate systems, i.e., heliographic
(Stonyhurst and Carrington), heliocentric and helioprojective
systems will be implemented. These will take the form of
low-level frame classes - HelioGraphicStonyhurst
, HelioGraphicCarrington
,
HelioCentric
and HelioProjective
. These will be made to subclass from
astropy.coordinates.BaseCoordinateFrame
.
To facilitate the convention of both helioprojective and
heliographic coordinate systems of wrapping Longitude at 180° a
custom SphericalWarp180Representation
object will be created as a
subclass of astropy.coordinates.SphericalRepresentation
to set the
Longitude wrapping to 180°.
No modification to or subclassing of SkyCoord
will occur to
maintain maximum possible compatibility and interoperability with
Astropy and other packages which use its coordinates framework.
Creating a helioprojective SkyCoord
object::
import astropy.units as u
from astropy.coordinates import SkyCoord
import sunpy.coordinates
sc1 = SkyCoord(230*u.arcsec, 120*u.arcsec, frame='helioprojective')
Transforming this object to heliographic Stonyhurst:
sc2 = sc1.transform_to('heliographicstonyhurst')
Creation of an object from astropy Quantity objects:
Tx = np.random.random([10])*100 * u.arcsec
Ty = np.random.random([10])*100 * u.arcsec
sc3 = SkyCoord(Tx, Ty, frame='helioprojective')
Because the helioprojective coordinate system is a projective system, where it is unusual to have information on the third spatial dimension of a coordinate, some assumptions are normally made when transforming from helioprojective to heliocentric coordinates.
This assumption (as currently implemented in sunpy.wcs
) is that
during transformation, if no helioprojective radial coordinate was specified
then the radial coordinate is calculated as if the coordinate point
is on the solar surface.
The third coordinate can be specified explicitly upon construction:
sc = SkyCoord(230*u.arcsec, 120*u.arcsec, 1*u.au, frame='helioprojective')
or will be calculated to facilitate transformations to other frames.
The third coordinate above is distance to the point from the
observer, i.e. radial distance in a spherical coordinate system.
Optionally, the third coordinate can be specified as zeta = Dsun - distance
, thus:
sc = SkyCoord(230*u.arcsec, 120*u.arcsec, zeta=695.5e3*u.km,
frame='helioprojective')
Fundamental to the coordinate transformations in solar physics is
the position of the observer. To pass this information to the
coordinate frame objects, the FrameAttribute
classes are used.
These classes provide immutable attributes of the frame class, where
default values can be selected and values can be passed into either
the frame constructors or the SkyCoord
constructor.
All of the frames have all the attributes needed for any frame transformation defined, this way if all the attribute values are specified or take their default values all the transformations can be performed on the data.
The frame attributes are:
- D0: Distance to solar center from the observer [default: 1 AU].
- L0: Heliographic longitude of the observer [default: 0°].
- B0: Heliographic latitude of the observer [default: 0°].
- dateobs: Date and time of the observation [no default].
The transformations between the frame classes are defined on a
bi-directional transformation graph which is specified in
astropy.coordinates
.
The SunPy frames can register their transformations on this graph
and are therefore detected by astropy.coordinates
and each solar
coordinate system can be transformed to any other, even if no direct
route between the nodes exists on the graph.
This implementation also allows the possibility of defining a transformation from a solar frame to an astronomical frame in the future and therefore allowing the transformation of any solar coordinate to any astronomical coordinate via the transformation graph.
from sunpy.coordinates.frames import HelioGraphicStonyhurst, HelioCentric, HelioProjective
from astropy.coordinates import SkyCoord, UnitSphericalRepresentation
from astropy import units as u
# Some ways to initialize a `SkyCoord` object.
# In Heliographic Stonyhurst frames, one can declare so -:
sc = SkyCoord(
1*u.deg, 1*u.deg, 1*u.km, frame='heliographicstonyhurst',
dateobs='2011/01/01T00:00:45'
)
print(sc)
<SkyCoord (HelioGraphicStonyhurst): B0=0.0 deg, dateobs=2011-01-01 00:00:45, L0=0.0 deg, hlon=1.0 deg, hlat=1.0 deg, rad=1.0 km>
# We can transform the data to another frame.
print(sc.transform_to('heliocentric'))
<SkyCoord (HelioCentric): D0=149597870.7 km, B0=0.0 deg, dateobs=2011-01-01 00:00:45, L0=0.0 deg, x=0.0174497483513 km, y=0.0174524064373 km, z=0.99969541351 km>
# One could also not give the distance/radius input, and it will
# default to solar radius.
sc = SkyCoord(
1*u.deg, 1*u.deg, frame='heliographicstonyhurst',
dateobs='2011/01/01T00:00:45'
)
print(sc)
<SkyCoord (HelioGraphicStonyhurst): B0=0.0 deg, dateobs=2011-01-01 00:00:45, L0=0.0 deg, hlon=1.0 deg, hlat=1.0 deg, rad=695508.0 km>
# It is also possible to provide the representation-specific args as a
# `BaseRepresentation` object.
from sunpy.coordinates.representation import SphericalWrap180Representation
sc = SkyCoord(
SphericalWrap180Representation(1*u.deg, 1*u.deg, 1*u.km),
frame='helioprojective', dateobs='2011/01/01T00:00:45'
)
print(sc)
<SkyCoord (HelioProjective): L0=0.0 deg, B0=0.0 deg, dateobs=2011-01-01 00:00:45, D0=149597870.7 km, Tx=3600.0 arcsec, Ty=3600.0 arcsec, distance=1.0 km>
# It is also possible to create a frame object directly
fr = HelioProjective(L0=10*u.deg, B0=-1.*u.deg, dateobs='2011/01/01T00:00:45')
print(fr)
<HelioProjective Frame: L0=10.0 deg, B0=-1.0 deg, dateobs=2011-01-01 00:00:45, D0=149597870.7 km>
# You can then realise this frame to get another frame with data:
print(fr.realize_frame(UnitSphericalRepresentation(230*u.arcsec, 10*u.arcsec)))
<HelioProjective Coordinate: L0=10.0 deg, B0=-1.0 deg, dateobs=2011-01-01 00:00:45, D0=149597870.7 km, Tx=230.0 arcsec, Ty=10.0 arcsec, distance=148922609.068 km>
Accepted at the board meeting on 2014-10-17 by a vote of 6-0.