Skip to content

Fix Monte Carlo random sampling for VRE siting availability - #249

Open
patrickbrown4 wants to merge 25 commits into
mainfrom
pb/mc
Open

patrickbrown4 wants to merge 25 commits into
mainfrom
pb/mc

Conversation

@patrickbrown4

@patrickbrown4 patrickbrown4 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR partially addresses #41 by fixing the Monte Carlo sampling functionality for VRE siting availability.

Latin hypercube sampling for VRE siting availability is still broken; we can decide whether to fix that here or in a followup PR.

Technical details

Implementation notes

  • The original sampling approach for siting was designed around the old region/class profiles; now that we use site-level profiles, that approach would be much more time- and memory-intensive.
  • We used to reweight the profiles based on the capacity in the sampled supply curve. Profiles do vary at the site level (see Fix Monte Carlo sampling for demand and VRE availability #41 for some background discussion and plots), but not very much.
  • So now we read a set of site-level profiles for the most permissive siting scenario included in the specified Monte Carlo distribution. For example, if the distribution includes both limited and reference access, the reference-access site profiles will be used; if it includes reference and open, the open-access profiles will be used.
    • There are sites in limited that are not in reference/open, and sites in reference that are not in open. So for Monte Carlo sampling, we ignore site mismatches between the profiles and the supply curves (printing messages to the user)

Additional changes

  • writecapdat.py: I was having trouble following the structure while debugging, so reorganized to put the globals at the top and renamed a few variables (sorry)
    • The substantive changes ended up just being to assign_class(); I was getting float classes (instead of integers) without this change, which were messing up downstream processing.
  • mcs_sampler.py: We no longer need the exogenous or prescribed capacity processing, so those parts are removed along with the recf profile processing.
  • mcs_distributions_default.yaml:
    • Updated AEO switches from 2025 to 2026
    • Tweaked a few scenario definitions to match what was used in the conference paper (we could still do more here to unify the naming and clarify the structure and options)
  • I wanted to check the offshore-zones functionality (MARICTNYNJPAOH_Offshore) since I touched the supply curves but it was already broken. So I included a fix for it in this PR.

Issues resolved

#41 (partially)

Known incompatibilities

  • I'm still getting an error for the MonteCarlo_LHS (latin hypercube) case when siting is included; I'm not sure why it's behaving differently from MonteCarlo_Random. I think the fix to random sampling is valuable enough to get in on its own, but if the LHS case ends up being a quick/easy fix, we can include it here too.

TODO before merge

  • Double check that the supply-curve sampling results make sense. Are all the site capacities somewhere between the capacities in the scenarios that define the distribution?
  • Debug full-USA MC run (error in missing_class_resource.csv)

Validation, testing, and comparison report(s)

Changes to USA_defaults are within the noise: results-v20261009_mainK0_USA_defaults,v20261009_mcK0_USA_defaults.pptx

The MonteCarlo_Random case now works with VRE siting included in the distribution.

Here's a full-US example with 10 samples and MCS_dist_groups set to load_flat_country.siting_lowmid_country.gasprice_flat.upv.onswind.ofswind.battery.nuclear.geo:
results-1,2,3,4,5,6,7,8,9,10.pptx

20261019 update

Checklist for author

Details to double-check

  • Charge code provided to reviewers
  • Included comparison reports for appropriate test cases
  • Code formatting standardized
  • Reusable functions used where possible instead of copy/pasted code

General information to guide review

  • Zero impact on results of default case
  • No large data file(s) added/modified
  • No substantive impact on runtime for full-US reference case
  • No substantive impact on folder size for full-US reference case
  • No change to process flow (runreeds.py, reeds/core/solve/solve.py)
  • No change to code organization
  • No change to package requirements (environment.yml or Project.toml)

Did you use LLM tools (chatbot or copilot) in the preparation of this PR? If so, describe how

No

@patrickbrown4
patrickbrown4 marked this pull request as draft October 7, 2026 20:09
@patrickbrown4
patrickbrown4 marked this pull request as ready for review October 7, 2026 23:23
@patrickbrown4
patrickbrown4 marked this pull request as draft October 7, 2026 23:39
@patrickbrown4
patrickbrown4 marked this pull request as ready for review October 9, 2026 15:57
@patrickbrown4
patrickbrown4 requested a review from bsergi October 9, 2026 16:13
Comment on lines +81 to +84
if (tech == 'wind-ofs') and int(sw.GSw_OffshoreZones):
gdf_joined['r'] = gdf_joined['ba']
else:
gdf_joined['r'] = gdf_joined['r_nearest']

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the only substantive change to this script (to get offshore zones working again); the rest were just to help me follow things while debugging

Comment thread runreeds.py
'copy_files',
'process_unitdata',
'mcs_sampler',
'process_unitdata',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Need to run after the sampling since it assigns existing capacity to sites

Comment thread cases_test.csv
,Default Value,Pacific,USA_defaults,Mid_Case,USA_decarb,github_Pacific,github_Everything,github_MA_county_CC,Pacific_CC,Pacific_weks,Pacific_full_year,Interday_storage,Pacific_2020,Pacific_rep15,WY_county,WECC_county,PJM_county_CC,NYVT_mixed,OR_water,MonteCarlo_Random,MonteCarlo_LHS,Everything,Simple,USA_fast,USA_faster,MultiMetricRA,Pacific_DR,Pacific_MGA,Pacific_MGA_RV,Pacific_LoadSite95,MARICTNYNJPAOH_Offshore,R2P
ignore,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
GSw_Region,cendiv/Pacific,,country/USA,country/USA,country/USA,,st/ID.WY.NE.IA.IL,st/MA,,,,,,,st/WY,interconnect/western,transreg/PJM,st/NY.VT,st/OR,st/NE.NY.PA,st/NE.NY.PA,st/ID.WY.NE.IA.IL,st/KS,country/USA,country/USA,st/NY.NJ,,,,,st/MA.RI.CT.NY.NJ.PA.OH,
GSw_Region,cendiv/Pacific,,country/USA,country/USA,country/USA,,st/ID.WY.NE.IA.IL,st/MA,,,,,,,st/WY,interconnect/western,transreg/PJM,st/NY.VT,st/OR,,,st/ID.WY.NE.IA.IL,st/KS,country/USA,country/USA,st/NY.NJ,,,,,st/MA.RI.CT.NY.NJ.PA.OH,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Changed from NE.NY.PA to Pacific to avoid the islanded-zones warning added in #243

Comment thread cases_test.csv
GSw_HourlyClusterAlgorithm,,,,,,,,,,,,,,,,,,,,user,user,,,,,,,,,,,
MCS_runs,,,,,,,,,,,,,,,,,,,,2,2,,,,,,,,,,,
MCS_dist_groups,,,,,,,,,,,,,,,,,,,,tech.hydro.nuclear.gas.coal.load_country,upv_tri.nuclear_tri.ng_fuel_price_tri.load_country_unif,,,,,,,,,,,
MCS_dist_groups,,,,,,,,,,,,,,,,,,,,load_flat_state.gasprice_flat.siting_flat_state.upv.onswind.ofswind.battery.nuclear.geo,load_country_unif.gasprice_tri.siting_country_discrete_flat.upv_tri.nuclear_tri,,,,,,,,,,,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I added siting to the LHS case, but it's not yet supported. @bsergi let me know if you'd rather leave it out until we fix it for LHS.

case=os.path.dirname(os.path.normpath(inputs_case)),
agg=agg,
).reset_index()
df = reeds.io.get_supplycurve(full_path, case=inputs_case)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now we just get the initial supply curve and assemble the full curve (i.e. add the interconnection costs) only once downstream in writesupplycurves.py, rather than assembling it twice (which complicates the MC sampling)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We could spend more time unifying the naming of the distributions in this file; let me know if you think we should do that here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Some of the changes here are just formatting. The main substantive change is that I removed the exogenous/prescribed sampling (since it's now handled downstream in process_unitdata.py) and only sample the capacity from the supply curve, inheriting the cf and profiles from the most permissive siting scenario included in the distribution.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry, a lot of these changes were just to help understand the organization while I was debugging.

pd.read_csv(os.path.join(inputs_case, 'classification_geothermal.csv'))
.query(f"access_case == '{sw.GSw_SitingGeo}'")

def get_class_cf_min(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this set of 3 functions is the main substantive change. While testing different zone sets, I was getting issues for cases where there was only a single site in a zone/tech_class combo. Now instead of defining min and max for each class, we just define min, and take the first match.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant