Skip to content

Remove system-level outputs from storage and replace with demand component (follow-on to 631)#666

Open
elenya-grant wants to merge 46 commits intoNatLabRockies:developfrom
elenya-grant:storage/standalone_outputs
Open

Remove system-level outputs from storage and replace with demand component (follow-on to 631)#666
elenya-grant wants to merge 46 commits intoNatLabRockies:developfrom
elenya-grant:storage/standalone_outputs

Conversation

@elenya-grant
Copy link
Copy Markdown
Collaborator

@elenya-grant elenya-grant commented Apr 10, 2026

Remove system-level outputs from storage and replace with demand component (follow-on to 631)

There has been a blurry line distinguishing system-level calculations and calculations done in storage performance models. This PR builds on PR #631 to resolve Issue #521. The storage performance outputs that depend on demand have been removed and the usage of demand components in the examples is more common. The outputs removed from storage performance models are:

  • unmet_{commodity}_demand_out: demand that has not been met
  • unused_{commodity}_out: production that exceeds the demand
  • storage_{commodity}_out: charge/discharge profile

The outputs with different calculations in the storage performance models are:

  • {commodity}_out: this used to be the combined commodity out from storage and whatever was input to storage, minus any production that exceeds the demand. This is now what storage_{commodity}_out used to be
  • capacity_factor: used to be the based on the combined commodity out, now it based on the sum of the charge/discharge profile
demand_calcs demand_commodity_out

This PR helps to better distinguish the differences between individual storage performance models and "system-level" performance calculations. This PR also enables the ability for the storage demand to be distinct from the overall demand. For example, if we wanted to use a battery to try to just keep an electrolyzer system on (at 10% power), then the demand profile to the battery would be 10% of the electrolyzer capacity, whereas the demand for the demand component would be equal to the electrolyzer capacity.

Section 1: Type of Contribution

  • Feature Enhancement
    • Framework
    • New Model
    • Updated Model
    • Tools/Utilities
    • Other (please describe):
  • Bug Fix
  • Documentation Update
  • CI Changes
  • Other (please describe):

Section 2: Draft PR Checklist

  • Open draft PR
  • Describe the feature that will be added
  • Fill out TODO list steps
  • Describe requested feedback from reviewers on draft PR
  • Complete Section 7: New Model Checklist (if applicable)

TODO:

  • Get PR Update Naming Convention in Open-Loop Converter Control Strategies #631 merged in
  • Update storage_baseclass.py so that demand is only an input if using feedback control (not doing just yet)
  • make figures to show what's happening in demand components for different use-cases
    • these figures have been added to docs/demand/demand_components.md
  • add test to test_all_examples for example 13
  • update or add doc page for example 13 in controller docs

Type of Reviewer Feedback Requested (on Draft PR)

Structural feedback:

Implementation feedback:

Other feedback:

Section 3: General PR Checklist

  • PR description thoroughly describes the new feature, bug fix, etc.
  • Added tests for new functionality or bug fixes
  • Tests pass (If not, and this is expected, please elaborate in the Section 6: Test Results)
  • Documentation
    • Docstrings are up-to-date
    • Related docs/ files are up-to-date, or added when necessary
    • Documentation has been rebuilt successfully
    • Examples have been updated (if applicable)
  • CHANGELOG.md
    • At least one complete sentence has been provided to describe the changes made in this PR
    • After the above, a hyperlink has been provided to the PR using the following format:
      "A complete thought. [PR XYZ]((https://github.com/NatLabRockies/H2Integrate/pull/XYZ)", where
      XYZ should be replaced with the actual number.

Section 3: Related Issues

This would resolve Issue #521

Section 4: Impacted Areas of the Software

Section 4.1: New Files

  • examples/13_dispatch_for_electrolyzer/: new example that highlights setting the storage demand as a different value than the demand component.
  • resource_files/wind/30.6617_-101.7096_2013_wtk_v2_60min_utc_tz.csv: wind resource file for example 23

Section 4.2: Modified Files

  • h2integrate/core/h2integrate_model.py
    • create_finance_model(): Updated logic so that any model without a cost model does not have to be included in the technologies list for a finance group. Was previously hard-coded so that only combiners didn't have to be included in the technologies list.
  • h2integrate/storage/storage_baseclass.py: modified StoragePerformanceBase
    • setup(): removed outputs related to demand
    • run_storage(): removed calculations of outputs related to demand. Updated calculation of capacity factor.
  • examples/test/test_all_examples.py::test_ng_demand_example: new test for Example 23
  • examples/test/test_all_examples.py::::test_electrolyzer_demand: new test for Example 13

Examples that were updated

  • Examples that had added combiners to combine storage outputs with the input to storage: 01, 02, 03/co2_hydrogenation_doc, 09/doc, 09/oae, 30
  • Examples that had added combiners and load demand components: 12, 16, 24, 30
  • Examples that had storage models as commodity streams (required additional combiner(s) and a new load demand component): 14, 18, 19, 29

Tests that were updated

Section 5: Additional Supporting Information

Section 6: Test Results, if applicable

  • h2integrate/core/test/test_framework.py::test_system_order
  • h2integrate/core/test/test_framework.py::test_technology_connections

Section 7 (Optional): New Model Checklist

  • Model Structure:
    • Follows established naming conventions outlined in docs/developer_guide/coding_guidelines.md
    • Used attrs class to define the Config to load in attributes for the model
      • If applicable: inherit from BaseConfig or CostModelBaseConfig
    • Added: initialize() method, setup() method, compute() method
      • If applicable: inherit from CostModelBaseClass
  • Integration: Model has been properly integrated into H2Integrate
    • Added to supported_models.py
    • If a new commodity_type is added, update create_financial_model in h2integrate_model.py
  • Tests: Unit tests have been added for the new model
    • Pytest-style unit tests
    • Unit tests are in a "test" folder within the folder a new model was added to
    • If applicable add integration tests
  • Example: If applicable, a working example demonstrating the new model has been created
    • Input file comments
    • Run file comments
    • Example has been tested and runs successfully in test_all_examples.py
  • Documentation:
    • Write docstrings using the Google style
    • Model added to the main models list in docs/user_guide/model_overview.md
      • Model documentation page added to the appropriate docs/ section
      • <model_name>.md is added to the _toc.yml

elenya-grant and others added 27 commits March 26, 2026 15:17
@bayc
Copy link
Copy Markdown
Collaborator

bayc commented Apr 10, 2026

@elenya-grant Trying to look through this, and wondering if you can put together a diagram or figure showing the inputs/outputs of the current system and proposed solution? Would help a lot to see what the differences are.

Copy link
Copy Markdown
Collaborator

@kbrunik kbrunik left a comment

Choose a reason for hiding this comment

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

I think this all makes sense for separating out the demand feature into the demand component. I do think a figure highlighting how the demand component works with the storage in this new configuration would be helpful.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I was looking at the docs for this and I think it could make sense to update example 14 and the outputs in this demonstration to show how the demand to the h2_storage and the h2_load_demand can be different and how that impacts the analysis. I would also recommend updating the tech_config executable block because it doesn't include the h2_load_demand and I think that would be helpful to showcase.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That's a good idea - I will work on that!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think that example 1 or 2 may be a better candidate. Those ones have a battery and we could set the battery demand profile to 10% of the electrolyzer rated capacity and then add/set an electricity component demand profile equal to the electrolyzer rated capacity. There is nothing that hydrogen is going to in example 14 which makes it hard to come up with a storage why the storage demand profile would be different than the demand component demand profile.

@elenya-grant elenya-grant marked this pull request as ready for review April 13, 2026 17:06
@bayc
Copy link
Copy Markdown
Collaborator

bayc commented Apr 13, 2026

@elenya-grant Trying to look through this, and wondering if you can put together a diagram or figure showing the inputs/outputs of the current system and proposed solution? Would help a lot to see what the differences are.

Thanks for adding the plots! That definitely helps me understand what the code is doing, which is moving the difference calculations out of the storage model. I think these outputs were originally developed with converters in mind as well and trying to apply the same set of inputs/outputs across technologies to be able to easily know how much of a commodity was consumed and how much, if any, demand is left unmet after sequentially working through each component.

My understanding now is that the difference calculations are being moved to demand components, and agree with @kbrunik that it would be helpful to see this built out in an example, so supportive of that! This would help me understand any other impacts to the dispatch/control flow and demand passing through converters as well.

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