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

Xmission/cost layers #122

Closed
wants to merge 60 commits into from
Closed

Conversation

mikebannis
Copy link
Collaborator

No description provided.

@mikebannis mikebannis requested a review from MRossol July 22, 2021 17:20
Copy link
Collaborator

@MRossol MRossol left a 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:

  1. 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
  2. Can we remove the old modules/methods that this will replace?

reVX/least_cost_xmission/config/xmission_config.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/config/xmission_config.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/config/xmission_config.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/config/xmission_config.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
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,
Copy link
Collaborator

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Renamed.

Copy link
Collaborator Author

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.

Copy link
Collaborator

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?

reVX/least_cost_xmission/cost_creator.py Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
# TODO - use self._profile instead of regions file
self._init_h5(h5_fpath, iso_regions_fpath)

self._tiff_dir = tiff_dir
Copy link
Collaborator

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

Copy link
Collaborator Author

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.

Copy link
Collaborator

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

Copy link
Collaborator Author

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.

Copy link
Collaborator 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

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

Copy link
Collaborator Author

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
Copy link
Collaborator

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?

reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
@mikebannis mikebannis force-pushed the xmission/cost_layers branch 3 times, most recently from 836292c to b7b3b6b Compare July 27, 2021 19:56
@MRossol MRossol self-requested a review July 29, 2021 15:52
"""
super().__init__()

if power_to_voltage_fpath is None:
Copy link
Collaborator

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):

Copy link
Collaborator Author

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):
Copy link
Collaborator

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.

Copy link
Collaborator Author

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?

Copy link
Collaborator

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.

reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
reVX/least_cost_xmission/cost_creator.py Outdated Show resolved Hide resolved
for i in indices:
mult_raster[i[0]] = i[1]

return mult_raster
Copy link
Collaborator

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

  1. run build_test_costs
  2. add any extra layers using layers_to_h5

Copy link
Collaborator Author

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?

Copy link
Collaborator

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



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, {})
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

Copy link
Collaborator

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?

@MRossol
Copy link
Collaborator

MRossol commented Jul 29, 2021

@mikebannis getting super close! This is looking great. A few minor comments

@MRossol
Copy link
Collaborator

MRossol commented Jul 29, 2021

one more comment, lets split the test file into two:

  1. test_xmission_cost_creator.py
  2. test_xmission_least_cost.py

@MRossol
Copy link
Collaborator

MRossol commented Aug 5, 2021

@mikebannis wanted to check in on this PR, would be nice to wrap this up before the next one...

@mikebannis
Copy link
Collaborator Author

Working on the path finding code. I'll wrap this up tonight or tmw

@MRossol
Copy link
Collaborator

MRossol commented Aug 5, 2021

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,
Copy link
Collaborator

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
Copy link
Collaborator

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?

@@ -4,7 +4,7 @@
"""
import os

from .xmission_config import XmissionConfig
from reVX.least_cost_xmission.config.xmission_config import XmissionConfig
Copy link
Collaborator Author

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.

Copy link
Collaborator

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]}}
Copy link
Collaborator Author

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?

Copy link
Collaborator

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-commenter
Copy link

codecov-commenter commented Aug 11, 2021

Codecov Report

Merging #122 (2894b8c) into mjb/feat/x-mission-path (adab7d9) will increase coverage by 0.06%.
The diff coverage is 78.52%.

Impacted file tree graph

@@                     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     
Flag Coverage Δ
unittests 79.69% <78.52%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
reVX/handlers/xmission_cost_layers.py 0.00% <0.00%> (ø)
reVX/least_cost_xmission/least_cost_xmission.py 0.00% <0.00%> (ø)
reVX/least_cost_xmission/utilities.py 0.00% <0.00%> (ø)
reVX/utilities/exclusions_converter.py 76.99% <ø> (ø)
setup.py 0.00% <ø> (ø)
reVX/handlers/geotiff.py 71.72% <33.33%> (+6.23%) ⬆️
reVX/least_cost_xmission/config/xmission_config.py 50.00% <50.00%> (ø)
reVX/least_cost_xmission/cost_creator_cli.py 68.53% <68.53%> (ø)
reVX/plexos/simple_plant_builder_cli.py 84.37% <84.37%> (ø)
reVX/least_cost_xmission/cost_creator.py 84.72% <84.72%> (ø)
... and 34 more

@mikebannis
Copy link
Collaborator Author

I merged xmission/cost_layers into xmission/cost_paths on my computer. Should we just close this and delete the PR?
At this point I'm tempted to just delete mjb/feat/x...

@MRossol
Copy link
Collaborator

MRossol commented Aug 13, 2021

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

@MRossol MRossol closed this Aug 13, 2021
@MRossol MRossol deleted the xmission/cost_layers branch August 13, 2021 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants