Skip to content

Quickstart reserves #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: next_release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SYNOPSIS
switch solve --verbose --log-run

This example extends spinning_reserves by adding quickstart reserve requirements.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
base_financial_year,interest_rate,discount_rate
2015,0.07,0.05
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
load_zone,fuel,period,fuel_cost
South,NaturalGas,2010,4
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fuel,co2_intensity,upstream_co2_intensity
NaturalGas,0.05306,0
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GENERATION_PROJECT,build_year,gen_overnight_cost,gen_fixed_om
S-Geothermal,1998,5524200,0.0
S-NG_CC,2000,1143900,5868.3
S-NG_GT,1990,605430,4891.8
S-NG_GT,2002,605430,4891.8
S-Central_PV-1,2001,2334300,41850.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
GENERATION_PROJECT,build_year,gen_predetermined_cap
S-Geothermal,1998,2.0
S-NG_CC,2000,7.0
S-NG_GT,1990,3.0
S-NG_GT,2002,4.0
S-Central_PV-1,2001,3.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GENERATION_PROJECT,power_start_mw,power_end_mw,incremental_heat_rate_mbtu_per_mwhr,fuel_use_rate_mmbtu_per_h
S-NG_CC,40,.,.,269.4069
S-NG_CC,40,100.0,6.684885,.
S-NG_GT,0,.,.,0.1039
S-NG_GT,0,1.0,10.2861,.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GENERATION_PROJECT,gen_loading_level,gen_heat_rate_at_loading_level
S-NG_CC,0.4,2.694069
S-NG_CC,1,6.705
S-NG_GT,0,0.1039
S-NG_GT,1,10.39
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GENERATION_PROJECT,gen_dbid,gen_tech,gen_load_zone,gen_connect_cost_per_mw,gen_capacity_limit_mw,gen_max_age,gen_min_build_capacity,gen_scheduled_outage_rate,gen_forced_outage_rate,gen_is_variable,gen_is_baseload,gen_is_cogen,gen_variable_om,gen_energy_source,gen_full_load_heat_rate,gen_unit_size,gen_min_load_fraction,gen_startup_fuel,gen_startup_om,gen_min_downtime,gen_can_provide_spinning_reserves
S-Geothermal,33,Geothermal,South,134222.0,3.0,30,0,0.0075,0.0241,0,1,0,28.83,Geothermal,.,.,.,.,.,.,0
S-NG_CC,34,NG_CC,South,57566.6,.,20,0,0.04,0.06,0,0,0,3.4131,NaturalGas,6.705,1.0,0.4,9.16,10.3,12.0,1
S-NG_GT,36,NG_GT,South,57566.6,.,20,0,0.04,0.06,0,0,0,27.807,NaturalGas,10.39,.,0.0,0.22,0.86,.,1
S-Central_PV-1,41,Central_PV,South,74881.9,4.0,20,0,0.0,0.02,1,0,0,0.0,Solar,.,.,0.0,.,0.0,.,0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LOAD_ZONE,existing_local_td,local_td_annual_cost_per_mw
South,10,128040
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
LOAD_ZONE,TIMEPOINT,zone_demand_mw
South,1,3
South,2,8
South,3,10
South,4,7
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Core Modules
switch_model
switch_model.timescales
switch_model.financials
switch_model.balancing.load_zones
switch_model.energy_sources.properties
switch_model.generators.core.build
switch_model.generators.core.dispatch
switch_model.reporting
# Custom Modules
switch_model.transmission.local_td
switch_model.generators.core.commit.operate
switch_model.generators.core.commit.fuel_use
switch_model.energy_sources.fuel_costs.simple
switch_model.balancing.operating_reserves.areas
switch_model.balancing.operating_reserves.spinning_reserves
switch_model.balancing.operating_reserves.quickstart
#switch_model.reporting.dump
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
energy_source
Geothermal
Solar
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INVESTMENT_PERIOD,period_start,period_end
2010,2008,2012
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
contingency_safety_factor
1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.0.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
timepoint_id,timestamp,timeseries
1,2010011500,2010_all
2,2010011506,2010_all
3,2010011512,2010_all
4,2010011518,2010_all
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TIMESERIES,ts_period,ts_duration_of_tp,ts_num_tps,ts_scale_to_period
2010_all,2010,6,1,1826.25
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GENERATION_PROJECT,timepoint,gen_max_capacity_factor
S-Central_PV-1,1,0.0
S-Central_PV-1,2,0.61
S-Central_PV-1,3,1.0
S-Central_PV-1,4,0.4
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LOAD_ZONE,PERIOD,zone_expected_coincident_peak_demand
South,2010,10
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--spinning-requirement-rule 3+5
--unit-contingency
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
36406402.36853148
216 changes: 216 additions & 0 deletions switch_model/balancing/operating_reserves/quickstart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Copyright (c) 2015-2019 The Switch Authors. All rights reserved.
# Licensed under the Apache License, Version 2.0, which is in the LICENSE file.
"""
A simple model of quickstart reserves to accompany the spinning_reserves
modules. Patterns from the spinning reserves modules were followed where
practical to simplify implementation and review.

Unlike spinning reserves, this module does not currently implement
contingency-based requirements because I lack an immediate use case for that.
The contigency reserves methodology from spinning reserve modules could
probably be adapted readily if needed.

For more discussion of operating reserve considerations and modeling
approaches, see the spinning_reserves module.

To do (wish list):

1) Define additional rules for quickstart reserve requirements.
2) Add an optional parameter to specify how much capacity of a generation unit can be used to provide quickstart reserves (defaults to GenCapacity if units are MW, or 1.0 if units are fraction of available capacity). This could give us modeling flexibility to adapt to different definitions of quickstart reserves (some markets are more stringent than others), as well as to include different technologies. E.g. one might model a CCGT with the capability of providing quickstart reserves using only the Gas Turbines, or model a BESS system with the capability of providing quickstart reserves up to a certain fraction of its capacity (because the other fraction is reserved for energy arbitrage, for instance).

"""
import os
from pyomo.environ import *

dependencies = (
'switch_model.timescales',
'switch_model.balancing.load_zones',
'switch_model.balancing.operating_reserves.areas',
'switch_model.financials',
'switch_model.energy_sources.properties',
'switch_model.generators.core.build',
'switch_model.generators.core.dispatch',
'switch_model.generators.core.commit.operate',
)
optional_prerequisites = (
'switch_model.balancing.operating_reserves.spinning_reserves',
'switch_model.balancing.operating_reserves.spinning_reserves_advanced',
)

# Uncomment this section when more than one rule is implemented.
# def define_arguments(argparser):
# group = argparser.add_argument_group(__name__)
# group.add_argument('--quickstart-requirement-rule', default="3+5",
# dest='quickstart_requirement_rule',
# choices = ["3+5"],
# help=("Choose rules for quickstart reserves requirements as a function "
# "of variable renewable power and load. '3+5' requires 3%% of "
# "load and 5%% of variable renewable output, based on the "
# "heuristic described in the 2010 Western Wind and Solar "
# "Integration Study.")
# )


def define_dynamic_lists(mod):
"""
Quickstart_Reserve_Requirements is a list of model components that
contribute to quickstart reserve requirements in each balancing area and
timepoint.

Quickstart_Reserve_Provisions is a list of model components that help
satisfy spinning reserve requirements in each balancing area and
timepoint.

Each component in both lists needs to use units of MW and be indexed by:
(b, t) in BALANCING_AREA_TIMEPOINTS.
"""
mod.Quickstart_Reserve_Requirements = []
mod.Quickstart_Reserve_Provisions = []


def nrel_3_5_quickstart_reserve_requirements(mod):
"""
NREL35QuickstartRequirement[(b,t) in BALANCING_AREA_TIMEPOINTS] is
an expression for quickstart reserve requirements of 3% of load plus 5% of
renewable output, based on a heuristic described in NREL's 2010 Western
Wind and Solar Integration study. It is added to the
Quickstart_Reserve_Requirements list. If the local_td module is available
with DER accounting, load will be set to WithdrawFromCentralGrid.
Otherwise load will be set to lz_demand_mw.
"""
def NREL35QuickstartRequirement_rule(m, b, t):
try:
load = m.WithdrawFromCentralGrid
except AttributeError:
load = m.lz_demand_mw
return (0.03 * sum(load[z, t] for z in m.LOAD_ZONES
if b == m.zone_balancing_area[z])
+ 0.05 * sum(m.DispatchGen[g, t] for g in m.VARIABLE_GENS
if (g, t) in m.VARIABLE_GEN_TPS and
b == m.zone_balancing_area[m.gen_load_zone[g]]))
mod.NREL35QuickstartRequirement = Expression(
mod.BALANCING_AREA_TIMEPOINTS,
rule=NREL35QuickstartRequirement_rule
)
mod.Quickstart_Reserve_Requirements.append('NREL35QuickstartRequirement')


def define_components(mod):
"""
gen_can_provide_quickstart_reserves[g] is a binary flag indicating whether
a generation project can provide quickstart reserves. Default to False for
baseload & variable generators, otherwise defaults to True.

QUICKSTART_RESERVE_GEN_TPS is a subset of GEN_TPS for generators that
have gen_can_provide_quickstart_reserves set to True.

CommitQuickstartReserves[(g,t) in QUICKSTART_RESERVE_GEN_TPS] is a
decision variable of how much quickstart reserve capacity to commit
(in MW).

CommitQuickstartReserves_Limit[(g,t) in SPINNING_RESERVE_GEN_TPS]
constrain the CommitGenSpinningReserves variables based on CommitSlackUp
(and CommitGenSpinningReservesSlackUp as applicable).

For example, if discrete unit commitment is enabled, and a 5MW hydro
generator is fully committed but only providing 2MW of power and 1 MW of
spinning reserves, the remaining 2MW of capacity (summarized in
CommitGenSpinningReservesSlackUp) could be committed to quickstart
reserves.

CommittedQuickstartReserves[(b,t) in BALANCING_AREA_TIMEPOINTS] is an
expression summarizing the CommitQuickstartReserves variables for
generators within each balancing area.

See also: NREL35QuickstartRequirement defined in the function above.
"""
mod.gen_can_provide_quickstart_reserves = Param(
mod.GENERATION_PROJECTS,
within=Boolean,
default=lambda m, g: not (m.gen_is_baseload[g] or m.gen_is_variable[g]),
doc="Denotes whether a generation project can provide quickstart "
"reserves. Default to false for baseload & variable generators, "
"otherwise true. Can be explicitly specified in an input file."
)
mod.QUICKSTART_RESERVE_GEN_TPS = Set(
dimen=2,
within=mod.GEN_TPS,
initialize=lambda m: set(
(g,t)
for g in m.GENERATION_PROJECTS
if m.gen_can_provide_quickstart_reserves[g]
for t in m.TPS_FOR_GEN[g]
)
)
mod.CommitQuickstartReserves = Var(
mod.QUICKSTART_RESERVE_GEN_TPS,
within=NonNegativeReals
)
def CommitQuickstartReserves_Limit_rule(m, g, t):
limit = m.CommitSlackUp[g,t]
try:
limit += m.CommitGenSpinningReservesSlackUp[g,t]
except (AttributeError, KeyError):
pass
return (m.CommitQuickstartReserves[g,t] <= limit)
mod.CommitQuickstartReserves_Limit = Constraint(
mod.QUICKSTART_RESERVE_GEN_TPS,
doc="Constrain committed quickstart reserves to uncommited capacity "
"plus any dispatch slack that is not committed to spinning "
"reserves (if applicable).",
rule=CommitQuickstartReserves_Limit_rule
)

mod.CommittedQuickstartReserves = Expression(
mod.BALANCING_AREA_TIMEPOINTS,
doc="Sum of committed quickstart reserve capacity per balancing "
"area and timepoint.",
rule=lambda m, b, t: (
sum(m.CommitQuickstartReserves[g, t]
for z in m.ZONES_IN_BALANCING_AREA[b]
for g in m.GENS_IN_ZONE[z]
if (g,t) in m.QUICKSTART_RESERVE_GEN_TPS
)
)
)
mod.Quickstart_Reserve_Provisions.append('CommittedQuickstartReserves')

# These rules are in a separate function in anticipation of additional
# rulesets eventually being defined and selectable via command line
# arguments.
nrel_3_5_quickstart_reserve_requirements(mod)


def define_dynamic_components(mod):
"""
Satisfy_Quickstart_Requirement[(b,t) in BALANCING_AREA_TIMEPOINTS]
is a constraint that ensures quickstart reserve requirements are
being satisfied based on the sum of the dynamic lists
Quickstart_Reserve_Requirements & Quickstart_Reserve_Provisions.
"""
mod.Satisfy_Quickstart_Requirement = Constraint(
mod.BALANCING_AREA_TIMEPOINTS,
rule=lambda m, b, t: (
sum(getattr(m, provision)[b,t]
for provision in m.Quickstart_Reserve_Provisions
) >=
sum(getattr(m, requirement)[b,t]
for requirement in m.Quickstart_Reserve_Requirements
)
)
)


def load_inputs(mod, switch_data, inputs_dir):
"""
All files & columns are optional. See notes above for default values.

generation_projects_info.csv
GENERATION_PROJECTS, ... gen_can_provide_quickstart_reserves
"""
switch_data.load_aug(
filename=os.path.join(inputs_dir, 'generation_projects_info.csv'),
auto_select=True,
optional_params=['gen_can_provide_quickstart_reserves'],
param=(mod.gen_can_provide_quickstart_reserves)
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
reserves, and contingency reserves without distinguishing their timescales or
required response duration. Operating reserves at timescales with slower
responses for load following or longer-term recovery from contingencies are not
included here.
included here, but can be accounted for with the quickstart module.

Most regions and countries use distinct terminology for reserves products and
distinct procedures for determining reserve requirements. This module provides
Expand Down