All method pages

MethodFeatures

partial some parts checked against the code, others not yet · what the statuses mean

Feasibility suite

In simple terms

Feasibility answers a harder question than prefeasibility: how does this plant actually run, hour by hour, across a whole year? It replays the plant under the real operating constraints prefeasibility ignores (minimum load, ramps, storage dynamics, electrolyser standby) — in one of two dispatch modes (below). The results are explored across several linked sub-rooms.

Two dispatch modes (same year, two ways to run it)

The two modes, why their results bracket how a plant really runs, and the electrolyser’s part-load curve and modules (both modes) are explained once, in How feasibility works — the page the stage’s How it works tab shows. What each choice under How it runs does (engine, battery, H₂ buffer, promised output, horizon): How it runs — the feasibility run settings.

In the code: the rule-based engine is core/feasibility_sim.py, the solver (LP) core/feasibility.py; the choice is saved as feas_mode. The battery strategy (storage_strategy, one of reactive · proactive · stable · accumulate) shapes the rule-based engine only — the LP never reads it. The electrolyser’s module count is ely_module_count; the solver models a curved part-load profile as parallel segments (still a pure LP, no integers).

Why it exists

Prefeasibility screens; feasibility de-risks. Lenders read these numbers, so the stage models real dispatch — coded rules that decide each hour without seeing ahead (the base case, the number you defend), or an optimiser with perfect foresight (the ideal ceiling) — and reports where the plant falls short (unserved minimum-load hours). It is the reference the prefeasibility screen is checked against.

Where it lives

  • Frontend: the cockpit frontend/src/shell/FeasibilityShell.tsx hosts the rooms in frontend/src/rooms/feasibility/ as the tabs listed below.
  • Engines: backend/core/feasibility_sim.py (rule-based) and backend/core/feasibility.py (PyPSA network + HiGHS); persistence: backend/core/dispatch_store.py; orchestration: PtxApi.solve_feasibility / start_feasibility_solve.

The tabs

The feasibility stage is one cockpit; these are its tabs and Design lab views, generated from frontend/src/shell/shellNav.ts and shell/FeasibilityShell.tsx:

Feasibility — /projects/:id/feasibility/<tab>, opens on overview.

Group Tab Address What it answers
Site Resources feasibility/resources What the site’s wind and sun give you, before any design.
Design Design lab feasibility/lab Vary the design: find a configuration, or size it at least cost.
Check the design Overview feasibility/overview The verdict and the cost of each product.
Check the design Operations feasibility/operations How the plant runs, hour by hour.
Check the design Reliability feasibility/reliability Delivered against promised; where it falls short, by cause, and what cures it.
Check the design Storage feasibility/storage The battery and hydrogen store: state of charge and value.
Check the design Grid feasibility/grid Grid draw, its cost, and the RFNBO screen.
Reference How it works feasibility/method How the feasibility engines work, and what this run consumed.
Tools Assumptions feasibility/assumptions This stage’s assumption book: every value, its source and its range.
Tools Snapshots feasibility/snapshots Save this stage’s design and results, and restore one.
Tools Derivatives feasibility/derivatives The value chain this stage solves: the products and the units each needs.
Tools Emissions feasibility/emissions Carbon intensity per product against the RFNBO limit — a screen, not a certificate.
Tools Scenarios (partial) feasibility/scenarios Compare two to four snapshots, designs or versions side by side. Partial here: Two snapshots compare inside Snapshots today; two to four side by side, and the four engines on one design, come with this tool.
Tools Settings (partial) feasibility/settings This project’s name, location, units and bundle. Partial here: Rename, duplicate, export and delete are in the project’s ⋯ menu in the sidebar; this page — place, units, the default book — is not built yet.

Design lab views — feasibility/lab?mode=<view>; the first view opens when no mode is given (old modes kept as aliases: explore → one, storage → one).

View mode= What it does
One component one Move one size — or two together — across a range; cost, output and reliability at each.
Try every combination every A range and a step per component; every combination solved; the cheapest all-green design.
Scale the plant scale Grow or shrink everything but storage together; cost and output per product.
Find a design search Sample whole designs on the rule-based engine and explain the best one.
Least cost (LP) optimizer The solver sizes the free components at least annual cost to make what you ask of each product.

The classic room addresses are redirects since the cockpit became the only layout; the query string is kept.

Old address Opens
/projects/:id/prefeasibility /projects/:id/prefeasibility/cockpit
/projects/:id/methods /projects/:id/prefeasibility/method
/projects/:id/feasibility /projects/:id/feasibility/operations
/projects/:id/resources /projects/:id/feasibility/resources
/projects/:id/feasibility-results /projects/:id/feasibility/overview
/projects/:id/feasibility-inputs /projects/:id/feasibility/method?view=inputs
/projects/:id/feasibility-methods /projects/:id/feasibility/method
/projects/:id/reliability /projects/:id/feasibility/reliability
/projects/:id/storage-lab /projects/:id/feasibility/storage
/projects/:id/grid /projects/:id/feasibility/grid
/projects/:id/finder /projects/:id/feasibility/lab?mode=search
/projects/:id/optimizer /projects/:id/feasibility/lab?mode=optimizer
/projects/:id/assumptions the Assumptions tab of the stage you were last in
/projects/:id/snapshots the Snapshots tab of the stage you were last in
/projects/:id/derivatives the Derivatives tab of the stage you were last in
/projects/:id/emissions the Emissions tab of the stage you were last in
/projects/:id/scenarios the Scenarios tab of the stage you were last in
/projects/:id/settings the Settings tab of the stage you were last in

“One place to edit, everywhere to read”: editing happens in the cockpit / Assumptions / version bars; the feasibility rooms read and explain.

How feasibility economics are computed (the Results room)

The dispatch engine returns physics only. The Results room shows economics by taking the design annualized cost (the same CAPEX + OPEX as the plant you sized — identical to the prefeasibility financials) and re-dividing it by the LP’s realized production. So the feasibility LCO is higher than prefeasibility’s by exactly the production shortfall (curtailment + operating limits) — the bankable number. It preserves the prefeasibility shape (multi per-product per_derivative, or NH₃ single-chain indicators), so the same cockpit charts render it. (core/run.py::feasibility_financials.)

How it works, step by step

  1. Start the solve. Solve at the foot of the design panel — it first writes the changes the panel holds (“Solve · 3 changes”) — kicks off an async job; the panel polls until done. Full detail: the feasibility solve flow.
  2. SOLVE once. The engine builds a PyPSA network (renewables on CF curves, grid as a capped third supply, BESS, electrolyser Link, H₂ buffer Store, per-derivative always-on-≥-min-load Links with ramps, penalty slacks) and solves it with HiGHS. The hourly frame + duals + metadata are persisted once.
  3. POST-PROCESS on read. Every chart across the suite is derived from that one frame — dispatch envelopes, duration curve, calendar heatmap, reliability episodes, monthly buckets, curtailment-by-cause, storage-value duals.

When the server is busy: “Queued · 2 ahead”

The server runs only a few heavy jobs at once — two, unless whoever started it set PTX_SOLVE_WORKERS (Environment variables). A job is a feasibility solve on the solver (LP) or over several plant years, a sweep of one size in the Design lab, Find a design, “Try every combination”, the cost landscape, the check of which assumptions move the cost — and Least cost, or Scale the plant and Grid on against off when the project runs the solver (LP). When every place is taken, a new job waits its turn: the design panel, the Operations and Emissions tabs and the tool that started it read Queued · 2 ahead — two jobs run or wait before it, from any workspace, never whose — then Solving… once it starts; pressing Solve also raises a short notice saying so. Nothing is lost while it waits, and you can leave the page.

Jobs start in the order they were asked, with one rule of fairness: a workspace that already has a job running does not get a second place while another workspace’s job waits. So with two places or more, the count can grow when the first job of a workspace with nothing running arrives — it takes its turn first; with one place it never does. A waiting job can be stopped like a running one (it then never starts), and pressing Solve again while it waits keeps its place in line. A rule-based solve of one year never waits: it takes about a second and starts at once, beside the places, and is counted in nobody’s line — over several plant years it takes a place like the others. The prefeasibility solve and the rule-based tools that answer at once (the plant-size curve, the live Scale the plant, the grid size sweep) never wait either. In the code: core/solve_queue.py.

Reading the results

  • Delivered against promised (Reliability) — each product’s output against its promise (demand_t_yr, saved there; Find a design and Least cost (LP) start from it), the shortfall split into hours without enough hydrogen and hours without enough power; with no promise, production and utilization only. What the promise is and the three places that use it: How feasibility works, “The promise”. In the code: core/promise.py::promise_check, returned as promise by PtxApi.reliability_data.
  • Unserved min-load hours is the verdict metric: 0 means the design holds; a positive number (shown in amber) means the plant can’t meet a unit’s minimum load in some hours → size more storage / electrolyser, or accept it.
  • Binding constraint per hour tells you why energy was curtailed (energy-limited, electrolyser-cap, buffer-full, synthesis-cap) → each has a specific remedy.
  • Storage-value duals report the marginal tH₂/yr from +1 t buffer or +1 MWh BESS — whether more storage would pay.
  • vs-Prefeasibility shows all three engines side by side (annual · timeseries · feasibility) so you can see where each lands.

Chart by chart, with what to do about each: How to read the Operations tab.

The storage sweep

It now runs in the Design lab’s One component view (the old storage lab mode opens it). What it does and how to read its curve: How feasibility works, “The storage sweep”. In the code: one solve per point on a copy of the project (PtxApi.start_storage_sweep, POST /projects/{project_id}/feasibility/sweep); the best pick is the cheapest storage within tolerance of the lowest unserved achieved; the BESS-energy axis holds the 4-hour (C/4) power convention.

Failure & edge cases

  • Missing hourly inputs for a sized carrier → 422 naming the carrier.
  • Stale result after a sizing change → a staleness banner (the solve stamps the sizing it consumed; the room compares it to the live fingerprint).
  • Solver error → surfaced via the job status, not a hung spinner.
  • Every place on the server taken → the job waits, queued with its place, and starts on its own (above); Stop takes it out of the line.

How to modify this safely

  • New derived view → a post-process read route + api.ts type; don’t widen the solve response with raw hours.
  • Keep the SOLVE/POST-PROCESS line and the “don’t read the store while running” poller rule intact.

From the app’s documentation, docs/02-features/feasibility-suite.md · Hyprisma 1.0.5