-
Notifications
You must be signed in to change notification settings - Fork 165
Resolve the issue of zero capacity factor #561
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
Merged
Merged
Changes from 15 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
be055a8
Add test for capacity factor
behnam-zakeri 6384afd
Apply black for code style
behnam-zakeri 7dae317
Copy enforcing new mapping set from PR#514
behnam-zakeri 0fc16a1
Add the masking set on the python side
behnam-zakeri 620982d
Add masking set (is_capacity_factor) in GAMS
behnam-zakeri e153ac7
Improve tests to work with the new formulation
behnam-zakeri 3c0e68c
Add #561 to release notes
behnam-zakeri 148018a
Update technology names for more intuition
behnam-zakeri 2bcafb6
Add .testing.make_subannual()
khaeru de42cc6
Use make_subannual() to handle test_feature_temporal_level cases
khaeru 1ddb2f1
Use globals instead of duplicates in test_feature_temporal_level
khaeru c64b6d8
Simplify make_subannual()
khaeru ff7ca20
Use globals instead of duplicates in test_feature_capacity_factor
khaeru eff15d1
Adjust expected failures in two tests of temporal levels
khaeru fae1455
Adjust reporting tests for new is_capacity_factor item
khaeru 53641ea
Apply suggestions from code review
khaeru File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
"""Test ``capacity_factor`` effects, mainly for models with sub-annual resolution.""" | ||
import pytest | ||
|
||
from message_ix import ModelError, Scenario | ||
from message_ix.testing import make_subannual | ||
|
||
|
||
def check_solution(scen: Scenario) -> None: | ||
"""Perform several assertions about the solution of `scen`.""" | ||
# Reading "ACT" and "CAP" from the solution | ||
act = scen.var("ACT").set_index(["technology", "time"]) | ||
cap = scen.var("CAP").set_index(["technology"]) | ||
|
||
# 1) ACT is zero when capacity factor is zero | ||
cf = scen.par("capacity_factor").set_index(["technology", "time"]) | ||
cf_zero = cf.loc[cf["value"] == 0] | ||
for i in cf_zero.index: | ||
assert act.loc[i, "lvl"] == 0 | ||
|
||
# 2) CAP is correctly calculated based on ACT and capacity_factor | ||
for i in act.loc[act["lvl"] > 0].index: | ||
# Correct ACT based on duration of each time slice | ||
duration = float(scen.par("duration_time", {"time": i[1]})["value"]) | ||
act.loc[i, "duration-corrected"] = act.loc[i, "lvl"] / duration | ||
# Divide by (non-zero) capacity factor | ||
act.loc[i, "cf-corrected"] = act.loc[i, "duration-corrected"] / float( | ||
cf.loc[i, "value"] | ||
) | ||
act = act.fillna(0).reset_index().set_index(["technology"]) | ||
# CAP = max("ACT" / "duration_time" / "capcity_factor") | ||
for i in cap.index: | ||
assert max(act.loc[i, "cf-corrected"]) == float(cap.loc[i, "lvl"]) | ||
|
||
|
||
TD_0 = { | ||
khaeru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"gas_ppl": { | ||
"time_origin": [], | ||
"time": ["summer", "winter"], | ||
"time_dest": ["summer", "winter"], | ||
}, | ||
} | ||
|
||
|
||
def test_capacity_factor_time(request): | ||
"""``capacity_factor`` is calculated correctly when it varies by time slice.""" | ||
# Build model and solve | ||
scen = make_subannual( | ||
request, | ||
TD_0, | ||
time_steps=[ | ||
("summer", 0.5, "season", "year"), | ||
("winter", 0.5, "season", "year"), | ||
], | ||
demand={"summer": 2, "winter": 1}, | ||
capacity_factor={"gas_ppl": {"summer": 0.8, "winter": 0.6}}, | ||
var_cost={"gas_ppl": {"summer": 0.2, "winter": 0.2}}, | ||
) | ||
check_solution(scen) | ||
|
||
|
||
def test_capacity_factor_unequal_time(request): | ||
"""``capacity_factor`` is calculated correctly when ``duration_time`` is uneven.""" | ||
# Build model and solve | ||
scen = make_subannual( | ||
request, | ||
TD_0, | ||
time_steps=[ | ||
("summer", 0.3, "season", "year"), | ||
("winter", 0.7, "season", "year"), | ||
], | ||
demand={"summer": 2, "winter": 1}, | ||
capacity_factor={"gas_ppl": {"summer": 0.8, "winter": 0.8}}, | ||
var_cost={"gas_ppl": {"summer": 0.2, "winter": 0.2}}, | ||
) | ||
check_solution(scen) | ||
|
||
|
||
TS_0 = [ | ||
khaeru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
("day", 0.5, "subannual", "year"), | ||
("night", 0.5, "subannual", "year"), | ||
] | ||
|
||
|
||
def test_capacity_factor_zero(request): | ||
"""Test zero capacity factor (CF) in a time slice. | ||
|
||
"solar_pv_ppl" is active in "day" and NOT at "night" (CF = 0). It is expected that | ||
the model will be infeasible, because "demand" at night cannot be met. | ||
""" | ||
# Technology input/output | ||
khaeru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tec_dict = { | ||
"solar_pv_ppl": { | ||
"time_origin": [], | ||
"time": ["day", "night"], | ||
"time_dest": ["day", "night"], | ||
}, | ||
} | ||
|
||
# Build model and solve (should raise GAMS error) | ||
with pytest.raises(ModelError): | ||
make_subannual( | ||
request, | ||
tec_dict, | ||
com_dict={"solar_pv_ppl": {"input": "fuel", "output": "electr"}}, | ||
time_steps=TS_0, | ||
demand={"day": 2, "night": 1}, | ||
capacity={"solar_pv_ppl": {"inv_cost": 0.2, "technical_lifetime": 5}}, | ||
capacity_factor={"solar_pv_ppl": {"day": 0.8, "night": 0}}, | ||
) | ||
|
||
|
||
def test_capacity_factor_zero_two(request): | ||
"""Test zero capacity factor (CF) in a time slice. | ||
|
||
"solar_pv_ppl" is active in "day" and NOT at "night" (CF = 0). The model output | ||
should show no activity of "solar_pv_ppl" at "night". So, "gas_ppl" is active at | ||
"night", even though a more expensive technology. | ||
""" | ||
# Technology input/output | ||
khaeru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tec_dict = { | ||
"solar_pv_ppl": { | ||
"time_origin": [], | ||
"time": ["day", "night"], | ||
"time_dest": ["day", "night"], | ||
}, | ||
"gas_ppl": { | ||
"time_origin": [], | ||
"time": ["day", "night"], | ||
"time_dest": ["day", "night"], | ||
}, | ||
} | ||
|
||
# Build model and solve | ||
scen = make_subannual( | ||
request, | ||
tec_dict, | ||
com_dict={ | ||
"solar_pv_ppl": {"input": "fuel", "output": "electr"}, | ||
"gas_ppl": {"input": "fuel", "output": "electr"}, | ||
}, | ||
time_steps=TS_0, | ||
demand={"day": 2, "night": 1}, | ||
capacity={ | ||
"solar_pv_ppl": {"inv_cost": 0.1, "technical_lifetime": 5}, | ||
"gas_ppl": {"inv_cost": 0.1, "technical_lifetime": 5}, | ||
}, | ||
capacity_factor={ | ||
"solar_pv_ppl": {"day": 0.8, "night": 0}, | ||
"gas_ppl": {"day": 0.8, "night": 0.8}, | ||
}, | ||
var_cost={ | ||
"solar_pv_ppl": {"day": 0, "night": 0}, | ||
"gas_ppl": {"day": 0.2, "night": 0.2}, | ||
}, | ||
) | ||
check_solution(scen) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be sure, both lines above are commented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm not sure why; they're not on #514 from which this was cherry-picked. That PR will need to be deconflicted when it is rebased, so we can clean up/remove then.