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.
Thinking About Demand & Supply
Key things to think about are:
What kinds of energy demands does each sector have, and how will those evolve in response to policy scenarios?
What fuels/energy carriers can be used to meet each of those energy demands (electricity, fossil fuels, biofuels, etc.)?
What are the costs & emissions impacts associated with meeting those energy demands?
When using electricity as an energy carrier, what does the hourly (or sub-hourly) demand profile look like (i.e., load shaping)?
Assets
- class Asset
An Asset is anything with a cost & quantity.
- Fields:
annualized_fixed_om_cost (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries)
asset_groups (dict[str, new_modeling_toolkit.core.linkage.AssetToAssetGroup])
caiso_tx_constraints (dict[str, new_modeling_toolkit.core.linkage.AssetToCaisoTxConstraint])
cumulative_retired_capacity (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries | None)
custom_constraints (dict[str, new_modeling_toolkit.core.three_way_linkage.CustomConstraintLinkage])
elcc_surfaces (dict[str, new_modeling_toolkit.core.linkage.AssetToELCC])
emissions_policies (dict[str, new_modeling_toolkit.core.linkage.EmissionsContribution])
erm_policies (dict[str, new_modeling_toolkit.core.linkage.ERMContribution])
include (Annotated[bool, Metadata(category=FieldCategory.BUILD)])
min_operational_capacity (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries | None)
operational_capacity (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries | None)
planned_capacity (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries)
prm_policies (dict[str, new_modeling_toolkit.core.linkage.ReliabilityContribution])
retired_capacity (new_modeling_toolkit.core.temporal.timeseries.NumericTimeseries | None)
zones (dict[str, new_modeling_toolkit.core.linkage.AssetToZone])
- 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 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 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 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 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_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.
- 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 operational_group: AssetGroup | None
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.
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:
Upper case Latin letters & some Greek letters refer to input parameters:
Lower case Latin letters & some Greek letters refer to decision variables & expressions:
Attention
If you notice issues with the written formulation, please leave a comment on the page so that we can fix it!