Add BadPointPressureLiftController tutorial notebook for district heating network - #711
Conversation
EPrade
left a comment
There was a problem hiding this comment.
I think we could also add this controller as a controller in src/control/controller as it is done in pandapower, since it is a common problem in heating grids.
Thoughts? @SimonRubenDrauz @dlohmeier
|
As discussed yesterday in the pandapipes meeting, I added a reference to the new Jupyter Notebook for the controller example. |
Could you move/add the controller as a controller in pandapipes/control and then use it as in import in this tutorial? |
Move BadPointPressureLiftController from Jupyter notebook to pandapipes.control package: - Add new controller module at src/pandapipes/control/controller/bad_point_pressure_lift_controller.py - Export controller from pandapipes.control for easy import - Update BadPointPressureController.ipynb to import controller from pandapipes instead of defining it inline - Fix documentation formatting and links in controller_classes.rst - Add controller subdirectory with proper __init__.py Documentation improvements: - Fix title underline length in controller_classes.rst to resolve Sphinx warning - Correct external link syntax for BadPointPressureController notebook - Update controller name to BadPointPressureLiftController (actual class name) The BadPointPressureLiftController maintains minimum pressure difference at the worst point (Schlechtpunkt) in district heating networks by automatically detecting the heat exchanger with the lowest pressure difference and adjusting circulation pump pressures accordingly. Features: - Automatic worst point detection - Proportional pressure control - Standby mode when no heat flow detected - Convergence checking with configurable tolerance
Added the controller in pandapipes/control/controller. Also updated the reference in the rst-file to solve the previous sphinx error. |
Fix Codacy code style issues by removing trailing whitespace: - Line 28: Remove trailing space from __init__ method signature - Line 53: Remove trailing whitespace from empty line after docstring - Line 136: Remove trailing spaces from pflow_adjustment assignment - Line 139: Remove trailing whitespace from empty line No functional changes, code style cleanup only.
We should also a test for the controller. |
Add test file with 2 focused test cases covering core controller functionality: Tests added: - Controller maintains target pressure difference at worst point in district heating network - Standby mode activation when no heat demand is present Additional improvements: - Fix pandas FutureWarning in controller code by replacing chained assignment with proper .loc syntax (net.circ_pump_pressure.loc[:, "column"]) All tests pass successfully with no warnings. Test location: src/pandapipes/test/api/test_components/test_bad_point_pressure_lift_controller.py
I think the test could be put into a directory test/control/ for a more clear structure |
Move BadPointPressureLiftController tests to test/control/
EPrade
left a comment
There was a problem hiding this comment.
Looks good to me. @SimonRubenDrauz I think it could be merged now
| Key Features: | ||
| - **Automatic Worst Point Detection:** Identifies the heat exchanger with the lowest pressure difference where heat flow is present. | ||
| - **Pressure Regulation:** Adjusts the circulation pump's lift and flow pressures to ensure the pressure difference at the worst point meets a specified minimum target. | ||
| - **Proportional Control:** Uses a proportional gain to determine the adjustment magnitude based on the deviation from the target pressure difference. | ||
| - **Standby Mode:** If no heat flow is detected, the controller switches the pump to a standby mode with minimum lift and flow pressures. | ||
| - **Convergence Check:** Determines if the pressure difference is within a specified tolerance of the target, signaling convergence. | ||
|
|
||
| Args: | ||
| net (pandapipesNet): The pandapipes network. | ||
| circ_pump_pressure_idx (int, optional): Index of the circulation pump. Defaults to 0. | ||
| target_dp_min_bar (float, optional): Target minimum pressure difference in bar. Defaults to 1. | ||
| tolerance (float, optional): Tolerance for pressure difference. Defaults to 0.2. | ||
| proportional_gain (float, optional): Proportional gain for the controller. Defaults to 0.2. | ||
| min_plift (float, optional): Minimum lift pressure in bar. Defaults to 1.5. | ||
| min_pflow (float, optional): Minimum flow pressure in bar. Defaults to 3.5. | ||
| **kwargs: Additional keyword arguments. |
There was a problem hiding this comment.
Could you adapt the docstrings to Sphinx / reStructuredText (reST) style
| for idx, qext, p_from, p_to in zip(net.heat_consumer.index, net.heat_consumer["qext_w"], | ||
| net.res_heat_consumer["p_from_bar"], net.res_heat_consumer["p_to_bar"]): | ||
| if qext != 0: | ||
| dp_diff = p_from - p_to | ||
| dp.append((dp_diff, idx)) | ||
|
|
||
| if not dp: | ||
| return 0, -1 | ||
|
|
||
| # Find the minimum delta p where the heat flow is not zero | ||
| dp_min, idx_min = min(dp, key=lambda x: x[0]) | ||
|
|
||
| return dp_min, idx_min |
There was a problem hiding this comment.
why not using:
diff = net.res_heat_consumer["p_from_bar"] - net.res_heat_consumer["p_to_bar"]
diff.min(), diff.idxmin()
There was a problem hiding this comment.
Good point! Old implementation of mine, never optimized it. I'm going to simplify the code to use pandas operations instead of the manual loop:
diff = net.res_heat_consumer["p_from_bar"] - net.res_heat_consumer["p_to_bar"]
Then filtering with active_consumers = qext != 0 and using diff.min() and diff.idxmin().
| net.circ_pump_pressure.loc[:, "plift_bar"] = self.min_plift # Minimum lift pressure | ||
| net.circ_pump_pressure.loc[:, "p_flow_bar"] = self.min_pflow # Minimum flow pressure |
There was a problem hiding this comment.
Why all circ pumps?
There was a problem hiding this comment.
You're right. I've never had a problem, as I always only use one circ_pump_pressure. I'm going to change it from .loc[:, ...] to .at[self.circ_pump_pressure_idx, ...] so it only affects the single controlled pump, not all pumps in the network.
| new_plift = current_plift_bar + plift_adjustment | ||
| new_pflow = current_pflow_bar + pflow_adjustment | ||
|
|
||
| net.circ_pump_pressure["plift_bar"].at[self.circ_pump_pressure_idx] = new_plift | ||
| net.circ_pump_pressure["p_flow_bar"].at[self.circ_pump_pressure_idx] = new_pflow |
There was a problem hiding this comment.
This seems to me a bit random and error prone. Usually you keep one pressure fixed: flow or return and only adapt the pressure lift accordingly.
There was a problem hiding this comment.
In my understanding: For this application we need to adjust both p_flow_bar
and plift_bar together. The reason is that p_flow_bar sets the absolute pressure at the
pump outlet (supply), and plift_bar sets the pressure increase across the pump.
If we only adjust plift_bar while keeping p_flow_bar constant, increasing plift_bar would
actually decrease the return pressure (since p_flow = p_return + plift), which is
would be restricted by the pressure maintenance in place, right?
By adjusting both pressures with the same proportional gain, we make sure, that the return pressure stays in place.
If that's not the case, I'd like to discuss it, before finishing this pull request.
There was a problem hiding this comment.
Yes, we should discuss this first I guess.
|
Didn't not have much time but here some ideas. |
Address code review feedback: - Simplify worst point calculation using pandas operations (min/idxmin) instead of manual loop for better performance and readability - Fix standby mode to only affect the controlled pump using .at indexing instead of .loc[:, ...] which would affect all pumps in the network Changes based on review by SimonRubenDrauz. All tests continue to pass.
…tps://github.com/JonasPfeiffer123/pandapipes into Tutorials-Examples-District-Heating-Controllers-
Changes based on code review feedback from SimonRubenDrauz.
…ure difference calculation
Implemented two operating modes to provide flexibility in pressure control strategy:
- **fixed_preturn mode (default)**: Adjusts both p_flow_bar and plift_bar
simultaneously to maintain constant return pressure. Ideal when return
pressure stability is critical for the overall network.
- **fixed_pflow mode**: Keeps flow pressure constant by adjusting only
plift_bar. Return pressure may vary but is protected by min_preturn
parameter. Useful when flow pressure must remain fixed due to supply
line limitations.
This resolves the implementation question of which control strategy is
more appropriate by allowing users to choose based on their specific
network requirements. Both modes successfully maintain the target
pressure difference at the worst point while respecting different
operational constraints.
Changes:
- Added 'mode' parameter with validation ('fixed_pflow'/'fixed_preturn')
- Added 'min_preturn' parameter to prevent return pressure drops in
fixed_pflow mode
- Updated control_step() logic to handle both modes
- Extended tests to verify both modes work correctly
- Updated documentation and tutorial notebook with mode comparison
|
I've implemented a dual-mode system for the BadPointPressureLiftController, allowing users to choose between Mode options:
Both modes successfully maintain the target pressure difference at the worst point while respecting different operational constraints. This follows discussions with @Theda-ISE and @EPrade regarding the optimal implementation approach for this controller. |
|
A small suggestion: change the name of the tutorial (and the rest of the files accrodingly) to WorstPointPressureDropController instead of BadPointPressureLiftController. |
After getting contacted by @Theda-ISE regarding certain features in my pandapipes usage that she had discovered, she asked if I could create a tutorial for some of the features. Therefore, I'd like to share an implementation of a bad-point differential pressure control system that I've been using for a while. Feel free to comment & sharing ideas for improvement.
This pull request introduces a new Jupyter notebook tutorial,
BadPointPressureController.ipynb, which provides a comprehensive guide and implementation for a custom pressure controller in district heating networks. The notebook includes detailed explanations, code implementation, and an example usage of theBadPointPressureLiftController.New Feature:
BadPointPressureLiftControllerBadPointPressureLiftController, a custom controller for district heating networks using pandapipes. It ensures a minimum pressure difference at the network's "worst point" (heat exchanger with the lowest pressure difference).Example Usage and Test Network