-
Notifications
You must be signed in to change notification settings - Fork 40
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
Create ScenarioInfo class #94
Conversation
3d5e491
to
da54b90
Compare
We should create a tests folder in PowerSimData/powersimdata/scemario and move the test_scenario_info.py there. The tests folder in PowerSimData/powersimdata/ houses the mock objects that are used in the tests. |
Some lines are too long. All lines should be < 80 characters (PEP8). |
'wind': wind, | ||
'hydro': hydro | ||
} | ||
|
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.
I would recommend to write a _check_state
function that makes sure that the scenario instance that you pass to the constructor is in the analyze
state (scenario.state.name == analyze
). Otherwise raise an error.
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.
The reason I did not add this after our discussion is it fails the tests. It seems the MockAnalyze
object has no 'name' attribute.
AttributeError: 'MockAnalyze' object has no attribute 'name'
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.
Good catch. I had been faking the class so you can import Analyze and do an isinstance
on the mock, but I didn't enable the lower-tech way of just checking the name attribute. We should probably add this.
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.
self.name = 'analyze' in MockAnalyze should do it
print("%s is incorrect." % area) | ||
raise Exception('Invalid area') | ||
return loadzone_set | ||
|
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.
I guess we can be more specific here and raise a ValueError inplace of a standard Exception.
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.
Currently, area
supports loadzone, state, state abbreviation, interconnect and 'all'. Potentially, it will be more in the future, such as combinations of interconnect, state or loadzones. Not sure whether we should put the specific guidance here or in function docs.
print('start_time falls behind end_time!') | ||
raise Exception('Invalid time range') | ||
return start_i, end_i | ||
|
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.
Same here. A ValueError would be more explicit.
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.
Should I simply change Exception
to ValueError
here? I was thinking about several conditions:
start_time
andend_time
are in wrong format or some random strings.start_time
andend_time
are in right format but not in the valid range of the scenariostart_time
andend_time
are in right format but in wrong order, i.e. should be switched
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.
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 saw the changes you made. Looks good.
'plant_id': [101, 102, 103, 104, 105, 106], | ||
'bus_id': [1001, 1002, 1003, 1004, 1005, 1006], | ||
'type': ['solar', 'wind', 'ng', 'coal', 'dfo', 'hydro'], | ||
'zone_name': ['zone1', 'zone1', 'zone1', 'zone1', 'zone1', 'zone1'], |
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.
Let's make sure this test data covers more edge cases: e.g. 2+ zones, some resources are in both zones, some are in just one or the other.
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.
That's exactly what I did originally and I figured out that in MockGrid
we only have one zone in the zone2id
attribute. This test uses MockScenario
which calls MockAnalyze
then takes MockGrid
. We could add attributes to the grid but seems not be able to overwrite the existing attributes in the grid.
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.
Let's expand MockGrid to have at least two zones/ids natively.
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.
Can we add other values in the zoneid dict of the MockGrid
object?
mock_wind = mock_pg[wind_plant_id] * 4 | ||
mock_hydro = mock_pg[hydro_plant_id] * 1.5 | ||
|
||
start_time = '2016-01-01 00:00:00' |
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.
Similarly, let's have our dates span more than one day, so that we can ensure that check_time_range
is comparing full datetimes and not just times. E.g. 6am one day to 3am the next day.
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.
Agree. The function is comparing the index order of the start time and the end time, thus it should work. But you are right we could span the mock profiles to longer range. The down side is it makes the tests less eyeball tractable.
total_capacity = self.grid.plant[(self.grid.plant['type'] == gentype) & | ||
(self.grid.plant['zone_name'].isin(loadzone_set))]['Pmax'].sum() | ||
if total_capacity == 0: | ||
print('Warning: no such type of generator in the area specified!') |
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.
There is the warnings package (https://docs.python.org/3/library/warnings.html#module-warnings) that could be useful here.
elif area in {'Texas', 'Western', 'Eastern'}: | ||
loadzone_set = interconnect2loadzone[area] | ||
elif area == 'all': | ||
loadzone_set = list(self.grid.zone2id.keys()) |
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.
This option does not return a set: we should wrap the grid keys in set()
instead of list()
.
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.
Good catch.
""" | ||
total_generation = self.get_generation(gentype, area, start_time, end_time) | ||
total_profile_resource = self.get_profile_resource(gentype, area, start_time, end_time) | ||
if total_profile_resource == 0 and total_generation == 0: |
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.
Good thinking ahead.
total_hours = end_i - start_i + 1 | ||
total_capacity = self.get_capacity(gentype, area) | ||
if total_capacity == 0: | ||
raise ZeroDivisionError('Division by zero') |
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.
Should this create an exception, or return 0? Either one seems okay, but it seems strange to me that it doesn't match get_curtailment
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.
I thought about this before. The idea is to separate between a reasonable zero and an irregular zero:
--A reasonable zero: 1) zero profile, zero generation, thus zero curtailment 2) zero generation, nonzero capacity, zero capacity factor
--An irregular zero: zero generation, zero capacity, also zero capacity factor.
Or we have a better way to handle this difference?
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.
As long as you've thought about it in the context of how we will use this object/method, I'm happy. If we can run the capacity scaling successfully in Western, including zones like WA where there's no solar, then I don't have strong feelings on the underlying implementation. Maybe a more descriptive message saying that the zero comes from zero capacity for the cases where we do run into this error.
Done with this. |
Should I modify |
@BainanXia yes, go ahead. |
2cd4b2f
to
1798743
Compare
The current version of this PR: |
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.
Great work
Check the following link: https://github.com/intvenlab/REISE/wiki/Pull-Request-Etiquette. It has been written by Merielle and it standardized the PR process.
The test using MockScenario is extended into 2 zones and 25 hours.
d15c220
to
28648be
Compare
This PR consists of three parts:
An empty
__init__.py
is added to the tests folder to fix the issue when usingmock_scenario
object in PostREISE, it complains not findingmock_grid
in PowerSimDataAll functions and attributes of
scenario_info
object is in a single python script,scenario_info.py
under scenario folder. Discussed with @rouille , both of us think the user should be able to accessscenario_info
in a general sense not just use it to calculate target capacities in scenario design.A full test of all the functions of the
scenario_info
object is implemented intest_scenario_info.py
. All 6 functions passed the tests via mock scenario.Note that I noticed the commit message should be a 'feat' instead of 'fix', a force push is conducted to fix this.