Skip to content

Commit

Permalink
Merge pull request sunpy#7220 from TrestanSimon/add-gong-map-class
Browse files Browse the repository at this point in the history
Add gong map class
  • Loading branch information
dstansby authored Oct 22, 2023
2 parents 7821330 + 2c4db6d commit 2d9b74a
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/7220.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a GONG synoptic map class which fixes non-compliant FITS metadata
78 changes: 78 additions & 0 deletions sunpy/data/test/gong_synoptic.header
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
SIMPLE = T / Written by IDL: Sat Sep 30 07:44:13 2023
BITPIX = -32 / Bits per pixel
NAXIS = 2 / Number of axes
NAXIS1 = 360 / Axis length
NAXIS2 = 180 / Axis length
EXTEND = F / File may contain extensions
ORIGIN = 'National Solar Observatory -- GONG' / FITS file originator
OBS-SITE= 'NSO/GONG NETWORK' / Instrument site location
TELESCOP= 'NSO-GONG' / NSO/GONG Network
OBS-URL = 'http://gong.nso.edu' / The GONG website
DATE = '2023-09-30T06:44:00'
DATE-OBS= '2023-09-30'
TIME-OBS= '06:44 '
DATATYPE= 'REAL*4 ' / Type of data
WAVELNTH= 676.8 / Wavelength of obs (nm)
CAM_TYPE= 'SMD ' / Camera manufacture type
SN_CAMS = '1014 1016 1027 1029 1017' / Camera serial numbers
CAR_ROT = 2276 / Carr-rot. number of position 0.0
WCSNAME = 'Carrington Cylin-equal-area'
CTYPE1 = 'CRLN-CEA' / Carrington longitude
CTYPE2 = 'CRLT-CEA' / Carrington sine latitude
CRPIX1 = 180.500 / 180 degrees from initial longitude
CRPIX2 = 90.5000 / Equator of map
CRVAL1 = 130 / Carrington longitude of map cntr (deg)
CRVAL2 = 0.00000 / Sine-lat of Equator
PV2_1 = 1.00000 / Lambda for latitude coordinate
CDELT1 = 1.00000 / Carrington long. step (deg)
CDELT2 = 0.0111111 / Sine-lat step
WCSNAMEA= 'Carrington-rotation Cylin-equal-area'
CTYPE1A = 'CRN-CEA ' / Carrington rotation number
CTYPE2A = 'CRLT-CEA' / Carrington sine latitude
CRPIX1A = 180.500 / Half rotation from initial pixel
CRPIX2A = 90.5000 / Equator of map
CRVAL1A = 2275.638889 / Carr-rot of map cntr
CRVAL2A = 0.00000 / Sine-lat of Equator
PV2_1A = 1.00000 / Lambda for latitude coordinate
CDELT1A = -0.00277777777778 / Carrington step (rotation)
CDELT2A = 0.0111111 / Sine-lat step
IMTYPE = 'MAGNETIC'
NFILETOT= 4281 / Total number of files included
LONG0 = 310 / Init. Carr-long. of synoptic map
IMGMN01 = -0.082834 / Image mean
IMGRMS01= 23.409344 / Image RMS (Standard Deviation)
IMGSKW01= 4.185349 / Image skewness
IMGMIN01= -509.079071 / Image Min
IMGMAX01= 846.215271 / Image Max
IMGADV01= 7.367440 / Image Average Deviation
IMGVAR01= 547.997375 / Image Variance
IMGKUR01= 189.706238 / Image Kurtosis
MMREL = 'v2.3 '
CARROT = 2276
BUNIT = 'Gauss '
LONGMC = 72.0
LONGIMC = 72
LONGADJ = -0.3273368
MAPCOUNT= 4281
MAPL0 = 10
MAPEDGE = 310
CREDGE = 2276.138889 / Carr-rot of map left edge
CRNOW = 2275.9731315 / Carr-rot of Now
CR60 = 2275.9722222 / Carr-rot of 60 degrees in
CRCENTER= 2275.6388889 / Carr-rot of map cntr
MAPNAME = '2276_310'
MAPDATE = '2023-09-30' / UT Date of this map (i.e. of last contributor)
MAPTIME = '06:44 ' / UT Time of this map (i.e. of last contributor)
FILELIST= 'mrbql230930t0644c2276_310'
COMMENT
COMMENT Please note:
COMMENT This is an hourly GONG product with UT date MAPDATE and UT time MAPTIME
COMMENT which is between 59.5 and 60.5 degrees from the left edge in the
COMMENT Carrington frame.
COMMENT
COMMENT This GONG product is produced from the QRII data stream.
COMMENT
COMMENT See http://gong.nso.edu for more information about GONG.
COMMENT
PLATFORM= 'Linux ncs-gong-proc1-lx redhat NOAO/IRAF V2.13-BETA'
FITSWASH= '$RCSfile: mag_hourly.kw,v $ $Revision: 2.4 $ $Date: 2021/11/05 23:35'
1 change: 1 addition & 0 deletions sunpy/map/sources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

from sunpy.map.map_factory import Map
from .gong import *
from .hinode import *
from .iris import *
from .mlso import *
Expand Down
59 changes: 59 additions & 0 deletions sunpy/map/sources/gong.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
GONG Map subclass definitions
"""
import numpy as np

import astropy.units as u
from astropy.time import Time

from sunpy.coordinates import get_earth
from sunpy.map import GenericMap

__all__ = ['GONGSynopticMap']

from sunpy.map.mapbase import SpatialPair


class GONGSynopticMap(GenericMap):
"""
GONG Synoptic Map.
The Global Oscillation Network Group (GONG) operates a six-station network of velocity
imagers located around the Earth that observe the Sun nearly continuously. GONG
produces hourly photospheric magnetograms using the Ni I 676.8 nm spectral line with an
array of 242×256 pixels covering the solar disk. These magnetograms are used to derive
synoptic maps which show a full-surface picture of the solar magnetic field.
References
----------
* `GONG Page <https://gong.nso.edu/>`_
* `Magnetogram Synoptic Map Images Page <https://gong.nso.edu/data/magmap/>`_
* `FITS header keywords <https://gong.nso.edu/data/DMAC_documentation/General/fitsdesc.html>`_
* `Instrument Paper (pp. 203–208) <https://inis.iaea.org/collection/NCLCollectionStore/_Public/20/062/20062491.pdf>`_
* `GONG+ Documentation <https://gong.nso.edu/data/DMAC_documentation/PipelineMap/GlobalMap.html>`_
"""

@classmethod
def is_datasource_for(cls, data, header, **kwargs):
return (str(header.get('TELESCOP', '')).endswith('GONG') and
str(header.get('CTYPE1', '').startswith('CRLN')))

@property
def date(self):
return Time(f"{self.meta.get('date-obs')} {self.meta.get('time-obs')}")

@property
def scale(self):
# Since, this map uses the cylindrical equal-area (CEA) projection,
# the spacing should be modified to 180/pi times the original value
# Reference: Section 5.5, Thompson 2006
return SpatialPair(self.meta['cdelt1'] * self.spatial_units[0] / u.pixel,
self.meta['cdelt2'] * 180 / np.pi * self.spatial_units[0] / u.pixel)

@property
def spatial_units(self):
return SpatialPair(u.deg, u.deg)

@property
def observer_coordinate(self):
return get_earth(self.date)
52 changes: 52 additions & 0 deletions sunpy/map/sources/tests/test_gong_synoptic_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pytest

import astropy.units as u

from sunpy.data.test import get_dummy_map_from_header, get_test_filepath
from sunpy.map.sources.gong import GONGSynopticMap


@pytest.fixture
def gong_synoptic():
return get_dummy_map_from_header(get_test_filepath('gong_synoptic.header'))


def test_fitstoGONGSynoptic(gong_synoptic):
"""Tests the creation of GongSynopticMap using FITS."""
assert isinstance(gong_synoptic, GONGSynopticMap)


def test_is_datasource_for(gong_synoptic):
"""Test the is_datasource_for method of GongSynopticMap."""
assert gong_synoptic.is_datasource_for(gong_synoptic.data, gong_synoptic.meta)


def test_observatory(gong_synoptic):
"""Tests the observatory property of the GongSynopticMap object."""
assert gong_synoptic.observatory == "NSO-GONG"


def test_measurement(gong_synoptic):
"""Tests the measurement property of the GongSynopticMap object."""
assert gong_synoptic.measurement == 676.8


def test_date(gong_synoptic):
"""Check that accessing the date doesn't raise a warning."""
gong_synoptic.date


def test_unit(gong_synoptic):
assert gong_synoptic.unit == u.G
assert gong_synoptic.unit == u.Unit("Mx/cm^2")
assert gong_synoptic.unit.to_string() == 'G'


def test_spatial_units(gong_synoptic):
assert gong_synoptic.spatial_units[0] == u.deg
assert gong_synoptic.spatial_units[1] == u.deg


def test_wcs(gong_synoptic):
# Smoke test that WCS is valid and can transform from pixels to world coordinates
gong_synoptic.pixel_to_world(0*u.pix, 0*u.pix)

0 comments on commit 2d9b74a

Please sign in to comment.