Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADAPT Client #7463

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f6013fb
moved to dataretriever
GillySpace27 Aug 18, 2023
0215b88
premerge
GillySpace27 Feb 29, 2024
1af871d
updated adapt code
GillySpace27 Feb 29, 2024
ae4fb30
added tests to adaptclient
GillySpace27 Feb 29, 2024
04107b4
make tests client functional
GillySpace27 Mar 1, 2024
6304a8c
remove larger data from repository
GillySpace27 Mar 11, 2024
1080de0
remove setup.cfg
GillySpace27 Mar 11, 2024
6c69b04
fix init files
GillySpace27 Mar 11, 2024
3f3efcc
update adapt source and attr
GillySpace27 Mar 11, 2024
da9ca77
deletions of spurious comments,
GillySpace27 Mar 11, 2024
2993d55
Apply suggestions from code review 1/?
GillySpace27 Mar 26, 2024
2be7f8a
return init file to existence
GillySpace27 Mar 26, 2024
28bc715
update docstring to be compliant
GillySpace27 Mar 26, 2024
10f2597
Removed carrington function and updated the docstring
GillySpace27 May 23, 2024
6b00234
renamed the longitude attribute to be more readable
GillySpace27 May 23, 2024
b0f9208
renamed attribute
GillySpace27 May 23, 2024
072c4d4
imported attrs as a
GillySpace27 May 23, 2024
723fbae
copied over the tests from goes, needs to be updated for adapt
GillySpace27 May 23, 2024
e40a847
update tests and client
nabobalis May 23, 2024
e1e68f1
whatsnew
nabobalis May 24, 2024
c2479d1
changelog
nabobalis May 24, 2024
f5c8188
Update doc test
nabobalis May 24, 2024
e374cb8
Fix tests and docs
nabobalis May 24, 2024
f1376ba
Don't actually need this
nabobalis May 24, 2024
8ef1abb
Merge branch 'main' into main
GillySpace27 May 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,15 @@ package.json

# Log files generated by 'vagrant up'
*.log

# asv stuff
asv_env
asv_results
html

# Figure tests
results
result_images

# Save from Map.save example
aia171.fits
1 change: 1 addition & 0 deletions changelog/7463.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A new client (`sunpy.net.dataretriever.ADAPTClient`) has been added to search and download `ADAPT <https://gong.nso.edu/adapt/maps/gong/>`__ files.
3 changes: 3 additions & 0 deletions docs/reference/net.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ Dataretriever
.. automodapi:: sunpy.net.dataretriever.attrs.goes
:headings: ^"

.. automodapi:: sunpy.net.dataretriever.attrs.adapt
:headings: ^"

JSOC
----

Expand Down
1 change: 1 addition & 0 deletions docs/topic_guide/extending_fido.rst
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ A simple example, which just checks the type of ``attrs`` and not their values w
return supported_attrs.issuperset(query_attrs)

Note, that this method is a class method, it gets called without instantiating your client to speed up the dispatching.
If you are using the `~sunpy.net.dataretriever.client.GenericClient` as a base class, you do not need to implement this method, as it is already implemented in the base class.

Writing a Fetch Method
----------------------
Expand Down
25 changes: 13 additions & 12 deletions docs/tutorial/acquiring_data/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ Fido supports a number of different remote data sources. To see a list the Fido
For details of using `~sunpy.net.Fido` see :ref:`sunpy-tutorial-acquiring-data-index`.
<BLANKLINE>
<BLANKLINE>
Client Description
----------------- -------------------------------------------------------------------------------------------------------
Client Description
----------------- -----------------------------------------------------------------------------------------------------------------------
CDAWEBClient Provides access to query and download from the Coordinated Data Analysis Web (CDAWeb).
ADAPTClient Provides access to the ADvanced Adaptive Prediction Technique (ADAPT) products of the National Solar Observatory (NSO).
EVEClient Provides access to Level 0CS Extreme ultraviolet Variability Experiment (EVE) data.
GBMClient Provides access to data from the Gamma-Ray Burst Monitor (GBM) instrument on board the Fermi satellite.
XRSClient Provides access to several GOES XRS files archive.
Expand Down Expand Up @@ -94,17 +95,17 @@ As an example:
<BLANKLINE>
Specifies the Instrument name for the search.
<BLANKLINE>
Attribute Name Client Full Name Description
--------------------------- ----------- ------------------------ --------------------------------------------------------------------------------
aia VSO AIA Atmospheric Imaging Assembly
bcs VSO BCS Bragg Crystal Spectrometer
be_continuum VSO BE-Continuum INAF-OACT Barra Equatoriale Continuum Instrument
be_halpha VSO BE-Halpha INAF-OACT Barra Equatoriale Hα Instrument
bigbear VSO Big Bear Big Bear Solar Observatory, California TON and GONG+ sites
caii VSO CAII Kanzelhöhe Ca II k Instrument
cds VSO CDS Coronal Diagnostic Spectrometer
celias VSO CELIAS Charge, Element, and Isotope Analysis System
Attribute Name Client ... Description
--------------------------- ----------- ... --------------------------------------------------------------------------------
adapt ADAPT ... ADvanced Adaptive Prediction Technique.
aia VSO ... Atmospheric Imaging Assembly
bcs VSO ... Bragg Crystal Spectrometer
be_continuum VSO ... INAF-OACT Barra Equatoriale Continuum Instrument
be_halpha VSO ... INAF-OACT Barra Equatoriale Hα Instrument
bigbear VSO ... Big Bear Solar Observatory, California TON and GONG+ sites
...
xrs XRS ... GOES X-ray Sensor
xrt VSO ... X-Ray Telescope

This is a full list of known values, a description, and which clients support those values (if you want to search using a specific data source).
Printing attributes like this is supported for most attributes, including client specific ones.
Expand Down
6 changes: 6 additions & 0 deletions docs/whatsnew/6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,9 @@ Deprecate positional arguments in :meth:`sunpy.map.GenericMap.plot`

The arguments for :meth:`sunpy.map.GenericMap.plot` have been changed to being keyword only.
Pass them as keyword arguments (e.g., ``..., title=True, ...``) instead.

Support for ADvanced Adaptive Prediction Technique (ADAPT)
==========================================================

A new map source has been added (``sunpy.map.sources.ADAPTMap``) to support the ADAPT data files.
In addition, a new client (`sunpy.net.dataretriever.ADAPTClient`) has been added to search and download ADAPT files.
6 changes: 3 additions & 3 deletions sunpy/net/attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
In addition to the core attrs defined here, other sunpy clients also provide
attrs specific to them, under:

* `a.vso <sunpy.net.vso.attrs>`
* `a.jsoc <sunpy.net.jsoc.attrs>`
* `a.adapt <sunpy.net.dataretriever.attrs.adapt>`
* `a.goes <sunpy.net.dataretriever.attrs.goes>`
* `a.hek <sunpy.net.hek.attrs>`
* `a.helio <sunpy.net.helio.attrs>`

* `a.jsoc <sunpy.net.jsoc.attrs>`
* `a.vso <sunpy.net.vso.attrs>`
"""
from ._attrs import (
Detector,
Expand Down
1 change: 1 addition & 0 deletions sunpy/net/dataretriever/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

from .client import *
from .sources.adapt import *
from .sources.eve import *
from .sources.fermi_gbm import *
from .sources.goes import *
Expand Down
4 changes: 2 additions & 2 deletions sunpy/net/dataretriever/attrs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from . import goes
from . import adapt, goes

__all__ = ['goes']
__all__ = ['adapt', 'goes']
77 changes: 77 additions & 0 deletions sunpy/net/dataretriever/attrs/adapt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from sunpy.net.attr import SimpleAttr

__all__ = ['ADAPTFileType', 'ADAPTLonType', 'ADAPTInputSource',
'ADAPTDataAssimilation', 'ADAPTResolution', 'ADAPTVersionYear', 'ADAPTVersionMonth',
'ADAPTEvolutionMode', 'ADAPTHelioData', 'ADAPTRealizations', 'ADAPTMagData']

# Define a custom __dir__ to restrict tab-completion to __all__
def __dir__():
return __all__

Check warning on line 9 in sunpy/net/dataretriever/attrs/adapt.py

View check run for this annotation

Codecov / codecov/patch

sunpy/net/dataretriever/attrs/adapt.py#L9

Added line #L9 was not covered by tests


class ADAPTFileType(SimpleAttr):
nabobalis marked this conversation as resolved.
Show resolved Hide resolved
"""
ADAPT file type: Public.
"""
pass

class ADAPTLonType(SimpleAttr):
"""
ADAPT longitude type: Carrington Fixed, Central Meridian, East Limb.
"""
pass

class ADAPTInputSource(SimpleAttr):
"""
ADAPT input source: All, KPVT, VSM, GONG, HMI, MDI, MWO.
"""
pass

class ADAPTDataAssimilation(SimpleAttr):
"""
ADAPT data assimilation: WH, enLS, enkf, enLAKF.
"""
pass

class ADAPTResolution(SimpleAttr):
"""
ADAPT model spatial resolution: 1.0 deg, 0.2 deg.
"""
pass

class ADAPTVersionYear(SimpleAttr):
"""
ADAPT code version year.
"""
pass

class ADAPTVersionMonth(SimpleAttr):
"""
ADAPT code version month.
"""
pass

class ADAPTEvolutionMode(SimpleAttr):
"""
ADAPT evolution mode: Data assimilation step, Intermediate step, Forecast step.
"""
pass

class ADAPTHelioData(SimpleAttr):
"""
ADAPT helioseismic data: Not added or no data, Far-side, Emergence, Both emergence & far-side.
"""
pass

class ADAPTRealizations(SimpleAttr):
"""
ADAPT realizations: number of model/file realizations, e.g., 16 -> "016"
"""
pass


class ADAPTMagData(SimpleAttr):
"""
ADAPT magnetic data: Not added or no data, Mag-los, Mag-vector, Mag- both los & vector, Mag- polar avg obs, Mag- los & polar, Mag- vector & polar, Mag- both los and vector & polar.
"""
pass
94 changes: 94 additions & 0 deletions sunpy/net/dataretriever/sources/adapt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from sunpy.net import attrs as a
from sunpy.net.dataretriever import GenericClient
from sunpy.net.dataretriever.attrs.adapt import (
ADAPTDataAssimilation,
ADAPTEvolutionMode,
ADAPTFileType,
ADAPTHelioData,
ADAPTInputSource,
ADAPTLonType,
ADAPTMagData,
ADAPTRealizations,
ADAPTResolution,
ADAPTVersionMonth,
ADAPTVersionYear,
)

__all__ = ['ADAPTClient']


class ADAPTClient(GenericClient):
GillySpace27 marked this conversation as resolved.
Show resolved Hide resolved
"""
Provides access to the ADvanced Adaptive Prediction Technique (ADAPT) products
of the National Solar Observatory (NSO).

`Searches data hosted by the NSO <https://gong.nso.edu/adapt/maps/gong/>`__

Examples
--------
>>> import astropy.units as u

>>> from sunpy.net import Fido, attrs as a
>>> from sunpy.coordinates.sun import carrington_rotation_time

>>> # Define the Carrington Rotation Number and the number of frames
>>> CR = 2193
>>> frames = 10
>>> date_start = carrington_rotation_time(CR)
>>> date_end = date_start + frames*(3*1.9999999 * u.hour)
>>> longitude_type = '0'

>>> Fido.search(a.Time(date_start, date_end), a.Instrument('adapt'), a.adapt.ADAPTLonType(longitude_type)) # doctest: +REMOTE_DATA
<sunpy.net.fido_factory.UnifiedResponse object at ...>
Results from 1 Provider:
<BLANKLINE>
10 Results from the ADAPTClient:
<BLANKLINE>
Start Time End Time Instrument Provider Source ... ADAPTMagData days_since_last_obs hours_since_last_obs minutes_since_last_obs seconds_since_last_obs
----------------------- ----------------------- ---------- -------- ------ ... ------------ ------------------- -------------------- ---------------------- ----------------------
2017-07-20 08:00:00.000 2017-07-20 08:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-20 14:00:00.000 2017-07-20 14:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-20 20:00:00.000 2017-07-20 20:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-21 02:00:00.000 2017-07-21 02:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-21 08:00:00.000 2017-07-21 08:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-21 14:00:00.000 2017-07-21 14:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-21 20:00:00.000 2017-07-21 20:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-22 02:00:00.000 2017-07-22 02:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
2017-07-22 08:00:00.000 2017-07-22 08:00:59.999 ADAPT NSO GONG ... 1 0 4 36 0
2017-07-22 14:00:00.000 2017-07-22 14:00:59.999 ADAPT NSO GONG ... 1 0 1 56 0
<BLANKLINE>
<BLANKLINE>

References
----------
`Names and possible attrs values are available <https://gong.nso.edu/adapt/maps/adapt_filename_notes.txt>`__.
"""
baseurl = r'https://gong.nso.edu/adapt/maps/gong/%Y/adapt(\d){5}_(\d){2}(\w){1}(\d){3}_(\d){12}_(\w){1}(\d){8}(\w){1}(\d){1}\.fts\.gz'
pattern = '{}adapt{ADAPTFileType:1d}{ADAPTLonType:1d}{ADAPTInputSource:1d}{ADAPTDataAssimilation:1d}{ADAPTResolution:1d}' + \
'_{ADAPTVersionYear:2d}{ADAPTVersionMonth:1l}{ADAPTRealizations:3d}_{year:4d}{month:2d}{day:2d}{hour:2d}{minute:2d}' + \
'_{ADAPTEvolutionMode:1l}{days_since_last_obs:2d}{hours_since_last_obs:2d}{minutes_since_last_obs:2d}{seconds_since_last_obs:2d}{ADAPTHelioData:1l}{ADAPTMagData:1d}.fts.gz'

@classmethod
def _attrs_module(cls):
return 'adapt', 'sunpy.net.dataretriever.attrs.adapt'

@classmethod
def register_values(cls):
adict = {
a.Instrument: [('ADAPT', 'ADvanced Adaptive Prediction Technique.')],
a.Provider: [('NSO', 'National Solar Observatory.')],
a.Source: [('GONG', 'Global Oscillation Network Group.')],
nabobalis marked this conversation as resolved.
Show resolved Hide resolved
ADAPTFileType: [('4', 'Public')],
ADAPTLonType: [('0', 'Carrington Fixed'), ('1', 'Central Meridian'), ('2', 'East Limb')],
ADAPTInputSource: [('0', 'All'), ('1', 'KPVT'), ('2', 'VSM'), ('3', 'GONG'), ('4', 'HMI'), ('5', 'MDI'), ('6', 'MWO')],
ADAPTDataAssimilation: [('0', 'WH'), ('1', 'enLS'), ('2', 'enkf'), ('3', 'enLAKF')],
ADAPTResolution: [('1', '1.0 deg'), ('2', '0.2 deg')],
ADAPTVersionYear: [(str(i), f"Code version year -> {2000 + i}") for i in range(1, 20)],
ADAPTRealizations: [(str(i), f"Number of Realizations -> {i}") for i in range(1, 20)],
ADAPTVersionMonth: [(chr(i+96), f"Code version month -> {i}") for i in range(1, 13)],
ADAPTEvolutionMode: [('a', 'Data assimilation step'), ('i', 'Intermediate step'), ('f', 'Forecast step')],
ADAPTHelioData: [('n', 'Not added or no data'), ('f', 'Far-side'), ('e', 'Emergence'), ('b', 'Both emergence & far-side')],
ADAPTMagData: [('0', 'Not added or no data'), ('1', 'Mag-los'), ('2', 'Mag-vector'), ('3', 'Mag- both los & vector'),
('4', 'Mag- polar avg obs'), ('5', 'Mag- los & polar'), ('6', 'Mag- vector & polar'), ('7', 'Mag- both los and vector & polar')]
}
return adict
104 changes: 104 additions & 0 deletions sunpy/net/dataretriever/sources/tests/test_adapt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

import tempfile

import pytest
from hypothesis import given

import sunpy.net.dataretriever.sources.adapt as adapt
from sunpy.net import attrs as a
from sunpy.net.dataretriever.client import QueryResponse
from sunpy.net.tests.strategies import time_attr
from sunpy.time import parse_time


@pytest.fixture
def adapt_client():
return adapt.ADAPTClient()


@given(time_attr())
def test_can_handle_query(time):
# Hypothesis complains if we use the fixture
adapt_client = adapt.ADAPTClient()
ans1 = adapt_client._can_handle_query(time, a.Instrument.adapt)
assert ans1 is True
ans2 = adapt_client._can_handle_query(time, a.Instrument.adapt,
a.adapt.ADAPTResolution('1'))
assert ans2 is True
ans3 = adapt_client._can_handle_query(time, a.Instrument.adapt,
a.adapt.ADAPTResolution('1'),
a.adapt.ADAPTHelioData('f'))
assert ans3 is True
ans4 = adapt_client._can_handle_query(time)
assert ans4 is False
ans5 = adapt_client._can_handle_query(time, a.Instrument.adapt, a.Provider.nso)
assert ans5 is True
ans6 = adapt_client._can_handle_query(time, a.Instrument.adapt,
a.adapt.ADAPTLonType('0'))
assert ans6 is True


def mock_query_object(adapt_client):
"""
Creating a Query Response object and prefilling it with some information
"""
start = '2019-05-25T02:00:00.00'
end = '2019-05-25T02:00:59.999'
obj = {
'Start Time': parse_time(start),
'End Time': parse_time(end),
'Instrument': 'ADAPT',
'Physobs': 'flux',
'Source': 'GONG',
'Provider': 'NSO',
'url': ("https://gong.nso.edu/adapt/maps/gong/2019/adapt40311_03i012_201905250200_i00005600n0.fts.gz")
}
results = QueryResponse([obj], client=adapt_client)
return results


@pytest.mark.remote_data
def test_fetch_working(adapt_client):
"""
Tests if the online server is working.
This also checks if the mock is working well.
"""
start = '2019/05/25 02:00:00'
end = '2019/05/26 02:00:59.999'
tr = a.Time(start, end)
qr = adapt_client.search(tr, a.Instrument.adapt)[0]
mock_qr = mock_query_object(adapt_client)[0]

assert mock_qr['Source'] == qr['Source']
assert mock_qr['Provider'] == qr['Provider']
assert mock_qr['Instrument'] == qr['Instrument']
assert mock_qr['url'] == qr['url']
assert qr['Start Time'].isot == mock_qr['Start Time'].isot
assert qr['End Time'].isot == mock_qr['End Time'].isot

with tempfile.TemporaryDirectory() as tmpdirname:
download_list = adapt_client.fetch(qr, path=tmpdirname)
assert len(download_list) == 1



def test_show(adapt_client):
mock_qr = mock_query_object(adapt_client)
qrshow0 = mock_qr.show()
qrshow1 = mock_qr.show('Start Time', 'Instrument')
allcols = {'Start Time', 'End Time', 'Instrument', 'Source', 'Provider', 'url'}
assert not allcols.difference(qrshow0.colnames)
assert qrshow1.colnames == ['Start Time', 'Instrument']
assert qrshow0['Instrument'][0] == 'ADAPT'


def test_attr_reg():
assert a.Instrument.adapt == a.Instrument('ADAPT')


def test_client_repr(adapt_client):
"""
Repr check
"""
output = str(adapt_client)
assert output[:50] == 'sunpy.net.dataretriever.sources.adapt.ADAPTClient\n'