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

Adds a script to run sensitivities #44

Merged
merged 7 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/plot_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def power_by_carrier(n):
n.generators.carrier).sum().T

if not n.storage_units.empty:
sto = n.storage_units_t.p.T.groupby(
sto = n.storage_units_t.p.T.clip(lower=0).groupby(
lshaver marked this conversation as resolved.
Show resolved Hide resolved
n.storage_units.carrier).sum().T
p_by_carrier = pd.concat([p_by_carrier, sto], axis=1)

Expand Down
72 changes: 72 additions & 0 deletions sensitivity-script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
import re
import itertools
import shutil

# Path to the base config file
base_config_file = "config.yml"
backup_config_file = "config_backup.yml"

# Backup the original config file to restore it later
shutil.copyfile(base_config_file, backup_config_file)

# Define the variables and their possible values
variable_ranges = {
'fuel_cost_year': [2018,2019,2020,2021,2022,2023],
'load_growth': [0, 1],
'total_demand': [136e6, 185e6],
'atb_scenario': ['Moderate'] # 'Conservative', 'Advanced'
}

# Create a string of all the rules that must be forced to run
forcerun = "retrieve_fuel_costs add_electricity" # add retrieve_costs when also modifying atb scenarios

# Generate all possible combinations of the variables
variable_combinations = list(itertools.product(
variable_ranges['fuel_cost_year'],
variable_ranges['load_growth'],
variable_ranges['total_demand'],
variable_ranges['atb_scenario']
))

# ATB scenarios must be handled differently because sub-parameters can't be passed to snakemake in the command line
atb_scenario_targets = ["scenario: \'Moderate\'", "scenario: \'Conservative\'", "scenario: \'Advanced\'"]

# Function to modify the atb_params in the config file (from ChatGPT)
def replace_strings_in_config(file_path, target_strings, new_value):
lshaver marked this conversation as resolved.
Show resolved Hide resolved
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()

pattern = '|'.join(map(re.escape, target_strings))
updated_content = re.sub(pattern, new_value, content)

with open(file_path, 'w', encoding='utf-8') as file:
file.write(updated_content)

run_no = 0
for idx, (fuel_cost_year, load_growth, total_demand, atb_scenario) in enumerate(variable_combinations):
# Name the scenario
scenario = f"cost-{fuel_cost_year}_growth-{load_growth}_demand-{total_demand:.2E}_atb-{atb_scenario}"

# Combine all the top-line config variables
config = f"time_res=1 fuel_cost_year={fuel_cost_year} load_growth={load_growth} total_demand={total_demand} scenario={scenario}"

# Modify the config file to update the ATB scenario.
# This is disabled because the model won't run -- alternate scenarios don't exist for nuclear
#atb_scenario_text = f"scenario: \'{atb_scenario}\'"
#replace_strings_in_config(base_config_file, atb_scenario_targets, atb_scenario_text)

# Run Snakemake, passing the new variables as configs
print(f"Running Snakemake with config {run_no} and the following command:")
print(f"snakemake --cores=4 --forcerun {forcerun} --config {config}")
os.system("snakemake --delete-all-output --cores=1") # this could probably be optimized to not delete everything
lshaver marked this conversation as resolved.
Show resolved Hide resolved
os.system(f"snakemake --cores=4 --forcerun {forcerun} --config {config}")
run_no += 1

# for debugging:
#if run_no == 1: break

# Restore the original base config after running all scenarios
shutil.copyfile(backup_config_file, base_config_file)
os.remove(backup_config_file)
print("Restored the original config file.")
27 changes: 27 additions & 0 deletions sensitivity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Variables to change for sensitivities

- **Coal and methane prices.** Fuel prices are modeled as 12 values from a historical year, derived from this PUDL database: https://data.catalyst.coop/pudl/core_eia923__monthly_fuel_receipts_costs.
- **ATB cases.** The model uses the 2022 ATB, which has three scenarios: "Moderate", "Conservative", and "Advanced". For sensitivity analysis we can ignore "Moderate" and just use "Conservative" and "Advanced".
lshaver marked this conversation as resolved.
Show resolved Hide resolved
- **Demand growth.** This will be modeled as either 0.00 or 1.00.
- **Exports.** There's no toggle or setting for this -- rather the starting load determines whether or not the model is matching the in-state load or the in-state generation. For no export the starting value should be 136e6; for export it should be 185e6.

| Parameter | Variable in `config.yml`| Scripts | Values |
|-------------|-------------------------|-----------------------------------------------|----------------------------------|
|Fuel prices |`fuel_cost_year` |`retrieve_fuel_prices.py`, `add_electricity.py`|2018, 2019, 2020, 2021, 2022, 2023|
|ATB cases |`scenario` |`retrieve_costs.py` |"Conservative", "Advanced" |
|Demand growth|`load_growth` |`add_electricity.py` |0.00, 1.00 |
|Exports |`total_demand` |`add_electricity.py` |136e6, 185e6 |

Total possibilities = 6x2x2x2 = 48

The order in the snakemake workflow of the rules we need to modify:

| Rule | Script |
|------|-------------------------|
|3 |`retrieve_costs.py` |
|4 |`retrieve_fuel_prices.py`|
|11 |`add_electricity.py` |

# Remove ATB cases

There are no conservative or advanced cases for nuclear in the ATB which causes the model to crash. The simplest workaround is just to not do sensitivites on ATB scenarios.
lshaver marked this conversation as resolved.
Show resolved Hide resolved