Computes the levelized cost of energy (LCOE) for a technology,
repository, model, or scenario object.
Usage
levcost(object, comm, name, ...)
# S4 method for class 'storage'
levcost(object, comm, name, ...)
# S4 method for class 'trade'
levcost(object, comm, name, ...)
# S4 method for class 'repository'
levcost(object, comm, name, ...)
# S4 method for class 'model'
levcost(object, comm, name, ...)
# S4 method for class 'scenario'
levcost(object, comm, name, ...)Arguments
- object
A
technology(or list thereof),repository,model, or solvedscenarioobject.- comm
Character vector or
NULL. Output commodity(ies) to use for LCOE normalisation.NULLuses all commodities in the resolved output group.- name
Character. For
technology, a name tag; forrepository/model/scenario, the name of the technology / process to price.- ...
Additional arguments passed to the underlying implementation. For
technologyobjects the most useful are:groupCharacter or
NULL. Output group name.repoA
repositoryor list of energyRt objects (supplies, commodities, weather) to supplement the mini-model.fuel_costsNamed numeric vector
[commodity -> cost]for input commodities not found inrepo. Auxiliary commodities consumed by the process (aux inputs) can be priced the same way; unnamed ones are supplied at zero cost.autocompleteLogical, default
FALSE(repository/modelmethods). WhenTRUE, input commodities without a supply in the container are auto-supplied (zero-cost, or priced viafuel_costs) instead of returningNULL.discountNumeric (0–1), default
0.05.base_yearInteger or
NULL.horizonA
horizonobject, numeric year vector, orNULL(derives from@olife).calendarA
calendarobject orNULL.timeframe"ANNUAL"(default) or"native"."ANNUAL"prices the technology on a single annual time-timeslice: any weather profile is collapsed to an annual capacity factor (applied as the technology's annual availability), so capacity is sized to serve unit annual demand at that factor (textbook LCOE)."native"keeps the supplied (sub-annual) calendar and normalises by total generation – useful when the technology is analysed together with storage or transmission, where sub-annual dispatch matters.backstopLogical, default
TRUE. Enables a very expensive dummy-import slack on the output commodity balance so the mini-model always solves even when the technology cannot serve a timeslice on its own; the slack cost is excluded from the LCOE.regionCharacter or
NULL.weatherA
weatherobject, list of weather objects, orNULL.frontierLogical, default
TRUE. WhenTRUEadditional solves are performed to map the production frontier for technologies with multi-commodity grouped output and share constraints (one solve per output / input corner solution). Has no effect for single-output or unconstrained technologies (the frontier is not meaningful, so only the base solve runs). SetFALSEto skip the extra solves.solverSolver spec list, default
solver_options$glpk.method"auto"(default),"analytic", or"solve". The unit-demand annual mini-model has a closed-form optimum for most technologies;"auto"computes it analytically (no solver needed) whenever the technology qualifies and falls back to the solver otherwise, with a message naming the reason."analytic"refuses non-qualifying technologies instead of falling back;"solve"always builds and solves the mini-model. The analytic result carries the same fields (plus$method = "analytic"and$frontier_vertices, which reports EVERY corner of the input/output share polytopes with its per-activity NPV cost breakdown and anoptimalflag);$scenarioisNULLon this path. Not analytically representable (solver required): technology chains,timeframe = "native",afc.*bounds, availability lower bounds,optimizeRetirement, year-varyinginvcost, reserve- or availability-constrained supplies, and group substitution combined with year-varying prices or efficiencies.run"single"(default) or"sequential"– only meaningful for a technology declaring vintages or clusters."single"prices every variant in one model (each in its own region, so they cannot compete); if that model does not solve it is retried with the dummy-import slack enabled and then, failing that, falls back to one model per variant."sequential"goes straight to one model per variant, so a single non-converging variant cannot take the rest down.max_failuresInteger, default
10. Abort the sequential fallback after this many consecutive failed variant solves, to bound the time spent on a technology whose variants all fail.as_scenarioLogical, default
FALSE. WhenTRUEthe full solvedscenariois returned with LCOE tables attached toscenario@misc.verboseLogical, default
TRUE.
Value
For technology input: a list of class "levcost" with fields:
$levcostdata.frame – total levelized cost by year.
$levcost_npvNamed numeric – NPV-weighted average LCOE.
$cost_breakdowndata.frame – tidy cost components by year. Components:
eac,fixom,varom,supply,import,export(negative, a credit).$cost_breakdown_npvdata.frame – NPV-weighted component breakdown.
$cost_yearlydata.frame – wide undiscounted cost table with activity, capacity, per-commodity outputs and inputs.
$levcost_per_actdata.frame or
NULL.$frontierdata.frame or
NULL(requiresfrontier = TRUEand multi-commodity grouped output).$scenarioThe solved
scenarioobject.
For a list of technology objects: a named list of class
"levcost_list".
For a technology declaring vintages and/or clusters: a
named list of class "levcost_variants" (which inherits
"levcost_list"), holding one full "levcost" result per
variant, keyed by variant name ("PWR_VIN2030"). Each variant is
priced in its own region so the variants cannot serve each other's demand;
without that isolation they compete for one unit of demand and the result
silently sums across them. The stacked tables are reachable with
levcost_by_variant(), and autoplot() compares the variants.
$frontier is NULL on this path – the frontier corners are a
per-commodity sweep, orthogonal to variants, and are not fanned out.
A technology with no vintages or clusters is unaffected and still returns a
single "levcost" object.
Details
technologya minimal single-technology energyRt model is built around the technology, solved, and the LCOE derived from the resulting cost and production variables.
repository/modelgive the technology
name; the method selects the related commodity and supply objects from the container and prices the named technology as above. If an input commodity has no supply in the container, it returnsNULLwith a message unlessautocomplete = TRUE(which adds a zero-cost /fuel_costssupply). Themodelmethod also takes the calendar, region, horizon and discount rate from the model's configuration (each overridable).scenarioan ex-post cost of the named process in the solved scenario: the discounted sum of its own costs (annualised investment, fixed and variable O&M, plus attributed fuel cost) divided by its discounted output. The process may be a
technology,storageortrade; each reads its own solved variables (vTechOut/vStorageOut/vTradeIrand the matching*Eac/*Fixom/*Varom). For atradethe denominator is what ARRIVES, i.e.vTradeIrtimes the route efficiency.
On the scenario path, fuel is attributed from the process's own
input variable and priced from the supply objects in the model. A
commodity with no supply – anything the model produces itself,
which is the usual case for a store's charging electricity – is charged
at ZERO here, because what it is worth is the commodity balance's dual and
not a slot. The scenario path therefore reports a store's OWN cost per
unit discharged, not its delivered cost; use levcost() on the
storage object with price = for the latter. Likewise a
technology with a grouped input (whose per-commodity consumption
is not a solution variable) reports no fuel component.
Examples
if (FALSE) { # \dontrun{
lc <- levcost(my_tech, discount = 0.07, base_year = 2025)
lc$levcost_npv
lc$cost_breakdown
autoplot(lc)
autoplot(lc, type = "npv")
# List of technologies (each solved independently):
lc_list <- levcost(list(tech1, tech2), discount = 0.07)
autoplot(lc_list, type = "npv")
} # }
