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 OnOffParameters to StatusParameters across the public API.
    • Updated parameter names: on_off_parametersstatus_parameters; effects_per_switch_oneffects_per_startup; on_hours_min/maxactive_hours_min/max; and related fields.
    • Renamed internal variables: onstatus; consecutive_on_hoursuptime; consecutive_off_hoursdowntime.
    • Breaking change: Migration required for existing code using On/Off parameters.
  • Documentation

    • Updated docs and examples to reflect new StatusParameters terminology and active/inactive state nomenclature.

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

## Parameters Class (`OnOffParameters` → `StatusParameters`)

| Current Name | Recommended Name | Rationale |
|--------------|------------------|-----------|
| `OnOffParameters` | **`StatusParameters`** | Aligns with PyPSA, clearer semantics |
| `effects_per_switch_on` | **`effects_per_startup`** | Standard UC terminology |
| `effects_per_running_hour` | **`effects_per_active_hour`** | Clear, concise, matches "active" state |
| `on_hours_total_min` | **`active_hours_min`** | Total (not consecutive) active hours |
| `on_hours_total_max` | **`active_hours_max`** | Total (not consecutive) active hours |
| `consecutive_on_hours_min` | **`min_uptime`** | Standard UC term (consecutive) |
| `consecutive_on_hours_max` | **`max_uptime`** | Standard UC term (consecutive) |
| `consecutive_off_hours_min` | **`min_downtime`** | Standard UC term (consecutive) |
| `consecutive_off_hours_max` | **`max_downtime`** | Standard UC term (consecutive) |
| `switch_on_total_max` | **`startup_limit`** | Clearer intent, matches "startup" |
| `force_switch_on` | **`force_startup_tracking`** | More explicit about what is forced |

## Model Class (`OnOffModel` → `StatusModel`)

### Class Name
| Current Name | Recommended Name |
|--------------|------------------|
| `OnOffModel` | **`StatusModel`** |

### Constructor Parameters
| Current Name | Recommended Name | Rationale |
|--------------|------------------|-----------|
| `on_variable` | **`status`** | Aligns with PyPSA and literature |
| `previous_states` | **`previous_status`** | Consistency with status variable |

### Variables (short_name in add_variables/expression_tracking_variable)
| Current Name | Recommended Name | Type | Notes |
|--------------|------------------|------|-------|
| `self.on` | **`self.status`** | Input variable | Main binary state variable |
| `'off'` | **Remove variable** | Binary variable | Replace with expression `1 - status` |
| `'switch\|on'` | **`'startup'`** | Binary variable | Startup event indicator |
| `'switch\|off'` | **`'shutdown'`** | Binary variable | Shutdown event indicator |
| `'switch\|count'` | **`'startup_count'`** | Integer variable | Number of startups |
| `'on_hours_total'` | **`'active_hours'`** | Continuous variable | Total active duration |
| `'consecutive_on_hours'` | **`'uptime'`** | Continuous variable | Consecutive active hours |
| `'consecutive_off_hours'` | **`'downtime'`** | Continuous variable | Consecutive inactive hours |

### Properties
| Current Name | Recommended Name | Returns | Meaning |
|--------------|------------------|---------|---------|
| `on_hours_total` | **`active_hours`** | `linopy.Variable` | Total active hours |
| `off` | **Remove property** | — | Use `1 - status` expression |
| `switch_on` | **`startup`** | `linopy.Variable \| None` | Startup events |
| `switch_off` | **`shutdown`** | `linopy.Variable \| None` | Shutdown events |
| `switch_on_nr` | **`startup_count`** | `linopy.Variable \| None` | Number of startups |
| `consecutive_on_hours` | **`uptime`** | `linopy.Variable \| None` | Consecutive active hours |
| `consecutive_off_hours` | **`downtime`** | `linopy.Variable \| None` | Consecutive inactive hours |

### Internal Methods
| Current Name | Recommended Name |
|--------------|------------------|
| `_get_previous_on_duration()` | **`_get_previous_uptime()`** |
| `_get_previous_off_duration()` | **`_get_previous_downtime()`** |

### Internal Properties/Flags (in parameters)
| Current Name | Recommended Name |
|--------------|------------------|
| `use_off` | **Remove** (use expression instead) |
| `use_switch_on` | **`use_startup_tracking`** |
| `use_consecutive_on_hours` | **`use_uptime_tracking`** |
| `use_consecutive_off_hours` | **`use_downtime_tracking`** |

## Constraint Names (short_name in add_constraints)
| Current Name | Recommended Name |
|--------------|------------------|
| `'complementary'` | **Remove** (no off variable) |
| `'on_hours_total'` | **`'active_hours'`** |
| `'switch\|on'`, `'switch\|off'` | **`'startup'`, `'shutdown'`** |
| `'switch\|count'` | **`'startup_count'`** |
| `'consecutive_on_hours'` | **`'uptime'`** |
| `'consecutive_off_hours'` | **`'downtime'`** |

## Complete Terminology Summary (Option A)

**State:**
- `status` (binary): 1 = active, 0 = inactive

**Events:**
- `startup` (binary): transition from inactive to active
- `shutdown` (binary): transition from active to inactive

**Durations:**
- `active_hours` (continuous): **total** hours in active state across time horizon
- `uptime` (continuous): **consecutive** hours currently active (UC standard)
- `downtime` (continuous): **consecutive** hours currently inactive (UC standard)

**Parameter Bounds:**
- `active_hours_min/max`: limits on **total** active hours
- `min_uptime/max_uptime`: limits on **consecutive** active hours (UC standard)
- `min_downtime/max_downtime`: limits on **consecutive** inactive hours (UC standard)
- `startup_limit`: maximum number of startup events

**Effects:**
- `effects_per_startup`: costs/impacts per startup event
- `effects_per_active_hour`: costs/impacts per active hour

This aligns perfectly with PyPSA and the unit commitment literature! 🎯
  1. interface.py - Module docstring now references "Status decisions"
  2. components.py - Updated all docstrings:
    - status_parameters parameter descriptions
    - Example code updated with new parameter names (effects_per_startup, min_uptime, startup_limit)
    - Fixed incorrect "OnOff feature" docstring to "Investment feature"
    - Updated TODO comment to reference StatusParameters
  3. linear_converters.py - All docstrings updated:
    - Import statement updated to StatusParameters
    - All parameter descriptions updated
    - All example code updated with new terminology
  4. flow_system.py - Updated references from "consecutive_on_hours" to "uptime and downtime" and on_off_parameters to status_parameters
  5. modeling.py - Updated docstring from "switch-on/off variables" to "state transition constraints for binary switching variables"

  Documentation Markdown Files Updated:

  1. Flow.md - All references updated:
    - Links to StatusParameters
    - "on/off state" → "active/inactive state"
    - Parameter names updated
  2. StatusParameters.md (renamed from OnOffParameters.md) - Comprehensive updates:
    - Title changed to "StatusParameters"
    - All terminology updated: on/off → active/inactive
    - Mathematical notation updated: s^on/s^off → s^startup/s^shutdown
    - Duration variables: d^on/d^off → d^uptime/d^downtime
    - Parameter names updated in all examples
    - All Python code examples updated with new API
  3. Other modeling pattern docs - Updated all references to StatusParameters and active/inactive terminology
  4. mkdocs.yml - Navigation updated to reference StatusParameters.md

  All docstrings and documentation now consistently use the new Status terminology aligned with PyPSA and unit commitment standards!
  Changes Made:

  1. Fixed error message in modeling.py

  - Corrected ModelingPrimitives.state_transition_bounds() → BoundingPatterns.state_transition_bounds() in error message (flixopt/modeling.py:591)

  2. Fixed Transmission type hint (flixopt/components.py:667)

  - Changed status_parameters: StatusParameters = None → status_parameters: StatusParameters | None = None

  3. Fixed absolute_losses=0 edge case (flixopt/components.py:768)

  - Added np.any(self.element.absolute_losses != 0) check in create_transmission_equation to match the initialization logic
  - This prevents AttributeError when absolute_losses is explicitly set to 0

  4. Updated test assertion messages (tests/test_component.py)

  - Changed "On does not work properly" → "Status does not work properly"

  5. Fixed effects_per_startup type (examples/02_Complex/complex_example.py)

  - Changed scalar effects_per_startup=0.01 → dict effects_per_startup={Costs.label: 0.01} in all 3 occurrences
  - Now consistent with the StatusParameters API which expects a dict mapping effect names to values

  6. Updated test_functional.py docstring

  - Removed reference to non-existent TestStatus class
  - Updated to accurately describe the status-related test functions

  7. Consistent unbounded upper bounds (flixopt/features.py:191)

  - Changed np.inf → None for unbounded active_hours_max
  - Now consistent with FlowModel's total_flow_hours pattern

  All changes maintain backward compatibility and align with the codebase's existing patterns. The documentation in index.md was already correct (BoundingPatterns is
  the right class for state_transition_bounds).
  1. CHANGELOG.md - Fixed parameter rename documentation (lines 89-90)
  - Changed incorrect status_parameters → status_parameters
  - To correct: on_off_parameters → status_parameters

  2. CHANGELOG.md - Removed duplicate logger warning (line 803 in v2.1.0)
  - Removed duplicate entry that was already documented in v2.0.1
  - Fixed v2.0.1 entry to say on_off_parameters (the name at that time)

  3. StatusParameters.md - Aligned flow bounds formulation (line 229)
  - Updated summary to include max(ε, rel_lower) like the main text
  - Now consistent: s(t) · P · max(ε, rel_lower) ≤ p(t) ≤ s(t) · P · rel_upper

  4. features.py - Narrowed previous_status type hint (line 155)
  - Changed from Numeric_TPS | None to xr.DataArray | None
  - Added import xarray as xr (line 12)
  - This accurately reflects that _get_previous_uptime() and _get_previous_downtime() use xarray APIs

All changes are verified to compile correctly and maintain consistency with the codebase patterns!
  1. Constraint naming in tests (tests/test_component.py:126-127, 158, 168,
  338, 348):
    - Updated test expectations from 'TestComponent|on|lb' and
  'TestComponent|on|ub' to 'TestComponent|status|lb' and
  'TestComponent|status|ub' to match the actual constraint names
  2. Added 'off' property to StatusModel (flixopt/features.py:284-287):
    - Added a new property that returns 1 - self.status for backward
  compatibility with tests expecting an off attribute
  3. Fixed deprecated parameter name (tests/test_functional.py:435):
    - Changed force_switch_on=True to force_startup_tracking=True in
  StatusParameters
  4. Fixed property name (tests/test_functional.py:466):
    - Changed switch_off to shutdown to match the actual property name in
  StatusModel
switch_on -> activate
switch_off -> deactivate
switch_on -> activate
switch_off -> deactivate
state_variable -> state
switch_on -> activate
switch_off -> deactivate
state_variable -> state
  ✅ All Parameters Now Documented

  Each primitive now has complete parameter documentation with:
  - Clear description of what each parameter does
  - Type expectations
  - Default values where applicable

  ✅ Focused on Math & Parameters

  Removed:
  - Excessive examples at low level
  - Use case lists that belong at higher levels

  Enhanced:
  - Mathematical formulations (using proper · symbol for multiplication)
  - Clear behavior descriptions
  - Precise return value documentation

  Updated Functions:

  ModelingPrimitives:

  1. expression_tracking_variable
    - All 6 parameters documented
    - Clear math formulation
  2. consecutive_duration_tracking
    - All 9 parameters documented
    - Explained Big-M value
    - Clear what constraints are returned
  3. mutual_exclusivity_constraint
    - All 4 parameters documented
    - Simplified, focused on math

  BoundingPatterns:

  4. basic_bounds
    - All 4 parameters documented
    - Concise formulation
  5. bounds_with_state
    - All 5 parameters documented
    - Explained epsilon (ε) usage
  6. scaled_bounds
    - All 5 parameters documented
    - Clear scaling relationship
  7. scaled_bounds_with_state
    - All 7 parameters documented
    - Explained Big-M formulation
  8. state_transition_bounds
    - All 7 parameters documented
    - Removed verbose examples, kept math focus
  9. continuous_transition_bounds
    - All 8 parameters documented
    - Clear Big-M constraint explanation

  Result

  ✅ All parameters documented
  ✅ Math-focused docstrings
  ✅ Consistent format across all primitives
  ✅ Tests still passing

  The modeling primitives now have professional, complete documentation!
# Conflicts:
#	docs/user-guide/mathematical-notation/features/OnOffParameters.md
#	examples/02_Complex/complex_example.py
#	examples/03_Calculation_types/example_calculation_types.py
#	examples/04_Scenarios/scenario_example.py
#	examples/05_Two-stage-optimization/two_stage_optimization.py
#	flixopt/components.py
#	flixopt/elements.py
#	flixopt/features.py
#	flixopt/flow_system.py
#	flixopt/interface.py
#	flixopt/linear_converters.py
#	tests/conftest.py
#	tests/test_flow.py
#	tests/test_functional.py
#	tests/test_linear_converter.py
#	tests/test_scenarios.py
# Conflicts:
#	flixopt/interface.py
@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 pull request implements a comprehensive terminology rebranding across the codebase, renaming binary on/off state concepts to active/inactive status-based concepts. OnOffParameters becomes StatusParameters, with cascading renames of related fields, variables, methods, and constraints throughout the library, documentation, examples, and tests.

Changes

Cohort / File(s) Summary
Public API Exposure
flixopt/__init__.py
Replaces OnOffParameters export with StatusParameters in public module interface
Core Interface
flixopt/interface.py
Renames OnOffParameters class to StatusParameters; updates all constructor fields (effects_per_switch_on → effects_per_startup, on_hours_min/max → active_hours_min/max, consecutive_on/off_hours → min/max_uptime/downtime, switch_on_max → startup_limit, force_switch_on → force_startup_tracking) and property names (use_switch_on → use_startup_tracking, use_consecutive_on_hours → use_uptime_tracking, use_consecutive_off_hours → use_downtime_tracking)
Feature Models
flixopt/features.py
Renames OnOffModel to StatusModel; updates state variable tracking from on to status, switch_on/switch_off to startup/shutdown, on_hours_total to active_hours, consecutive_on_hours to uptime, consecutive_off_hours to downtime; adds inactive complementary variable; renames public properties and accessors accordingly
Core Element & Component Logic
flixopt/elements.py, flixopt/components.py
Updates Component and Flow class constructors from on_off_parameters to status_parameters; wires StatusModel instead of OnOffModel; updates constraint and accessor names; changes on_off property to status, previous_states to previous_status, with_on_off to with_status
Linear Converters
flixopt/linear_converters.py
Updates Boiler, Power2Heat, HeatPump, CoolingTower, CHP, and HeatPumpWithSource constructors to accept status_parameters instead of on_off_parameters; updates super() calls and docstrings
Modeling Primitives
flixopt/modeling.py
Renames consecutive_duration_tracking parameter from state_variable to state; updates state_transition_bounds, continuous_transition_bounds, bounds_with_state, and scaled_bounds_with_state function parameters (variable_state → state, switch_on/off → activate/deactivate); updates docstrings and constraint terminology
Flow System & Documentation
flixopt/flow_system.py
Updates docstring examples to reference status_parameters and active_hours terminology
Documentation: Features & Patterns
docs/user-guide/mathematical-notation/features/OnOffParameters.md (removed)
docs/user-guide/mathematical-notation/features/StatusParameters.md (added)
docs/user-guide/mathematical-notation/modeling-patterns/state-transitions.md
docs/user-guide/mathematical-notation/modeling-patterns/duration-tracking.md
docs/user-guide/mathematical-notation/modeling-patterns/bounds-and-states.md
Removes OnOffParameters documentation page; adds comprehensive StatusParameters documentation with state variables, startup/shutdown tracking, uptime/downtime constraints; updates modeling patterns to reference new terminology and parameter names
Documentation: Elements
docs/user-guide/mathematical-notation/elements/Flow.md
docs/user-guide/mathematical-notation/elements/Storage.md
Updates Flow documentation to reference StatusParameters instead of OnOffParameters in descriptions and See Also sections; expands Storage API documentation with charge/discharge efficiency and final state bound parameters
Documentation: Core Concepts & Index
docs/user-guide/core-concepts.md
docs/user-guide/mathematical-notation/index.md
docs/user-guide/mathematical-notation/dimensions.md
docs/user-guide/mathematical-notation/effects-penalty-objective.md
docs/user-guide/mathematical-notation/features/InvestParameters.md
docs/user-guide/mathematical-notation/modeling-patterns/index.md
docs/user-guide/recipes/index.md
Updates terminology from on/off to active/inactive status throughout; replaces OnOffParameters references with StatusParameters in indices and tables; adds clarifications in Where sections; minor formatting/editorial improvements
Configuration & Metadata
.github/workflows/test.yaml
CHANGELOG.md
mkdocs.yml
Adds trailing period to workflow comment; documents complete API renaming and migration guidance in changelog; updates navigation link from OnOffParameters.md to StatusParameters.md
Examples
examples/02_Complex/complex_example.py
examples/02_Complex/complex_example_results.py
examples/03_Optimization_modes/example_optimization_modes.py
examples/04_Scenarios/scenario_example.py
examples/05_Two-stage-optimization/two_stage_optimization.py
Updates all component constructors to use status_parameters instead of on_off_parameters; renames parameter fields (effects_per_switch_on → effects_per_startup, on_hours_* → active_hours_, consecutive_on_hours_ → min/max_uptime, consecutive_off_hours_* → min/max_downtime); updates plot references from
Tests: Core & Component
tests/conftest.py
tests/test_component.py
tests/test_flow.py
Updates fixture construction to use StatusParameters; renames all variable and constraint references in test expectations (
Tests: Specialized
tests/test_functional.py
tests/test_linear_converter.py
tests/test_scenarios.py
tests/test_storage.py
Updates functional tests to use status-based parameter structures and updated accessor paths (submodel.on_off → submodel.status); renames constraint/variable references across converter, scenario, and storage tests; updates expected result value paths for startup/shutdown/status tracking

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • flixopt/elements.py: Large-scale wiring updates with multiple state variable renames and constraint logic changes—requires careful verification of all state propagation paths and accessor updates
  • flixopt/features.py: StatusModel implementation with significant variable tracking changes (addition of inactive complementary variable, rename of tracking logic)—needs validation of constraint consistency
  • tests/test_flow.py and tests/test_component.py: Extensive test refactoring with many renamed variables and constraint assertions—verify all expected model outputs match new terminology
  • flixopt/interface.py: Public API surface with numerous field renames and internal transform_data logic updates—ensure backward compatibility is not required (breaking change acknowledged)
  • flixopt/linear_converters.py and flixopt/components.py: Constructor signature changes across multiple classes—confirm all call sites in examples and tests are updated
  • Cross-file consistency: Verify StatusParameters usage is uniform across library, examples, tests, and documentation

Possibly related PRs

Poem

🐰 On/Off be gone, now Status reigns supreme!
Active hours flow like a coding dream,
Startup and shutdown, uptime so bright,
A rabbit hops through the refactored night.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is a template with placeholder text and unchecked checkboxes. It lacks actual implementation details, issue references, and testing information specific to this substantial refactoring PR. Replace placeholder text with concrete details about the refactoring scope, affected components, migration path, and verified test results. Link related issue(s) and confirm all tests pass.
Docstring Coverage ⚠️ Warning Docstring coverage is 74.04% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature/rename on off to status' directly describes the main change - a comprehensive rename of on/off terminology to status terminology throughout the codebase.

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.

@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

Caution

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

⚠️ Outside diff range comments (2)
docs/user-guide/mathematical-notation/effects-penalty-objective.md (1)

157-159: Code example uses deprecated API terminology that no longer exists in the codebase.

Lines 157-159 show fx.OnOffParameters and effects_per_switch_on, which were renamed as breaking changes:

  • OnOffParametersStatusParameters
  • effects_per_switch_oneffects_per_startup

The entire codebase has been migrated to the new terminology (verified across tests, examples, and implementation files). This documentation example will fail at runtime.

-on_off = fx.OnOffParameters(
-    effects_per_switch_on={'Penalty': 1}  # Add bias against switching on this component, without adding costs
+on_off = fx.StatusParameters(
+    effects_per_startup={'Penalty': 1}  # Add bias against startup of this component, without adding costs
 )
flixopt/linear_converters.py (1)

643-672: Based on my verification, I have confirmed that the review comment is accurate and identifies a real issue in the codebase. Here is my rewritten review comment:


Docstring range notation conflicts with exclusive bounds enforcement

check_bounds() enforces exclusive limits (value_arr > lower_bound and < upper_bound), but multiple parameter docstrings use standard range notation that conventionally implies inclusive endpoints:

  • Line 222, 542: "cop...typically 1–20 range" (suggests 1 and 20 are valid, but code enforces 1 < cop < 20)
  • Line 34, 126, 412, 414: "thermal_efficiency factor (0–1 range)" (suggests 0 and 1 are valid, but code enforces 0 < eff < 1)
  • Line 318: "specific_electricity_demand...0.01–0.05 range" (paired with exclusive bounds validation)
  • Line 460: "Total efficiency...should be ≤ 1.0" but code enforces < 1.0 (exclusive)

To align expectations with implementation, either:

  • Allow endpoints by changing > to >= and < to <=, or
  • Tighten docstrings to explicitly state exclusive bounds (e.g., "0–1 (exclusive)" or "COP > 1, < 20")

Note: Some docstrings (e.g., line 261–262, 592) already correctly state "COP should be greater than 1", which aligns with the exclusive check.

🧹 Nitpick comments (12)
flixopt/features.py (3)

149-252: StatusModel core modeling looks coherent; consider a small robustness improvement

The construction of inactive, startup/shutdown, active_hours, and uptime/downtime using the shared primitives and bounding patterns is internally consistent, and the dimension handling (time/period/scenario) appears correct.

One thing to harden: _add_effects later assumes self.startup exists when effects_per_startup is set. If a caller ever configures effects_per_startup without enabling use_startup_tracking, self.startup will be None and self.startup * factor will fail. You could defensively either:

  • implicitly require/enable use_startup_tracking when effects_per_startup is non‑empty, or
  • guard on self.startup is not None when adding those effects.

255-312: Accessor properties are thin wrappers over Submodel storage

active_hours, inactive, startup, shutdown, startup_count, uptime, and downtime all delegate to __getitem__/get, matching how variables are registered in _do_modeling. The “deprecated” note for inactive is a bit confusing given it is still used for downtime tracking; consider clarifying that the property is mainly for backward compatibility while users should prefer 1 - status in custom expressions.


313-328: Previous uptime/downtime helpers mostly align with semantics; docstring nit

The _get_previous_uptime / _get_previous_downtime helpers use ModelingUtilities.compute_consecutive_hours_in_state with complementary encodings and scalar hours_per_step, which is consistent with how consecutive_duration_tracking expects previous_duration.

Minor nit: _get_previous_uptime’s docstring (“Previously inactive by default, for one timestep”) doesn’t match the implementation (return 0 when no previous status, i.e., zero prior active duration). You may want to reword the docstring to avoid confusion.

flixopt/modeling.py (1)

245-352: consecutive_duration_tracking docs improved; consider fixing the return annotation

The updated docstring correctly explains the active-state duration logic, Big‑M construction, and the contents of the constraints dict. The implementation still returns (variables_dict, constraints_dict), but the return type is annotated as tuple[linopy.Variable, tuple[...]], which is now misleading.

If you rely on static typing, it would be good to update the annotation to reflect the actual (dict[str, linopy.Variable], dict[str, linopy.Constraint]) structure.

docs/user-guide/mathematical-notation/index.md (1)

59-62: Align feature label wording with status-based terminology

The Features Cross-Reference table still uses the older “On/off operation” label, while the surrounding docs and PR intent use “binary active/inactive status”.

To keep terminology consistent, consider updating that row:

-| **On/off operation** | [StatusParameters](features/StatusParameters.md) | [`StatusParameters`][flixopt.interface.StatusParameters] |
+| **Binary active/inactive operation** | [StatusParameters](features/StatusParameters.md) | [`StatusParameters`][flixopt.interface.StatusParameters] |

The status_parameters mention in the user API paragraph and the Python Class Lookup entry otherwise look correct.

Also applies to: 100-100, 122-122

docs/user-guide/mathematical-notation/features/StatusParameters.md (1)

125-127: Clarify parameter names and tighten wording in StatusParameters doc

The formulation and examples look solid; a couple of small wording tweaks would improve clarity:

  1. Min‑uptime behavior bullet

Current text:

- When shutting down at time $t$: enforces equipment was on for at least $h^\text{uptime}_\text{min}$ prior to the switch

To avoid the “prior to” wording and keep it simple:

-- When shutting down at time $t$: enforces equipment was on for at least $h^\text{uptime}_\text{min}$ prior to the switch
+- When shutting down at time $t$: enforces equipment was on for at least $h^\text{uptime}_\text{min}$ before the switch
  1. Time series boundary note

The current phrasing:

**Time Series Boundary:** The final time period constraints for min_uptime/max and min_downtime/max are not enforced ...

can be misread and doesn’t match the parameter names. Consider:

-**Time Series Boundary:** The final time period constraints for min_uptime/max and min_downtime/max are not enforced at the end of the planning horizon.
+**Time Series Boundary:** The final time period constraints for `min_uptime`/`max_uptime` and `min_downtime`/`max_downtime` are not enforced at the end of the planning horizon.

This makes the mapping to the actual StatusParameters arguments unambiguous.

Also applies to: 317-317

tests/test_component.py (1)

72-177: Status-based component tests look consistent with the new model

The component tests now:

  • Construct components/flows with status_parameters=fx.StatusParameters(...).
  • Expect per-flow and component-level variables named ...|status and ...|active_hours.
  • Assert that flow bounds are correctly scaled by corresponding status binaries.
  • Check initial uptime behavior via TestComponent|uptime|initial in the parameterized previous-state test.

These updates align with the StatusParameters design and preserve the original structural coverage.

As a low-priority clean-up, you might eventually want to rename the test methods and parameters from test_on_* / previous_on_hours to test_status_* / previous_active_hours for consistency with the new terminology, but the current naming doesn’t affect correctness.

Also applies to: 178-238, 239-417

CHANGELOG.md (1)

149-151: Clarify: These removals are from a previous version, not this PR.

The "Removed" section at Lines 149-151 references OnOffParameters with old deprecated names (on_hours_total_min, on_hours_total_max, switch_on_total_max). This appears to document removals from v4.0.0 deprecations, but since OnOffParameters is being renamed to StatusParameters in this PR, this entry may cause confusion.

Consider either:

  1. Updating these references to use StatusParameters with a note about the class rename, or
  2. Adding a clarifying note that these were the deprecated names in the old OnOffParameters class (now StatusParameters)
examples/02_Complex/complex_example.py (1)

50-50: Minor terminology inconsistency in comment.

The comment says "on-inactive parameters" but the new terminology is "status parameters" representing "active/inactive" states. Consider updating to:

-    # A gas boiler that converts fuel into thermal output, with investment and on-inactive parameters
+    # A gas boiler that converts fuel into thermal output, with investment and status parameters
tests/conftest.py (1)

125-180: Fixture StatusParameters use may create more binaries than necessary

Several fixtures (e.g., Converters.Boilers.complex, Converters.CHPs.base, Converters.LinearConverters.*, long-system boiler/CHP in flow_system_long) attach StatusParameters both at the component level and on individual Flow objects. This is functionally fine but multiplies the number of status binaries and related constraints, which can slow MIP solves for larger systems.

If these tests don’t rely on both flow-level and component-level status behavior simultaneously, consider simplifying to a single StatusParameters attachment point (either on the key flow or on the component) to keep the fixture systems lighter.

Also applies to: 181-207, 209-253, 596-615

flixopt/interface.py (1)

1008-1260: StatusParameters API looks coherent; only minor doc polish possible

The class definition, transform_data, and the tracking properties align well with how StatusParameters is consumed in flows/components and tests (startup, active-hour, uptime/downtime, and startup_limit behavior).

Two small doc nits you may want to adjust later:

  • startup_limit description ends with a double period (per period..).
  • The docstring emphasizes dicts for effects_per_startup / effects_per_active_hour, while the type hints also allow numeric/time-series. If scalar/array inputs are intentionally supported, mentioning that explicitly would make the API clearer.
tests/test_flow.py (1)

518-1070: Status-related flow tests are thorough; consider future extensibility of name-based checks

The updated tests around status_parameters (status/active_hours, uptime/downtime, startup_limit, effects_per_active_hour, active_hours_min/max, and the invest+status combinations) exercise the new StatusModel wiring in detail and look consistent with the modeling logic in FlowModel and StatusParameters.

One thing to keep in mind long-term: many assertions compare set(flow.submodel.variables) / set(flow.submodel.constraints) to exact hard-coded sets. That’s excellent for locking down the current formulation, but it will force test updates for any future enhancement that adds auxiliary status-related constraints or variables. If you later extend StatusModel, you may want to relax some checks to require a superset (or at least focus on the most important names) instead of strict equality.

Also applies to: 1076-1273

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e09f46 and b692ef4.

📒 Files selected for processing (37)
  • .github/workflows/test.yaml (1 hunks)
  • CHANGELOG.md (1 hunks)
  • docs/user-guide/core-concepts.md (1 hunks)
  • docs/user-guide/mathematical-notation/dimensions.md (1 hunks)
  • docs/user-guide/mathematical-notation/effects-penalty-objective.md (4 hunks)
  • docs/user-guide/mathematical-notation/elements/Flow.md (3 hunks)
  • docs/user-guide/mathematical-notation/elements/Storage.md (2 hunks)
  • docs/user-guide/mathematical-notation/features/InvestParameters.md (8 hunks)
  • docs/user-guide/mathematical-notation/features/OnOffParameters.md (0 hunks)
  • docs/user-guide/mathematical-notation/features/StatusParameters.md (1 hunks)
  • docs/user-guide/mathematical-notation/index.md (3 hunks)
  • docs/user-guide/mathematical-notation/modeling-patterns/bounds-and-states.md (9 hunks)
  • docs/user-guide/mathematical-notation/modeling-patterns/duration-tracking.md (8 hunks)
  • docs/user-guide/mathematical-notation/modeling-patterns/index.md (2 hunks)
  • docs/user-guide/mathematical-notation/modeling-patterns/state-transitions.md (10 hunks)
  • docs/user-guide/recipes/index.md (1 hunks)
  • examples/02_Complex/complex_example.py (4 hunks)
  • examples/02_Complex/complex_example_results.py (1 hunks)
  • examples/03_Optimization_modes/example_optimization_modes.py (2 hunks)
  • examples/04_Scenarios/scenario_example.py (2 hunks)
  • examples/05_Two-stage-optimization/two_stage_optimization.py (1 hunks)
  • flixopt/__init__.py (2 hunks)
  • flixopt/components.py (13 hunks)
  • flixopt/elements.py (25 hunks)
  • flixopt/features.py (3 hunks)
  • flixopt/flow_system.py (2 hunks)
  • flixopt/interface.py (5 hunks)
  • flixopt/linear_converters.py (25 hunks)
  • flixopt/modeling.py (17 hunks)
  • mkdocs.yml (1 hunks)
  • tests/conftest.py (8 hunks)
  • tests/test_component.py (16 hunks)
  • tests/test_flow.py (20 hunks)
  • tests/test_functional.py (19 hunks)
  • tests/test_linear_converter.py (7 hunks)
  • tests/test_scenarios.py (3 hunks)
  • tests/test_storage.py (2 hunks)
💤 Files with no reviewable changes (1)
  • docs/user-guide/mathematical-notation/features/OnOffParameters.md
🧰 Additional context used
🧬 Code graph analysis (14)
flixopt/__init__.py (1)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
examples/03_Optimization_modes/example_optimization_modes.py (1)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
tests/test_storage.py (2)
flixopt/results.py (2)
  • variables (332-336)
  • variables (1168-1176)
flixopt/structure.py (1)
  • variables (1499-1505)
tests/test_functional.py (2)
flixopt/elements.py (2)
  • Flow (310-597)
  • status (828-832)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
examples/04_Scenarios/scenario_example.py (1)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
flixopt/interface.py (1)
flixopt/structure.py (4)
  • Interface (279-956)
  • transform_data (297-311)
  • _fit_effect_coords (364-382)
  • _fit_coords (349-362)
tests/test_component.py (3)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
tests/conftest.py (2)
  • assert_var_equal (753-787)
  • assert_conequal (734-750)
flixopt/elements.py (1)
  • status (828-832)
tests/test_flow.py (1)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
flixopt/components.py (2)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
flixopt/elements.py (1)
  • status (828-832)
tests/test_linear_converter.py (5)
flixopt/results.py (6)
  • flow_system (353-372)
  • size (2002-2010)
  • variables (332-336)
  • variables (1168-1176)
  • constraints (339-343)
  • constraints (1179-1187)
flixopt/structure.py (5)
  • flow_system (329-347)
  • variables (1499-1505)
  • constraints (1490-1496)
  • hours_per_step (184-185)
  • hours_per_step (1531-1532)
flixopt/elements.py (1)
  • Flow (310-597)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
flixopt/components.py (1)
  • LinearConverter (30-245)
flixopt/elements.py (2)
flixopt/features.py (2)
  • StatusModel (149-327)
  • size (137-139)
flixopt/interface.py (7)
  • StatusParameters (1009-1261)
  • transform_data (77-80)
  • transform_data (229-231)
  • transform_data (461-463)
  • transform_data (680-683)
  • transform_data (908-965)
  • transform_data (1214-1237)
flixopt/linear_converters.py (1)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
tests/conftest.py (2)
flixopt/interface.py (1)
  • StatusParameters (1009-1261)
flixopt/linear_converters.py (9)
  • CHP (401-527)
  • thermal_efficiency (105-106)
  • thermal_efficiency (109-111)
  • thermal_efficiency (201-202)
  • thermal_efficiency (205-207)
  • thermal_efficiency (512-513)
  • thermal_efficiency (516-518)
  • electrical_efficiency (521-522)
  • electrical_efficiency (525-527)
flixopt/modeling.py (2)
flixopt/structure.py (3)
  • constraints (1490-1496)
  • add_constraints (1397-1406)
  • Submodel (1362-1541)
flixopt/config.py (1)
  • Modeling (508-519)
🪛 LanguageTool
docs/user-guide/mathematical-notation/features/StatusParameters.md

[style] ~126-~126: ‘prior to’ might be wordy. Consider a shorter alternative.
Context: ...r at least $h^\text{uptime}_\text{min}$ prior to the switch - Prevents short cycling and...

(EN_WORDINESS_PREMIUM_PRIOR_TO)

🔇 Additional comments (59)
docs/user-guide/mathematical-notation/dimensions.md (1)

100-106: Terminology update is consistent

The new “binary states (active/inactive)” wording matches the status terminology elsewhere; no technical impact.

docs/user-guide/recipes/index.md (1)

25-32: Recipe title rename looks good

Renaming the topic to “Status Constraints” aligns with the new status/active‑inactive vocabulary.

.github/workflows/test.yaml (1)

3-10: No behavioral change in workflow

Only the inline comment on workflow_call was tweaked; YAML structure and triggers remain unchanged.

flixopt/features.py (1)

26-83: InvestmentModel change is consistent with state-based bounds

Using BoundingPatterns.bounds_with_state with state=self._variables['invested'] matches the intent that size is zero when not invested and bounded when invested. No issues seen.

flixopt/modeling.py (10)

54-81: Binary-state counting docs now match behavior

The updated count_consecutive_states docstring correctly describes counting the final consecutive “active” period and treating the final “inactive” state as zero. Implementation remains unchanged and consistent.


118-177: Status-oriented utilities documentation is consistent

compute_consecutive_hours_in_state and compute_previous_off_duration now use “active/inactive” wording, matching how they are consumed by the new status logic (uptime/downtime). The behavior (using to_binary and complementing for “off”) is unchanged and still correct.


199-243: expression_tracking_variable type and docs are clearer

Allowing tracked_expression: linopy.expressions.LinearExpression | linopy.Variable and clarifying the “tracker = expression, optional bounds” behavior matches how it’s used (e.g., for active_hours). No functional change, and usage in StatusModel is valid.


355-395: mutual_exclusivity_constraint documentation now matches the math

The new docstring cleanly states the at‑most‑one‑active semantics (Σ binary_vars ≤ tolerance) and keeps the existing binary checks and single-constraint implementation. Looks good.


401-432: basic_bounds docstring matches implementation

The clarified description of lower/upper bounds and the returned [lower_constraint, upper_constraint] list lines up with the current implementation. No behavior change.


434-477: bounds_with_state behavior remains correct under new naming

The “force to 0 when state=0, enforce [lower, upper] when state=1” semantics are clearly documented and still correctly implemented via the Big‑M style constraints and epsilon floor. The change to the state argument name is consistent with the status terminology.


479-515: scaled_bounds documentation aligned with usage

The updated docstring clearly frames relative_bounds as factors relative to the scaling variable and matches the implementation. No issues spotted.


518-572: scaled_bounds_with_state docs and math are consistent

The new description of state, M_misc, and the Big‑M upper/lower bounds matches the actual constraints being added. The four returned constraints (lb2, ub2, ub1, lb1) are still in the documented order.


575-626: state_transition_bounds wording matches existing constraints

The updated “active/inactive, activate/deactivate” terminology matches how these binaries are used in StatusModel. The three constraints (transition, initial, mutex) and their formulas remain unchanged and correct.


629-695: continuous_transition_bounds docstring now accurately describes behavior

The clarified behavior (“only change when transitions occur, within ±max_change”) matches the current Big‑M constraints on the continuous variable. No functional changes; math remains sound.

docs/user-guide/core-concepts.md (1)

27-33: Flow constraints wording matches StatusParameters

Describing constraints as covering “min/max, total flow hours, active/inactive status” ties in well with the new status model; no technical concerns.

flixopt/flow_system.py (2)

48-56: Docstring update for hours_of_previous_timesteps is accurate

Referencing uptime/downtime as a key consumer of hours_of_previous_timesteps reflects how it feeds the status tracking logic; no behavioral changes.


73-83: Example updated to use status_parameters

Switching the example to status_parameters=... is consistent with the new StatusModel/StatusParameters API elsewhere in the PR.

mkdocs.yml (1)

21-29: MkDocs nav correctly points to StatusParameters

The feature link under Mathematical Notation now targets StatusParameters.md, which matches the new feature name and avoids dangling references.

docs/user-guide/mathematical-notation/features/InvestParameters.md (1)

18-18: LGTM! Documentation clarity improvements.

The addition of "With:" subsections explicitly defining variables used in the equations improves documentation readability and follows best practices for mathematical notation.

Also applies to: 38-38, 85-85, 105-105, 130-130, 154-154, 219-219, 236-236

tests/test_storage.py (1)

410-426: LGTM! Variable naming updated consistently.

The test correctly updates binary variable references from |on to |status, aligning with the broader terminology shift from OnOffParameters to StatusParameters. The test logic remains sound, and assertions properly verify the prevent_simultaneous_charge_and_discharge functionality.

examples/02_Complex/complex_example_results.py (1)

32-33: LGTM! Example updated for new variable naming.

The plot variable references correctly updated from |on to |status, ensuring examples remain functional with the renamed API.

docs/user-guide/mathematical-notation/modeling-patterns/index.md (1)

20-20: LGTM! Documentation terminology updated consistently.

The updates from "on/off" to "active/inactive" and OnOffParameters to StatusParameters maintain consistency with the API changes and improve conceptual clarity.

Also applies to: 46-46

docs/user-guide/mathematical-notation/elements/Storage.md (1)

56-71: LGTM! Documentation completeness improved.

The addition of previously undocumented parameters (minimal_final_charge_state, maximal_final_charge_state, eta_charge, eta_discharge) and the reference to the "Bounds with State" pattern improve the documentation's completeness and usability.

docs/user-guide/mathematical-notation/modeling-patterns/bounds-and-states.md (1)

14-17: LGTM! Documentation improvements and terminology updates.

The addition of "With:" subsections for variable definitions and the consistent update from "on/off" to "active/inactive" terminology enhance documentation clarity and align with the StatusParameters API changes.

Also applies to: 29-29, 36-41, 50-51, 64-68, 84-84, 95-103, 114-115, 134-137, 157-160

docs/user-guide/mathematical-notation/modeling-patterns/duration-tracking.md (1)

18-21: LGTM! Documentation updated for new parameter naming.

The code examples correctly update the parameter name from state_variable to state, and documentation references are updated from OnOffParameters to StatusParameters with corresponding active/inactive terminology. These changes maintain consistency with the API rename.

Also applies to: 42-44, 61-63, 95-96, 123-126, 136-138, 150-153, 161-162

flixopt/__init__.py (1)

34-34: Perfect! I now have enough information to verify this review comment. Let me check one more thing about the documentation reference to ensure completeness:
<function_calls>

#!/bin/bash

Check the stale documentation reference

echo "=== Stale documentation reference ==="
rg -n -B3 -A3 "OnOffParameters" docs/user-guide/mathematical-notation/effects-penalty-objective.md


</function_calls>

#!/bin/bash
# Verify if this documentation file needs updating
echo "=== Check when this documentation was last modified ==="
git log --oneline -n 5 -- docs/user-guide/mathematical-notation/effects-penalty-objective.md 2>/dev/null || echo "No git history"

echo ""
echo "=== Check if there's a corresponding StatusParameters documentation ==="
find docs -name "*StatusParameters*" -o -name "*status*parameter*" 2>/dev/null | grep -v ".git"
</parameter>
</invoke>
</function_calls>

```shell
#!/bin/bash
# Final verification: Check the full picture
echo "=== Verify backwards compatibility classes handling ==="
rg -n "AggregationParameters|OnOffParameters" flixopt/__init__.py

echo ""
echo "=== Compare with how deprecated classes are handled ==="
sed -n '18,20p' flixopt/__init__.py
sed -n '58,70p' flixopt/__init__.py
examples/04_Scenarios/scenario_example.py (1)

120-127: StatusParameters usage in scenario example is consistent

Switching from on_off_parameters=fx.OnOffParameters() to status_parameters=fx.StatusParameters() on the Boiler thermal flow and CHP electrical flow matches the new API and keeps the intended binary-operation behavior. No issues from this change.

Also applies to: 137-139

docs/user-guide/mathematical-notation/elements/Flow.md (1)

26-28: Flow–StatusParameters documentation is coherent

The added references to StatusParameters (extension text, modeling pattern bullet, key parameter, and See Also) are consistent with the new binary active/inactive feature and match the StatusParameters API. No changes needed here.

Also applies to: 36-38, 48-53, 60-60

docs/user-guide/mathematical-notation/modeling-patterns/state-transitions.md (1)

13-15: State transition pattern text aligns with StatusParameters

The refreshed wording (startup/shutdown behavior, mutual exclusivity, and the “Used In → StatusParameters” reference) is consistent with the equations and with the new status-based terminology. I don’t see issues in these updated sections.

Also applies to: 29-33, 51-52, 86-91, 117-118, 139-141, 153-154, 183-185, 200-201, 214-214, 232-233

examples/03_Optimization_modes/example_optimization_modes.py (1)

83-96: StatusParameters usage in optimization-modes example is correct

The Boiler and CHP now use status_parameters=fx.StatusParameters(...) with effects_per_startup fields, which matches the new API and preserves the intended startup-cost behavior from the old OnOffParameters examples.

Also applies to: 99-107

tests/test_component.py (1)

448-452: Transmission status assertions match the new StatusParameters interface

The transmission tests now validate:

  • transmission.in1.submodel.status.status.solution.values instead of an OnOff-specific attribute.
  • That the status pattern (always on vs. partially on) matches expectations, with updated messages (“Status does not work properly”).

This correctly exercises the new status submodel without changing the underlying transmission behavior checks.

Also applies to: 513-516, 593-597

examples/05_Two-stage-optimization/two_stage_optimization.py (1)

48-61: Two-stage example correctly migrated to StatusParameters

The Kessel and BHKW2 configurations now use status_parameters=fx.StatusParameters(...) with:

  • effects_per_startup replacing effects_per_switch_on.
  • min_uptime / min_downtime replacing consecutive on/off hour minima.

This is consistent with the new StatusParameters API and preserves the earlier operational semantics.

Also applies to: 63-79

tests/test_linear_converter.py (3)

137-192: LGTM! Test correctly updated for StatusParameters terminology.

The test properly:

  • Uses fx.StatusParameters with new parameter names (active_hours_min, active_hours_max, effects_per_active_hour)
  • Asserts correct variable names (Converter|status, Converter|active_hours)
  • Verifies constraint naming (Converter|active_hours, Converter->costs(temporal))
  • Validates the status-based calculation logic

374-374: Comment updated to reflect status terminology.

The comment correctly notes "If there's no status parameter" instead of the previous on/off terminology.


381-497: LGTM! Piecewise conversion test properly updated for StatusParameters.

The test correctly:

  • Renamed to test_piecewise_conversion_with_status
  • Uses fx.StatusParameters with appropriate new parameter names
  • Verifies Converter|status variable is created and used as zero_point
  • Validates the single_segment constraint uses model.variables['Converter|status'] (Line 481)
  • Checks Converter|active_hours constraint with correct status-based calculation (Lines 485-489)
  • Verifies cost effects use status variable (Lines 495-496)
tests/test_scenarios.py (2)

143-173: LGTM! Boiler configuration correctly updated to StatusParameters.

The configuration properly uses:

  • status_parameters=fx.StatusParameters(effects_per_active_hour=...) at component level
  • Nested status_parameters in thermal_flow with all renamed fields:
    • active_hours_min/max (was on_hours_total_min/max)
    • max_uptime/min_uptime (was consecutive_on_hours_max/min)
    • max_downtime (was consecutive_off_hours_max)
    • effects_per_startup (was effects_per_switch_on)
    • startup_limit (was switch_on_total_max)

234-234: LGTM! LinearConverter correctly uses StatusParameters.

The effects_per_startup parameter is correctly used with the new fx.StatusParameters class.

CHANGELOG.md (1)

54-123: Excellent changelog documentation for the breaking change.

The changelog entry is comprehensive and well-structured:

  • Clear summary of the terminology change
  • Detailed migration tables for all renamed entities
  • Explicit note that this is a clean breaking change with no backwards compatibility wrapper
  • Find-and-replace guidance for users
examples/02_Complex/complex_example.py (1)

51-116: LGTM! Example correctly demonstrates StatusParameters usage.

The example properly showcases:

  • Component-level status_parameters with effects_per_active_hour (Lines 54-56)
  • Flow-level status_parameters with comprehensive constraints (Lines 72-80):
    • active_hours_min/max for total operating hours
    • max_uptime/min_uptime for consecutive operation
    • max_downtime for consecutive downtime
    • effects_per_startup for startup costs
    • startup_limit for maximum starts
  • CHP units with effects_per_startup (Lines 91, 115)

This serves as good documentation for users migrating to the new API.

tests/test_functional.py (8)

6-17: LGTM! Module docstring properly updated for status terminology.

The docstring correctly describes tests for "status operational constraints" and lists the renamed test functions (test_startup_shutdown, test_consecutive_uptime_downtime).


333-369: LGTM! test_on correctly updated to use StatusParameters.

The test properly:

  • Uses fx.StatusParameters() instead of fx.OnOffParameters()
  • Accesses solution via submodel.status.status.solution.values (Line 357)

372-420: LGTM! test_off correctly updated for StatusParameters.

The test properly:

  • Uses fx.StatusParameters(max_downtime=100) with new parameter name
  • Accesses status.status and status.inactive solution values correctly (Lines 401, 408-409)

423-478: LGTM! Test renamed and updated for startup/shutdown terminology.

The test correctly:

  • Renamed from test_switch_on_off to test_startup_shutdown
  • Uses force_startup_tracking=True (was force_switch_on=True)
  • Accesses status.startup and status.shutdown solution values (Lines 459, 466)

Minor note: Error messages at Lines 463 and 470 still reference old variable names ("Boiler__Q_th__switch_on"). Consider updating for consistency, though this doesn't affect test functionality.


481-528: LGTM! test_on_total_max correctly uses active_hours_max.

The test properly uses fx.StatusParameters(active_hours_max=1) and accesses status.status.solution.values.


531-602: LGTM! test_on_total_bounds correctly uses active_hours_min/max.

The test properly uses:

  • fx.StatusParameters(active_hours_max=2) for the first boiler
  • fx.StatusParameters(active_hours_min=3) for the backup boiler

605-663: LGTM! Test renamed and updated for uptime/downtime terminology.

The test correctly:

  • Renamed from test_consecutive_on_off to test_consecutive_uptime_downtime
  • Uses max_uptime=2, min_uptime=2 (was consecutive_on_hours_max/min)
  • Accesses solution via correct paths

666-733: LGTM! test_consecutive_off correctly uses downtime parameters.

The test properly uses fx.StatusParameters(max_downtime=2, min_downtime=2) and accesses status.status and status.inactive solution values.

flixopt/components.py (2)

552-688: Transmission absolute_losses correctly wired to flow status

The updated Transmission/TransmissionModel logic looks consistent:

  • status_parameters is now a first-class ctor argument and passed into the base Component.
  • When absolute_losses is nonzero, TransmissionModel.__init__ ensures each participating flow has flow.status_parameters = StatusParameters() if none was provided, so in_flow.submodel.status.status is always available.
  • create_transmission_equation then gates absolute losses with that binary (out + status * absolute_losses = in * (1 - rel_losses)), which matches the documented “absolute losses create binary active/inactive variables” behavior.

This keeps the API flexible (users can still supply explicit status_parameters on flows or the Transmission) while guaranteeing correctness when absolute losses are used.

Also applies to: 736-777


781-826: LinearConverter piecewise zero_point now correctly uses component status

Using zero_point=self.status.status if self.status is not None else False in LinearConverterModel’s piecewise branch keeps the previous on/off semantics but with the new status model:

  • When the converter has component-level status_parameters, the piecewise conversion is anchored to that status binary.
  • When only flow-level status is used (and no component-level StatusParameters), self.status remains None, so the piecewise model sees a constant False zero point and relies on per-flow status constraints instead—identical to the prior behavior.

No changes needed from a modeling or API perspective.

flixopt/elements.py (3)

89-129: StatusParameters plumbing through Component and Flow is consistent

The way status_parameters is threaded now looks solid:

  • Component accepts an optional status_parameters, stores it, and propagates its flow_system plus coordinate transformation via _set_flow_system and transform_data.
  • Flow stores its own optional status_parameters, propagates the flow_system reference, and calls transform_data on it after fitting its own numeric fields.
  • This ensures both component-level and flow-level StatusParameters share the same coordinate system and can be modeled independently or together as needed.

No changes needed here.

Also applies to: 309-346, 448-483, 507-545


547-573: FlowModel status/investment gating and previous_status handling look correct

The updated FlowModel logic for status is coherent:

  • _constraint_flow_rate cleanly separates four cases (no status/no investment, status only, investment only, both), delegating bounds to the appropriate BoundingPatterns helper and always using the binary status variable when present.
  • absolute_flow_rate_bounds now forces lb=0 whenever with_status is true, which is essential to allow true on/off switching; the actual min-flow behavior is then enforced via bounds_with_state / scaled_bounds_with_state using the status binary.
  • _create_status_model passes previous_status derived from previous_flow_rate through ModelingUtilitiesAbstract.to_binary, which is what the uptime/downtime tests rely on for “previously active” behavior.
  • The status property and with_status flag correctly track whether a StatusModel submodel exists for the flow.

This matches the expectations encoded in TestFlowOnModel and the uptime/downtime tests.

Also applies to: 600-633, 669-733, 798-825, 827-833, 847-860


922-983: ComponentModel aggregation of status and previous_status is well-structured

The component-level status logic is consistent with the flow-level status model:

  • If Component.status_parameters is set, flows without explicit status_parameters are given a default StatusParameters(), ensuring every relevant flow has a StatusModel.
  • After creating all FlowModels, the component builds a binary status variable and constraints that make it 1 iff any connected flow is active, then wraps that in a StatusModel with the component’s own StatusParameters.
  • previous_status aggregates each flow’s status._previous_status across inputs/outputs, aligns time indices by padding, and ORs them into a single component-level previous status vector.

This matches the intended semantics (“component active if any flow is active”) and provides a sensible previous_status for component-level uptime/downtime constraints.

Also applies to: 992-1010

flixopt/linear_converters.py (7)

15-18: TYPE_CHECKING import updated cleanly to StatusParameters

Using StatusParameters only under TYPE_CHECKING together with postponed annotations keeps runtime imports minimal and correctly reflects the new interface type.


124-133: Power2Heat: status_parameters wiring and docs look correct

The new status_parameters parameter is optional, forwarded correctly to LinearConverter, and the electrode boiler example uses valid StatusParameters fields (min_uptime, effects_per_startup), so the change is consistent with the new terminology.

Also applies to: 150-158, 171-194


220-229: HeatPump: integration with StatusParameters is coherent

Constructor signature, super call, and the geothermal example using min_uptime and effects_per_active_hour all correctly reference StatusParameters and keep the external API shape intact.

Also applies to: 246-254, 266-290


315-324: CoolingTower: status-based constraints hooked up properly

The status_parameters argument is threaded through to LinearConverter, and the example’s StatusParameters usage (min_uptime, effects_per_active_hour) matches the provided interface, without altering existing conversion logic.

Also applies to: 341-349, 363-384


410-421: CHP: status_parameters addition maintains prior behavior

Adding status_parameters to the CHP constructor and forwarding it in the super().__init__ call preserves the previous structure while exposing the new status-based constraints; the industrial CHP example uses valid StatusParameters fields (min_uptime, effects_per_startup, active_hours_max), so the docs remain accurate.

Also applies to: 440-451, 465-495


540-551: HeatPumpWithSource: StatusParameters usage and forwarding are sound

The new status_parameters argument is optional, correctly passed to LinearConverter, and the example’s StatusParameters call (with min_uptime and effects_per_startup) aligns with the central StatusParameters definition.

Also applies to: 569-578, 596-622


32-39: Perfect! I have all the information needed to verify the review comment. Let me complete my findings:

All verification checks passed - review comment is accurate

The code inspection confirms:

  1. LinearConverter accepts status_parameters: Defined at line 165 in flixopt/components.py with signature def __init__(self, label: str, inputs: list[Flow], outputs: list[Flow], status_parameters: StatusParameters | None = None, ...)

  2. Boiler properly forwards the parameter: At line 109 in flixopt/linear_converters.py, super().__init__() is called with status_parameters=status_parameters

  3. Examples are consistent with StatusParameters API:

    • Lines 62-65: Natural gas boiler without status_parameters (valid use)
    • Lines 76-99: Biomass boiler with StatusParameters(min_uptime=4, effects_per_startup={'startup_fuel': 50}) (correct API usage)
  4. No remaining old references in active code: Only CHANGELOG.md and docs contain historical references to OnOffParameters

  1. Return type annotation for consecutive_duration_tracking (flixopt/modeling.py:255):
    - Changed from tuple[linopy.Variable, tuple[linopy.Constraint, linopy.Constraint, linopy.Constraint]]
    - To tuple[dict[str, linopy.Variable], dict[str, linopy.Constraint]] to match the actual return value
  2. Clarified inactive property docstring (flixopt/features.py:284-291):
    - Replaced the confusing "deprecated" note with a clear explanation that:
        - The variable is only created when downtime tracking is enabled
      - Users should prefer 1 - status expression for general use
  3. Fixed _get_previous_uptime docstring (flixopt/features.py:318-322):
    - Clarified that it returns 0 when no previous status is provided (assumes previously inactive)
  4. Fixed _get_previous_downtime docstring (flixopt/features.py:329-333):
    - Clarified that it returns one timestep duration when no previous status is provided (assumes previously inactive)
  5. No action needed for effects_per_startup without use_startup_tracking:
    - Verified that use_startup_tracking already returns True when effects_per_startup has values (line 1258 in interface.py), so this is already
  handled correctly
  6. Test fixes (tests/test_flow.py):
    - Updated three test assertions to use model.hours_per_step.sum('time') as the expected upper bound for active_hours when active_hours_max is
  not specified
@FBumann FBumann merged commit 4af7ee4 into feature/v5 Nov 30, 2025
1 check passed
FBumann added a commit that referenced this pull request Dec 10, 2025
* Perfect! Here's the **final complete renaming table with Option A**:

## Parameters Class (`OnOffParameters` → `StatusParameters`)

| Current Name | Recommended Name | Rationale |
|--------------|------------------|-----------|
| `OnOffParameters` | **`StatusParameters`** | Aligns with PyPSA, clearer semantics |
| `effects_per_switch_on` | **`effects_per_startup`** | Standard UC terminology |
| `effects_per_running_hour` | **`effects_per_active_hour`** | Clear, concise, matches "active" state |
| `on_hours_total_min` | **`active_hours_min`** | Total (not consecutive) active hours |
| `on_hours_total_max` | **`active_hours_max`** | Total (not consecutive) active hours |
| `consecutive_on_hours_min` | **`min_uptime`** | Standard UC term (consecutive) |
| `consecutive_on_hours_max` | **`max_uptime`** | Standard UC term (consecutive) |
| `consecutive_off_hours_min` | **`min_downtime`** | Standard UC term (consecutive) |
| `consecutive_off_hours_max` | **`max_downtime`** | Standard UC term (consecutive) |
| `switch_on_total_max` | **`startup_limit`** | Clearer intent, matches "startup" |
| `force_switch_on` | **`force_startup_tracking`** | More explicit about what is forced |

## Model Class (`OnOffModel` → `StatusModel`)

### Class Name
| Current Name | Recommended Name |
|--------------|------------------|
| `OnOffModel` | **`StatusModel`** |

### Constructor Parameters
| Current Name | Recommended Name | Rationale |
|--------------|------------------|-----------|
| `on_variable` | **`status`** | Aligns with PyPSA and literature |
| `previous_states` | **`previous_status`** | Consistency with status variable |

### Variables (short_name in add_variables/expression_tracking_variable)
| Current Name | Recommended Name | Type | Notes |
|--------------|------------------|------|-------|
| `self.on` | **`self.status`** | Input variable | Main binary state variable |
| `'off'` | **Remove variable** | Binary variable | Replace with expression `1 - status` |
| `'switch\|on'` | **`'startup'`** | Binary variable | Startup event indicator |
| `'switch\|off'` | **`'shutdown'`** | Binary variable | Shutdown event indicator |
| `'switch\|count'` | **`'startup_count'`** | Integer variable | Number of startups |
| `'on_hours_total'` | **`'active_hours'`** | Continuous variable | Total active duration |
| `'consecutive_on_hours'` | **`'uptime'`** | Continuous variable | Consecutive active hours |
| `'consecutive_off_hours'` | **`'downtime'`** | Continuous variable | Consecutive inactive hours |

### Properties
| Current Name | Recommended Name | Returns | Meaning |
|--------------|------------------|---------|---------|
| `on_hours_total` | **`active_hours`** | `linopy.Variable` | Total active hours |
| `off` | **Remove property** | — | Use `1 - status` expression |
| `switch_on` | **`startup`** | `linopy.Variable \| None` | Startup events |
| `switch_off` | **`shutdown`** | `linopy.Variable \| None` | Shutdown events |
| `switch_on_nr` | **`startup_count`** | `linopy.Variable \| None` | Number of startups |
| `consecutive_on_hours` | **`uptime`** | `linopy.Variable \| None` | Consecutive active hours |
| `consecutive_off_hours` | **`downtime`** | `linopy.Variable \| None` | Consecutive inactive hours |

### Internal Methods
| Current Name | Recommended Name |
|--------------|------------------|
| `_get_previous_on_duration()` | **`_get_previous_uptime()`** |
| `_get_previous_off_duration()` | **`_get_previous_downtime()`** |

### Internal Properties/Flags (in parameters)
| Current Name | Recommended Name |
|--------------|------------------|
| `use_off` | **Remove** (use expression instead) |
| `use_switch_on` | **`use_startup_tracking`** |
| `use_consecutive_on_hours` | **`use_uptime_tracking`** |
| `use_consecutive_off_hours` | **`use_downtime_tracking`** |

## Constraint Names (short_name in add_constraints)
| Current Name | Recommended Name |
|--------------|------------------|
| `'complementary'` | **Remove** (no off variable) |
| `'on_hours_total'` | **`'active_hours'`** |
| `'switch\|on'`, `'switch\|off'` | **`'startup'`, `'shutdown'`** |
| `'switch\|count'` | **`'startup_count'`** |
| `'consecutive_on_hours'` | **`'uptime'`** |
| `'consecutive_off_hours'` | **`'downtime'`** |

## Complete Terminology Summary (Option A)

**State:**
- `status` (binary): 1 = active, 0 = inactive

**Events:**
- `startup` (binary): transition from inactive to active
- `shutdown` (binary): transition from active to inactive

**Durations:**
- `active_hours` (continuous): **total** hours in active state across time horizon
- `uptime` (continuous): **consecutive** hours currently active (UC standard)
- `downtime` (continuous): **consecutive** hours currently inactive (UC standard)

**Parameter Bounds:**
- `active_hours_min/max`: limits on **total** active hours
- `min_uptime/max_uptime`: limits on **consecutive** active hours (UC standard)
- `min_downtime/max_downtime`: limits on **consecutive** inactive hours (UC standard)
- `startup_limit`: maximum number of startup events

**Effects:**
- `effects_per_startup`: costs/impacts per startup event
- `effects_per_active_hour`: costs/impacts per active hour

This aligns perfectly with PyPSA and the unit commitment literature! 🎯

* Refactor tests and examples

* Refactor tests and examples

* Update CHANGELOG.md

* Python Docstrings Updated:

  1. interface.py - Module docstring now references "Status decisions"
  2. components.py - Updated all docstrings:
    - status_parameters parameter descriptions
    - Example code updated with new parameter names (effects_per_startup, min_uptime, startup_limit)
    - Fixed incorrect "OnOff feature" docstring to "Investment feature"
    - Updated TODO comment to reference StatusParameters
  3. linear_converters.py - All docstrings updated:
    - Import statement updated to StatusParameters
    - All parameter descriptions updated
    - All example code updated with new terminology
  4. flow_system.py - Updated references from "consecutive_on_hours" to "uptime and downtime" and on_off_parameters to status_parameters
  5. modeling.py - Updated docstring from "switch-on/off variables" to "state transition constraints for binary switching variables"

  Documentation Markdown Files Updated:

  1. Flow.md - All references updated:
    - Links to StatusParameters
    - "on/off state" → "active/inactive state"
    - Parameter names updated
  2. StatusParameters.md (renamed from OnOffParameters.md) - Comprehensive updates:
    - Title changed to "StatusParameters"
    - All terminology updated: on/off → active/inactive
    - Mathematical notation updated: s^on/s^off → s^startup/s^shutdown
    - Duration variables: d^on/d^off → d^uptime/d^downtime
    - Parameter names updated in all examples
    - All Python code examples updated with new API
  3. Other modeling pattern docs - Updated all references to StatusParameters and active/inactive terminology
  4. mkdocs.yml - Navigation updated to reference StatusParameters.md

  All docstrings and documentation now consistently use the new Status terminology aligned with PyPSA and unit commitment standards!

* Update remaining mentions of old parameters

* ⏺ Perfect! I've addressed all the actionable review comments:

  Changes Made:

  1. Fixed error message in modeling.py

  - Corrected ModelingPrimitives.state_transition_bounds() → BoundingPatterns.state_transition_bounds() in error message (flixopt/modeling.py:591)

  2. Fixed Transmission type hint (flixopt/components.py:667)

  - Changed status_parameters: StatusParameters = None → status_parameters: StatusParameters | None = None

  3. Fixed absolute_losses=0 edge case (flixopt/components.py:768)

  - Added np.any(self.element.absolute_losses != 0) check in create_transmission_equation to match the initialization logic
  - This prevents AttributeError when absolute_losses is explicitly set to 0

  4. Updated test assertion messages (tests/test_component.py)

  - Changed "On does not work properly" → "Status does not work properly"

  5. Fixed effects_per_startup type (examples/02_Complex/complex_example.py)

  - Changed scalar effects_per_startup=0.01 → dict effects_per_startup={Costs.label: 0.01} in all 3 occurrences
  - Now consistent with the StatusParameters API which expects a dict mapping effect names to values

  6. Updated test_functional.py docstring

  - Removed reference to non-existent TestStatus class
  - Updated to accurately describe the status-related test functions

  7. Consistent unbounded upper bounds (flixopt/features.py:191)

  - Changed np.inf → None for unbounded active_hours_max
  - Now consistent with FlowModel's total_flow_hours pattern

  All changes maintain backward compatibility and align with the codebase's existing patterns. The documentation in index.md was already correct (BoundingPatterns is
  the right class for state_transition_bounds).

* Changes Made:

  1. CHANGELOG.md - Fixed parameter rename documentation (lines 89-90)
  - Changed incorrect status_parameters → status_parameters
  - To correct: on_off_parameters → status_parameters

  2. CHANGELOG.md - Removed duplicate logger warning (line 803 in v2.1.0)
  - Removed duplicate entry that was already documented in v2.0.1
  - Fixed v2.0.1 entry to say on_off_parameters (the name at that time)

  3. StatusParameters.md - Aligned flow bounds formulation (line 229)
  - Updated summary to include max(ε, rel_lower) like the main text
  - Now consistent: s(t) · P · max(ε, rel_lower) ≤ p(t) ≤ s(t) · P · rel_upper

  4. features.py - Narrowed previous_status type hint (line 155)
  - Changed from Numeric_TPS | None to xr.DataArray | None
  - Added import xarray as xr (line 12)
  - This accurately reflects that _get_previous_uptime() and _get_previous_downtime() use xarray APIs

All changes are verified to compile correctly and maintain consistency with the codebase patterns!

* Fixed Issues

  1. Constraint naming in tests (tests/test_component.py:126-127, 158, 168,
  338, 348):
    - Updated test expectations from 'TestComponent|on|lb' and
  'TestComponent|on|ub' to 'TestComponent|status|lb' and
  'TestComponent|status|ub' to match the actual constraint names
  2. Added 'off' property to StatusModel (flixopt/features.py:284-287):
    - Added a new property that returns 1 - self.status for backward
  compatibility with tests expecting an off attribute
  3. Fixed deprecated parameter name (tests/test_functional.py:435):
    - Changed force_switch_on=True to force_startup_tracking=True in
  StatusParameters
  4. Fixed property name (tests/test_functional.py:466):
    - Changed switch_off to shutdown to match the actual property name in
  StatusModel

* Delete mistakingly added files

* Delete mistakingly added files

* Final touches

* Final touches

* Replace off with inactive

* Rename low level parameetrs as well:
switch_on -> activate
switch_off -> deactivate

* Rename low level parameetrs as well:
switch_on -> activate
switch_off -> deactivate
state_variable -> state

* Rename low level parameetrs as well:
switch_on -> activate
switch_off -> deactivate
state_variable -> state

* Docstring Improvements Summary

  ✅ All Parameters Now Documented

  Each primitive now has complete parameter documentation with:
  - Clear description of what each parameter does
  - Type expectations
  - Default values where applicable

  ✅ Focused on Math & Parameters

  Removed:
  - Excessive examples at low level
  - Use case lists that belong at higher levels

  Enhanced:
  - Mathematical formulations (using proper · symbol for multiplication)
  - Clear behavior descriptions
  - Precise return value documentation

  Updated Functions:

  ModelingPrimitives:

  1. expression_tracking_variable
    - All 6 parameters documented
    - Clear math formulation
  2. consecutive_duration_tracking
    - All 9 parameters documented
    - Explained Big-M value
    - Clear what constraints are returned
  3. mutual_exclusivity_constraint
    - All 4 parameters documented
    - Simplified, focused on math

  BoundingPatterns:

  4. basic_bounds
    - All 4 parameters documented
    - Concise formulation
  5. bounds_with_state
    - All 5 parameters documented
    - Explained epsilon (ε) usage
  6. scaled_bounds
    - All 5 parameters documented
    - Clear scaling relationship
  7. scaled_bounds_with_state
    - All 7 parameters documented
    - Explained Big-M formulation
  8. state_transition_bounds
    - All 7 parameters documented
    - Removed verbose examples, kept math focus
  9. continuous_transition_bounds
    - All 8 parameters documented
    - Clear Big-M constraint explanation

  Result

  ✅ All parameters documented
  ✅ Math-focused docstrings
  ✅ Consistent format across all primitives
  ✅ Tests still passing

  The modeling primitives now have professional, complete documentation!

* Update docs

* Add missing type hints

* Fix bullet points

* Fix bullet points

* Re-apply changes from main

* Bugfix: Usage of old on_off_parameters

* Update CHANGELOG.md

* Update CHANGELOG.md

* Update CHANGELOG.md

* Fix typos

* Improve flagging of wether to create inactive varaible

* Improve default upper bound of active_hours

* Bugfix self._model.hours_per_step.sum('time').item() with scenarios/periods

* Fix test

* FIx names

* pdate the test assertions to expect upper=total_hours instead of upper=inf when active_hours_max is not
  specified

* Empty

* Trigger CI

* Fix test

* Triggger CI

* Summary of Fixes

  1. Return type annotation for consecutive_duration_tracking (flixopt/modeling.py:255):
    - Changed from tuple[linopy.Variable, tuple[linopy.Constraint, linopy.Constraint, linopy.Constraint]]
    - To tuple[dict[str, linopy.Variable], dict[str, linopy.Constraint]] to match the actual return value
  2. Clarified inactive property docstring (flixopt/features.py:284-291):
    - Replaced the confusing "deprecated" note with a clear explanation that:
        - The variable is only created when downtime tracking is enabled
      - Users should prefer 1 - status expression for general use
  3. Fixed _get_previous_uptime docstring (flixopt/features.py:318-322):
    - Clarified that it returns 0 when no previous status is provided (assumes previously inactive)
  4. Fixed _get_previous_downtime docstring (flixopt/features.py:329-333):
    - Clarified that it returns one timestep duration when no previous status is provided (assumes previously inactive)
  5. No action needed for effects_per_startup without use_startup_tracking:
    - Verified that use_startup_tracking already returns True when effects_per_startup has values (line 1258 in interface.py), so this is already
  handled correctly
  6. Test fixes (tests/test_flow.py):
    - Updated three test assertions to use model.hours_per_step.sum('time') as the expected upper bound for active_hours when active_hours_max is
  not specified

* Trigger CI
@coderabbitai coderabbitai bot mentioned this pull request Dec 10, 2025
9 tasks
@coderabbitai coderabbitai bot mentioned this pull request Dec 27, 2025
9 tasks
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