Skip to content

Add random vector sampling method to MGA - #162

Open
bsergi wants to merge 46 commits into
mainfrom
bs/mga_rv
Open

Add random vector sampling method to MGA#162
bsergi wants to merge 46 commits into
mainfrom
bs/mga_rv

Conversation

@bsergi

@bsergi bsergi commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a new capability to the existing MGA method to support random vector sampling across subcategories of the variables being explored.

Technical details

The current MGA method applies the minimization (or maximization) to the sum of a variable across all modeled regions (e.g., total U.S. solar capacity or fossil generation). The random vector method assigns randomly-sampled weights to the regional quantities applied before the summation. This technique allows for exploring the regional distribution of capacity and generation results in the near-optimal space.

As an illustration, the plot below shows the range of natural gas capacity by region (using the 54-zones) from 100 runs with the MGA random vector method with a 1% cost threshold. The MGA max/min squares indicate the results from the previous, nationwide-method; the original min/max approach is better suited for getting a wider range of total capacity, whereas the new method is better geared toward understanding uncertainty at a regional level.

image

Implementation notes

  • The weights are generated by themain_mga_rv function in mcs_sampler.py, with the number of samples (runs) controlled by GSw_MGA_RV_runs.
  • Regional weights are drawn from a support of {-1,1} with equal probability; including both negative and positive values allows for exploring minimization in one region and maximization in another.
    • The method in mcs_sampler.py can support linear sampling from [-1,1] using a uniform distribution. Initial tests suggested this didn't yield as much of a signal so we haven't implemented a switch to control this.
    • The regionality at which unique weights are sampled is controlled by GSw_MGA_RV_region and can be any level in the hierarchy file.
  • Currently this method is only supported for GSw_MGA_Objective = (capacity or generation), with weights generated by region and technology group (i_subtech).
    • If GSw_MGA_SubObjective is an aggregated tech category (e.g., gentech), unique weights will be sampled for the different i_subtech groups within the larger category.
  • Weights are read in by b_inputs.gms and applied to the MGA objective function in d_mga.gms.

Additional changes

Added a run using the random vector method to cases_test.csv.

Switches added/removed/changed

  • GSw_MGA_RV_runs: number of random weight vectors to draw; corresponds to the number of ReEDS runs.
  • GSw_MGA_RV_region`: level of regionality at which to sample the random weights.

Relevant sources or documentation

The random vector method has been used in previous MGA studies (examples here and here

Validation, testing, and comparison report(s)

Will run reference case tests once the HPC is back in service. Will also link a slide deck with some results using this method.

Checklist for author

Details to double-check

  • Charge code provided to reviewers
  • Included comparison reports for appropriate test cases
  • Documentation updated if necessary
  • If input data added/modified:
    • Dollar year recorded and converted to 2004$ for GAMS
    • Timeseries are in Central Time
    • Units are specified
    • Preprocessing steps have been documented and committed to ReEDS_Input_Processing
    • New large data files handled with .h5 instead of .csv
    • If new parameters are added to d_objective.gms, they are included in objective_function_params.yaml for completeness checking
    • If spatially resolved inputs are modified, the following visualizations for each file are included in the PR description (time-averaged if the inputs are time-resolved):
      • Map of absolute values before
      • Map of absolute values after
      • Map of differences: (after - before) or (after / before)
    • If entries are added/removed/changed in the EIA-NEMS unit database:
      • Changes have been committed to ReEDS_Input_Processing
      • hourlize/resource.py was rerun to regenerate the existing/prescribed VRE capacity data
  • 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

Tag points of contact here if you would like additional review of the relevant parts of the model

Comment thread reeds/inputs.py
print(f"\n[Warning] Case Column: '{c}'")
print(
"You are attempting to run a Monte Carlo simulation with "
"You are attempting to run a Monte Carlo or MGA Random Vector simulation with "

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 probably doesn't matter since the MGA runs should all have the same inputs, but I left it in for now in case there's a non-deterministic component to the representative day sampling.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the inputs are unchanged then the rep days will be unchanged, so I'm pretty sure we can remove the check for RV and only keep it for MCS, which makes it a little easier to use.

@bsergi
bsergi marked this pull request as ready for review July 27, 2026 20:54
@bsergi
bsergi requested a review from patrickbrown4 July 27, 2026 20:54
@bsergi
bsergi requested a review from atpham88 July 27, 2026 20:54

@patrickbrown4 patrickbrown4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks great! The only critical comment is in d_mga.gms; all the rest are minor cleanups. Approving now but should still confirm zero change before merging.

inflation.csv,inputs/financials/inflation_{inflation_suffix}.csv,1,ignore,ignore,,,,0,0,,,,,,
interconnection_queues.csv,inputs/capacity_exogenous/interconnection_queues.csv,1,ignore,ignore,r,"tg,r",,1,0,,,,,,
jtype.csv,inputs/sets/jtype.csv,1,ignore,ignore,,,,,,,,set,jtype,job types used in model (construction and om),
jtype.csv,inputs/sets/jtype.csv,1,ignore,ignore,,,,,0,,,set,jtype,job types used in model (construction and om),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

jtype.csv doesn't have a header so I think the changes to this file should be reverted

Comment thread reeds/inputs.py
print(f"\n[Warning] Case Column: '{c}'")
print(
"You are attempting to run a Monte Carlo simulation with "
"You are attempting to run a Monte Carlo or MGA Random Vector simulation with "

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the inputs are unchanged then the rep days will be unchanged, so I'm pretty sure we can remove the check for RV and only keep it for MCS, which makes it a little easier to use.

Comment thread reeds/inputs.py
Comment on lines +286 to +292
if int(dfcases[c].MCS_runs) > 0:
mcs_sampler.general_mcs_dist_validation(reeds.io.reeds_path, mcs_dist_path, sw)
numruns = int(dfcases[c].MCS_runs)
run_type = 'MC'
else:
numruns = int(dfcases[c].GSw_MGA_RV_runs)
run_type = 'R'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MCS and RV are mutually incompatible, right (at least in the current implementation, which is totally ok)? If so, should probably add a check to runreeds.check_compatibility() that raises an exception if MCS_runs and GSw_MGA_RV_runs are both nonzero.

import pandas as pd
import scipy.stats
import sys
import re

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(minor cleanup) can remove since unused

Suggested change
import re

Comment on lines +2013 to +2014

# %%

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
# %%

Comment thread docs/source/user_guide.md

By default the MGA min/max is applied to the sum of the variable across all regions being modeled.
The MGA approach also supports an option to randomly sample of a vector of weights to apply to the regional values of the variable being optimized.
This method can be useful to characterizing the uncertainty in the regional distribution of the results.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
This method can be useful to characterizing the uncertainty in the regional distribution of the results.
This method can be used to characterize the uncertainty in the regional distribution of the results.

Comment thread docs/source/user_guide.md
By default the MGA min/max is applied to the sum of the variable across all regions being modeled.
The MGA approach also supports an option to randomly sample of a vector of weights to apply to the regional values of the variable being optimized.
This method can be useful to characterizing the uncertainty in the regional distribution of the results.
Weights are sampled as discrete values from a support of {-1,1} to allow for simultaneous minimization and maximization.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just to check, is "support" the right word here? (I'm unfamiliar with this usage but also don't know much stats)

Comment thread docs/source/user_guide.md

The MGA random vector capability is controlled by the following switches:
- `GSw_MGA_RV_runs` (default `0`): Number of random samples of weight vectors to draw; corresponds to the number of runs.
- `GSw_MGA_RV_region` (default `r`): Regionality level (specified by hierarhcy file) over which to sample the random weights.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
- `GSw_MGA_RV_region` (default `r`): Regionality level (specified by hierarhcy file) over which to sample the random weights.
- `GSw_MGA_RV_region` (default `r`): Regionality level (specified by hierarchy file) over which to sample the random weights.

Comment on lines +6055 to +6058
*TODO: add different handling for other subobjectives with different dimensions
* should we also include error checking?


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Best to move to issue if you still want to address it (or just remove if it's old)

Suggested change
*TODO: add different handling for other subobjectives with different dimensions
* should we also include error checking?

Comment on lines +29 to +42
* ---------------------------------------------------------------------------

$elseif.mgaobj %GSw_MGA_Objective% == 'generation'
Equation eq_MGA_Objective "--MW-- Defines generation for MGA" ;
Variable MGA_OBJ "--MWh-- Generation of technology to be minimized/maximied" ;
eq_MGA_Objective$Sw_MGA..
MGA_OBJ
=e=
sum{(i,v,r,h,t)
$[tmodel(t)
$valgen(i,v,r,t)
$%GSw_MGA_SubObjective%(i)],
GEN(i,v,r,h,t) * hours(h)
* sum{i_subtech$i_subsets(i,i_subtech), mga_weights(r,i_subtech)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicates the next block below; can instead just add * sum{i_subtech$i_subsets(i,i_subtech), mga_weights(r,i_subtech)} to the existing $elseif.mgaobj %GSw_MGA_Objective% == 'generation' block

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.

3 participants