Optimizer Documentation
Technical documentation for the capacity expansion optimization engine.
← Back to Grid Planner
|
Simulation Model Docs →
Table of Contents
1. Introduction
The optimizer performs least-cost capacity expansion planning under a CO2 emissions constraint. Given a target annual CO2 level (in million metric tons), it determines the optimal mix of new generation, storage, and carbon removal technologies to add to the existing grid that minimizes total annualized system cost while meeting the emissions target and reliability constraints.
Unlike Manual Mode, where the user adjusts technology sliders by hand and observes the impact, Optimize Mode automates this process. The problem is formulated as a linear program — capacity additions and hourly dispatch as decision variables, cost as a linear objective, and the CO2 target, energy balance, storage physics, and reliability requirements as linear constraints — and solved exactly with the open-source HiGHS solver running in the browser via WebAssembly. The result is the provably cost-optimal portfolio for the stated assumptions, and identical inputs always produce identical results.
Key outputs: Recommended capacity additions (GW or GWh per technology), total system cost ($/year), achieved CO2 emissions, reserve margin, curtailment rate, and a detailed cost breakdown including abatement costs.
Recent Updates (July 2026)
1. Exact Linear-Programming Optimizer: The heuristic multi-start search has been replaced by a linear program solved with HiGHS (WebAssembly, runs entirely in your browser — no backend). The LP jointly optimizes capacity additions and all 288 hours of dispatch, so the answer is the provable global cost optimum rather than the best of several heuristic runs. Results are now fully repeatable: the same inputs always return the same portfolio.
2. Marginal Abatement Cost: The dual value (shadow price) of the CO2 constraint is reported with the results — the cost of removing one additional ton of CO2 at your target, i.e., the implied carbon price of the policy.
3. Simulation-Verified Solutions: Every LP solution is re-evaluated through the full dispatch simulation (the same engine as Manual Mode) before being reported. If the simulation's heuristic dispatch emits slightly more CO2 than the LP's optimal dispatch, the LP is automatically re-solved with a tightened target until the simulated result meets the user's target.
4. Repeatability Fixes: Removed hidden run-to-run state (adaptive initial-guess scaling, shared baseline-capacity references) that previously caused identical inputs to produce different answers. The legacy heuristic remains only as an offline fallback if the solver cannot be downloaded.
5. CAISO-Calibrated Solar Profiles: California's monthly solar shapes were recalibrated against CAISO actuals — monthly seasonality from 2023-25 daily generation data, realistic daylight windows (07:00-17:00 in January through 06:00-20:30 in June, validated against 5-minute actuals), and an annual fleet capacity factor of 26% (previously the profiles implied just 14%, which made new solar uneconomic in the optimizer).
6. 2025-26 Cost Benchmark Refresh: CAPEX updated to current US utility-scale market data: solar $1,000/kW, wind $1,400/kW, nuclear $8,500/kW, gas CCGT $2,000/kW (up 66% on the turbine supply crunch), 4-hr battery $330/kWh, hydrogen CT $2,200/kW, plus supply-curve base updates for geothermal ($3,800/kW) and biomass ($4,000/kW). Sources: NREL ATB/2025 benchmarks, Lazard LCOE+, LBNL wind market reports, BNEF.
Previous Updates (February 2026)
1. Deterministic Multi-Start Optimization: The optimizer now uses a seeded PRNG (Mulberry32) for full reproducibility. By default, 3 runs with different seeds (42, 137, 2024) are executed, and the best result is selected. This addresses non-determinism caused by the multimodal solution space.
2. Supply Curves for Resource-Constrained Technologies: Geothermal (0-2 GW: 1.0×, 2-4 GW: 1.3×, 4-5 GW: 1.6×) and Biomass (0-1.5 GW: 1.0×, 1.5-3 GW: 1.4×) now have stepped cost curves reflecting resource scarcity. Marginal CAPEX guides selection; blended CAPEX calculates total cost.
3. Tightened Resource Bounds: Geothermal max reduced from 20 GW to 5 GW (hydrothermal + EGS resource limit). Biomass max reduced from 20 GW to 3 GW (sustainable feedstock constraint).
4. Updated Solar & Wind CAPEX: Solar reduced from $1,200/kW to $800/kW (2025-2026 utility-scale market prices). Wind reduced from $1,500/kW to $1,200/kW. This significantly improves VRE competitiveness (solar LCOE ~$42/MWh, wind ~$41/MWh).
5. RNG & Hydrogen Dispatch Fix: Moved from inflexible (24/7 must-run) to flexible dispatch. They now respond to net load, operating only when needed, improving system efficiency and correctly counting toward reserve margin.
6. Inter-Day Storage Carryover: Long-duration storage (24-hr) can now carry state-of-charge across days with 1% monthly self-discharge, enabling multi-day energy shifting. Short-term batteries (4-hr, 8-hr) remain day-independent.
7. Storage Dispatch by Type: Each storage type (4-hr, 8-hr, 24-hr) now dispatches independently with type-specific parameters, replacing the previous pooled dispatch model.
8. Nelder-Mead Exploration: Simplex refinement now includes "exploration points" for up to 3 inactive technologies, allowing discovery of cost-effective technologies missed by the greedy search phase.
9. Bug Fixes: Corrected storage variable O&M double-counting, fixed SoC tracking (gross vs net charge), and reordered thermal dispatch (CCGT → Coal → CT).
2. Time Resolution & Demand Model
The model uses a 288-hour representative year, consisting of 12 months × 24 hours. Each month is represented by a single "typical day" of 24 hourly time steps. This compact representation captures seasonal and diurnal variation while keeping computation fast enough for interactive use.
To convert hourly simulation values to annual totals, each hour is weighted by the number of days in its month:
where:
| Month | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Days | 31 | 28 | 31 | 30 | 31 | 30 | 31 | 31 | 30 | 31 | 30 | 31 |
Demand is provided as a 288-element array in GW (12 months × 24 hours). For California, the system uses direct CAISO-derived monthly profiles where each of the 12 months has a complete 24-hour demand pattern with realistic diurnal variation. For other regions, four seasonal base 24-hour shapes (spring, summer, fall, winter) are scaled by per-month multipliers to generate 12 monthly profiles, preserving backward compatibility while capturing month-to-month variation.
3. Technology Cost Model
3.1 Cost Data
Each technology has four cost parameters plus a lifetime. Users can edit these values in the "Edit Cost & Performance Assumptions" panel. Default values are:
| Technology | CAPEX | Fixed O&M | Variable O&M | Lifetime | Capacity Factor |
|---|---|---|---|---|---|
| Solar PV | $1,000/kW | $22/kW-yr | $0/MWh | 30 yr | 25% |
| Onshore Wind | $1,400/kW | $40/kW-yr | $1/MWh | 30 yr | 35% |
| Offshore Wind | $5,000/kW | $100/kW-yr | $0/MWh | 30 yr | 50% |
| Nuclear | $8,500/kW | $140/kW-yr | $10/MWh | 60 yr | 90% |
| Geothermal | $3,800/kW* | $120/kW-yr | $5/MWh | 30 yr | 90% |
| Biomass | $4,000/kW* | $100/kW-yr | $10/MWh | 25 yr | 85% |
| RNG (Biogas) | $3,000/kW | $95/kW-yr | $50/MWh | 25 yr | 85% |
| Hydrogen | $2,200/kW | $90/kW-yr | $410/MWh | 30 yr | 20% |
| Gas CCGT | $2,000/kW | $20/kW-yr | $35–80/MWh | 30 yr | 55% |
| Coal | $4,407/kW | $40/kW-yr | $30/MWh | 40 yr | 60% |
| Battery (4-hr) | $330/kWh | $15/kW-yr | $2/MWh | 15 yr | — |
| Battery (8-hr) | $285/kWh | $15/kW-yr | $2/MWh | 15 yr | — |
| Long-Duration (24-hr) | $250/kWh | $60/kW-yr | $1/MWh | 25 yr | — |
| DAC | $1,000/ton-yr | $20/ton-yr | $400/ton | 25 yr | — |
Note: Storage CAPEX is in $/kWh of energy capacity. DAC costs are per annual ton of CO2 capture capacity.
Benchmarks updated July 2026 against NREL ATB / NREL 2025 cost benchmarks, Lazard LCOE+, LBNL wind market reports, and BNEF/GridLab gas plant cost analyses (CCGT CAPEX rose ~66% from 2023-25 amid the turbine supply crunch). For California, the dispatch uses CAISO-calibrated hourly capacity-factor profiles rather than the flat nominal CF shown here.
* Geothermal and Biomass use supply curves: CAPEX increases with deployment. Base costs shown; see section 3.2 Supply Curves for details.
3.2 Supply Curves for Resource-Constrained Technologies
Some technologies face increasing costs as deployment grows, reflecting resource scarcity and site quality degradation. The model implements supply curves for geothermal and biomass, where CAPEX increases in steps as cumulative capacity grows.
Geothermal Supply Curve
| Capacity Range | Cost Multiplier | Effective CAPEX | Marginal LCOE |
|---|---|---|---|
| 0-2 GW | 1.0× | $3,800/kW | ~$59/MWh |
| 2-4 GW | 1.3× | $4,940/kW | ~$71/MWh |
| 4-5 GW | 1.6× | $6,080/kW | ~$82/MWh |
The first 2 GW represents the best hydrothermal resources (The Geysers, Salton Sea). The 2-4 GW band captures good sites requiring deeper drilling and higher reservoir development costs. Beyond 4 GW, only marginal sites and enhanced geothermal systems (EGS) remain feasible, significantly increasing costs.
Biomass Supply Curve
| Capacity Range | Cost Multiplier | Effective CAPEX | Marginal LCOE |
|---|---|---|---|
| 0-1.5 GW | 1.0× | $4,000/kW | ~$70/MWh |
| 1.5-3 GW | 1.4× | $5,600/kW | ~$88/MWh |
The first 1.5 GW uses cheapest feedstocks: waste residues, agricultural waste, and forest thinnings with minimal transport costs. Beyond 1.5 GW, dedicated energy crops are required with longer transport distances, increasing both feedstock and logistics costs.
How Supply Curves Work
The optimizer uses two CAPEX values:
- Marginal CAPEX: Used in LCOE calculations to guide technology selection. This is the cost of the next GW at the current deployment level. For example, if 3 GW of geothermal is already deployed, the marginal CAPEX for the 4th GW is $4,940/kW (1.3× multiplier).
- Blended CAPEX: Used in total system cost calculations. This is the capacity-weighted average cost across all deployment bands. For example, if 3 GW is deployed, blended CAPEX = (2 GW × $3,800 + 1 GW × $4,940) / 3 GW = $4,180/kW.
This dual approach ensures the optimizer sees accurate marginal economics (guiding incremental decisions) while calculating correct total costs (reflecting what was actually paid for all deployed capacity).
3.3 Capital Recovery Factor (CRF)
Capital costs are annualized using the Capital Recovery Factor, which converts a lump-sum investment into equal annual payments over the asset's lifetime at a given discount rate:
where d is the discount rate (default: 7% = 0.07) and n is the asset lifetime in years.
For example, a solar plant (30 years, 7% discount): CRF = 0.07 × 1.0730 / (1.0730 − 1) ≈ 0.0806, meaning ~8.06% of capital cost is paid annually.
3.4 Annualized Cost Formulas
Generation Technologies (Solar, Wind, Nuclear, etc.)
Annual Fixed O&M = Capacity (kW) × Fixed O&M ($/kW-yr)
Annual Variable O&M = Annual Generation (MWh) × Variable O&M ($/MWh)
Total Annual Cost = Annual CAPEX + Fixed O&M + Variable O&M
Annual generation is computed by summing hourly dispatch across all 288 hours, weighted by days in each month.
Storage Technologies (Battery, Long-Duration)
Storage is specified in GWh of energy capacity. Power capacity is derived from the duration:
4-hr battery: Duration = 4 hours
8-hr battery: Duration = 8 hours
Long-duration: Duration = 24 hours
Annual CAPEX = Energy (kWh) × CAPEX ($/kWh) × CRF(d, n)
Annual Fixed O&M = Power (kW) × Fixed O&M ($/kW-yr)
Annual Variable O&M = Annual Discharge (MWh) × Variable O&M ($/MWh)
Round-trip efficiency for all storage types is 85%. This means for every 1 MWh charged, only 0.85 MWh is available for discharge.
Direct Air Capture (DAC)
Annual CAPEX = Annual Capacity × CAPEX ($/ton-yr) × CRF(d, n)
Annual Fixed O&M = Annual Capacity × Fixed O&M ($/ton-yr)
Annual Variable O&M = Annual Capacity × Variable O&M ($/ton)
3.5 Incentives
Government incentives reduce technology costs:
- Production Tax Credit (PTC): Applied as $/MWh to annual generation. Reduces the annual cost of the technology by
Annual Generation (MWh) × PTC rate. Available for solar, wind, offshore wind, nuclear, geothermal, biomass, RNG, and hydrogen. - Investment Tax Credit (ITC): Applied to storage. Reduces cost by
Energy Capacity (kWh) × CAPEX × ITC rate × CRF(annualized). - DAC Incentive: Per-ton subsidy that directly reduces DAC annual cost.
- Carbon Tax: Adds cost:
(Annual CO2 in kg / 1000) × Carbon Tax ($/ton). - Export Price: Curtailed energy can be "exported" at a given price (can be negative). Revenue =
Curtailment (GWh) × 1000 × Export Price ($/MWh).
3.6 Total System Cost
∑ Generation Tech Costs (CAPEX + Fixed O&M + Var O&M − PTC)
+ ∑ Storage Costs (CAPEX + Fixed O&M + Var O&M − ITC)
+ DAC Cost (CAPEX + Fixed O&M + Var O&M − DAC Incentive)
+ Carbon Tax Cost
− Export Revenue
This cost includes both existing baseline capacity and new additions. The optimizer minimizes this total while meeting the CO2 constraint.
4. Dispatch Simulation
Every candidate solution is evaluated by running a full hourly dispatch simulation (getSimulationResult). This determines how the grid operates each hour: which plants run, how storage charges/discharges, what gets curtailed, and the resulting emissions. The dispatch follows a merit order, prioritizing low-cost and zero-carbon sources.
Dispatch Order (each hour)
- Must-run baseload: Nuclear, geothermal, and biomass run at their capacity factor regardless of demand. Hydro runs at its country-specific capacity factor.
- Variable Renewable Energy (VRE): Solar and wind generation is computed as
Capacity (GW) × CF Profile[hour]. The CF profile varies by hour and month, capturing diurnal and seasonal patterns. - Net Load calculation:
Net Load = Demand − Must-run − VRE. If net load is negative, there is excess generation. - Storage dispatch: Storage operates via economic arbitrage. Short-term batteries (4-hr, 8-hr) charge/discharge within each day. Long-duration storage (24-hr) can carry state-of-charge across days with 1% monthly self-discharge, enabling multi-day energy shifting. All storage has 85% round-trip efficiency. The algorithm sorts hours by net load, identifying arbitrage opportunities (charge during excess generation, discharge during high net load) while respecting energy and power constraints.
- Flexible clean dispatch: RNG (biogas) and Hydrogen are dispatched only when net load is positive, operating as flexible zero-carbon resources. Unlike the old inflexible dispatch (24/7 must-run), they now respond to system needs.
- Thermal dispatch: Remaining net load (after storage and flexible clean) is met by fossil fuels in merit order: Natural Gas CCGT (cheapest) → Coal → Natural Gas CT (most expensive peakers). Each plant ramps between a minimum and maximum output, with the marginal cost increasing linearly as output increases.
- Curtailment: If total generation exceeds demand after all dispatch, the excess is curtailed.
Curtailment Rate = Curtailed Energy / (Total Generation + Curtailment).
4.1 Emissions Calculation
Hourly emissions are computed by multiplying each technology's generation by its emission factor:
| Technology | Emission Factor (kg CO2/MWh) |
|---|---|
| Natural Gas (generic) | 410 |
| Natural Gas CCGT | 370 |
| Natural Gas CT | 500 |
| Coal | 920 |
| Biomass | 50 (net, after regrowth offset) |
| All other (solar, wind, nuclear, etc.) | 0 |
Annual CO2 is then computed by summing hourly emissions weighted by days per month:
5. Optimization Algorithm (Linear Programming)
The optimizer formulates capacity expansion as a linear program (LP) and solves it exactly with HiGHS, a state-of-the-art open-source solver compiled to WebAssembly and loaded on demand — everything runs client-side in your browser. This is the same mathematical approach used by research-grade capacity expansion models such as PyPSA and GenX.
5.1 Why a Linear Program
Earlier versions used a multi-start heuristic search (documented in section 5.6 below, retained as an offline fallback). Heuristics can only promise "a good solution," and small differences in starting conditions could produce visibly different portfolios with similar costs — which understandably raised questions about what the actual answer was. The LP removes that ambiguity:
- Exact: the solution is the provable global cost minimum for the stated assumptions, not the best of several tries.
- Repeatable: the model is a pure function of the inputs and the simplex method is deterministic — identical inputs always return the identical portfolio.
- Fast: the ~7,000-variable LP solves in about a second, versus tens of seconds for the heuristic's thousands of simulation calls.
- Informative: LP duals give the shadow price of the CO2 constraint — the marginal abatement cost — for free.
5.2 Decision Variables
The LP jointly optimizes capacity and operation:
- Capacity additions (bounded per section 8): solar, wind, offshore wind, nuclear, RNG, hydrogen (GW); 4-hr / 8-hr / long-duration storage (GWh); DAC (t/hr). Geothermal and biomass are split into one variable per supply-curve cost band (section 3.2), so the LP pays the correct marginal CAPEX as deployment climbs the curve.
- Hourly dispatch over the 288-hour representative year: generation per technology, natural-gas output split into CCGT/CT tranches that reproduce the rising marginal-cost curves of section 4, hydro limited by its daily energy budget, storage charge/discharge/state-of-charge with 85% round-trip efficiency, and curtailment.
5.3 Constraints
| Constraint | Form |
|---|---|
| Energy balance | Generation + storage discharge − storage charge = demand, every hour |
| Resource availability | Generation ≤ (baseline + new capacity) × hourly capacity factor |
| CO2 target | ∑ (gas + coal emissions) − DAC capture ≤ target (kg/year), with a floor at zero net emissions |
| Reserve margin | Flexible capacity (RNG, hydrogen, gas, hydro, storage power) ≥ 120% of peak demand |
| Curtailment cap | Curtailed energy ≤ user-set ceiling (default 20%) of (generation + curtailment), if enabled |
| Storage physics | State-of-charge dynamics with charge efficiency; short-duration batteries day-cyclic with a one-cycle/day throughput cap; long-duration carries state across the year |
| Hydro budget | Daily energy ≤ capacity × CF × 24h; hourly output capped (32% of nameplate in California) |
| Capacity bounds | Per-technology limits of section 8; disabled technologies fixed to zero |
5.4 Objective Function
Minimize total annual system cost, mirroring the cost model of section 3: CRF-annualized CAPEX plus fixed O&M on capacity (with supply-curve multipliers and storage CAPEX incentives), variable O&M minus production incentives on generation, tranche-priced natural gas fuel costs, carbon tax on net emissions, DAC costs on full capacity, and export revenue (or cost, at negative prices) on curtailed energy. Costs of the existing baseline fleet are constants and drop out of the minimization; the reported system cost is computed by the full dispatch simulation afterwards.
5.5 Verification & Shadow Prices
The LP's optimal dispatch is slightly more efficient than the rule-based dispatch simulation used in Manual Mode (which has a storage profit threshold, quantized dispatch steps, and heuristic hydro scheduling). To make sure the recommendation holds up in the same simulation users see, every LP solution is re-evaluated through the full dispatch simulation before being reported. If the simulated CO2 comes out above target, the optimizer bisects on the LP's internal CO2 target: it first probes the floor (internal target of zero — the cleanest portfolio the LP can build), then bisects for the loosest internal target whose portfolio still verifies. Because simulated CO2 rises monotonically with the internal target, this deterministic search lands on the cheapest confirmable portfolio with simulated emissions close to (not far below) the user's target. Small unmet-energy residuals below 0.001% of annual demand are treated as dispatch-quantization noise; larger gaps trigger a re-solve with a small planning buffer on demand. If even the floor probe simulates above the requested target, the error message reports that floor — the true lowest reachable CO2 for the current fleet and bounds — rounded up so that entering the suggested value is guaranteed to succeed.
The marginal abatement cost shown with the results is the dual value of the CO2 constraint: the system cost of removing one more ton of CO2 at your target. When the cost-optimal portfolio already beats the target (e.g., because a carbon tax makes clean energy profitable on its own), the constraint is slack and no shadow price is shown.
5.6 Legacy Heuristic Search (offline fallback)
If the HiGHS solver cannot be downloaded (no network access to the CDN), the optimizer falls back to the previous multi-start heuristic: three seeded search runs (Mulberry32 PRNG, seeds 42/137/2024) with LCOE-guided neighborhood search and Nelder-Mead refinement, keeping the lowest-cost feasible result. The fallback is deterministic for a given input but, being a local search, does not carry the LP's global-optimality guarantee. Its phases are documented below.
5.6.1 Initial Guess Heuristic
Rather than starting from zero capacity, the optimizer estimates a reasonable starting point based on the CO2 reduction needed:
CO2 Reduction Needed = max(0, Baseline CO2 − Target CO2)
Total Clean Capacity Needed (GW) = CO2 Reduction / 1.1 × 109
(Empirical rate: ~1.1 million MT CO2 reduced per GW of clean capacity)
Initial Solar = min(100, 60% of Total Clean Capacity)
Initial Wind = min(80, 40% of Total Clean Capacity)
Initial Battery = min(50, 25% of VRE Capacity) [GWh, 4-hr]
Reserve Margin Gap Check
Before starting the main loop, the optimizer checks whether the existing grid plus the initial guess has sufficient flexible capacity. If the reserve margin target (20%) is not met, it adds:
- 80% of the gap as 4-hr battery (GWh = gap × 4 × 0.8)
- 15% as RNG
- 5% as Hydrogen
5.6.2 Main Optimization Loop
The core loop runs up to 1000 iterations (configurable). Each iteration:
-
Compute system-value adjusted LCOE for each technology using
calculateMarginalLCOEWithSystemValue. This starts from the base LCOE but adjusts based on current system conditions:- If curtailment > 10%: VRE LCOE is penalized (solar ×(1 + curtailment rate), wind ×(1 + curtailment × 0.5), offshore ×(1 + curtailment × 0.3)) since adding more VRE will further increase curtailment.
- If reserve margin < target: Flexible technology LCOEs receive a 90% discount (multiplied by 0.1), and firm baseload (nuclear, geothermal) gets a 50% discount.
- If CO2 gap exists: All zero-carbon technologies get a 10% discount. If the gap is severe (>1.5× target), DAC gets a 30% discount.
-
Generate candidate solutions: Technologies are ranked by adjusted LCOE. For each technology (in LCOE order), candidates are generated by adding or subtracting a step size. Step sizes vary by technology:
Technology Step Size Unit Solar 1.0 – 5.0 GW Wind 1.0 – 5.0 GW Offshore Wind 0.5 – 2.0 GW Nuclear 0.5 – 2.0 GW Geothermal 0.5 – 1.0 GW Biomass 0.5 – 1.0 GW RNG / Hydrogen 0.5 – 2.0 GW Battery (4-hr / 8-hr) 2.0 – 10.0 GWh Long-Duration 5.0 – 20.0 GWh DAC 100 – 500 t/hr The step size adapts based on iteration count (larger early, smaller later) and system conditions.
- Quick feasibility pre-screen: Before running a full simulation, candidates are checked with a fast reserve margin estimate. Candidates that clearly fail are skipped.
- Full evaluation: Remaining candidates are evaluated via complete dispatch simulation, computing cost, CO2, reserve margin, curtailment, and energy balance.
- Selection: The best feasible candidate is selected. Under normal operation, the lowest-cost feasible solution wins. When the current best solution is >10% below the CO2 target, a weighted objective is used: 70% cost + 30% proximity to target, to push the solution back toward the target.
- Improvement check: An improvement is "meaningful" if cost improves by >0.01% or the CO2 gap narrows by >1%. If meaningful, the no-improvement counter resets. Otherwise, it increments.
5.6.3 Feasibility Constraints
A solution must pass all four constraints to be considered feasible:
| Constraint | Requirement | Tolerance |
|---|---|---|
| CO2 Target | Annual CO2 ≤ Target CO2 | 2% above target allowed |
| Reserve Margin | Flexible Capacity / Peak Demand − 1 ≥ 0.20 | None |
| Curtailment Cap | Curtailment Rate ≤ 20% | Only if enabled by user |
| Energy Balance | Unmet Energy < 10 MWh/yr | None |
The quick feasibility check only tests reserve margin (fast to compute). The full feasibility check tests all four constraints after running the complete dispatch simulation.
5.6.4 Convergence & Early Stopping
The optimizer stops when no meaningful improvement is found for a number of consecutive iterations:
- Normal convergence: 50 iterations with no meaningful improvement.
- Below-target mode: When the best solution's CO2 is >10% below target, the threshold increases to 200 iterations to allow the optimizer more time to find solutions closer to the target.
- Near-minimum capacity: If baseload capacity < 1 GW and total non-flexible capacity < 8 GW, the threshold reverts to 50 since we've hit a physical limit.
Perturbation (Escaping Local Minima)
After 30 iterations without improvement, the current solution is randomly perturbed. Each technology's capacity is multiplied by a random factor between 0.7 and 1.3 (up to ±30% change). This helps the optimizer explore different regions of the solution space.
5.6.5 Nelder-Mead Local Refinement
After the main loop converges, the best solution is refined using the Nelder-Mead simplex algorithm. This derivative-free optimization method works in the space of "active" technologies (those with non-zero capacity in the best solution), plus a limited set of inactive technologies for exploration.
Simplex Initialization
For N active technologies plus up to 3 inactive "exploration" technologies, a simplex of (N+M)+1 points is created. The first point is the current best solution. The remaining points are created by:
- Active tech points: Perturb each active technology dimension by ±0.5 GW (generation) or ±2.0 GWh (storage)
- Exploration points: Introduce small positive amounts of inactive technologies (1 GW for generation, 5 GWh for storage), allowing Nelder-Mead to discover cost-effective technologies that the greedy search phase missed
This enhancement addresses a limitation of the original algorithm: Nelder-Mead could only refine technologies already in the solution, never discovering new ones. By including exploration points, the refinement phase can now find and add previously unused technologies if they improve the objective.
Simplex Operations
Each iteration sorts the simplex by cost, then attempts to replace the worst point using these transformations:
Reflection: xr = c + α(c − xworst) [α = 1.0]
Expansion: xe = c + γ(xr − c) [γ = 2.0]
Contraction: xc = c + ρ(xworst − c) [ρ = 0.5]
Shrink: xi = xbest + σ(xi − xbest) [σ = 0.5]
The algorithm first tries reflection. If the reflected point is the best so far, it tries expansion. If reflection is worse than the second-worst, it tries contraction. If all fail, it shrinks the entire simplex toward the best point.
Convergence: The refinement stops when the cost range across the simplex (worst − best) is less than 1% of the best cost, or after 150 iterations.
6. Direct Air Capture (DAC)
DAC is a technology that actively removes CO2 from the atmosphere. In the optimizer, it acts as negative emissions.
When DAC is Enabled
DAC is only added to the candidate technology list when the CO2 target is aggressive: specifically, when the target is less than 60% of the baseline emissions. For easier targets, DAC is excluded because conventional clean generation is more cost-effective. DAC can also be manually disabled by the user via a checkbox.
LCOE Adjustments for DAC
When the CO2 gap is severe (>1.5× the target), DAC receives a 30% LCOE discount to make it more competitive. This reflects that DAC becomes increasingly valuable when other options are insufficient.
7. Reserve Margin
The reserve margin measures how much flexible, dispatchable capacity exceeds peak demand. It is a proxy for grid reliability—ensuring there is enough backup capacity for unexpected demand spikes or generator outages.
Target: ≥ 0.20 (20%)
What Counts as Flexible Capacity
| Resource Type | Capacity Credit | Notes |
|---|---|---|
| Fully Flexible (100% capacity credit) | ||
| Natural Gas (all types) | 100% | Fully dispatchable |
| RNG (Biogas) | 100% | Flexible dispatch (responds to net load) |
| Hydrogen | 100% | Flexible dispatch (responds to net load) |
| Hydro | 100% | Fully dispatchable |
| Battery Storage | Power capacity (GWh ÷ duration) | 4-hr: GWh/4; 8-hr: GWh/8; 24-hr: GWh/24 |
| Not Counted (Intermittent or Inflexible) | ||
| Solar, Wind, Offshore Wind | 0% | Intermittent generation (VRE) |
| Nuclear, Geothermal, Biomass, Coal | 0% | Inflexible baseload (24/7 operation) |
Example: A 100 GWh, 4-hour battery provides 25 GW of flexible power capacity toward the reserve margin.
8. Capacity Bounds
Each technology has minimum and maximum capacity limits. These prevent unrealistic solutions and keep the optimization space manageable:
| Technology | Min | Max | Unit |
|---|---|---|---|
| Solar | 0 | 100 | GW |
| Onshore Wind | 0 | 80 | GW |
| Offshore Wind | 0 | 50 | GW |
| Nuclear | 0 | 30 | GW |
| Geothermal | 0 | 5 | GW |
| Biomass | 0 | 3 | GW |
| RNG | 0 | 20 | GW |
| Hydrogen | 0 | 20 | GW |
| Battery (4-hr) | 0 | 100 | GWh |
| Battery (8-hr) | 0 | 100 | GWh |
| Long-Duration (24-hr) | 0 | 200 | GWh |
| DAC | 0 | 10,000 | t/hr |
These bounds represent new capacity additions only, not total installed capacity. Existing baseline capacity is separate.
9. Stranded Asset Detection
After optimization, the model checks whether existing fossil fuel capacity is underutilized. If the optimized grid's peak hourly usage of natural gas or coal is less than 80% of the installed capacity, the system flags these as potentially stranded assets.
When stranded capacity is detected, the user is offered the option to re-optimize with reduced fossil baseline. The suggested new capacity is set to 110% of the peak optimized usage (a 10% buffer). Reducing fossil capacity lowers Fixed O&M costs but may require additional flexible clean resources (batteries, RNG, hydrogen) to maintain the reserve margin.
10. Configuration Parameters
Optimization Configuration
| Parameter | Value | Description |
|---|---|---|
| MAX_ITERATIONS | 1000 | Maximum iterations in main loop |
| RESERVE_MARGIN_TARGET | 0.20 | 20% flexible capacity above peak demand |
| Discount Rate | 0.07 | 7% real discount rate for CRF |
| CO2 Tolerance | 2% | Solutions up to 2% above target are feasible |
| Curtailment Cap | 20% | Max allowed curtailment (if enabled) |
| Convergence Threshold | 50 / 200 | Iterations without improvement before stopping |
| Perturbation Trigger | 30 | No-improvement iterations before random perturbation |
| Nelder-Mead Iterations | 150 | Maximum iterations for local refinement |
| Storage Efficiency | 85% | Round-trip efficiency for all storage |
| Cache Precision | 0.1 GW | Solution hashing rounds to nearest 0.1 GW |
Monthly VRE Capacity Factor Profiles
Capacity factor profiles for solar, onshore wind, and offshore wind vary by month to capture seasonal patterns. Two approaches are used:
- California: Uses direct 12-month × 24-hour profiles extracted from CAISO 2025 Summer Assessment (Figures 2.4 & 2.5). Each month has a unique diurnal pattern with realistic shapes and all capacity factors ≤ 1.0.
- Other regions: Uses a base 24-hour profile scaled by monthly multipliers. All resulting CFs are capped at 1.0 via
Math.min(1, baseCF × multiplier).
California Monthly Profiles (CAISO-derived, rescaled to peak=1.0)
| Month | Solar Peak CF | Wind Peak CF | Offshore Wind Peak CF | Pattern Notes |
|---|---|---|---|---|
| January | 0.58 | 0.30 | 0.50 | 10 sun hours, winter-boosted offshore |
| February | 0.70 | 0.39 | 0.65 | 11 sun hours, strengthening wind |
| March | 0.81 | 0.57 | 0.80 | 13 sun hours, spring transition |
| April | 0.91 | 0.79 | 1.00 | 14 sun hours, wind ramping up |
| May | 0.98 | 0.91 | 0.93 | 15 sun hours, peak solar & wind correlation |
| June | 1.00 | 1.00 | 0.89 | 16 sun hours, strongest wind, reduced offshore |
| July | 0.96 | 0.79 | 0.80 | 15 sun hours, sustained summer peak |
| August | 0.91 | 0.66 | 0.76 | 14 sun hours, beginning descent |
| September | 0.83 | 0.63 | 0.72 | 12 sun hours, fall transition |
| October | 0.70 | 0.39 | 0.50 | 11 sun hours, weakening wind |
| November | 0.56 | 0.30 | 0.46 | 10 sun hours, winter approaching |
| December | 0.48 | 0.29 | 0.44 | 9 sun hours, winter minimum |
Key California pattern: Unlike most US regions, California wind is summer-peaking due to the coastal-to-inland thermal gradient driving strong winds through mountain passes (Tehachapi, Altamont, San Gorgonio). Both solar and wind peak in May–June (positively correlated). Offshore wind uses season-dependent transformation: winter-boosted (1.3×), summer-reduced (0.7×), then smoothed to reflect steadier marine winds. All profiles have been rescaled so the peak CF across all months equals 1.0, providing accurate relative seasonal variation while allowing maximum theoretical output during optimal conditions.
Default (other regions)
| Month | Solar | Onshore Wind | Offshore Wind |
|---|---|---|---|
| January | 0.60 | 1.15 | 1.15 |
| February | 0.70 | 1.10 | 1.10 |
| March | 0.85 | 1.05 | 1.05 |
| April | 0.95 | 0.95 | 1.00 |
| May | 1.05 | 0.90 | 0.95 |
| June | 1.15 | 0.85 | 0.90 |
| July | 1.15 | 0.80 | 0.85 |
| August | 1.10 | 0.80 | 0.85 |
| September | 0.95 | 0.85 | 0.90 |
| October | 0.80 | 0.95 | 1.00 |
| November | 0.65 | 1.10 | 1.10 |
| December | 0.55 | 1.15 | 1.15 |
In the default pattern, solar is strongest in summer and weakest in winter, while wind has the opposite pattern (strongest in winter). This seasonal complementarity is typical for most US and European regions.
Monthly Demand Profiles
Demand profiles vary by month to capture seasonal load patterns. Two approaches are used:
- California: Uses direct 12-month × 24-hour demand profiles derived from CAISO operational data. Each month has a complete hourly pattern with realistic diurnal variation, including subtle midday plateau characteristics.
- Other regions: Uses seasonal base 24-hour profiles (spring, summer, fall, winter) scaled by per-month multipliers. Each month maps to its season's shape, then is scaled by a multiplier to capture month-to-month intensity variation.
California Monthly Demand Profiles (CAISO-derived)
| Month | Peak Demand (GW) | Overnight Min (GW) | Pattern Characteristics |
|---|---|---|---|
| January | 29.5 | 19.3 | Moderate winter, evening peak |
| February | 28.0 | 18.2 | Mildest month (lowest peak) |
| March | 27.0 | 16.3 | Spring transition, lowest demand season |
| April | 26.5 | 16.4 | Annual minimum, mild spring weather |
| May | 31.0 | 17.5 | Warming, early AC usage begins |
| June | 38.5 | 21.7 | Early summer, AC demand rising |
| July | 45.0 | 25.3 | Peak summer heat, AC-driven evening peak |
| August | 46.5 | 26.2 | Hottest month (highest consistent peak) |
| September | 46.0 | 26.9 | Late summer heatwaves, volatile (historical record 52 GW) |
| October | 34.5 | 20.1 | Fall transition, cooling down |
| November | 29.0 | 18.5 | Cooling down, lower demand |
| December | 30.0 | 19.1 | Winter, holiday lighting and heating |
California pattern: Profiles exhibit subtle midday plateau (1-2 GW dip below morning peak) before the evening peak, characteristic of CAISO operational data. Demand follows a clear seasonal pattern: spring (March-April) represents the annual minimum at ~26-27 GW due to mild weather and high solar output offsetting daytime load. Summer months (July-September) show the highest peaks at 45-46 GW driven by air conditioning demand, with September being particularly volatile due to late-season heatwaves (CAISO's all-time record of 52 GW occurred in September 2022). Winter and fall months range from 28-35 GW. All values based on typical CAISO operational ranges.
Default (other regions)
For non-California regions, the system uses four seasonal base 24-hour profiles (spring, summer, fall, winter) scaled by per-month multipliers ranging from 0.92 to 1.11. This preserves backward compatibility while still capturing month-to-month demand variation.
Solution Caching
To avoid redundant dispatch simulations, the optimizer caches evaluation results. Solutions are hashed by rounding each technology's capacity to the nearest 0.1 GW (or GWh for storage, t/hr for DAC). If a solution with the same hash has been evaluated before, the cached result is returned directly. The cache is cleared at the start of each optimization run.