Skip to content

Commit 1c06a0d

Browse files
A module & test case for quickstart reserves, based on the pattern of spinning reserves, but without contingencies. I only implemented a single rule for quickstart reserves here because that satisfies my immediate use case, and I don't know what rules were used in the GE Hawaii RPS study. I structured the quickstart reserve module to allow for easy subsequent extension of rules for quickstart reserve requirements.
1 parent b5b1a28 commit 1c06a0d

24 files changed

+299
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
SYNOPSIS
2+
switch solve --verbose --log-run
3+
4+
This example extends spinning_reserves by adding quickstart reserve requirements.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
base_financial_year,interest_rate,discount_rate
2+
2015,0.07,0.05
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
load_zone,fuel,period,fuel_cost
2+
South,NaturalGas,2010,4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fuel,co2_intensity,upstream_co2_intensity
2+
NaturalGas,0.05306,0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
GENERATION_PROJECT,build_year,gen_overnight_cost,gen_fixed_om
2+
S-Geothermal,1998,5524200,0.0
3+
S-NG_CC,2000,1143900,5868.3
4+
S-NG_GT,1990,605430,4891.8
5+
S-NG_GT,2002,605430,4891.8
6+
S-Central_PV-1,2001,2334300,41850.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
GENERATION_PROJECT,build_year,gen_predetermined_cap
2+
S-Geothermal,1998,2.0
3+
S-NG_CC,2000,7.0
4+
S-NG_GT,1990,3.0
5+
S-NG_GT,2002,4.0
6+
S-Central_PV-1,2001,3.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GENERATION_PROJECT,power_start_mw,power_end_mw,incremental_heat_rate_mbtu_per_mwhr,fuel_use_rate_mmbtu_per_h
2+
S-NG_CC,40,.,.,269.4069
3+
S-NG_CC,40,100.0,6.684885,.
4+
S-NG_GT,0,.,.,0.1039
5+
S-NG_GT,0,1.0,10.2861,.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GENERATION_PROJECT,gen_loading_level,gen_heat_rate_at_loading_level
2+
S-NG_CC,0.4,2.694069
3+
S-NG_CC,1,6.705
4+
S-NG_GT,0,0.1039
5+
S-NG_GT,1,10.39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
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
2+
S-Geothermal,33,Geothermal,South,134222.0,3.0,30,0,0.0075,0.0241,0,1,0,28.83,Geothermal,.,.,.,.,.,.,0
3+
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
4+
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
5+
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 numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
LOAD_ZONE,existing_local_td,local_td_annual_cost_per_mw
2+
South,10,128040
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
LOAD_ZONE,TIMEPOINT,zone_demand_mw
2+
South,1,3
3+
South,2,8
4+
South,3,10
5+
South,4,7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Core Modules
2+
switch_model
3+
switch_model.timescales
4+
switch_model.financials
5+
switch_model.balancing.load_zones
6+
switch_model.energy_sources.properties
7+
switch_model.generators.core.build
8+
switch_model.generators.core.dispatch
9+
switch_model.reporting
10+
# Custom Modules
11+
switch_model.transmission.local_td
12+
switch_model.generators.core.commit.operate
13+
switch_model.generators.core.commit.fuel_use
14+
switch_model.energy_sources.fuel_costs.simple
15+
switch_model.balancing.operating_reserves.areas
16+
switch_model.balancing.operating_reserves.spinning_reserves
17+
switch_model.balancing.operating_reserves.quickstart
18+
#switch_model.reporting.dump
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
energy_source
2+
Geothermal
3+
Solar
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
INVESTMENT_PERIOD,period_start,period_end
2+
2010,2008,2012
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
contingency_safety_factor
2+
1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2.0.5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
timepoint_id,timestamp,timeseries
2+
1,2010011500,2010_all
3+
2,2010011506,2010_all
4+
3,2010011512,2010_all
5+
4,2010011518,2010_all
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
TIMESERIES,ts_period,ts_duration_of_tp,ts_num_tps,ts_scale_to_period
2+
2010_all,2010,6,1,1826.25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GENERATION_PROJECT,timepoint,gen_max_capacity_factor
2+
S-Central_PV-1,1,0.0
3+
S-Central_PV-1,2,0.61
4+
S-Central_PV-1,3,1.0
5+
S-Central_PV-1,4,0.4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
LOAD_ZONE,PERIOD,zone_expected_coincident_peak_demand
2+
South,2010,10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--spinning-requirement-rule 3+5
2+
--unit-contingency
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
36406402.36853148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# Copyright (c) 2015-2019 The Switch Authors. All rights reserved.
2+
# Licensed under the Apache License, Version 2.0, which is in the LICENSE file.
3+
"""
4+
A simple model of quickstart reserves to accompany the spinning_reserves
5+
modules. Patterns from the spinning reserves modules were followed where
6+
practical to simplify implementation and review.
7+
8+
Unlike spinning reserves, this module does not currently implement
9+
contingency-based requirements because I lack an immediate use case for that.
10+
The contigency reserves methodology from spinning reserve modules could
11+
probably be adapted readily if needed.
12+
13+
For more discussion of operating reserve considerations and modeling
14+
approaches, see the spinning_reserves module.
15+
16+
"""
17+
import os
18+
from pyomo.environ import *
19+
20+
dependencies = (
21+
'switch_model.timescales',
22+
'switch_model.balancing.load_zones',
23+
'switch_model.balancing.operating_reserves.areas',
24+
'switch_model.financials',
25+
'switch_model.energy_sources.properties',
26+
'switch_model.generators.core.build',
27+
'switch_model.generators.core.dispatch',
28+
'switch_model.generators.core.commit.operate',
29+
)
30+
optional_prerequisites = (
31+
'switch_model.balancing.operating_reserves.spinning_reserves',
32+
'switch_model.balancing.operating_reserves.spinning_reserves_advanced',
33+
)
34+
35+
# Uncomment this section when more than one rule is implemented.
36+
# def define_arguments(argparser):
37+
# group = argparser.add_argument_group(__name__)
38+
# group.add_argument('--quickstart-requirement-rule', default="3+5",
39+
# dest='quickstart_requirement_rule',
40+
# choices = ["3+5"],
41+
# help=("Choose rules for quickstart reserves requirements as a function "
42+
# "of variable renewable power and load. '3+5' requires 3%% of "
43+
# "load and 5%% of variable renewable output, based on the "
44+
# "heuristic described in the 2010 Western Wind and Solar "
45+
# "Integration Study.")
46+
# )
47+
48+
49+
def define_dynamic_lists(mod):
50+
"""
51+
Quickstart_Reserve_Requirements is a list of model components that
52+
contribute to quickstart reserve requirements in each balancing area and
53+
timepoint.
54+
55+
Quickstart_Reserve_Provisions is a list of model components that help
56+
satisfy spinning reserve requirements in each balancing area and
57+
timepoint.
58+
59+
Each component in both lists needs to use units of MW and be indexed by:
60+
(b, t) in BALANCING_AREA_TIMEPOINTS.
61+
"""
62+
mod.Quickstart_Reserve_Requirements = []
63+
mod.Quickstart_Reserve_Provisions = []
64+
65+
66+
def nrel_3_5_quickstart_reserve_requirements(mod):
67+
"""
68+
NREL35QuickstartRequirement[(b,t) in BALANCING_AREA_TIMEPOINTS] is
69+
an expression for quickstart reserve requirements of 3% of load plus 5% of
70+
renewable output, based on a heuristic described in NREL's 2010 Western
71+
Wind and Solar Integration study. It is added to the
72+
Quickstart_Reserve_Requirements list. If the local_td module is available
73+
with DER accounting, load will be set to WithdrawFromCentralGrid.
74+
Otherwise load will be set to lz_demand_mw.
75+
"""
76+
def NREL35QuickstartRequirement_rule(m, b, t):
77+
try:
78+
load = m.WithdrawFromCentralGrid
79+
except AttributeError:
80+
load = m.lz_demand_mw
81+
return (0.03 * sum(load[z, t] for z in m.LOAD_ZONES
82+
if b == m.zone_balancing_area[z])
83+
+ 0.05 * sum(m.DispatchGen[g, t] for g in m.VARIABLE_GENS
84+
if (g, t) in m.VARIABLE_GEN_TPS and
85+
b == m.zone_balancing_area[m.gen_load_zone[g]]))
86+
mod.NREL35QuickstartRequirement = Expression(
87+
mod.BALANCING_AREA_TIMEPOINTS,
88+
rule=NREL35QuickstartRequirement_rule
89+
)
90+
mod.Quickstart_Reserve_Requirements.append('NREL35QuickstartRequirement')
91+
92+
93+
def define_components(mod):
94+
"""
95+
gen_can_provide_quickstart_reserves[g] is a binary flag indicating whether
96+
a generation project can provide quickstart reserves. Default to False for
97+
baseload & variable generators, otherwise defaults to True.
98+
99+
QUICKSTART_RESERVE_GEN_TPS is a subset of GEN_TPS for generators that
100+
have gen_can_provide_quickstart_reserves set to True.
101+
102+
CommitQuickstartReserves[(g,t) in QUICKSTART_RESERVE_GEN_TPS] is a
103+
decision variable of how much quickstart reserve capacity to commit
104+
(in MW).
105+
106+
CommitQuickstartReserves_Limit[(g,t) in SPINNING_RESERVE_GEN_TPS]
107+
constrain the CommitGenSpinningReserves variables based on CommitSlackUp
108+
(and CommitGenSpinningReservesSlackUp as applicable).
109+
110+
For example, if discrete unit commitment is enabled, and a 5MW hydro
111+
generator is fully committed but only providing 2MW of power and 1 MW of
112+
spinning reserves, the remaining 2MW of capacity (summarized in
113+
CommitGenSpinningReservesSlackUp) could be committed to quickstart
114+
reserves.
115+
116+
CommittedQuickstartReserves[(b,t) in BALANCING_AREA_TIMEPOINTS] is an
117+
expression summarizing the CommitQuickstartReserves variables for
118+
generators within each balancing area.
119+
120+
See also: NREL35QuickstartRequirement defined in the function above.
121+
"""
122+
mod.gen_can_provide_quickstart_reserves = Param(
123+
mod.GENERATION_PROJECTS,
124+
within=Boolean,
125+
default=lambda m, g: not (m.gen_is_baseload[g] or m.gen_is_variable[g]),
126+
doc="Denotes whether a generation project can provide quickstart "
127+
"reserves. Default to false for baseload & variable generators, "
128+
"otherwise true. Can be explicitly specified in an input file."
129+
)
130+
mod.QUICKSTART_RESERVE_GEN_TPS = Set(
131+
dimen=2,
132+
within=mod.GEN_TPS,
133+
initialize=lambda m: set(
134+
(g,t)
135+
for g in m.GENERATION_PROJECTS
136+
if m.gen_can_provide_quickstart_reserves[g]
137+
for t in m.TPS_FOR_GEN[g]
138+
)
139+
)
140+
mod.CommitQuickstartReserves = Var(
141+
mod.QUICKSTART_RESERVE_GEN_TPS,
142+
within=NonNegativeReals
143+
)
144+
def CommitQuickstartReserves_Limit_rule(m, g, t):
145+
limit = m.CommitSlackUp[g,t]
146+
try:
147+
limit += m.CommitGenSpinningReservesSlackUp[g,t]
148+
except (AttributeError, KeyError):
149+
pass
150+
return (m.CommitQuickstartReserves[g,t] <= limit)
151+
mod.CommitQuickstartReserves_Limit = Constraint(
152+
mod.QUICKSTART_RESERVE_GEN_TPS,
153+
doc="Constrain committed quickstart reserves to uncommited capacity "
154+
"plus any dispatch slack that is not committed to spinning "
155+
"reserves (if applicable).",
156+
rule=CommitQuickstartReserves_Limit_rule
157+
)
158+
159+
mod.CommittedQuickstartReserves = Expression(
160+
mod.BALANCING_AREA_TIMEPOINTS,
161+
doc="Sum of committed quickstart reserve capacity per balancing "
162+
"area and timepoint.",
163+
rule=lambda m, b, t: (
164+
sum(m.CommitQuickstartReserves[g, t]
165+
for z in m.ZONES_IN_BALANCING_AREA[b]
166+
for g in m.GENS_IN_ZONE[z]
167+
if (g,t) in m.QUICKSTART_RESERVE_GEN_TPS
168+
)
169+
)
170+
)
171+
mod.Quickstart_Reserve_Provisions.append('CommittedQuickstartReserves')
172+
173+
# These rules are in a separate function in anticipation of additional
174+
# rulesets eventually being defined and selectable via command line
175+
# arguments.
176+
nrel_3_5_quickstart_reserve_requirements(mod)
177+
178+
179+
def define_dynamic_components(mod):
180+
"""
181+
Satisfy_Quickstart_Requirement[(b,t) in BALANCING_AREA_TIMEPOINTS]
182+
is a constraint that ensures quickstart reserve requirements are
183+
being satisfied based on the sum of the dynamic lists
184+
Quickstart_Reserve_Requirements & Quickstart_Reserve_Provisions.
185+
"""
186+
mod.Satisfy_Quickstart_Requirement = Constraint(
187+
mod.BALANCING_AREA_TIMEPOINTS,
188+
rule=lambda m, b, t: (
189+
sum(getattr(m, provision)[b,t]
190+
for provision in m.Quickstart_Reserve_Provisions
191+
) >=
192+
sum(getattr(m, requirement)[b,t]
193+
for requirement in m.Quickstart_Reserve_Requirements
194+
)
195+
)
196+
)
197+
198+
199+
def load_inputs(mod, switch_data, inputs_dir):
200+
"""
201+
All files & columns are optional. See notes above for default values.
202+
203+
generation_projects_info.csv
204+
GENERATION_PROJECTS, ... gen_can_provide_quickstart_reserves
205+
"""
206+
switch_data.load_aug(
207+
filename=os.path.join(inputs_dir, 'generation_projects_info.csv'),
208+
auto_select=True,
209+
optional_params=['gen_can_provide_quickstart_reserves'],
210+
param=(mod.gen_can_provide_quickstart_reserves)
211+
)

switch_model/balancing/operating_reserves/spinning_reserves.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
reserves, and contingency reserves without distinguishing their timescales or
1616
required response duration. Operating reserves at timescales with slower
1717
responses for load following or longer-term recovery from contingencies are not
18-
included here.
18+
included here, but can be accounted for with the quickstart module.
1919
2020
Most regions and countries use distinct terminology for reserves products and
2121
distinct procedures for determining reserve requirements. This module provides

0 commit comments

Comments
 (0)