From 0d760489676ade281a5ce4ca89198db1195ef3ee Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sat, 30 Sep 2023 02:21:11 -0600 Subject: [PATCH 01/18] Copy GongSynopticMap subclass from pfsspy https://github.com/dstansby/pfsspy/blob/f493e2cdc653e541425f01318ec2f35645ee36d0/pfsspy/map.py#L12 --- sunpy/map/sources/__init__.py | 1 + sunpy/map/sources/gong.py | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 sunpy/map/sources/gong.py diff --git a/sunpy/map/sources/__init__.py b/sunpy/map/sources/__init__.py index a2dbc319aa4..ced82a62f80 100644 --- a/sunpy/map/sources/__init__.py +++ b/sunpy/map/sources/__init__.py @@ -7,6 +7,7 @@ """ from sunpy.map.map_factory import Map +from .gong import * from .hinode import * from .iris import * from .mlso import * diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py new file mode 100644 index 00000000000..c072c2018bc --- /dev/null +++ b/sunpy/map/sources/gong.py @@ -0,0 +1,41 @@ +""" +GONG Map subclass definitions +""" +import numpy as np +from astropy.time import Time + +from sunpy.map import GenericMap + +__all__ = ['GongSynopticMap'] + + +class GongSynopticMap(GenericMap): + def __init__(self, data, header, **kwargs): + # Fix coordinate system stuff + if 'KEYCOMMENTS' in header: + if 'deg' in header['KEYCOMMENTS']['CDELT1']: + header['CUNIT1'] = 'deg' + if header['KEYCOMMENTS']['CDELT2'] == 'Sine-lat step': + header['CUNIT2'] = 'deg' + # Instead of the spacing in sin(lat), this should be 180/pi times + # that value (see Thompson 2005) + header['CDELT2'] = 180 / np.pi * header['CDELT2'] + header['KEYCOMMENTS']['CDELT2'] = '180 / pi * sine-lat step' + # Fix timestamp + if 'time-obs' in header: + header['date-obs'] = (header['date-obs'] + ' ' + + header.pop('time-obs')) + header['date-obs'] = Time(header['date-obs']).isot + # Fix unit + if 'bunit' in header and header['bunit'] == 'Gauss': + header['bunit'] = 'G' + # Fix observer coordinate + if 'hglt_obs' not in header: + header.update(_earth_obs_coord_meta(header['date-obs'])) + super().__init__(data, header, **kwargs) + + @classmethod + def is_datasource_for(cls, data, header, **kwargs): + """Determines if header corresponds to an GONG map.""" + return (str(header.get('TELESCOP', '')).endswith('GONG') and + str(header.get('CTYPE1', '').startswith('CRLN'))) From 93552594b87e3b48ec7e6b29d78da80f6cc71024 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sat, 30 Sep 2023 02:27:47 -0600 Subject: [PATCH 02/18] Add remaining definitions from pfsspy --- sunpy/map/sources/gong.py | 44 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index c072c2018bc..ec7b21067a4 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -3,10 +3,12 @@ """ import numpy as np from astropy.time import Time +import astropy.units as u from sunpy.map import GenericMap +from sunpy.coordinates import get_earth, HeliographicStonyhurst -__all__ = ['GongSynopticMap'] +__all__ = ['GongSynopticMap', 'ADAPTMap'] class GongSynopticMap(GenericMap): @@ -39,3 +41,43 @@ def is_datasource_for(cls, data, header, **kwargs): """Determines if header corresponds to an GONG map.""" return (str(header.get('TELESCOP', '')).endswith('GONG') and str(header.get('CTYPE1', '').startswith('CRLN'))) + + +class ADAPTMap(GenericMap): + def __init__(self, data, header, **kwargs): + if 'date-obs' not in header: + header['date-obs'] = header['maptime'] + # Fix CTYPE + if header['ctype1'] == 'Long': + header['ctype1'] = 'CRLN-CAR' + if header['ctype2'] == 'Lat': + header['ctype2'] = 'CRLT-CAR' + + super().__init__(data, header, **kwargs) + + @classmethod + def is_datasource_for(cls, data, header, **kwargs): + """Determines if header corresponds to an ADAPT map.""" + return header.get('model') == 'ADAPT' + + +def _observer_coord_meta(observer_coord): + """ + Convert an observer coordinate into FITS metadata. + """ + new_obs_frame = HeliographicStonyhurst( + obstime=observer_coord.obstime) + observer_coord = observer_coord.transform_to(new_obs_frame) + + new_meta = {} + new_meta['hglt_obs'] = observer_coord.lat.to_value(u.deg) + new_meta['hgln_obs'] = observer_coord.lon.to_value(u.deg) + new_meta['dsun_obs'] = observer_coord.radius.to_value(u.m) + return new_meta + + +def _earth_obs_coord_meta(obstime): + """ + Return metadata for an Earth obeserver coordinate. + """ + return _observer_coord_meta(get_earth(obstime)) From e3f68da483dcd9722d2ad5e8e022e871f3d6d4d4 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sat, 30 Sep 2023 03:48:10 -0600 Subject: [PATCH 03/18] Adapt tests from pfsspy for gong synoptic --- sunpy/data/test/gong_synoptic.header | 78 +++++++++++++++++++ .../tests/test_gong_synoptic_source.py | 55 +++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 sunpy/data/test/gong_synoptic.header create mode 100644 sunpy/map/sources/tests/test_gong_synoptic_source.py diff --git a/sunpy/data/test/gong_synoptic.header b/sunpy/data/test/gong_synoptic.header new file mode 100644 index 00000000000..f97c89fbe44 --- /dev/null +++ b/sunpy/data/test/gong_synoptic.header @@ -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' diff --git a/sunpy/map/sources/tests/test_gong_synoptic_source.py b/sunpy/map/sources/tests/test_gong_synoptic_source.py new file mode 100644 index 00000000000..67412a32e23 --- /dev/null +++ b/sunpy/map/sources/tests/test_gong_synoptic_source.py @@ -0,0 +1,55 @@ +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' + gong_synoptic.meta['bunit'] = 'm' + assert gong_synoptic.unit == u.m + + +def test_coordinate_system(gong_synoptic): + assert gong_synoptic.meta['CUNIT1'] == 'deg' + assert gong_synoptic.meta['CUNIT2'] == 'deg' + + +def test_observer(gong_synoptic): + assert gong_synoptic.meta['hglt_obs'] is not None + assert gong_synoptic.meta['hgln_obs'] is not None + assert gong_synoptic.meta['dsun_obs'] is not None From 5b001a7104e5c026e668bfc4a92f6627e60dae4f Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sat, 30 Sep 2023 04:10:29 -0600 Subject: [PATCH 04/18] Adapt tests from pfsspy for adapt map --- sunpy/data/test/adapt.header | 267 ++++++++++++++++++ sunpy/map/sources/gong.py | 4 +- sunpy/map/sources/tests/test_adapt_source.py | 33 +++ .../tests/test_gong_synoptic_source.py | 4 +- 4 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 sunpy/data/test/adapt.header create mode 100644 sunpy/map/sources/tests/test_adapt_source.py diff --git a/sunpy/data/test/adapt.header b/sunpy/data/test/adapt.header new file mode 100644 index 00000000000..f26fc1c96ab --- /dev/null +++ b/sunpy/data/test/adapt.header @@ -0,0 +1,267 @@ +SIMPLE = T / file does conform to FITS standard +BITPIX = -32 / number of bits per data pixel +NAXIS = 3 / number of data axes +NAXIS1 = 360 / length of data axis 1 +NAXIS2 = 180 / length of data axis 2 +NAXIS3 = 12 / length of data axis 3 +EXTEND = T / FITS dataset may contain extensions +ADD_DATE= 20231003 / Date for new map +ADD_UT = 8. / UT for new map +LASTSITE= 8 / Last obs site: Udaipur (GONG) +LAST_OBS= 3.052778 / Days since last obs merged +LAST_RND= 0. / Time since random flux merged +NEVODAYS= 11432.08 / No. of days evolved from init seed map +NMODEL = 16 / Number of realizations used in model +NREAL = 12 / Number of realizations in this file +COVERAGE= 100 / Percent of columns with 3+ obs +MISSING = -9999. / Value filled in for missing pixels +MONOINIT= 0.02154954 / Initial monopole value +MONOFINL= 0.02154954 / Final monopole value +MONODMOD= 0. / Model % monopole dampening +MONODPUB= 0. / Public % monopole dampening +MONOCUT = 1. / Flux cutoff for monopole correction +FLUXSCAL= 0. / Scaling applied to input data +SM_MTHD = 2 / Smoothing Type: Hanning +SM_CUT_E= 60. / Equatorial Smoothing Cutoff [deg] +SM_RAD_E= 0.03490658 / Equatorial Smoothing Radius [solar rad] +SM_CUT_P= 75. / Polar Smoothing Cutoff [deg] +SM_RAD_P= 0.042 / Polar Smoothing Radius [solar rad] +MAPTIME = '2023-10-03T08:00:00' / Date & time info for map/mag +MAPDATA = 'GONG ' / Data instrument/telescope source +MAPJUL = 2460220.83333333 / Julian Date of latest map/mag +MAPLON = 329.49301120572 / Carrington long @ CM of latest map/obs +MAPCR = 2276.08474163554 / Carrington rot @ CM of latest map/obs +EPHEM_B0= 6.632232 / Solar B0 at time of latest map/mag +MAPTYPE = 'synchronic' / Type of synoptic map +MAPPARAM= 'mag ' / Map obs data parameter type +CRLNGEDG= 149. / WSA SPEC: Carr-long of leading edge +CRROTEDG= 2276 / WSA SPEC: Carr-rot of leading edge +MAPCREDG= 2276.586 / Carrington rot of leading edge +GRID = 1. / Uniform grid res: del(lat)=del(lng) +ATTR_RES= 1 / Attract map spatial-res: 1.0 deg/pix +LNGTYPE = 1 / Central Meridian: Obs CM @ map center +LATTYPE = 0 / Latitude +MAG_TYPE= 0 / Mag: Not added and/or no data +HEL_TYPE= 0 / Helioseismic: Not added and/or no data +LAST_FAR= -9999. / Time since last farside DA [days] +LAST_NER= -9999. / Time since last nearside DA [days] +LAST_NPL= -9999. / Time since last north pole DA [days] +LAST_SPL= -9999. / Time since last south pole DA [days] +MODEL = 'ADAPT ' / Model Name +MODELDA = 1 / DA model: Ensemble Least Squares +MODELVER= '3.1106 ' / Model Version: [YY - 9].MMDD +MODPAR01= 0.0209 / Mean map supergran size +MODPAR02= 23.4 / Mean map supergran lifetime (hr) +MODPAR03= 8. / North: Mean map meridional flow rate +MODPAR04= -8. / South: Mean map meridional flow rate +MODPAR05= 2.913 / North: Mean map diff-rot coef A +MODPAR06= 0.405 / North: Mean map diff-rot coef B +MODPAR07= 0.422 / North: Mean map diff-rot coef C +MODPAR08= 2.913 / South: Mean map diff-rot coef A +MODPAR09= 0.405 / South: Mean map diff-rot coef B +MODPAR10= 0.422 / South: Mean map diff-rot coef C +MODPAR11= 25. / Mean map mag-field sgran cutoff (Gauss) +MODPAR12= 2.1 / Mean map random flux amp (Gauss) +WCSNAME = 'Heliocentric-cart' +CTYPE1 = 'Long ' / Coordinate axis label +CTYPE2 = 'Lat ' / Coordinate axis label +CRPIX1 = 180.5 / Current X position for center +CRPIX2 = 90.5 / Current Y position for center +CUNIT1 = 'deg ' / X axis units +CUNIT2 = 'deg ' / Y axis units +CDELT1 = 1. / X resolution [deg/pxl] +CDELT2 = 1. / Y resolution [deg/pxl] +CRVAL1 = 329. / Reference pixel value +CRVAL2 = 0. / Reference pixel value +SIMPLE = T / file does conform to FITS standard +BITPIX = -32 / number of bits per data pixel +NAXIS = 3 / number of data axes +NAXIS1 = 360 / length of data axis 1 +NAXIS2 = 180 / length of data axis 2 +NAXIS3 = 12 / length of data axis 3 +EXTEND = T / FITS dataset may contain extensions +ADD_DATE= 20231003 / Date for new map +ADD_UT = 8. / UT for new map +LASTSITE= 8 / Last obs site: Udaipur (GONG) +LAST_OBS= 3.052778 / Days since last obs merged +LAST_RND= 0. / Time since random flux merged +NEVODAYS= 11432.08 / No. of days evolved from init seed map +NMODEL = 16 / Number of realizations used in model +NREAL = 12 / Number of realizations in this file +COVERAGE= 100 / Percent of columns with 3+ obs +MISSING = -9999. / Value filled in for missing pixels +MONOINIT= 0.02154954 / Initial monopole value +MONOFINL= 0.02154954 / Final monopole value +MONODMOD= 0. / Model % monopole dampening +MONODPUB= 0. / Public % monopole dampening +MONOCUT = 1. / Flux cutoff for monopole correction +FLUXSCAL= 0. / Scaling applied to input data +SM_MTHD = 2 / Smoothing Type: Hanning +SM_CUT_E= 60. / Equatorial Smoothing Cutoff [deg] +SM_RAD_E= 0.03490658 / Equatorial Smoothing Radius [solar rad] +SM_CUT_P= 75. / Polar Smoothing Cutoff [deg] +SM_RAD_P= 0.042 / Polar Smoothing Radius [solar rad] +MAPTIME = '2023-10-03T08:00:00' / Date & time info for map/mag +MAPDATA = 'GONG ' / Data instrument/telescope source +MAPJUL = 2460220.83333333 / Julian Date of latest map/mag +MAPLON = 329.49301120572 / Carrington long @ CM of latest map/obs +MAPCR = 2276.08474163554 / Carrington rot @ CM of latest map/obs +EPHEM_B0= 6.632232 / Solar B0 at time of latest map/mag +MAPTYPE = 'synchronic' / Type of synoptic map +MAPPARAM= 'mag ' / Map obs data parameter type +CRLNGEDG= 149. / WSA SPEC: Carr-long of leading edge +CRROTEDG= 2276 / WSA SPEC: Carr-rot of leading edge +MAPCREDG= 2276.586 / Carrington rot of leading edge +GRID = 1. / Uniform grid res: del(lat)=del(lng) +ATTR_RES= 1 / Attract map spatial-res: 1.0 deg/pix +LNGTYPE = 1 / Central Meridian: Obs CM @ map center +LATTYPE = 0 / Latitude +MAG_TYPE= 0 / Mag: Not added and/or no data +HEL_TYPE= 0 / Helioseismic: Not added and/or no data +LAST_FAR= -9999. / Time since last farside DA [days] +LAST_NER= -9999. / Time since last nearside DA [days] +LAST_NPL= -9999. / Time since last north pole DA [days] +LAST_SPL= -9999. / Time since last south pole DA [days] +MODEL = 'ADAPT ' / Model Name +MODELDA = 1 / DA model: Ensemble Least Squares +MODELVER= '3.1106 ' / Model Version: [YY - 9].MMDD +MODPAR01= 0.0209 / Mean map supergran size +MODPAR02= 23.4 / Mean map supergran lifetime (hr) +MODPAR03= 8. / North: Mean map meridional flow rate +MODPAR04= -8. / South: Mean map meridional flow rate +MODPAR05= 2.913 / North: Mean map diff-rot coef A +MODPAR06= 0.405 / North: Mean map diff-rot coef B +MODPAR07= 0.422 / North: Mean map diff-rot coef C +MODPAR08= 2.913 / South: Mean map diff-rot coef A +MODPAR09= 0.405 / South: Mean map diff-rot coef B +MODPAR10= 0.422 / South: Mean map diff-rot coef C +MODPAR11= 25. / Mean map mag-field sgran cutoff (Gauss) +MODPAR12= 2.1 / Mean map random flux amp (Gauss) +WCSNAME = 'Heliocentric-cart' +CTYPE1 = 'Long ' / Coordinate axis label +CTYPE2 = 'Lat ' / Coordinate axis label +CRPIX1 = 180.5 / Current X position for center +CRPIX2 = 90.5 / Current Y position for center +CUNIT1 = 'deg ' / X axis units +CUNIT2 = 'deg ' / Y axis units +CDELT1 = 1. / X resolution [deg/pxl] +CDELT2 = 1. / Y resolution [deg/pxl] +CRVAL1 = 329. / Reference pixel value +CRVAL2 = 0. / Reference pixel value +XTENSION= 'BINTABLE' / binary table extension +BITPIX = 8 / 8-bit bytes +NAXIS = 2 / 2-dimensional binary table +NAXIS1 = 48 / width of table in bytes +NAXIS2 = 12 / number of rows in table +PCOUNT = 0 / size of special data area +GCOUNT = 1 / one data group (required keyword) +TFIELDS = 12 / number of fields in each row +TTYPE1 = 'sgSize ' / label for field 1 +TFORM1 = '1E ' / data format of field: 4-byte REAL +TUNIT1 = 'radians ' / physical unit of field +TTYPE2 = 'sgLife ' / label for field 2 +TFORM2 = '1E ' / data format of field: 4-byte REAL +TUNIT2 = 'hr ' / physical unit of field +TTYPE3 = 'magCutOff' / label for field 3 +TFORM3 = '1E ' / data format of field: 4-byte REAL +TUNIT3 = 'Gauss ' / physical unit of field +TTYPE4 = 'merid_N ' / label for field 4 +TFORM4 = '1E ' / data format of field: 4-byte REAL +TUNIT4 = 'm/s ' / physical unit of field +TTYPE5 = 'merid_S ' / label for field 5 +TFORM5 = '1E ' / data format of field: 4-byte REAL +TUNIT5 = 'm/s ' / physical unit of field +TTYPE6 = 'difrot_A_N' / label for field 6 +TFORM6 = '1E ' / data format of field: 4-byte REAL +TUNIT6 = ' ' / physical unit of field +TTYPE7 = 'difrot_B_N' / label for field 7 +TFORM7 = '1E ' / data format of field: 4-byte REAL +TUNIT7 = ' ' / physical unit of field +TTYPE8 = 'difrot_C_N' / label for field 8 +TFORM8 = '1E ' / data format of field: 4-byte REAL +TUNIT8 = ' ' / physical unit of field +TTYPE9 = 'difrot_A_S' / label for field 9 +TFORM9 = '1E ' / data format of field: 4-byte REAL +TUNIT9 = ' ' / physical unit of field +TTYPE10 = 'difrot_B_S' / label for field 10 +TFORM10 = '1E ' / data format of field: 4-byte REAL +TUNIT10 = ' ' / physical unit of field +TTYPE11 = 'difrot_C_S' / label for field 11 +TFORM11 = '1E ' / data format of field: 4-byte REAL +TUNIT11 = ' ' / physical unit of field +TTYPE12 = 'ranAmp ' / label for field 12 +TFORM12 = '1E ' / data format of field: 4-byte REAL +TUNIT12 = 'Gauss ' / physical unit of field +EXTNAME = 'ensemParmInfo' / name of this binary table extension +XTENSION= 'BINTABLE' / binary table extension +BITPIX = 8 / 8-bit bytes +NAXIS = 2 / 2-dimensional binary table +NAXIS1 = 36 / width of table in bytes +NAXIS2 = 12 / number of rows in table +PCOUNT = 0 / size of special data area +GCOUNT = 1 / one data group (required keyword) +TFIELDS = 9 / number of fields in each row +TTYPE1 = 'mnMapAll' / label for field 1 +TFORM1 = '1E ' / data format of field: 4-byte REAL +TUNIT1 = 'Gauss ' / physical unit of field +TTYPE2 = 'mnMapNH ' / label for field 2 +TFORM2 = '1E ' / data format of field: 4-byte REAL +TUNIT2 = 'Gauss ' / physical unit of field +TTYPE3 = 'mnMapSH ' / label for field 3 +TFORM3 = '1E ' / data format of field: 4-byte REAL +TUNIT3 = 'Gauss ' / physical unit of field +TTYPE4 = 'mnPol_60N' / label for field 4 +TFORM4 = '1E ' / data format of field: 4-byte REAL +TUNIT4 = 'Gauss ' / physical unit of field +TTYPE5 = 'mnPol_69N' / label for field 5 +TFORM5 = '1E ' / data format of field: 4-byte REAL +TUNIT5 = 'Gauss ' / physical unit of field +TTYPE6 = 'mnPol_6090N' / label for field 6 +TFORM6 = '1E ' / data format of field: 4-byte REAL +TUNIT6 = 'Gauss ' / physical unit of field +TTYPE7 = 'mnPol_60S' / label for field 7 +TFORM7 = '1E ' / data format of field: 4-byte REAL +TUNIT7 = 'Gauss ' / physical unit of field +TTYPE8 = 'mnPol_69S' / label for field 8 +TFORM8 = '1E ' / data format of field: 4-byte REAL +TUNIT8 = 'Gauss ' / physical unit of field +TTYPE9 = 'mnPol_6090S' / label for field 9 +TFORM9 = '1E ' / data format of field: 4-byte REAL +TUNIT9 = 'Gauss ' / physical unit of field +EXTNAME = 'ensemStatInfo' / name of this binary table extension +XTENSION= 'BINTABLE' / binary table extension +BITPIX = 8 / 8-bit bytes +NAXIS = 2 / 2-dimensional binary table +NAXIS1 = 36 / width of table in bytes +NAXIS2 = 12 / number of rows in table +PCOUNT = 0 / size of special data area +GCOUNT = 1 / one data group (required keyword) +TFIELDS = 9 / number of fields in each row +TTYPE1 = 'mnMapAll' / label for field 1 +TFORM1 = '1E ' / data format of field: 4-byte REAL +TUNIT1 = 'Gauss ' / physical unit of field +TTYPE2 = 'mnMapNH ' / label for field 2 +TFORM2 = '1E ' / data format of field: 4-byte REAL +TUNIT2 = 'Gauss ' / physical unit of field +TTYPE3 = 'mnMapSH ' / label for field 3 +TFORM3 = '1E ' / data format of field: 4-byte REAL +TUNIT3 = 'Gauss ' / physical unit of field +TTYPE4 = 'mnPol_60N' / label for field 4 +TFORM4 = '1E ' / data format of field: 4-byte REAL +TUNIT4 = 'Gauss ' / physical unit of field +TTYPE5 = 'mnPol_69N' / label for field 5 +TFORM5 = '1E ' / data format of field: 4-byte REAL +TUNIT5 = 'Gauss ' / physical unit of field +TTYPE6 = 'mnPol_6090N' / label for field 6 +TFORM6 = '1E ' / data format of field: 4-byte REAL +TUNIT6 = 'Gauss ' / physical unit of field +TTYPE7 = 'mnPol_60S' / label for field 7 +TFORM7 = '1E ' / data format of field: 4-byte REAL +TUNIT7 = 'Gauss ' / physical unit of field +TTYPE8 = 'mnPol_69S' / label for field 8 +TFORM8 = '1E ' / data format of field: 4-byte REAL +TUNIT8 = 'Gauss ' / physical unit of field +TTYPE9 = 'mnPol_6090S' / label for field 9 +TFORM9 = '1E ' / data format of field: 4-byte REAL +TUNIT9 = 'Gauss ' / physical unit of field +EXTNAME = 'ensemStatInfo2' / name of this binary table extension diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index ec7b21067a4..e880e98b843 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -8,10 +8,10 @@ from sunpy.map import GenericMap from sunpy.coordinates import get_earth, HeliographicStonyhurst -__all__ = ['GongSynopticMap', 'ADAPTMap'] +__all__ = ['GONGSynopticMap', 'ADAPTMap'] -class GongSynopticMap(GenericMap): +class GONGSynopticMap(GenericMap): def __init__(self, data, header, **kwargs): # Fix coordinate system stuff if 'KEYCOMMENTS' in header: diff --git a/sunpy/map/sources/tests/test_adapt_source.py b/sunpy/map/sources/tests/test_adapt_source.py new file mode 100644 index 00000000000..ae31f7f59ef --- /dev/null +++ b/sunpy/map/sources/tests/test_adapt_source.py @@ -0,0 +1,33 @@ +import pytest + +from sunpy.data.test import get_dummy_map_from_header, get_test_filepath +from sunpy.map.sources.gong import ADAPTMap + + +@pytest.fixture +def adapt_map(): + return get_dummy_map_from_header(get_test_filepath('adapt.header')) + + +def test_fitstoADAPTMap(adapt_map): + """Tests the creation of ADAPTMap using FITS.""" + assert isinstance(adapt_map, ADAPTMap) + + +def test_is_datasource_for(adapt_map): + """Test the is_datasource_for method of GongSynopticMap.""" + assert adapt_map.is_datasource_for(adapt_map.data, adapt_map.meta) + + +def test_date(adapt_map): + """Check that accessing the date doesn't raise a warning.""" + adapt_map.date + + +def test_date_maptime(adapt_map): + assert adapt_map.meta['date-obs'] == adapt_map.meta['maptime'] + + +def test_ctype(adapt_map): + assert adapt_map.meta['ctype1'] == 'CRLN-CAR' + assert adapt_map.meta['ctype2'] == 'CRLT-CAR' diff --git a/sunpy/map/sources/tests/test_gong_synoptic_source.py b/sunpy/map/sources/tests/test_gong_synoptic_source.py index 67412a32e23..82a8e794df8 100644 --- a/sunpy/map/sources/tests/test_gong_synoptic_source.py +++ b/sunpy/map/sources/tests/test_gong_synoptic_source.py @@ -3,7 +3,7 @@ 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 +from sunpy.map.sources.gong import GONGSynopticMap @pytest.fixture @@ -13,7 +13,7 @@ def gong_synoptic(): def test_fitstoGONGSynoptic(gong_synoptic): """Tests the creation of GongSynopticMap using FITS.""" - assert isinstance(gong_synoptic, GongSynopticMap) + assert isinstance(gong_synoptic, GONGSynopticMap) def test_is_datasource_for(gong_synoptic): From 5687ad6a345d54ca0388c7b5fbb0bd13d4836717 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sun, 1 Oct 2023 03:50:37 -0600 Subject: [PATCH 05/18] Add documentation --- sunpy/map/sources/gong.py | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index e880e98b843..525e9089eb0 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -12,6 +12,32 @@ 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. + + Notes + ----- + SunPy automatically fixes non-compliant FITS metadata in GONG maps. Namely, CDELT2 is + converted to degrees and CUNIT1 and CUNIT2 are set to 'deg'; DATE-OBS is converted to + ISO format; BUNIT is set to 'G'; and HGLT_OBS, HGLN_OBS, and DSUN_OBS are set to the + appropriate values for an observer on Earth. + + References + ---------- + * `GONG Page `_ + * `Magnetogram Synoptic Map Images Page `_ + * `FITS header keywords `_ + * `Instrument Paper (pp. 203–208) `_ + * `GONG+ Documentation `_ + + + """ def __init__(self, data, header, **kwargs): # Fix coordinate system stuff if 'KEYCOMMENTS' in header: @@ -44,6 +70,20 @@ def is_datasource_for(cls, data, header, **kwargs): class ADAPTMap(GenericMap): + """ + ADAPT Map. + + The Air Force Data Assimilative Photospheric Flux Transport (ADAPT) model + evolves the solar magnetic flux when no observations are available and + updates the modeled flux with data assimilation. KPVT,SOLIS/VSM, and GONG + magnetograms are used. + + References + ---------- + * `ADAPT Model Page `_ + * `ADAPT Model Paper `_ + * `ADAPT Maps data access `_ + """ def __init__(self, data, header, **kwargs): if 'date-obs' not in header: header['date-obs'] = header['maptime'] From da4f078ef629dd78269e8ef7081413cdaa27ded3 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sun, 1 Oct 2023 03:56:59 -0600 Subject: [PATCH 06/18] Add changelog --- changelog/7220.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/7220.feature.rst diff --git a/changelog/7220.feature.rst b/changelog/7220.feature.rst new file mode 100644 index 00000000000..ef2f0b95a59 --- /dev/null +++ b/changelog/7220.feature.rst @@ -0,0 +1 @@ +Added a GONG synoptic map class and ADAPT map class which fix non-compliant FITS metadata From 4ba2a64a1dd6a1edba47bba902943c9ea3f2cbcc Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sun, 1 Oct 2023 04:03:26 -0600 Subject: [PATCH 07/18] Fix pre-commit issues --- sunpy/map/sources/gong.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 525e9089eb0..53b5c5868d5 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -2,11 +2,12 @@ GONG Map subclass definitions """ import numpy as np -from astropy.time import Time + import astropy.units as u +from astropy.time import Time +from sunpy.coordinates import HeliographicStonyhurst, get_earth from sunpy.map import GenericMap -from sunpy.coordinates import get_earth, HeliographicStonyhurst __all__ = ['GONGSynopticMap', 'ADAPTMap'] @@ -118,6 +119,6 @@ def _observer_coord_meta(observer_coord): def _earth_obs_coord_meta(obstime): """ - Return metadata for an Earth obeserver coordinate. + Return metadata for an Earth observer coordinate. """ return _observer_coord_meta(get_earth(obstime)) From f058ee7ff8e8578c0acf058c14c369d73846f352 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Sun, 1 Oct 2023 18:58:21 -0600 Subject: [PATCH 08/18] Remove ADAPT map class --- changelog/7220.feature.rst | 2 +- sunpy/data/test/adapt.header | 267 ------------------- sunpy/map/sources/gong.py | 34 +-- sunpy/map/sources/tests/test_adapt_source.py | 33 --- 4 files changed, 2 insertions(+), 334 deletions(-) delete mode 100644 sunpy/data/test/adapt.header delete mode 100644 sunpy/map/sources/tests/test_adapt_source.py diff --git a/changelog/7220.feature.rst b/changelog/7220.feature.rst index ef2f0b95a59..f33f9ddd989 100644 --- a/changelog/7220.feature.rst +++ b/changelog/7220.feature.rst @@ -1 +1 @@ -Added a GONG synoptic map class and ADAPT map class which fix non-compliant FITS metadata +Added a GONG synoptic map class which fixes non-compliant FITS metadata diff --git a/sunpy/data/test/adapt.header b/sunpy/data/test/adapt.header deleted file mode 100644 index f26fc1c96ab..00000000000 --- a/sunpy/data/test/adapt.header +++ /dev/null @@ -1,267 +0,0 @@ -SIMPLE = T / file does conform to FITS standard -BITPIX = -32 / number of bits per data pixel -NAXIS = 3 / number of data axes -NAXIS1 = 360 / length of data axis 1 -NAXIS2 = 180 / length of data axis 2 -NAXIS3 = 12 / length of data axis 3 -EXTEND = T / FITS dataset may contain extensions -ADD_DATE= 20231003 / Date for new map -ADD_UT = 8. / UT for new map -LASTSITE= 8 / Last obs site: Udaipur (GONG) -LAST_OBS= 3.052778 / Days since last obs merged -LAST_RND= 0. / Time since random flux merged -NEVODAYS= 11432.08 / No. of days evolved from init seed map -NMODEL = 16 / Number of realizations used in model -NREAL = 12 / Number of realizations in this file -COVERAGE= 100 / Percent of columns with 3+ obs -MISSING = -9999. / Value filled in for missing pixels -MONOINIT= 0.02154954 / Initial monopole value -MONOFINL= 0.02154954 / Final monopole value -MONODMOD= 0. / Model % monopole dampening -MONODPUB= 0. / Public % monopole dampening -MONOCUT = 1. / Flux cutoff for monopole correction -FLUXSCAL= 0. / Scaling applied to input data -SM_MTHD = 2 / Smoothing Type: Hanning -SM_CUT_E= 60. / Equatorial Smoothing Cutoff [deg] -SM_RAD_E= 0.03490658 / Equatorial Smoothing Radius [solar rad] -SM_CUT_P= 75. / Polar Smoothing Cutoff [deg] -SM_RAD_P= 0.042 / Polar Smoothing Radius [solar rad] -MAPTIME = '2023-10-03T08:00:00' / Date & time info for map/mag -MAPDATA = 'GONG ' / Data instrument/telescope source -MAPJUL = 2460220.83333333 / Julian Date of latest map/mag -MAPLON = 329.49301120572 / Carrington long @ CM of latest map/obs -MAPCR = 2276.08474163554 / Carrington rot @ CM of latest map/obs -EPHEM_B0= 6.632232 / Solar B0 at time of latest map/mag -MAPTYPE = 'synchronic' / Type of synoptic map -MAPPARAM= 'mag ' / Map obs data parameter type -CRLNGEDG= 149. / WSA SPEC: Carr-long of leading edge -CRROTEDG= 2276 / WSA SPEC: Carr-rot of leading edge -MAPCREDG= 2276.586 / Carrington rot of leading edge -GRID = 1. / Uniform grid res: del(lat)=del(lng) -ATTR_RES= 1 / Attract map spatial-res: 1.0 deg/pix -LNGTYPE = 1 / Central Meridian: Obs CM @ map center -LATTYPE = 0 / Latitude -MAG_TYPE= 0 / Mag: Not added and/or no data -HEL_TYPE= 0 / Helioseismic: Not added and/or no data -LAST_FAR= -9999. / Time since last farside DA [days] -LAST_NER= -9999. / Time since last nearside DA [days] -LAST_NPL= -9999. / Time since last north pole DA [days] -LAST_SPL= -9999. / Time since last south pole DA [days] -MODEL = 'ADAPT ' / Model Name -MODELDA = 1 / DA model: Ensemble Least Squares -MODELVER= '3.1106 ' / Model Version: [YY - 9].MMDD -MODPAR01= 0.0209 / Mean map supergran size -MODPAR02= 23.4 / Mean map supergran lifetime (hr) -MODPAR03= 8. / North: Mean map meridional flow rate -MODPAR04= -8. / South: Mean map meridional flow rate -MODPAR05= 2.913 / North: Mean map diff-rot coef A -MODPAR06= 0.405 / North: Mean map diff-rot coef B -MODPAR07= 0.422 / North: Mean map diff-rot coef C -MODPAR08= 2.913 / South: Mean map diff-rot coef A -MODPAR09= 0.405 / South: Mean map diff-rot coef B -MODPAR10= 0.422 / South: Mean map diff-rot coef C -MODPAR11= 25. / Mean map mag-field sgran cutoff (Gauss) -MODPAR12= 2.1 / Mean map random flux amp (Gauss) -WCSNAME = 'Heliocentric-cart' -CTYPE1 = 'Long ' / Coordinate axis label -CTYPE2 = 'Lat ' / Coordinate axis label -CRPIX1 = 180.5 / Current X position for center -CRPIX2 = 90.5 / Current Y position for center -CUNIT1 = 'deg ' / X axis units -CUNIT2 = 'deg ' / Y axis units -CDELT1 = 1. / X resolution [deg/pxl] -CDELT2 = 1. / Y resolution [deg/pxl] -CRVAL1 = 329. / Reference pixel value -CRVAL2 = 0. / Reference pixel value -SIMPLE = T / file does conform to FITS standard -BITPIX = -32 / number of bits per data pixel -NAXIS = 3 / number of data axes -NAXIS1 = 360 / length of data axis 1 -NAXIS2 = 180 / length of data axis 2 -NAXIS3 = 12 / length of data axis 3 -EXTEND = T / FITS dataset may contain extensions -ADD_DATE= 20231003 / Date for new map -ADD_UT = 8. / UT for new map -LASTSITE= 8 / Last obs site: Udaipur (GONG) -LAST_OBS= 3.052778 / Days since last obs merged -LAST_RND= 0. / Time since random flux merged -NEVODAYS= 11432.08 / No. of days evolved from init seed map -NMODEL = 16 / Number of realizations used in model -NREAL = 12 / Number of realizations in this file -COVERAGE= 100 / Percent of columns with 3+ obs -MISSING = -9999. / Value filled in for missing pixels -MONOINIT= 0.02154954 / Initial monopole value -MONOFINL= 0.02154954 / Final monopole value -MONODMOD= 0. / Model % monopole dampening -MONODPUB= 0. / Public % monopole dampening -MONOCUT = 1. / Flux cutoff for monopole correction -FLUXSCAL= 0. / Scaling applied to input data -SM_MTHD = 2 / Smoothing Type: Hanning -SM_CUT_E= 60. / Equatorial Smoothing Cutoff [deg] -SM_RAD_E= 0.03490658 / Equatorial Smoothing Radius [solar rad] -SM_CUT_P= 75. / Polar Smoothing Cutoff [deg] -SM_RAD_P= 0.042 / Polar Smoothing Radius [solar rad] -MAPTIME = '2023-10-03T08:00:00' / Date & time info for map/mag -MAPDATA = 'GONG ' / Data instrument/telescope source -MAPJUL = 2460220.83333333 / Julian Date of latest map/mag -MAPLON = 329.49301120572 / Carrington long @ CM of latest map/obs -MAPCR = 2276.08474163554 / Carrington rot @ CM of latest map/obs -EPHEM_B0= 6.632232 / Solar B0 at time of latest map/mag -MAPTYPE = 'synchronic' / Type of synoptic map -MAPPARAM= 'mag ' / Map obs data parameter type -CRLNGEDG= 149. / WSA SPEC: Carr-long of leading edge -CRROTEDG= 2276 / WSA SPEC: Carr-rot of leading edge -MAPCREDG= 2276.586 / Carrington rot of leading edge -GRID = 1. / Uniform grid res: del(lat)=del(lng) -ATTR_RES= 1 / Attract map spatial-res: 1.0 deg/pix -LNGTYPE = 1 / Central Meridian: Obs CM @ map center -LATTYPE = 0 / Latitude -MAG_TYPE= 0 / Mag: Not added and/or no data -HEL_TYPE= 0 / Helioseismic: Not added and/or no data -LAST_FAR= -9999. / Time since last farside DA [days] -LAST_NER= -9999. / Time since last nearside DA [days] -LAST_NPL= -9999. / Time since last north pole DA [days] -LAST_SPL= -9999. / Time since last south pole DA [days] -MODEL = 'ADAPT ' / Model Name -MODELDA = 1 / DA model: Ensemble Least Squares -MODELVER= '3.1106 ' / Model Version: [YY - 9].MMDD -MODPAR01= 0.0209 / Mean map supergran size -MODPAR02= 23.4 / Mean map supergran lifetime (hr) -MODPAR03= 8. / North: Mean map meridional flow rate -MODPAR04= -8. / South: Mean map meridional flow rate -MODPAR05= 2.913 / North: Mean map diff-rot coef A -MODPAR06= 0.405 / North: Mean map diff-rot coef B -MODPAR07= 0.422 / North: Mean map diff-rot coef C -MODPAR08= 2.913 / South: Mean map diff-rot coef A -MODPAR09= 0.405 / South: Mean map diff-rot coef B -MODPAR10= 0.422 / South: Mean map diff-rot coef C -MODPAR11= 25. / Mean map mag-field sgran cutoff (Gauss) -MODPAR12= 2.1 / Mean map random flux amp (Gauss) -WCSNAME = 'Heliocentric-cart' -CTYPE1 = 'Long ' / Coordinate axis label -CTYPE2 = 'Lat ' / Coordinate axis label -CRPIX1 = 180.5 / Current X position for center -CRPIX2 = 90.5 / Current Y position for center -CUNIT1 = 'deg ' / X axis units -CUNIT2 = 'deg ' / Y axis units -CDELT1 = 1. / X resolution [deg/pxl] -CDELT2 = 1. / Y resolution [deg/pxl] -CRVAL1 = 329. / Reference pixel value -CRVAL2 = 0. / Reference pixel value -XTENSION= 'BINTABLE' / binary table extension -BITPIX = 8 / 8-bit bytes -NAXIS = 2 / 2-dimensional binary table -NAXIS1 = 48 / width of table in bytes -NAXIS2 = 12 / number of rows in table -PCOUNT = 0 / size of special data area -GCOUNT = 1 / one data group (required keyword) -TFIELDS = 12 / number of fields in each row -TTYPE1 = 'sgSize ' / label for field 1 -TFORM1 = '1E ' / data format of field: 4-byte REAL -TUNIT1 = 'radians ' / physical unit of field -TTYPE2 = 'sgLife ' / label for field 2 -TFORM2 = '1E ' / data format of field: 4-byte REAL -TUNIT2 = 'hr ' / physical unit of field -TTYPE3 = 'magCutOff' / label for field 3 -TFORM3 = '1E ' / data format of field: 4-byte REAL -TUNIT3 = 'Gauss ' / physical unit of field -TTYPE4 = 'merid_N ' / label for field 4 -TFORM4 = '1E ' / data format of field: 4-byte REAL -TUNIT4 = 'm/s ' / physical unit of field -TTYPE5 = 'merid_S ' / label for field 5 -TFORM5 = '1E ' / data format of field: 4-byte REAL -TUNIT5 = 'm/s ' / physical unit of field -TTYPE6 = 'difrot_A_N' / label for field 6 -TFORM6 = '1E ' / data format of field: 4-byte REAL -TUNIT6 = ' ' / physical unit of field -TTYPE7 = 'difrot_B_N' / label for field 7 -TFORM7 = '1E ' / data format of field: 4-byte REAL -TUNIT7 = ' ' / physical unit of field -TTYPE8 = 'difrot_C_N' / label for field 8 -TFORM8 = '1E ' / data format of field: 4-byte REAL -TUNIT8 = ' ' / physical unit of field -TTYPE9 = 'difrot_A_S' / label for field 9 -TFORM9 = '1E ' / data format of field: 4-byte REAL -TUNIT9 = ' ' / physical unit of field -TTYPE10 = 'difrot_B_S' / label for field 10 -TFORM10 = '1E ' / data format of field: 4-byte REAL -TUNIT10 = ' ' / physical unit of field -TTYPE11 = 'difrot_C_S' / label for field 11 -TFORM11 = '1E ' / data format of field: 4-byte REAL -TUNIT11 = ' ' / physical unit of field -TTYPE12 = 'ranAmp ' / label for field 12 -TFORM12 = '1E ' / data format of field: 4-byte REAL -TUNIT12 = 'Gauss ' / physical unit of field -EXTNAME = 'ensemParmInfo' / name of this binary table extension -XTENSION= 'BINTABLE' / binary table extension -BITPIX = 8 / 8-bit bytes -NAXIS = 2 / 2-dimensional binary table -NAXIS1 = 36 / width of table in bytes -NAXIS2 = 12 / number of rows in table -PCOUNT = 0 / size of special data area -GCOUNT = 1 / one data group (required keyword) -TFIELDS = 9 / number of fields in each row -TTYPE1 = 'mnMapAll' / label for field 1 -TFORM1 = '1E ' / data format of field: 4-byte REAL -TUNIT1 = 'Gauss ' / physical unit of field -TTYPE2 = 'mnMapNH ' / label for field 2 -TFORM2 = '1E ' / data format of field: 4-byte REAL -TUNIT2 = 'Gauss ' / physical unit of field -TTYPE3 = 'mnMapSH ' / label for field 3 -TFORM3 = '1E ' / data format of field: 4-byte REAL -TUNIT3 = 'Gauss ' / physical unit of field -TTYPE4 = 'mnPol_60N' / label for field 4 -TFORM4 = '1E ' / data format of field: 4-byte REAL -TUNIT4 = 'Gauss ' / physical unit of field -TTYPE5 = 'mnPol_69N' / label for field 5 -TFORM5 = '1E ' / data format of field: 4-byte REAL -TUNIT5 = 'Gauss ' / physical unit of field -TTYPE6 = 'mnPol_6090N' / label for field 6 -TFORM6 = '1E ' / data format of field: 4-byte REAL -TUNIT6 = 'Gauss ' / physical unit of field -TTYPE7 = 'mnPol_60S' / label for field 7 -TFORM7 = '1E ' / data format of field: 4-byte REAL -TUNIT7 = 'Gauss ' / physical unit of field -TTYPE8 = 'mnPol_69S' / label for field 8 -TFORM8 = '1E ' / data format of field: 4-byte REAL -TUNIT8 = 'Gauss ' / physical unit of field -TTYPE9 = 'mnPol_6090S' / label for field 9 -TFORM9 = '1E ' / data format of field: 4-byte REAL -TUNIT9 = 'Gauss ' / physical unit of field -EXTNAME = 'ensemStatInfo' / name of this binary table extension -XTENSION= 'BINTABLE' / binary table extension -BITPIX = 8 / 8-bit bytes -NAXIS = 2 / 2-dimensional binary table -NAXIS1 = 36 / width of table in bytes -NAXIS2 = 12 / number of rows in table -PCOUNT = 0 / size of special data area -GCOUNT = 1 / one data group (required keyword) -TFIELDS = 9 / number of fields in each row -TTYPE1 = 'mnMapAll' / label for field 1 -TFORM1 = '1E ' / data format of field: 4-byte REAL -TUNIT1 = 'Gauss ' / physical unit of field -TTYPE2 = 'mnMapNH ' / label for field 2 -TFORM2 = '1E ' / data format of field: 4-byte REAL -TUNIT2 = 'Gauss ' / physical unit of field -TTYPE3 = 'mnMapSH ' / label for field 3 -TFORM3 = '1E ' / data format of field: 4-byte REAL -TUNIT3 = 'Gauss ' / physical unit of field -TTYPE4 = 'mnPol_60N' / label for field 4 -TFORM4 = '1E ' / data format of field: 4-byte REAL -TUNIT4 = 'Gauss ' / physical unit of field -TTYPE5 = 'mnPol_69N' / label for field 5 -TFORM5 = '1E ' / data format of field: 4-byte REAL -TUNIT5 = 'Gauss ' / physical unit of field -TTYPE6 = 'mnPol_6090N' / label for field 6 -TFORM6 = '1E ' / data format of field: 4-byte REAL -TUNIT6 = 'Gauss ' / physical unit of field -TTYPE7 = 'mnPol_60S' / label for field 7 -TFORM7 = '1E ' / data format of field: 4-byte REAL -TUNIT7 = 'Gauss ' / physical unit of field -TTYPE8 = 'mnPol_69S' / label for field 8 -TFORM8 = '1E ' / data format of field: 4-byte REAL -TUNIT8 = 'Gauss ' / physical unit of field -TTYPE9 = 'mnPol_6090S' / label for field 9 -TFORM9 = '1E ' / data format of field: 4-byte REAL -TUNIT9 = 'Gauss ' / physical unit of field -EXTNAME = 'ensemStatInfo2' / name of this binary table extension diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 53b5c5868d5..6febe1d64dc 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -9,7 +9,7 @@ from sunpy.coordinates import HeliographicStonyhurst, get_earth from sunpy.map import GenericMap -__all__ = ['GONGSynopticMap', 'ADAPTMap'] +__all__ = ['GONGSynopticMap'] class GONGSynopticMap(GenericMap): @@ -70,38 +70,6 @@ def is_datasource_for(cls, data, header, **kwargs): str(header.get('CTYPE1', '').startswith('CRLN'))) -class ADAPTMap(GenericMap): - """ - ADAPT Map. - - The Air Force Data Assimilative Photospheric Flux Transport (ADAPT) model - evolves the solar magnetic flux when no observations are available and - updates the modeled flux with data assimilation. KPVT,SOLIS/VSM, and GONG - magnetograms are used. - - References - ---------- - * `ADAPT Model Page `_ - * `ADAPT Model Paper `_ - * `ADAPT Maps data access `_ - """ - def __init__(self, data, header, **kwargs): - if 'date-obs' not in header: - header['date-obs'] = header['maptime'] - # Fix CTYPE - if header['ctype1'] == 'Long': - header['ctype1'] = 'CRLN-CAR' - if header['ctype2'] == 'Lat': - header['ctype2'] = 'CRLT-CAR' - - super().__init__(data, header, **kwargs) - - @classmethod - def is_datasource_for(cls, data, header, **kwargs): - """Determines if header corresponds to an ADAPT map.""" - return header.get('model') == 'ADAPT' - - def _observer_coord_meta(observer_coord): """ Convert an observer coordinate into FITS metadata. diff --git a/sunpy/map/sources/tests/test_adapt_source.py b/sunpy/map/sources/tests/test_adapt_source.py deleted file mode 100644 index ae31f7f59ef..00000000000 --- a/sunpy/map/sources/tests/test_adapt_source.py +++ /dev/null @@ -1,33 +0,0 @@ -import pytest - -from sunpy.data.test import get_dummy_map_from_header, get_test_filepath -from sunpy.map.sources.gong import ADAPTMap - - -@pytest.fixture -def adapt_map(): - return get_dummy_map_from_header(get_test_filepath('adapt.header')) - - -def test_fitstoADAPTMap(adapt_map): - """Tests the creation of ADAPTMap using FITS.""" - assert isinstance(adapt_map, ADAPTMap) - - -def test_is_datasource_for(adapt_map): - """Test the is_datasource_for method of GongSynopticMap.""" - assert adapt_map.is_datasource_for(adapt_map.data, adapt_map.meta) - - -def test_date(adapt_map): - """Check that accessing the date doesn't raise a warning.""" - adapt_map.date - - -def test_date_maptime(adapt_map): - assert adapt_map.meta['date-obs'] == adapt_map.meta['maptime'] - - -def test_ctype(adapt_map): - assert adapt_map.meta['ctype1'] == 'CRLN-CAR' - assert adapt_map.meta['ctype2'] == 'CRLT-CAR' From 6c9d01a799cf996346020de17df2bd70f68435cc Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 11:30:00 -0600 Subject: [PATCH 09/18] Change metadata fixing --- sunpy/map/sources/gong.py | 66 ++++++++++--------- .../tests/test_gong_synoptic_source.py | 10 +-- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 6febe1d64dc..789dde662e8 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -11,6 +11,8 @@ __all__ = ['GONGSynopticMap'] +from sunpy.map.mapbase import SpatialPair + class GONGSynopticMap(GenericMap): """ @@ -36,39 +38,41 @@ class GONGSynopticMap(GenericMap): * `FITS header keywords `_ * `Instrument Paper (pp. 203–208) `_ * `GONG+ Documentation `_ - - """ - def __init__(self, data, header, **kwargs): - # Fix coordinate system stuff - if 'KEYCOMMENTS' in header: - if 'deg' in header['KEYCOMMENTS']['CDELT1']: - header['CUNIT1'] = 'deg' - if header['KEYCOMMENTS']['CDELT2'] == 'Sine-lat step': - header['CUNIT2'] = 'deg' - # Instead of the spacing in sin(lat), this should be 180/pi times - # that value (see Thompson 2005) - header['CDELT2'] = 180 / np.pi * header['CDELT2'] - header['KEYCOMMENTS']['CDELT2'] = '180 / pi * sine-lat step' - # Fix timestamp - if 'time-obs' in header: - header['date-obs'] = (header['date-obs'] + ' ' + - header.pop('time-obs')) - header['date-obs'] = Time(header['date-obs']).isot - # Fix unit - if 'bunit' in header and header['bunit'] == 'Gauss': - header['bunit'] = 'G' - # Fix observer coordinate - if 'hglt_obs' not in header: - header.update(_earth_obs_coord_meta(header['date-obs'])) - super().__init__(data, header, **kwargs) @classmethod def is_datasource_for(cls, data, header, **kwargs): - """Determines if header corresponds to an GONG map.""" return (str(header.get('TELESCOP', '')).endswith('GONG') and str(header.get('CTYPE1', '').startswith('CRLN'))) + @property + def date(self): + return Time(self.meta.get('date-obs') + ' ' + + self.meta.get('time-obs')).isot + + @property + def scale(self): + # Instead of the spacing in sin(lat), this should be 180/pi times + # that value (see Thompson 2005) + 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 unit(self): + unit_str = self.meta.get('bunit', None) + if unit_str == 'Gauss': + return 'G' + else: + return + + @property + def spatial_units(self): + return SpatialPair(u.deg, u.deg) + + @property + def observer_coordinate(self): + return _earth_obs_coord_meta(self.meta['date-obs']) + def _observer_coord_meta(observer_coord): """ @@ -78,11 +82,11 @@ def _observer_coord_meta(observer_coord): obstime=observer_coord.obstime) observer_coord = observer_coord.transform_to(new_obs_frame) - new_meta = {} - new_meta['hglt_obs'] = observer_coord.lat.to_value(u.deg) - new_meta['hgln_obs'] = observer_coord.lon.to_value(u.deg) - new_meta['dsun_obs'] = observer_coord.radius.to_value(u.m) - return new_meta + return { + 'hglt_obs': observer_coord.lat.to_value(u.deg), + 'hgln_obs': observer_coord.lon.to_value(u.deg), + 'dsun_obs': observer_coord.radius.to_value(u.m) + } def _earth_obs_coord_meta(obstime): diff --git a/sunpy/map/sources/tests/test_gong_synoptic_source.py b/sunpy/map/sources/tests/test_gong_synoptic_source.py index 82a8e794df8..ec5455017e7 100644 --- a/sunpy/map/sources/tests/test_gong_synoptic_source.py +++ b/sunpy/map/sources/tests/test_gong_synoptic_source.py @@ -45,11 +45,11 @@ def test_unit(gong_synoptic): def test_coordinate_system(gong_synoptic): - assert gong_synoptic.meta['CUNIT1'] == 'deg' - assert gong_synoptic.meta['CUNIT2'] == 'deg' + assert gong_synoptic.spatial_units[0] == u.deg + assert gong_synoptic.spatial_units[1] == u.deg def test_observer(gong_synoptic): - assert gong_synoptic.meta['hglt_obs'] is not None - assert gong_synoptic.meta['hgln_obs'] is not None - assert gong_synoptic.meta['dsun_obs'] is not None + assert gong_synoptic.observer_coordinate['hglt_obs'] is not None + assert gong_synoptic.observer_coordinate['hgln_obs'] is not None + assert gong_synoptic.observer_coordinate['dsun_obs'] is not None From 7c58043d913a84dbd3574cff240d9b74e9e67152 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 13:58:38 -0600 Subject: [PATCH 10/18] Fix unit property --- sunpy/map/sources/gong.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 789dde662e8..c65e767c0ed 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -60,10 +60,11 @@ def scale(self): @property def unit(self): unit_str = self.meta.get('bunit', None) - if unit_str == 'Gauss': - return 'G' - else: + if unit_str is None: return + elif unit_str == 'Gauss': + return u.G + return u.Unit(unit_str) @property def spatial_units(self): From 7a5c58f1bd858ee59c48756cfc7e5296a7ac6ca1 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 19:16:16 -0600 Subject: [PATCH 11/18] Fix observer_coord property --- sunpy/map/sources/gong.py | 41 ++++++++----------- .../tests/test_gong_synoptic_source.py | 9 ++-- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index c65e767c0ed..9bbe9847cf3 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -4,6 +4,7 @@ import numpy as np import astropy.units as u +from astropy.coordinates import SkyCoord from astropy.time import Time from sunpy.coordinates import HeliographicStonyhurst, get_earth @@ -48,7 +49,7 @@ def is_datasource_for(cls, data, header, **kwargs): @property def date(self): return Time(self.meta.get('date-obs') + ' ' - + self.meta.get('time-obs')).isot + + self.meta.get('time-obs')) @property def scale(self): @@ -72,26 +73,18 @@ def spatial_units(self): @property def observer_coordinate(self): - return _earth_obs_coord_meta(self.meta['date-obs']) - - -def _observer_coord_meta(observer_coord): - """ - Convert an observer coordinate into FITS metadata. - """ - new_obs_frame = HeliographicStonyhurst( - obstime=observer_coord.obstime) - observer_coord = observer_coord.transform_to(new_obs_frame) - - return { - 'hglt_obs': observer_coord.lat.to_value(u.deg), - 'hgln_obs': observer_coord.lon.to_value(u.deg), - 'dsun_obs': observer_coord.radius.to_value(u.m) - } - - -def _earth_obs_coord_meta(obstime): - """ - Return metadata for an Earth observer coordinate. - """ - return _observer_coord_meta(get_earth(obstime)) + observer_coord = get_earth(self.date) + new_obs_frame = HeliographicStonyhurst(obstime=self.date) + observer_coord = observer_coord.transform_to(new_obs_frame) + + sc = SkyCoord( + obstime=self.date, + lon=observer_coord.lon.to_value(u.deg), + lat=observer_coord.lat.to_value(u.deg), + radius=observer_coord.radius.to_value(u.m), + unit=(u.deg, u.deg, u.m), + frame="heliographic_stonyhurst" + ) + sc = sc.heliographic_stonyhurst + + return SkyCoord(sc.replicate(rsun=self._rsun_meters(sc.radius))) diff --git a/sunpy/map/sources/tests/test_gong_synoptic_source.py b/sunpy/map/sources/tests/test_gong_synoptic_source.py index ec5455017e7..31f3dc91d25 100644 --- a/sunpy/map/sources/tests/test_gong_synoptic_source.py +++ b/sunpy/map/sources/tests/test_gong_synoptic_source.py @@ -44,12 +44,11 @@ def test_unit(gong_synoptic): assert gong_synoptic.unit == u.m -def test_coordinate_system(gong_synoptic): +def test_spatial_units(gong_synoptic): assert gong_synoptic.spatial_units[0] == u.deg assert gong_synoptic.spatial_units[1] == u.deg -def test_observer(gong_synoptic): - assert gong_synoptic.observer_coordinate['hglt_obs'] is not None - assert gong_synoptic.observer_coordinate['hgln_obs'] is not None - assert gong_synoptic.observer_coordinate['dsun_obs'] is not None +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) From 6b55f4817ed32da9877c13ea412a3f64603cc6a6 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 19:50:39 -0600 Subject: [PATCH 12/18] Remove unit property Co-authored-by: Will Barnes --- sunpy/map/sources/gong.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 9bbe9847cf3..4c0d321c1d0 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -58,14 +58,6 @@ def scale(self): 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 unit(self): - unit_str = self.meta.get('bunit', None) - if unit_str is None: - return - elif unit_str == 'Gauss': - return u.G - return u.Unit(unit_str) @property def spatial_units(self): From e5c5985ba7b2cddc50da83f4f0d981288cbb6975 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 19:54:06 -0600 Subject: [PATCH 13/18] Use f-string Co-authored-by: Will Barnes --- sunpy/map/sources/gong.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 4c0d321c1d0..536fcd35e7d 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -48,8 +48,7 @@ def is_datasource_for(cls, data, header, **kwargs): @property def date(self): - return Time(self.meta.get('date-obs') + ' ' - + self.meta.get('time-obs')) + return Time(f"{self.meta.get('date-obs')} {self.meta.get('time-obs')}") @property def scale(self): From 2e485d8376e544c67f4d589eebe68eae7b1dd20e Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 19:54:46 -0600 Subject: [PATCH 14/18] Remove base unit override test Co-authored-by: Will Barnes --- sunpy/map/sources/tests/test_gong_synoptic_source.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sunpy/map/sources/tests/test_gong_synoptic_source.py b/sunpy/map/sources/tests/test_gong_synoptic_source.py index 31f3dc91d25..e9a58b215d4 100644 --- a/sunpy/map/sources/tests/test_gong_synoptic_source.py +++ b/sunpy/map/sources/tests/test_gong_synoptic_source.py @@ -40,8 +40,6 @@ 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' - gong_synoptic.meta['bunit'] = 'm' - assert gong_synoptic.unit == u.m def test_spatial_units(gong_synoptic): From 9bdfab6d9c11c331c5de64c6604d1ef0fb4c276b Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 19:59:57 -0600 Subject: [PATCH 15/18] Remove no longer relevant doc notes --- sunpy/map/sources/gong.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 536fcd35e7d..23ead6034b0 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -25,13 +25,6 @@ class GONGSynopticMap(GenericMap): 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. - Notes - ----- - SunPy automatically fixes non-compliant FITS metadata in GONG maps. Namely, CDELT2 is - converted to degrees and CUNIT1 and CUNIT2 are set to 'deg'; DATE-OBS is converted to - ISO format; BUNIT is set to 'G'; and HGLT_OBS, HGLN_OBS, and DSUN_OBS are set to the - appropriate values for an observer on Earth. - References ---------- * `GONG Page `_ @@ -57,7 +50,6 @@ def scale(self): 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) From acaebfdddd7cb192b929251a79aea0be3a338234 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 20:20:02 -0600 Subject: [PATCH 16/18] Simplify observer_coordinate property --- sunpy/map/sources/gong.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 23ead6034b0..3b4affe172b 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -56,18 +56,4 @@ def spatial_units(self): @property def observer_coordinate(self): - observer_coord = get_earth(self.date) - new_obs_frame = HeliographicStonyhurst(obstime=self.date) - observer_coord = observer_coord.transform_to(new_obs_frame) - - sc = SkyCoord( - obstime=self.date, - lon=observer_coord.lon.to_value(u.deg), - lat=observer_coord.lat.to_value(u.deg), - radius=observer_coord.radius.to_value(u.m), - unit=(u.deg, u.deg, u.m), - frame="heliographic_stonyhurst" - ) - sc = sc.heliographic_stonyhurst - - return SkyCoord(sc.replicate(rsun=self._rsun_meters(sc.radius))) + return get_earth(self.date) From 3949d95a627f7f15a49a6014cc4e2b891b1f9eb3 Mon Sep 17 00:00:00 2001 From: Trestan Simon Date: Wed, 18 Oct 2023 20:23:52 -0600 Subject: [PATCH 17/18] Remove unused imports --- sunpy/map/sources/gong.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index 3b4affe172b..f94a9e589bf 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -4,10 +4,9 @@ import numpy as np import astropy.units as u -from astropy.coordinates import SkyCoord from astropy.time import Time -from sunpy.coordinates import HeliographicStonyhurst, get_earth +from sunpy.coordinates import get_earth from sunpy.map import GenericMap __all__ = ['GONGSynopticMap'] From 2c4db6da9c8982344b3691c42fa52a7776c8bc28 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Sun, 22 Oct 2023 18:46:24 +0100 Subject: [PATCH 18/18] Improve explanation of scale correction Co-authored-by: Will Barnes --- sunpy/map/sources/gong.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sunpy/map/sources/gong.py b/sunpy/map/sources/gong.py index f94a9e589bf..60e669da87e 100644 --- a/sunpy/map/sources/gong.py +++ b/sunpy/map/sources/gong.py @@ -44,8 +44,9 @@ def date(self): @property def scale(self): - # Instead of the spacing in sin(lat), this should be 180/pi times - # that value (see Thompson 2005) + # 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)