Skip to content

Conversation

@FBumann
Copy link
Member

@FBumann FBumann commented Nov 30, 2025

Description

Rename bus variables and penalty parameter

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

  • Breaking Changes

    • Public parameter renamed: excess_penalty_per_flow_hour → imbalance_penalty_per_flow_hour
    • Default penalty behavior changed: now None (enforces strict balance) instead of a large numeric default
  • Deprecation

    • Old parameter name still accepted with a deprecation warning; please migrate to the new name
  • Documentation

    • User guides, examples, and result labels updated to use imbalance / virtual_supply / virtual_demand terminology
  • Tests

    • Test suite updated to reflect the new parameter and naming conventions

✏️ 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

Walkthrough

Renames Bus penalty API from excess_penalty_per_flow_hourimbalance_penalty_per_flow_hour (default changed to None), renames internal model fields excess_input/excess_outputvirtual_supply/virtual_demand, adds deprecation mapping for the old kwarg, and updates docs, examples, tests, and result reporting.

Changes

Cohort / File(s) Summary
Core implementation
flixopt/elements.py, flixopt/optimization.py
Rename public Bus parameter to imbalance_penalty_per_flow_hour (default None), replace excess_input/excess_output with virtual_supply/virtual_demand in models, update penalty expressions and results reporting, add deprecation mapping for the old kwarg, and rename with_excessallows_imbalance.
Flow-system example
flixopt/flow_system.py
Update example Bus initialization to use imbalance_penalty_per_flow_hour.
Documentation & changelog
docs/user-guide/mathematical-notation/effects-penalty-objective.md, docs/user-guide/mathematical-notation/elements/Bus.md, CHANGELOG.md
Replace terminology and parameter names with imbalance_penalty_per_flow_hour, virtual_supply, virtual_demand; expand penalty documentation and add deprecation notes in the changelog.
Examples
examples/02_Complex/complex_example.py, examples/03_Optimization_modes/example_optimization_modes.py
Replace excess_penalty* usage with imbalance_penalty_per_flow_hour and corresponding local variable renames; behavior preserved.
Tests
tests/test_bus.py, tests/test_functional.py
Update tests to construct Bus with imbalance_penalty_per_flow_hour, and replace assertions/constraints referencing excess_* with virtual_supply/virtual_demand.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect deprecation mapping in flixopt/elements.py to ensure the old kwarg is accepted and correctly mapped in all construction paths.
  • Verify result keys and reporting in flixopt/optimization.py align with virtual_supply/virtual_demand.
  • Confirm tests and examples reflect the new default (None) where intended.

Possibly related PRs

  • Feature/penalty as effect #486 — Related penalty-handling changes that promote penalty into the Effect system and introduce PENALTY_EFFECT_LABEL; directly connected to penalty renames and reporting.

Suggested labels

v3.0.0

Poem

🐇
I hopped through code and nibbled names,
excess became virtual carrots and games,
imbalance now hums where penalties play,
supplies and demands in a tidy array,
a joyful hop — the API's renamed.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete and generic. It lacks detail about what was renamed, why the changes were made, and leaves template placeholders unfilled without issue references or testing confirmation. Provide a detailed description of the renaming changes, specify the related issue number, and confirm testing status by checking the appropriate boxes.
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 is vague and generic, using non-descriptive phrasing like 'Feature/excess rename v4' that doesn't clearly communicate the main changes to someone scanning history. Use a more descriptive title that clearly indicates the specific renaming changes, e.g., 'Rename excess penalty and bus model properties to imbalance terminology'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/excess-rename-v4

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bc03a8 and 8914750.

📒 Files selected for processing (1)
  • flixopt/elements.py (8 hunks)
⏰ 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.10)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.11)
🔇 Additional comments (5)
flixopt/elements.py (5)

199-243: Documentation clearly reflects the API rename.

The updated docstring correctly documents imbalance_penalty_per_flow_hour, provides clear examples for both hard constraint (None) and penalty-based imbalance scenarios, and accurately describes the balance equation using virtual_supply/virtual_demand terminology.


247-259: Deprecation handling and kwargs validation implemented correctly.

The initialization properly handles the deprecated excess_penalty_per_flow_hour parameter via _handle_deprecated_kwarg and validates remaining kwargs with _validate_kwargs, preventing silent failures from typos or unexpected arguments.


274-294: Property and method updates are consistent with the rename.

The transform_data, _plausibility_checks, and allows_imbalance property correctly reference the new imbalance_penalty_per_flow_hour parameter. The property rename to allows_imbalance is more semantically clear than the previous with_excess.


938-939: Field renames improve semantic clarity.

Renaming excess_input/excess_output to virtual_supply/virtual_demand better describes these variables' role in the balance equation as slack variables that can supply to or absorb from the bus when imbalances are allowed.


952-992: Balance equation and penalty logic correctly implement the renamed variables.

The implementation properly:

  • Creates virtual_supply and virtual_demand variables when imbalances are allowed
  • Adjusts the balance equation to: inputs + virtual_supply == outputs + virtual_demand (matches docstring on line 234)
  • Applies penalty costs to both virtual_supply and virtual_demand using the renamed imbalance_penalty_per_flow_hour
  • Reports virtual_supply in inputs and virtual_demand in outputs, which correctly represents their role in the balance

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.

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/user-guide/mathematical-notation/elements/Bus.md (1)

13-24: Clean up LaTeX notation in balance and penalty equations

There are a couple of small LaTeX issues here that are worth fixing for clarity:

  • In the balance equation, remove the stray space in the subscript:
  • \sum_{f_\text{in} \in \mathcal{F}\text{in}} p{f_ \text{in}}(\text{t}i) + \phi\text{in}(\text{t}_i) =
  • \sum_{f_\text{in} \in \mathcal{F}\text{in}} p{f_\text{in}}(\text{t}i) + \phi\text{in}(\text{t}_i) =

- In the penalty term, wrap `\text` properly:
```diff
-      \text a_{b \rightarrow \Phi}(\text{t}_i) \cdot \Delta \text{t}_i
+      \text{a}_{b \rightarrow \Phi}(\text{t}_i) \cdot \Delta \text{t}_i
🧹 Nitpick comments (4)
CHANGELOG.md (1)

52-72: Changelog entries match implementation; consider adding removal version to deprecation

The new bullets for the Bus imbalance penalty default and the renames look consistent with the Bus implementation and behavior. As a minor consistency tweak with other sections, you could extend the deprecation bullet to mention the planned removal version (e.g. “…will be removed in v5.0.0”) if that is already decided.

flixopt/optimization.py (1)

329-342: Align “Buses with excess” reporting with virtual_supply/virtual_demand terminology

The switch to virtual_supply / virtual_demand in main_results is consistent with the BusModel changes, and the filtering on non‑zero sums still works as before.

For naming consistency with the new terminology, you might (optionally) rename the section key to something like "Buses with imbalance" instead of "Buses with excess" in a future breaking release.

flixopt/elements.py (2)

199-201: Docstring and examples match new parameter; consider terminology polish

The constructor docs and examples correctly describe imbalance_penalty_per_flow_hour and its None default (hard balance). The note still uses “excess/deficit” language while the implementation/tests talk about virtual_supply/virtual_demand; it’s still conceptually correct but you might want to align terminology here for clarity.

Also applies to: 211-211, 220-220, 229-229, 233-236


952-953: Imbalance modeling and penalty shares are consistent; consider simplifying balance update

The BusModel now:

  • builds imbalance_penalty = hours_per_step * imbalance_penalty_per_flow_hour,
  • adds non-negative virtual_supply and virtual_demand variables,
  • adjusts the balance so it effectively becomes inputs - outputs + virtual_supply - virtual_demand == 0,
  • and adds temporal penalty shares for both virtual variables.

This matches the updated tests and yields the expected objective contributions. The only nit is the line:

eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand

which is algebraically correct but a bit hard to read. For clarity you might prefer:

eq_bus_balance.lhs += self.virtual_supply - self.virtual_demand

leaving behavior unchanged.

Also applies to: 955-961, 963-963, 968-971, 973-976

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 423496a and 3e725b9.

📒 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 (9 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 (4)
examples/02_Complex/complex_example.py (1)
flixopt/elements.py (1)
  • Bus (184-297)
examples/03_Optimization_modes/example_optimization_modes.py (1)
flixopt/elements.py (1)
  • Bus (184-297)
tests/test_functional.py (1)
flixopt/elements.py (1)
  • Bus (184-297)
tests/test_bus.py (1)
flixopt/elements.py (1)
  • Bus (184-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.13)
  • GitHub Check: test (3.12)
  • GitHub Check: test (3.10)
  • GitHub Check: test (3.11)
🔇 Additional comments (14)
docs/user-guide/mathematical-notation/elements/Bus.md (1)

28-34: Virtual supply/demand terminology and coefficient name look consistent

The definitions of $\phi_\text{in}$ / $\phi_\text{out}$ as virtual supply/demand and the mapping of $\text{a}_{b \rightarrow \Phi}$ to imbalance_penalty_per_flow_hour are clear and aligned with the Bus API.

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

193-207: Penalty usage note is accurate and well-scoped

The new “Primary usage” sentence correctly links penalties to imbalance_penalty_per_flow_hour on Buses and TSA flexibility; no changes needed.

examples/02_Complex/complex_example.py (1)

13-40: Bus example now correctly uses imbalance_penalty_per_flow_hour

The local imbalance_penalty variable and the three Bus initializations are aligned with the new parameter name and semantics; no further changes needed.

examples/03_Optimization_modes/example_optimization_modes.py (1)

41-74: Imbalance penalty wiring in example is consistent with Bus API

The renamed imbalance_penalty variable and its use as imbalance_penalty_per_flow_hour for all buses are consistent and clearly documented by the “or set to None if not needed” comment.

flixopt/flow_system.py (1)

73-83: FlowSystem docstring Bus example updated correctly

The example now uses imbalance_penalty_per_flow_hour=1e4, which matches the new Bus constructor and docs.

tests/test_functional.py (1)

64-80: Functional tests correctly updated to new Bus penalty keyword

Using imbalance_penalty_per_flow_hour=None for the two buses in flow_system_base matches the new Bus API and keeps the tests’ strict-balance assumption explicit.

tests/test_bus.py (2)

12-12: Bus constructor updates align with new API

Using imbalance_penalty_per_flow_hour in all three test setups correctly tracks the renamed parameter, and explicitly passing None where you want a hard balance is consistent with the new default. No issues from the test side here.

Also applies to: 31-31, 85-85


40-41: Virtual supply/demand expectations and penalty expression look consistent

The updated expectations for:

  • variable names (TestBus|virtual_supply, TestBus|virtual_demand),
  • balance constraint (Gastarif - Wärmelast + virtual_supply - virtual_demand == 0),
  • and penalty shares (virtual_* * 1e5 * hours_per_step)

all match the BusModel logic that augments the bus balance with virtual_supply/virtual_demand and multiplies by hours_per_step * imbalance_penalty_per_flow_hour. This is a faithful adaptation of the previous excess-based tests.

Also applies to: 48-48, 51-51, 58-59, 78-79

flixopt/elements.py (6)

250-251: Behavioral change: defaulting to a hard bus balance now

With imbalance_penalty_per_flow_hour: Numeric_TPS | None = None and with_excess implemented as self.imbalance_penalty_per_flow_hour is not None, a Bus without an explicit penalty now enforces a hard balance (no virtual variables, no slack). That’s stricter than a non-zero default penalty and may break existing models that relied on an implicit imbalance penalty.

If this change is intentional, it’s fine as-is; otherwise, consider:

  • restoring a positive default value, or
  • clearly highlighting this as a breaking change in release notes / migration docs.

Also applies to: 293-293


275-277: Coordinate fitting for imbalance penalty looks consistent

Transforming imbalance_penalty_per_flow_hour via _fit_coords using the bus prefix mirrors how other time/coords-dependent parameters are handled. As long as _fit_coords already accepts None, this is correct and consistent.


280-281: Zero-penalty plausibility warning is reasonable

The new check for imbalance_penalty_per_flow_hour being identically zero and emitting a warning is a good guardrail against accidentally allowing free imbalances. The use of np.all(np.equal(..., 0)) should work for both scalars and arrays.

Also applies to: 284-285


291-293: with_excess semantics align with imbalance penalty presence

Basing with_excess purely on imbalance_penalty_per_flow_hour is not None keeps the modeling logic simple: virtual_supply/virtual_demand are only created when there is a (possibly zero) penalty parameter. This matches how BusModel gates imbalance handling and is internally consistent.


937-939: Initialization of virtual_supply / virtual_demand is clean

Declaring self.virtual_supply and self.virtual_demand as None before calling super().__init__ makes their later optional use in results_structure straightforward and type-safe.


982-985: Including virtual supply/demand in results only when present makes sense

Appending virtual_supply to inputs and virtual_demand to outputs conditionally on them being non-None is a nice way to keep the results structure minimal for hard-balance buses while still exposing imbalance variables when enabled.

Comment on lines +8 to 10
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.

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix grammar and spelling in imbalance penalty description

Consider tightening the wording and correcting typos, e.g.:

-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 penalizes imbalances from missing or excess flow-rates.
+This is useful as it handles potential infeasibility gently.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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 penalizes imbalances from missing or excess flow-rates.
This is useful as it handles potential infeasibility gently.
🧰 Tools
🪛 LanguageTool

[grammar] ~9-~9: Ensure spelling is correct
Context: ...r missing or excess flow-rates. This is usefull as it handles a possible ifeasiblity ge...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~9-~9: Ensure spelling is correct
Context: ...his is usefull as it handles a possible ifeasiblity gently. This changes the balance to $...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
In docs/user-guide/mathematical-notation/elements/Bus.md around lines 8 to 10,
the description of the imbalance_penalty_per_flow_hour parameter contains typos
and unclear wording; rewrite the sentence to correct spelling (e.g., "penaltize"
→ "penalize", "usefull" → "useful", "ifeasiblity" → "infeasibility"), tighten
phrasing, and clarify the intent (for example: "Optionally, a Bus can have an
imbalance_penalty_per_flow_hour parameter, which penalizes deviations from
balance in flow rates and softly handles possible infeasibility."). Ensure
concise, grammatical English and keep technical meaning unchanged.

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 (3)
CHANGELOG.md (1)

60-73: Changelog entry is accurate; consider clarifying deprecation/removal details

The bullets correctly describe the new default (None → strict balance) and the Bus/BusModel renames. Two minor polish points:

  • In the Deprecated section, consider adding the planned removal version for Bus.excess_penalty_per_flow_hour (consistent with other deprecations in this file).
  • For Bus.with_excessallows_imbalance, if with_excess is no longer available even as a deprecated alias, this is a breaking change and might be worth calling out explicitly under Breaking Changes rather than only under Changed.
flixopt/elements.py (2)

193-237: Align Bus docstring balance equation with new virtual_supply/virtual_demand naming

The docstring still describes the balance as Σ(inflows) = Σ(outflows) + excess - deficit, while the implementation and results now use virtual_supply and virtual_demand. For clarity, consider updating the equation and surrounding text to something like:

  • Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand

and consistently referring to “virtual supply/demand” instead of “excess/deficit” in this block.


280-295: Consider stricter plausibility checks on imbalance penalties

Right now _plausibility_checks() only warns when all entries of imbalance_penalty_per_flow_hour are exactly zero, and allows_imbalance simply checks for is not None.

If negative penalties are never meaningful in this context, you may want to:

  • Raise (or at least warn) when any value is < 0, since that would make imbalances rewarding.
  • Optionally decide whether a mixed array (some zeros, some positive) should also trigger a warning, depending on whether “free” imbalances in some timesteps are intended.

The current behavior is safe but tightening these checks would catch obvious misconfigurations earlier.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e725b9 and 7bc03a8.

📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • flixopt/elements.py (8 hunks)
  • flixopt/optimization.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • flixopt/optimization.py
🧰 Additional context used
🧬 Code graph analysis (1)
flixopt/elements.py (2)
flixopt/structure.py (5)
  • _handle_deprecated_kwarg (517-588)
  • _validate_kwargs (590-618)
  • _fit_coords (349-362)
  • get_coords (227-256)
  • get_coords (1445-1450)
flixopt/flow_system.py (1)
  • coords (1120-1126)
🔇 Additional comments (2)
flixopt/elements.py (2)

247-278: Deprecation handling for Bus penalty keyword and data transformation look correct

Using _handle_deprecated_kwarg to map excess_penalty_per_flow_hourimbalance_penalty_per_flow_hour and then calling _validate_kwargs ensures:

  • The old keyword keeps working with a deprecation path.
  • Typos and unexpected kwargs still raise TypeError instead of being silently ignored.
  • transform_data() correctly routes imbalance_penalty_per_flow_hour through _fit_coords so it aligns with model coordinates.

This mirrors the pattern used elsewhere (e.g., Flow.__init__) and avoids the earlier risk of swallowed kwargs. No changes needed from my side.


937-987: Virtual supply/demand modeling and penalty integration are consistent with the new API

The BusModel changes look coherent:

  • Initializing virtual_supply/virtual_demand to None in __init__ and only creating non‑negative variables when element.allows_imbalance is true cleanly distinguishes hard vs. soft balance.
  • Updating the balance constraint via eq_bus_balance.lhs -= -virtual_supply + virtual_demand yields Σ(inputs) + virtual_supply = Σ(outputs) + virtual_demand, which matches the intended semantics.
  • Multiplying by hours_per_step before applying imbalance_penalty_per_flow_hour correctly converts the per‑flow‑hour penalty into a per‑timestep contribution.
  • Including the virtual variables in results_structure() inputs/outputs only when they exist keeps result inspection aligned with the new terminology without affecting strictly balanced buses.

I don’t see any issues here; this is a clean refactor.

@FBumann FBumann changed the base branch from main to feature/v5 November 30, 2025 04:17
@FBumann FBumann changed the base branch from feature/v5 to main November 30, 2025 04:17
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