Update interzonal transmission costs/distances and use directly calculated values#95
Update interzonal transmission costs/distances and use directly calculated values#95patrickbrown4 wants to merge 49 commits into
Conversation
…; only define co2_routes for r,rr pairs with nonzero distance
…thout an interfaces list
…ap() (no longer need to modify zone map in aggregate_regions.py)
… the cost and length of too-straight lines in transmission.py accordingly
There was a problem hiding this comment.
Removed because the versions that match the interzonal paths are in the zonehash.csv files; these no longer match
There was a problem hiding this comment.
Included so we can avoid adding more 'MW' or '$/MWmile' columns to the already-large transmission_cost_distance.csv; instead we just look it up from here using the voltage column
There was a problem hiding this comment.
The "name" column doesn't actually matter but including it here in case it's useful for backwards compatibility
There was a problem hiding this comment.
not directly related but was deferred earlier and it's on the list for #37
| return offshore_zones | ||
|
|
||
|
|
||
| def get_zonemap(case=None, exclude_water_areas=False, crs='ESRI:102008', **kwargs): |
There was a problem hiding this comment.
Updated to use the new zone node lat/lons and avoid need for county/mixed-specific processing
| GSw_TransSquiggliness,Transmission distance multiplier to approximate the squigglier paths followed by actual lines (only applied to NEW lines),float,1, | ||
| GSw_TransUpgradeMethod,Method for calculating AC transmission upgrade costs,500kv,500kv, | ||
| GSw_TransScen,Additional candidate interfaces for transmission expansion between zones,^(none|NTP_(MT|P2P))$,none, | ||
| GSw_TransSquigglinessMin,Minimum squiggliness (straight-line length multiplier) to apply for interzonal transmission; the default value is from the MISO Transmission Cost Estimation Guide (https://www.misoenergy.org/planning/transmission-planning/mtep),float,1.3, |
There was a problem hiding this comment.
The new routes are even straighter than the old, so I think now is a good time for this change (and it keeps us more aligned with MISO assumptions)
| scalars = reeds.io.get_scalars(case) | ||
|
|
||
| interface_params = reeds.inputs.get_distances(case) | ||
| ## Apply the minimum-squiggliness factor |
There was a problem hiding this comment.
This part is new; most of the rest is just reorganized
| # Mixed resolution procedure | ||
| if agglevel_variables['lvl'] == 'mult': | ||
| ### Model zones | ||
| dfba = gpd.read_file(os.path.join(reeds_path, 'inputs', 'shapefiles', 'US_PCA')) |
There was a problem hiding this comment.
With this change, we're no longer using this 134-zone shapefile directly. We can wait and remove it in a future PR though, since there might be upstream or downstream processes relying on it.
| [['r', 'rr', 'MW_forward', 'MW_reverse']] | ||
| .assign(trtype='AC') | ||
| ) | ||
| ### DEPRECATED: p19 is islanded with NARIS transmission data, so connect it manually |
There was a problem hiding this comment.
Dropped because we only calculate AC distances/costs for interfaces crossed by existing AC lines and this one is not crossed by any lines. So I think p19 is now islanded, but I didn't have any issues with extra ReEDS/PRAS iterations there (and we're now only ~2 PRs away from switching to 90 zones).
| dfcounty['r'] = county2zone | ||
| dfzones = dfcounty.dissolve('r') |
There was a problem hiding this comment.
Because this zone map is built from the county map, which is more detailed than the old US_PCA map, all the downstream calculations and plots that use the maps (accessed via reeds.io.get_dfmap() or maps.gpkg) are slowed down. There is a .simplify_coverage() function in geopandas 1.1 that we can use to simplify the geometry and speed them all up again, but it requires an update to the conda environment.
Elaine is also working on a gdxpds update; my plan is to go ahead with the current implementation for now, and then once the new gdxpds version is ready, do a holistic environment update to geopandas 1.1 / pandas 3 / python 3.14 / etc., so everyone only has to update their environment once.
There was a problem hiding this comment.
One other package that might be worth adding in an update is the highs package to give access to the HiGHS solver for things like representative period selection.
| Network reinforcement costs are approximated by tracing a path along existing transmission lines from each wind/solar POI to each zone "center" within the same state; | ||
| the zone center is usually taken as the largest population center in the model zone but is sometimes (for zones without large urban centers) assigned to a high-voltage substation within the zone.[^ref35] | ||
| A cost for each reinforcement route is calculated using the cost surface described above, with capital expenditure (CAPEX) costs multiplied by 50% to approximate the lower cost for reconductoring compared to greenfield transmission construction. | ||
| Network reinforcement costs are approximated by tracing a path along existing transmission lines from each wind/solar POI to a nearby urban center. |
There was a problem hiding this comment.
Can you quantify "nearby" and "urban center"? I can't remember the specifics, but this seems like a good place to document those.
| @@ -0,0 +1,9 @@ | |||
| voltage_kv,kcmil,conductor_type,conductor_quantity,amp | |||
There was a problem hiding this comment.
It's a silly U.S. unit but it's the standard measurement of wire gauge: https://en.wikipedia.org/wiki/Circular_mil
| Cross Sound Cable,330,-72.90222222,41.28666667,-72.8675,40.95916667 | ||
| Neptune Cable,660,-73.55111111,40.76055556,-74.35308333,40.47371667 | ||
| Trans Bay Cable,400,-121.89666667,38.03083333,-122.38583333,37.75472222 | ||
| name,MW,year_online,trtype,certain,from_lon,from_lat,to_lon,to_lat |
There was a problem hiding this comment.
Is year_online the number of years until it is online? If so, it might be worth updating the name, as I was expecting something like "2028" for the value rather than "0".
There was a problem hiding this comment.
Added a description to inputs/transmission/README.md and changed these to their actual historical online year
| @@ -0,0 +1,3 @@ | |||
| name,MW,year_online,trtype,certain,from_lon,from_lat,to_lon,to_lat | |||
| TransWestExpress,3000,2032,VSC,1,-107.176147,41.747242,-112.590781,39.541825 | |||
There was a problem hiding this comment.
This one has year_online as what I would expect, so I think I'm not understanding this column correcting, or what a zero value for this column means.
| ### TEMPORARY 20260402: Drop county interfaces with no distance/cost | ||
| if (level == 'r') and (sw.GSw_RegionResolution in ['county', 'mixed']): | ||
| transmission_line_fom = get_transmission_fom(case, interface_params) | ||
| indices = ['r', 'rr', 'trtype'] | ||
| drop = ( | ||
| dfout | ||
| .merge(transmission_line_fom.reset_index(), on=indices, how='left') | ||
| ) | ||
| drop = list(drop.loc[drop.USDperMWyear.isnull(), indices].itertuples(index=False)) | ||
| dfout = dfout.set_index(indices).drop(drop).reset_index() |
There was a problem hiding this comment.
Is this what is making WECC county runs fail (mentioned in your PR text)? Or does this make it not fail?
Yunzhi is nearly done with the WECC county bug fix, so it would be nice to not have it immediately broken again if that can be avoided, even if that meant a temporary patched solution until new reV data is available.
There was a problem hiding this comment.
No, it's a bit different; this is to keep GSw_ZoneSet = z3109 (county-level, which includes counties with no transmission links to neighbors) working until we finish reformatting the spatial pipeline, which will allow use of GSw_ZoneSet = z2972 (which aggregates those counties into their neighbors and avoids making islanded zones).
The missing SunZia line at county resolution is caught in check_inputs.py. But I'll add it before merging.
Summary
In the same vein as 2003, this PR:
Technical details
Implementation notes
Least-cost paths
There are a few updates to the interzonal least-cost path procedure:
inputs/transmission/conductor_{ac or dc}.csv, provide lookup tables for converting from the assumed kV to MW capacitySpatial flexibility
planned_lines-NTP_{MT or P2P}.csv), but now specify individual from/to endpointsinputs/transmission/README.mdinputs/transmission/newlinks_offshore_backbone.csvinputs/zones/{GSw_ZoneSet}/newlinks_offshore_radial.csvGSw_ZoneSetbecause the user might want to control which zone they make landfall in, particularly at county resolutiontransmission.pyAdditional changes
inputs/shapefiles/transmission_endpoints(now ininputs/zones/{GSw_ZoneSet}/zonehash.csv)copy_files.pyandaggregate_regions.pyreeds.io.get_zonemap()transmission.pyhas been reorganized to make it importablemin_co2_spurline_miles(= 20): moved from hard-coded intransmission.pytoscalars.csvSwitches added/removed/changed
GSw_TranScen: Allowable options changed tonone(default, meaning only interfaces with existing capacity can be expanded),NTP_MT, orNTP_P2PIssues resolved
Known incompatibilities
Validation, testing, and comparison report(s)
Here's some background info and plots of the new costs: 20260515 - transmission costs distances.pptx
I'll add compare reports to that deck as they come in.
Checklist for author
Details to double-check
New large data files handled with .h5 instead of .csv<- No, because we will add to the costs/distances as new zone geometries are addedGeneral information to guide review
Did you use LLM tools (chatbot or copilot) in the preparation of this PR? If so, describe how
No