WIP: Helper Methods in SLC BaseClass - #816
Draft
elenya-grant wants to merge 73 commits into
Draft
Conversation
…d for dictionary, using a set instead)
…p_multi_commodity()
johnjasa
reviewed
Aug 4, 2026
27 tasks
…ttributes in another class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Helper Methods in SLC BaseClass
Added some hopefully useful helper methods in the SLC baseclass and intended to resolve Issue #741. I also view this as a pre-requisite to tackling Issue #747. These methods are intended to help future control development be more easily expanded to varying system architectures and make them more friendly to multi-commodity systems (systems that contain converters such as an electrolyzer or Haber Bosch system). To me, this meant being able to understand complex systems in a more understandable way and to be able to easily translate the demanded commodity into the demand of each upstream technology. For example, how to translate the ammonia demand into hydrogen demand, and also translate that hydrogen demand into electricity demand and water demand.
The methods in the SLC baseclass do work for more complex system architectures than we can currently represent with the models in H2I. I think that the methods would be able to handle architectures that include splitters (and if not, I think the changes to them would be more simple). I think that integrating splitters may just change how some of the methods called by controllers that inherit the baseclass provide the necessary inputs. Aka - I think that
_post_setup_multi_commodity()should work for splitters (or require minor changes).This PR also includes some updates to the
DemandFollowingControlto show-case how to use some of the methods in the SLC baseclass. I am still working on adding all the necessary doc-strings and cleaning up the code.Please do not yet push any changes to this branch until the TODOs are complete
A note to reviewers:
Hi reviewer! First, I tried to put some "worked examples" in the doc strings of the methods I added, and these can be seen in a nice way if you look at the read the docs build for the SLC base class. All the methods I added are at the end of the file. I also showed examples of the main attributes instantiated in the
_post_setup_multi_commodity()method in the docs page for the SLC baseclass under the section titled "Heterogeneous Commodity Hybrid System". Give those a look!What would be very helpful to me is if you went through the methods in the SLC baseclass that I call out in "Summary of methods added in the SLC base class" (only look at the ones in the demand following controller if it helps you understand how the ones in the SLC baseclass are used). The most complicated methods are the ones noted in Step 1. I would really love to know which of the methods called in
_post_setup_multi_commodityare the most confusing/hard to follow (and perhaps some more detail on what parts are confusing). I would very much recommend reading Step 1 as you look at the code and the worked out examples in the doc page. I think that understanding the variables at each substep of Step 1 are crucial to understanding what's happening in_post_setup_multi_commodity(), the methods used in_post_setup_multi_commodity(), and the attributes/methods that are used (or useful) in Step 2 and Step 3.Please communicate with me if you want to push up any changes to the code. In some places of the code, the code may seem overly complex because it has to be that complicated to work properly (but sometimes it may be overly complex for no good reason - and we should figure that out together). Also - sometimes in the code you may realize that things could be make 1-liners, but for the sake of readability I didn't do that. There are also errors and warnings that aren't very descriptive - they aren't very descriptive because usually it means that some unexpected system design was encountered or that something else "upstream" may have broke. Also - I totally expect to rename some methods and variable names - please feel free to recommend ideas for different naming, but don't focus on that (yet).
Some of the tests in
h2integrate/control/control_strategies/system_level/test/test_slc_baseclass.pyare a bit confusing. I can/will clean these up before this PR is merged in. Right now, this mess of tests is to ensure that nothing breaks if changes are made.Please focus on the new methods added to the SLC baseclass, specifically the ones called in
_post_setup_multi_commodity. I did make changes to the demand following control and the demand following controller still has its limitation. The goal of this PR was to add in helpful methods to the SLC baseclass and showcase their utilization - not to address the short falls of the demand following controller. Future PRs can work on making the demand following controller more robust and flexible - but not this one!I think that the
conversion_recipesattribute thats made at the end of thepost_setup_multi_commodity()is the most confusing and hard-to-explain attribute. I tried to make using this attribute more developer-friendly with the methodsget_conversion_from_recipeandget_techs_to_demand_from_recipe.The only other part of this PR body that may be good to look at (outside of Section 1) is the TODO list. Besides that, the only thing you should read right now (assuming you've read everything above here) is "Summary of methods added in the SLC base class".
Summary of methods added in the SLC base class
The methods included in this PR that were added to
SystemLevelControlBaseperhaps fall into 3 buckets, this is summarized below. Please note that the term "converter" I'm using throughout this PR body is used to refer to components that convert at least one commodity type into at least one other commodity type. Resource (such as wind and solar) is not the same as a commodity. An electrolyzer is a converter, a wind farm is not.technology_graphThis step is a pre-cursor to 2 and 3. The top-level method of this is the
_post_setup_multi_commodity(which is called at the end of thesetup()method of theSystemLevelControlBase). The goals of this method are to:find the converter technologies within the system and their relationships to other technologies. This is done with the method
_find_converter_techs(), which outputsconvertersandconverter_upstreams._find_converter_techs()outputsconvertersandconverter_upstreams, which are used in the following steps and are saved in theHCHSConfig(aka - these are important)_find_converter_techs()calls the methodget_successors_for_tech_with_input_cmod().get_successors_for_tech_with_input_cmod()is used elsewhere in the code and may be a good option to replace or be used within the methodget_upstream_techs_for_commodity()_find_converter_techs(): only called in_post_setup_multi_commodity()get_successors_for_tech_with_input_cmod(): currently only used in the context of_post_setup_multi_commodity(), but may be useful elsewhere.HCHSConfigattributes created:convertersandconverter_upstreamssimplify the technology graph into "subsystems". Each "subsystem" is defined by its relationship to converters and its output commodities. This simplification is done within
_post_setup_multi_commodity(). It starts with creatinggrouped_techsandgrouped_commodities. Then it creates a more "easily searchable" version ofgrouped_techsandgrouped_commoditiescalledreversed_grouped_techsandreversed_group_commodities.grouped_techsis used later on, butgrouped_commodities,reversed_grouped_techs, andreversed_group_commoditiesare only used to makesimple_graph.simple_graphis directional graph representation of the subsystems and their relationships to each other.convertersandconverter_upstreamsHCHSConfigattributes created:grouped_techsandsimple_graphmake instructions on how to translate the "system demand" (user-defined in the SLC topology) to the demand of each subsystem. I.e., convert ammonia demand into hydrogen demand, then also convert that hydrogen demand into electricity demand (there are two recipes - one for the hydrogen subsystem and one for the electricity subsystem that feeds into the hydrogen subsystem). This is done in the method
_make_conversion_factor_recipes()which outputsconversion_recipes._make_conversion_factor_recipes(): only called in_post_setup_multi_commodity()_make_recipe_from_grouped_path()._make_recipe_from_grouped_path()is only called from_make_conversion_factor_recipes()converters,simple_graph, andgrouped_techsHCHSConfigattributes created:conversion_recipesother information that is summarized in
_post_setup_multi_commoditybut not necessary to the main functionality this PR offers are the parametersnon_converter_keysandconverter_tech_names. These are stored as attributes in theHCHSConfigto partially simplify some stuff later on.non_converter_keysis stored inHCHSConfigas the attribute namenon_converter_conversion_factor_keys."Compute" methods to calculate ratios (production and capacity) of different "subsystems". These methods are intended to calculate some input/output ratio from the inputs. The logic within these methods are independent of anything done in Step 1 - but providing the inputs to them is made substantially easier with the use of the
convertersandconverter_upstreamsattributes used in Step 1. The usage of these methods is showcased in theget_conversion_factors()method added to theDemandFollowingControlcontroller. Note that within theDemandFollowingControl.get_conversion_factors()method, we also see where thenon_converter_conversion_factor_keyscomes in handy. The two methods are:get_converter_conversion_ratio(): calculates the ratio of input commodity production to output commodity productionget_converter_capacity_ratio(): calculates the ratio of input commodity capacity to output commodity capacity"Compute" methods for getting information about a "subsystem" and the relationship between that "subsystem" and the demand. These methods would be called from a class that inherits
SystemLevelControlBasein thecompute()method. These methods are intended to make theconversion_recipescreated in Step 1 to be easily usable by classes that inherit it.conversion_recipesis perhaps the most confusing variable made in Step 1 - but these two methods are helpful at extracting the important information from it. Similar to Step 2, the usage of these are showcased in thecompute()method ofDemandFollowingControl. The methods areget_techs_to_demand_from_recipe()andget_conversion_from_recipe().get_techs_to_demand_from_recipe()will take in a "recipe name" (key ofconversion_recipes) and return the technologies that should be "dispatched" based on that recipe. This method uses the attributessimple_graphandgrouped_techscreated in Step 1.get_conversion_from_recipe()takes in a dictionary of conversion factors (like those created inDemandFollowingControl.get_conversion_factors()and a "recipe" (value fromconversion_recipes). It uses the recipe to determine which of theconversion_factorsto multiply together in order to calculate the compounding conversion ratio.Section 1: Type of Contribution
Section 2: Draft PR Checklist
TODO:
_post_setup_multi_commodityto a separate classChangeNameAttributeClassrename_me_configto something elsetest_find_converter_techs_fake_systemh2integrate/control/control_strategies/system_level/test/test_slc_baseclass.pyType of Reviewer Feedback Requested (on Draft PR)
Structural feedback:
Implementation feedback:
_post_setup_multi_commodity()be updated to have the format__method_name__? Or no?_method_nameor justmethod_name?Other feedback:
converter_upstreams, is a dictionary like:Section 3: General PR Checklist
docs/files are up-to-date, or added when necessaryCHANGELOG.md"A complete thought. [PR XYZ]((https://github.com/NatLabRockies/H2Integrate/pull/XYZ)", where
XYZshould be replaced with the actual number.Section 4: Related Issues
Intended to resolve Issue #741
Section 5: Impacted Areas of the Software
Section 5.1: New Files
h2integrate/control/control_strategies/system_level/test/test_slc_baseclass.py: new test file for some methods introduced in the SLC baseclassSection 5.2: Modified Files
h2integrate/core/h2integrate_model.py._classify_slc_technologies(): updated so that other inputs (such astech_control_classifiersandstorage_techs_to_control) only include technologies that are upstream of the demand component.h2integrate/control/control_strategies/system_level/demand_following_control.pyDemandFollowingControlConfig: new configuration class for the demand following controllerDemandFollowingControlcompute()in a method namedget_setpoints_for_commodity_subset()get_conversion_factors(): new methodcompute(): changed a bunchMany new methods were added to
h2integrate/control/control_strategies/system_level/system_level_control_base.py. Below is a summary of the major new methods and the other methods that they use_post_setup_multi_commodity(): called insetup()and uses the below methods_find_converter_techs: only called during_post_setup_multi_commodity()and uses the below methodsget_successors_for_tech_with_input_cmod: called elsewhere - not specific to this method._make_conversion_factor_recipes: only called during_post_setup_multi_commodity()_make_recipe_from_grouped_path: only called in_make_conversion_factor_recipes()ChangeNameAttributeClasssimple_graphnon_converter_conversion_factor_keys:grouped_techs:converters:converter_upstreams:converter_tech_names: could perhaps removeconversion_recipes:New methods in the SLC baseclass that are used by the
DemandFollowingControl.compute()method are:get_techs_to_demand_from_recipeget_conversion_from_recipeget_converter_capacity_ratioget_converter_conversion_ratioSection 6: Additional Supporting Information
Section 7: Test Results, if applicable
Section 8 (Optional): New Model Checklist
docs/developer_guide/coding_guidelines.mdattrsclass to define theConfigto load in attributes for the modelBaseConfigorCostModelBaseConfiginitialize()method,setup()method,compute()methodCostModelBaseClasssupported_models.pycreate_financial_modelinh2integrate_model.pytest_all_examples.pydocs/user_guide/model_overview.mddocs/section<model_name>.mdis added to the_toc.ymlgenerate_class_hierarchy.pyto update the class hierarchy diagram indocs/developer_guide/class_structure.md