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).

Documentation:

# Display important package versions used
%load_ext watermark
%watermark -i -v -p viresclient,pandas,xarray,matplotlib
Python implementation: CPython
Python version       : 3.11.6
IPython version      : 8.18.0

viresclient: 0.15.2
pandas     : 2.1.3
xarray     : 2023.12.0
matplotlib : 3.8.2
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()

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()
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()
Vicry Spacecraft Calibration_flags Viy Vixv_error Vixv By Latitude_QD Radius MLT_QD ... Ehx VsatE Evz Ehy Latitude Vixh Quality_flags Bx Vicrx Bz
Timestamp
2018-07-17 11:28:49.231500032 83.115257 A 50529027 2120.916016 -14.849242 -6378.091797 -2032.779541 75.221916 6805732.5 17.152279 ... -101.939255 1978.689941 -17.083946 -208.541107 80.103966 -4369.472168 0 -1941.969727 -19.133141 47833.585938
2018-07-17 11:28:49.731500032 83.389847 A 50529027 2195.653809 -14.849242 -6341.005371 -2032.834717 75.193153 6805734.5 17.153959 ... -105.307312 1972.037720 -17.166695 -216.759445 80.072952 -4536.605469 0 -1947.767822 -19.119896 47837.687500
2018-07-17 11:28:50.231500032 83.664406 A 50529027 2149.880859 -14.849242 -6508.682617 -2033.334229 75.164375 6805735.5 17.155634 ... -103.137848 1965.429321 -17.435713 -220.021118 80.041931 -4604.627441 0 -1954.280518 -19.106642 47841.738281
2018-07-17 11:28:50.731500032 83.938942 A 50529027 2173.743652 -14.849242 -6535.101562 -2034.152954 75.135590 6805736.0 17.157301 ... -103.988091 1958.853638 -17.556908 -215.698181 80.010902 -4507.862793 0 -1961.330688 -19.093380 47845.742188
2018-07-17 11:28:51.231500032 84.213448 A 50529027 2087.728027 -14.849242 -6356.244629 -2032.190674 75.106796 6805737.0 17.158964 ... -100.248749 1952.320923 -17.029562 -224.552765 79.979858 -4699.985352 0 -1969.853027 -19.080120 47849.816406

5 rows ร— 31 columns

ds = data.as_xarray()
ds
<xarray.Dataset>
Dimensions:            (Timestamp: 32535)
Coordinates:
  * Timestamp          (Timestamp) datetime64[ns] 2018-07-17T11:28:49.2315000...
Data variables: (12/31)
    Spacecraft         (Timestamp) object 'A' 'A' 'A' 'A' ... 'A' 'A' 'A' 'A'
    Calibration_flags  (Timestamp) uint32 50529027 50529027 ... 50529027
    Vixv               (Timestamp) float32 -6.378e+03 -6.341e+03 ... -4.731e+03
    Radius             (Timestamp) float32 6.806e+06 6.806e+06 ... 6.807e+06
    MLT_QD             (Timestamp) float32 17.15 17.15 17.16 ... 4.769 4.769
    Viy_error          (Timestamp) float32 -14.85 -14.85 ... -14.85 -14.85
    ...                 ...
    Evz                (Timestamp) float32 -17.08 -17.17 -17.44 ... 23.6 22.58
    Ehy                (Timestamp) float32 -208.5 -216.8 ... -209.6 -206.1
    Quality_flags      (Timestamp) uint16 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0
    Bx                 (Timestamp) float32 -1.942e+03 -1.948e+03 ... 9.496e+03
    Viz_error          (Timestamp) float32 -14.85 -14.85 ... -14.85 -14.85
    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=1, linewidths=0)
ds.plot.scatter(x="Timestamp", y="Vixh", ax=axes[1], s=1, linewidths=0)
ds.plot.scatter(x="Timestamp", y="Viy", ax=axes[2], s=1, linewidths=0)
ds.plot.scatter(
    x="Timestamp", y="Viz", ax=axes[3], s=1, linewidths=0, 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/ff3eed62a5a0e4e2b0feaca82b5b7cdef454a7ac90e4555ff64720e1657aebf8.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?