Energy Storage

Data Fields & Method Definitions
New
class StorageResource

Resource with storage capacity.

Adds state-of-charge tracking.

It feels like BatteryResource could be composed of a GenericResource + Asset (that represents the storage costs), but need to think about this more before implementing.

Fields:
field allow_inter_period_sharing: Annotated[bool, Metadata(category=FieldCategory.OPERATIONS)] = False

For resources & fuel storage resources that have chronological energy storage capability, enable inter-period energy/state-of-charge tracking. For resources with ramp rates, enable inter-period tracking of ramp constraints.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field annual_energy_policies: Annotated[dict[str, linkage.AnnualEnergyStandardContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
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: Annotated[float, Metadata(category=FieldCategory.BUILD, units=units.dollar / units.kW_year, excel_short_title='Capital Cost', warning_bounds=(0, 1000))] = 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: Annotated[ts.NumericTimeseries, Metadata(category=FieldCategory.BUILD, units=units.dollar / units.kW_year, excel_short_title='Fixed O&M', warning_bounds=(0, 100))] [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 annualized_storage_capital_cost: float = 0.0 (alias 'new_storage_annual_fixed_cost_dollars_per_kwh_yr_by_vintage')

$/kWh-yr. For new storage capacity, the annualized fixed cost of investment. This is an annualized version of an overnight cost that could include financing costs ($/kWh-year).

Constraints:
  • units = dollar / kiloWh_year

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field annualized_storage_fixed_om_cost: NumericTimeseries [Optional] (alias 'new_storage_capacity_fixed_om_by_vintage')

$/kWh-yr. For the planned portion of the resource’s storage capacity, the ongoing fixed O&M cost

Constraints:
  • units = dollar / kiloWh_year

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field asset_groups: Annotated[dict[str, linkage.AssetToAssetGroup], Metadata(linkage_order='to')] = {}
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: Annotated[pd.Timestamp, Metadata(category=FieldCategory.BUILD)] = 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: Annotated[dict[str, linkage.AssetToCaisoTxConstraint], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field can_build_new: Annotated[bool, Metadata(category=FieldCategory.BUILD)] = 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: Annotated[bool, Metadata(category=FieldCategory.BUILD)] = 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 charging_efficiency: FractionalTimeseries [Optional]

[RESOLVE, RECAP]. % of Charging MW. Efficiency losses associated with charging (increasing load), typically expressed as a % of nameplate unless charging power specified to increase storage “state of charge”.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field charging_efficiency__type: TimeseriesType | None = None

Whether the charging_efficiency profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • 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: ts.NumericTimeseries | None = None
field cumulative_retired_storage_capacity: NumericTimeseries | None = None
field custom_constraints: Annotated[dict[str, CustomConstraintLinkage], Metadata(linkage_order=3, default_exclude=True)] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = 3

  • default_exclude = True

field discharging_efficiency: FractionalTimeseries [Optional]

[RESOLVE, RECAP]. % of Discharging MW, Efficiency losses associated with discharging (providing power), typically expressed as a % of nameplate unless charging power specified, taking energy out of storage “state of charge”.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field discharging_efficiency__type: TimeseriesType | None = None

Whether the discharging_efficiency profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field duration: float [Required] (alias 'storage_duration')

[RESOLVE, RECAP]. Hours of operational time the battery can operate at a specified power level before it runs out of energy. Required when resource is an operational group or does not belong to one.

Constraints:
  • ge = 0

  • category = FieldCategory.OPERATIONS

  • units = hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = False

  • default_exclude = False

field duration_constraint: StorageDurationConstraint = StorageDurationConstraint.FIXED

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.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field elcc_surfaces: Annotated[dict[str, linkage.AssetToELCC], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field emissions_policies: Annotated[dict[str, linkage.EmissionsContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field energy_budget_annual: Annotated[ts.FractionalTimeseries | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.year, excel_short_title='Annual')] = None

Annual fraction of energy capacity allowed for annual dispatch.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / year

  • excel_short_title = Annual

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field energy_budget_daily: Annotated[ts.FractionalTimeseries | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.day, excel_short_title='Daily')] = None

Daily fraction of energy capacity allowed for daily dispatch.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / day

  • excel_short_title = Daily

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field energy_budget_monthly: Annotated[ts.FractionalTimeseries | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.month, excel_short_title='Monthly')] = None

Monthly fraction of energy capacity allowed for monthly dispatch]

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / month

  • excel_short_title = Monthly

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field erm_policies: Annotated[dict[str, linkage.ERMContribution], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field hourly_energy_policies: Annotated[dict[str, linkage.HourlyEnergyStandardContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
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: Annotated[float | None, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] = 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: Annotated[float | None, Metadata(category=FieldCategory.RELIABILITY, units=units.hour)] = 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: Annotated[ts.NumericTimeseries | None, Metadata(units=units.MW)] = 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: ts.NumericTimeseries | None = None
field operational_storage_capacity: NumericTimeseries | None = None
field outage_distributions: Annotated[dict[str, linkage.ResourceToOutageDistribution], Metadata(linkage_order='to')] [Optional]

This input links resources to a specific OutageDistribution component. When a random or planned outage occurs, the outage distribution dictates what the possible outage state are for each resource. For example, if a unit is either on or offline, then it’s outage distribution is 0,1.

Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field outage_profile: Annotated[ts.FractionalTimeseries, Metadata(category=FieldCategory.OPERATIONS, units=units.unitless, excel_short_title='Outage', default_exclude=True)] [Optional]

Fixed profile of simulated outages, where a value of 1.0 represents availability of full nameplate capacity and a value less than 1.0 represents a partial outage.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = unitless

  • excel_short_title = Outage

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = True

field outage_profile__type: Annotated[TimeseriesType | None, Metadata(category=FieldCategory.OPERATIONS)] = None

Whether the outage_profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field parasitic_loss: float = 0

[Storage] Hourly state of charge losses.

Constraints:
  • ge = 0

  • le = 1

  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field physical_lifetime: Annotated[int, Metadata(category=FieldCategory.BUILD, units=units.year)] = 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: Annotated[ts.NumericTimeseries, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] [Optional]
Constraints:
  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field potential: Annotated[float | None, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] = inf
Constraints:
  • ge = 0

  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_input_max: FractionalTimeseries [Optional] (alias 'increase_load_potential_profile')

Fixed shape of resource’s potential power draw (e.g. flat shape for storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = unitless

  • excel_short_title = Max Input Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_input_max__type: TimeseriesType | None = None

Whether the power_input_max profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_input_min: FractionalTimeseries [Optional]

Fixed shape of resource’s potential power draw (e.g. flat shape for storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = unitless

  • excel_short_title = Min Input Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_input_min__type: TimeseriesType | None = None

Whether the power_input_min profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_max: Annotated[ts.FractionalTimeseries, Metadata(category=FieldCategory.OPERATIONS, excel_short_title='Max Output Profile')] [Optional] (alias 'provide_power_potential_profile')

Fixed shape of resource’s potential power output (e.g., solar or wind shape or flat shapefor firm resources or storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title = Max Output Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_max__type: Annotated[TimeseriesType | None, Metadata(category=FieldCategory.OPERATIONS)] = None

Whether the power_output_max profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_min: Annotated[ts.FractionalTimeseries, Metadata(category=FieldCategory.OPERATIONS, excel_short_title='Min Output Profile')] [Optional] (alias 'provide_power_min_profile')

Fixed shape of resource’s potential power output (e.g., solar or wind shape or flat shapefor firm resources or storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title = Min Output Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_min__type: Annotated[TimeseriesType | None, Metadata(category=FieldCategory.OPERATIONS)] = None

Whether the power_output_min profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field prm_policies: Annotated[dict[str, linkage.ReliabilityContribution], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field production_tax_credit: Annotated[float | None, Metadata(units=units.dollar / units.MWh, excel_short_title='PTC')] = None
Constraints:
  • units = dollar / megawatt_hour

  • excel_short_title = PTC

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ptc_term: Annotated[int | None, Metadata(units=units.years, excel_short_title='PTC Term')] = None
Constraints:
  • units = year

  • excel_short_title = PTC Term

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_1_hour: Annotated[float | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.hour)] = None

Single-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_2_hour: Annotated[float | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.hour / 2)] = None

Two-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.5 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_3_hour: Annotated[float | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.hour / 3)] = None

Three-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.3333333333333333 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_4_hour: Annotated[float | None, Metadata(category=FieldCategory.OPERATIONS, units=1 / units.hour / 4)] = None

Four-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.25 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field random_seed: Annotated[int | None, Metadata(category=FieldCategory.RELIABILITY)] = None

Random seed

Constraints:
  • category = FieldCategory.RELIABILITY

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field reserves: Annotated[dict[str, linkage.ResourceToReserve], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] [Optional]

This input links the resource to a specific reserve type that it can contribute to. For example, Storage can provide both regulation up and down, but might not provide non-spin reserves.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field resource_groups: Annotated[dict[str, linkage.ResourceToResourceGroup], Metadata(linkage_order='to')] [Optional]

This gives each resource a group for RECAP. Depending on the Resource class, the upsampling method could change. For example, with Solar and Wind, these will be upsampled using a day draw methodology.

Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field retired_capacity: ts.NumericTimeseries | None = None
field retired_storage_capacity: NumericTimeseries | None = None
field selected_capacity: float | None = None
field selected_storage_capacity: float | None = None
field state_of_charge_min: float = 0

[Storage] Minimum state-of-charge at any given time.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field stochastic_outage_rate: Annotated[float | None, Metadata(category=FieldCategory.RELIABILITY)] = 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 variable_cost_power_input: NumericTimeseries [Optional] (alias 'variable_cost_increase_load')

Variable O&M cost per MWh generated.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = dollar / megawatt_hour

  • excel_short_title = VO&M In

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field variable_cost_power_output: Annotated[ts.NumericTimeseries, Metadata(category=FieldCategory.OPERATIONS, units=units.dollar / units.MWh, excel_short_title='VO&M Out')] [Optional] (alias 'variable_cost_provide_power')

Variable O&M cost per MWh charged.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = dollar / megawatt_hour

  • excel_short_title = VO&M Out

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field vintage_parent_group: str | None = None
field zones: Annotated[dict[str, linkage.ResourceToZone], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

apply_parasitic_loss(state_of_charge, period_hrs)
check_if_operationally_equal(other)

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

clear_calculated_properties()

Clear the property cache so scaled profiles are recalculated after rescaling

revalidate()

Abstract method to run additional validations after Linkage.announce_linkage_to_instances.

save_capacity_expansion_results()
save_cumulative_retired_storage_capacity()

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

save_operational_storage_capacity()

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

save_retired_storage_capacity()

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

save_selected_storage_capacity()

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

SAVE_PATH: ClassVar[str] = 'resources/storage'
property imax_profile: Series
property imin_profile: Series
property planned_storage_capacity: Series

This property is for storage only now.

property scaled_SOC_max_profile: Dict[int, Series]

This property is for storage only now.

property scaled_imax_profile: Dict[int, Series]
property scaled_imin_profile: Dict[int, Series]
Inherited
class GenericResource
Fields:
field allow_inter_period_sharing: bool = False

For resources & fuel storage resources that have chronological energy storage capability, enable inter-period energy/state-of-charge tracking. For resources with ramp rates, enable inter-period tracking of ramp constraints.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field annual_energy_policies: Annotated[dict[str, linkage.AnnualEnergyStandardContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
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: Annotated[float, Metadata(category=FieldCategory.BUILD, units=units.dollar / units.kW_year, excel_short_title='Capital Cost', warning_bounds=(0, 1000))] = 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: Annotated[ts.NumericTimeseries, Metadata(category=FieldCategory.BUILD, units=units.dollar / units.kW_year, excel_short_title='Fixed O&M', warning_bounds=(0, 100))] [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: Annotated[dict[str, linkage.AssetToAssetGroup], Metadata(linkage_order='to')] = {}
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: Annotated[pd.Timestamp, Metadata(category=FieldCategory.BUILD)] = 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: Annotated[dict[str, linkage.AssetToCaisoTxConstraint], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field can_build_new: Annotated[bool, Metadata(category=FieldCategory.BUILD)] = 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: Annotated[bool, Metadata(category=FieldCategory.BUILD)] = 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: ts.NumericTimeseries | None = None
field custom_constraints: Annotated[dict[str, CustomConstraintLinkage], Metadata(linkage_order=3, default_exclude=True)] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = 3

  • default_exclude = True

field elcc_surfaces: Annotated[dict[str, linkage.AssetToELCC], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field emissions_policies: Annotated[dict[str, linkage.EmissionsContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field energy_budget_annual: FractionalTimeseries | None = None

Annual fraction of energy capacity allowed for annual dispatch.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / year

  • excel_short_title = Annual

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field energy_budget_daily: FractionalTimeseries | None = None

Daily fraction of energy capacity allowed for daily dispatch.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / day

  • excel_short_title = Daily

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field energy_budget_monthly: FractionalTimeseries | None = None

Monthly fraction of energy capacity allowed for monthly dispatch]

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / month

  • excel_short_title = Monthly

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field erm_policies: Annotated[dict[str, linkage.ERMContribution], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field hourly_energy_policies: Annotated[dict[str, linkage.HourlyEnergyStandardContribution], Metadata(linkage_order='to', category=FieldCategory.OPERATIONS)] = {}
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: Annotated[float | None, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] = 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: Annotated[float | None, Metadata(category=FieldCategory.RELIABILITY, units=units.hour)] = 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: Annotated[ts.NumericTimeseries | None, Metadata(units=units.MW)] = 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: ts.NumericTimeseries | None = None
field outage_distributions: dict[str, ResourceToOutageDistribution] [Optional]

This input links resources to a specific OutageDistribution component. When a random or planned outage occurs, the outage distribution dictates what the possible outage state are for each resource. For example, if a unit is either on or offline, then it’s outage distribution is 0,1.

Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field outage_profile: FractionalTimeseries [Optional]

Fixed profile of simulated outages, where a value of 1.0 represents availability of full nameplate capacity and a value less than 1.0 represents a partial outage.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = unitless

  • excel_short_title = Outage

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = True

field outage_profile__type: TimeseriesType | None = None

Whether the outage_profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field physical_lifetime: Annotated[int, Metadata(category=FieldCategory.BUILD, units=units.year)] = 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: Annotated[ts.NumericTimeseries, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] [Optional]
Constraints:
  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field potential: Annotated[float | None, Metadata(category=FieldCategory.BUILD, units=units.megawatt)] = inf
Constraints:
  • ge = 0

  • category = FieldCategory.BUILD

  • units = megawatt

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_max: FractionalTimeseries [Optional] (alias 'provide_power_potential_profile')

Fixed shape of resource’s potential power output (e.g., solar or wind shape or flat shapefor firm resources or storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title = Max Output Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_max__type: TimeseriesType | None = None

Whether the power_output_max profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_min: FractionalTimeseries [Optional] (alias 'provide_power_min_profile')

Fixed shape of resource’s potential power output (e.g., solar or wind shape or flat shapefor firm resources or storage resources). Used in conjunction with new_modeling_toolkit.common.resource.Resource.curtailable.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title = Min Output Profile

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field power_output_min__type: TimeseriesType | None = None

Whether the power_output_min profile data is of type ‘weather year’, ‘modeled year’, ‘month-hour’, ‘season-hour’, or ‘monthly’

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field prm_policies: Annotated[dict[str, linkage.ReliabilityContribution], Metadata(linkage_order='to')] = {}
Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field production_tax_credit: float | None = None
Constraints:
  • units = dollar / megawatt_hour

  • excel_short_title = PTC

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ptc_term: int | None = None
Constraints:
  • units = year

  • excel_short_title = PTC Term

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_1_hour: float | None = None

Single-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 1 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_2_hour: float | None = None

Two-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.5 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_3_hour: float | None = None

Three-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.3333333333333333 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field ramp_rate_4_hour: float | None = None

Four-hour ramp rate. When used in conjunction with the other ramp rate limits (1-4 hour), a resource’s dispatch will be constrained by all applicable ramp rate limits on a rolling basis.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = 0.25 / hour

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field random_seed: Annotated[int | None, Metadata(category=FieldCategory.RELIABILITY)] = None

Random seed

Constraints:
  • category = FieldCategory.RELIABILITY

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

field reserves: dict[str, ResourceToReserve] [Optional]

This input links the resource to a specific reserve type that it can contribute to. For example, Storage can provide both regulation up and down, but might not provide non-spin reserves.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field resource_groups: dict[str, ResourceToResourceGroup] [Optional]

This gives each resource a group for RECAP. Depending on the Resource class, the upsampling method could change. For example, with Solar and Wind, these will be upsampled using a day draw methodology.

Constraints:
  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

field retired_capacity: ts.NumericTimeseries | None = None
field selected_capacity: float | None = None
field stochastic_outage_rate: Annotated[float | None, Metadata(category=FieldCategory.RELIABILITY)] = 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 variable_cost_power_output: NumericTimeseries [Optional] (alias 'variable_cost_provide_power')

Variable O&M cost per MWh charged.

Constraints:
  • category = FieldCategory.OPERATIONS

  • units = dollar / megawatt_hour

  • excel_short_title = VO&M Out

  • warning_bounds = (None, None)

  • show_year_headers = True

  • default_exclude = False

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

  • units =

  • excel_short_title =

  • warning_bounds = (None, None)

  • show_year_headers = True

  • linkage_order = to

  • default_exclude = False

clear_calculated_properties()

Clear the property cache so scaled profiles are recalculated after rescaling

get_ramp_MW(modeled_year: Timestamp, timepoint_1: Tuple[Timestamp, Timestamp], timepoint_2: Tuple[Timestamp, Timestamp])

Change in output MW between two timepoints

revalidate()

Abstract method to run additional validations after Linkage.announce_linkage_to_instances.

SAVE_PATH: ClassVar[str] = 'resources/generic'
property annual_results_column_order

This property defines the ordering of columns in the Asset annual results summary out of Resolve.

property has_energy_budget: bool
property outage_distribution: OutageDistribution | None
property pmax_profile: Series
property pmin_profile: Series
property production_tax_credit_ts: NumericTimeseries
property resource_group: ResourceGroup | None
property results_reporting_category
property results_reporting_folder
property scaled_annual_energy_budget
property scaled_daily_energy_budget
property scaled_monthly_energy_budget
property scaled_pmax_profile: Dict[int, Series]
property scaled_pmin_profile

The StorageResources and HybridStorageResource class represent resources that both provide power and take power and energy capacity. These resources are typically described as “energy-limited resources” or ELRs.

The keystone feature in rebuilding resolve in kit in 2021 was to migrate to a more flexible formulation for storage energy tracking based on [1].

Recap

What are considered Energy-limited Resources?

Batteries are the most obvious technology that fits into this category, but as more ELRs emerge, this class can flexibly take on resources of different durations, round-trip efficiencies (RTE) and performance characteristics

Where do the data inputs go?

  1. Resource Attributes will be specified in the UI

  2. Custom attributes below can be specified as a timeseries, placed in data > profiles

    • Pmin Rating

    • Pmax Rating

    • Max Charging Rating (CSV file)

    • Daily Energy Budget

    • Annual Energy Budget

Important considerations when modeling storage:
  1. Symmetric or Asymmetric round-trip efficiency (RTE)

  2. Total energy capacity / duration relative to RTE

  1. is the 4-hr duration inclusive of RTE losses?

  1. Forced outage rate assumption

  1. During the Summer of Sept 2022 when CAISO avoided a near black-out, the 2GW storage fleet experienced unplanned outages of ~10% of the total nameplate

In Recap, StorageResource are considered energy-limited resources, a special class of resources in Recap that has two types of dispatch: Heuristic or Optimized dispatch.