Intro to FAST data#
Abstract: Some datasets are available more rapidly than others (for space weather monitoring). These are delivered through a special βFASTβ processing chain, as opposed to the normal operational βOPERβ chain. They are available under different collection names containing the string βFASTβ. Here we compare the availability and quality of FAST data in contrast to OPER data.
NB: Data is currently only available on the DISC machine for select users
SERVER_URL = 'https://vires.services/ows'
%load_ext watermark
%watermark -i -v -p viresclient,pandas,xarray,matplotlib,tqdm
Python implementation: CPython
Python version : 3.11.6
IPython version : 8.18.0
viresclient: 0.12.0
pandas : 2.1.3
xarray : 2023.12.0
matplotlib : 3.8.2
tqdm : 4.66.1
from viresclient import SwarmRequest
import datetime as dt
from tqdm import tqdm
import matplotlib as mpl
import matplotlib.pyplot as plt
from operator import or_
from functools import reduce
Which data are available FAST?#
request = SwarmRequest(SERVER_URL)
all_collections = request.available_collections(details=False)
# Identify collections with FAST in the name
collections = {group: [c for c in colls if "FAST" in c] for (group, colls) in all_collections.items()}
# Filter the empty groups
collections = {group: colls for group, colls in collections.items() if len(colls) > 0}
collections
{'MAG': ['SW_FAST_MAGA_LR_1B', 'SW_FAST_MAGB_LR_1B', 'SW_FAST_MAGC_LR_1B'],
'MAG_HR': ['SW_FAST_MAGA_HR_1B', 'SW_FAST_MAGB_HR_1B', 'SW_FAST_MAGC_HR_1B'],
'EFI': ['SW_FAST_EFIA_LP_1B', 'SW_FAST_EFIB_LP_1B', 'SW_FAST_EFIC_LP_1B'],
'FAC': ['SW_FAST_FACATMS_2F', 'SW_FAST_FACBTMS_2F', 'SW_FAST_FACCTMS_2F'],
'MOD_SC': ['SW_FAST_MODA_SC_1B', 'SW_FAST_MODB_SC_1B', 'SW_FAST_MODC_SC_1B']}
Letβs use 'SW_FAST_MAGA_LR_1B'
as an example and compare to 'SW_OPER_MAGA_LR_1B'
.
We can query the availability times of the underlying products:
fast_availability = request.available_times("SW_FAST_MAGA_LR_1B")
fast_availability
starttime | endtime | bbox | identifier | |
---|---|---|---|---|
0 | 2024-03-19 22:05:21+00:00 | 2024-03-20 10:26:18.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240319T220521_20240320T10... |
1 | 2024-03-20 10:26:21+00:00 | 2024-03-20 21:36:18.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240320T102621_20240320T21... |
2 | 2024-03-20 21:36:21+00:00 | 2024-03-21 11:32:18.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240320T213621_20240321T11... |
3 | 2024-03-21 11:32:21+00:00 | 2024-03-21 21:08:18.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240321T113221_20240321T21... |
4 | 2024-03-21 21:08:21+00:00 | 2024-03-22 09:32:19.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240321T210821_20240322T09... |
... | ... | ... | ... | ... |
401 | 2024-09-17 18:08:21+00:00 | 2024-09-18 06:48:20.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240917T180821_20240918T06... |
402 | 2024-09-18 06:48:21+00:00 | 2024-09-18 19:10:20.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240918T064821_20240918T19... |
403 | 2024-09-18 19:10:21+00:00 | 2024-09-19 06:19:19.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240918T191021_20240919T06... |
404 | 2024-09-19 06:19:21+00:00 | 2024-09-19 18:39:20.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240919T061921_20240919T18... |
405 | 2024-09-19 18:39:21+00:00 | 2024-09-20 07:20:20.001000+00:00 | (-90,-180,90,180) | SW_FAST_MAGA_LR_1B_20240919T183921_20240920T07... |
406 rows Γ 4 columns
Note: VirES only keeps a rolling store of the most recent month of FAST data.
oper_availability = request.available_times("SW_OPER_MAGA_LR_1B")
oper_availability
starttime | endtime | bbox | identifier | |
---|---|---|---|---|
0 | 2013-11-25 11:02:52+00:00 | 2013-11-25 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20131125T110252_20131125T23... |
1 | 2013-11-26 00:00:00+00:00 | 2013-11-26 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20131126T000000_20131126T23... |
2 | 2013-11-27 00:00:00+00:00 | 2013-11-27 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20131127T000000_20131127T23... |
3 | 2013-11-28 00:00:00+00:00 | 2013-11-28 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20131128T000000_20131128T23... |
4 | 2013-11-29 00:00:00+00:00 | 2013-11-29 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20131129T000000_20131129T23... |
... | ... | ... | ... | ... |
3928 | 2024-09-12 00:00:00+00:00 | 2024-09-12 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20240912T000000_20240912T23... |
3929 | 2024-09-13 00:00:00+00:00 | 2024-09-13 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20240913T000000_20240913T23... |
3930 | 2024-09-14 00:00:00+00:00 | 2024-09-14 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20240914T000000_20240914T23... |
3931 | 2024-09-15 00:00:00+00:00 | 2024-09-15 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20240915T000000_20240915T23... |
3932 | 2024-09-16 00:00:00+00:00 | 2024-09-16 23:59:59.001000+00:00 | (-90,-180,90,180) | SW_OPER_MAGA_LR_1B_20240916T000000_20240916T23... |
3933 rows Γ 4 columns
print(f"Latest OPER: {oper_availability['endtime'].iloc[-1]}")
print(f"Latest FAST: {fast_availability['endtime'].iloc[-1]}")
Latest OPER: 2024-09-16 23:59:59.001000+00:00
Latest FAST: 2024-09-20 07:20:20.001000+00:00
As you can see above, OPER
data is delivered in full-day chunks with a few days delay. FAST
data are typically delivered in several-hour chunks and available as soon as possible, subject to downlink opportunities from the satellite passes over the ground stations and subsequent processing time.
Accessing FAST data#
FAST
data are identical in format to OPER
data so can be accessed and used in the same way through VirES.
In the following example, we access the latest available day of OPER
data and compare to the available FAST
data, for each of Swarm A, B, C.
collection_root = "SW_{}_MAG{}_LR_1B"
def find_latest_oper(spacecraft="A"):
"""Identify the latest availability time for OPER data"""
collection = collection_root.format("OPER", spacecraft)
request = SwarmRequest(SERVER_URL)
times = request.available_times(collection)
return times['endtime'].iloc[-1].to_pydatetime()
def fetch_data(spacecraft="A", type="OPER", start=None, end=None):
"""Fetch either OPER or FAST data"""
collection = collection_root.format(type, spacecraft)
request = SwarmRequest(SERVER_URL)
request.set_collection(collection)
request.set_products(
measurements=["B_NEC", "Flags_B"],
models=["CHAOS"],
)
data = request.get_between(start, end, asynchronous=False, show_progress=False)
ds = data.as_xarray()
ds["B_NEC_res_CHAOS"] = ds["B_NEC"] - ds["B_NEC_CHAOS"]
return ds
# Find the latest availability times of OPER data per-satellite
oper_end_times = {sc: find_latest_oper(sc) for sc in "ABC"}
oper_end_times
{'A': datetime.datetime(2024, 9, 16, 23, 59, 59, 1000, tzinfo=datetime.timezone.utc),
'B': datetime.datetime(2024, 9, 16, 23, 59, 59, 1000, tzinfo=datetime.timezone.utc),
'C': datetime.datetime(2024, 9, 16, 23, 59, 59, 1000, tzinfo=datetime.timezone.utc)}
data_fast = {}
data_oper = {}
for sc in tqdm("ABC"):
# Fetch the latest available day of OPER data
oper_end = oper_end_times[sc] + dt.timedelta(seconds=1)
oper_start = oper_end - dt.timedelta(days=1)
data_oper[sc] = fetch_data(sc, "OPER", oper_start, oper_end)
# Fetch all FAST data from then until now
data_fast[sc] = fetch_data(sc, "FAST", oper_end, dt.datetime.now())
0%| | 0/3 [00:00<?, ?it/s]
33%|ββββ | 1/3 [00:09<00:18, 9.24s/it]
67%|βββββββ | 2/3 [00:18<00:09, 9.14s/it]
100%|ββββββββββ| 3/3 [00:28<00:00, 9.51s/it]
100%|ββββββββββ| 3/3 [00:28<00:00, 9.42s/it]
def flag_filter(ds):
"""A simplistic filter for close-to-nominal data"""
# Filtering by Flags_B
# For flag meanings, see https://swarmhandbook.earth.esa.int/catalogue/SW_MAGx_LR_1B
# This includes Charlie data, where the ASM was lost
nominal = 0b0000
asm_off = 0b0001
vfm_asm_discrepency = 0b1000
bitmask_filters = (nominal, asm_off, vfm_asm_discrepency)
flags = ds["Flags_B"]
flags_masked = reduce(or_, [flags & x for x in bitmask_filters])
return ds.where(flags == flags_masked)
# Identify the minimal and maximal times in the datasets
tmin = min(data_oper[sc]["Timestamp"].data[0] for sc in "ABC")
tmax = max(data_fast[sc]["Timestamp"].data[-1] for sc in "ABC")
fig, axes = plt.subplots(nrows=3, figsize=(15, 10), sharex=True)
for ax, sc in zip(axes, "ABC"):
# Remove bad data before plotting
ds_oper_nominal = flag_filter(data_oper[sc])
ds_fast_nominal = flag_filter(data_fast[sc])
ax.set_prop_cycle("color", ["tab:blue", "tab:orange", "tab:green"])
ds_oper_nominal["B_NEC_res_CHAOS"].plot.line(x="Timestamp", ax=ax)
ds_fast_nominal["B_NEC_res_CHAOS"].plot.line(x="Timestamp", ax=ax)
ax.set_xlim(tmin, tmax)
# Add shading behind OPER data section
oper_start = data_oper[sc]["Timestamp"].data[0]
oper_end = data_oper[sc]["Timestamp"].data[-1]
ymin, ymax = ax.get_ylim()
ax.fill_betweenx((ymin, ymax), oper_start, oper_end, alpha=0.3, color="grey")
# Add and fix some labelling
ax.text(oper_end, ymax, "β¬
οΈ OPER FAST β‘οΈ", ha="center", va="top")
ax.set_xlim(oper_start, ax.get_xlim()[-1])
ax.set_xlabel("")
ax.set_ylabel(f"Swarm {sc}\n{ax.get_ylabel()}")
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter("%Y-%m-%d\n%H:%M"))