Updating pointing and observer keywords in the FITS header

This example demonstrates how to update the metadata in an AIA FITS file to ensure that it has the most accurate information regarding the spacecraft pointing and observer position.

import sunpy.map

import aiapy.data.sample as sample_data
from aiapy.calibrate import fix_observer_location, update_pointing

An AIA FITS header contains various pieces of standard. metadata that are critical to the physical interpretation of the data. These include the pointing of the spacecraft, necessary for connecting positions on the pixel grid to physical locations on the Sun, as well as the observer (i.e. satellite) location.

While this metadata is recorded in the FITS header, some values in the headers exported by data providers (e.g. Joint Science Operations Center (JSOC) and the Virtual Solar Observatory may not always be the most accurate. In the case of the spacecraft pointing, a more accurate 3-hourly pointing table is available from the JSOC.

For this example, we will read a 171 Å image from the aiapy sample data into a Map object.

DEBUG: Reading /home/docs/.local/share/aiapy/aia_lev1_171a_2019_01_01t00_00_09_35z_image_lev1.fits [sunpy.map.map_factory]

To update the pointing keywords, we can pass our Map to the aiapy.calibrate.update_pointing function. This function will query the JSOC, using sunpy, for the most recent pointing information, update the metadata, and then return a new Map with this updated metadata.

m_updated_pointing = update_pointing(m)
DEBUG: HCRS->HGS [sunpy.coordinates.transformations]
DEBUG: ├─From: <HCRS Coordinate (obstime=2019-01-01T00:00:09.350): (ra, dec, distance) in (deg, deg, m)
       │           (100.8640075, 23.05574953, 1.47085021e+11)> [sunpy.coordinates.transformations]
DEBUG: ├─To  : <HeliographicStonyhurst Frame (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km)> [sunpy.coordinates.transformations]
DEBUG: └─Out : <HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, m)
                   (-0.01480901, -2.97611845, 1.47085021e+11)> [sunpy.coordinates.transformations]
DEBUG: HPC->HPC [sunpy.coordinates.transformations]
DEBUG: ├─From: <Helioprojective Coordinate (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km, observer=<HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km): (lon, lat, radius) in (deg, deg, m)
       │           (-0.01480901, -2.97611845, 1.47085021e+11)>): (Tx, Ty) in arcsec
       │           (0., 0.)> [sunpy.coordinates.transformations]
DEBUG: ├─To  : <Helioprojective Frame (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km, observer=<HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km): (lon, lat, radius) in (deg, deg, m)
       │           (-0.01480901, -2.97611845, 1.47085021e+11)>)> [sunpy.coordinates.transformations]
DEBUG: └─Out : <Helioprojective Coordinate (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km, observer=<HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=696000.0 km): (lon, lat, radius) in (deg, deg, m)
                   (-0.01480901, -2.97611845, 1.47085021e+11)>): (Tx, Ty) in arcsec
                   (0., 0.)> [sunpy.coordinates.transformations]
DEBUG: Running following query: aia.master_pointing3h[2018.12.31_12:00:46_TAI-2019.01.01_12:00:46_TAI] [sunpy.net.jsoc.jsoc]
DEBUG: Requesting following keywords: **ALL** [sunpy.net.jsoc.jsoc]

If we inspect the reference pixel and rotation matrix of the original map

PixelPair(x=<Quantity 2055.310059 pix>, y=<Quantity 2045.709961 pix>)
[[ 9.99999944e-01 -3.34562158e-04]
 [ 3.34562158e-04  9.99999944e-01]]

and the map with the updated pointing information

PixelPair(x=<Quantity 2055.501465 pix>, y=<Quantity 2046.018311 pix>)
[[ 9.99999944e-01 -3.34562158e-04]
 [ 3.34562158e-04  9.99999944e-01]]

we find that the relevant keywords, CRPIX1, CRPIX2, CDELT1, CDELT2, and CROTA2, have been updated.

Similarly, the Heliographic Stonyhurst (HGS) coordinates of the observer location in the header are inaccurate. If we check the HGS longitude keyword in the header, we find that it is 0 degrees which is not the HGS longitude coordinate of SDO.

print(m_updated_pointing.meta["hgln_obs"])
print(m_updated_pointing.meta["hglt_obs"])
0.0
-2.976075

To update the HGS observer coordinates, we can use the aiapy.calibrate.fix_observer_location function. This function reads the correct observer location from Heliocentric Aries Ecliptic (HAE) coordinates in the header, converts them to HGS, and replaces the inaccurate HGS keywords.

m_observer_fixed = fix_observer_location(m_updated_pointing)
DEBUG: HCRS->HGS [sunpy.coordinates.transformations]
DEBUG: ├─From: <HCRS Coordinate (obstime=2019-01-01T00:00:09.350): (ra, dec, distance) in (deg, deg, m)
       │           (100.8640075, 23.05574953, 1.47085021e+11)> [sunpy.coordinates.transformations]
DEBUG: ├─To  : <HeliographicStonyhurst Frame (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km)> [sunpy.coordinates.transformations]
DEBUG: └─Out : <HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, m)
                   (-0.01480901, -2.97611845, 1.47085021e+11)> [sunpy.coordinates.transformations]

Looking again at the HGS longitude and latitude keywords, we can see that they have been updated.

print(m_observer_fixed.meta["hgln_obs"])
print(m_observer_fixed.meta["hglt_obs"])
-0.01480900749072589
-2.976118447285844

Note that in AIAMap, the observer_coordinate attribute is already derived from the HAE coordinates such that it is not strictly necessary to apply aiapy.calibrate.fix_observer_location. For example, the unfixed Map will still have an accurate derived observer position

DEBUG: HCRS->HGS [sunpy.coordinates.transformations]
DEBUG: ├─From: <HCRS Coordinate (obstime=2019-01-01T00:00:09.350): (ra, dec, distance) in (deg, deg, m)
       │           (100.8640075, 23.05574953, 1.47085021e+11)> [sunpy.coordinates.transformations]
DEBUG: ├─To  : <HeliographicStonyhurst Frame (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km)> [sunpy.coordinates.transformations]
DEBUG: └─Out : <HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, m)
                   (-0.01480901, -2.97611845, 1.47085021e+11)> [sunpy.coordinates.transformations]
<SkyCoord (HeliographicStonyhurst: obstime=2019-01-01T00:00:09.350, rsun=696000.0 km): (lon, lat, radius) in (deg, deg, m)
    (-0.01480901, -2.97611845, 1.47085021e+11)>

However, we suggest that users apply this fix such that the information stored in meta is accurate and consistent.

Finally, plot the fixed map.

AIA $171 \; \mathrm{\mathring{A}}$ 2019-01-01 00:00:09
DEBUG: HCRS->HGS [sunpy.coordinates.transformations]
DEBUG: ├─From: <HCRS Coordinate (obstime=2019-01-01T00:00:09.350): (ra, dec, distance) in (deg, deg, m)
       │           (100.8640075, 23.05574953, 1.47085021e+11)> [sunpy.coordinates.transformations]
DEBUG: ├─To  : <HeliographicStonyhurst Frame (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km)> [sunpy.coordinates.transformations]
DEBUG: └─Out : <HeliographicStonyhurst Coordinate (obstime=2019-01-01T00:00:09.350, rsun=695700.0 km): (lon, lat, radius) in (deg, deg, m)
                   (-0.01480901, -2.97611845, 1.47085021e+11)> [sunpy.coordinates.transformations]

Total running time of the script: ( 0 minutes 3.099 seconds)

Gallery generated by Sphinx-Gallery