-
Notifications
You must be signed in to change notification settings - Fork 9
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
Xmission/cost layers #122
Xmission/cost layers #122
Conversation
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 is looking great. Some general pythonic comments and suggestions.
Two other asks:
- Lets get some test data started, let me know if I can help getting the landuse layer added to the test 'ri_exclusions.h5' file
- Can we remove the old modules/methods that this will replace?
base_line_costs, iso_lookup, default_mults, | ||
excl_h5='/shared-projects/rev/exclusions/ATB_Exclusions.h5', | ||
slope_lyr='srtm_slope', nlcd_lyr='usa_mrlc_nlcd2011'): | ||
def __init__(self, h5_fpath, iso_regions_fpath, atb_excl_h5, iso_lookup, |
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.
atb_excl_h5
is WAY to exact, this should just be excl_h5. Also I don't think we need this here, we should init the .h5 file from the iso_regions geotiff. We just need to make sure its profile matches the excl_h5 profile.
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.
Renamed.
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'm ignoring the profile issue for a bit.
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.
LOL, still waiting on Evan to fix that?
# TODO - use self._profile instead of regions file | ||
self._init_h5(h5_fpath, iso_regions_fpath) | ||
|
||
self._tiff_dir = tiff_dir |
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 shouldn't be an attribute, we should ask people to explicitly give the geotiff path ONLY when saving to a geotfiff
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.
Is the problem saving the tiff path as an instance attribute? Should create_geotiff()
not be in build_cost_rasters()
at all? I need tiffs for development purposes, but I can rip them out once this code is stable.
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.
no, no, its that tiff_dir is ONLY used in create_geotiff
, so it shouldn't be a class attribute. Instead it should be a kwarg in build_cost_rasters
and then the actual geotiff path should be passed into create_geotiff
.
What i would actually do is convert the save_geotiff
kwargs into tiff_dir
and use this logic:
if tiff_dir is not None:
save_geotiff = True
else:
save_geotiff = False
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.
What about
if tiff_dir:
xcc.create_geotiff('mults.tif', tiff_dir, mults_arr)
Less code, though using to tiff_dir
to set save_geotiff
is 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.
Done
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 if statement logic is fine, but I don't follow the create_geotiff
logic. Passing in the name and directory is silly, just pass in the full file path and create it from tiff_dir
and mults.tif
in the classmethod. Also when ever generating filenames be verbose: tie-line_cost_multipliers.tiff
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.
See notes below.
if None | ||
default_mults : dict | ||
Multipliers for regions not specified in iso_mults_f. | ||
save_to_h5 : bool |
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 still don't understand why we wouldn't want to write to the .h5 file... thats the whole point of the class, particularly for this classmethod I think the whole point of the workflow... What happens if you set both to False?
836292c
to
b7b3b6b
Compare
""" | ||
super().__init__() | ||
|
||
if power_to_voltage_fpath is None: |
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 is nit-picky, but I wonder if there is a way to reduce the number of if statements here. One thought is to build a dictionary like this:
defaults = {'power_to_voltage_fpath' : 'power_to_voltage', ...}
for kwarg, name in defaults.items:
self[name] = kwargs.get(kwarg, os.path.join(D_DIR, f'{name}.json'))
The only downside is that the init becomes which would be less verbose, but seeing as this is an internal handler the simplicity might be work it...
def __init__(self, **kwargs):
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.
Noted. Let's revisit this once the code works.
self._profile['nodata'] = None | ||
self._write_layer(self._excl_h5, layer_name, self._profile, data) | ||
|
||
def create_geotiff(self, tiff_dir, geotiff_fpath, data): |
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.
Simplify this to be just:
def create_geotiff(self, geotiff_fpath, data):
There is no need to do an os.path.join inside this method.
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.
Keeping os.path.join inside create_geotiff is much DRYer and keeps the code in build_cost_rasters() shorter. I'd prefer to save the tiff_dir as an attribute to further simply the function arguments. Thoughts?
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 don't fully follow. Since this is a public method it seem much more straight forward to just request the full geotiff path and data to write (for anyone using this class that is not us). Then in the build_cost_rasters
class method the tiff_dir is an input value so its a local variable, and we can create the custom file paths with os.path.join
inside the if save_geotfif
logic on lines 135 and 142.
for i in indices: | ||
mult_raster[i[0]] = i[1] | ||
|
||
return mult_raster |
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.
Lets add a second class method, could be run
, build
, or create
that would
- run
build_test_costs
- add any extra layers using
layers_to_h5
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.
What do you mean by extra layers?
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.
Transmission barrier layer and dist_to_coast layers I think are the only "other" layers we need. i.e none cost layers
tests/test_x_mission_costs.py
Outdated
|
||
|
||
def test_land_use_multiplier(): | ||
""" Test land use multiplier creation """ | ||
lu_mults = {'forest': 1.63, 'wetland': 1.5} | ||
arr = np.array([[[0, 95, 90], [42, 41, 15]]]) | ||
cm = CostMultiplier() | ||
out = cm._create_land_use_mult(arr, lu_mults) | ||
xcc = XmissionCostCreator(INPUT_H5F, ISO_REGIONS_F, {}) |
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.
whats up with the empty dict here?
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.
iso region dict. It's not needed for the test.
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.
Ah! Should we make that a kwarg then?
@mikebannis getting super close! This is looking great. A few minor comments |
one more comment, lets split the test file into two:
|
@mikebannis wanted to check in on this PR, would be nice to wrap this up before the next one... |
Working on the path finding code. I'll wrap this up tonight or tmw |
No rush just a gentle nudge before we both forget what we were thinking, so definitely tomorrow, you don't get paid enough to work tonight... |
costs_arr) | ||
|
||
@classmethod | ||
def build_test_costs(cls, h5_fpath, iso_regions_fpath, input_h5_fpath, |
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 isn't useful outside of the tests, we should just move this code to the tests as a function that can be run if needed.
|
||
# _write_geotiff sets nodata to the max for the dtype. For float32 this | ||
# then breaks JSONifying the profile when writing h5s. Reset it. | ||
self._profile['nodata'] = nodata |
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.
Why is nodata pulled out and then added back to the profiel? I dont' see it being used in this function, are the above comments supposed to be a TODO?
fix docstring in excl converter
add tests
a6c8fc5
to
b4d4242
Compare
@@ -4,7 +4,7 @@ | |||
""" | |||
import os | |||
|
|||
from .xmission_config import XmissionConfig | |||
from reVX.least_cost_xmission.config.xmission_config import XmissionConfig |
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.
Out of curiosity, why the absolute versus relative import? It seems the relative import is less work if the folder structure changes.
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.
No good reason beyond Grant's preference that we started following in reV and has bleed over to reVX. We have run into some strange import issues in the past but I think that was mainly noobness + python 3.6 being weird.
@@ -0,0 +1 @@ | |||
{"iso_lookup": {"MISO": 3, "SCE": 2, "Southeast": 4, "TEPPC": 1}, "min_power_classes": {"100MW": 0, "200MW": 100, "400MW": 200, "1000MW": 400}, "new_substation_costs": {"MISO": {"138": 7800000, "230": 9700000, "500": 20300000, "69": 5700000}, "SCE": {"138": 8870000, "230": 17525000, "500": 37017000, "69": 3975000}, "Southeast": {"138": 4692000, "230": 5732000, "500": 20364000, "69": 3064000}, "TEPPC": {"138": 5541000, "230": 9171000, "500": 15489000, "69": 3498000}}, "power_classes": {"1000MW": 1500, "100MW": 102, "200MW": 205, "400MW": 400}, "transformer_costs": {"115": {"115": 5230, "138": 4260, "161": 4480, "230": 4970, "345": 5790, "500": 7110, "69": 3840}, "138": {"115": 4260, "138": 5790, "161": 4720, "230": 4970, "345": 5790, "500": 7110, "69": 4260}, "161": {"115": 4480, "138": 4720, "161": 6420, "230": 5230, "345": 6100, "500": 7490, "69": 4480}, "230": {"115": 4970, "138": 4970, "161": 5230, "230": 7110, "345": 6100, "500": 7490, "69": 4970}, "345": {"115": 5790, "138": 5790, "161": 6100, "230": 6100, "345": 8670, "500": 7860, "69": 6100}, "500": {"115": 7110, "138": 7110, "161": 7490, "230": 7490, "345": 7860, "500": 11610, "69": 7860}, "69": {"115": 3840, "138": 4260, "161": 4480, "230": 4970, "345": 6100, "500": 7860, "69": 4720}}, "power_to_voltage": {"102": 69, "1500": 500, "171": 115, "205": 138, "240": 161, "343": 230, "400": 230, "68": 46, "750": 345}, "upgrade_substation_costs": {"MISO": {"138": 1600000, "230": 2200000, "500": 5300000, "69": 1100000}, "SCE": {"138": 1117000, "230": 3975000, "500": 9665000, "69": 767000}, "Southeast": {"138": 1179000, "230": 2210000, "500": 8340000, "69": 917000}, "TEPPC": {"138": 2198000, "230": 5500000, "500": 10236000, "69": 1352000}}, "iso_multipliers": [{"iso": "TEPPC", "land_use": {"cropland": 1, "forest": 2.25, "suburban": 1.3, "urban": 1.59, "wetland": 1.2}, "slope": {"hill_mult": 1.4, "hill_slope": 2, "mtn_mult": 1.75, "mtn_slope": 8}}, {"iso": "SCE", "land_use": {"cropland": 1, "forest": 3, "suburban": 2, "urban": 3, "wetland": 2}, "slope": {"hill_mult": 1.5, "hill_slope": 2, "mtn_mult": 2, "mtn_slope": 8}}, {"iso": "MISO", "land_use": {"cropland": 1.03, "forest": 1.2, "suburban": 1.08, "urban": 1.2, "wetland": 1.8}, "slope": {"hill_mult": 1.1, "hill_slope": 2, "mtn_mult": 1.21, "mtn_slope": 8}}, {"iso": "Southeast", "land_use": {"cropland": 1, "forest": 1.47, "suburban": 1.75, "urban": 1.12, "wetland": 1.33}, "slope": {"hill_mult": 1.2, "hill_slope": 2, "mtn_mult": 1.6, "mtn_slope": 8}}], "base_line_costs": {"MISO": {"102": 1255000, "1500": 2787000, "205": 1446000, "400": 1695000}, "SCE": {"102": 1524000, "1500": 4777000, "205": 2084000, "400": 3034000}, "Southeast": {"102": 819000, "1500": 4056000, "205": 984000, "400": 1568000}, "TEPPC": {"102": 984000, "1500": 2248000, "205": 1180000, "400": 1570000}}, "nlcd_land_use_classes": {"cropland": [80, 81], "forest": [41, 42, 43], "wetland": [90, 95], "suburban": [21, 22, 23], "urban": [24]}} |
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.
Is it safe to assume github actions will format that?
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.
Yeah I did a no-verify commit just to get up before calling it a day. Going to finish it up / clean it up now.
turn off geotiff checker
Codecov Report
@@ Coverage Diff @@
## mjb/feat/x-mission-path #122 +/- ##
===========================================================
+ Coverage 79.63% 79.69% +0.06%
===========================================================
Files 93 102 +9
Lines 9529 10095 +566
===========================================================
+ Hits 7588 8045 +457
- Misses 1941 2050 +109
Flags with carried forward coverage won't be shown. Click here to find out more.
|
I merged xmission/cost_layers into xmission/cost_paths on my computer. Should we just close this and delete the PR? |
Fine by me, i'll close this PR with out merging into mjb/.... and agreed lets delete mjb/... I'll delete it here so you just have to delete your remote branch |
No description provided.