"""Single source of truth for per-tab help copy. Read by both ``tabs/guide.py`` (full writeup) and each tab builder (one-line tagline under the tab title). """ from __future__ import annotations TAB_HELP: dict[str, dict] = { "guide": { "title": "Guide", "tagline": "Start here — what each tab does and how they fit together.", "purpose": ( "Single-page reference covering every tab's purpose, inputs, " "outputs, when to use it, and how data flows between tabs." ), "inputs": [], "outputs": [ ("Workflow diagram", "Shows the Simulation → Sweep → Process Sim pipeline."), ("Per-tab sections", "One section per tab with full docs."), ], "when_to_use": "When you're new to the dashboard, or trying to decide which sweep-like tab to reach for.", "related": [], "gotchas": [], }, "simulation": { "title": "Simulation", "tagline": "Single-cycle baseline — run one fill, inspect P-T traces, export params.", "purpose": ( "Run a single cryogenic pump cycle with the full parameter surface " "(ICV, DCV, pump geometry, process losses). Produces pressure-time " "traces, valve motion, mass flow and diagnostics. Writes the current " "widget state into the shared sim_params_state so the Sweep tab can " "use it as a baseline." ), "inputs": [ ("Engine", "Lightspeed (fast JIT) / General ODE (scipy) / Euler."), ("Fluid", "H2 or N2."), ("Operating conditions", "Pexit, speed, Ptank, Psat."), ("ICV / DCV / geometry / process accordions", "Full raw parameter edit."), ], "outputs": [ ("Metrics panel", "mdot, mass_eff, Tc_peak, pc_peak, kWh_extend."), ("Plots", "P-T curves, valve motion, mdot profile, optional extras."), ("Diagnostics", "Threshold-based warnings/criticals."), ("sim_params_state", "Shared state consumed by Sweep tab."), ], "when_to_use": "Before running any sweep — establish a known-good baseline here first.", "related": ["sweep", "advanced_raw_sweep", "process_sim"], "gotchas": [ "Lightspeed JIT warms up async on startup; first call may fall back to Euler.", "N2 on Lightspeed is not supported — auto-falls back to general ODE.", ], }, "sweep": { "title": "Sweep", "tagline": "Curated 1D/2D parameter study — caches results, feeds Process Sim.", "purpose": ( "Sweep one or two of 17 curated sensitivity-ranked parameters on top " "of the Simulation-tab baseline. Results are cached in SQLite " "(keyed on full baseline + preset + engine). A 2D Pexit_barg × speed_f " "sweep produces a payload consumable by the Process Sim tab." ), "inputs": [ ("sim_params_state", "Baseline, read from the Simulation tab."), ("Mode", "1D or 2D."), ("Hardware preset", "Baseline / Old ICV / New ICV (applied on top of baseline)."), ("Swept parameter(s) + range", "Min/max sliders (1D and 2D)."), ], "outputs": [ ("Heatmap / line plot", "mdot vs swept param(s)."), ("Cache-status badge", "Shows fresh / cached / partial."), ("Send to Process Sim", "Enabled only after a 2D Pexit × speed run."), ], "when_to_use": "Parameter studies on realistic hardware settings. First stop for most sensitivity questions.", "related": ["simulation", "advanced_raw_sweep", "process_sim", "comparison"], "gotchas": [ "Locked to Lightspeed engine — use General ODE via Compare Engines tab if you need a cross-check.", "Preset keys that overlap with your swept parameter are disabled automatically (warning banner shown).", "Send-to-Process-Sim requires a 2D Pexit_barg × speed_f sweep specifically.", ], }, "advanced_raw_sweep": { "title": "Advanced / Raw Sweep", "tagline": "Power-user sweep with all 38 raw params exposed — no sim-state link, no cache.", "purpose": ( "Expose every ICV/DCV/geometry/process parameter as an editable widget " "so you can sweep less-common parameters without first changing the " "Simulation baseline. Standalone — does not consume sim_params_state, " "does not feed Process Sim, does not cache." ), "inputs": [ ("Operating conditions", "Pexit, speed, Ptank, Psat."), ("All 38 raw parameters", "In ICV/DCV/geom/proc accordions."), ("Sweep mode + param + range", "1D or 2D."), ], "outputs": [ ("Heatmap / line plot", "mdot vs swept param(s)."), ], "when_to_use": "When you need to sweep something not in the curated 17 params of the Sweep tab.", "related": ["sweep", "simulation"], "gotchas": [ "No caching — every run recomputes from scratch.", "Changes made here do NOT propagate to the Simulation or Sweep tabs.", "Dropdown auto-updates min/max sliders when you pick a new parameter.", ], }, "process_sim": { "title": "Process Sim", "tagline": "Downstream piping transient given a pump LUT — from CSV, generator, or Sweep.", "purpose": ( "Simulate the downstream transient (pump → snubber → valve → pipe → " "atm or tank) given a pump performance LUT. Three LUT sources: CSV " "upload, on-the-fly cycle2mdot generation, or a 2D sweep payload " "shipped from the Sweep tab." ), "inputs": [ ("Pump LUT", "CSV upload / Generate / From Sweep (one of three modes)."), ("Pipe & valve params", "Snubber volume, pipe D/L, valve Cv, discharge mode."), ("Optional profile CSV", "Motor %/time profile to replay."), ("Optional actual-data CSV", "For overlay comparison."), ], "outputs": [ ("Transient plot", "P, T, mdot, valve position over time."), ("Summary metrics", "Fill duration, max ΔP, etc."), ("Comparison with actual data (if provided)", ""), ], "when_to_use": "After characterising pump performance (via Sweep or CSV) — study downstream transient behaviour.", "related": ["sweep", "simulation"], "gotchas": [ "LUT from Sweep requires a 2D Pexit_barg × speed_f sweep; other axes will error.", "CSV upload now accepts pressure_units='bar' or 'barg'; default is 'bar' (absolute).", "Switching LUT mode does NOT clear prior state — if you ingested from Sweep then upload a CSV later, check lut_mode.", ], }, "comparison": { "title": "Compare Engines", "tagline": "Side-by-side Lightspeed vs General-ODE sweep; overlay plot + deviation metrics.", "purpose": ( "Run the same 1D parameter sweep on both the Lightspeed and General-ODE " "engines and display overlaid curves, delta table, and percent " "agreement. Useful for validating Lightspeed against the higher-order " "solver." ), "inputs": [ ("Hardware preset", "old_icv or new_icv."), ("Sweep param + range", "Single-parameter 1D sweep."), ("N points", "Capped on HuggingFace Space."), ("Pexit, speed", "Fixed operating point."), ], "outputs": [ ("Overlay plot", "Lightspeed and General-ODE curves."), ("Agreement metrics", "% agreement, max |Δ|."), ("Delta table", "Per-point values."), ], "when_to_use": "To validate Lightspeed results against scipy ODE before trusting a sweep.", "related": ["sweep", "simulation"], "gotchas": [ "General-ODE is slow — a 15-point sweep can take minutes.", "On HuggingFace Spaces, N is silently capped (warning shown pre-run).", ], }, "real_cycles": { "title": "Real Cycles", "tagline": "Query TimescaleDB for recorded pump cycles; overlay PT/TT/VFD/FT sensors.", "purpose": ( "Pull real recorded pump cycles from the CSH2 TimescaleDB and display " "the sensor overlay (discharge pressure, discharge temp, VFD speed, " "mass flow). Standalone — no engine sim involved." ), "inputs": [ ("Pressure / duration filters", "Narrow the cycle list."), ("Cycle selection", "Pick a cycle id."), ], "outputs": [ ("Cycle list dataframe", "All matching cycles."), ("Sensor overlay plot", "PT130 / TT130 / VFD / FT140 on one axis."), ("Sensor summary", "Min/max/mean per sensor."), ], "when_to_use": "When you want to inspect actual recorded data, e.g., to compare against a simulation.", "related": ["simulation", "process_sim"], "gotchas": [ "Requires psycopg2 (pip install psycopg2-binary) and DB credentials.", "Tag IDs are hardcoded from a specific DB schema snapshot; may drift.", ], }, "design_agent": { "title": "Design Agent [WIP]", "tagline": "Managed-agent chat — start/send/interrupt design sessions and browse records.", "purpose": ( "Chat UI for the managed-agent design session. Starts a session, sends " "messages, streams tool events (with caveats — see gotchas), ends the " "session, and browses past records." ), "inputs": [ ("GITHUB_TOKEN env var", "Required for agent config."), ("Chat messages", "User prompts."), ], "outputs": [ ("Chat history", "Assistant replies."), ("Tool log display", "Buffered tool events (not streamed live today)."), ("Past-session browser", "List and open prior records."), ], "when_to_use": "For exploratory design conversations backed by the managed-agent orchestrator.", "related": [], "gotchas": [ "Labelled WIP — known issues: synchronous send_message blocks the UI; tool log does not stream live.", "Requires GITHUB_TOKEN env var.", ], }, } def tagline_html(tab_key: str) -> str: """Small dim monospace tagline rendered under a tab's title.""" entry = TAB_HELP.get(tab_key) if entry is None: return "" return ( f'
' f'{entry["tagline"]}' f'
' )