Skip to content

Conversation

@genevievestarke
Copy link
Collaborator

@genevievestarke genevievestarke commented Dec 9, 2025

Bring Pyomo load following dispatch capabilities into H2I

This feature would enable dispatch optimization using one storage technology and multiple generation technologies (using the combiner) to determine optimal storage operation to follow a load while minimizing costs. This feature adds the optimization problem formulation, framework, and solver for the optimization in Pyomo. To do this, a hybrid_rule.py file was added to aggregate the storage and production variables to create one problem for the optimizer. The added files are

  • OptimizedDispatchController class in pyomo_controllers.py
  • The hybrid_rule.py file: Aggregates optimization pieces from the various components and formulates the model for the optimization. This file collects the objective function, initializes model parameters, and updates time series parameters.
  • The generic_converter_opt.py file: Houses the variables, parameters, constraints, and objective function for the generator technology in the optimization model.
  • The pyomo_storage_rule_min_operating_cost.py file: houses the storage and system variables, parameters, constraints, and objective function. Ideally the system parameters would be in a separate file, perhaps, but have been combined for efficiency in the first implementation.
  • The controller_opt_problem_state.py file: Formulates the optimization model for the solver

The below is an example of how and where the dispatch is run using a battery for electricity storage:
image

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 general feedback on framework of added pyomo pieces
  • Apply any framework feedback and update code so that heuristic dispatch works as expected
  • Update example to accurately describe run
  • Update doc strings in methods
  • Write tests for new pyomo optimization
  • Make docs page?
  • Maybe: address where dispatch inputs should live for generator technologies
  • Maybe: make an example with multiple generation technologies, using the combiner to connect to dispatch

Type of Reviewer Feedback Requested (on Draft PR)

Structural feedback:
This dispatch model differs significantly from the heuristic block formulation in H2I. The dispatch for the generation + storage system is aggregated in hybrid_rule.py, which pulls from generic_converter_opt.py and pyomo_storage_rule_min_operating_cost.py, all three of which are classes, and thus outside of the OpenMDAO input/output framework. This was implemented because the previous dispatch_rule framework was difficult to aggregate in the way that was needed to formulate the optimization problem. I would like feedback on this structure, and whether we could make it more OpenMDAO-friendly.

Implementation feedback:

Other feedback:
The inputs to the dispatch are all defined in the storage technology config, including the cost_per_production term, which describes the cost of the production technologies. I think this should be defined under the production technologies in the config, so any feedback on how to pull this into the battery dispatch would be appreciated!

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 has been updated to describe the changes made in this PR

Section 3: Related Issues

This resolves #386

Section 4: Impacted Areas of the Software

Section 4.1: New Files

  • path/to/file.extension
    • method1: What and why something was changed in one sentence or less.

Section 4.2: Modified Files

  • path/to/file.extension
    • method1: What and why something was changed in one sentence or less.

Section 5: Additional Supporting Information

Section 6: Test Results, if applicable

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

jaredthomas68 and others added 15 commits October 2, 2025 09:16
             {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers}
             ...

This is the main driver for the Pyomo optimization software.

options:
  -h, --help            show this help message and exit
  --version             show program's version number and exit

subcommands:
  {build-extensions,convert,download-extensions,help,install-extras,model-viewer,run,solve,test-solvers}
    build-extensions    Build compiled extension modules
    convert             Convert a Pyomo model to another format
    download-extensions
                        Download compiled extension modules
    help                Print help information.
    install-extras      Install "extra" packages that Pyomo can leverage.
    model-viewer        Run the Pyomo model viewer
    run                 Execute a command from the Pyomo bin (or Scripts)
                        directory.
    solve               Optimize a model
    test-solvers        Test Pyomo solvers

-------------------------------------------------------------------------
Pyomo supports a variety of modeling and optimization capabilities,
which are executed either as subcommands of 'pyomo' or as separate
commands.  Use the 'help' subcommand to get information about the
capabilities installed with Pyomo.  Additionally, each subcommand
supports independent command-line options.  Use the -h option to
print details for a subcommand.  For example, type

   pyomo solve -h

to print information about the `solve` subcommand. branch that needs to be saved for later
Merging in current pyomo opt branch
@genevievestarke genevievestarke added the ready for review This PR is ready for input from folks label Dec 31, 2025
@genevievestarke
Copy link
Collaborator Author

This pull request is ready for an overall framework review!

@jaredthomas68 jaredthomas68 self-requested a review January 6, 2026 22:38
@elenya-grant elenya-grant self-requested a review January 6, 2026 22:55
Copy link
Collaborator

@jaredthomas68 jaredthomas68 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 is an excellent piece of work, well done. Thank you for the effort to make it relatively clean and straight forward. My thoughts are:

  • structurally I think it is very good. I guess we will find ways to improve as we move forward, but I like where it is at generally.
  • I am concerned with the number of getter and setter methods, are they really necessary?
  • more tests are needed for added functionality
  • lots of comments and print statements need to be removed, but that is expected in a draft
  • more comments would be helpful as there are some methods with little to no comments



class PyomoDispatchGenericConverterMinOperatingCosts:
def __init__(
Copy link
Collaborator

Choose a reason for hiding this comment

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

before going to production we will need some more comments and explanation here I think

def _create_parameters(self, pyomo_model: pyo.ConcreteModel):
"""Create technology Pyomo parameters to add to the Pyomo model instance.
Method is currently passed but this can serve as a template to add parameters to the Pyomo
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure what you mean by "Method is currently passed"

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This was a copy/past mistake. Fixed now!

def _create_constraints(self, pyomo_model: pyo.ConcreteModel):
"""Create technology Pyomo parameters to add to the Pyomo model instance.
Method is currently passed but this can serve as a template to add constraints to the Pyomo
Copy link
Collaborator

Choose a reason for hiding this comment

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

see above comment

# initial_soc = self._check_initial_soc(initial_soc)
# pyomo_model.initial_soc = round(initial_soc, self.round_digits)

@property
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wish we could avoid having so many getter and setter methods, but I don't have any good ideas for that at the moment (non-blocking).

solver_problem_dict = {
k.lower().replace(" ", "_"): v.value for k, v in solver_results.problem._list[0].items()
}
prob_to_attr_map = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

some unclear names in the solver, but this is a fairly nice solution for dealing with it

upper_bound = solver_problem_dict["upper_bound"]
lower_bound = solver_problem_dict["lower_bound"]
if upper_bound != 0.0:
gap = abs(upper_bound - lower_bound) / abs(upper_bound)
Copy link
Collaborator

Choose a reason for hiding this comment

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

some comments here would be good. I think I get what you are doing, but it took me a minute

but has not been implemented yet."
)
)
# TODO: implement optimized solutions; this is where pyomo_model would be used
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove comment

return dispatch_inputs


class OptimizedDispatchController(SimpleBatteryControllerHeuristic):
Copy link
Collaborator

Choose a reason for hiding this comment

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

This inheritance strikes me as odd since the parent and child are technically at the same level in their usage. If there are common elements they both need I think we should make a base class for them both to inherit from.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a good point. I've fixed this in the most recent update. Now it inherits from PyomoControllerBaseClass

wind_speed: 9.
model_inputs:
performance_parameters:
num_turbines: 100
Copy link
Collaborator

Choose a reason for hiding this comment

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

The wind farm rating is really high in comparison with the battery. I think the plots in the example would be more meaningful if you reduced the size of the wind farm

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed!

@johnjasa johnjasa added needs modifications This PR has been reviewed, at least partially, and is ready for PR author response and removed ready for review This PR is ready for input from folks labels Jan 13, 2026
@genevievestarke genevievestarke marked this pull request as ready for review January 27, 2026 20:33
@genevievestarke genevievestarke added ready for review This PR is ready for input from folks and removed needs modifications This PR has been reviewed, at least partially, and is ready for PR author response labels Jan 27, 2026
@johnjasa johnjasa self-requested a review January 27, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in progress ready for review This PR is ready for input from folks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants