EFIxTCT (Cross-track ion flow)

EFIxTCT (Cross-track ion flow)

Abstract: Access to the 2Hz & 16Hz cross-track ion flow data derived from the Thermal Ion Imager (TII), part of the Electric Field Instrument package (EFI).

For more information about this product, see the release notes.

SERVER_URL = 'https://vires.services/ows'
# Display important package versions used
%load_ext watermark
%watermark -i -v -p viresclient,pandas,xarray,matplotlib
Python implementation: CPython
Python version       : 3.9.7
IPython version      : 8.0.1

viresclient: 0.11.0
pandas     : 1.4.1
xarray     : 0.21.1
matplotlib : 3.5.1
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
# Control the HTML display of the datasets
xr.set_options(display_expand_attrs=False, display_expand_coords=True, display_expand_data=True)

from viresclient import SwarmRequest
request = SwarmRequest(SERVER_URL)

What data is available?

There are two sets of collections available, one for 2Hz and one for 16Hz, and for each there are three collections, one for each Swarm spacecraft.

request.available_collections("EFI_TCT02", details=False)
{'EFI_TCT02': ['SW_EXPT_EFIA_TCT02',
  'SW_EXPT_EFIB_TCT02',
  'SW_EXPT_EFIC_TCT02']}
request.available_collections("EFI_TCT16", details=False)
{'EFI_TCT16': ['SW_EXPT_EFIA_TCT16',
  'SW_EXPT_EFIB_TCT16',
  'SW_EXPT_EFIC_TCT16']}
print(request.available_measurements("EFI_TCT02"))
['VsatC', 'VsatE', 'VsatN', 'Bx', 'By', 'Bz', 'Ehx', 'Ehy', 'Ehz', 'Evx', 'Evy', 'Evz', 'Vicrx', 'Vicry', 'Vicrz', 'Vixv', 'Vixh', 'Viy', 'Viz', 'Vixv_error', 'Vixh_error', 'Viy_error', 'Viz_error', 'Latitude_QD', 'MLT_QD', 'Calibration_flags', 'Quality_flags']
print(request.available_measurements("EFI_TCT16"))
['VsatC', 'VsatE', 'VsatN', 'Bx', 'By', 'Bz', 'Ehx', 'Ehy', 'Ehz', 'Evx', 'Evy', 'Evz', 'Vicrx', 'Vicry', 'Vicrz', 'Vixv', 'Vixh', 'Viy', 'Viz', 'Vixv_error', 'Vixh_error', 'Viy_error', 'Viz_error', 'Latitude_QD', 'MLT_QD', 'Calibration_flags', 'Quality_flags']

As seen above, the variables available for both the 2Hz and 16Hz datasets are the same. Here is a short description for each variable:

tct_vars = [
    # Satellite velocity in NEC frame
    "VsatC", "VsatE", "VsatN",
    # Geomagnetic field components derived from 1Hz product
    #  (in satellite-track coordinates)
    "Bx", "By", "Bz",
    # Electric field components derived from -VxB with along-track ion drift
    #  (in satellite-track coordinates)
    # Eh: derived from horizontal sensor
    # Ev: derived from vertical sensor
    "Ehx", "Ehy", "Ehz",
    "Evx", "Evy", "Evz",
    # Ion drift corotation signal, removed from ion drift & electric field
    #  (in satellite-track coordinates)
    "Vicrx", "Vicry", "Vicrz",
    # Ion drifts along-track from vertical (..v) and horizontal (..h) TII sensor
    "Vixv", "Vixh",
    # Ion drifts cross-track (y from horizontal sensor, z from vertical sensor)
    #  (in satellite-track coordinates)
    "Viy", "Viz",
    # Random error estimates for the above
    #  (Negative value indicates no estimate available)
    "Vixv_error", "Vixh_error", "Viy_error", "Viz_error",
    # Quasi-dipole magnetic latitude and local time
    #  redundant with VirES auxiliaries, QDLat & MLT
    "Latitude_QD", "MLT_QD",
    # Refer to release notes link above for details:
    "Calibration_flags", "Quality_flags",
]

Fetching and plotting data

For demonstration, we will fetch the 2Hz data from Swarm Alpha (SW_EXPT_EFIA_TCT02)

start = "2018-07-17T11:00:00"
end = "2018-07-17T16:00:00"

request = SwarmRequest(SERVER_URL)
request.set_collection("SW_EXPT_EFIA_TCT02")
request.set_products(measurements=tct_vars)
data = request.get_between(start, end)

Data can be loaded as either a pandas datframe or a xarray dataset.

df = data.as_dataframe()
df.head()
VsatC Ehx Quality_flags Evx Evy Viy Calibration_flags Bx Latitude By ... Latitude_QD Viz_error Vicrx Radius Viy_error VsatN Longitude Vicry MLT_QD Ehy
Timestamp
2018-07-17 11:28:49.225250048 5.364018 -146.413574 0 -146.413574 -866.204529 3072.314697 50529027 -1941.897339 80.104347 -2032.778809 ... 75.208305 -14.849242 -19.133307 6805734.0 -14.849242 -7367.462402 83.477844 83.111824 17.153055 -705.941589
2018-07-17 11:28:49.725250048 5.379858 -132.751846 0 -132.751846 -848.451111 2794.406982 50529027 -1947.693359 80.073341 -2032.832520 ... 75.179535 -14.849242 -19.120062 6805735.5 -14.849242 -7369.250000 83.526100 83.386414 17.154737 -693.349854
2018-07-17 11:28:50.225250048 5.395653 -130.952698 0 -130.952698 -868.396301 2748.852295 50529027 -1954.192383 80.042313 -2033.323975 ... 75.150764 -14.849242 -19.106810 6805736.0 -14.849242 -7371.019043 83.574059 83.660973 17.156416 -697.077820
2018-07-17 11:28:50.725250048 5.411411 -130.928070 0 -130.928070 -868.061523 2760.554688 50529027 -1961.238281 80.011284 -2034.150879 ... 75.121979 -14.849242 -19.093546 6805737.0 -14.849242 -7372.773438 83.621712 83.935509 17.158089 -692.121216
2018-07-17 11:28:51.225250048 5.427133 -126.337891 0 -126.337891 -864.288635 2662.979004 50529027 -1969.732666 79.980247 -2032.240967 ... 75.093193 -14.849242 -19.080286 6805739.0 -14.849242 -7374.509277 83.669060 84.210022 17.159754 -700.008362

5 rows × 31 columns

ds = data.as_xarray()
ds
<xarray.Dataset>
Dimensions:            (Timestamp: 32535)
Coordinates:
  * Timestamp          (Timestamp) datetime64[ns] 2018-07-17T11:28:49.2252500...
Data variables: (12/31)
    Spacecraft         (Timestamp) object 'A' 'A' 'A' 'A' ... 'A' 'A' 'A' 'A'
    VsatC              (Timestamp) float32 5.364 5.38 5.396 ... -11.04 -11.03
    Quality_flags      (Timestamp) uint16 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
    Evy                (Timestamp) float32 -866.2 -848.5 ... -720.4 -715.7
    Bx                 (Timestamp) float32 -1.942e+03 -1.948e+03 ... 9.496e+03
    Latitude           (Timestamp) float32 80.1 80.07 80.04 ... 64.75 64.78
    ...                 ...
    Vicrx              (Timestamp) float32 -19.13 -19.12 ... -24.47 -24.46
    Radius             (Timestamp) float32 6.806e+06 6.806e+06 ... 6.807e+06
    Viy_error          (Timestamp) float32 -14.85 -14.85 ... -14.85 -14.85
    VsatN              (Timestamp) float32 -7.367e+03 -7.369e+03 ... 7.606e+03
    Bz                 (Timestamp) float32 4.783e+04 4.784e+04 ... 4.539e+04
    Vixh_error         (Timestamp) float32 -14.85 -14.85 ... -14.85 -14.85
Attributes: (3)

An example plot:

fig, axes = plt.subplots(nrows=4, sharex=True, figsize=(10, 7))
# Plot velocities with left axis
ds.plot.scatter(x="Timestamp", y="Vixv", ax=axes[0], s=0.1)
ds.plot.scatter(x="Timestamp", y="Vixh", ax=axes[1], s=0.1)
ds.plot.scatter(x="Timestamp", y="Viy", ax=axes[2], s=0.1)
ds.plot.scatter(x="Timestamp", y="Viz", ax=axes[3], s=0.1, label="Velocities")
# Plot velocities with right axis
axes_r = [ax.twinx() for ax in axes]
ds.plot.scatter(x="Timestamp", y="Vixv_error", ax=axes_r[0], s=0.1, color="tab:orange")
ds.plot.scatter(x="Timestamp", y="Vixh_error", ax=axes_r[1], s=0.1, color="tab:orange")
ds.plot.scatter(x="Timestamp", y="Viy_error", ax=axes_r[2], s=0.1, color="tab:orange")
ds.plot.scatter(x="Timestamp", y="Viz_error", ax=axes_r[3], s=0.1, color="tab:orange")
fig.subplots_adjust(hspace=0)
# Add legend to identify each side
blue = mpl.patches.Patch(color="tab:blue", label="Velocities")
orange = mpl.patches.Patch(color="tab:orange", label="Errors")
axes[0].legend(handles=[blue, orange])
# # Generate additional ticklabels for x-axis
# Use time xticks to get dataset vars at those xticks
locx = axes[-1].get_xticks()
times = mpl.dates.num2date(locx)
times = [t.replace(tzinfo=None) for t in times]
_ds_xticks = ds.reindex({"Timestamp": times}, method="nearest")
# Build ticklabels from dataset vars
xticklabels = np.stack([
    _ds_xticks["Timestamp"].dt.strftime("%H:%M").values,
    np.round(_ds_xticks["Latitude"].values, 2).astype(str),
    np.round(_ds_xticks["Longitude"].values, 2).astype(str),
])
xticklabels = ["\n".join(row) for row in xticklabels.T]
# Add labels to first xtick
_xt0 = xticklabels[0].split("\n")
xticklabels[0] = f"Time:  {_xt0[0]}\nLat:  {_xt0[1]}\nLon: {_xt0[2]}"
axes[-1].set_xticks(axes[-1].get_xticks())
axes[-1].set_xticklabels(xticklabels)
axes[-1].set_xlabel("")
# Adjust title
title = "".join([
    f"Swarm {ds['Spacecraft'].data[0]} 2Hz ion flow, ",
    ds["Timestamp"].dt.date.data[0].isoformat(),
    f"\n{ds.attrs['Sources']}"
])
fig.suptitle(title);
../_images/03k2_Demo-EFIxTCT_21_0.png

Due to contamination in the instrument, great care must be taken to use these data correctly. Check the release notes and make use of the Quality_flags variable to identify valid data periods.

TODO: use section 3.4.1.1 to identify untrusty periods (bitx = 0) and shade them grey?