Skip to content

Conversation

@FBumann
Copy link
Member

@FBumann FBumann commented Nov 14, 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

    • transform_data calls simplified to name-prefix only; FlowSystem is propagated via new linkage hooks and internal _fit_coords/_fit_effect_coords helpers. Modeling reordered to create nested submodels first, then constraints/objectives.
  • New Features

    • Interface now exposes FlowSystem linkage (property) and _set_flow_system propagation.
  • Bug Fixes

    • Stronger element registration, system-integrity validation, consolidated logging, and solve() auto-runs modeling when needed.
  • Documentation

    • Expanded docstrings describing modeling order, propagation, and fitting behavior.

@FBumann FBumann marked this pull request as draft November 14, 2025 09:55
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

Walkthrough

Remove FlowSystem parameters from element/model transform_data signatures; add per-element FlowSystem linkage via _set_flow_system/flow_system; centralize coordinate/effect fitting into _fit_coords/_fit_effect_coords; propagate FlowSystem to nested objects and validate system integrity before model creation.

Changes

Cohort / File(s) Summary
Core interface & linkage
flixopt/structure.py
Add Interface.flow_system property, _set_flow_system(), _fit_coords(), _fit_effect_coords(); store Element._flow_system; change Interface.transform_data to transform_data(name_prefix: str='').
FlowSystem orchestration
flixopt/flow_system.py
Call _set_flow_system() when adding elements; change element.transform_data calls to prefix-only; add _validate_system_integrity() and _check_if_element_already_assigned(); run integrity validation after transform.
Elements (Component / Bus / Flow)
flixopt/elements.py
Remove FlowSystem arg from Component.transform_data, Bus.transform_data, Flow.transform_data; add _set_flow_system() propagation; replace external fits with _fit_coords() / _fit_effect_coords() and use prefix-only nested transforms.
Components & conversions
flixopt/components.py
Remove FlowSystem arg from LinearConverter.transform_data, Storage.transform_data, Transmission.transform_data; add _set_flow_system() propagation; change conversion-factor handling to return fitted data via internal helpers and invoke Piecewise transforms with prefixed names.
Interface pieces & params
flixopt/interface.py
Remove FlowSystem from Piece, Piecewise, PiecewiseConversion, PiecewiseEffects, InvestParameters, OnOffParameters transform_data; add _set_flow_system() to each and switch nested transforms to prefix-only with _fit_coords/_fit_effect_coords.
Effects & models
flixopt/effects.py
Change transform_data to prefix-only; replace flow_system fit calls with _fit_effect_coords()/_fit_coords(); reorder _do_modeling to create nested effect submodels and penalty submodel, then attach shares and objective.
Features / piecewise modeling
flixopt/features.py
Change dims typing to Collection[...] where applicable; add docstrings and reorder _do_modeling to create variables/submodels before constraints; explicit PieceModel/PiecewiseModel wiring and validation.
Calculation lifecycle
flixopt/calculation.py
Remove internal _modeled flag; rely on public modeled/model existence; FullCalculation.solve() auto-invokes do_modeling() if needed; fix_sizes uses self.modeled.
Misc / coordination
multiple files (flixopt/*)
Replace direct flow_system.fit_to_model_coords / fit_effects_to_model_coords calls with _fit_coords / _fit_effect_coords wrappers; propagate FlowSystem to nested structures via _set_flow_system; update docstrings and logs.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User
    participant FS as FlowSystem
    participant Reg as Registry (_add_*)
    participant Elem as Element / Interface
    participant Fit as _fit_coords / _fit_effect_coords

    User->>FS: connect_and_transform()
    FS->>Reg: add_elements(...)
    Reg->>Elem: _set_flow_system(FS)
    Elem->>Elem: store self._flow_system

    FS->>Elem: transform_data(name_prefix)
    activate Elem
    Elem->>Fit: _fit_coords(prefix, data) / _fit_effect_coords(prefix, values)
    activate Fit
    Fit->>FS: delegate to FlowSystem.fit_to_model_coords / fit_effects_to_model_coords
    FS-->>Fit: fitted data
    Fit-->>Elem: return fitted data
    deactivate Fit
    Elem-->>FS: transformed data stored
    deactivate Elem

    FS->>FS: _validate_system_integrity()
    FS-->>User: ready for create_model / solve
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review focus:
    • Ensure _set_flow_system() is invoked for all element-addition paths and propagated to nested subcomponents (Piece, Piecewise*, InvestParameters, OnOffParameters, etc.).
    • Verify all transform_data call sites updated to the new signature and prefix naming conventions.
    • Confirm _fit_coords() / _fit_effect_coords() delegate correctly to FlowSystem and preserve dims/time semantics.
    • Validate _validate_system_integrity() checks (flows → buses, uniqueness) and that it runs at appropriate times before model creation.
    • Inspect reordering in _do_modeling across models (effects, piecewise) for possible ordering or dependency issues.

Possibly related PRs

Poem

🐇 I hop through code, attach each piece with care,
Prefixes tidy, coords fitted fair.
Systems link up, submodels nest and play,
I nibble glitches, then commit away.
🍃

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses the template but provides only placeholders and generic checkbox selections without substantive details about the refactoring changes. Replace placeholder text with actual description of changes: detail the refactoring objective (e.g., simplifying transform_data signatures), affected components, and testing performed. Specify which tests pass and what testing was conducted.
Docstring Coverage ⚠️ Warning Docstring coverage is 48.96% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feature/simplify structure' is vague and generic, using non-descriptive terms that don't convey meaningful information about the actual changes. Revise the title to be more specific. Consider: 'Refactor transform_data API to remove FlowSystem parameter and add _set_flow_system propagation' or similar that captures the main refactoring scope.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/simplify-structure

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 14, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 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 (1)
flixopt/structure.py (1)

257-290: transform_data API change is correct but breaking; update docs accordingly

Changing Interface.transform_data to accept only name_prefix and rely on an internal flow_system link matches the PR’s direction, but it is a backwards-incompatible public API change. Also, the class docstring still mentions transform_data(flow_system) and should be aligned with the new signature.
Please ensure user-facing docs / release notes call out this change and that any external callers no longer pass a FlowSystem argument.

🧹 Nitpick comments (3)
flixopt/flow_system.py (1)

647-649: System integrity validation is useful but currently limited to flows→buses

Calling _validate_system_integrity() before model construction gives a clearer error path for missing buses and is cheap. Right now it only checks flow.bus in self.buses; consider extending it later (e.g., component/flow consistency, duplicated labels) if you want this to be a central consistency gate.

Also applies to: 782-804

flixopt/structure.py (1)

291-367: FlowSystem linkage helpers are sound; be aware of private-attribute caveat

_set_flow_system plus the flow_system property and _fit_coords / _fit_effect_coords give a clean way to access FlowSystem context from any Interface subclass and its nested children. Because _set_flow_system skips attributes whose names start with _, any nested Interface stored only under a private attribute will not be linked; that’s fine today but worth keeping in mind if future parameter objects are attached via private fields. Initializing _flow_system in Element.__init__ completes the contract.

Also applies to: 936-946

flixopt/interface.py (1)

932-949: Consider consistent argument passing style for _fit_effect_coords().

The calls to _fit_effect_coords() use keyword arguments here (lines 932-949), but Line 1296 in OnOffParameters.transform_data uses positional arguments. While both may work, consistent style improves maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a4d773 and 76a65a7.

📒 Files selected for processing (6)
  • flixopt/components.py (3 hunks)
  • flixopt/effects.py (1 hunks)
  • flixopt/elements.py (3 hunks)
  • flixopt/flow_system.py (3 hunks)
  • flixopt/interface.py (7 hunks)
  • flixopt/structure.py (2 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.13)
  • GitHub Check: test (3.11)
  • GitHub Check: test (3.10)
🔇 Additional comments (15)
flixopt/flow_system.py (2)

597-608: Simplified connect_and_transform call path looks consistent

Using element.transform_data() without a FlowSystem parameter is fine now that elements are linked via _set_flow_system; Component, Bus, Effect, and nested parameter classes all rely on the flow_system property instead.


805-808: FlowSystem linkage via _set_flow_system is wired correctly

Hooking _set_flow_system(self) in _add_effects, _add_components, and _add_buses ensures all Elements (and their nested Interface children) have a valid flow_system reference before transform_data runs, which matches the new design.
Please double-check that all element creation paths (including any legacy helpers or deserialization utilities) go through these _add_* methods so nothing can be transformed without being linked first.

Also applies to: 810-817, 819-824

flixopt/effects.py (1)

343-378: Effect.transform_data correctly uses the new helpers and dims

The refactored transform_data cleanly routes everything through _fit_coords / _fit_effect_coords with sensible prefixes and dimensionality for temporal vs periodic data; the assignment back onto the instance matches downstream expectations in EffectCollectionModel and share handling.

flixopt/elements.py (2)

103-110: Component/Flow transform_data wiring aligns with the new linkage model

Component.transform_data now only prefixes component-level OnOffParameters and lets each Flow handle its own fit via _fit_coords / _fit_effect_coords using label_full, which is sufficient for uniqueness. This slightly changes the generated variable names compared to passing a component prefix into Flow.transform_data, so it’s worth checking any tests or tooling that rely on exact DataArray names, but the optimization logic itself remains consistent.

Also applies to: 471-496


244-248: Bus.transform_data correctly moves penalty fitting behind _fit_coords

Transforming excess_penalty_per_flow_hour through _fit_coords with a prefixed name is consistent with other elements and ensures the penalty series is aligned with the FlowSystem coordinates before modeling.

flixopt/components.py (3)

215-223: LinearConverter.transform_data and conversion-factor normalization look correct

Delegating to Component.transform_data(prefix) and then converting conversion_factors via _transform_conversion_factors() ensures all coefficients are aligned to model coords before LinearConverterModel uses them. Using self.flows[flow].label_full in the fit-name keeps labels unambiguous, and mutating self.conversion_factors to hold DataArrays after transformation is safe given how it’s used later.

Also applies to: 224-237


437-475: Storage.transform_data consistently fits all temporal/periodic parameters

The storage refactor routes all charge-state bounds, efficiencies, losses, initial/final states, and capacity into _fit_coords, with correct handling of the 'lastValueOfSim' sentinel and the InvestParameters vs scalar capacity cases. This matches how StorageModel later constructs _relative_charge_state_bounds and investment constraints.


719-724: Transmission.transform_data correctly prepares loss parameters

Transforming relative_losses and absolute_losses via _fit_coords after the base Component transformation ensures loss series are aligned to the FlowSystem grid before TransmissionModel inspects them (e.g., to decide whether to add on/off binaries) and builds constraints.

flixopt/interface.py (7)

81-84: LGTM!

The refactor cleanly delegates coordinate fitting to the internal helper _fit_coords, removing the explicit FlowSystem parameter dependency.


227-229: LGTM!

The nested transform_data calls correctly propagate only the name_prefix, aligning with the new internal coordination model.


453-455: LGTM!

Consistent with the refactoring pattern across all piecewise classes.


665-668: LGTM!

The refactor maintains consistency across all piecewise effect classes.


1295-1320: LGTM!

The refactor successfully removes the FlowSystem parameter and delegates to internal helpers. The transformation is complete and consistent.


81-81: All callsites of transform_data() have been properly updated.

Verification confirms that no callsite is passing the removed flow_system argument. All 15 identified calls throughout the codebase—in flow_system.py, elements.py, components.py, and interface.py—have been updated to use the new signature with either zero arguments or the single optional name_prefix parameter.


967-982: The review comment is incorrect.

Lines 967-982 access self.flow_system through a property getter that contains defensive checks (structure.py:321-339). The property raises a RuntimeError if _flow_system is not set, with a message to ensure the parent element is registered via flow_system.add_elements() first. Additionally, _set_flow_system recursively sets the flow system reference on nested Interface objects when the parent element is registered. By the time transform_data() is called during FlowSystem iteration through components, effects, and buses, the initialization is guaranteed. Any missing initialization will raise a descriptive error before reaching the code in question.

Likely an incorrect or invalid review comment.

…implementing a two-phase modeling pattern:

  Phase 1 - Variable Creation (_create_variables()):
  - Called during __init__
  - Creates all variables and submodels
  - No constraints allowed (to avoid circular dependencies)

  Phase 2 - Constraint Creation (_create_constraints()):
  - Called from FlowSystemModel.do_modeling() after all models exist
  - Safely accesses variables from child/sibling models
  - Creates all constraints and relationships
@FBumann
Copy link
Member Author

FBumann commented Nov 16, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 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.

@FBumann FBumann marked this pull request as ready for review November 16, 2025 21:12
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 (1)
flixopt/components.py (1)

511-526: Bug: initial capacity bounds computed with swapped min/max.

minimum_initial_capacity should use minimum_capacity; maximum_initial_capacity should use maximum_capacity. Current code reverses them, leading to incorrect plausibility errors.

Apply this fix:

-        minimum_initial_capacity = maximum_capacity * self.relative_minimum_charge_state.isel(time=0)
-        maximum_initial_capacity = minimum_capacity * self.relative_maximum_charge_state.isel(time=0)
+        minimum_initial_capacity = minimum_capacity * self.relative_minimum_charge_state.isel(time=0)
+        maximum_initial_capacity = maximum_capacity * self.relative_maximum_charge_state.isel(time=0)
🧹 Nitpick comments (1)
flixopt/structure.py (1)

328-354: Consider None passthrough in _fit_coords/_fit_effect_coords.

Many callers pass optional values (possibly None). If FlowSystem.fit_* doesn’t handle None, add a fast return to avoid errors:

 def _fit_coords(self, name: str, data, dims=None):
-    return self.flow_system.fit_to_model_coords(name, data, dims=dims)
+    if data is None:
+        return None
+    return self.flow_system.fit_to_model_coords(name, data, dims=dims)
 
 def _fit_effect_coords(self, prefix: str, effect_values, suffix: str = None, dims=None):
-    return self.flow_system.fit_effects_to_model_coords(prefix, effect_values, suffix, dims=dims)
+    if effect_values is None:
+        return None
+    return self.flow_system.fit_effects_to_model_coords(prefix, effect_values, suffix, dims=dims)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22f364b and ded18c8.

📒 Files selected for processing (4)
  • flixopt/components.py (10 hunks)
  • flixopt/elements.py (11 hunks)
  • flixopt/interface.py (7 hunks)
  • flixopt/structure.py (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
flixopt/elements.py (1)
flixopt/structure.py (8)
  • Element (918-966)
  • Interface (258-915)
  • register_class_for_io (45-54)
  • _set_flow_system (292-305)
  • flow_system (308-326)
  • transform_data (276-290)
  • _fit_coords (328-339)
  • _fit_effect_coords (341-353)
flixopt/interface.py (3)
flixopt/components.py (2)
  • _set_flow_system (185-189)
  • _set_flow_system (443-447)
flixopt/elements.py (3)
  • _set_flow_system (103-109)
  • _set_flow_system (252-256)
  • _set_flow_system (485-491)
flixopt/structure.py (6)
  • _fit_coords (328-339)
  • _set_flow_system (292-305)
  • flow_system (308-326)
  • values (1268-1273)
  • values (1555-1556)
  • _fit_effect_coords (341-353)
flixopt/structure.py (3)
flixopt/components.py (5)
  • transform_data (221-228)
  • transform_data (449-486)
  • transform_data (731-735)
  • _set_flow_system (185-189)
  • _set_flow_system (443-447)
flixopt/elements.py (6)
  • transform_data (111-117)
  • transform_data (258-262)
  • transform_data (493-517)
  • _set_flow_system (103-109)
  • _set_flow_system (252-256)
  • _set_flow_system (485-491)
flixopt/interface.py (10)
  • transform_data (81-84)
  • transform_data (233-235)
  • transform_data (465-467)
  • transform_data (684-687)
  • transform_data (956-1013)
  • transform_data (1320-1351)
  • _set_flow_system (227-231)
  • _set_flow_system (459-463)
  • _set_flow_system (677-682)
  • _set_flow_system (950-954)
flixopt/components.py (3)
flixopt/elements.py (7)
  • _set_flow_system (103-109)
  • _set_flow_system (252-256)
  • _set_flow_system (485-491)
  • transform_data (111-117)
  • transform_data (258-262)
  • transform_data (493-517)
  • label_full (559-560)
flixopt/interface.py (18)
  • _set_flow_system (227-231)
  • _set_flow_system (459-463)
  • _set_flow_system (677-682)
  • _set_flow_system (950-954)
  • transform_data (81-84)
  • transform_data (233-235)
  • transform_data (465-467)
  • transform_data (684-687)
  • transform_data (956-1013)
  • transform_data (1320-1351)
  • has_time_dim (203-204)
  • has_time_dim (207-210)
  • has_time_dim (441-442)
  • has_time_dim (445-448)
  • has_time_dim (667-668)
  • has_time_dim (671-675)
  • items (450-457)
  • InvestParameters (691-1107)
flixopt/structure.py (10)
  • _set_flow_system (292-305)
  • flow_system (308-326)
  • transform_data (276-290)
  • label_full (943-944)
  • label_full (1435-1436)
  • values (1268-1273)
  • values (1555-1556)
  • items (1275-1280)
  • items (1549-1550)
  • _fit_coords (328-339)
🔇 Additional comments (33)
flixopt/elements.py (8)

103-110: FlowSystem propagation to nested interfaces/flows — looks good.

Propagation covers on_off_parameters and all connected flows; aligns with new linkage model.


111-118: Confirm intentional omission of name_prefix for Flow.transform_data.

Flows are transformed without the parent prefix. Please confirm this is intentional and consistent with scenario-equality naming (variables end with |flow_rate/|size and rely on element.label_full only).


252-257: Bus: FlowSystem propagation — OK.

Propagation to all connected flows is consistent with Component behavior.


258-263: Bus: penalty fitting via _fit_coords — OK.

Correctly aligns penalty to model coords with prefix; no concerns.


485-492: Flow: propagate FlowSystem to nested params — OK.

Covers on_off_parameters and InvestParameters size; matches Interface contract.


493-518: Flow: coordinate/effect fitting centralization — OK.

Comprehensive use of _fit_coords/_fit_effect_coords and InvestParameters handling looks correct.


592-604: Total flow hours tracking: bounds and coords look correct.

Lower/upper bounds derived from element values, coords set to period/scenario; no issues spotted.


823-837: Bus balance with excess variables — signs are correct.

Adjusting lhs by -(−excess_in + excess_out) yields inputs + excess_in = outputs + excess_out as intended.

flixopt/structure.py (6)

103-109: Model creation order — OK.

Effects first, then components, then buses: consistent with dependencies.


276-289: Interface.transform_data contract update — OK.

Doc reflects prefix-only API and internal FlowSystem access; consistent across modules.


292-306: Internal FlowSystem linkage — OK.

Centralized _set_flow_system is clear and allows explicit propagation downstream.


307-327: Interface.flow_system accessor — good defensive check.

Helpful error if not linked; message guides correct usage.


932-933: Initialize Element._flow_system — OK.

Prepares elements for late linkage; aligns with new access pattern.


1494-1499: Submodel modeling-order doc — OK.

Guidance to create nested submodels before constraints is appropriate.

flixopt/interface.py (7)

81-85: Piece.transform_data via _fit_coords — OK.

Dims toggle via has_time_dim is clear; no issues.


227-232: Piecewise: FlowSystem propagation to Pieces — OK.


233-236: Piecewise: prefixed per-piece transform — OK.


459-468: PiecewiseConversion: propagation + prefixed transform — OK.


950-955: InvestParameters: propagate FlowSystem to PiecewiseEffects — OK.


956-1014: InvestParameters.transform_data — linked_periods guard looks right.

Using flow_system.periods with clear error/warnings; fitting effects and bounds via wrappers is consistent.


1320-1351: OnOffParameters.transform_data — OK.

Effect fitting and scalar bounds aligned to model coords.

flixopt/components.py (12)

185-190: LinearConverter: FlowSystem propagation to PiecewiseConversion — OK.


221-229: LinearConverter.transform_data — OK.

Parent prefixing + conversion factor transform + delegated piecewise conversion looks consistent.


230-243: Conversion factor fitting — OK.

Per-flow, per-equation prefixes ensure unique names; plausible alignment.


443-448: Storage: propagate FlowSystem to InvestParameters — OK.


449-487: Storage.transform_data — OK.

Comprehensive fitting of all temporal/periodic parameters; InvestParameters branch handled.


731-736: Transmission.transform_data — OK.

Loss parameters fitted via helpers; consistent with the new API.


750-752: TransmissionModel: modeling-order doc — OK.


790-795: LinearConverterModel: modeling-order doc — OK.


840-851: StorageModel: variable creation — OK.

charge_state uses extra timestep coords; bounds from helper; no issues.


855-861: StorageModel: netto_discharge constraint — OK.

Constraint matches definition; uses connected flow submodels.


879-897: StorageModel: investment + scaled bounds — OK.

Submodel addition and bounds scaling based on investment size are consistent.


902-907: StorageModel: balanced sizes — OK.

Equality constraint ties investment sizes; conditionally applied.

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 (11)
flixopt/calculation.py (1)

101-101: Consider consolidating modeling state tracking.

The new _modeled flag introduces a second mechanism for tracking modeling state alongside the existing modeled property (lines 172-173). This creates potential inconsistency:

  • Line 209 checks self.modeled (property that tests self.model is not None)
  • Line 233 checks self._modeled (flag set after completion)

These could diverge if do_modeling() fails after setting self.model but before setting self._modeled = True.

Consider updating the modeled property to use this flag instead:

 @property
 def modeled(self) -> bool:
-    return True if self.model is not None else False
+    return self._modeled

This ensures consistent state tracking throughout the class.

flixopt/features.py (3)

339-365: PieceModel dims typing could be tightened

The new explicit inside_piece, lambda0, and lambda1 variables plus the inside_piece == lambda0 + lambda1 constraint look correct. Given that self.dims can be a tuple like ('period', 'scenario'), you might want to adjust the type hint from FlowSystemDimensions | None to something like Collection[FlowSystemDimensions] | None to reflect actual usage and avoid confusing type checkers.


523-626: ShareAllocationModel: constraint wiring is correct; error message could be clearer

The pattern of:

  • initializing total with total == 0,
  • optionally adding total_per_timestep == 0 for time‑resolved models,
  • and adjusting the LHS of these constraints in add_share()

implements total == Σ(non_time_shares) + Σ_t total_per_timestep(t) and total_per_timestep == Σ(time_shares) correctly. The guard against using per‑hour bounds without a time dimension is also good.

Minor nit: the message 'Both max_per_hour and min_per_hour cannot be used when has_time_dim is False' doesn’t quite match the condition (it rejects either being set when 'time' not in dims). Consider updating the message to say “either max_per_hour or min_per_hour” or adjusting the condition if the intent really was “both”.


399-456: PiecewiseModel segment constraints are correct; add clarifying comment on zero_point gate semantics

The segment validation, lambda representation, and piece wiring are sound. The zero-point constraint sum(piece.inside_piece) <= rhs is also correct: it gates segment activation—when rhs=zero_point (a freely created binary), the piecewise is enabled only if zero_point=1, matching test expectations and usage (e.g., gating to on_off.on in components.py).

The existing constraint implementation is functionally correct. However, to clarify design intent for future readers, consider adding a brief comment near line 452–456 explaining that the freely-created zero_point acts as a gate: "When zero_point is enabled (=1), at most one segment is active; when disabled (=0), all segments remain inactive, effectively disabling the piecewise approximation."

flixopt/effects.py (1)

663-683: EffectCollectionModel._do_modeling sequencing is reasonable but objective depends on penalty submodel state

The new flow—creating all EffectModel submodels, initializing the scalar penalty ShareAllocationModel, wiring cross‑effect shares, then setting the objective on objective_effect.submodel.total plus penalty.total.sum()—is coherent and leverages the new share allocation abstraction.

Because penalty shares from buses/components are added after this method (via add_share_to_penalty), the objective expression relies on the penalty.total variable being fully constrained later, which linopy supports. Just be aware of this temporal coupling when extending penalty logic in the future.

flixopt/flow_system.py (3)

603-640: add_elements adds useful guardrails on types and ownership

The new checks for allowed types (Component, Effect, Bus), prior assignment to another FlowSystem, and global label uniqueness significantly reduce the chance of building inconsistent systems. The early _connected_and_transformed reset also avoids stale transformed state after adding new elements.


804-826: _validate_system_integrity currently only checks bus references; consider extending later

The new integrity check that ensures every Flow.bus label exists in self.buses is sensible, even though _connect_network already raises if a bus is missing. It provides a central place to grow cross‑element validations (e.g., future checks on flows, components, or effects), so keeping the method and docstring generic is a good choice.


878-883: Manual flow_count computation avoids side‑effects when logging

Computing flow_count from component inputs/outputs instead of calling len(self.flows) is a nice touch to avoid triggering a cache rebuild during _connect_network. Logging remains informative without hidden work.

flixopt/structure.py (1)

254-287: Interface.transform_data docs slightly out of sync with new signature

The method signature now correctly takes only name_prefix: str = '', and the note about accessing the FlowSystem via self._flow_system / self.flow_system is helpful. The class‑level docstring still mentions transform_data(flow_system) as the required override, which could confuse users and implementers. Consider updating that bullet to reflect the new signature and usage.

flixopt/elements.py (1)

587-613: FlowModel._do_modeling now clearly separates creation of flow variable, tracking, and shares

Adding a docstring and calling super()._do_modeling() first, then:

  • creating the flow_rate variable,
  • delegating to _constraint_flow_rate() (which may add nested OnOff/Investment submodels),
  • adding the total_flow_hours tracking via ModelingPrimitives.expression_tracking_variable,
  • then creating load factor bounds and effect shares,

matches the recommended “variables → submodels → constraints” pattern and keeps responsibilities well‑factored.

flixopt/components.py (1)

748-750: Consider more descriptive docstrings.

The generic docstring "Create variables, constraints, and nested submodels" appears in three model classes but doesn't convey class-specific behavior. Consider adding specifics, e.g., for TransmissionModel: "Create transmission efficiency equations and optional absolute loss constraints" or for StorageModel: "Create charge state variables, balance equations, and investment submodels."

Also applies to: 789-791, 838-840

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ded18c8 and 72c525e.

📒 Files selected for processing (8)
  • flixopt/calculation.py (3 hunks)
  • flixopt/components.py (10 hunks)
  • flixopt/effects.py (3 hunks)
  • flixopt/elements.py (11 hunks)
  • flixopt/features.py (8 hunks)
  • flixopt/flow_system.py (5 hunks)
  • flixopt/interface.py (7 hunks)
  • flixopt/structure.py (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
flixopt/features.py (1)
flixopt/structure.py (1)
  • _do_modeling (1497-1504)
flixopt/calculation.py (2)
flixopt/structure.py (1)
  • do_modeling (98-107)
flixopt/aggregation.py (1)
  • do_modeling (317-347)
flixopt/effects.py (2)
flixopt/structure.py (9)
  • label_full (947-948)
  • label_full (1439-1440)
  • _fit_coords (324-337)
  • _fit_effect_coords (339-357)
  • _do_modeling (1497-1504)
  • values (1272-1277)
  • values (1559-1560)
  • create_model (943-944)
  • add_submodels (70-78)
flixopt/features.py (7)
  • _do_modeling (48-51)
  • _do_modeling (174-245)
  • _do_modeling (339-365)
  • _do_modeling (399-456)
  • _do_modeling (485-521)
  • _do_modeling (556-582)
  • ShareAllocationModel (524-627)
flixopt/components.py (2)
flixopt/structure.py (8)
  • _set_flow_system (288-301)
  • flow_system (304-322)
  • transform_data (272-286)
  • values (1272-1277)
  • values (1559-1560)
  • items (1279-1284)
  • items (1553-1554)
  • _fit_coords (324-337)
flixopt/interface.py (18)
  • _set_flow_system (223-227)
  • _set_flow_system (455-459)
  • _set_flow_system (673-678)
  • _set_flow_system (942-946)
  • transform_data (77-80)
  • transform_data (229-231)
  • transform_data (461-463)
  • transform_data (680-683)
  • transform_data (948-1005)
  • transform_data (1308-1339)
  • has_time_dim (199-200)
  • has_time_dim (203-206)
  • has_time_dim (437-438)
  • has_time_dim (441-444)
  • has_time_dim (663-664)
  • has_time_dim (667-671)
  • items (446-453)
  • InvestParameters (687-1099)
flixopt/structure.py (5)
flixopt/core.py (1)
  • TimeSeriesData (33-141)
flixopt/flow_system.py (3)
  • FlowSystem (38-1412)
  • fit_to_model_coords (521-559)
  • fit_effects_to_model_coords (561-584)
flixopt/components.py (5)
  • transform_data (220-227)
  • transform_data (448-485)
  • transform_data (730-734)
  • _set_flow_system (184-188)
  • _set_flow_system (442-446)
flixopt/elements.py (6)
  • transform_data (120-126)
  • transform_data (267-271)
  • transform_data (502-526)
  • _set_flow_system (112-118)
  • _set_flow_system (261-265)
  • _set_flow_system (494-500)
flixopt/interface.py (10)
  • transform_data (77-80)
  • transform_data (229-231)
  • transform_data (461-463)
  • transform_data (680-683)
  • transform_data (948-1005)
  • transform_data (1308-1339)
  • _set_flow_system (223-227)
  • _set_flow_system (455-459)
  • _set_flow_system (673-678)
  • _set_flow_system (942-946)
flixopt/flow_system.py (3)
flixopt/structure.py (4)
  • label_full (947-948)
  • label_full (1439-1440)
  • Element (922-970)
  • _set_flow_system (288-301)
flixopt/components.py (2)
  • _set_flow_system (184-188)
  • _set_flow_system (442-446)
flixopt/elements.py (5)
  • Component (41-178)
  • label_full (568-569)
  • _set_flow_system (112-118)
  • _set_flow_system (261-265)
  • _set_flow_system (494-500)
flixopt/interface.py (3)
flixopt/structure.py (7)
  • transform_data (272-286)
  • _fit_coords (324-337)
  • _set_flow_system (288-301)
  • flow_system (304-322)
  • values (1272-1277)
  • values (1559-1560)
  • _fit_effect_coords (339-357)
flixopt/components.py (5)
  • transform_data (220-227)
  • transform_data (448-485)
  • transform_data (730-734)
  • _set_flow_system (184-188)
  • _set_flow_system (442-446)
flixopt/elements.py (6)
  • transform_data (120-126)
  • transform_data (267-271)
  • transform_data (502-526)
  • _set_flow_system (112-118)
  • _set_flow_system (261-265)
  • _set_flow_system (494-500)
flixopt/elements.py (2)
flixopt/structure.py (14)
  • Element (922-970)
  • ElementModel (1571-1592)
  • FlowSystemModel (81-251)
  • Interface (254-919)
  • _set_flow_system (288-301)
  • flow_system (304-322)
  • transform_data (272-286)
  • label_full (947-948)
  • label_full (1439-1440)
  • _fit_coords (324-337)
  • _fit_effect_coords (339-357)
  • _do_modeling (1497-1504)
  • add_submodels (70-78)
  • create_model (943-944)
flixopt/flow_system.py (1)
  • create_model (641-654)
⏰ 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 (32)
flixopt/calculation.py (2)

232-235: Auto-modeling convenience feature looks good.

The automatic call to do_modeling() before solving improves the user experience by ensuring the model is ready. The logging message clearly communicates what's happening.

Note: This check uses self._modeled while fix_sizes() at line 209 uses self.modeled (the property). Consider standardizing on one approach as mentioned in the earlier comment.


199-199: Correct placement of flag setting.

Setting self._modeled = True at the end of both FullCalculation.do_modeling() and AggregatedCalculation.do_modeling() ensures the flag accurately reflects successful completion of all modeling operations.

Note: SegmentedCalculation doesn't set this flag, but that appears intentional since it uses sub-calculations (each with their own _modeled state) rather than having its own model.

Also applies to: 333-333

flixopt/features.py (2)

174-245: OnOffModel _do_modeling ordering looks consistent with Submodel guidance

Calling super()._do_modeling() first and then creating variables/constraints and nested patterns keeps this feature aligned with the new Submodel contract. The reuse of ModelingPrimitives/BoundingPatterns is coherent; no issues spotted here.


485-521: PiecewiseEffectsModel modeling flow is coherent

Initializing shares before constructing the nested PiecewiseModel, then wiring origin and share variables via their .name into piecewise_variables, ensures that piecewise constraints apply directly to the created variables. The final call to add_share_to_effects using self.shares looks correct. No functional issues spotted.

flixopt/effects.py (2)

395-435: EffectModel._do_modeling follows the new “variables → submodels → constraints” pattern

Creating the periodic and temporal ShareAllocationModel submodels first, followed by the total effect variable and the coupling constraint total == temporal.total + periodic.total, matches the new Submodel guidance and keeps the flow of dependencies clear. Bounds passed into the submodels (maximum_*, minimum_*, min_per_hour, max_per_hour) align with their intended semantics.


342-377: Effect.transform_data correctly leverages new FlowSystem wrappers

Switching to self._fit_coords / self._fit_effect_coords and dropping the explicit flow_system parameter simplifies the API and keeps all coordinate alignment centralized in FlowSystem. The chosen dims for temporal/periodic/total bounds (['period', 'scenario']) and for share_from_* (['time', 'period', 'scenario'] vs ['period', 'scenario']) are consistent with how the modeling layer consumes these arrays in EffectModel._do_modeling.

FlowSystem linkage is guaranteed before transform_data is called: elements receive their _flow_system reference via _set_flow_system() during add_elements, before connect_and_transform triggers the transform_data calls. The property raises RuntimeError if not set, preventing silent failures. The refactor itself is correct and safe.

flixopt/flow_system.py (3)

586-602: connect_and_transform now cleanly orchestrates transform + integrity check

Using element.transform_data() (without passing the FlowSystem) together with the new _set_flow_system linkage, followed by _validate_system_integrity(), gives a clear two‑phase setup: local data alignment then cross‑element validation. This is a nice simplification as long as all elements are registered via add_elements() / _add_*() (which they are in the provided code), so that flow_system is set before transform.


786-803: Single-owner enforcement via _check_if_element_already_assigned looks correct

Guarding against adding an Element that already belongs to another FlowSystem using the _flow_system back‑reference is a good safety check and matches the new _set_flow_system contract. The error message is explicit about how to reuse elements (via .copy()), which should help users.


827-847: _add_effects/_add_components/_add_buses: FlowSystem linkage and cache invalidation are well placed

Linking each element back to the FlowSystem via ._set_flow_system(self) before adding it to the respective container ensures that subsequent transform_data() calls can reliably use self.flow_system. Invalidating the flows cache once per batch of components/buses is efficient and avoids unnecessary recomputation.

flixopt/structure.py (4)

27-36: New imports support FlowSystem linkage and stats helpers

Bringing in FlowSystemDimensions, TimeSeriesData, and type aliases for numeric/effect types is consistent with the new _fit_coords and _fit_effect_coords helpers and the stats export functionality. No issues here.


288-358: FlowSystem linkage and coordinate helpers in Interface are well designed

_set_flow_system, the flow_system property, and the _fit_coords / _fit_effect_coords wrappers nicely encapsulate access to FlowSystem.fit_to_model_coords and fit_effects_to_model_coords. The explicit RuntimeError when an Interface isn’t yet linked to a FlowSystem provides a clear failure mode if someone calls transform_data() too early.


927-937: Element now tracking _flow_system enables single-owner checks

Adding self._flow_system: FlowSystem | None = None in Element.__init__ is the foundation for _check_if_element_already_assigned() in FlowSystem, and aligns with the new Interface linkage API. This will not affect serialization, as _flow_system is not part of the constructor parameters.


1497-1504: Submodel._do_modeling docstring clarifies expected modeling order

The updated docstring spelling out “create nested submodels first, then constraints referencing their variables” matches how the refactored models are structured (e.g., in FlowModel, ComponentModel, BusModel, and feature models). Keeping this guidance explicit should help keep future implementations consistent.

flixopt/elements.py (6)

20-38: Updated imports support Interface-based linkage and typing

Importing Interface and FlowSystemModel from .structure plus the FlowSystem type for TYPE_CHECKING is consistent with the new _set_flow_system patterns and the isinstance(self.size, Interface) check in Flow. No issues.


112-127: Component._set_flow_system / transform_data integrate cleanly with new Interface API

Propagating flow_system from Component to its OnOffParameters and all attached Flow instances ensures that all nested objects can safely use _fit_coords and _fit_effect_coords. The transform_data method building a prefix from name_prefix and label_full, then delegating to on_off_parameters and each flow, matches the new per‑element transform contract used from FlowSystem.connect_and_transform().


261-271: Bus._set_flow_system / transform_data correctly handle penalty data

Forwarding the FlowSystem to connected flows in _set_flow_system and using _fit_coords to align excess_penalty_per_flow_hour with model coordinates (using the bus‑level prefix) is consistent with how BusModel later multiplies by hours_per_step. The dims and naming look coherent.


494-527: Flow._set_flow_system / transform_data correctly propagate linkage and fit all parameters

  • _set_flow_system forwarding to on_off_parameters and to size when it’s an Interface (i.e., InvestParameters) ensures all nested parameter objects can access the FlowSystem.
  • transform_data fits relative bounds, fixed profiles, per‑flow‑hour effects, total flow‑hour bounds, load factors, and size itself (when not InvestParameters) via the new helpers with a consistent prefix based on label_full.

This keeps the Flow-level API aligned with the rest of the refactor without changing modeling semantics.


822-846: BusModel._do_modeling correctly integrates excess variables and penalties

The updated _do_modeling:

  • registers all connected flow_rate variables,
  • enforces the bus balance constraint,
  • conditionally adds non‑negative excess_input / excess_output variables and adjusts the balance equation,
  • and pushes penalty terms into the global penalty ShareAllocationModel via add_share_to_penalty,

is consistent with the new effects/penalty structure. The use of hours_per_step * excess_penalty_per_flow_hour to convert to per‑flow‑hour penalties is dimensionally correct.


869-923: ComponentModel._do_modeling sequencing is consistent with new Submodel guidelines

The method now:

  • ensures all relevant flows have OnOffParameters where needed,
  • creates all FlowModel submodels,
  • then (optionally) creates a component‑level on variable and associated OnOffModel,
  • and finally enforces mutual exclusivity for prevent_simultaneous_flows.

This ordering respects the instruction to create nested submodels before adding constraints that depend on them and keeps the logic straightforward.

flixopt/components.py (6)

184-188: LGTM! Proper flow_system propagation.

The conditional propagation to piecewise_conversion correctly prevents errors when it's None, and the pattern aligns with the codebase's propagation strategy.


220-227: Consistent signature refactoring.

The removal of the FlowSystem parameter and delegation to internal coordinate-fitting utilities is correctly implemented. All nested transform_data calls properly pass only the prefix.


229-241: Correctly updated to use internal fitting utility.

The switch from receiving FlowSystem as a parameter to using self._fit_coords is consistent with the refactoring pattern and maintains the same functionality.


442-446: Proper conditional propagation for InvestParameters.

The isinstance check correctly identifies when capacity_in_flow_hours is an InvestParameters instance that needs flow_system propagation, while scalar values don't require it.


448-485: Well-structured transform_data implementation.

The parallel structure between _set_flow_system (lines 442-446) and transform_data consistently handles InvestParameters vs. scalar values for capacity_in_flow_hours. All coordinate fitting properly uses the internal _fit_coords wrapper.


730-734: Consistent coordinate fitting for transmission losses.

The signature update and use of self._fit_coords align with the refactoring pattern. Note that Transmission correctly omits a _set_flow_system override since it has no nested Interface objects requiring special propagation (the parent Component handles on_off_parameters).

flixopt/interface.py (7)

77-80: Clean signature update.

The removal of the FlowSystem parameter and use of self._fit_coords maintains the existing dimension logic while aligning with the refactoring pattern.


223-231: Correct propagation and transformation for nested Pieces.

The _set_flow_system method properly iterates through all Piece objects to propagate the reference, and transform_data consistently enumerates pieces to create unique prefixes.


455-463: Appropriate iteration patterns for propagation and transformation.

Using .values() in _set_flow_system (no names needed) and .items() in transform_data (names needed for prefixes) is the correct approach for this dictionary-based structure.


673-683: Proper handling of dual piecewise structure.

The implementation correctly manages both the singular piecewise_origin and the dictionary of piecewise_shares, ensuring all nested Piecewise objects receive the flow_system reference and have distinct prefixes.


942-946: Proper propagation to nested PiecewiseEffects.

The conditional check prevents errors when piecewise_effects_of_investment is None, following the established pattern.


948-1005: Complex but well-structured transform_data implementation.

The method correctly handles multiple effect types, piecewise effects, and the intricate linked_periods conversion logic. The multiple accesses to self.flow_system.periods (lines 984, 991, 993, 995, 997, 999) assume _set_flow_system has been called first—this is the intended design, enforced by the flow_system property's RuntimeError.

The warnings at lines 992-997 are appropriately informational rather than blocking, allowing compute_linked_periods to proceed with boundary-inclusive logic even when start/end aren't exact period values.


1308-1339: Correct coordinate fitting with appropriate dimensions.

The distinction between time-varying parameters (consecutive constraints using default dims) and period-level aggregates (total constraints using ['period', 'scenario']) correctly reflects the semantic differences in these constraints.

  Updated the modeled property to use the _modeled flag instead of checking self.model is not None, ensuring consistent state tracking throughout
  the Calculation class.

  2. features.py - PieceModel Type Hints

  Improved the dims parameter type from FlowSystemDimensions | None to Collection[FlowSystemDimensions] | None in both PieceModel and
  PiecewiseModel to accurately reflect actual usage with tuples like ('period', 'scenario').

  3. features.py - ShareAllocationModel Error Message

  Updated the validation error message from "Both max_per_hour and min_per_hour cannot be used..." to "max_per_hour and min_per_hour require
  'time' dimension in dims" to match the actual condition being checked.

  4. features.py - PiecewiseModel Zero-Point Documentation

  Added clarifying comments explaining that the zero_point binary variable acts as a gate: when enabled (=1), at most one segment is active; when
  disabled (=0), all segments remain inactive.

  5. effects.py - Penalty Temporal Coupling

  Added a comment in EffectCollectionModel._do_modeling noting that penalty shares are added after the objective is set, explaining the temporal
  coupling in the design.

  6. structure.py - Interface Documentation

  Updated the class-level docstring to reflect the correct transform_data(name_prefix='') signature instead of the outdated
  transform_data(flow_system).

  7. components.py - Model Class Docstrings

  Replaced generic docstrings with specific descriptions:
  - TransmissionModel: "Create transmission efficiency equations and optional absolute loss constraints for both flow directions"
  - LinearConverterModel: "Create linear conversion equations or piecewise conversion constraints between input and output flows"
  - StorageModel: "Create charge state variables, energy balance equations, and optional investment submodels"

  All changes improve code clarity, consistency, and maintainability without altering functionality.
… feature/simplify-structure

# Conflicts:
#	flixopt/features.py
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 (1)
CHANGELOG.md (1)

54-84: Accurate and well-structured changelog entries for architectural improvements.

The Unreleased section clearly documents the internal restructuring work. However, a few items could be refined:

  1. Lines 59, 62–63 (Added section): The "Helper methods in Interface base class" and "FlowSystem property in Interface" are internal/architectural plumbing rather than user-facing features. Consider moving these to the "Development" section or the "Changed" section if they're part of the internal refactoring story rather than new capabilities.

  2. Lines 71 and 79 (duplication): Both the "Changed" section (line 71) and "Development" section (line 79) describe the two-phase modeling pattern in _do_modeling(). This creates redundancy—consider consolidating or clarifying the distinction between what changed (line 71) and what was refactored (line 79).

Apply this diff to improve clarity and reduce duplication:

### ✨ Added
- **Auto-modeling**: `Calculation.solve()` now automatically calls `do_modeling()` if not already done, making the explicit `do_modeling()` call optional for simpler workflows
- **System validation**: Added `_validate_system_integrity()` to validate cross-element references (e.g., Flow.bus) immediately after transformation, providing clearer error messages
- **Element registration validation**: Added checks to prevent elements from being assigned to multiple FlowSystems simultaneously

### ♻️ Changed
- **Refactored FlowSystem-Element coupling**:
    - Introduced `_set_flow_system()` method in Interface base class to propagate FlowSystem reference to nested Interface objects
    - Each Interface subclass now explicitly propagates the reference to its nested interfaces (e.g., Component → OnOffParameters, Flow → InvestParameters)
    - Elements can now access FlowSystem via `self.flow_system` property instead of passing it through every method call
    - Added `_fit_coords()` and `_fit_effect_coords()` convenience wrappers for cleaner data transformation code
- **Simplified transform_data() signature**: Removed `flow_system` parameter from `transform_data()` methods - FlowSystem reference is now accessed via `self.flow_system` property
- **Two-phase modeling pattern within _do_modeling()**: Clarified the pattern where `_do_modeling()` creates nested submodels first (so their variables exist), then creates constraints that reference those variables - eliminates circular dependencies in Submodel architecture
- **Improved cache invalidation**: Cache invalidation in `add_elements()` now happens once after all additions rather than per element
- **Better logging**: Centralized element registration logging to show element type and full label

### 🐛 Fixed
- Fixed inconsistent argument passing in `_fit_effect_coords()` - standardized all calls to use named arguments (`prefix=`, `effect_values=`, `suffix=`) instead of mix of positional and named arguments

### 👷 Development
- **Eliminated circular dependencies**: Implemented two-phase modeling pattern within `_do_modeling()` where nested submodels are created first (creating their variables), then constraints are created that can safely reference those submodel variables
- Added comprehensive docstrings to `_do_modeling()` methods explaining the pattern
- Added missing type hints throughout the codebase
- Improved code organization by making FlowSystem reference propagation explicit and traceable
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a334178 and 1fcf109.

📒 Files selected for processing (1)
  • CHANGELOG.md (1 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.11)
  • GitHub Check: test (3.13)
  • GitHub Check: test (3.10)

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