Metadata-Version: 2.4
Name: ocean-diva
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=1.5 ; extra == 'accessors'
Requires-Dist: xarray>=2023.1 ; extra == 'accessors'
Requires-Dist: pandas>=1.5 ; extra == 'pandas'
Requires-Dist: matplotlib>=3.7 ; extra == 'plot'
Requires-Dist: xarray>=2023.1 ; extra == 'xarray'
Provides-Extra: accessors
Provides-Extra: pandas
Provides-Extra: plot
Provides-Extra: xarray
License-File: LICENSE
Summary: A lightweight, pip-installable Python implementation of Data-Interpolating Variational Analysis
Author: GHER, University of Liège
License: GPL-3.0-or-later
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# Ocean-DIVA

[![CI](https://github.com/gher-uliege/DIVA/actions/workflows/ci.yml/badge.svg)](https://github.com/gher-uliege/DIVA/actions/workflows/ci.yml)
[![DOI](https://zenodo.org/badge/80114691.svg)](https://zenodo.org/badge/latestdoi/80114691)

[Open the interactive HTML guide](README.html) for an explorable land-mask
example.

Ocean-DIVA performs Data-Interpolating Variational Analysis on scattered spatial
observations. It produces a gridded analysis and relative posterior error while
respecting coastlines, islands, and disconnected basins.

This implementation has a NumPy-first Python API and a focused Rust engine for
coastline-aware shortest paths. Published wheels require no Fortran compiler,
Julia installation, or system NetCDF library.

## Installation

```bash
python -m pip install ocean-diva
```

Optional integrations are available as extras:

```bash
python -m pip install "ocean-diva[accessors]"  # pandas and xarray
python -m pip install "ocean-diva[plot]"       # example plots
```

The distribution is named `ocean-diva`; the Python package remains `diva`.

## Python API

A grid is inferred from the finite observation extent when one is not supplied.
The inferred grid preserves the aspect ratio, adds a 5% buffer, and uses about
50 cells along its longest axis.

```python
from diva import analyze

result = analyze(
    x=[0.3, 0.55, 0.85],
    y=[0.3, 0.9, 0.1],
    values=[1.0, -1.0, 0.2],
    correlation_length=0.2,
    signal_to_noise=1.0,
)

result.save("results.npz")
```

Use `grid_resolution` and `grid_buffer` to customize an inferred grid:

```python
result = analyze(
    x,
    y,
    values,
    correlation_length=0.2,
    grid_resolution=100,
    grid_buffer=(0.5, 0.25),
)
```

Pass an explicit `Grid` when exact coordinates are required:

```python
import numpy as np
from diva import Grid, analyze

grid = Grid(np.linspace(0, 1, 101), np.linspace(0, 1, 101))
result = analyze(x, y, values, grid, correlation_length=0.2)
```

## Pandas and xarray

Importing `diva` registers a `.diva` accessor when pandas or xarray is
installed.

```python
# Returns a tidy DataFrame indexed by (latitude, longitude).
result_df = observations.diva.analyze(
    x="longitude",
    y="latitude",
    values="temperature",
    correlation_length=0.2,
)

# Returns a Dataset containing analysis, error, and water.
result_ds = temperature.diva.analyze(
    x="longitude",
    y="latitude",
    correlation_length=0.2,
)
```

Both accessors accept the same solver and automatic-grid options as
`diva.analyze`. The xarray accessor also accepts a coordinate-aware
`land_mask`, using 1 for land and 0 for ocean.

For example, an xarray analysis can include an island that observations on
opposite sides must be interpolated around:

```python
import numpy as np
import xarray as xr

temperature = xr.DataArray(
    [12.0, 10.0, 20.0, 18.0],
    dims="observation",
    coords={
        "longitude": ("observation", [0.2, 0.3, 0.7, 0.8]),
        "latitude": ("observation", [0.25, 0.75, 0.75, 0.25]),
    },
    name="temperature",
    attrs={"units": "degree_Celsius"},
)

longitude = np.linspace(0, 1, 51)
latitude = np.linspace(0, 1, 51)
land = xr.DataArray(
    (
        (latitude[:, None] >= 0.20)
        & (latitude[:, None] <= 0.80)
        & (longitude[None, :] >= 0.42)
        & (longitude[None, :] <= 0.58)
    ).astype(np.uint8),
    dims=("latitude", "longitude"),
    coords={"longitude": longitude, "latitude": latitude},
    name="land",
)

result = temperature.diva.analyze(
    x="longitude",
    y="latitude",
    correlation_length=0.2,
    land_mask=land,
)

# `water` is false on the island; mask land before plotting or exporting.
water_temperature = result["analysis"].where(result["water"])
```

The mask coordinates define the output grid when no `Grid` is supplied. They
must match an explicit grid when one is supplied. A land mask also enables
shortest-water-path distances, so covariance does not pass straight through
the island.

## Command line

The CLI reads portable DIVA observation, contour, and parameter files:

```bash
diva analyze input/data.dat \
  --contours input/coast.cont \
  --params input/param.par \
  --output results.npz
```

## Capabilities

- whitespace- or comma-delimited `x y value [weight]` observations;
- ODV spreadsheet layer extraction;
- legacy `coast.cont` and `param.par` readers;
- zero, mean, and planar background fields;
- relative posterior error estimates;
- even-odd coastline masks with islands and holes;
- shortest-water-path covariance around land barriers;
- compressed NumPy and long-form CSV output.

The solver uses a normalized Matérn field rather than being a line-for-line
port of the historical finite-element implementation. Advanced historical
workflows such as 3-D/4-D climatology, advection constraints, generalized
cross-validation, and NetCDF output are outside its current scope.

## Examples

```bash
python examples/python_basic.py
python examples/black_sea_surface.py
python benchmarks/benchmark_core.py
```

The Black Sea example uses the bundled ODV sample in `data/` and writes its
`.npz` and `.png` outputs beside the script.

## Development

The package is built with [maturin](https://www.maturin.rs/) and PyO3:

```bash
python -m pip install ".[accessors,plot]"
python -m unittest discover -s tests -v
```

Running from an unbuilt source checkout falls back to the equivalent Python
shortest-path implementation.

## References

- Troupin, C. et al. (2012), “Generation of analysis and consistent error
  fields using Data Interpolating Variational Analysis (Diva),”
  *Ocean Modelling*, 52–53, 90–101.
  [doi:10.1016/j.ocemod.2012.05.002](https://doi.org/10.1016/j.ocemod.2012.05.002)
- Barth, A. et al. (2014), “divand-1.0: n-dimensional variational data
  analysis for ocean observations,” *Geoscientific Model Development*, 7,
  225–241.
  [doi:10.5194/gmd-7-225-2014](https://doi.org/10.5194/gmd-7-225-2014)
- [DIVAnd.jl](https://github.com/gher-uliege/DIVAnd.jl), the actively
  maintained N-dimensional generalization of DIVA.

## License

GPL-3.0-or-later. See [LICENSE](LICENSE).

