This release contains several major new additions — the full 3D variational equations with Lyapunov exponents, the MultipoleExpansionPotential for arbitrary density distributions, smooth StreamTrack models for tidal streams, and a complete rewrite of the documentation as tested Jupyter notebooks — along with many new features, bug fixes, and dependency/project maintenance updates.
Major changes
-
3D variational equations (state-transition matrix) + Lyapunov by @jobovy with Claude in #891:
galpy now supports the full 3D variational equations (the state-transition matrix) during orbit integration in C, the 3D analogue of the existing planar machinery, for most of the potential library. This enables fast tangent-dynamics and chaos calculations — including the new
Orbit.lyapunovmethod for estimating the largest Lyapunov exponent (or, withspectrum=True, the full Lyapunov spectrum) — and lays the groundwork for differentiable orbit integration. The variational equations also support velocity-dependent (dissipative) forces such as dynamical friction. -
Add MultipoleExpansionPotential for multipole expansion of arbitrary densities by @jobovy with Claude in #829:
The new
MultipoleExpansionPotentialrepresents the potential of an arbitrary, and optionally time-dependent, density distribution through a real spherical-harmonic multipole expansion, with both Python and C evaluation of the potential, forces, second derivatives, and density; it can be built directly from a density function via thefrom_densityclassmethod. A companionDiskMultipoleExpansionPotentialuses it to solve the Poisson equation for disk+halo systems (the multipole analogue ofDiskSCFPotential). -
Smooth stream track for streamspraydf models by @jobovy with Claude in #861
-
df.streamdf: streamTrack method + deprecate calc_stream_lb (and Rnorm/Vnorm) by @jobovy with Claude in #878:
A new
StreamTrackclass holds a smooth, precomputed phase-space track through a tidal stream, with accessors for every standard galpy coordinate system, an analytic 6×6 phase-space covariance along the track, and built-in plotting. Tracks can be built from a particle sample or generated directly from astreamspraydforstreamdfvia their newstreamTrackmethods. -
Rewrite tutorials as Jupyter notebooks with gallery navigation by @jobovy with Claude in #851:
The documentation tutorials have been completely rewritten as Jupyter notebooks with gallery-style navigation. The notebooks are executed as part of the test suite and periodically re-rendered, so the documentation is automatically verified against the current code and stays up to date.
New Features
- Add
DiskMultipoleExpansionPotentialby @jobovy with Claude in #838 - Add analytical power-law spherical distribution functions by @jobovy with Claude in #844
- Add time-dependent MultipoleExpansionPotential by @jobovy with Claude in #847
- Add tail= keyword to streamspraydf, deprecate leading= by @jobovy with Claude in #849
- Vectorize EllipsoidalPotential evaluations to support array inputs by @jobovy with @Copilot and Claude in #858
- Per-orbit time arrays in Orbit.integrate; batched streamspraydf integration by @jobovy with Claude in #873
- Add align_to_orbit helper to coords + Orbit by @jobovy with Claude in #874
- df.streamspraydf: allow callable, time-dependent progenitor_mass by @jobovy with Claude in #880
- df.streamspraydf: non-uniform stripping-time distributions + pericenter helper by @jobovy with Claude in #881
- Add cinterp option to NonInertialFrameForce for fast C orbit integration by @jobovy with Claude in #889
- actionAngleStaeckel: pure-Python (c=False) frequencies and angles by @jobovy with Claude in #1010
- Add ExpTruncNFWPotential: exponentially-truncated NFW profile by @sgpfaff with Claude in #976
Bug fixes and minor tweaks
- Fix in-place mutation of input arrays in coordinate transformation functions by @jobovy with @Copilot in #842
- Fix p(v|r) interpolator grid not covering full rmax range by @jobovy with Claude in #846
- Fix incorrect physical unit conversion for
phitorqueinDissipativeForceandplanarDissipativeForceby @jobovy with @Copilot in #853 - Propagate turn_physical_on/off to CompositePotential components by @jobovy with @Copilot in #855
- Try to deal with flakiness of the stepsize test by @jobovy in #875
- df.streamdf: rename custom_transform → custom_sky_transform by @jobovy in #879
- Fix incorrect SpiralArms C R2deriv/PlanarR2deriv used by integrate_dxdv by @jobovy with Claude in #899
- Fix incorrect power of R in TwoPowerSpherical C PlanarR2deriv by @jobovy with Claude in #902
- Fix incorrect coefficient in FlattenedPowerPotential C PlanarR2deriv by @jobovy with Claude in #912
- Fix sign of SCFPotential C planar 2nd derivatives (variational STM) by @jobovy with Claude in #923
- SCFPotential: analytic second derivatives (replace numerical mixin) by @jobovy with Claude in #921
- Fix interpolation-range warning for multiple orbits by @jobovy with Claude in #924
- DiskSCF family: planar 2nd derivatives in C (planar variational equations) by @jobovy with Claude in #925
- Fix: KuijkenDubinski layer drops t for the embedded expansion (time-dependent DiskMultipole frozen at t=0) by @jobovy with Claude in #943
- Fix list-of-Potential input to wrapper potentials: upgrade through _check_potential_list_and_deprecate by @jobovy with Claude in #947
- Fix wrapper repr for direct WrapperPotential subclasses (eaten first character) by @jobovy with Claude in #948
- Fix silent-skip in _parse_pot: planarized potentials without planar C support segfaulted the C integrator by @jobovy with Claude in #953
- RotateAndTiltWrapperPotential C: include t in the force-cache key by @jobovy with Claude in #954
- Support astropy ≥ 8: galcen_v_sun is now a CartesianRepresentation (.xyz) by @jobovy with Claude in #971
- Fix deepcopy of MultipoleExpansionPotential under scipy>=1.18 by @jobovy with Claude in #980
- Fix numpy 2.5.0 compatibility (eig/eigvals complex + chararray deprecation) by @jobovy with Claude in #994
- Fix sphericaldf sampling crash for slightly-negative isotropic DFs by @jobovy with Claude in #1032
Dependencies / maintenance
- Fix release date in 1.11.2 release by @jobovy in #833
- Bump version to next development version by @jobovy in #834
- Increase MACOSX_DEPLOYMENT_TARGET to 11.0 because latest llvm-openmp requires that (see llvm/llvm-project#176094) by @jobovy in #836
- Bump the actions group with 2 updates by @dependabot[bot] in #835
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #837
- Bump pypa/cibuildwheel from 3.3 to 3.4 in the actions group by @dependabot[bot] in #839
- Update vendored xsf from v0.1.3 to v0.2.0 by @jobovy with @Copilot in #843
- Bump the actions group with 2 updates by @dependabot[bot] in #845
- Bump mymindstorm/setup-emsdk from 14 to 15 in the actions group by @dependabot[bot] in #848
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #850
- Bump mymindstorm/setup-emsdk from 15 to 16 in the actions group by @dependabot[bot] in #859
- Remove old rst documentation replaced by notebook tutorials by @jobovy with Claude in #860
- Staeckel tutorial: pyvo fallback for flaky Gaia archive by @jobovy with Claude in #863
- Add monthly workflow to re-execute documentation notebooks by @jobovy with Claude in #862
- Fix dry_run boolean comparison in update-doc-notebooks workflow by @jobovy with Claude in #865
- Bump the actions group with 2 updates by @dependabot[bot] in #866
- Use emscripten-core/setup-emsdk action by @jobovy with Claude in #867
- Replace archived jakejarvis/s3-sync-action with AWS CLI by @jobovy with Claude in #868
- Expand documentation notebook coverage by @jobovy with Codex and Claude in #869
- Restore doc images mistakenly removed in #860 by @jobovy with Claude in #871
- Cache Gaia DR3 query result in staeckel doc notebook by @jobovy with Claude in #870
- Cache Dierickx 2010 catalog in orbit/examples notebook to reduce CI flakes by @jobovy with Claude in #876
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #877
- CI: use runner's preinstalled Miniconda instead of setup-micromamba by @jobovy with Claude and Codex in #882
- CI: update-doc-notebooks workflow should only stage .ipynb files by @jobovy with Claude in #884
- Add updating the doc notebooks to the release checklist by @jobovy in #887
- Reproducible doc-notebook re-renders + Claude diff summary in PR body by @jobovy with Claude in #886
- [auto] Update documentation notebook outputs (2026-05-16) by @github-actions[bot] in #888
- [pre-commit.ci] pre-commit autoupdate by @pre-commit-ci[bot] in #890
- Bump the actions group with 2 updates by @dependabot[bot] in #915
- CI: remove the unused 'ci skip' commit-message guard by @jobovy with Claude in #955
- tests: fix pytest 9.1.0 collection error (list(zip(...)) in parametrize) by @jobovy with Claude in #957
- Bump pypa/cibuildwheel from 4.0 to 4.1 in the actions group by @dependabot[bot] in #958
- tests: parametrize the per-potential loop-tests in test_potential.py by @jobovy with Claude in #977
- Add an 'all-clear' aggregate status check for auto-merge / merge queue by @jobovy with Claude in #979
- Bump actions/checkout from 6 to 7 in the actions group by @dependabot[bot] in #995
- [auto] Update documentation notebook outputs (2026-06-15) by @github-actions[bot] in #961
- Bump actions/cache from 5 to 6 in the actions group by @dependabot[bot] in #1030
- Add truncated-NFW N-body sampling examples to spherical_dfs tutorial by @jobovy with Claude in #1031
- [auto] Update documentation notebook outputs (2026-06-30) by @github-actions[bot] in #1035
- Release 1.12.0 by @jobovy with Claude in #1037
- Bump version to 1.12.0 by @jobovy in #1041
New Contributors
- @github-actions[bot] made their first contribution in #888
- @sgpfaff made their first contribution in #976
Full Changelog: v1.11.2...v1.12.0