Skip to content

Diffcocip

diffcocip

Optional, forward-only diffcocip execution with checked weather coverage.

The adapter targets diffcocip's v1 formation/evolution API. Retrieval runs on host Python, outside JAX transformations. No global engine hooks are installed.

EvolutionResult dataclass

Forward result; age_limit_reached is conservative, never extinction.

Diagnostics contain only executed step ends; trailing extinct steps from the dense scan are omitted. energy_forcing_j sums the same hard EF.

Source code in packages/barograph-met/src/baro/met/diffcocip.py
@dataclass(frozen=True)
class EvolutionResult:
    """Forward result; ``age_limit_reached`` is conservative, never extinction.

    Diagnostics contain only executed step ends; trailing extinct steps from
    the dense scan are omitted. ``energy_forcing_j`` sums the same hard EF.
    """

    energy_forcing_j: float
    stop_reason: str
    formation: Mapping[str, Any]
    final_state: Mapping[str, Any]
    diagnostics: Mapping[str, Any]
    times: npt.NDArray[np.datetime64]
    weather_requests: int

WeatherDemand dataclass

Exact probe coordinates to cover, including interpolation neighbours.

points columns are longitude degrees, latitude degrees, pressure hPa, and seconds since 2000-01-01. Radiation ignores the pressure column. A provider returns complete diffcocip met/radiation dictionaries covering all probes in this request. Radiation values must be W/m² at midpoints. Spatial/time bounds are requests, never permission to extrapolate.

Source code in packages/barograph-met/src/baro/met/diffcocip.py
@dataclass(frozen=True)
class WeatherDemand:
    """Exact probe coordinates to cover, including interpolation neighbours.

    ``points`` columns are longitude degrees, latitude degrees, pressure hPa,
    and seconds since 2000-01-01. Radiation ignores the pressure column.
    A provider returns complete diffcocip met/radiation dictionaries covering
    all probes in this request. Radiation values must be W/m² at midpoints.
    Spatial/time bounds are requests, never permission to extrapolate.
    """

    points: Array

    @property
    def bounds(self) -> dict[str, tuple[float, float]]:
        """Minimum/maximum requested coordinates, in diffcocip units."""
        return {
            axis: (float(self.points[:, i].min()), float(self.points[:, i].max()))
            for i, axis in enumerate(_AXES)
        }
bounds property

Minimum/maximum requested coordinates, in diffcocip units.

run_diffcocip(flight, provider, params, *, max_age_s)

Evolve one flight with demand-driven weather, stopping at extinction/cap.

provider supplies native-grid dicts in diffcocip's documented units. It may use Barograph caches and return larger coverage than requested. Requests include lower meteorological probes and wake downwash. Trial steps outside coverage are discarded and replayed with complete weather. The input flight follows diffcocip's dict contract (altitude in metres). This host driver does not support autodifferentiation or smoothing. Provider responses must describe one consistent meteorological dataset: extending a window must not change values at previously covered nodes. Longitudes use [-180, 180]; seam crossings can request a wide domain. max_age_s is mandatory and overrides the corresponding params value.

Source code in packages/barograph-met/src/baro/met/diffcocip.py
def run_diffcocip(
    flight: dict[str, Any],
    provider: Callable[[WeatherDemand], Weather],
    params: Mapping[str, Any],
    *,
    max_age_s: float,
) -> EvolutionResult:
    """Evolve one flight with demand-driven weather, stopping at extinction/cap.

    ``provider`` supplies native-grid dicts in diffcocip's documented units.
    It may use Barograph caches and return larger coverage than requested.
    Requests include lower meteorological probes and wake downwash. Trial
    steps outside coverage are discarded and replayed with complete weather.
    The input flight follows diffcocip's dict contract (altitude in metres).
    This host driver does not support autodifferentiation or smoothing.
    Provider responses must describe one consistent meteorological dataset:
    extending a window must not change values at previously covered nodes.
    Longitudes use [-180, 180]; seam crossings can request a wide domain.
    ``max_age_s`` is mandatory and overrides the corresponding params value.
    """
    options = _validate(flight, params, max_age_s)
    weather = _Coverage(provider)
    formed, state, times = _initialize(flight, options, weather)
    state, records, executed, cap, previous = _evolve(state, times, options, weather)
    cap = cap or _limit_reached(state, previous)
    diagnostics = (
        {key: np.stack([record[key] for record in records]) for key in records[0]}
        if records
        else {}
    )
    return EvolutionResult(
        float(np.sum(diagnostics.get("ef", 0))),
        "age_limit_reached" if cap else "extinct",
        formed,
        state,
        diagnostics,
        np.asarray(executed, dtype="datetime64[ns]"),
        weather.requests,
    )