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

Feat add ilofar #57

Merged
merged 9 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Features

- Add support for SOLO RPW data. (`#62 <https://github.com/sunpy/radiospectra/pull/62>`__)

Features
--------
- Add `sunpy.net.Fido` client `~radiospectra.net.sources.ilofar.ILOFARMode357` and spectrogram class `~radiospectra.spectrogram2.sources.ILOFARMode357` for ILOFAR mode 357 observations. (`#57 <https://github.com/sunpy/radiospectra/pull/57>`__)

0.4.0 (2022-05-24)
==================

Expand Down
5 changes: 4 additions & 1 deletion radiospectra/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ def plot(self, axes=None, **kwargs):

axes.set_title(title)
axes.plot(self.times.datetime[[0, -1]], self.frequencies[[0, -1]], linestyle="None", marker="None")
ret = axes.pcolormesh(self.times.datetime, self.frequencies.value, data[:-1, :-1], shading="auto", **kwargs)
if self.times.shape[0] == self.data.shape[0] and self.frequencies.shape[0] == self.data.shape[1]:
ret = axes.pcolormesh(self.times.datetime, self.frequencies.value, data, shading="auto", **kwargs)
else:
ret = axes.pcolormesh(self.times.datetime, self.frequencies.value, data[:-1, :-1], shading="auto", **kwargs)
axes.set_xlim(self.times.datetime[0], self.times.datetime[-1])
locator = mdates.AutoDateLocator(minticks=4, maxticks=8)
formatter = mdates.ConciseDateFormatter(locator)
Expand Down
11 changes: 10 additions & 1 deletion radiospectra/net/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from radiospectra.net.attrs import *
from radiospectra.net.sources.ecallisto import eCALLISTOClient
from radiospectra.net.sources.eovsa import EOVSAClient
from radiospectra.net.sources.ilofar import ILOFARMode357Client
from radiospectra.net.sources.psp import RFSClient
from radiospectra.net.sources.rstn import RSTNClient
from radiospectra.net.sources.stereo import SWAVESClient
from radiospectra.net.sources.wind import WAVESClient

__all__ = ["eCALLISTOClient", "EOVSAClient", "RFSClient", "SWAVESClient", "RSTNClient", "WAVESClient"]
__all__ = [
"eCALLISTOClient",
"EOVSAClient",
"RFSClient",
"SWAVESClient",
"RSTNClient",
"WAVESClient",
"ILOFARMode357Client",
]
124 changes: 124 additions & 0 deletions radiospectra/net/sources/ilofar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import numpy as np

import astropy.units as u
from sunpy.net import attrs as a
from sunpy.net.dataretriever.client import GenericClient, QueryResponse
from sunpy.net.scraper import Scraper
from sunpy.time import TimeRange

from radiospectra.net.attrs import PolType

__all__ = ["ILOFARMode357Client"]

RECEIVER_FREQUENCIES = a.Wavelength(10.546875 * u.MHz, 244.53125 * u.MHz)
DATASET_NAMES = ["rcu357_1beam", "rcu357_1beam_datastream"]


class ILOFARMode357Client(GenericClient):
"""
Provides access to I-LOFAR mode 357 observations from the
data `archive <https://data.lofar.ie>`__

Examples
--------
>>> import radiospectra.net
>>> from sunpy.net import Fido, attrs as a
>>> results = Fido.search(a.Time("2021/09/01", "2021/09/21"),
... a.Instrument('ILOFAR')) # doctest: +REMOTE_DATA
>>> results #doctest: +REMOTE_DATA
<sunpy.net.fido_factory.UnifiedResponse object at ...>
Results from 1 Provider:
<BLANKLINE>
10 Results from the ILOFARMode357Client:
<BLANKLINE>
Start Time End Time ... Provider Polarisation
----------------------- ----------------------- ... -------- ------------
2021-09-14 07:39:13.000 2021-09-14 07:39:13.999 ... ILOFAR X
2021-09-14 07:39:13.000 2021-09-14 07:39:13.999 ... ILOFAR Y
2021-09-01 08:07:29.000 2021-09-01 08:07:29.999 ... ILOFAR X
2021-09-01 08:07:29.000 2021-09-01 08:07:29.999 ... ILOFAR Y
2021-09-07 08:07:52.000 2021-09-07 08:07:52.999 ... ILOFAR X
2021-09-07 08:07:52.000 2021-09-07 08:07:52.999 ... ILOFAR Y
2021-09-08 08:04:07.000 2021-09-08 08:04:07.999 ... ILOFAR X
2021-09-08 08:04:07.000 2021-09-08 08:04:07.999 ... ILOFAR Y
2021-09-08 10:34:31.000 2021-09-08 10:34:31.999 ... ILOFAR X
2021-09-08 10:34:31.000 2021-09-08 10:34:31.999 ... ILOFAR Y
<BLANKLINE>
<BLANKLINE>
"""

baseurl = r"https://data.lofar.ie/%Y/%m/%d/bst/kbt/{dataset}/" r"%Y%m%d_\d{{6}}_bst_00\S{{1}}.dat"

pattern = r"{}/{year:4d}{month:2d}{day:2d}_{hour:2d}{minute:2d}{second:2d}" r"_bst_00{Polarisation}.dat"

@classmethod
def _check_wavelengths(cls, wavelength):
"""
Check for overlap between given wavelength and receiver frequency coverage defined in
`RECEIVER_FREQUENCIES`.

Parameters
----------
wavelength : `sunpy.net.attrs.Wavelength`
Input wavelength range to check

Returns
-------
`bool`
"""
return wavelength.min in RECEIVER_FREQUENCIES or wavelength.max in RECEIVER_FREQUENCIES

def search(self, *args, **kwargs):
"""
Query this client for a list of results.

Parameters
----------
*args: `tuple`
`sunpy.net.attrs` objects representing the query.
**kwargs: `dict`
Any extra keywords to refine the search.

Returns
-------
A `QueryResponse` instance containing the query result.
"""
matchdict = self._get_match_dict(*args, **kwargs)
metalist = []

wavelentgh = matchdict.get("Wavelength", False)
if wavelentgh and not self._check_wavelengths(wavelentgh):
return QueryResponse(metalist, client=self)

tr = TimeRange(matchdict["Start Time"], matchdict["End Time"])

for dataset in DATASET_NAMES:
url = self.baseurl.format(dataset=dataset)
scraper = Scraper(url, regex=True)
filesmeta = scraper._extract_files_meta(tr, extractor=self.pattern)
for i in filesmeta:
rowdict = self.post_search_hook(i, matchdict)
metalist.append(rowdict)

query_response = QueryResponse(metalist, client=self)
mask = np.full(len(query_response), True)
pol = matchdict.get("PolType")
if len(pol) == 1:
pol = pol.upper()
mask = mask & query_response["Polarisation"] == pol

if query_response:
query_response.remove_column("PolType")

return query_response[mask]

@classmethod
def register_values(cls):
adict = {
a.Instrument: [("ILOFAR", "Irish LOFAR STATION (IE63)")],
a.Source: [("ILOFAR", "Irish LOFAR Data Archive")],
a.Provider: [("ILOFAR", "Irish LOFAR Data Archive")],
a.Wavelength: [("*")],
PolType: [("X", "X"), ("X Linear Polarisation", "Y Linear Polarisation")],
}
return adict
Loading
Loading