Skip to content
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

feat: analyze binding constraints (ramp, pmin, pmax) #121

Merged
merged 1 commit into from
Jun 11, 2020

Conversation

danielolsen
Copy link
Contributor

Purpose

This is a re-creation of #58, to analyze binding generator constraints. Thanks to the MATReader framework, we can now re-open this PR!

Validation

New integration tests:

python
>>> from powersimdata.scenario.scenario import Scenario
>>> from postreise.analyze.generation import binding
>>> scenario = Scenario('87')
SCENARIO: base | WesternBase_2016_noHVDC_Final_2019Sep

--> State
analyze
--> Loading grid
Loading bus
Loading plant
Loading heat_rate_curve
Loading gencost_before
Loading gencost_after
Loading branch
Loading sub
Loading bus2sub
--> Loading ct
>>> binding_pmin = binding.pmin_constraints(scenario)
--> Loading PG
>>> binding_pmin
                     10390  10391  10392  10393  ...  13457  13458  13459  13460
UTC                                              ...                            
2016-01-01 00:00:00  False  False  False  False  ...  False  False  False  False
2016-01-01 01:00:00  False  False  False  False  ...  False  False  False  False
2016-01-01 02:00:00  False  False  False  False  ...  False  False  False  False
2016-01-01 03:00:00  False  False  False  False  ...  False  False  False  False
2016-01-01 04:00:00  False  False  False  False  ...  False  False  False  False
...                    ...    ...    ...    ...  ...    ...    ...    ...    ...
2016-12-31 19:00:00  False  False  False  False  ...  False  False  False  False
2016-12-31 20:00:00  False  False  False  False  ...  False  False  False  False
2016-12-31 21:00:00  False  False  False  False  ...  False  False  False  False
2016-12-31 22:00:00  False  False  False  False  ...  False  False  False  False
2016-12-31 23:00:00  False  False  False  False  ...  False  False  False  False

[8784 rows x 2527 columns]
>>> grid = scenario.state.get_grid()
>>> plant = grid.plant
>>> binding_pmin.sum().groupby(plant.type).mean()
type
coal          4033.089744
geothermal    0.000000
hydro         0.000000
ng            5680.429158
nuclear       0.000000
solar         4636.910486
wind          879.777778
dtype: float64
>>> binding_pmax = binding.pmax_constraints(scenario)
--> Loading PG
>>> binding_pmax.sum().groupby(plant.type).mean()
type
coal          4566.455128
geothermal    8784.000000
hydro         148.001399
ng            3082.960986
nuclear       8784.000000
solar         343.907928
wind          995.860082
dtype: float64
>>> binding_ramp = binding.ramp_constraints(scenario)
--> Loading PG
>>> binding_ramp.sum().groupby(plant.type).mean()
type
coal          136.429487
geothermal    0.000000
hydro         0.000000
ng            0.000000
nuclear       0.000000
solar         0.000000
wind          0.000000
dtype: float64

Explanation: each function generates a boolean dataframe of the same dimension as PG. We can perform some groupby analysis to see that, for the Western 2016 base scenario:

  • Coal, NG, and solar generators are, on average, at their Pmins ~50% of the hours of the year
  • Nuclear and geothermal generators are at their Pmax 100% of the time (since their power is effectively free), Coal and NG generator ~50% of the time, solar/wind/hydro rarely. Another interesting insight here: because we have a single cost curve segment, NG and coal are either at their Pmin or their Pmax 98% of the time.
  • The only type of generators hitting their ramp limits in this scenario are coal generators. Because with the MATReader object we are getting the grid parameters as they're passed to the OPF problem, we don't get false positives on e.g. hydro hitting its ramp limit (see feat: analyze binding constraints (ramp, pmin, pmax) #58) when in reality we are setting this to effectively INF within REISE.

Time to review

Half an hour.

@danielolsen danielolsen added the new feature Feature that is currently in progress. label Jun 11, 2020
@@ -0,0 +1,212 @@
import unittest

from numpy.testing import assert_array_equal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ununused import

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

})
self.default_expected.set_index('UTC', inplace=True)


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be 1 blank line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

_check_dataframes_match(binding_pmaxs, expected)

def test_pmax_constraints_default_sepc_epsilon1(self):
binding_pmaxs = pmax_constraints(self.mock_scenario, epsilon=1e-3)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sepc --> spec in function name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

_check_dataframes_match(binding_pmaxs, expected)

def test_pmax_constraints_default_sepc_epsilon2(self):
binding_pmaxs = pmax_constraints(self.mock_scenario, epsilon=1e-6)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

expected.loc['t1', 'B'] = False
_check_dataframes_match(binding_pmaxs, expected)

def test_pmax_constraints_default_sepc_epsilon3(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@rouille rouille left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Tests seem to cover everything.

@danielolsen danielolsen force-pushed the binding_constraints branch from 4b039b2 to a836ed9 Compare June 11, 2020 20:03
@danielolsen danielolsen merged commit b6a2023 into develop Jun 11, 2020
@danielolsen danielolsen deleted the binding_constraints branch June 11, 2020 20:06
@ahurli ahurli mentioned this pull request Mar 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Feature that is currently in progress.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants