Metadata-Version: 2.4
Name: drifterOI
Version: 0.1.0
Summary: Python package for drifter data interpolation.
Author-email: William Edge <william.edge@uwa.edu.au>
License-Expression: BSD-3-Clause
Project-URL: Homepage, https://github.com/williamedge/drifterOI-public
Project-URL: Bug Tracker, https://github.com/williamedge/drifterOI-public/issues
Project-URL: Changelog, https://github.com/williamedge/drifterOI-public/releases
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: scipy
Requires-Dist: xarray
Requires-Dist: h5netcdf
Requires-Dist: h5py
Requires-Dist: matplotlib
Requires-Dist: cmocean
Requires-Dist: emcee
Requires-Dist: arviz
Requires-Dist: gpvecchia
Requires-Dist: xrft
Requires-Dist: colorstamps
Requires-Dist: wootils
Requires-Dist: gptide
Requires-Dist: datide
Requires-Dist: scikit-learn
Requires-Dist: dask
Requires-Dist: sparse
Requires-Dist: tqdm
Requires-Dist: cartopy
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Dynamic: license-file

# drifterOI

Python code for 3D (space + time) optimal interpolation of sparse Lagrangian
drifter velocities, using Gauss-Markov / Gaussian Process regression. Splits
observed velocities into:

- a **seasonal** component: a smooth annual harmonic cycle per location,
  fit as a separable spatial-Matern x per-harmonic Gauss-Markov model
  (`drifterOI.seasonal_gp`, solved efficiently via
  [`datide.MultiscaleGP`](https://github.com/TIDE-ITRH/datide)'s
  block-diagonal decomposition rather than a dense joint solve), and
- an **eddy/synoptic** residual: fit as a Vecchia-approximated Gaussian
  Process over the seasonal-corrected residuals
  (via [`gpvecchia`](https://github.com/TIDE-ITRH/gpvecchia)), to scale to
  the full drifter dataset without a dense covariance solve.

This is the companion code for the accompanying manuscript, submitted to
*Ocean Science*: **[preprint link]**. See [Citation](#citation) below.

## Installation

Local development install (no PyPI release yet):

```bash
git clone https://github.com/williamedge/drifterOI.git
cd drifterOI
pip install -e .
```

Requires Python >= 3.10 (set by the `gpvecchia` dependency's floor). Besides
the usual scientific Python stack, this pulls in three sibling packages from
the same research group: [`gpvecchia`](https://github.com/TIDE-ITRH/gpvecchia)
(Vecchia-approximated GPs), [`datide`](https://github.com/TIDE-ITRH/datide)
(Gauss-Markov / data assimilation routines), and
[`gptide`](https://github.com/TIDE-ITRH/gptide) (GP kernels, MLE/MCMC
fitting).

## Quickstart

A minimal example of the separable seasonal Gauss-Markov model on synthetic
data -- the same model `seasonal_gp.init_gm_scales` builds for the real
pipeline, without needing the drifter dataset:

```python
import numpy as np
from datide import MultiscaleGP

import drifterOI.seasonal_gp as sgp
from drifterOI.cov import matern32_covfunc

rng = np.random.default_rng(0)
n_obs = 200
X = np.column_stack([
    rng.uniform(-100, 100, n_obs),   # easting (km)
    rng.uniform(-100, 100, n_obs),   # northing (km)
    np.sort(rng.uniform(0, 200, n_obs)),  # time (days)
])
Y = rng.normal(size=n_obs)  # observed velocity component

# [sigma, lx, ly, lt]: spatial Matern prior for the seasonal coefficients
B_params = [1.0, 50.0, 50.0, 5.0]
R = np.eye(n_obs) * 0.05  # observation noise covariance

H_list, scales, design = sgp.init_gm_scales(X, matern32_covfunc, B_params, mean=True)
model = MultiscaleGP(H_list, scales, R)

param_stack = model.conditional_mean(Y)          # (n_params, n_obs) harmonic coefficients
seasonal_fit = sgp.apply_harmonic_design(design, param_stack)
eddy_residual = Y - seasonal_fit
```

## Pipeline

The `scripts/` directory holds the full analysis pipeline behind the
manuscript, in stages (each stage reads the previous stage's saved output):

| Stage | Purpose |
|---|---|
| `L0_processing/` | Raw drifter/bathymetry inspection and pre-processing notebooks |
| `L1_inference/` | Fit the seasonal + eddy Gauss-Markov/Vecchia-GP model to drifter observations (MLE + MCMC) |
| `L2_predict_seasonal/` | Predict the seasonal field on a spatial grid or at a fixed point, from the L1 fit |
| `L3_predict_eddy/` | Predict the eddy/synoptic field and derive stream function / velocity potential |
| `L4_plot_results/` | Manuscript figures and comparisons against reference (e.g. BLUElink) products |

Example data (`data/`) is included in the repository so the `L1`-`L2`
scripts can be run directly (`BODY_drifters_6_hours.nc` drifter
observations, `SUNTANS_bathy_unstructured.nc` bathymetry for plotting).
`data/`, `scripts/`, and `tests/` aren't part of the installable package
(`pip install drifterOI` won't fetch them) -- **clone the repo** if you want
the example data or to run the pipeline scripts yourself.

## Citation

If you use this code, please cite it as described in
[`CITATION.cff`](CITATION.cff). Once published, the accompanying *Ocean
Science* manuscript will be the preferred citation -- see
**[preprint link]** in the meantime.

## License

BSD-3-Clause -- see [`LICENSE`](LICENSE).
