Skip to content

Commit b631b56

Browse files
committed
Add .tools.res_marg
- Copied from message_data `ssp_dev` branch - File message_data/scenario_generation/reserve_margin/res_marg.py - Last modified by commit f3efc8b104044676434695aa461d26a7b20e5cd7: Author: FRICKO Oliver <[email protected]> Date: Wed Nov 27 13:48:26 2024 +0100 Update reserve_margin script to remove print statement - message_single_country `SSP_Dev_2023` branch contains an identical file.
1 parent 43ce610 commit b631b56

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

message_ix_models/tools/res_marg.py

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import argparse
2+
3+
4+
def main(scen, contin=0.2):
5+
"""Updates the reserve margin.
6+
For a given scenario, regional reserve margin (=peak load factor) values
7+
are updated based on the electricity demand in the industry and res/comm
8+
sector.
9+
This is based on the approach described in Johnsonn et al. (2017):
10+
DOI: https://doi.org/10.1016/j.eneco.2016.07.010
11+
(see section 2.2.1. Firm capacity requirement)
12+
13+
Parameters
14+
----------
15+
scen : :class:`message_ix.Scenario`
16+
scenario to which changes should be applied
17+
contin : float
18+
Backup capacity for contingency reasons as percentage of peak capacity
19+
(default 20%)
20+
"""
21+
22+
demands = scen.par("demand")
23+
demands = (
24+
demands[demands.commodity.isin(["i_spec", "rc_spec"])]
25+
.set_index(["node", "commodity", "year", "level", "time", "unit"])
26+
.sort_index()
27+
)
28+
input_eff = (
29+
scen.par("input", {"technology": ["elec_t_d"]})
30+
.set_index(
31+
[
32+
"node_loc",
33+
"year_act",
34+
"year_vtg",
35+
"commodity",
36+
"level",
37+
"mode",
38+
"node_origin",
39+
"technology",
40+
"time",
41+
"time_origin",
42+
"unit",
43+
]
44+
)
45+
.sort_index()
46+
)
47+
48+
with scen.transact("Update reserve-margin constraint"):
49+
for reg in demands.index.get_level_values("node").unique():
50+
if "_GLB" in reg:
51+
continue
52+
for year in demands.index.get_level_values("year").unique():
53+
rc_spec = float(
54+
demands.loc[reg, "rc_spec", year, "useful", "year"].iloc[0].value
55+
)
56+
i_spec = float(
57+
demands.loc[reg, "i_spec", year, "useful", "year"].iloc[0].value
58+
)
59+
inp = float(
60+
input_eff.loc[
61+
reg,
62+
year,
63+
year,
64+
"electr",
65+
"secondary",
66+
"M1",
67+
reg,
68+
"elec_t_d",
69+
"year",
70+
"year",
71+
]
72+
.iloc[0]
73+
.value
74+
)
75+
val = (
76+
((i_spec * 1.0 + rc_spec * 2.0) / (i_spec + rc_spec))
77+
* (1.0 + contin)
78+
* inp
79+
* -1.0
80+
)
81+
scen.add_par(
82+
"relation_activity",
83+
{
84+
"relation": ["res_marg"],
85+
"node_rel": [reg],
86+
"year_rel": [year],
87+
"node_loc": [reg],
88+
"technology": ["elec_t_d"],
89+
"year_act": [year],
90+
"mode": ["M1"],
91+
"value": [val],
92+
"unit": ["GWa"],
93+
},
94+
)
95+
96+
97+
if __name__ == "__main__":
98+
descr = """
99+
Reserve margin calculation
100+
101+
Example usage:
102+
python res_marg.py --version [X] [model name] [scenario name]
103+
104+
"""
105+
parser = argparse.ArgumentParser(
106+
description=descr, formatter_class=argparse.RawDescriptionHelpFormatter
107+
)
108+
version = "--version : string\n ix-scenario name"
109+
parser.add_argument("--version", help=version)
110+
model = "model : string\n ix-model name"
111+
parser.add_argument("model", help=model)
112+
scenario = "scenario : string\n ix-scenario name"
113+
parser.add_argument("scenario", help=scenario)
114+
115+
# parse cli
116+
args = parser.parse_args()
117+
model = args.model
118+
scenario = args.scenario
119+
version = int(args.version) if args.version else None
120+
121+
import ixmp
122+
import message_ix
123+
124+
mp = ixmp.Platform()
125+
scen = message_ix.Scenario(mp, model, scenario, version=version, cache=True)
126+
127+
main(scen)

0 commit comments

Comments
 (0)