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

feat: add storage expansion results to Grid #104

Merged
merged 11 commits into from
Jun 17, 2021

Conversation

danielolsen
Copy link
Contributor

@danielolsen danielolsen commented Jun 9, 2021

Pull Request doc

Purpose

  • Bugfixes to storage data preparation (follow-up to feat: add storage candidate buses to Switch input preparation #101).
    • some sloppy refactoring on my part, plus
    • we had not added the Switch storage module to the list of modules to import, so Switch was ignoring all the storage data we were providing, so we did not realize that we were not providing the full set of required information.
  • Add storage expansion results to Grid (serves Build a Grid object #49).

What the code is doing

  • In const.py: the previously mentioned bugfix constants.
  • In grid_to_switch.py: the previously-mentioned bugfix logic
  • In helpers.py:
    • We add a recover_storage_buses function which translates Switch storage expansion candidates into bus IDs (following the pattern from feat: add storage candidate buses to Switch input preparation #101)
    • We add a split_plant_existing_expansion function which separates a list of plant IDs into real and hypothetical (this was needed to fix a bug that popped up within add_gen_upgrades_to_grid, when existing generators with Pmax = 0 are present in the input data).
  • In switch_to_grid.py:
    • extract_build_decisions is expanded to return generation, transmission, and storage energy decisions.
    • in add_gen_upgrades_to_grid, we make some small changes to indexing to ensure that we only process generator expansions (not storage, not existing generators).
    • We add a new function add_storage_upgrades_to_grid, which does what's expected following the name.

Testing

Tested manually on results files generated both with and without storage candidates.

Code used to prepare inputs with storage candidates:

>>> import os
>>> import pandas as pd
>>> from powersimdata import Scenario
>>> from switchwrapper.prepare import prepare_inputs
>>> scenario = Scenario(599)
>>> grid = scenario.get_grid()
>>> profiles = {
...     "demand": scenario.get_demand(),
...     "hydro": scenario.get_hydro(),
...     "solar": scenario.get_solar(),
...     "wind": scenario.get_wind(),
... }
>>> timepoints = pd.read_csv("timepoints_input_v2.csv", index_col=0)
>>> timestamps_to_timepoints = pd.read_csv("slicing_recovery.csv", index_col=0).squeeze()
>>> prepare_inputs(grid, profiles, timepoints, timestamps_to_timepoints, "prepared", storage_candidate_buses={2010001, 2010002})
Please enter base study year (normally PowerSimData scenario year): 2030
Please enter the number of investment stages: 1
Single stage expansion identified.
Please enter investment period year, separate by space: 2030
Please enter start year for each period, separate by space: 2030
Please enter end year for each period, separate by space: 2030
>>>

To analyze the results:

>>> import pickle
>>> from powersimdata import Scenario
>>> from switchwrapper.switch_to_grid import construct_grids_from_switch_results
>>> filename = "path_to_results_file\results.pickle"
>>> with open(filename, "rb") as f:
...     results = pickle.load(f)
...
>>> grid = Scenario(599).get_grid() # the grid used as input to this Switch run
>>> all_grids = construct_grids_from_switch_results(grid, results)
>>>

For this example, there are storage results, as verified via:

>>> import re
>>> sorted({re.search(r"(.*)\[", v).group(1) for v in results.solution._list[0]["Variable"]})
['BuildGen', 'BuildLocalTD', 'BuildStorageEnergy', 'BuildTx', 'ChargeStorage', 'DispatchBaseloadByPeriod', 'DispatchGen', 'DispatchTx', 'GenFuelUseRate', 'StateOfCharge', 'WithdrawFromCentralGrid']

But no storage capacity is build, so there is no storage added to the resulting Grid:

>>> all_grids[2030].storage
{'gen': Empty DataFrame
Columns: [bus_id, Pg, Qg, Qmax, Qmin, Vg, mBase, status, Pmax, Pmin, Pc1, Pc2, Qc1min, Qc1max, Qc2min, Qc2max, ramp_agc, ramp_10, ramp_30, ramp_q, apf, mu_Pmax, mu_Pmin, mu_Qmax, mu_Qmin]
Index: [], 'gencost': Empty DataFrame
Columns: [type, startup, shutdown, n, c2, c1, c0]
Index: [], 'StorageData': Empty DataFrame
Columns: [UnitIdx, InitialStorage, InitialStorageLowerBound, InitialStorageUpperBound, InitialStorageCost, TerminalStoragePrice, MinStorageLevel, MaxStorageLevel, OutEff, InEff, LossFactor, rho, ExpectedTerminalStorageMax, ExpectedTerminalStorageMin]
Index: [], 'genfuel': [], 'duration': None, 'min_stor': None, 'max_stor': None, 'InEff': None, 'OutEff': None, 'LossFactor': None, 'energy_price': None, 'terminal_min': None, 'terminal_max': None}

Time estimate

30 minutes.

@danielolsen danielolsen self-assigned this Jun 9, 2021
@rouille rouille removed their request for review June 9, 2021 23:57
@danielolsen danielolsen requested review from jenhagg and removed request for lanesmith June 10, 2021 17:57
switchwrapper/helpers.py Outdated Show resolved Hide resolved
@BainanXia
Copy link
Collaborator

Correct me if I'm wrong: there are two parameters that we need to extract for each storage expansion candidate: 1) capacity, which is specified within the group of generators, i.e. BuildGen, and it gives the maximum input/output power of a storage device 2) energy, which is specified within the particular group "BuildStorageEnergy", and it gives the maximum energy that a specific storage device could store. What is the relationship of the same entry between different investment years? Are they cumulative values that we could take directly or deltas that we need to do a cumulative sum?

@danielolsen
Copy link
Contributor Author

Correct me if I'm wrong: there are two parameters that we need to extract for each storage expansion candidate: 1) capacity, which is specified within the group of generators, i.e. BuildGen, and it gives the maximum input/output power of a storage device 2) energy, which is specified within the particular group "BuildStorageEnergy", and it gives the maximum energy that a specific storage device could store.

This is correct.

What is the relationship of the same entry between different investment years? Are they cumulative values that we could take directly or deltas that we need to do a cumulative sum?

This is a very good question! I don't know, but we have the same concerns for generation and transmission. Currently, we are processing the Switch results as if they are cumulative, but that could be wrong. It will need further investigation.

@danielolsen danielolsen force-pushed the daniel/add_storage_results branch from 3145892 to 3b2c369 Compare June 14, 2021 16:16
@danielolsen danielolsen mentioned this pull request Jun 14, 2021
switchwrapper/helpers.py Outdated Show resolved Hide resolved
@danielolsen danielolsen force-pushed the daniel/add_storage_results branch 4 times, most recently from 721ac97 to fe6c3a0 Compare June 17, 2021 17:03
@danielolsen
Copy link
Contributor Author

I added a couple more commits so that we can successfully call get_pg even when there are some storage candidates in the inputs, and therefore storage dispatch in the results:

  • match_variables and parse_timepoints now have a new parameter value_name, rather than hard-coding that the returned variable values are labaled "capacity" (as we did when we originally set up extraction of grid build decisions).
  • We pass value_name="dispatch" within SwitchExtract._get_parsed_data
  • We index into this MultiIndex (`("capacity", foo), ("capacity", bar), ...) to only return the PG values of the plants, not the storage devices.

@danielolsen danielolsen force-pushed the daniel/add_storage_results branch from 9497144 to a5e5b29 Compare June 17, 2021 18:50
switchwrapper/helpers.py Outdated Show resolved Hide resolved
@BainanXia
Copy link
Collaborator

Looks good to me. We can merge this once @YifanLi86 is happy.

Copy link
Collaborator

@BainanXia BainanXia left a comment

Choose a reason for hiding this comment

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

I do like it!

@danielolsen danielolsen force-pushed the daniel/add_storage_results branch from f6e78a4 to fb5a8ac Compare June 17, 2021 20:40
@danielolsen danielolsen merged commit f968eed into output_processing Jun 17, 2021
@danielolsen danielolsen deleted the daniel/add_storage_results branch June 17, 2021 20:41
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.

4 participants