Validation with PySPEDAS

Performance Notes
  • Calling Python from Julia (via PythonCall.jl) introduces only a negligible overhead, typically within nanoseconds.
  • Memory allocations shown in Julia benchmarks do not include allocations that occur within Python. To measure Python-side allocations, profiling should be done directly in Python.
  • The documentation and benchmarks are generated using GitHub Actions. Running the code locally with multiple threads (e.g., by setting JULIA_NUM_THREADS) can yield even greater performance improvements for Julia.
using PlasmaWaves
using PySPEDAS, PythonCall
using DimensionalData
using PySPEDAS: get_data
using CairoMakie, SpacePhysicsMakie
    CondaPkg Found dependencies: /home/runner/.julia/packages/CondaPkg/8GjrP/CondaPkg.toml
    CondaPkg Found dependencies: /home/runner/.julia/packages/PythonCall/83z4q/CondaPkg.toml
    CondaPkg Found dependencies: /home/runner/.julia/packages/PySPEDAS/qgs9e/CondaPkg.toml
    CondaPkg Resolving changes
             + certifi
             + libstdcxx
             + libstdcxx-ng
             + netcdf4
             + openssl
             + pyspedas (pip)
             + python
             + python-gil
             + uv
    CondaPkg Initialising pixi
             /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
             init
             --format pixi
             /home/runner/work/PlasmaWaves.jl/PlasmaWaves.jl/docs/.CondaPkg
✔ Created /home/runner/work/PlasmaWaves.jl/PlasmaWaves.jl/docs/.CondaPkg/pixi.toml
    CondaPkg Wrote /home/runner/work/PlasmaWaves.jl/PlasmaWaves.jl/docs/.CondaPkg/pixi.toml
             [dependencies]
             netcdf4 = "*"
             libstdcxx = ">=3.4,<15.0"
             openssl = ">=3, <3.6"
             libstdcxx-ng = ">=3.4,<15.0"
             uv = ">=0.4"
             python-gil = "*"
             certifi = "*"
                              [dependencies.python]
                 channel = "conda-forge"
                 build = "*cp*"
                 version = ">=3.10,!=3.14.0,!=3.14.1,<4"
                          [project]
             name = ".CondaPkg"
             platforms = ["linux-64"]
             channels = ["conda-forge"]
             channel-priority = "strict"
             description = "automatically generated by CondaPkg.jl"
                          [pypi-dependencies.pyspedas]
             git = "https://github.com/spedas/pyspedas"
    CondaPkg Installing packages
             /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
             install
             --manifest-path /home/runner/work/PlasmaWaves.jl/PlasmaWaves.jl/docs/.CondaPkg/pixi.toml
✔ The default environment has been installed.

Wave polarization

@py import pyspedas.analysis.tests.test_twavpol: TwavpolDataValidation
TwavpolDataValidation.setUpClass()

thc_scf_fac = get_data("thc_scf_fac") |> DimArray
py_tvars = [
    "thc_scf_fac_powspec",
    "thc_scf_fac_degpol",
    "thc_scf_fac_waveangle",
    "thc_scf_fac_elliptict",
    "thc_scf_fac_helict",
]
# PySPEDAS returns non valid values at the first and last frequency bin, the last time bin is also not valid
_subset_py(x) = x[1:end-1,2:end-1]
py_result = DimStack(_subset_py.(DimArray.(get_data.(py_tvars))))
py_result.thc_scf_fac_powspec.metadata[:colorscale] = log10
py_result.thc_scf_fac_helict.metadata[:colorscale] = identity
res = twavpol(thc_scf_fac)

f = Figure(; size=(1200, 800))
tplot(f[1,1], py_result)
tplot(f[1,2], res)
f
Example block output

We can also use single value decomposition (SVD) technique to calculate the wave polarization.

res = twavpol_svd(thc_scf_fac)
tplot(res)
Example block output

Benchmark

using Chairmarks

@b twavpol(thc_scf_fac), twavpol_svd(thc_scf_fac), pyspedas.twavpol("thc_scf_fac")
(19.891 ms (200 allocs: 1.519 MiB, without a warmup), 12.164 ms (148 allocs: 1.302 MiB, without a warmup), 5.594 s (6 allocs: 112 bytes, without a warmup))

Julia is about 100 times faster than Python.

References