Skip to main content

xeos

Lightweight, xarray-enabled wrappers for seawater equations of state.

Ocean models (MOM6, MITgcm, MPAS-Ocean, Oceananigans) differ in the equation of state (EOS) they use, and many let you change it at run time. Python post-processing then often applies a different EOS than the simulation did, silently corrupting derived quantities like density, thermal expansion, and water-mass transformation diagnostics. xeos lets you pick the EOS that matches your run — by the model's own selector string — and apply it to xarray/dask data through one uniform API.

It stays lightweight on purpose: the polynomial/rational equations of state are vendored as small numpy kernels, so the core install needs only numpy + xarray. TEOS-10 (via gsw) is an optional extra.

Install

pip install xeos              # core (numpy + xarray): all vendored EOS
pip install xeos[teos10]      # adds TEOS-10 via gsw
pip install xeos[complete]    # gsw + numba acceleration

Usage

Match your model run by its selector string:

import xeos

# MOM6 run with EQN_OF_STATE = "WRIGHT_FULL"
eos = xeos.from_model("MOM6", "WRIGHT_FULL")
rho = eos.rho(theta, salt, pressure)     # xarray DataArrays in, labeled DataArray out
a   = eos.alpha(theta, salt, pressure)   # thermal expansion
b   = eos.beta(theta, salt, pressure)    # haline contraction

# MITgcm eosType = 'JMD95Z'
xeos.from_model("MITgcm", "JMD95Z").rho(theta, salt, p)

# MPAS-Ocean config_eos_type = 'jm'
xeos.from_model("MPAS-Ocean", "jm").rho(theta, salt, p)

# Oceananigans TEOS10EquationOfState
xeos.from_model("Oceananigans", "TEOS10EquationOfState").rho(CT, SA, p)

Or address an EOS directly:

xeos.equation_of_state("jmd95").rho(t, s, p)
xeos.rho(t, s, p, eos="wright97-full")          # one-off functional form
xeos.list_eos()                                  # what's available

Inputs may be scalars, numpy arrays, or xarray DataArrays (dask-backed arrays stay lazy). Pressure is sea pressure in dbar by default.

Conventions

xeos does not silently convert inputs. Each EOS declares the temperature and salinity it expects: TEOS-10 and the Roquet polynomials use conservative temperature + absolute salinity; the others use potential temperature + practical salinity (see eos.temperature / eos.salinity). Explicit conversion helpers live in xeos.conventions (these need the gsw extra).

Supported equations of state

xeos.list_eos() returns the current set. As of now:

  • linear — configurable (MOM6/MITgcm/Oceananigans LINEAR)
  • wright97-full, wright97-reduced — Wright 1997 (MOM6 WRIGHT_FULL, WRIGHT_RED/WRIGHT_REDUCED). The bare MOM6 WRIGHT selector also resolves to wright97-reduced with a warning: it is the corrected reduced fit, whereas MOM6's legacy WRIGHT runs the uncorrected kernel (see "not yet implemented").
  • jmd95 — Jackett & McDougall 1995 (MITgcm JMD95Z/JMD95P; also MOM6 UNESCO/JACKETT_MCD, which are this fit — not EOS-80)
  • unesco — UNESCO/EOS-80, Fofonoff & Millard 1983 (MITgcm UNESCO)
  • mdjwf — McDougall et al. 2003 (MITgcm MDJWF)
  • teos10-poly55 — Roquet 55-term polynomial / TEOS-10 density form (Oceananigans TEOS10EquationOfState, MOM6 ROQUET_RHO/NEMO)
  • roquet-spv — Roquet 55-term specific-volume form (MOM6 ROQUET_SPV)
  • roquet-{linear,cabbeling,cabbeling-thermobaricity,freezing,second-order,simplest-realistic} — idealized second-order Roquet forms (Oceananigans RoquetSeawaterPolynomial(:…))
  • mpas-linear, mpas-jm, mpas-wright — MPAS-Ocean / E3SM config_eos_type = linear/jm/wright; mpas-jm and mpas-wright reuse the jmd95 and wright97-reduced kernels (MPAS-O's jm/wright are the same EOS)
  • teos10 — TEOS-10 via gsw (its 75-term Roquet polynomial, not the exact Gibbs function; MOM6/MITgcm TEOS10)

Not yet implemented (planned, slot into the same registry): MOM6 JACKETT_06 and the legacy-buggy WRIGHT kernel (the bare WRIGHT selector currently resolves to the corrected wright97-reduced with a warning), and MITgcm POLY3 (per-level runtime coefficients).

Full literature references with DOIs are in the usage docs.

Development

pip install -e .[test]
pytest                       # validates vendored kernels against frozen fixtures

Test "truth" values are generated from authoritative reference packages in a pinned, separate environment and frozen into xeos/tests/reference/truth.json; the test suite reads that file and stays lightweight. See xeos/tests/reference/README.md to regenerate.

Releasing

The git tag is the version. xeos has no version string checked into the source tree: hatch-vcs derives it from the tag at build time and writes xeos/_version.py (gitignored, but shipped inside the sdist and wheel). To cut a release you tag; there is no file to bump and nothing to keep in sync.

  1. Make sure main is green and has everything you want in the release.
  2. Publish a GitHub Release whose tag is vX.Y.Z, targeting the commit you want to ship:
    gh release create vX.Y.Z --target "$(git rev-parse origin/main)" \
      --title vX.Y.Z --generate-notes
    
    Publishing it (not merely pushing a tag) is what fires the workflow.
  3. The Publish to PyPI workflow builds from that tag and uploads to PyPI via Trusted Publishing (OIDC — no token secret). It checks out with fetch-depth: 0 so the tag is visible to hatch-vcs, and asserts that the built version matches the tag before publishing.
  4. Verify: https://pypi.org/project/xeos/.
  5. conda-forge builds from the PyPI sdist and lags by design — see conda/README.md. After the first release the autotick bot opens the version-bump PR for you.

To rehearse without publishing, run the workflow manually (Actions → Publish to PyPI → Run workflow); on workflow_dispatch it builds and can optionally push to TestPyPI, but never to PyPI.

Release files for xeos 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xeos 0.2.3
File Size Uploaded
xeos-0.2.3.tar.gz 106.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for xeos 0.2.3
File Interpreter ABI Platform
xeos-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 230.7 kB

Release files / xeos-0.2.3.tar.gz

Download URL xeos-0.2.3.tar.gz
Size 106.4 kB
Tags Source
SHA-256 checksum
How to use checksums
cb820086fc581e0ec21539a01436e58ac3a4fd38bd2e6071adb3ecf0f97d0299
BLAKE2b-256 checksum
How to use checksums
3a0acb69db6cf73d7f0e5d37e5bef35bb3994a6aaf74e541388f36ee9bc6f1fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release files / xeos-0.2.3-py3-none-any.whl

Download URL xeos-0.2.3-py3-none-any.whl
Size 124.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce875dec1276c397f2c30113ece7e977048d53853ef85be556efb042c3cebab4
BLAKE2b-256 checksum
How to use checksums
7a6bf18c4914d605d40d0dc06d4309350bd6d45ad00c35581fb6007b8a3f48f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.3 This release

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page