IDL Data#

This notebook focuses on handling data in the IDL format.

Importing the package#

import flekspy

# Set display for XArrays
import xarray as xr

xr.set_options(
    display_expand_coords=False,
    display_expand_data=False,
    display_expand_data_vars=False,
)
<xarray.core.options.set_options at 0x7f88740b3080>

Downloading demo data#

If you don’t have FLEKS data to start with, you can download demo field data with the following:

from flekspy.util import download_testfile

url = "https://raw.githubusercontent.com/henry2004y/batsrus_data/master/batsrus_data.tar.gz"
download_testfile(url, "data")

Loading data#

flekspy.load is the interface to read files of all formats. It returns a different object for different formats. IDL format data are processed into XArray data structures:

file = "data/1d__raw_2_t25.60000_n00000258.out"
ds = flekspy.load(file)
ds
<xarray.Dataset> Size: 31kB
Dimensions:  (x: 256)
Coordinates: (1)
Data variables: (14)
Attributes: (12/18)
    filename:    /home/runner/work/flekspy/flekspy/docs/data/1d__raw_2_t25.60...
    isOuts:      False
    npict:       1
    nInstance:   1
    fileformat:  ascii
    unit:        normalized
    ...          ...
    grid:        [256]
    npoints:     256
    parameters:  {np.str_('r'): np.float64(3.0), np.str_('g'): np.float64(2.0...
    dims:        ['x']
    variables:   [np.str_('x'), np.str_('Rho'), np.str_('Mx'), np.str_('My'),...
    strtime:     0000h00m25.600s

The coordinates can be accessed via

ds.coords
Coordinates: (1)

The variables can be accessed via

ds.var
<bound method DatasetAggregations.var of <xarray.Dataset> Size: 31kB
Dimensions:  (x: 256)
Coordinates: (1)
Data variables: (14)
Attributes: (12/18)
    filename:    /home/runner/work/flekspy/flekspy/docs/data/1d__raw_2_t25.60...
    isOuts:      False
    npict:       1
    nInstance:   1
    fileformat:  ascii
    unit:        normalized
    ...          ...
    grid:        [256]
    npoints:     256
    parameters:  {np.str_('r'): np.float64(3.0), np.str_('g'): np.float64(2.0...
    dims:        ['x']
    variables:   [np.str_('x'), np.str_('Rho'), np.str_('Mx'), np.str_('My'),...
    strtime:     0000h00m25.600s>

and individual variables can be accessed through keys or properties:

ds["p"]
ds.p
<xarray.DataArray 'p' (x: 256)> Size: 2kB
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 ... 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
Coordinates: (1)

Unstructured data#

Unstructured data is handled with Xugrid, with support of regridding and partitioning.

file = "data/bx0_mhd_6_t00000100_n00000352.out"
dsu = flekspy.load(file)
dsu
<xarray.Dataset> Size: 12kB
Dimensions:        (mesh2d_nNodes: 116)
Coordinates: (1)
Data variables: (12)
Attributes: (12/18)
    filename:    /home/runner/work/flekspy/flekspy/docs/data/bx0_mhd_6_t00000...
    isOuts:      False
    npict:       1
    nInstance:   1
    fileformat:  ascii
    unit:        2000-06-21T10:46:00;
    ...          ...
    grid:        [116   1]
    npoints:     116
    parameters:  {np.str_('xSI'): np.float64(6378000.0), np.str_('r'): np.flo...
    dims:        ['x', 'y']
    variables:   [np.str_('x'), np.str_('y'), np.str_('z'), np.str_('Rho'), n...
    strtime:     0000h01m00.000s

Interpolating data#

Variable interpolation is supported via XArray. For 1D data, simply provide the coordinate:

ds["Rho"].interp(x=100)
<xarray.DataArray 'Rho' ()> Size: 8B
0.1225
Coordinates: (1)

For multidimensional interpolation, it can be easily extended as

file = "data/z=0_fluid_region0_0_t00001640_n00010142.out"
ds = flekspy.load(file)
ds["rhoS0"].interp(x=-28000.0, y =0.0)
<xarray.DataArray 'rhoS0' ()> Size: 8B
0.122
Coordinates: (2)

If you want to interpolate for all variables at a single location,

ds.interp(x=-28000.0, y =0.0)
<xarray.Dataset> Size: 240B
Dimensions:  ()
Coordinates: (2)
Data variables: (28)
Attributes: (12/18)
    filename:    /home/runner/work/flekspy/flekspy/docs/data/z=0_fluid_region...
    isOuts:      False
    npict:       1
    nInstance:   1
    fileformat:  binary
    unit:        PLANETARY
    ...          ...
    grid:        [601   2]
    npoints:     1202
    parameters:  {np.str_('mS0'): np.float64(0.009999999776482582), np.str_('...
    dims:        ['x', 'y']
    variables:   [np.str_('x'), np.str_('y'), np.str_('rhoS0'), np.str_('rhoS...
    strtime:     0000h16m40.021s

Visualizing fields#

Thanks to XArray’s Matplotlib wrapper, all Matplotlib’s plotting functionalities are directly supported.

import matplotlib.pyplot as plt

file = "data/1d__raw_2_t25.60000_n00000258.out"
ds = flekspy.load(file)

fig, axs = plt.subplots(2, 1, constrained_layout=True, sharex=True, sharey=True)
ds.p.plot(ax=axs[0])
ds.Bx.plot(ax=axs[1])
plt.show()
_images/c4f31640002be3277a9bfc4caeddf409a0bedc5e4357f327c186e733191813c4.png

By default, XArray’s 2D plotting functions map the first dimension to the vertical y-axis and the second dimension to the horizontal x-axis. To overwrite this default behavior, we can explicitly set the x and y arguments:

file = "data/z=0_fluid_region0_0_t00001640_n00010142.out"
ds = flekspy.load(file)
fig, axs = plt.subplots(
    3, 1, figsize=(10, 6), constrained_layout=True, sharex=True, sharey=True
)
ds.Bx.plot.pcolormesh(ax=axs[0], x="x", y="y")
ds.By.plot.pcolormesh(ax=axs[1], x="x", y="y")
ds.Bz.plot.pcolormesh(ax=axs[2], x="x", y="y")
plt.show()
_images/bc9710dd422fe51bf423db11bb73152126aa18881a511852549c97cda043ab42.png

Unstructured IDL format output plotting is supported directly by Xugrid. Note that here we need an additional level ugrid compared to direct plotting via xarray.

dsu.Rho.ugrid.plot.contourf()
plt.show()
_images/e24f05fee37cf24e910763a07c2b76ad7f2bb6836eae676220af8181afc50466.png

Derived Variables#

Pressure Anisotropy#

In this demo, the ion pressure anisotropy can be as large as 60 because in a 1D quasi-perpendicular shock simulation, there is no parallel heating.

import matplotlib.pyplot as plt

file = "data/z=0_fluid_region0_0_t00001640_n00010142.out"
ds = flekspy.load(file)
anisotropy = ds.derived.get_pressure_anisotropy(species=1)
fig, ax = plt.subplots(1, 1, figsize=(8, 2), constrained_layout=True)
anisotropy.plot.pcolormesh(
    ax=ax,
    x="x",
    y="y",
    cmap="GnBu",
    vmin=0,
    vmax=60,
    cbar_kwargs=dict(label=r"$P_{i\perp}/P_{i\parallel}$", pad=0.0, aspect=25),
)
plt.show()
_images/bcd9941b2b4115440814565fe729a005aae9c7de8017ee0c5e52b6807f60b1d5.png

Current density#

Current density can be calculated in two ways: from the curl of the magnetic field or from the definition \(J = \sum_\alpha n_\alpha q_\alpha \vec{v}_\alpha\). Both methods are available in the IDL accessor. As can be seen below, the current density results may not be identical.

import matplotlib.colors as colors

current = ds.derived.get_current_density()

norm = colors.SymLogNorm(0.1, linscale=0.4, vmin=-0.03, vmax=0.03)
fig, ax = plt.subplots(figsize=(8,2), constrained_layout=True)
current["jy"].plot.pcolormesh(x="x", y="y", cmap="RdBu_r", norm=norm, cbar_kwargs=dict(label=r"$J_y\,[\mu A/m]$", pad=0.0, aspect=40))
ax.set_xlabel(r"x [km]", fontsize=14)
ax.set_ylabel(r"y [km]", fontsize=14)
plt.show()
_images/9279c2a98e0bd8b4999a302887139dafc150a778a7283b3810061ba91f993818.png
current = ds.derived.get_current_density_from_definition(species=[0, 1])

fig, ax = plt.subplots(figsize=(8,2), constrained_layout=True)
current["jy"].plot.pcolormesh(ax=ax, x="x", y="y", cmap="RdBu_r", vmax=0.03, cbar_kwargs=dict(label=r"$J_y\,[\mu A/m]$", pad=0.0, aspect=40))
ax.set_xlabel(r"x [km]", fontsize=14)
ax.set_ylabel(r"y [km]", fontsize=14)
plt.show()
_images/6041a0f7ee669ba3e3a6ad8232b9f713af020b0475b0a181688cadf9c00c247f.png