# SeaCommons - Drift Methodology

## Overview

SeaCommons computes Lagrangian particle trajectories with OpenDrift's Leeway model for SAR drift estimation and a separate closed-form fallback for degraded environments. A standard maritime drift run seeds 128 particles from a reported position, advances them forward in time, and summarizes the spread as 6 h, 12 h, and 24 h search cones plus a trajectory line.

---

## Lagrangian Particle Model

| Parameter | Value |
|-----------|-------|
| Library | OpenDrift `opendrift.models.leeway.Leeway` |
| Particle count | 128 |
| Integration time step | 900 s |
| Output interval | 3,600 s |
| Seed radius | 150 m |
| Runtime path | Python subprocess via `core/drift/opendrift_runner.py` |

The current implementation is a forward drift ensemble. It does not yet produce formal IAMSAR search ellipses.

---

## Environmental Forcing

SeaCommons combines two live forcing sources:

- Open-Meteo for wind, fetched without an API key
- CMEMS for ocean currents, temperature, and wave context

### Wind

Wind is fetched from Open-Meteo at the seed point and decomposed into x/y vector components before being passed to OpenDrift. If the live request fails, the system falls back to cached wind values.

### Surface currents

Ocean current data is fetched through the CMEMS point sampler. The configured current dataset is:

`cmems_mod_glo_phy-cur_anfc_0.083deg_P1D-m`

That is finer than the original 0.25 degree planning assumption. Results are cached on disk per 0.1 degree cell with a 2 hour TTL because CMEMS point fetches are relatively expensive.

If the point fetch fails, the runtime falls back to a conservative current vector of:

- `u_ms = 0.10`
- `v_ms = 0.05`

In the separate Gaussian fallback path, the simplified model instead assumes an approximately uniform 0.15 m/s surface current.

---

## Leeway / Scarroccio

Wind-driven leeway is modeled as 3.5% of the surface wind speed and is added vectorially to the surface current.

```text
drift_vector = leeway_vector(wind) + current_vector
leeway_factor = 0.035
```

This same 3.5% factor is also used in the simplified fallback and in weather-derived SAR summaries.

---

## Object Type Mapping

SeaCommons now maps `vessel_type` to OpenDrift's Leeway `object_type` instead of forcing every case to PIW.

| vessel_type | OpenDrift code | Description |
|-------------|----------------|-------------|
| `person_in_water` | 26 | Person in water |
| `rubber_boat` | 38 | Inflatable boat without canopy |
| `life_raft` with 1-4 persons | 27 | Small canopied life raft |
| `life_raft` with 5-9 persons | 29 | Larger canopied life raft |
| `fishing_vessel` | 52 | Fishing vessel profile |
| `wooden_boat` | 46 | Open wooden boat |
| `sailboat` | 26 | Conservative fallback; no dedicated sail category used |
| unknown / default | 26 | Person in water default |

This mapping is resolved in `core/drift/models.py` and injected by `core/drift/engine.py` before the OpenDrift subprocess is launched. Alert ingestion now forwards both `vessel_type` and `persons` to the drift request.

---

## Search Cones

SeaCommons exposes three search cones:

- 6 hours
- 12 hours
- 24 hours

For OpenDrift output, the search area is derived from the particle cloud and summarized as a convex-hull style boundary. For the Gaussian fallback, the cone is generated as a fan sector with widening half-angles over time.

This is an operational visualization aid, not a formal IAMSAR ellipse product. It should be reviewed by a qualified SAR operator before tactical use.

---

## Stokes Drift

Explicit Stokes drift is currently disabled.

Rationale:

- it would increase model complexity and forcing dependencies
- the current CMEMS-driven path already captures part of the effective surface transport context indirectly
- the present platform goal is reproducible operational support, not a full wave-coupled ocean forecast stack

---

## Survival Probability

SeaCommons includes a separate survival probability model under `core/probability/survival.py`.

It uses:

1. Golden 1976 survival-time lookup by water temperature
2. Tikuisis 1997 inspired cooling-rate penalty from wind exposure
3. Additional penalties for wave exposure, vessel condition, medical emergency, and children aboard

The final decay model is exponential:

```text
P(t) = exp(-t / T)
```

where `T` is the effective survival window after environmental and vulnerability penalties.

---

## Forensic Mode

When an alert-driven drift is processed through `/api/v1/alert`, SeaCommons can persist the event as a signed forensic packet.

Current implementation:

- Ed25519 signature via PyNaCl
- BLAKE3 hash of the signed payload
- persistent storage through the forensic packet store
- verification endpoint at `/api/v1/forensic/{event_id}/verify`

This is intended for evidence preservation, replayability, and chain-of-custody support in incident review and legal documentation workflows.

---

## Gaussian Fallback

If OpenDrift is unavailable, or when the environment is explicitly running in mock mode for non-SAR development flows, SeaCommons can produce a deterministic fallback drift geometry.

The fallback uses:

- Open-Meteo wind when available
- 3.5% wind leeway
- 0.15 m/s scalar current assumption
- widening angular sectors at 6 h, 12 h, and 24 h

This mode is useful for demonstrations and degraded deployments, but it is not the preferred operational SAR path.
