MethodFeatures
partial some parts checked against the code, others not yet · what the statuses mean
How prefeasibility works — the screening
What the two modes compute, how the numbers are costed, and how the right-size optimizer finds the cheapest design. Directional screening — verify before FEED.
In a project, this page is the prefeasibility stage’s How it works tab: the tab shows the same text, after the list of the tools in the stage. The next stage explains itself in How feasibility works; what no stage models is in What the model leaves out.
How to read this stage
screening, not bankable
Prefeasibility answers “is this project worth a closer look, and roughly how should it be sized?” in seconds — not to two decimal places. It has two resolutions:
- Mode A · Annual — closed-form averages. It assumes a curtailment floor (an input you set) and knows no hourly limits.
- Mode B · Timeseries — an hour-by-hour simulation on real weather, with no look-ahead.
How the plant really runs, hour by hour, lies between a run with no look-ahead — Mode B here, the rule-based engine in Feasibility — and the Feasibility optimiser, which sees the whole year ahead. The optimiser usually comes out higher, because foresight lets it keep energy and hydrogen for the hours that need them; the annual figure can land above or below both, because it rests on the curtailment floor you assume rather than on the hours.
Everything here is driven by the assumption book and your sizing; nothing is hard-coded. Change a value in Assumptions or a size in the cockpit and the whole chain — production, energy, cost, the right-size target — recomputes.
Mode A — Annual (closed-form)
ceilings → binding constraint
Each component reports the most product it could pass in a year (its ceiling): renewables energy, electrolyser throughput, each synthesis unit. The orchestrator finds the binding (smallest) ceiling — that’s production. Energy, curtailment and the right-size targets follow in closed form. With several products, the product units fill together (see H₂ allocation, below), so they bind together: the result names them as one stage.
- Curtailment is an assumed floor (an input), not simulated.
- Storage is cost-only — it doesn’t move energy in time here.
- No weather data required — fast to iterate.
- The three-limits read-out (renewables / electrolyser / unit ceilings, with the binding one lit) exists only in this mode — the ceilings are what the closed form computes.
Mode B — Timeseries (greedy hourly)
8,760 h · no foresight
Every hour, the plant follows a fixed order on the site’s real wind/solar curve:
- Renewables serve the fixed auxiliaries (BoP) first; the BESS, then the grid backstop, cover what they cannot.
- The synthesis units come next, before the electrolyser: together they take hydrogen up to their nameplate rate — each hour’s hydrogen split between the units in proportion to their capacities — from the buffer first, with the electricity their synthesis needs. Short of power, they run at what it allows: on the buffer while it holds hydrogen, else on hydrogen made for them this hour.
- The electrolyser takes the power that is left, but makes only the H₂ the units take this hour plus what still fits in the buffer.
- Power still unused charges the BESS, then is curtailed. When the renewables run short, the BESS also powers steps 2 and 3 (unless the deficit tie-break keeps it for the BoP). The H₂ buffer and the BESS carry to the next hour.
Hydrogen is never lost: every hour, what the electrolyser makes is used by the units or stored in the buffer, and the engine checks this hour by hour. Power the electrolyser cannot use because the units and the buffer are full is curtailed, like any other surplus.
It’s deterministic and has no foresight — so it can’t “save for later” perfectly, which usually keeps it below what the Feasibility optimiser finds. Grid may serve BoP only (never the electrolyser — a compliance boundary).
There are no closed-form ceilings here — the binding stage emerges from the hourly coincidence, so the cockpit reports the upstream bottleneck (usually renewables) rather than a three-limits chart. Curtailment, the H₂ buffer’s cycling and the energy balance are all outputs you read, not inputs you set.
Assumptions & provenance
the book is canonical
Every result is driven by the project’s assumption book — each technical and financial parameter threads through the engines, the components, and the financials, so editing any one changes the answer. Numbers carry a source on a ladder of increasing confidence:
dab < user < quote < contract
dab = the default assumption book (seeded values); user = your override; quote / contract = the later gates. Edit values in the Assumptions room; size the plant in the cockpit.
The financial model
CRF · allocation · LCO
Costs are annualized: CAPEX is spread over the project life with the capital recovery factor (CRF), then added to yearly OPEX. The levelized cost of a product is that annual cost divided by annual output.
CRF = wacc · (1+wacc)ⁿ / ((1+wacc)ⁿ − 1)
LCOA = (Σ CRF·CAPEXᵢ + OPEXᵢ) / annual product
- LCOH — levelized cost of the (intermediate) hydrogen: shared upstream cost ÷ H₂.
- LCOA — levelized cost of the product (e.g. ammonia), $/t.
- LCOE — levelized cost of the electricity delivered to the plant.
Costs are allocated: shared upstream (renewables → electrolyser) by each product’s share of the hydrogen — a result of the capacities, below; the CO₂ chain by CO₂ demand; unit-specific CAPEX/OPEX directly to that product.
H₂ allocation
a result of the capacities, not an input (since 2026-11-09)
You do not type how the hydrogen is shared: each product’s capacity decides it. A unit’s need is the hydrogen it takes at its maximum output over a year — its capacity × the book’s maximum utilisation for that unit × the hydrogen a tonne needs. Its share is its need over all the units’ needs:
shareᵢ = needᵢ / Σ needs needᵢ = capacityᵢ × max utilisationᵢ × H₂ per tonneᵢ
- Short of hydrogen: every unit runs at the same fraction of its maximum output — no unit starves another.
- Exactly enough: every unit is full.
- More than the units can take: every unit is full and the surplus is not made — the electrolyser idles and that electricity is curtailed, not exported. The result says how much hydrogen was not made. To use it, add an H₂-export product: it has a capacity like any unit and takes its share.
The same rule runs hour by hour in timeseries mode. Every product needs a capacity: without one the solve stops and names the product to fix (right-size can size it when it is the one product left free). The shares show in the cockpit’s Production panel and in every export. Feasibility does not use shares at all: each unit takes hydrogen by its size and the dispatch.
Curtailment
assumed vs realized
In annual mode curtailment is an assumption (the floor you set). In timeseries mode it’s a computed output of the hourly coincidence between renewables and demand — you read it, you don’t set it.
Right-size optimization
find the cheapest design
“Right-size” picks the component sizes that make your product cheapest — it minimizes the product’s levelized cost. In annual mode that’s a closed-form balance; in timeseries mode the sizes are tuned against the hourly simulation, because the real coincidence + storage change what’s optimal. It’s a self-applying action: click it and the sizing updates; the cockpit re-solves instantly.
In plain steps
- Choose which stages to fix (lock) — the rest are sized to match (default: lock renewables, size everything else to them).
- Start from the closed-form (annual) sizing — a sensible first guess.
- Pick a candidate size for the free stages (e.g. electrolyser + the unit).
- Simulate the whole year hour-by-hour → the real annual product.
- Cost it → the product’s levelized cost for that candidate.
- Step the sizes downhill (lower cost) and repeat until it stops improving.
- That’s the recommendation; the landscape below confirms it’s the global best.
The maths behind it
Let x be the free sizes (e.g. electrolyser MW and unit t/yr). The greedy simulation gives
the annual product P(x), and the financials give the total annualized cost C(x). We
minimize a single objective — the product’s levelized cost:
minimize LCO(x) = C(x) / P(x)
Why a single objective? C(x) already contains every cost — renewables, storage, electrolyser and the synthesis unit — so nothing is left out and there’s no need for separate per-component targets. (Minimizing hydrogen cost alone, LCOH, would ignore the unit’s CAPEX and oversize it.)
Several molecules. With more than one product the objective is the H₂-share-weighted average of the per-product LCOs — each molecule weighted by its share of the hydrogen in that candidate (the share follows the capacities, so it moves when a candidate resizes a product):
LCO(x) = Σᵢ shareᵢ · LCOᵢ(x) / Σᵢ shareᵢ
This is price-free and consistent with the by-H₂-share cost allocation, and — unlike a plain cost-per-total-tonne — it doesn’t let a cheap, high-volume molecule drown out an expensive one, and it never mixes unlike product tonnes. The same objective drives both the optimizer and the landscape colours, so the ★ and the map always agree.
Why it has a minimum (a “bowl”). Too small → little product, so the fixed upstream cost is spread thin → cost high. Too big → idle CAPEX you never use → cost high. The trade-off is convex, with one interior minimum.
The search — two stages. Each candidate is one fast year-simulation, so we minimize directly. First, coordinate descent: line-minimize the cost over one size (golden-section), then the next, and repeat. That alone can stall where the electrolyser and the derivative basket want to grow together — a diagonal “ridge” a one-axis-at-a-time search can’t climb, leaving it a fraction of a percent short. So we then run a short joint Nelder–Mead polish — a “simplex” tumbling downhill over both sizes at once (the amoeba you see crawl across the landscape) — which follows the ridge to the true bottom. Because the greedy objective is deterministic, this is exact and repeatable.
Locked vs free. Fixed stages are held exactly; only the free ones move. At least one must be locked and one free. When you lock the larger of two coupled stages, the smaller free stages are sized to it and the surplus shows as idle capacity (the graph’s “N% idle” badge) rather than being silently hidden. The capacities are your product mix: free products keep their ratio to one another and grow or shrink together (as wind and solar do); with every product locked, the upstream is sized to all their needs. If the locked products alone need more hydrogen than a locked upstream can make, right-size stops and says so — any size for the free product would leave part of it idle.
The ★ is what “Apply” gives you. With the joint polish the optimizer reaches the very bottom of the bowl, so the landscape’s ★ (its recommendation) is the same design the Right-size button produces — “apply the ★” is literally one click. The ★-on-the-map is reported as the best of the continuous search and every grid sample, so it’s never drawn above a cheaper coloured cell; since the continuous search now reaches (or slightly beats) the coarse grid, that reconciliation is a tie-break, not a correction.
The optimization landscape
see the cost surface (Mode B)
The landscape is the picture of the bowl the optimizer descends — a heatmap of the levelized cost over the two free sizing axes, so you can see that the recommendation sits at the global minimum, not a local dip. It lives in the Prefeasibility cockpit (timeseries mode); map it there to validate a design in one glance. The project is never modified — it’s ~200 throwaway solves on copies.
- The axes adapt to your lock. The x-axis is the free upstream — the electrolyser when it’s free (the classic renewables-locked view), or the renewables (wind + solar together) when you’ve locked the electrolyser. The y-axis is the free derivative basket (total t/yr). Lock a stage and it stops being an axis — the map shows only what you can actually move.
- The colour is the objective. Bright = cheap, dark = dear — the blended product LCO for a multi-molecule project (labelled as such), or the single molecule’s LCO on its own. Same number the optimizer minimizes, so ★ and colour agree.
- ◦ current, ★ optimum — decomposed. Both markers carry a per-derivative read-out: each molecule’s capacity and its own LCO at that design (e.g. “NH₃ 81 kt · $1,197/t · eMeOH 77 kt · $1,276/t”), so you see how the blend is built, not just the headline.
- Are you optimized? A badge collapses it to one honest number — the % gap between your current design and the ★. Within tolerance → “✓ Optimized”; otherwise “↓ X% cheaper available”, your cue to hit Right-size.
- The search path. An optional overlay draws the Nelder–Mead simplex crawling from the current design into the bowl — the same polish the optimizer runs.
Reading the shape of the bowl
One dark basin ⇒ a single global optimum: the downhill search is trustworthy. A flat valley ⇒ several sizings are near-equal — a robust design, cheap to get roughly right. Tight rings ⇒ cost is sensitive to size — worth sizing carefully. Hover anywhere for a continuous (bilinear-interpolated) read-out of the exact electrolyser MW, unit t/yr and cost under the cursor — not snapped to a cell.
Because the free products scale together, moving up the y-axis scales the whole basket in its set ratio — so every point on the map is a real, specific set of per-molecule capacities, and the two axes are the complete design space the optimizer explores. (Changing the mix between molecules — their capacities’ ratio — is your call in the design panel, not the optimizer’s.)
Limits & honesty
directional
Prefeasibility is a screen. The timeseries mode has no look-ahead and the annual figures rest on the curtailment floor you assume; how the plant really runs is settled in Feasibility, between its rule-based engine (no look-ahead) and its optimiser (foresight). Assumptions are indicative until you replace them with quotes and contracts at the later gates. Use these numbers to decide whether and roughly how — not as a final cost.
From the app’s documentation, docs/02-features/how-prefeasibility-works.md · Hyprisma 1.0.5