Electron-scale measurements of magnetic reconnection in space

Obtain and analyze plasma data, including spectra, for the first MMS Science event (Burch et al., Science 2016, link here) showing magnetopause reconnection at the electron diffusion region on 2016/10/16 13:07:02.2 UT. Start by using Hwk06_mpause_RX.pro, provided. The objective of this exercise is to introduce plasma distributions from MMS (electrons and ions) and create burst spectra. In the process also create plasma moments and the plasma current and plot these along E and B. You are requested to create Figure 2 of Burch et al. plus the 3 bottom (electron) spectrograms from Figure 3 of the same paper (panels 3G, 3H and 3I). Your figure should look like the one shown on the next page, but using burst mode data in order to make it look like in Burch et al. You are requested to plot this figure at 2 time scales: the overview (2 min) timescale as in Fig. 2 of Burch et al. [‘13:05:30’,’13:07:30’] and the zoom-in (3 sec) timescale as in Fig. 3 of Burch et al. [‘13:07:00.5’,‘13:07:03.5’]. Notice that the clean and fast m’pause crossing was at 13:05:40UT, and this is used to determine N. In Fig. 2K of Burch et al. (the right-hand side of Fig. 2, the pictorial view of the MMS trajectory for the 2min interval) this initial m’pause crossing was near the start of the trajectory. The trajectory crosses the X-point at the 3 seconds of the zoom-in interval.

Code
using Speasy
using DimensionalData
using SPEDAS
using SPEDAS.MMS
using CairoMakie, SpacePhysicsMakie
using Unitful
using Dates

update_theme!(colormap=:rainbow1)
SpacePhysicsMakie.DEFAULTS.add_title = true;
    CondaPkg Found dependencies: /Users/zijin/.julia/packages/DimensionalData/hv9KC/CondaPkg.toml
    CondaPkg Found dev dependencies: /Users/zijin/.julia/dev/Speasy/CondaPkg.toml
    CondaPkg Found dependencies: /Users/zijin/.julia/packages/CondaPkg/0UqYV/CondaPkg.toml
    CondaPkg Found dependencies: /Users/zijin/.julia/packages/PythonCall/mkWc2/CondaPkg.toml
    CondaPkg Initialising pixi
             /Users/zijin/.julia/artifacts/d2fecc2a9fa3eac2108d3e4d9d155e6ff5dfd0b2/bin/pixi
             init
             --format pixi
             /Users/zijin/src/juliaspacephysics.github.io/.CondaPkg
✔ Created /Users/zijin/src/juliaspacephysics.github.io/.CondaPkg/pixi.toml
    CondaPkg Wrote /Users/zijin/src/juliaspacephysics.github.io/.CondaPkg/pixi.toml
             [dependencies]
             openssl = ">=3, <3.6, >=3, <3.6"
             uv = ">=0.4"
             xarray = "*"
             sqlite = "!=3.49.1"
             numpy = "*"
                              [dependencies.python]
                 channel = "conda-forge"
                 build = "*cp*"
                 version = ">=3.9,<4"
                          [project]
             name = ".CondaPkg"
             platforms = ["osx-arm64"]
             channels = ["conda-forge"]
             channel-priority = "strict"
             description = "automatically generated by CondaPkg.jl"
                          [pypi-dependencies.speasy]
             git = "https://github.com/SciQLop/speasy"
    CondaPkg Installing packages
             /Users/zijin/.julia/artifacts/d2fecc2a9fa3eac2108d3e4d9d155e6ff5dfd0b2/bin/pixi
             install
             --manifest-path /Users/zijin/src/juliaspacephysics.github.io/.CondaPkg/pixi.toml
✔ The default environment has been installed.

Overview plot

Minimum Variance Analysis

Code
trange = DateTime.(("2015-10-16T13:05:35", "2015-10-16T13:07:25"))
tr_mpause = DateTime.(("2015-10-16T13:05:40", "2015-10-16T13:06:09"))

probe = 2

tvars = (
    "cda/MMS2_FGM_SRVY_L2/mms2_fgm_b_gse_srvy_l2_clean",
    "cda/MMS2_EDP_FAST_L2_DCE/mms2_edp_dce_gse_fast_l2",
)
B_gse, edp_dce_gse = get_data(tvars, trange) .|> DimArray
rotMat = mva_eigen(tview(B_gse[:, 1:3], tr_mpause))
B_LMN = rotate(B_gse[:, 1:3], rotMat) |> set_coord("LMN") |> set_coord("Boundary-normal coordinates"; old_coords=["Geocentric Solar Ecliptic"])
E_LMN = rotate(edp_dce_gse, rotMat) |> set_coord("LMN")

rotMat
Can't get MMS2_FGM_SRVY_L2/mms2_fgm_b_gse_srvy_l2_clean without web service, switching to web service
LinearAlgebra.Eigen{Float32, Float32, StaticArraysCore.SMatrix{3, 3, Float32, 9}, StaticArraysCore.SVector{3, Float32}}
values:
3-element StaticArraysCore.SVector{3, Float32} with indices SOneTo(3):
 501.50854
  32.284042
  13.253316
vectors:
3×3 StaticArraysCore.SMatrix{3, 3, Float32, 9} with indices SOneTo(3)×SOneTo(3):
  0.368873   0.571603   0.732941
 -0.122903  -0.751631   0.648033
  0.921318  -0.329122  -0.207005

The direction obtained from the Minimum Variance Analysis (MVA) in our study closely aligns with the direction reported in the literature.

The (x, y, z) GSE components of the L, M, and N axes are L = (0.3665, –0.1201, 0.9226) GSE, M = (0.5694, –0.7553, –0.3245) GSE, and N = (0.7358, 0.6443, –0.2084) GSE

Plasma data

Code
data_rate = "brst"
fpi_des_ds = FPIDataSet(; probe, data_rate, data_type="des")
fpi_dis_ds = FPIDataSet(; probe, data_rate, data_type="dis")

func = x -> begin
    out = unit(x) * DimArray(x)
    out.metadata["DEPEND_1"] = x.dims[2] # a temporary fix for `SpacePhysicsMakie`
    out
end
des_data = map(func, get_data(NamedTuple, fpi_des_ds, trange))
dis_data = map(func, get_data(NamedTuple, fpi_dis_ds, trange))

des_n = setmeta(des_data.numberdensity[:, 1], labels="Ne")
dis_bulkv_lmn = rotate(dis_data.bulkv_gse, rotMat) |> set_coord("LMN")
des_bulkv_lmn = rotate(des_data.bulkv_gse, rotMat) |> set_coord("LMN")
dis_n = setmeta(dis_data.numberdensity[:, 1], labels="Ni")
733-element DimArray{Unitful.Quantity{Float32, 𝐋⁻³, Unitful.FreeUnits{(cm⁻³,), 𝐋⁻³, nothing}}, 1}
├──────────────────────────────────────────────────────────────────────── dims ┤
  Ti Sampled{UnixTimes.UnixTime} [2015-10-16T13:05:35.144103000, …, 2015-10-16T13:07:24.945661000] ForwardOrdered Irregular Points
├──────────────────────────────────────────────────────────────────── metadata ┤
  Dict{Any, Any} with 17 entries:
  "SCALETYP"        => "linear"
  "FILLVAL"         => Any[-1.0e31]
  "DEPEND_0"        => "Epoch"
  "FIELDNAM"        => "MMS2 FPI/DIS number density"
  "SI_CONVERSION"   => "1e6>m^-3"
  "VALIDMAX"        => Any[100000.0]
  "DEPEND_1"        => 1:1
  "DELTA_MINUS_VAR" => "mms2_dis_numberdensity_err_brst"
  "FORMAT"          => "E12.2"
  "VAR_TYPE"        => "data"
  "CATDESC"         => "MMS2 FPI/DIS ion number density during this burst"
  :labels           => "Ni"
  "LABLAXIS"        => "N"
  "DELTA_PLUS_VAR"  => "mms2_dis_numberdensity_err_brst"
  "DISPLAY_TYPE"    => "time_series"
  "VALIDMIN"        => Any[0.001]
  "UNITS"           => "cm^-3"
└──────────────────────────────────────────────────────────────────────────────┘
 ⋮      ⋱  

Magnitudes of electron and ion convection velocities

Code
Vi_perp_mag, Ve_perp_mag = let Vi = dis_data.bulkv_gse, Ve = des_data.bulkv_gse, B = B_gse
    tr = timerange(B)
    Vi_clip = tview(Vi, tr)
    Ve_clip = tview(Ve, tr)

    B_int_Vi = tinterp(B, Vi_clip)[:, 1:3]
    B_int_Ve = tinterp(B, Ve_clip)[:, 1:3]
    Vi_perp_mag = toproj(Vi_clip, B_int_Vi) |> tnorm
    Ve_perp_mag = toproj(Ve_clip, B_int_Ve) |> tnorm

    setmeta(Vi_perp_mag, labels="Viper_t"), setmeta(Ve_perp_mag, labels="Veper_t")
end
(Quantity{Float32, 𝐋 𝐓⁻¹, Unitful.FreeUnits{(km, s⁻¹), 𝐋 𝐓⁻¹, nothing}}[16.370079f0 km s⁻¹, 39.08527f0 km s⁻¹, 18.779638f0 km s⁻¹, 36.385616f0 km s⁻¹, 28.834595f0 km s⁻¹, 31.232655f0 km s⁻¹, 21.860336f0 km s⁻¹, 25.042305f0 km s⁻¹, 19.904325f0 km s⁻¹, 3.4641075f0 km s⁻¹  …  54.85829f0 km s⁻¹, 52.707363f0 km s⁻¹, 43.587463f0 km s⁻¹, 37.501587f0 km s⁻¹, 32.176003f0 km s⁻¹, 29.350264f0 km s⁻¹, 22.573793f0 km s⁻¹, 23.164637f0 km s⁻¹, 26.775883f0 km s⁻¹, 33.856125f0 km s⁻¹], Quantity{Float32, 𝐋 𝐓⁻¹, Unitful.FreeUnits{(km, s⁻¹), 𝐋 𝐓⁻¹, nothing}}[179.42912f0 km s⁻¹, 65.0223f0 km s⁻¹, 95.883736f0 km s⁻¹, 80.23359f0 km s⁻¹, 31.38685f0 km s⁻¹, 176.10417f0 km s⁻¹, 21.706322f0 km s⁻¹, 53.19559f0 km s⁻¹, 126.49119f0 km s⁻¹, 102.77766f0 km s⁻¹  …  42.916092f0 km s⁻¹, 72.561844f0 km s⁻¹, 39.365314f0 km s⁻¹, 40.89979f0 km s⁻¹, 34.341866f0 km s⁻¹, 35.257183f0 km s⁻¹, 31.910059f0 km s⁻¹, 45.77481f0 km s⁻¹, 69.921875f0 km s⁻¹, 93.317215f0 km s⁻¹])

Current density

Code
J = begin
    Vi = dis_bulkv_lmn
    Ve = des_bulkv_lmn
    n = dis_n
    Ve_clip = tclip(Ve, timerange(Vi))
    Vi_interp = tinterp(Vi, Ve_clip)
    n_interp = tinterp(n, Ve_clip)
    J = mapslices(Vi_interp - Ve_clip; dims=Ti) do V_diff_i
        @. Unitful.q * V_diff_i * n_interp |> u"μA*m^-2"
    end
    setmeta(J, labels=["j_L", "j_M", "j_N"])
end
3661×3 DimArray{Unitful.Quantity{Float64, 𝐈 𝐋⁻², Unitful.FreeUnits{(μA, m⁻²), 𝐈 𝐋⁻², nothing}}, 2}
├──────────────────────────────────────────────────────────────────────── dims ┤
  Ti Sampled{UnixTimes.UnixTime} [2015-10-16T13:05:35.144103000, …, 2015-10-16T13:07:24.945661000] ForwardOrdered Irregular Points,
  AnonDim Sampled{Int64} [1, …, 3] ForwardOrdered Irregular Points
├──────────────────────────────────────────────────────────────────── metadata ┤
  Dict{Any, Any} with 20 entries:
  "UNITS"             => "km/s"
  "SCALETYP"          => "linear"
  "FILLVAL"           => Any[-1.0e31]
  "DEPEND_0"          => "Epoch"
  "FIELDNAM"          => "MMS2 FPI/DIS LMN bulk v"
  "SI_CONVERSION"     => "1.0e3>m s^-1"
  "VALIDMAX"          => Any[110000.0]
  "LABL_PTR_1"        => ["Vx_LMN", "Vy_LMN", "Vz_LMN"]
  "TENSOR_ORDER"      => Any[1]
  "DEPEND_1"          => 1:3
  "COORDINATE_SYSTEM" => "LMN"
  "DELTA_MINUS_VAR"   => "mms2_dis_bulkv_err_brst"
  "FORMAT"            => "E12.2"
  "VAR_TYPE"          => "data"
  "CATDESC"           => "MMS2 FPI/DIS ion bulk-velocity LMN vector during this…
  :labels             => ["j_L", "j_M", "j_N"]
  "DELTA_PLUS_VAR"    => "mms2_dis_bulkv_err_brst"
  "DISPLAY_TYPE"      => "time_series"
  "VALIDMIN"          => Any[-110000.0]
  "REPRESENTATION_1"  => "mms2_dis_cartrep_brst"
└──────────────────────────────────────────────────────────────────────────────┘
 ⋮      ⋱  

Para, perp and anti-parallel spectra of electrons

Code
des_energyspectr_tvars = [
    "cda/MMS2_FPI_BRST_L2_DES-MOMS/mms$(probe)_des_energyspectr_par_$(data_rate)",
    "cda/MMS2_FPI_BRST_L2_DES-MOMS/mms$(probe)_des_energyspectr_perp_$(data_rate)",
    "cda/MMS2_FPI_BRST_L2_DES-MOMS/mms$(probe)_des_energyspectr_anti_$(data_rate)"
]

des_energyspectr = get_data(des_energyspectr_tvars, trange) .|> func
replace!.(des_energyspectr, 0 => NaN)
des_energyspectr_ratio = des_energyspectr[1] ./ des_energyspectr[2]
des_energyspectr = setmeta.(des_energyspectr, colorrange=(1e5, 1e9))
des_energyspectr_ratio = setmeta(des_energyspectr_ratio,
    colorrange=(1e-1, 1e1), title="Ratio (Para/Perp)"
)
[ Info: Cannot parse mms2_des_energyspectr_par_brst unit 
[ Info: Cannot parse mms2_des_energyspectr_perp_brst unit 
[ Info: Cannot parse mms2_des_energyspectr_anti_brst unit 
3666×32 DimArray{Float32, 2}
├──────────────────────────────┴───────────────────────────────────────── dims ┐
  Ti Sampled{UnixTimes.UnixTime} [2015-10-16T13:05:35.024103000, …, 2015-10-16T13:07:24.975661000] ForwardOrdered Irregular Points,
  Y Sampled{Int64} 1:32 ForwardOrdered Regular Points
├──────────────────────────────────────────────────────────────────── metadata ┤
  Dict{Any, Any} with 15 entries:
  "VAR_NOTES"    => "Counts, summed within 30 degrees parallel bentPipe magneti…
  "SCALETYP"     => "log"
  "FILLVAL"      => Any[-1.0e31]
  "DEPEND_0"     => "Epoch"
  "FIELDNAM"     => "MMS2 FPI/DES energySpectr_par"
  "VALIDMAX"     => Any[1.0e30]
  :colorrange    => (0.1, 10.0)
  "DEPEND_1"     => mms2_des_energy_brst [ Units: eV, Size: (3666, 32)]
  "FORMAT"       => "E12.2"
  "VAR_TYPE"     => "data"
  "CATDESC"      => "MMS2 FPI/DES electron energy parallel spectrum 30 degrees …
  "LABLAXIS"     => "FPI1/DES EnSpectr, Parallel"
  :title         => "Ratio (Para/Perp)"
  "DISPLAY_TYPE" => "spectrogram"
  "VALIDMIN"     => Any[-1.0e30]
└──────────────────────────────────────────────────────────────────────────────┘
 ⋮      ⋱  

Summary data plot

In 1 paragraph (10 lines) explain what each panel represents for this reconnection interval.

From top to bottom, the panels represent the following: 1. the magnetic field vectors in LMN coordinate system; 2. energy times spectrogram of ion energy flux; 3. energy times spectrogram of electron energy flux; 4. plasma density (ion and electron); 5. ion flow velocity vectors in LMN coordinate system; 6. magnitudes of electron and ion convection velocities; 7. current density; 8. electron parallel and perpendicular temperatures; 9. electric field vectors in LMN coordinate system; 10-12. electron spectrograms (parallel, perpendicular, anti-parallel); 13. electron spectrogram ratio (para/perp).

Code
tvars2plot = (
    B_LMN,
    [dis_n, des_n],
    setmeta(dis_data.energyspectr_omni, colorrange=(1e3, 1e9)),
    setmeta(des_data.energyspectr_omni, colorrange=(1e3, 1e9)),
    dis_bulkv_lmn,
    [Vi_perp_mag, Ve_perp_mag],
    E_LMN,
    des_energyspectr...,
    des_energyspectr_ratio
)
faxes = tplot(tvars2plot)
tlines!(faxes, "2015-10-16T13:05:52")
tlines!(faxes, ["2015-10-16T13:05:44", "2015-10-16T13:06:00"])
tlines!(faxes, ["2015-10-16T13:06:46", "2015-10-16T13:07:12"])
ylims!.(faxes.axes[end-3:end], 0.9e1, 1.2e3)
faxes
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25
Warning: y values are not constant along time
@ SpacePhysicsMakie ~/.julia/packages/SpacePhysicsMakie/Os7PA/src/attributes.jl:25

Reproducibility

Code
using Pkg
Pkg.status()
Status `~/src/juliaspacephysics.github.io/Project.toml`
 [13f3f980] CairoMakie v0.14.0
  [0703355e] DimensionalData v0.29.24
  [3930f61c] SPEDAS v0.2.1
  [0c28ffd8] SpacePhysicsMakie v0.1.3
  [09b745ad] Speasy v0.4.8 `~/.julia/dev/Speasy`
  [31d49243] TimeseriesUtilities v0.1.4
 [1986cc42] Unitful v1.25.0
Info Packages marked with  have new versions available and may be upgradable.
Code
using InteractiveUtils # hide
versioninfo()
Julia Version 1.12.1
Commit ba1e628ee49 (2025-10-17 13:02 UTC)
Build Info:
  Official https://julialang.org release
Platform Info:
  OS: macOS (arm64-apple-darwin24.0.0)
  CPU: 12 × Apple M2 Max
  WORD_SIZE: 64
  LLVM: libLLVM-18.1.7 (ORCJIT, apple-m2)
  GC: Built with stock GC
Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores)
Environment:
  JULIA_PROJECT = @.
  JULIA_LOAD_PATH = @:@stdlib
Back to top