Overview

A System is the basic data structure that defines the energy system that is being modeled. Depending on use-case, this energy system can encompass the electric sector or multiple sectors of the economy, similar to the Sankey diagram below.

llnl-sankey

Thinking About Demand & Supply

Key things to think about are:

  1. What kinds of energy demands does each sector have, and how will those evolve in response to policy scenarios?

  2. What fuels/energy carriers can be used to meet each of those energy demands (electricity, fossil fuels, biofuels, etc.)?

  3. What are the costs & emissions impacts associated with meeting those energy demands?

  4. When using electricity as an energy carrier, what does the hourly (or sub-hourly) demand profile look like (i.e., load shaping)?

pathways-supply-demand

Assets

class Asset

An Asset is anything with a cost & quantity.

Fields:
field annual_energy_policies: dict[str, AnnualEnergyStandardContribution] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field annualized_capital_cost: float = 0
Constraints:
  • category = FieldCategory.BUILD

  • units = dollar / kiloW_year

  • excel_short_title = Capital Cost

  • warning_bounds = (0, 1000)

  • show_year_headers = True

  • default_exclude = False

field annualized_fixed_om_cost: NumericTimeseries [Optional]
Constraints:
  • category = FieldCategory.BUILD

  • units = dollar / kiloW_year

  • excel_short_title = Fixed O&M

  • warning_bounds = (0, 100)

  • show_year_headers = True

  • default_exclude = False

field asset_groups: dict[str, AssetToAssetGroup] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field attr_path: str | pathlib.Path | None = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/e3-resolve/checkouts/latest/docs/source')

the path to the attributes file

field build_year: Timestamp = Timestamp('2000-01-01 00:00:00') (alias 'commission_date')
Constraints:
  • category = FieldCategory.BUILD

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field caiso_tx_constraints: dict[str, AssetToCaisoTxConstraint] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field can_build_new: bool = False

Whether resource can be expanded (for now only linear capacity expansion).

Constraints:
  • category = FieldCategory.BUILD

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field can_retire: bool = False

Whether resource can be retired. By default, resources cannot be retired.

Constraints:
  • category = FieldCategory.BUILD

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field class_name: str | None = None
field cumulative_retired_capacity: NumericTimeseries | None = None
field custom_constraints: dict[str, CustomConstraintLinkage] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = 3

  • default_exclude = True

field elcc_surfaces: dict[str, AssetToELCC] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field emissions_policies: dict[str, EmissionsContribution] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field erm_policies: dict[str, ERMContribution] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field hourly_energy_policies: dict[str, HourlyEnergyStandardContribution] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field include: Annotated[bool, Metadata(category=FieldCategory.BUILD)] = True

Include component in system.

Constraints:
  • category = FieldCategory.BUILD

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field integer_build_increment: float | None = None

If not None, consider integer (rather than linear) build decisions. If set equal to potential, this will force an all or nothing choice. Otherwise, this can be used to build certain increments of assets

Constraints:
  • ge = 0

  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field mean_time_to_repair: float | None = None

Mean time to repair

Constraints:
  • category = FieldCategory.RELIABILITY

  • units = hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field min_operational_capacity: NumericTimeseries | None = None

These three attributes are outputs, not inputs. They are initialized to None and are updated to their chosen optimal values after the RESOLVE model is solved. The attributes are used to give build and retirement decisions to a model run in production simulation mode.

Minimum required operational capacity (planned+selected) by model year for this asset

Constraints:
  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field name: str | tuple [Required]
field operational_capacity: NumericTimeseries | None = None
field physical_lifetime: int = 100

Number of years after commission date that asset is operational.

Constraints:
  • ge = 0

  • category = FieldCategory.BUILD

  • units = year

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field planned_capacity: NumericTimeseries [Optional]
Constraints:
  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field potential: float | None = inf
Constraints:
  • ge = 0

  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field prm_policies: dict[str, ReliabilityContribution] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field random_seed: int | None = None

Random seed

Constraints:
  • category = FieldCategory.RELIABILITY

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field retired_capacity: NumericTimeseries | None = None
field selected_capacity: float | None = None
field stochastic_outage_rate: float | None = None

Stochastic forced outage rate

Constraints:
  • category = FieldCategory.RELIABILITY

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field vintage_parent_group: str | None = None
field zones: dict[str, AssetToZone] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

check_if_operationally_equal(other: Asset, check_linkages: bool = True, fields_to_check: list[str] | None = None) bool

Check is this Asset is “operationally equivalent” to another Asset.

This check is used when automatically grouping resources together in RESOLVE for the construction of operational constraints. See AssetGroup for more information.

Operational equivalence is defined by two categories. First, all the “operational attributes” of the Assets (which are defined in a class variable) must be equal. Any attribute whose value may impact the optimal operational decisions for the assets have to be equal. For example, they must have equal power_output_max profiles, among other things. Second, they must have equivalent “operational linkages” - see check_operational_linkages_are_equal for more information.

Parameters:
  • other – the Resource to compare to

  • check_linkages – whether linkages should be considered in determining operational equality

  • fields_to_check – an optional list of a subset of fields to check

Returns:

whether the two Resources are operationally equal

Return type:

bool

check_operational_linkages_are_equal(other: Asset) bool

Checks whether two Assets have equivalent “operational linkages.”

In order for two Assets to be “operationally equivalent,” one condition is that any linkages which may impact

the operational decisions of the resource must also be equal. For example, if a Resource is linked to an

AnnualEmissionsStandard, then its dispatch will be partially influenced by this emissions target, so the other Resource must also be linked to that policy.

Parameters:

other – the other Asset to compare against

Returns:

whether or not the two components have equivalent operational linkages

Return type:

equal

revalidate()

Abstract method to run additional validations after Linkage.announce_linkage_to_instances.

save_capacity_expansion_results()
save_cumulative_retired_capacity()

Save the resulting retired capacity after the RESOLVE model has been solved.

save_operational_capacity()

Save the resulting operational capacity after the RESOLVE model has been solved.

save_retired_capacity()

Save the resulting retired capacity after the RESOLVE model has been solved.

save_selected_capacity()

Save the resulting selected capacity after the RESOLVE model has been solved.

SAVE_PATH: ClassVar[str] = 'assets'
property annual_results_column_order

This property defines the ordering of columns in the Asset annual results summary out of Resolve. The name of the model field or formulation_block pyomo component can be used.

property has_operational_rules: bool

Property for whether this asset has operational rules (i.e., it is not a part of an operational group)

property non_operational_linkages
property operational_attributes
property operational_group: AssetGroup | None
property operational_group_name: str
property operational_linkages
property operational_three_way_linkages
property outage_distribution
property policies
property zone_names_string: str

This property concatenates the keys in the zones dictionary for results reporting.


Formulation
Asset._operational_capacity(block, modeled_year: Timestamp)

The amount of operational new-build capacity in each year

Asset._physical_lifetime_constraint(block: Block, modeled_year: Timestamp)

The Asset must be retired after the end of its physical lifetime

Asset._potential_constraint(block: Block, modeled_year)

The total amount of planned and new-build capacity cannot exceed the available potential

Asset._retired_capacity_max_constraint(block: Block, modeled_year: Timestamp)

Upper bound on the amount of retired capacity in each year. Retired capacity in a given year cannot exceed the operational capacity in the previous year, and capacity cannot be retired before the build year of the Asset.

Tests

Assets are one of the foundational modeling components in kit, standardizing how we interact with resource costs, sizes & build years.

%%{ init: { "theme": "base", "themeVariables": { 'primaryColor': '#E2ECF0', 'primaryTextColor': '#034E6E', 'primaryBorderColor': '#E2ECF0', 'lineColor': '#BFBFBF', 'secondaryColor': '#E2ECF0', 'tertiaryColor': '#E2ECF0', 'fontFamily': 'rubik' }, 'flowchart': { 'curve': 'bumpX' } } }%% flowchart LR %% NODES %% TIER 1 asset(" <font size=4.25><b>Asset</b></font> A physical asset with a defined size, cost & build year. ") style asset fill:#555555,stroke:#555555,color:#ffffff %% TIER 2 generic(" <font size=4.25><b>Generic</b></font> A generic generator. ") click generic "./electric/resources/index.html" tx_paths(" <font size=4.25><b>TxPath</b></font> A path between two electric zones. ") click tx_paths "./electric/resources/tx_paths.html" %% TIER 3 thermal(" <font size=4.25><b>Thermal</b></font> A fuel-burning generator. ") click thermal "./electric/resources/thermal.html" variable(" <font size=4.25><b>Variable</b></font> Alias for <b>Generic</b>, generally used for solar & wind resources. ") click variable "./electric/resources/variable.html" hydro(" <font size=4.25><b>Hydro</b></font> Alias for <b>Generic</b>, typically utilizing energy budgets. ") click hydro "./electric/resources/hydro.html" unit_commitment(" <font size=4.25><b>Unit Commitment</b> (UC)</font> A generator with commitment variables and min up-/down- time tracking. ") click unit_commitment "./electric/resources/unit_commitment.html" storage(" <font size=4.25><b>Energy Storage</b></font> An resource that draw power from the grid, store energy with losses & provide power. ") click storage "./electric/resources/storage.html" %% TIER 4 thermal_uc(" <font size=4.25><b>Thermal UC</b></font> A fuel-burning generator with unit commitment constraints. ") click thermal_uc "./electric/resources/thermal.html" shed_dr(" <font size=4.25><b>Shed Demand Response</b></font> A resource with a limited number of calls per day, month and/or year. ") click shed_dr "./electric/resources/shed_dr.html" %% TIER 5 flex_loads(" <font size=4.25><b>Flexible Loads</b></font> A resource that can shift its demand for a limited number of hours. ") click flex_loads "./electric/resources/flex_loads.html" %% EDGES asset o--o generic asset o--o tx_paths generic o--o hydro generic o--o variable generic o--o thermal generic o--o unit_commitment generic o--o storage thermal o--o thermal_uc unit_commitment o--o thermal_uc unit_commitment o--o shed_dr storage o--o flex_loads shed_dr o--o flex_loads

Asset inheritance diagram
(click any of the blue boxes in the diagram to jump to the relevant documentation)

this is sort of hard to explain. basically it sort of exists, but only sparingly because the “starting point” for how resolve was designed like 8 years ago was that “resources” represent aggregated things, rather than “real physical generating units”.

probably most succinctly, all operations are aggregated to the resource level (so no vintage indices), but builds are by vintage (since you can select new capacity each year)

Math Nomenclature

Throughout the documentation, we will try to use consistent nomenclature:

“Blackboard bold” letters generally refer to sets:

Sets

Symbol

Description

\(\mathbb{A}\)

Assets

\(\mathbb{A}^{r}\)

Resources

\(\mathbb{A}^{tx}\)

Transmission paths

\(\mathbb{D}({s \in \mathbb{S}})\)

Demands (for each sector, e.g., electric sector load components)

\(\mathbb{ELCC}\)

ELCC surfaces

\(\mathbb{F}\)

Fuels

\(\mathbb{P}\)

Policies

\(\mathbb{R}\)

Electric sector operating reserves

\(\mathbb{S}\)

Sectors

\(\mathbb{T}({w \in \mathbb{W}})\)

Timesteps (for each dispatch window)

\(\mathbb{W}\)

Dispatch windows

\(\mathbb{Y}^{m}\)

Modeled years

\(\mathbb{Y}^{w}\)

Weather years

Upper case Latin letters & some Greek letters refer to input parameters:

Parameters

Symbol

Examples

Description

\(C\)

\(C^{f}, C^{v}\)

Costs

\(\eta\)

\(\eta^{in}, \eta^{out}, \eta^{idle} \)

Efficiency losses (charging, discharging, idle/parasitic)

\(\lambda\)

Price (e.g., GHG price)

\(\hat{D}\)

Demand derate (%) in timestep (e.g., for outages, seasonal derates)

\(\check{D}\)

Demand minimum rating (%) in timestep

\(\hat{P}\)

Production derate (%) in timestep (e.g., for outages, seasonal derates, generation profiles)

\(\check{P}\)

Production minimum rating (%) in timestep

\(\bar{P}\)

\(\bar{P}_{d}, \bar{P}_{m}, \bar{P}_{y}\)

Average daily, monthly or annual production (i,.e., normalized energy budget)

\(Y^{build}\)

Build year of asset

\(I\)

\(I^{build}, I^{retire}\)

Boolean indicators whether model can choose to build or retire resource (v.s., input trajectory)

\(L\)

\(\hat{L}^{p},\hat{L}^{f}, {L}_{y}\)

Physical & financial lifetimes of asset, and current age of asset (in years)

Lower case Latin letters & some Greek letters refer to decision variables & expressions:

Decision Variables & Expressions

Symbol

Examples

Description

\(\lambda\)

Constraint dual (shadow price)

\(\xi\)

\(\xi^{+}, \xi^{-}\)

Slack variables

\(d\)

\(d^{fuel}, d^{e}\)

Demand (e.g., fuel demand in timestep, storage charging demand)

\(p\)

Production (e.g., storage discharging/power production)

\(\hat{\hat{p}}\)

Operational nameplate (power) capacity

\(r\)

\(r^{spin}\)

Operating reserves provided

\(\hat{\hat{soc}}\)

Nameplate storage capacity

\(soc\)

Storage state-of-charge

Attention

If you notice issues with the written formulation, please leave a comment on the page so that we can fix it!