pyspharm-cpp implements a PySpharm-compatible Python API for scalar and vector spherical harmonic transforms (SHTs), spectral regridding, Legendre functions, and interpolation. It uses ducc0's C++ transforms with nanobind and requires only NumPy at runtime.
For lower-level spherical harmonic transforms, consider using ducc0. For atmospheric science operations such as relative vorticity, divergence, streamfunction, velocity potential, spectral filtering, and regridding, consider using spharmgrid. Spharmgrid supports Xarray fields with a ducc0 CPU backend and separate JAX/S2FFT and PyTorch/torch-harmonics interfaces for GPU calculations.
Install from PyPI:
python -m pip install pyspharm-cppOr install from conda-forge with Conda or Mamba:
conda install -c conda-forge pyspharm-cpp
mamba install -c conda-forge pyspharm-cppPython 3.11 or newer is required. Source builds need a C++17 compiler; Git checkouts also need the ducc0 submodule. Source distributions include the required ducc0 files. The Python module imports as spharm_cpp; import spharm_cpp as spharm is convenient when adapting PySpharm code.
import numpy as np
import spharm_cpp as spharm
nlon, nlat = 32, 16
sht = spharm.Spharmt(nlon, nlat, gridtype="gaussian")
lat, _ = spharm.gaussian_lats_wts(nlat)
lon = np.arange(nlon) * (360.0 / nlon)
field = np.cos(np.deg2rad(lat))[:, None] * np.cos(np.deg2rad(lon))[None, :]
coefficients = sht.grdtospec(field, ntrunc=1)
reconstructed = sht.spectogrd(coefficients)
np.testing.assert_allclose(reconstructed, field, atol=2e-12, rtol=2e-12)- Backend: ducc0 replaces the SPHEREPACK transforms.
- Precision: float64/complex128 by default; float32/complex64 can be selected with
dtype=np.float32. - Legendre functions:
legfunc="computed"is the default. Stored Legendre functions (legfunc="stored") are not supported. - Batched interpolation:
legendreandspecintrpalso accept one-dimensional coordinate arrays, using overloads of the original scalar functions. - Truncation: Clenshaw–Curtis analysis supports degrees through
min(nlat-2, nlon//2); Gaussian analysis throughmin(nlat-1, nlon//2). Vector analysis excludes the even-longitude Nyquist order. - Other differences: zero truncation, optional float64 geodesic coordinates, index dtype, and mixed-precision regridding are documented in the PySpharm comparison.
See numerical conventions for coefficient ordering and normalization, and the quickstart and API reference for usage.
Median timings in milliseconds on the Gaussian 1280 × 640 grid, which has the largest measured speedup among the five cases (69.42× for wind analysis). ducc0 and pyspharm-cpp use eight threads; pyspharm is serial. All timings use float32 and the same truncation.
| Operation | pyspharm f32 | pyspharm-cpp f32 | ducc0 f32 | Speedup vs pyspharm |
|---|---|---|---|---|
| Scalar analysis | 139.024 ms | 2.103 ms | 2.411 ms | 66.11× |
| Scalar synthesis | 32.081 ms | 2.227 ms | 2.304 ms | 14.41× |
| Wind analysis | 339.515 ms | 4.890 ms | 3.389 ms | 69.42× |
| Wind synthesis | 67.204 ms | 5.432 ms | 4.558 ms | 12.37× |
See benchmark results and reproduction instructions for all five grid cases.
GPL-2.0-or-later. ducc0 is included as an unmodified submodule; see third-party notices. ducc0 is used under its respective license.