Skip to content

Conversation

@FBumann
Copy link
Member

@FBumann FBumann commented Nov 30, 2025

Description

Brief description of the changes in this PR.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Code refactoring

Related Issues

Closes #(issue number)

Testing

  • I have tested my changes
  • Existing tests still pass

Checklist

  • My code follows the project style
  • I have updated documentation if needed
  • I have added tests for new functionality (if applicable)

Summary by CodeRabbit

  • Refactor

    • Renamed Bus parameter excess_penalty_per_flow_hour to imbalance_penalty_per_flow_hour for improved clarity
    • Renamed Bus property with_excess to allows_imbalance
    • Changed default bus balance constraint to strict (None instead of 1e5)
    • Deprecated legacy Calculation and Aggregation APIs; migrate to Optimization and Clustering equivalents
  • Documentation

    • Updated guides and examples to reflect renamed parameters

✏️ Tip: You can customize this high-level summary in your review settings.

  |-------------------------|----------------------------------------------------------------------------------|
  | flixopt/elements.py     | Renamed attributes excess_input → virtual_supply, excess_output → virtual_demand |
  | flixopt/optimization.py | Updated attribute access and result keys                                         |
  | tests/test_bus.py       | Updated variable name strings in assertions                                      |
  | docs/.../Bus.md         | Updated description of φ symbols                                                 |

  The variable names in the optimization model are now:
  - {BusName}|virtual_supply (was excess_input)
  - {BusName}|virtual_demand (was excess_output)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR implements large-scale public API refactoring involving parameter and attribute renames (excess → imbalance semantics, with new virtual supply/demand concepts), removal of deprecated calculation modules with migration pathways, and updates to related method signatures and results structures across the codebase.

Changes

Cohort / File(s) Summary
Bus & BusModel Core Semantics
flixopt/elements.py, tests/test_bus.py
Renamed Bus.excess_penalty_per_flow_hourimbalance_penalty_per_flow_hour (default: None for strict balance); renamed BusModel.excess_input/excess_outputvirtual_supply/virtual_demand; added Bus.allows_imbalance() method; updated balance logic and penalty handling to use new virtual concepts.
Documentation
docs/user-guide/mathematical-notation/effects-penalty-objective.md, docs/user-guide/mathematical-notation/elements/Bus.md
Updated penalty parameter references and descriptions to use imbalance_penalty_per_flow_hour and virtual supply/demand terminology in mathematical notation and Bus documentation.
Examples
examples/02_Complex/complex_example.py, examples/03_Optimization_modes/example_optimization_modes.py
Updated Bus constructor calls to use imbalance_penalty_per_flow_hour parameter instead of excess_penalty_per_flow_hour.
FlowSystem & Optimization
flixopt/flow_system.py, flixopt/optimization.py
Updated FlowSystem docstring example and refactored "Buses with excess" results section to use allows_imbalance filtering and virtual_supply/virtual_demand metrics instead of excess_input/excess_output.
Test Coverage
tests/test_functional.py
Updated Bus constructor parameter references in flow system setup from excess_penalty_per_flow_hour to imbalance_penalty_per_flow_hour.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Attention areas:
    • Semantic correctness of virtual supply/demand logic in flixopt/elements.py balance equation and penalty accumulation
    • Backward compatibility handling and deprecated parameter aliasing in Bus.__init__
    • Results structure changes and data propagation through BusModel.results_structure
    • Consistency of allows_imbalance() checks across optimization and reporting code paths

Possibly related PRs

  • Feature/v3/update 2 #355: Updates deprecation guidance for active_timesteps to recommend flow_system.sel/isel, complementing removal and migration patterns in this PR.
  • Feature/sums over all periods #475: Renames FlowSystem.weightsscenario_weights, representing a similar public API refactoring pattern.
  • Feature/penalty as effect #486: Modifies penalty modeling and application in flixopt/elements.py, overlapping with imbalance penalty semantic changes here.

Poem

🐰 Excess becomes balance, with virtual touch,
Supply and demand dance—a semantic crutch,
API blooms renamed, the old paths retire,
From imbalance penalties to truths we aspire,
Migration maps guide us through change's sweet hedge.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is completely empty template boilerplate with no actual details about the significant API changes, renames, or migration paths. Fill in the description template with details about excess→imbalance renames, virtual_supply/demand changes, related issues/issue numbers, and testing verification.
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feature/excess rename' is vague and uses non-descriptive branch naming convention terminology rather than summarizing the actual changes. Use a descriptive title like 'Rename excess penalty and balance parameters to imbalance semantics' to clearly convey the primary change.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	CHANGELOG.md
#	flixopt/flow_system.py
@FBumann
Copy link
Member Author

FBumann commented Nov 30, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
docs/user-guide/mathematical-notation/elements/Bus.md (1)

8-9: Fix pre-existing typos in documentation.

While reviewing the updated documentation, I noticed some pre-existing typos that should be corrected:

  • Line 8: "a imbalance_penalty_per_flow_hour" → "an imbalance_penalty_per_flow_hour"
  • Line 9: "usefull" → "useful"
  • Line 9: "ifeasiblity" → "infeasibility"
-Optionally, a Bus can have a `imbalance_penalty_per_flow_hour` parameter, which allows to penaltize the balance for missing or excess flow-rates.
-This is usefull as it handles a possible ifeasiblity gently.
+Optionally, a Bus can have an `imbalance_penalty_per_flow_hour` parameter, which allows to penalize the balance for missing or excess flow-rates.
+This is useful as it handles a possible infeasibility gently.
tests/test_bus.py (2)

39-52: Virtual supply/demand test expectations align with BusModel

The expectations for:

  • variables: TestBus|virtual_supply, TestBus|virtual_demand, and
  • balance constraint: GastarifTest(Q_Gas)|flow_rate - WärmelastTest(Q_th_Last)|flow_rate + virtual_supply - virtual_demand == 0

are consistent with the BusModel implementation (Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand). The assert_var_equal checks against model.add_variables(lower=0, coords=...) are a bit indirect but correctly validate bounds and coordinates.

If you want the tests to be less side‑effecty, consider exposing a small helper that creates an anonymous variable with the same defaults instead of calling add_variables inside the assertion.

Also applies to: 54-60


68-80: Penalty share test matches new imbalance semantics; comments mention “excess”

The final penalty constraint check correctly asserts that
TestBus->Penalty(temporal) equals (virtual_supply + virtual_demand) * 1e5 * hours_per_step, which matches the BusModel’s use of imbalance_penalty_per_flow_hour. The only nit is that the comments still refer to “excess” rather than imbalance/virtual supply/demand, which might confuse readers.

You could update Lines 68–70 to use the new terminology (imbalance, virtual_supply/virtual_demand) to keep tests and docs aligned.

flixopt/elements.py (2)

246-259: Bus constructor, data transform, and plausibility checks look coherent

  • The __init__ signature with imbalance_penalty_per_flow_hour and **kwargs, plus _handle_deprecated_kwarg(...) for excess_penalty_per_flow_hour, provides a clean migration path while still validating unexpected kwargs.
  • transform_data correctly routes imbalance_penalty_per_flow_hour through _fit_coords, consistent with other TPS‑style parameters.
  • _plausibility_checks reuses the existing pattern to warn on all‑zero penalties and still enforces the “at least one flow” invariant.
  • allows_imbalance as imbalance_penalty_per_flow_hour is not None is simple and used appropriately in BusModel.

No functional issues spotted here.

If you want to be stricter, you could later extend _plausibility_checks to reject negative penalties rather than silently allowing them.

Also applies to: 273-277, 279-286, 291-293


863-891: BusModel balance and penalty logic are mathematically sound; minor clarity improvements possible

The BusModel changes behave as intended:

  • virtual_supply/virtual_demand are only created when allows_imbalance is true.
  • The modified balance constraint effectively enforces
    Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand,
    which matches the docstring and tests (they check the inputs - outputs + virtual_supply - virtual_demand == 0 form).
  • The penalty scaling imbalance_penalty = hours_per_step * imbalance_penalty_per_flow_hour mirrors the FlowModel shares pattern, and separate temporal penalty shares for supply and demand are consistent with the tests.

Two small readability/maintenance nits:

  • Line 890’s eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand is algebraically correct but a bit opaque. eq_bus_balance.lhs += self.virtual_supply - self.virtual_demand would be easier to read.
  • The two add_share_to_effects calls could be combined into a single call with a summed expression to make it obvious that the total penalty is (virtual_supply + virtual_demand) * imbalance_penalty.

You could refactor this block as:

-        if self.element.allows_imbalance:
-            imbalance_penalty = np.multiply(self._model.hours_per_step, self.element.imbalance_penalty_per_flow_hour)
-
-            self.virtual_supply = self.add_variables(
-                lower=0, coords=self._model.get_coords(), short_name='virtual_supply'
-            )
-
-            self.virtual_demand = self.add_variables(
-                lower=0, coords=self._model.get_coords(), short_name='virtual_demand'
-            )
-
-            eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand
+        if self.element.allows_imbalance:
+            imbalance_penalty = np.multiply(
+                self._model.hours_per_step, self.element.imbalance_penalty_per_flow_hour
+            )
+
+            self.virtual_supply = self.add_variables(
+                lower=0, coords=self._model.get_coords(), short_name='virtual_supply'
+            )
+            self.virtual_demand = self.add_variables(
+                lower=0, coords=self._model.get_coords(), short_name='virtual_demand'
+            )
+
+            # Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand
+            eq_bus_balance.lhs += self.virtual_supply - self.virtual_demand
@@
-            self._model.effects.add_share_to_effects(
-                name=self.label_of_element,
-                expressions={PENALTY_EFFECT_LABEL: self.virtual_supply * imbalance_penalty},
-                target='temporal',
-            )
-            self._model.effects.add_share_to_effects(
-                name=self.label_of_element,
-                expressions={PENALTY_EFFECT_LABEL: self.virtual_demand * imbalance_penalty},
-                target='temporal',
-            )
+            total_imbalance = (self.virtual_supply + self.virtual_demand) * imbalance_penalty
+            self._model.effects.add_share_to_effects(
+                name=self.label_of_element,
+                expressions={PENALTY_EFFECT_LABEL: total_imbalance},
+                target='temporal',
+            )

This preserves behavior while making the intent more obvious.

Also applies to: 895-903

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90d5e9c and 66fb2d8.

📒 Files selected for processing (10)
  • CHANGELOG.md (1 hunks)
  • docs/user-guide/mathematical-notation/effects-penalty-objective.md (1 hunks)
  • docs/user-guide/mathematical-notation/elements/Bus.md (2 hunks)
  • examples/02_Complex/complex_example.py (2 hunks)
  • examples/03_Optimization_modes/example_optimization_modes.py (2 hunks)
  • flixopt/elements.py (8 hunks)
  • flixopt/flow_system.py (1 hunks)
  • flixopt/optimization.py (1 hunks)
  • tests/test_bus.py (4 hunks)
  • tests/test_functional.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
tests/test_functional.py (1)
flixopt/elements.py (1)
  • Bus (183-297)
flixopt/optimization.py (1)
flixopt/elements.py (1)
  • allows_imbalance (292-293)
examples/03_Optimization_modes/example_optimization_modes.py (1)
flixopt/elements.py (1)
  • Bus (183-297)
examples/02_Complex/complex_example.py (1)
flixopt/elements.py (1)
  • Bus (183-297)
tests/test_bus.py (1)
flixopt/elements.py (1)
  • Bus (183-297)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.10)
🔇 Additional comments (10)
CHANGELOG.md (1)

124-135: LGTM! Comprehensive changelog documentation.

The changelog clearly documents:

  • The breaking change in default value (None vs 1e5)
  • All renamed attributes and properties
  • The deprecation path for the old parameter name

This provides users with clear migration guidance.

flixopt/flow_system.py (1)

80-80: LGTM! Documentation example updated correctly.

The example in the FlowSystem docstring correctly uses the new imbalance_penalty_per_flow_hour parameter name.

flixopt/optimization.py (1)

309-322: LGTM! Implementation correctly uses new API.

The implementation correctly:

  • References virtual_supply and virtual_demand instead of the old excess_input/excess_output
  • Uses bus.allows_imbalance property instead of the old with_excess
  • Applies appropriate numerical tolerance (1e-3) when checking for non-zero imbalances

The logic correctly filters to only report buses that both allow imbalances AND have actual non-zero imbalances in the solution.

docs/user-guide/mathematical-notation/effects-penalty-objective.md (1)

200-200: LGTM! Documentation correctly updated.

The penalty usage description correctly references the new imbalance_penalty_per_flow_hour parameter name.

examples/03_Optimization_modes/example_optimization_modes.py (1)

44-44: LGTM! Example correctly updated to use new API.

The example correctly:

  • Renames the variable from excess_penalty to imbalance_penalty for clarity
  • Uses the new imbalance_penalty_per_flow_hour parameter in all Bus constructors
  • Maintains the same behavior with explicit value of 1e5

Also applies to: 70-73

tests/test_functional.py (1)

69-70: LGTM! Test correctly updated to use new API.

The test setup correctly uses the new imbalance_penalty_per_flow_hour=None parameter, which appropriately tests the strict balance constraint behavior (no imbalances allowed).

examples/02_Complex/complex_example.py (1)

16-16: LGTM! Example correctly updated to use new API.

The example correctly:

  • Renames the variable from excess_penalty to imbalance_penalty for improved clarity
  • Uses the new imbalance_penalty_per_flow_hour parameter in all Bus constructors
  • Maintains consistent behavior with explicit value of 1e5

Also applies to: 37-39

tests/test_bus.py (1)

9-16: Constructor rename usage looks correct

All Bus instantiations now use imbalance_penalty_per_flow_hour with None and large positive values, matching the new API and doc semantics (hard vs soft balance). No issues here.

Also applies to: 28-36, 82-90

flixopt/elements.py (2)

196-236: Bus docstring and examples are in sync with new imbalance behavior

The updated docstring and examples for imbalance_penalty_per_flow_hour, the virtual balance equation, and the None vs > 0 semantics match what BusModel actually implements with virtual_supply and virtual_demand. This keeps the public API documentation aligned with the modeling logic.


906-918: Including virtual_supply/virtual_demand in results_structure is consistent with balance semantics

Conditionally appending virtual_supply to inputs and virtual_demand to outputs when those variables exist lines up with the balance equation and keeps results for strict buses unchanged. This should make downstream result consumers see virtual imbalance terms as just another input/output, which is intuitive.

…ee typos:

    - "a imbalance_penalty_per_flow_hour" → "an imbalance_penalty_per_flow_hour"
    - "usefull" → "useful"
    - "ifeasiblity" → "infeasibility"
  2. tests/test_bus.py - Updated comments to use the new imbalance terminology instead of the old "excess" terminology
  3. flixopt/elements.py (BusModel) - Improved code clarity:
    - Changed eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand to the more readable eq_bus_balance.lhs += self.virtual_supply -
  self.virtual_demand
    - Added a comment explaining the equation: # Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand
    - Combined the two separate add_share_to_effects calls into a single call with the combined expression (self.virtual_supply +
  self.virtual_demand) * imbalance_penalty

  All 12 bus tests pass with these changes.
@FBumann FBumann merged commit 1c4511a into feature/v5 Nov 30, 2025
8 checks passed
FBumann added a commit that referenced this pull request Dec 10, 2025
* | File                    | Changes                                                                          |
  |-------------------------|----------------------------------------------------------------------------------|
  | flixopt/elements.py     | Renamed attributes excess_input → virtual_supply, excess_output → virtual_demand |
  | flixopt/optimization.py | Updated attribute access and result keys                                         |
  | tests/test_bus.py       | Updated variable name strings in assertions                                      |
  | docs/.../Bus.md         | Updated description of φ symbols                                                 |

  The variable names in the optimization model are now:
  - {BusName}|virtual_supply (was excess_input)
  - {BusName}|virtual_demand (was excess_output)

* Renamed excess_penalty_per_flow_hour → imbalance_penalty_per_flow_hour

* rename excess_penalty to imbalance_penalty

* Change default to None

* Added self._validate_kwargs(kwargs) to catch typos and unexpected arguments

* Renamed with_excess → allows_imbalance

* Fix docstring

* 1. docs/user-guide/mathematical-notation/elements/Bus.md - Fixed three typos:
    - "a imbalance_penalty_per_flow_hour" → "an imbalance_penalty_per_flow_hour"
    - "usefull" → "useful"
    - "ifeasiblity" → "infeasibility"
  2. tests/test_bus.py - Updated comments to use the new imbalance terminology instead of the old "excess" terminology
  3. flixopt/elements.py (BusModel) - Improved code clarity:
    - Changed eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand to the more readable eq_bus_balance.lhs += self.virtual_supply -
  self.virtual_demand
    - Added a comment explaining the equation: # Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand
    - Combined the two separate add_share_to_effects calls into a single call with the combined expression (self.virtual_supply +
  self.virtual_demand) * imbalance_penalty

  All 12 bus tests pass with these changes.
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.

2 participants