Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions scripts/make_test_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python
"""Generate trimmed L1 CSV test fixtures from raw Slocum NetCDF files.

Usage:
uv run python scripts/make_test_fixtures.py <dbd_nc> <ebd_nc>

Outputs:
tests/data/sl685.dbd.csv — m_* source variables from core.yml
tests/data/sl685.ebd.csv — sci_* source variables + sci_generic_{a-l}

The time window is fixed to 2026-03-27 00:33–06:45 UTC.
"""

import argparse
import os
from datetime import datetime, timezone
from pathlib import Path

import netCDF4 as nc
import numpy as np
import pandas as pd
import yaml

REPO_ROOT = Path(__file__).parent.parent
CORE_YML = REPO_ROOT / "src/glide/assets/core.yml"
OUT_DIR = REPO_ROOT / "tests/data"

T0 = datetime(2026, 3, 27, 0, 33, tzinfo=timezone.utc).timestamp()
T1 = datetime(2026, 3, 27, 6, 45, tzinfo=timezone.utc).timestamp()

GENERIC_KEEP = {f"sci_generic_{c}" for c in "abcdefghijkl"}


def collect_sources(d: dict) -> set[str]:
sources: set[str] = set()
if not isinstance(d, dict):
return sources
if "source" in d:
s = d["source"]
sources.update(s if isinstance(s, list) else [s])
for v in d.values():
sources |= collect_sources(v)
return sources


def extract(nc_path: str, time_var: str, out_path: Path, keep: set[str]) -> None:
ds = nc.Dataset(nc_path)
t = np.array(ds.variables[time_var][:])
mask = ~np.isnan(t) & (t >= T0) & (t <= T1)
avail = {v for v in ds.variables if ds.variables[v].dimensions == ("i",)}
cols = sorted(avail & keep)
data = {v: np.array(ds.variables[v][:])[mask] for v in cols}
ds.close()

df = pd.DataFrame(data)

# Use 12 significant figures
df.to_csv(out_path, index=False, float_format="%.12g")
sz = os.path.getsize(out_path) / 1024
print(f" {out_path.name}: {len(df)} rows × {len(df.columns)} cols ({sz:.0f} KB)")


def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument("dbd_nc", help="Path to the DBD (flight) NetCDF file")
parser.add_argument("ebd_nc", help="Path to the EBD (science) NetCDF file")
args = parser.parse_args()

sources = collect_sources(yaml.safe_load(CORE_YML.read_text()))
OUT_DIR.mkdir(parents=True, exist_ok=True)

print("Extracting test fixtures...")
extract(args.dbd_nc, "m_present_time", OUT_DIR / "sl685.dbd.csv", sources)
extract(
args.ebd_nc,
"sci_m_present_time",
OUT_DIR / "sl685.ebd.csv",
sources | GENERIC_KEEP,
)


if __name__ == "__main__":
main()
38 changes: 38 additions & 0 deletions src/glide/assets/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,41 @@ merged_variables:
valid_max: 0.001
instrument: instrument_microrider
observation_type: calculated


# =============================================================================
# FLIGHT MODEL
# =============================================================================
# Optional steady-state glider flight model parameters. This section is only
# used by the `glide flight` command and is ignored by all other commands.
#
# Parameters marked (*) are commonly calibrated per deployment. All others
# default to the values shown here if omitted.
#
# calibrate: list the parameter names to fit against the observed depth rate.
# Any subset of: Vg, mg, Cd0, ah, aw, Cd1
# Default: [Vg, mg, Cd0, ah]
#
# bounds: restrict which observations are used during calibration.
# min_pressure / max_pressure — pressure range in dbar
# time_start / time_end — ISO 8601 datetime strings or null (no bound)
#
# All model parameters (calibrated and fixed) are stored as global NetCDF
# attributes prefixed with `flight_model_` in the output file.

# flight:
# rho0: 1025.0 # reference density (kg m-3)
# mg: 70.0 # (*) glider mass (kg)
# Vg: 0.070 # (*) glider volume (m3)
# Cd0: 0.15 # (*) parasitic drag coefficient
# ah: 3.8 # (*) hull lift slope (rad-1)
# calibrate:
# - Vg
# - mg
# - Cd0
# - ah
# bounds:
# min_pressure: 20.0
# max_pressure: 200.0
# time_start: null
# time_end: null
Loading
Loading