Skip to content

Kernel

kernel

Interpolation of a regional cube at aircraft positions.

For each of the 4 horizontal corners around a point, the full-level pressures of that grid column are computed from its own surface pressure (p_k = A_k + B_k * ps), the two levels bracketing the aircraft pressure are found, and the field is interpolated linearly in ln p (default) or p. The 4 column values are then combined bilinearly. Time interpolation between two hourly cubes is done by the caller. Nothing is ever extrapolated: points outside the domain or outside a column get NaN and a flag.

Flag

Bases: IntFlag

Bit flags describing why a value is missing.

Source code in packages/barograph-met/src/baro/met/kernel.py
class Flag(IntFlag):
    """Bit flags describing why a value is missing."""

    OK = 0
    INVALID_INPUT = 1  # non-finite time/position/pressure
    OUTSIDE_DOMAIN = 2  # outside the cube's horizontal grid
    ABOVE_TOP = 4  # above the highest retrieved level
    BELOW_BOTTOM = 8  # below the lowest retrieved level (near/below the surface)
    MISSING_DATA = 16  # NaN in the source data or cube not published
    OUT_OF_COVERAGE = 32  # time outside the period the source covers

SampleOptions dataclass

How to interpolate on the vertical.

vertical: "log" (linear in ln p, default) or "linear" in p. surface_pressure: "actual" (column pressures from the cube's surface pressure) or "standard" (101325 Pa everywhere, i.e. a fixed altitude->level table).

Source code in packages/barograph-met/src/baro/met/kernel.py
@dataclass(frozen=True)
class SampleOptions:
    """How to interpolate on the vertical.

    ``vertical``: ``"log"`` (linear in ln p, default) or ``"linear"`` in p.
    ``surface_pressure``: ``"actual"`` (column pressures from the cube's
    surface pressure) or ``"standard"`` (101325 Pa everywhere, i.e. a fixed
    altitude->level table).
    """

    vertical: VerticalMethod = "log"
    surface_pressure: SurfacePressureMode = "actual"

sample(cube, lat, lon, pressure, options=None)

Interpolate every cube field at the given positions (pressure in Pa).

Source code in packages/barograph-met/src/baro/met/kernel.py
def sample(
    cube: Cube,
    lat: ArrayLike,
    lon: ArrayLike,
    pressure: ArrayLike,
    options: SampleOptions | None = None,
) -> SampleResult:
    """Interpolate every cube field at the given positions (pressure in Pa)."""
    la = np.asarray(lat, dtype=np.float64)
    lo = np.asarray(lon, dtype=np.float64)
    p = np.asarray(pressure, dtype=np.float64)
    n = la.size
    values = {name: np.full(n, np.nan) for name in cube.fields}
    flags = np.zeros(n, dtype=np.uint8)
    if n == 0:
        return values, flags
    if len(cube.vertical) < MIN_LEVELS:
        flags[:] = Flag.ABOVE_TOP | Flag.BELOW_BOTTOM
        return values, flags
    opts = options or SampleOptions()
    for start in range(0, n, _BATCH):
        sl = slice(start, min(start + _BATCH, n))
        v, f = _sample_batch(cube, la[sl], lo[sl], p[sl], opts)
        for name in values:
            values[name][sl] = v[name]
        flags[sl] = f
    return values, flags

track_components(u, v, track_deg)

Along-track (tailwind > 0) and cross-track (from left to right > 0) wind.

Source code in packages/barograph-met/src/baro/met/kernel.py
def track_components(
    u: ArrayLike, v: ArrayLike, track_deg: ArrayLike
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
    """Along-track (tailwind > 0) and cross-track (from left to right > 0) wind."""
    chi = np.deg2rad(np.asarray(track_deg, dtype=np.float64))
    ua = np.asarray(u, dtype=np.float64)
    va = np.asarray(v, dtype=np.float64)
    return ua * np.sin(chi) + va * np.cos(chi), ua * np.cos(chi) - va * np.sin(chi)