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.

Release files for xeos 0.2.1

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.1
File Size Uploaded
xeos-0.2.1.tar.gz 97.7 kB Details

Built distribution (wheel)

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

Total release size: 213.7 kB

Release files / xeos-0.2.1.tar.gz

Download URL xeos-0.2.1.tar.gz
Size 97.7 kB
Tags Source
SHA-256 checksum
How to use checksums
f1accaddd65b72bdc7cad9c14607280fd60144175c9dbc6d4b83763da1dd5088
BLAKE2b-256 checksum
How to use checksums
f015edf85a9de10d66c59c659b550f5b1c91256d920b4cb84fdb43a4ef03c78f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 28, 2026.

Transparency log

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

Download URL xeos-0.2.1-py3-none-any.whl
Size 116.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c7018afb85d13d998380c250ee7a8f060d8cf2fc2cd3e2f7acd9e6e4c3c16dcb
BLAKE2b-256 checksum
How to use checksums
cc3756e94fcab5208aa59b08a5553cff790f6c93a764259784f6e2cc8f8a6473
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.3

2 release files

0.2.2

2 release files

This release

0.2.1 This release

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