DSECS: Dipolar Spherical Elementary Current Systems#
For more information about the project and the technique, see:
Vanhamäki, H., Maute, A., Alken, P. et al. Dipolar elementary current systems for ionospheric current reconstruction at low and middle latitudes. Earth Planets Space 72, 146 (2020). https://doi.org/10.1186/s40623-020-01284-1
import logging
import datetime as dt
from swarmpal.io import create_paldata, PalDataItem
from swarmpal.toolboxes import dsecs
import matplotlib.pyplot as plt
# To enable logging in the notebook, uncomment this line:
# logging.basicConfig(level=logging.INFO, force=True)
Fetching inputs to the toolbox#
def data_params(spacecraft="A"):
return dict(
server_url="https://vires.services/ows",
collection=f"SW_OPER_MAG{spacecraft}_LR_1B",
measurements=["B_NEC"],
models=["Model = CHAOS"], # currently must use name "Model"
auxiliaries=["QDLat"],
start_time="2016-03-18T11:00:00",
end_time="2016-03-18T14:00:00",
filters=["OrbitDirection == 1"], # Filters according to ascending passes
options=dict(asynchronous=False, show_progress=False),
)
data = create_paldata(
PalDataItem.from_vires(**data_params("A")),
PalDataItem.from_vires(**data_params("C")),
)
print(data)
<xarray.DataTree 'paldata'>
Group: /
├── Group: /SW_OPER_MAGA_LR_1B
│ Dimensions: (Timestamp: 5506, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 2016-...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ Spacecraft (Timestamp) object 44kB 'A' 'A' 'A' 'A' 'A' ... 'A' 'A' 'A' 'A'
│ QDLat (Timestamp) float64 44kB -68.58 -68.54 -68.5 ... 82.04 82.01
│ B_NEC (Timestamp, NEC) float64 132kB 1.413e+04 ... 4.687e+04
│ Latitude (Timestamp) float64 44kB -82.61 -82.55 -82.49 ... 87.35 87.35
│ Longitude (Timestamp) float64 44kB -26.01 -25.83 -25.66 ... 48.7 50.09
│ B_NEC_Model (Timestamp, NEC) float64 132kB 1.411e+04 ... 4.688e+04
│ Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
│ Attributes:
│ Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGA_LR_1B_20160318T00...
│ MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
│ AppliedFilters: ['OrbitDirection == 1']
│ PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
└── Group: /SW_OPER_MAGC_LR_1B
Dimensions: (Timestamp: 5500, NEC: 3)
Coordinates:
* Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 2016-...
* NEC (NEC) <U1 12B 'N' 'E' 'C'
Data variables:
Spacecraft (Timestamp) object 44kB 'C' 'C' 'C' 'C' 'C' ... 'C' 'C' 'C' 'C'
QDLat (Timestamp) float64 44kB -68.47 -68.43 -68.39 ... 82.03 82.0
B_NEC (Timestamp, NEC) float64 132kB 1.412e+04 ... 4.688e+04
Latitude (Timestamp) float64 44kB -82.35 -82.29 -82.23 ... 87.35 87.35
Longitude (Timestamp) float64 44kB -23.86 -23.69 -23.54 ... 49.16 50.54
B_NEC_Model (Timestamp, NEC) float64 132kB 1.41e+04 ... 4.688e+04
Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
Attributes:
Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGC_LR_1B_20160318T00...
MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
AppliedFilters: ['OrbitDirection == 1']
PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
Applying the DSECS process#
Preprocess#
This initial process adds in Apex coordinates to the datasets.
p1 = dsecs.processes.Preprocess()
p1(data)
print(data)
<xarray.DataTree 'paldata'>
Group: /
│ Attributes:
│ PAL_meta: {"output_datasets": ["DSECS_output"]}
├── Group: /SW_OPER_MAGA_LR_1B
│ Dimensions: (Timestamp: 5506, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 201...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ Spacecraft (Timestamp) object 44kB 'A' 'A' 'A' 'A' ... 'A' 'A' 'A' 'A'
│ QDLat (Timestamp) float64 44kB -68.58 -68.54 -68.5 ... 82.04 82.01
│ B_NEC (Timestamp, NEC) float64 132kB 1.413e+04 ... 4.687e+04
│ Latitude (Timestamp) float64 44kB -82.61 -82.55 -82.49 ... 87.35 87.35
│ Longitude (Timestamp) float64 44kB -26.01 -25.83 -25.66 ... 48.7 50.09
│ B_NEC_Model (Timestamp, NEC) float64 132kB 1.411e+04 ... 4.688e+04
│ Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
│ ApexLatitude (Timestamp) float64 44kB -69.37 -69.33 -69.29 ... 82.31 82.29
│ ApexLongitude (Timestamp) float64 44kB 25.92 26.02 26.12 ... 155.1 155.5
│ Attributes:
│ Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGA_LR_1B_20160318T00...
│ MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
│ AppliedFilters: ['OrbitDirection == 1']
│ PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
├── Group: /SW_OPER_MAGC_LR_1B
│ Dimensions: (Timestamp: 5500, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 201...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ Spacecraft (Timestamp) object 44kB 'C' 'C' 'C' 'C' ... 'C' 'C' 'C' 'C'
│ QDLat (Timestamp) float64 44kB -68.47 -68.43 -68.39 ... 82.03 82.0
│ B_NEC (Timestamp, NEC) float64 132kB 1.412e+04 ... 4.688e+04
│ Latitude (Timestamp) float64 44kB -82.35 -82.29 -82.23 ... 87.35 87.35
│ Longitude (Timestamp) float64 44kB -23.86 -23.69 -23.54 ... 49.16 50.54
│ B_NEC_Model (Timestamp, NEC) float64 132kB 1.41e+04 ... 4.688e+04
│ Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
│ ApexLatitude (Timestamp) float64 44kB -69.27 -69.23 -69.19 ... 82.3 82.28
│ ApexLongitude (Timestamp) float64 44kB 26.81 26.91 27.01 ... 155.2 155.6
│ Attributes:
│ Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGC_LR_1B_20160318T00...
│ MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
│ AppliedFilters: ['OrbitDirection == 1']
│ PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
└── Group: /DSECS_output
Attributes:
PAL_meta: {"DSECS_Preprocess": {"output_dataset": "DSECS_output", "datas...
Analysis#
This process performs the DSECS analysis. It currently takes about 3 minutes to process one pass over the mid-latitudes.
%%time
p2 = dsecs.processes.Analysis()
p2(data)
CPU times: user 4min 9s, sys: 2.63 s, total: 4min 11s
Wall time: 2min 53s
<xarray.DataTree 'paldata'>
Group: /
│ Attributes:
│ PAL_meta: {"output_datasets": ["DSECS_output"]}
├── Group: /SW_OPER_MAGA_LR_1B
│ Dimensions: (Timestamp: 5506, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 201...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ Spacecraft (Timestamp) object 44kB 'A' 'A' 'A' 'A' ... 'A' 'A' 'A' 'A'
│ QDLat (Timestamp) float64 44kB -68.58 -68.54 -68.5 ... 82.04 82.01
│ B_NEC (Timestamp, NEC) float64 132kB 1.413e+04 ... 4.687e+04
│ Latitude (Timestamp) float64 44kB -82.61 -82.55 -82.49 ... 87.35 87.35
│ Longitude (Timestamp) float64 44kB -26.01 -25.83 -25.66 ... 48.7 50.09
│ B_NEC_Model (Timestamp, NEC) float64 132kB 1.411e+04 ... 4.688e+04
│ Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
│ ApexLatitude (Timestamp) float64 44kB -69.37 -69.33 -69.29 ... 82.31 82.29
│ ApexLongitude (Timestamp) float64 44kB 25.92 26.02 26.12 ... 155.1 155.5
│ Attributes:
│ Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGA_LR_1B_20160318T00...
│ MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
│ AppliedFilters: ['OrbitDirection == 1']
│ PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
├── Group: /SW_OPER_MAGC_LR_1B
│ Dimensions: (Timestamp: 5500, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 44kB 2016-03-18T11:00:00 ... 201...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ Spacecraft (Timestamp) object 44kB 'C' 'C' 'C' 'C' ... 'C' 'C' 'C' 'C'
│ QDLat (Timestamp) float64 44kB -68.47 -68.43 -68.39 ... 82.03 82.0
│ B_NEC (Timestamp, NEC) float64 132kB 1.412e+04 ... 4.688e+04
│ Latitude (Timestamp) float64 44kB -82.35 -82.29 -82.23 ... 87.35 87.35
│ Longitude (Timestamp) float64 44kB -23.86 -23.69 -23.54 ... 49.16 50.54
│ B_NEC_Model (Timestamp, NEC) float64 132kB 1.41e+04 ... 4.688e+04
│ Radius (Timestamp) float64 44kB 6.832e+06 6.832e+06 ... 6.814e+06
│ ApexLatitude (Timestamp) float64 44kB -69.27 -69.23 -69.19 ... 82.3 82.28
│ ApexLongitude (Timestamp) float64 44kB 26.81 26.91 27.01 ... 155.2 155.6
│ Attributes:
│ Sources: ['CHAOS-8.1_static.shc', 'SW_OPER_MAGC_LR_1B_20160318T00...
│ MagneticModels: ["Model = 'CHAOS-Core'(max_degree=20,min_degree=1) + 'CH...
│ AppliedFilters: ['OrbitDirection == 1']
│ PAL_meta: {"analysis_window": ["2016-03-18T11:00:00", "2016-03-18T...
└── Group: /DSECS_output
│ Attributes:
│ PAL_meta: {"DSECS_Preprocess": {"output_dataset": "DSECS_output", "datas...
├── Group: /DSECS_output/0
│ ├── Group: /DSECS_output/0/currents
│ │ Dimensions: (x: 160, y: 7)
│ │ Coordinates:
│ │ Longitude (x, y) float64 9kB 348.4 349.1 349.8 ... 350.5 351.2 351.9
│ │ Latitude (x, y) float64 9kB -39.96 -39.96 -39.96 ... 39.54 39.54 39.54
│ │ Dimensions without coordinates: x, y
│ │ Data variables:
│ │ JEastDf (x, y) float64 9kB 12.75 12.97 13.34 ... 37.09 37.21 37.56
│ │ JNorthDf (x, y) float64 9kB 3.218 3.287 3.355 ... -2.858 -1.361 0.6997
│ │ Jr (x, y) float64 9kB 6.202 5.203 3.722 ... -0.896 0.6389 -0.2665
│ │ JEastCf (x, y) float64 9kB 4.798 4.568 4.314 ... -1.064 -1.587 -2.082
│ │ JNorthCf (x, y) float64 9kB 17.18 17.35 17.49 ... 3.934 4.322 4.705
│ │ JEastTotal (x, y) float64 9kB 17.55 17.54 17.66 ... 36.03 35.62 35.47
│ │ JNorthTotal (x, y) float64 9kB 20.4 20.63 20.84 20.96 ... 1.076 2.961 5.405
│ │ Attributes:
│ │ description: DSECS result geographic coordinates
│ │ ionospheric height (km): 6501
│ │ Time interval: 2016-03-18T11:06:00 - 2016-03-18T11:37:13
│ │ Mean time: 2016-03-18T11:21:36
│ ├── Group: /DSECS_output/0/Fit_Alpha
│ │ Dimensions: (Timestamp: 1874, NEC: 3)
│ │ Coordinates:
│ │ * Timestamp (Timestamp) datetime64[s] 15kB 2016-03-18T11:06:00 ... 2016-0...
│ │ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ │ Data variables:
│ │ B_NEC_fit (Timestamp, NEC) float64 45kB 0.3856 11.99 ... -9.585 -9.392
│ │ B_NEC_data (Timestamp, NEC) float64 45kB 0.5193 13.86 ... -10.72 -8.95
│ │ Longitude (Timestamp) float64 15kB -11.22 -11.21 -11.2 ... -9.878 -9.871
│ │ Latitude (Timestamp) float64 15kB -59.96 -59.9 -59.83 ... 59.92 59.99
│ │ Radius (Timestamp) float64 15kB 6.832e+06 6.832e+06 ... 6.816e+06
│ │ Attributes:
│ │ description: DSECS magnetic field fit.
│ │ satellite: Swarm Alpha
│ └── Group: /DSECS_output/0/Fit_Charlie
│ Dimensions: (Timestamp: 1874, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 15kB 2016-03-18T11:06:00 ... 2016-0...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ B_NEC_fit (Timestamp, NEC) float64 45kB -1.874 12.42 ... -9.667 -9.198
│ B_NEC_data (Timestamp, NEC) float64 45kB 0.03879 14.71 ... -10.37 -8.686
│ Longitude (Timestamp) float64 15kB -9.758 -9.75 -9.743 ... -8.419 -8.411
│ Latitude (Timestamp) float64 15kB -59.69 -59.62 -59.56 ... 60.2 60.26
│ Radius (Timestamp) float64 15kB 6.831e+06 6.831e+06 ... 6.816e+06
│ Attributes:
│ description: DSECS magnetic field fit.
│ satellite: Swarm Charlie
└── Group: /DSECS_output/1
├── Group: /DSECS_output/1/currents
│ Dimensions: (x: 160, y: 7)
│ Coordinates:
│ Longitude (x, y) float64 9kB 324.9 325.7 326.4 ... 327.0 327.7 328.4
│ Latitude (x, y) float64 9kB -39.95 -39.95 -39.95 ... 39.55 39.55 39.55
│ Dimensions without coordinates: x, y
│ Data variables:
│ JEastDf (x, y) float64 9kB 17.04 17.12 17.33 17.3 ... 15.74 15.62 15.73
│ JNorthDf (x, y) float64 9kB 14.18 15.26 15.93 ... -17.27 -14.99 -11.65
│ Jr (x, y) float64 9kB 1.502 6.781 13.28 ... -18.05 -15.92 -13.4
│ JEastCf (x, y) float64 9kB 10.62 9.857 8.802 ... -0.1018 0.7477 1.433
│ JNorthCf (x, y) float64 9kB 33.54 33.31 33.29 ... -8.726 -8.786 -8.729
│ JEastTotal (x, y) float64 9kB 27.66 26.98 26.13 ... 15.64 16.36 17.16
│ JNorthTotal (x, y) float64 9kB 47.72 48.57 49.22 ... -26.0 -23.78 -20.38
│ Attributes:
│ description: DSECS result geographic coordinates
│ ionospheric height (km): 6501
│ Time interval: 2016-03-18T12:39:33 - 2016-03-18T13:10:46
│ Mean time: 2016-03-18T12:55:09
├── Group: /DSECS_output/1/Fit_Alpha
│ Dimensions: (Timestamp: 1874, NEC: 3)
│ Coordinates:
│ * Timestamp (Timestamp) datetime64[s] 15kB 2016-03-18T12:39:33 ... 2016-0...
│ * NEC (NEC) <U1 12B 'N' 'E' 'C'
│ Data variables:
│ B_NEC_fit (Timestamp, NEC) float64 45kB -1.932 35.9 ... -32.04 -5.286
│ B_NEC_data (Timestamp, NEC) float64 45kB -3.939 42.52 ... -28.39 -2.321
│ Longitude (Timestamp) float64 15kB -34.69 -34.68 -34.67 ... -33.35 -33.34
│ Latitude (Timestamp) float64 15kB -59.95 -59.89 -59.82 ... 59.93 60.0
│ Radius (Timestamp) float64 15kB 6.832e+06 6.832e+06 ... 6.816e+06
│ Attributes:
│ description: DSECS magnetic field fit.
│ satellite: Swarm Alpha
└── Group: /DSECS_output/1/Fit_Charlie
Dimensions: (Timestamp: 1874, NEC: 3)
Coordinates:
* Timestamp (Timestamp) datetime64[s] 15kB 2016-03-18T12:39:33 ... 2016-0...
* NEC (NEC) <U1 12B 'N' 'E' 'C'
Data variables:
B_NEC_fit (Timestamp, NEC) float64 45kB -4.751 36.55 ... -31.72 -5.789
B_NEC_data (Timestamp, NEC) float64 45kB -5.979 45.27 ... -22.74 -1.324
Longitude (Timestamp) float64 15kB -33.22 -33.21 -33.21 ... -31.88 -31.88
Latitude (Timestamp) float64 15kB -59.61 -59.55 -59.49 ... 60.27 60.33
Radius (Timestamp) float64 15kB 6.832e+06 6.832e+06 ... 6.816e+06
Attributes:
description: DSECS magnetic field fit.
satellite: Swarm CharlieOutputs are stored under a new “DSECS_output” branch of the datatree. This branch is further divided into N branches (“0”, “1”, “2”, …) depending on how many passes have been analysed, and under each branch into “currents” (the estimated current densities), “Fit_Alpha” and “Fit_Charlie” (the residuals for the fitted magnetic data).
data.groups
('/',
'/SW_OPER_MAGA_LR_1B',
'/SW_OPER_MAGC_LR_1B',
'/DSECS_output',
'/DSECS_output/0',
'/DSECS_output/1',
'/DSECS_output/0/currents',
'/DSECS_output/0/Fit_Alpha',
'/DSECS_output/0/Fit_Charlie',
'/DSECS_output/1/currents',
'/DSECS_output/1/Fit_Alpha',
'/DSECS_output/1/Fit_Charlie')
Plotting the outputs and fitted magnetic field#
Simple line plots of the currents from the central latitudinal slice#
The outputs in the datatree are enumerated, for each analyzed equatorial crossing included inside the timestamps. (“DSECS_output/0/currents”,”DSECS_output/1/currents” etc.)
print(data["DSECS_output/0/currents"].coords)
print(data["DSECS_output/0/currents"].data_vars)
Coordinates:
Longitude (x, y) float64 9kB 348.4 349.1 349.8 350.6 ... 350.5 351.2 351.9
Latitude (x, y) float64 9kB -39.96 -39.96 -39.96 ... 39.54 39.54 39.54
Data variables:
JEastDf (x, y) float64 9kB 12.75 12.97 13.34 ... 37.09 37.21 37.56
JNorthDf (x, y) float64 9kB 3.218 3.287 3.355 ... -2.858 -1.361 0.6997
Jr (x, y) float64 9kB 6.202 5.203 3.722 ... -0.896 0.6389 -0.2665
JEastCf (x, y) float64 9kB 4.798 4.568 4.314 ... -1.064 -1.587 -2.082
JNorthCf (x, y) float64 9kB 17.18 17.35 17.49 ... 3.934 4.322 4.705
JEastTotal (x, y) float64 9kB 17.55 17.54 17.66 ... 36.03 35.62 35.47
JNorthTotal (x, y) float64 9kB 20.4 20.63 20.84 20.96 ... 1.076 2.961 5.405
latitudes = data["DSECS_output/0/currents"]["Latitude"][:, 3]
fig, ax = plt.subplots(4, 1, figsize=(10, 20))
lineE = ax[0].plot(
latitudes,
data["DSECS_output/0/currents"]["JEastTotal"][:, 3],
"r",
label="Eastward",
)
lineN = ax[0].plot(
latitudes,
data["DSECS_output/0/currents"]["JNorthTotal"][:, 3],
"k",
label="Northward",
)
ax[0].set_title("Total Current")
ax[0].set_ylabel("Current density (A/km)")
lineE = ax[1].plot(
latitudes, data["DSECS_output/0/currents"]["JEastCf"][:, 3], "r", label="Eastward"
)
lineN = ax[1].plot(
latitudes, data["DSECS_output/0/currents"]["JNorthCf"][:, 3], "k", label="Northward"
)
ax[1].set_title("Curl free current")
ax[1].set_ylabel("Current density (A/km)")
# ax[0].set_title('Total Current (DF + CF)')
lineE = ax[2].plot(
latitudes, data["DSECS_output/0/currents"]["JEastDf"][:, 3], "r", label="Eastward"
)
lineN = ax[2].plot(
latitudes, data["DSECS_output/0/currents"]["JNorthDf"][:, 3], "k", label="Northward"
)
ax[2].set_title("Divergence free current")
ax[2].set_ylabel("Current density (A/km)")
liner = ax[3].plot(
latitudes,
data["DSECS_output/0/currents"]["Jr"][:, 3],
"r",
label="Radial current density",
)
ax[3].set_title("Radial current density")
ax[3].set_ylabel("Current density (nA/m^2)")
for axv in ax:
axv.set_xlabel("Latitude", loc="left")
axv.legend()
(Preview) Quicklook plots#
from swarmpal.experimental import dsecs_plotting
Plot a specific pass
dsecs_plotting.plot_analysed_pass(data, "DSECS_output", pass_no=0)
/home/docs/checkouts/readthedocs.org/user_builds/swarmpal/envs/main/lib/python3.11/site-packages/cartopy/io/__init__.py:242: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/110m_physical/ne_110m_coastline.zip
warnings.warn(f'Downloading: {url}', DownloadWarning)
Automatically plot all passes
figs = dsecs_plotting.quicklook(data)
figs[0]
figs[1]
Create an animation of those quicklook plots (using ipwidgets)
(If you are viewing this on the web, it will not be interactive)
dsecs_plotting.quicklook_animated(data)
data.to_netcdf("dsecs_example.nc")