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 MOM6WRIGHTselector also resolves towright97-reducedwith a warning: it is the corrected reduced fit, whereas MOM6's legacyWRIGHTruns the uncorrected kernel (see "not yet implemented"). - jmd95 — Jackett & McDougall 1995 (MITgcm
JMD95Z/JMD95P; also MOM6UNESCO/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, MOM6ROQUET_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-jmandmpas-wrightreuse thejmd95andwright97-reducedkernels (MPAS-O'sjm/wrightare the same EOS) - teos10 — TEOS-10 via
gsw(its 75-term Roquet polynomial, not the exact Gibbs function; MOM6/MITgcmTEOS10)
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)
| File | Size | Uploaded | |
|---|---|---|---|
| xeos-0.2.1.tar.gz | 97.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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