Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
19ff6e1
initial example files for plm for a converter
jaredthomas68 May 15, 2026
d026a8a
run converter plm with single demand profile
jaredthomas68 May 15, 2026
c653a77
merge from develop
jaredthomas68 May 26, 2026
c1564c2
Merge branch 'develop' into control-converter
jaredthomas68 May 27, 2026
1d80254
have precommit ignore demand profiles for converter plm example
jaredthomas68 May 27, 2026
bcd95c2
peak load converter working with multiple demand profiles
jaredthomas68 May 27, 2026
d58cbf9
minor plot updates
jaredthomas68 May 27, 2026
0f99537
remove incorrect comments
jaredthomas68 May 28, 2026
3d7dc9c
add key file that was missed earlier
jaredthomas68 May 29, 2026
3b2fdfd
include init file
jaredthomas68 May 29, 2026
eafbf14
update units/naming
jaredthomas68 Jun 1, 2026
d885c12
bugfix, grap element instead of array
jaredthomas68 Jun 2, 2026
b964811
Merge branch 'develop' into control-converter
kbrunik Jun 9, 2026
19b84f9
include price dispatch capability to converter demand control
jaredthomas68 Jun 9, 2026
6193c9a
Merge remote-tracking branch 'myfork/control-converter' into control-…
jaredthomas68 Jun 9, 2026
1602280
wip
jaredthomas68 Jun 11, 2026
2afd03b
include unit definitions for peak cutoff
jaredthomas68 Jun 16, 2026
6296b1a
Merge branch 'develop' into control-converter
jaredthomas68 Jun 16, 2026
c124ecb
update naming:
jaredthomas68 Jun 17, 2026
b4f54ba
Fuel Cell Operational Calculations (#5)
kbrunik Jun 18, 2026
7b8c33a
resolve merge conflict
jaredthomas68 Jul 24, 2026
8bc1616
move demand profiles for examples to library and update converter plm…
jaredthomas68 Jul 24, 2026
d0abe9f
put converter and storage peak load management examples in subfolders…
jaredthomas68 Jul 24, 2026
6c5caed
reformat and fix pre-commit hook ignores
jaredthomas68 Jul 24, 2026
e09472a
move heuristic plm examples to 33_peak_load_management_heuristics
jaredthomas68 Jul 24, 2026
fd466c6
rename run files for example 33
jaredthomas68 Jul 24, 2026
02ea362
update docstrings and example descriptions for plm heuristic
jaredthomas68 Jul 24, 2026
c448201
update descriptions
jaredthomas68 Jul 24, 2026
eb2502d
Merge branch 'develop' into control-converter
jaredthomas68 Aug 4, 2026
8989520
make plm converter controller tech agnostic by using rated production…
jaredthomas68 Aug 4, 2026
c418808
set time step bounds and add example tests for plm converter example
jaredthomas68 Aug 4, 2026
6aaba79
update docs to include the converter plm controller
jaredthomas68 Aug 4, 2026
c513199
update changelog
jaredthomas68 Aug 4, 2026
201eb25
update class hierarchy
jaredthomas68 Aug 4, 2026
98609d7
update doc strings, class hierarchy, model overview, and comments
jaredthomas68 Aug 4, 2026
fc8c4c2
rename and move converter controller section
jaredthomas68 Aug 4, 2026
bbb42bd
update path in test
jaredthomas68 Aug 4, 2026
fd8bb7c
Potential fix for pull request finding
jaredthomas68 Aug 4, 2026
61a327a
update based on copilot review
jaredthomas68 Aug 4, 2026
b5f0c1b
resolve merge conflicts
jaredthomas68 Aug 4, 2026
fa4b8c4
minor updates based on copilot feedback
jaredthomas68 Aug 4, 2026
fcc4ed6
Merge branch 'develop' into control-converter
jaredthomas68 Aug 4, 2026
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 .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repos:
- id: yamlfix
# Exclude YAML files that are used as inputs for testing or examples, or ones for desired schedule in HOPP as they
# expect misformatted YAML files.
exclude: ^(h2integrate/core/test/inputs/.*|examples/11_hybrid_energy_plant/tech_inputs/desired_schedules/.*|examples/33_peak_load_management/demand_profiles/.*|examples/34_plm_optimized_dispatch/demand_profiles/.*)$
exclude: ^(h2integrate/core/test/inputs/.*|examples/11_hybrid_energy_plant/tech_inputs/desired_schedules/.*|library/demand_profiles/.*|examples/34_plm_optimized_dispatch/demand_profiles/.*)$
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.8.1
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
- Corrected timestamps in OpenMeteo resource downloads when resource data is downloaded in local time [PR #814](https://github.com/NatLabRockies/H2Integrate/pull/814)
- Added a thermal-nuclear (light-water reactor) model and a high-temperature steam electrolysis model. [PR 807](https://github.com/NatLabRockies/H2Integrate/pull/807)
- Fixed docs build warnings by correcting inline-literal docstring markup etc, also enabled warning-as-error in the shared docs build script to minimize number of future warnings. [PR 821](https://github.com/NatLabRockies/H2Integrate/pull/821)
- Added a converter controller that implements a peak-load management heuristic. [PR 773](https://github.com/NatLabRockies/H2Integrate/pull/773)

## 0.8 [April 15, 2026]

Expand Down
4 changes: 2 additions & 2 deletions docs/_static/class_hierarchy.html

Large diffs are not rendered by default.

27 changes: 26 additions & 1 deletion docs/control/technology_level_control/open-loop_controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@ An example output for the first week of a one-year simulation is shown below. Or
![](./figures/example_peak_load_dispatch.png)

For an example of how to use the `PeakLoadManagementHeuristicOpenLoopStorageController`, see:
- `examples/33_peak_load_management/`
- `examples/33_peak_load_management_heuristics/plm_storage/`

For API details, see the [`PeakLoadManagementHeuristicOpenLoopStorageController` API documentation](../../_autosummary/h2integrate.control.control_strategies.storage.plm_openloop_storage_controller).

## Open-Loop Converter Controllers
The open-loop converter controllers can be attached as the control strategy in the `tech_config` for converter technologies (e.g., a fuel cell). Unlike the storage controllers, converter controllers do not track a state of charge; they translate a set-point into a `{commodity}_command_value` that is bounded by the converter's rated production. There is currently one converter controller:
1. [Peak Load Management Open-Loop Converter Controller](#peak-load-management-open-loop-converter-controller) — computes a peak-shaving converter command from one or two demand profiles using simple threshold heuristics.

(peak-load-management-open-loop-converter-controller)=
### Peak Load Management Open-Loop Converter Controller
The `PeakLoadManagementHeuristicOpenLoopConverterController` computes a per-timestep converter command that shaves demand peaks using threshold-based heuristics rather than storage state-of-charge dynamics or optimization. It is designed for dispatching a converter (such as a fuel cell) to reduce peak loads using either one or two demand profiles.

The command at each timestep is determined by three limits:

- **A primary set-point cutoff (`demand_profile_peak_cutoff`)** — dispatch is only considered when the local `{commodity}_set_point` exceeds this threshold. The desired dispatch is the amount by which the set-point exceeds the cutoff.
- **An optional upstream signal and cutoff (`demand_profile_upstream` and `demand_profile_upstream_peak_cutoff`)** — a supervisory or upstream signal that can also trigger or shape dispatch. Its interpretation is controlled by `demand_profile_upstream_kind`:
- `"electricity"` (default) — the upstream signal is an upstream demand in commodity-amount units. The command tracks the larger exceedance of the local and upstream profiles.
- `"price"` — the upstream signal is a price time series. Dispatch is only enabled on timesteps where the upstream price exceeds `demand_profile_upstream_peak_cutoff`.
- **A converter capacity ceiling** — the command is clipped so it never exceeds the converter's `rated_{commodity}_production` (read from the performance model) or the instantaneous local demand.

Because the controller reads the performance model's `rated_{commodity}_production` output as its command ceiling, a solver is automatically added to converge the controller/performance-model data cycle within the technology group.

**Configuration parameters**

For an example of how to use the `PeakLoadManagementHeuristicOpenLoopConverterController`, see:
- `examples/33_peak_load_management_heuristics/plm_converter/`

For API details, see the [`PeakLoadManagementHeuristicOpenLoopConverterController` API documentation](../../_autosummary/h2integrate.control.control_strategies.converters.plm_openloop_converter_controller).
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Supported controllers:
- [`SimpleStorageOpenLoopController`](#pass-through-controller)
- [`DemandOpenLoopStorageController`](#demand-open-loop-storage-controller)
- [`PeakLoadManagementHeuristicOpenLoopStorageController`](#peak-load-management-open-loop-storage-controller)
- [`PeakLoadManagementHeuristicOpenLoopConverterController`](#peak-load-management-open-loop-converter-controller)

(pyomo-control-framework)=
## Pyomo control framework
Expand Down
4 changes: 4 additions & 0 deletions docs/user_guide/model_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ auto-generated API page.
+ {py:class}`~h2integrate.control.control_rules.storage.pyomo_storage_rule_baseclass.PyomoRuleStorageBaseclass` - Base class defining Pyomo rules for generic commodity storage components.
+ {py:class}`~h2integrate.control.control_rules.storage.pyomo_storage_rule_min_operating_cost.PyomoRuleStorageMinOperatingCosts` - Class defining Pyomo rules for the optimized dispatch for load following for generic commodity storage components.

- `converter_controllers`: converter controllers
- controllers:
+ {py:class}`~h2integrate.control.control_strategies.converters.plm_openloop_converter_controller.PeakLoadManagementHeuristicOpenLoopConverterController` - Open-loop peak-load management controller for converter technologies.

- `storage_controllers`: storage controllers
- controllers:
+ {py:class}`~h2integrate.control.control_strategies.storage.demand_openloop_storage_controller.DemandOpenLoopStorageController` - A controller that manages commodity flow based on demand and storage constraints.
Expand Down
5 changes: 0 additions & 5 deletions examples/33_peak_load_management/driver_config.yaml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: driver_config
description: Driver configuration for peak load management converter heuristic control
general:
folder_output: outputs
create_om_reports: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: plant_config
description: Plant configuration for peak load management converter heuristic control
plant:
plant_life: 30
simulation:
n_timesteps: 8760
dt: 3600
timezone: -6
start_time: 2025/07/01 00:00:00
technology_interconnections:
- [hydrogen_feedstock, fuel_cell, hydrogen, pipe]
- [fuel_cell, electrical_load_demand, [electricity_out, electricity_in]]
- [electrical_load_demand, grid_buy, [unmet_electricity_demand_out, electricity_set_point]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
Example 33: Peak load management converter heuristic dispatch

This example demonstrates peak load management dispatch open loop control of a converter
with two demand profiles of interest

In this example, the fuel-cell converter command is determined by a simple open-loop
threshold heuristic that uses two profiles:

1. demand_profile (local set-point)
2. demand_profile_upstream (supervisory or upstream signal)

At each time step, dispatch is only considered when either profile exceeds its configured
cutoff. For electricity-mode upstream control, the commanded dispatch is based on the
larger exceedance of the two profiles and is then limited by both the instantaneous local
demand and converter capacity. This creates a peak-shaving command profile for the
converter without storage state-of-charge dynamics or optimization.

The output figure compares the original local demand, upstream demand, cutoff thresholds,
converter output, resulting unmet demand, and grid purchases.

"""

import numpy as np
import matplotlib.pyplot as plt

from h2integrate import H2IntegrateModel
from h2integrate.core.utilities import build_time_series_from_plant_config


# Create, setup, and run the H2Integrate model
model = H2IntegrateModel("33_plm_converter_heuristic.yaml")

model.setup()
# om.n2(model.prob)
model.run()
model.post_process()

demand_profile = model.prob.get_val("fuel_cell.electricity_set_point", units="kW")
# plot the results for the first week
demand_profile_upstream = np.array(
model.technology_config["technologies"]["fuel_cell"]["model_inputs"]["control_parameters"][
"demand_profile_upstream"
]
)
demand_profile_peak_cutoff = model.technology_config["technologies"]["fuel_cell"]["model_inputs"][
"control_parameters"
]["demand_profile_peak_cutoff"]
demand_profile_upstream_peak_cutoff = model.technology_config["technologies"]["fuel_cell"][
"model_inputs"
]["control_parameters"]["demand_profile_upstream_peak_cutoff"]
grid_output = model.prob.get_val("grid_buy.electricity_out", units="MW")

time_series = build_time_series_from_plant_config(model.plant_config)

n_plot = 24 * 7
time_plot = time_series[:n_plot]

fig, ax = plt.subplots(3, 1, sharex=True, figsize=(10, 5))
ax[0].plot(time_plot, demand_profile_upstream[:n_plot] * 1e-3, label="Upstream demand")
ax[0].plot(time_plot, demand_profile[:n_plot] * 1e-3, label="Original demand")
ax[0].axhline(
demand_profile_peak_cutoff * 1e-3, label="Demand peak cutoff", color="k", linestyle="--"
)
ax[0].axhline(
demand_profile_upstream_peak_cutoff * 1e-3,
label="Upstream demand peak cutoff",
color="k",
linestyle=":",
)
ax[0].set(ylabel="Power (MW)", ylim=[-2, 2])
ax[0].legend(frameon=True, ncol=3)

ax[1].plot(time_plot, demand_profile[:n_plot] * 1e-3, label="Original demand (MW)")
ax[1].plot(
time_plot,
model.prob.get_val("fuel_cell.electricity_out", units="MW")[:n_plot],
label="fuel_cell dispatch",
)
ax[1].set(ylabel="Power (MW)", ylim=[-2, 2])
ax[1].legend(frameon=False, ncol=2)

ax[2].plot(time_plot, demand_profile[:n_plot] * 1e-3, label="Original demand (MW)")
ax[2].plot(
time_plot,
model.prob.get_val("electrical_load_demand.unmet_electricity_demand_out", units="MW")[:n_plot],
label="New demand profile",
)
ax[2].plot(time_plot, grid_output[:n_plot], label="Grid purchase (MW)", linestyle=":")

ax[2].set(ylabel="Power (MW)", ylim=[-2, 2])
ax[2].legend(frameon=False, ncol=3)
ax[2].tick_params(axis="x", labelrotation=90)

for axis in ax:
axis.minorticks_on()
axis.grid(True, which="major", alpha=0.45, linewidth=0.8)
axis.grid(True, which="minor", alpha=0.2, linewidth=0.5)

plt.tight_layout()
plt.savefig("example_peak_load_dispatch.png", transparent=False)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: technology_config
description: This plant dispatches a fuel cell to reduce peak demand
technologies:
hydrogen_feedstock:
performance_model:
model: FeedstockPerformanceModel
cost_model:
model: FeedstockCostModel
model_inputs:
shared_parameters:
commodity: hydrogen
commodity_rate_units: kg/h
performance_parameters:
rated_capacity: 50.0 # kg of H2/hour
cost_parameters:
cost_year: 2022
price: 5.0 # USD/kg H2
annual_cost: 0.
start_up_cost: 0.0
fuel_cell:
performance_model:
model: LinearH2FuelCellPerformanceModel
cost_model:
model: H2FuelCellCostModel
control_strategy:
model: PeakLoadManagementHeuristicOpenLoopConverterController
model_inputs:
shared_parameters:
system_capacity_kw: 1000.0
performance_parameters:
fuel_cell_efficiency_hhv: 0.50
uptime_hours_until_eol: 80000
cost_parameters:
capex_per_kw: 200.0
fixed_opex_per_kw_per_year: 10.0
variable_opex_per_kwh: 0.0
cost_year: 2018
control_parameters:
commodity: electricity
commodity_rate_units: kW
demand_profile: !include demand_profiles/demand_profile.yaml # found in library/demand_profiles
demand_profile_upstream: !include demand_profiles/demand_profile_upstream.yaml # found in library/demand_profiles
demand_profile_peak_cutoff: 400.0
demand_profile_upstream_peak_cutoff: 1000.0
electrical_load_demand:
Comment thread
jaredthomas68 marked this conversation as resolved.
performance_model:
model: GenericDemandComponent
model_inputs:
performance_parameters:
commodity: electricity
commodity_rate_units: kW
demand_profile: !include demand_profiles/demand_profile.yaml # found in library/demand_profiles
grid_buy:
performance_model:
model: GridPerformanceModel
cost_model:
model: GridCostModel
model_inputs:
shared_parameters:
interconnection_size: 100000
cost_parameters:
cost_year: 2024
fixed_interconnection_cost: 0.0
interconnection_capex_per_kw: 0.0
interconnection_opex_per_kw: 0.0
electricity_buy_price: 0.09

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 think it could be good to have both peak load management examples (storage and converter) in the same folder 33_peak_load_management and then have nested folders for each example.

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.

Done

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.

Let's update name of this file so it's not the same as the storage PLM file.

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.

Done

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: H2Integrate_config
system_summary: Peak load management dispatch
driver_config: driver_config.yaml
technology_config: tech_config.yaml
plant_config: plant_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: driver_config
description: Driver configuration for peak load management storage heuristic control
general:
folder_output: outputs
create_om_reports: false
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: plant_config
description: Demonstrates multivariable streams with a gas combiner
description: Plant configuration for peak load management storage heuristic control
plant:
plant_life: 30
simulation:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Example 33: Peak load management dispatch
Example 33: Peak load management storage heuristic dispatch

This example demonstrates:
1. Peak load management dispatch open loop control with two demand profiles of interest
Expand Down Expand Up @@ -32,7 +32,7 @@


# Create, setup, and run the H2Integrate model
model = H2IntegrateModel("33_peak_load_management.yaml")
model = H2IntegrateModel("33_plm_storage_heuristic.yaml")

model.setup()
model.run()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: technology_config
description: This plant charges a battery from the grid to reduce peak demand
description: This plant dispatches a battery to reduce peak demand
technologies:
battery:
performance_model:
Expand All @@ -21,9 +21,9 @@ technologies:
init_soc_fraction: 0.9 # percent as decimal
charge_efficiency: 1.0 # percent as decimal
discharge_efficiency: 1.0 # percent as decimal
demand_profile: !include demand_profiles/demand_profile.yaml
demand_profile: !include demand_profiles/demand_profile.yaml # found in library/demand_profiles
control_parameters:
demand_profile_upstream: !include demand_profiles/demand_profile_upstream.yaml # demand used to define when the supervisor commands battery dispatch. This may represent an upstream load.
demand_profile_upstream: !include demand_profiles/demand_profile_upstream.yaml # found in library/demand_profiles. Demand used to define when the supervisor commands battery dispatch. This may represent an upstream load.
dispatch_priority_demand_profile: demand_profile_upstream # demand profile the controller prioritizes when deciding dispatch
n_override_events: 3 # maximum number of peak events from the priority demand profile that the controller will respond to within each event period
override_events_period: W # pandas-style period code for resetting event counts; W means per week, M means month, etc
Expand Down Expand Up @@ -52,7 +52,7 @@ technologies:
performance_parameters:
commodity: electricity
commodity_rate_units: kW
demand_profile: !include demand_profiles/demand_profile.yaml
demand_profile: !include demand_profiles/demand_profile.yaml # found in library/demand_profiles
grid_buy:
performance_model:
model: GridPerformanceModel
Expand Down
2 changes: 1 addition & 1 deletion examples/34_plm_optimized_dispatch/tech_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ technologies:
demand_profile: 0.0
control_parameters:
system_commodity_interface_limit: 1.0e9
supervisory_signal: !include demand_profiles/supervisory_signal.yaml
supervisory_signal: !include demand_profiles/supervisory_signal.yaml # found in library/demand_profiles
peak_window:
start: 12:00:00
end: 20:00:00
Expand Down
42 changes: 40 additions & 2 deletions examples/test/test_all_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -2961,12 +2961,13 @@ def test_cmu_eaf_dri_example(subtests, temp_copy_of_example):

@pytest.mark.integration
@pytest.mark.parametrize(
"example_folder,resource_example_folder", [("33_peak_load_management", None)]
"example_folder,resource_example_folder",
[("33_peak_load_management_heuristics/plm_storage", None)],
)
def test_peak_load_management_example(subtests, temp_copy_of_example):
example_folder = temp_copy_of_example

model = H2IntegrateModel(example_folder / "33_peak_load_management.yaml")
model = H2IntegrateModel(example_folder / "33_plm_storage_heuristic.yaml")
model.setup()
model.run()

Expand Down Expand Up @@ -3005,6 +3006,43 @@ def test_peak_load_management_example(subtests, temp_copy_of_example):
assert battery_unmet_demand.sum() == pytest.approx(grid_purchase.sum(), rel=1e-3)


@pytest.mark.integration
@pytest.mark.parametrize(
"example_folder,resource_example_folder",
[("33_peak_load_management_heuristics/plm_converter", None)],
)
def test_plm_converter_heuristic_example(subtests, temp_copy_of_example):
example_folder = temp_copy_of_example

model = H2IntegrateModel(example_folder / "33_plm_converter_heuristic.yaml")
model.setup()
model.run()

command = model.prob.get_val("fuel_cell.electricity_command_value", units="kW")
electricity_out = model.prob.get_val("fuel_cell.electricity_out", units="kW")
unmet = model.prob.get_val("electrical_load_demand.unmet_electricity_demand_out", units="kW")
grid_purchase = model.prob.get_val("grid_buy.electricity_out", units="kW")
rated = model.prob.get_val("fuel_cell.rated_electricity_production", units="kW")

with subtests.test("Fuel-cell command sum"):
assert command.sum() == pytest.approx(778276.0, rel=1e-6)

with subtests.test("Fuel-cell output matches command"):
np.testing.assert_allclose(electricity_out, command, rtol=1e-9)

with subtests.test("Fuel-cell command max"):
assert command.max() == pytest.approx(519.0, rel=1e-6)

with subtests.test("Unmet demand equals grid purchase"):
assert unmet.sum() == pytest.approx(grid_purchase.sum(), rel=1e-9)

with subtests.test("Rated fuel-cell production"):
assert rated[0] == pytest.approx(1000.0, rel=1e-9)

with subtests.test("Nonzero dispatch timesteps"):
assert np.sum(command > 0) == 3648


@pytest.mark.integration
@pytest.mark.parametrize(
"example_folder,resource_example_folder", [("34_plm_optimized_dispatch", None)]
Expand Down
3 changes: 3 additions & 0 deletions h2integrate/control/control_strategies/converters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from h2integrate.control.control_strategies.converters.plm_openloop_converter_controller import (
PeakLoadManagementHeuristicOpenLoopConverterController,
)
Loading
Loading