From 43c85dd9de863aaf3b61889e19f597783fe8623c Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Wed, 15 Oct 2025 13:45:17 +0200
Subject: [PATCH 01/42] Fix Docs
---
docs/user-guide/migration-guide-v3.md | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 190503dc3..898bb5377 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -239,9 +239,9 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
=== "v2.x (Deprecated)"
```python
- fx.Source('my_source', source=flow)
+ flow1 = fx.Source('Buy', bus='Gas)
- fx.Sink('my_sink', sink=flow)
+ flow2 = fx.Flow('Sell', bus='Gas)
fx.SourceAndSink(
'my_source_sink',
@@ -254,14 +254,14 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
=== "v3.0.0 (Recommended)"
```python
- fx.Source('my_source', outputs=flow)
+ flow1 = fx.Source('Buy', bus='Gas)
- fx.Sink('my_sink', inputs=flow)
+ flow2 = fx.Flow('Sell', bus='Gas)
fx.SourceAndSink(
'my_source_sink',
- outputs=flow1,
- inputs=flow2,
+ outputs=[flow1],
+ inputs=[flow2],
prevent_simultaneous_flow_rates=True
)
```
From fa82b5f352078688fc42cfc92b2486ddbd9a30e3 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 09:37:21 +0200
Subject: [PATCH 02/42] Update Changelog and migration guide for missing
breaking changes
---
CHANGELOG.md | 31 +++-
docs/user-guide/migration-guide-v3.md | 233 ++++++++++++++++++++++++--
2 files changed, 244 insertions(+), 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a043fc56..e4b0da8ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -139,17 +139,36 @@ This replaces `specific_share_to_other_effects_*` parameters and inverts the dir
### 💥 Breaking Changes
-- `relative_minimum_charge_state` and `relative_maximum_charge_state` don't have an extra timestep anymore.
+**API and Behavior Changes:**
+
+- **Effect sharing system redesigned** (no deprecation): The old `specific_share_to_other_effects_*` parameters were completely replaced with the new `share_from_temporal` and `share_from_periodic` syntax (see 🔥 Removed section)
+- **FlowSystem independence**: FlowSystems cannot be shared across multiple Calculations anymore. A copy of the FlowSystem is created instead, making every Calculation independent. Each Subcalculation in `SegmentedCalculation` now has its own distinct `FlowSystem` object
+- **Bus and Effect object assignment**: Direct assignment of Bus/Effect objects is no longer supported. Use labels (strings) instead:
+ - `Flow.bus` must receive a string label, not a Bus object
+ - Effect shares must use effect labels (strings) in dictionaries, not Effect objects
+- **Logging defaults** (from v2.2.0): Console and file logging are now disabled by default. Enable explicitly with `CONFIG.Logging.console = True` and `CONFIG.apply()`
+
+**Class and Method Renaming:**
+
- Renamed class `SystemModel` to `FlowSystemModel`
- Renamed class `Model` to `Submodel`
- Renamed `mode` parameter in plotting methods to `style`
-- Renamed investment binary variable `is_invested` to `invested` in `InvestmentModel`
-- `Calculation.do_modeling()` now returns the `Calculation` object instead of its `linopy.Model`. Callers that previously accessed the linopy model directly should now use `calculation.do_modeling().model` instead of `calculation.do_modeling()`.
+- `Calculation.do_modeling()` now returns the `Calculation` object instead of its `linopy.Model`. Callers that previously accessed the linopy model directly should now use `calculation.do_modeling().model` instead of `calculation.do_modeling()`
+
+**Variable Renaming in Results:**
+
+- Investment binary variable: `is_invested` → `invested` in `InvestmentModel`
+- Switch tracking variables in `OnOffModel`:
+ - `switch_on` → `switch|on`
+ - `switch_off` → `switch|off`
+ - `switch_on_nr` → `switch|count`
+
+**Data Structure Changes:**
+
+- `relative_minimum_charge_state` and `relative_maximum_charge_state` don't have an extra timestep anymore. Use the new `relative_minimum_final_charge_state` and `relative_maximum_final_charge_state` parameters for final state control
### ♻️ Changed
-- FlowSystems cannot be shared across multiple Calculations anymore. A copy of the FlowSystem is created instead, making every Calculation independent
-- Each Subcalculation in `SegmentedCalculation` now has its own distinct `FlowSystem` object
- Type system overhaul - added clear separation between temporal and non-temporal data throughout codebase for better clarity
- Enhanced FlowSystem interface with improved `__repr__()` and `__str__()` methods
- Improved Model Structure - Views and organisation is now divided into:
@@ -164,8 +183,6 @@ This replaces `specific_share_to_other_effects_*` parameters and inverts the dir
- The `agg_group` and `agg_weight` parameters of `TimeSeriesData` are deprecated and will be removed in a future version. Use `aggregation_group` and `aggregation_weight` instead.
- The `active_timesteps` parameter of `Calculation` is deprecated and will be removed in a future version. Use the new `sel(time=...)` method on the FlowSystem instead.
-- The assignment of Bus Objects to Flow.bus is deprecated and will be removed in a future version. Use the label of the Bus instead.
-- The usage of Effects objects in Dicts to assign shares to Effects is deprecated and will be removed in a future version. Use the label of the Effect instead.
- **InvestParameters** parameters renamed for improved clarity around investment and retirement effects:
- `fix_effects` → `effects_of_investment`
- `specific_effects` → `effects_of_investment_per_size`
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 898bb5377..9ab1079e9 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -57,25 +57,141 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
---
-### 2. Class and Variable Renaming
+### 2. Variable Renaming in Results
+
+!!! warning "Breaking Change"
+ Multiple variables have been renamed in the optimization results. Update all result access accordingly.
+
+**Investment Variables:**
+
+=== "v2.x (Old)"
+
+ ```python
+ # Investment decision variable
+ results.solution['element|is_invested']
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ # Investment decision variable
+ results.solution['element|invested']
+ ```
+
+**Switch Tracking Variables (OnOffModel):**
+
+=== "v2.x (Old)"
+
+ ```python
+ # Switch state tracking
+ results.solution['component|switch_on']
+ results.solution['component|switch_off']
+ results.solution['component|switch_on_nr']
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ # Switch state tracking with pipe delimiter
+ results.solution['component|switch|on']
+ results.solution['component|switch|off']
+ results.solution['component|switch|count']
+ ```
+
+**Quick Reference Table:**
+
+| Old Variable Name (v2.x) | New Variable Name (v3.0.0) | Component Type |
+|--------------------------|---------------------------|----------------|
+| `is_invested` | `invested` | Investment |
+| `switch_on` | `switch|on` | OnOff |
+| `switch_off` | `switch|off` | OnOff |
+| `switch_on_nr` | `switch|count` | OnOff |
+
+---
+
+### 3. FlowSystem Independence
+
+!!! warning "Breaking Change"
+ FlowSystems can no longer be shared across multiple Calculations.
+
+**What changed:** Each `Calculation` now automatically creates its own copy of the FlowSystem, making calculations fully independent.
+
+**Impact:**
+- Mutations to one calculation's FlowSystem won't affect others
+- Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
+- Memory usage may increase slightly due to copying
=== "v2.x (Old)"
```python
- # In optimization results
- results.solution['component|is_invested']
+ # FlowSystem was shared
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system)
+ calc2 = fx.FullCalculation('calc2', flow_system)
+
+ # Both calculations shared the same FlowSystem object
+ # Changes in one affected the other
```
=== "v3.0.0 (New)"
```python
- # In optimization results
- results.solution['component|invested']
+ # Each calculation gets its own copy
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Gets a copy
+ calc2 = fx.FullCalculation('calc2', flow_system) # Gets another copy
+
+ # Calculations are now independent
+ # Changes to calc1's FlowSystem won't affect calc2
```
+!!! tip "Migration"
+ If you relied on shared FlowSystem behavior (which you most likely did not), you should copy the flow_system before passing it to another calculation.
+
---
-### 3. Calculation API Change
+### 4. Bus and Effect Object Assignment
+
+!!! warning "Breaking Change"
+ Direct assignment of Bus and Effect objects is no longer supported. Use string labels instead.
+
+**Bus Assignment:**
+
+=== "v2.x (Old)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus=my_bus) # ❌ Object assignment
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+ ```
+
+**Effect Shares Assignment:**
+
+=== "v2.x (Old)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={CO2: 0.2}) # ❌ Effect object
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}) # ✅ String label
+ ```
+
+---
+
+### 5. Calculation API Change
!!! info "Method Chaining Support"
`Calculation.do_modeling()` now returns the Calculation object to enable method chaining.
@@ -106,7 +222,7 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
---
-### 4. Storage Charge State Bounds
+### 6. Storage Charge State Bounds
!!! warning "Array Dimensions Changed"
`relative_minimum_charge_state` and `relative_maximum_charge_state` no longer have an extra timestep.
@@ -139,7 +255,7 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
---
-### 5. Plotting Parameter Rename
+### 7. Plotting Parameter Rename
=== "v2.x (Old)"
@@ -155,6 +271,50 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
---
+### 8. Logging Configuration
+
+!!! warning "Breaking Change (from v2.2.0)"
+ Console and file logging are now **disabled by default**.
+
+**What changed:** In v2.2.0 (before v3.0.0), the default logging behavior was changed to be opt-in rather than opt-out.
+
+**Impact:** If you're upgrading from v2.1.x or earlier to v3.0.0, you may notice that logging output is no longer displayed unless explicitly enabled.
+
+=== "v2.1.x and earlier"
+
+ ```python
+ import flixopt as fx
+
+ # Logging was enabled by default
+ calculation = fx.FullCalculation('calc', flow_system)
+ calculation.solve() # Logs were shown automatically
+ ```
+
+=== "v2.2.0+ and v3.0.0"
+
+ ```python
+ import flixopt as fx
+
+ # Enable console logging explicitly
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.Logging.level = 'INFO'
+ fx.CONFIG.Logging.file = 'flixopt.log' # Optional: Enable file logging
+ fx.CONFIG.apply()
+
+ calculation = fx.FullCalculation('calc', flow_system)
+ calculation.solve() # Now logs are shown
+ ```
+
+!!! tip "Migration"
+ Add logging configuration at the start of your scripts if you want to see log output:
+ ```python
+ import flixopt as fx
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.apply()
+ ```
+
+---
+
## Deprecated Parameters (Still Supported)
!!! info "Gradual Migration"
@@ -524,6 +684,37 @@ flow = fx.Flow('P_el', bus='electricity') # ✅
**Solution:** Rename `SystemModel` → `FlowSystemModel`
+### Issue: "KeyError when accessing results variables"
+
+**Solution:** Variable names have changed. Update your result access:
+
+```python
+# Old variable names
+results.solution['component|is_invested'] # ❌
+results.solution['component|switch_on'] # ❌
+results.solution['component|switch_off'] # ❌
+results.solution['component|switch_on_nr'] # ❌
+
+# New variable names
+results.solution['component|invested'] # ✅
+results.solution['component|switch|on'] # ✅
+results.solution['component|switch|off'] # ✅
+results.solution['component|switch|count'] # ✅
+```
+
+### Issue: "FlowSystem changes affecting multiple calculations"
+
+**Solution:** FlowSystems are now automatically copied for each Calculation. If you need to access the FlowSystem from a calculation, use `calculation.flow_system` instead of keeping a reference to the original.
+
+### Issue: "No logging output"
+
+**Solution:** Logging is disabled by default in v2.2.0+. Enable it explicitly:
+
+```python
+import flixopt as fx
+fx.CONFIG.Logging.console = True
+fx.CONFIG.apply()
+```
---
@@ -537,14 +728,30 @@ flow = fx.Flow('P_el', bus='electricity') # ✅
## Summary Checklist
+**Critical (Breaking Changes):**
+
- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update effect sharing syntax (no deprecation warning!)
-- [ ] Update `Calculation.do_modeling()` usage
-- [ ] Fix storage charge state array dimensions
+- [ ] Update effect sharing syntax (no deprecation warning!) - move shares to receiving effect
+- [ ] Update all variable names in result access (`is_invested` → `invested`, `switch_on` → `switch|on`, etc.)
+- [ ] Replace Bus/Effect object assignments with string labels
+- [ ] Remove any code that relies on shared FlowSystem objects across Calculations
+- [ ] Update `Calculation.do_modeling()` usage if accessing return value
+- [ ] Fix storage charge state array dimensions (remove extra timestep)
+
+**Important:**
+
- [ ] Rename `mode` → `style` in plotting calls
+- [ ] Enable logging explicitly if needed (`fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
- [ ] Update deprecated parameter names (optional, but recommended)
-- [ ] Enable logging explicitly if needed
+
+**Testing:**
+
- [ ] Test your code thoroughly
-- [ ] Explore new features (periods, scenarios, enhanced I/O)
+- [ ] Check for deprecation warnings
+- [ ] Validate results match v2.x output (if upgrading)
+
+**Optional:**
+
+- [ ] Explore new features (periods, scenarios, enhanced I/O, balanced storage, final charge state control)
**Welcome to flixopt v3.0.0!** 🎉
From a80da63cd47dd3e795056894c76d47c05fd85625 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 10:42:18 +0200
Subject: [PATCH 03/42] Update Migration guide
---
docs/user-guide/migration-guide-v3.md | 784 +++++---------------------
1 file changed, 135 insertions(+), 649 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 9ab1079e9..f4b6a6d87 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -1,15 +1,14 @@
# Migration Guide: Upgrading to v3.0.0
-This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.0 introduces powerful new features like multi-period investments and scenario-based stochastic optimization, along with a redesigned effect sharing system.
+Quick guide for migrating flixopt from v2.x to v3.0.0.
-!!! tip "Quick Start"
- 1. **Update your installation:**
- ```bash
- pip install --upgrade flixopt
- ```
- 2. **Review breaking changes** in the sections below
- 3. **Update deprecated parameters** to their new names
- 4. **Test your code** with the new version
+## Quick Start
+
+```bash
+pip install --upgrade flixopt
+```
+
+Review breaking changes, update deprecated parameters, and test thoroughly.
---
@@ -17,348 +16,105 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
### 1. Effect Sharing System Redesign
-!!! warning "Breaking Change - No Deprecation"
- The effect sharing syntax has been inverted and simplified. This change was made WITHOUT deprecation warnings due to the fundamental restructuring.
-
-**What changed:** Effects now "pull" shares from other effects instead of "pushing" them.
-
-=== "v2.x (Old)"
-
- ```python
- # Effects "pushed" shares to other effects
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
- specific_share_to_other_effects_operation={'costs': 0.2})
+⚠️ **No deprecation warning** - Effects now "pull" shares instead of "pushing" them.
- land = fx.Effect('land', 'm²', 'Land usage',
- specific_share_to_other_effects_invest={'costs': 100})
-
- costs = fx.Effect('costs', '€', 'Total costs')
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- # Effects "pull" shares from other effects (clearer direction)
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
-
- land = fx.Effect('land', 'm²', 'Land usage')
+**v2.x:**
+```python
+CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
+ specific_share_to_other_effects_operation={'costs': 0.2})
+land = fx.Effect('land', 'm²', 'Land usage',
+ specific_share_to_other_effects_invest={'costs': 100})
+costs = fx.Effect('costs', '€', 'Total costs')
+```
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}, # From temporal (operation) effects
- share_from_periodic={'land': 100}) # From periodic (investment) effects
- ```
+**v3.0.0:**
+```python
+CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+land = fx.Effect('land', 'm²', 'Land usage')
+costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}, # From temporal effects
+ share_from_periodic={'land': 100}) # From periodic effects
+```
-!!! success "Migration Steps"
- 1. Find all uses of `specific_share_to_other_effects_operation` and `specific_share_to_other_effects_invest`
- 2. Move the share definition to the **receiving** effect
- 3. Rename parameters:
- - `specific_share_to_other_effects_operation` → `share_from_temporal`
- - `specific_share_to_other_effects_invest` → `share_from_periodic`
+**Migration:**
+- Move share definitions to receiving effect
+- `specific_share_to_other_effects_operation` → `share_from_temporal`
+- `specific_share_to_other_effects_invest` → `share_from_periodic`
---
### 2. Variable Renaming in Results
-!!! warning "Breaking Change"
- Multiple variables have been renamed in the optimization results. Update all result access accordingly.
-
-**Investment Variables:**
-
-=== "v2.x (Old)"
-
- ```python
- # Investment decision variable
- results.solution['element|is_invested']
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- # Investment decision variable
- results.solution['element|invested']
- ```
-
-**Switch Tracking Variables (OnOffModel):**
-
-=== "v2.x (Old)"
-
- ```python
- # Switch state tracking
- results.solution['component|switch_on']
- results.solution['component|switch_off']
- results.solution['component|switch_on_nr']
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- # Switch state tracking with pipe delimiter
- results.solution['component|switch|on']
- results.solution['component|switch|off']
- results.solution['component|switch|count']
- ```
-
-**Quick Reference Table:**
-
-| Old Variable Name (v2.x) | New Variable Name (v3.0.0) | Component Type |
-|--------------------------|---------------------------|----------------|
-| `is_invested` | `invested` | Investment |
-| `switch_on` | `switch|on` | OnOff |
-| `switch_off` | `switch|off` | OnOff |
-| `switch_on_nr` | `switch|count` | OnOff |
-
----
-
-### 3. FlowSystem Independence
-
-!!! warning "Breaking Change"
- FlowSystems can no longer be shared across multiple Calculations.
-
-**What changed:** Each `Calculation` now automatically creates its own copy of the FlowSystem, making calculations fully independent.
-
-**Impact:**
-- Mutations to one calculation's FlowSystem won't affect others
-- Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
-- Memory usage may increase slightly due to copying
-
-=== "v2.x (Old)"
-
- ```python
- # FlowSystem was shared
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system)
- calc2 = fx.FullCalculation('calc2', flow_system)
-
- # Both calculations shared the same FlowSystem object
- # Changes in one affected the other
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- # Each calculation gets its own copy
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Gets a copy
- calc2 = fx.FullCalculation('calc2', flow_system) # Gets another copy
-
- # Calculations are now independent
- # Changes to calc1's FlowSystem won't affect calc2
- ```
-
-!!! tip "Migration"
- If you relied on shared FlowSystem behavior (which you most likely did not), you should copy the flow_system before passing it to another calculation.
-
----
-
-### 4. Bus and Effect Object Assignment
-
-!!! warning "Breaking Change"
- Direct assignment of Bus and Effect objects is no longer supported. Use string labels instead.
-
-**Bus Assignment:**
-
-=== "v2.x (Old)"
-
- ```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus=my_bus) # ❌ Object assignment
- ```
-
-=== "v3.0.0 (New)"
+| Old (v2.x) | New (v3.0.0) |
+|------------|--------------|
+| `is_invested` | `invested` |
+| `switch_on` | `switch\|on` |
+| `switch_off` | `switch\|off` |
+| `switch_on_nr` | `switch\|count` |
- ```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus='electricity') # ✅ String label
- ```
-
-**Effect Shares Assignment:**
-
-=== "v2.x (Old)"
-
- ```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={CO2: 0.2}) # ❌ Effect object
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}) # ✅ String label
- ```
+```python
+# Old: results.solution['component|is_invested']
+# New: results.solution['component|invested']
+```
---
-### 5. Calculation API Change
-
-!!! info "Method Chaining Support"
- `Calculation.do_modeling()` now returns the Calculation object to enable method chaining.
-
-=== "v2.x (Old)"
-
- ```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- linopy_model = calculation.do_modeling() # Returned linopy.Model
-
- # Access model directly from return value
- print(linopy_model)
- ```
-
-=== "v3.0.0 (New)"
+### 3. Use String Labels
- ```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- calculation.do_modeling() # Returns Calculation object
- linopy_model = calculation.model # Access model via property
+Pass string labels instead of objects:
- # This enables chaining operations
- fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
- ```
+```python
+# Old: flow = fx.Flow('P_el', bus=my_bus)
+# New: flow = fx.Flow('P_el', bus='electricity')
+```
-!!! tip "Migration"
- If you used the return value of `do_modeling()`, update to access `.model` property instead.
+Applies to Bus assignments and Effect share dictionaries.
---
-### 6. Storage Charge State Bounds
-
-!!! warning "Array Dimensions Changed"
- `relative_minimum_charge_state` and `relative_maximum_charge_state` no longer have an extra timestep.
-
-**Impact:** If you provided arrays with `len(timesteps) + 1` elements, reduce to `len(timesteps)`.
-
-=== "v2.x (Old)"
-
- ```python
- # Array with extra timestep
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 values for 4 timesteps
- )
- ```
+### 4. FlowSystem Independence
-=== "v3.0.0 (New)"
-
- ```python
- # Array matches timesteps
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
- relative_minimum_final_charge_state=0.3 # Specify the final value directly
- )
- ```
-
-!!! note "Final State Control"
- Use the new `relative_minimum_final_charge_state` and `relative_maximum_final_charge_state` parameters to explicitly control the final charge state.
+Each `Calculation` now gets its own FlowSystem copy - calculations are fully independent.
---
-### 7. Plotting Parameter Rename
-
-=== "v2.x (Old)"
+### 5. Storage Charge State Bounds
- ```python
- results.plot_heatmap('component|variable', mode='line')
- ```
+Array length now matches timesteps (no extra element):
-=== "v3.0.0 (New)"
-
- ```python
- results.plot_heatmap('component|variable', style='line')
- ```
+```python
+storage = fx.Storage(
+ 'storage',
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # Matches timesteps
+ relative_minimum_final_charge_state=0.3 # New: control final state explicitly
+)
+```
---
-### 8. Logging Configuration
-
-!!! warning "Breaking Change (from v2.2.0)"
- Console and file logging are now **disabled by default**.
-
-**What changed:** In v2.2.0 (before v3.0.0), the default logging behavior was changed to be opt-in rather than opt-out.
-
-**Impact:** If you're upgrading from v2.1.x or earlier to v3.0.0, you may notice that logging output is no longer displayed unless explicitly enabled.
-
-=== "v2.1.x and earlier"
-
- ```python
- import flixopt as fx
-
- # Logging was enabled by default
- calculation = fx.FullCalculation('calc', flow_system)
- calculation.solve() # Logs were shown automatically
- ```
-
-=== "v2.2.0+ and v3.0.0"
-
- ```python
- import flixopt as fx
-
- # Enable console logging explicitly
- fx.CONFIG.Logging.console = True
- fx.CONFIG.Logging.level = 'INFO'
- fx.CONFIG.Logging.file = 'flixopt.log' # Optional: Enable file logging
- fx.CONFIG.apply()
+### 6. Other Breaking Changes
- calculation = fx.FullCalculation('calc', flow_system)
- calculation.solve() # Now logs are shown
- ```
-
-!!! tip "Migration"
- Add logging configuration at the start of your scripts if you want to see log output:
- ```python
- import flixopt as fx
- fx.CONFIG.Logging.console = True
- fx.CONFIG.apply()
- ```
+- **`do_modeling()` return value:** Now returns `Calculation` object (access model via `.model` property)
+- **Plotting:** `mode` parameter renamed to `style`
+- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
---
-## Deprecated Parameters (Still Supported)
-
-!!! info "Gradual Migration"
- These parameters still work but will be removed in a future version. Update them at your convenience - deprecation warnings will guide you.
+## Deprecated Parameters (Still Work)
### InvestParameters
-**Parameter Changes:**
-
-| Old Parameter (v2.x) | New Parameter (v3.0.0) |
-|---------------------|----------------------|
+| Old | New |
+|-----|-----|
| `fix_effects` | `effects_of_investment` |
| `specific_effects` | `effects_of_investment_per_size` |
| `divest_effects` | `effects_of_retirement` |
| `piecewise_effects` | `piecewise_effects_of_investment` |
-=== "v2.x (Deprecated)"
-
- ```python
- fx.InvestParameters(
- fix_effects=1000,
- specific_effects={'costs': 10},
- divest_effects=100,
- piecewise_effects=my_piecewise,
- )
- ```
-
-=== "v3.0.0 (Recommended)"
-
- ```python
- fx.InvestParameters(
- effects_of_investment=1000,
- effects_of_investment_per_size={'costs': 10},
- effects_of_retirement=100,
- piecewise_effects_of_investment=my_piecewise,
- )
- ```
-
### Effect
-**Parameter Changes:**
-
-| Old Parameter (v2.x) | New Parameter (v3.0.0) |
-|---------------------|----------------------|
+| Old | New |
+|-----|-----|
| `minimum_investment` | `minimum_periodic` |
| `maximum_investment` | `maximum_periodic` |
| `minimum_operation` | `minimum_temporal` |
@@ -366,392 +122,122 @@ This guide helps you migrate your flixopt code from v2.x to v3.0.0. Version 3.0.
| `minimum_operation_per_hour` | `minimum_per_hour` |
| `maximum_operation_per_hour` | `maximum_per_hour` |
-=== "v2.x (Deprecated)"
-
- ```python
- fx.Effect(
- 'my_effect', 'unit', 'description',
- minimum_investment=10,
- maximum_investment=100,
- minimum_operation=5,
- maximum_operation=50,
- minimum_operation_per_hour=1,
- maximum_operation_per_hour=10,
- )
- ```
-
-=== "v3.0.0 (Recommended)"
-
- ```python
- fx.Effect(
- 'my_effect', 'unit', 'description',
- minimum_periodic=10,
- maximum_periodic=100,
- minimum_temporal=5,
- maximum_temporal=50,
- minimum_per_hour=1,
- maximum_per_hour=10,
- )
- ```
-
-### Component Parameters
-
-=== "v2.x (Deprecated)"
-
- ```python
- flow1 = fx.Source('Buy', bus='Gas)
-
- flow2 = fx.Flow('Sell', bus='Gas)
-
- fx.SourceAndSink(
- 'my_source_sink',
- source=flow1,
- sink=flow2,
- prevent_simultaneous_sink_and_source=True
- )
- ```
-
-=== "v3.0.0 (Recommended)"
-
- ```python
- flow1 = fx.Source('Buy', bus='Gas)
-
- flow2 = fx.Flow('Sell', bus='Gas)
-
- fx.SourceAndSink(
- 'my_source_sink',
- outputs=[flow1],
- inputs=[flow2],
- prevent_simultaneous_flow_rates=True
- )
- ```
-
-### TimeSeriesData
-
-=== "v2.x (Deprecated)"
+### SourceAndSink
- ```python
- fx.TimeSeriesData(
- agg_group='group1',
- agg_weight=2.0
- )
- ```
+| Old | New |
+|-----|-----|
+| `source` | `outputs` |
+| `sink` | `inputs` |
+| `prevent_simultaneous_sink_and_source` | `prevent_simultaneous_flow_rates` |
-=== "v3.0.0 (Recommended)"
+### TimeSeriesData
- ```python
- fx.TimeSeriesData(
- aggregation_group='group1',
- aggregation_weight=2.0
- )
- ```
+| Old | New |
+|-----|-----|
+| `agg_group` | `aggregation_group` |
+| `agg_weight` | `aggregation_weight` |
### Calculation
-=== "v2.x (Deprecated)"
-
- ```python
- calculation = fx.FullCalculation(
- 'calc',
- flow_system,
- active_timesteps=[0, 1, 2]
- )
- ```
-
-=== "v3.0.0 (Recommended)"
-
- ```python
- # Use FlowSystem selection methods
- flow_system_subset = flow_system.sel(time=slice('2020-01-01', '2020-01-03'))
- calculation = fx.FullCalculation('calc', flow_system_subset)
-
- # Or with isel for index-based selection
- flow_system_subset = flow_system.isel(time=slice(0, 3))
- calculation = fx.FullCalculation('calc', flow_system_subset)
- ```
+Replace `active_timesteps` with FlowSystem selection:
+```python
+# Old: calculation = fx.FullCalculation('calc', flow_system, active_timesteps=[0, 1, 2])
+# New:
+fs_subset = flow_system.isel(time=slice(0, 3))
+calculation = fx.FullCalculation('calc', fs_subset)
+```
---
-## New Features in v3.0.0
-
-### 1. Multi-Period Investments
+## New Features
-Model transformation pathways with distinct investment decisions in each period:
+### Multi-Period Investments
```python
-import pandas as pd
-
-# Define multiple investment periods
periods = pd.Index(['2020', '2030'])
flow_system = fx.FlowSystem(time=timesteps, periods=periods)
-# Components can now invest differently in each period
-solar = fx.Source(
- 'solar',
- outputs=[fx.Flow(
- 'P_el',
- bus='electricity',
- size=fx.InvestParameters(
- minimum_size=0,
- maximum_size=1000,
- effects_of_investment_per_size={'costs': 100}
- )
- )]
-)
+solar = fx.Source('solar', outputs=[fx.Flow('P_el', bus='electricity',
+ size=fx.InvestParameters(minimum_size=0, maximum_size=1000))])
```
-### 2. Scenario-Based Stochastic Optimization
-
-Model uncertainty with weighted scenarios:
-
-```python
-# Define scenarios with probabilities
-scenarios = pd.Index(['low_demand', 'base', 'high_demand'], name='scenario')
-scenario_weights = [0.2, 0.6, 0.2] # Probabilities
-
-flow_system = fx.FlowSystem(
- time=timesteps,
- scenarios=scenarios,
- scenario_weights=scenario_weights
-)
-
-# Define scenario-dependent data
-demand = xr.DataArray(
- data=[[70, 80, 90], # low_demand scenario
- [90, 100, 110], # base scenario
- [110, 120, 130]], # high_demand scenario
- dims=['scenario', 'time'],
- coords={'scenario': scenarios, 'time': timesteps}
-)
-
-```
+### Scenario-Based Stochastic Optimization
-**Control variable independence:**
```python
-# By default: investment sizes are shared across scenarios, flow rates vary
-# To make sizes scenario-independent:
-flow_system = fx.FlowSystem(
- time=timesteps,
- scenarios=scenarios,
- scenario_independent_sizes=True # Each scenario gets its own capacity
-)
+scenarios = pd.Index(['low', 'base', 'high'], name='scenario')
+flow_system = fx.FlowSystem(time=timesteps, scenarios=scenarios,
+ scenario_weights=[0.2, 0.6, 0.2],
+ scenario_independent_sizes=True) # Optional: scenario-specific capacities
```
-### 3. Enhanced I/O and Data Handling
+### Enhanced I/O
```python
-# Save and load FlowSystem
-flow_system.to_netcdf('my_system.nc')
-flow_system_loaded = fx.FlowSystem.from_netcdf('my_system.nc')
-
-# Manipulate FlowSystem
+flow_system.to_netcdf('system.nc')
+fs = fx.FlowSystem.from_netcdf('system.nc')
fs_subset = flow_system.sel(time=slice('2020-01', '2020-06'))
-fs_resampled = flow_system.resample(time='D') # Resample to daily
-fs_copy = flow_system.copy()
-
-# Access FlowSystem from results (lazily loaded)
-results = calculation.results
-original_fs = results.flow_system # No manual restoration needed
+fs_resampled = flow_system.resample(time='D')
```
-### 4. Effects Per Component
-
-Analyze the impact of each component, including indirect effects through effect shares:
+### Effects Per Component
```python
-# Get dataset showing contribution of each component to all effects
effects_ds = calculation.results.effects_per_component()
-
-print(effects_ds['costs']) # Total costs by component
-print(effects_ds['CO2']) # CO2 emissions by component (including indirect)
+print(effects_ds['costs']) # Costs by component
```
-### 5. Balanced Storage
-
-Force charging and discharging capacities to be equal:
+### Balanced Storage
```python
-storage = fx.Storage(
- 'storage',
- charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(effects_per_size=100, minimum_size=5)),
- discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(),
- balanced=True, # Ensures charge_size == discharge_size
- capacity_in_flow_hours=100
-)
-```
-
-### 6. Final Charge State Control
-
-Set bounds on the storage state at the end of the optimization:
-
-```python
-storage = fx.Storage(
- 'storage',
- charging=fx.Flow('charge', bus='electricity', size=100),
- discharging=fx.Flow('discharge', bus='electricity', size=100),
- capacity_in_flow_hours=10,
- relative_minimum_final_charge_state=0.5, # End at least 50% charged
- relative_maximum_final_charge_state=0.8 # End at most 80% charged
-)
+storage = fx.Storage('storage',
+ charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(...)),
+ discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(...)),
+ balanced=True, # Charge size == discharge size
+ capacity_in_flow_hours=100)
```
---
-## Configuration Changes
+## Common Issues
-### Logging (v2.2.0+)
+**"Effect share parameters not working"**
+→ Move shares to receiving effect using `share_from_temporal`/`share_from_periodic`
-**Breaking change:** Console and file logging are now disabled by default.
+**"Storage charge state has wrong dimensions"**
+→ Remove extra timestep; use `relative_minimum_final_charge_state`
-```python
-import flixopt as fx
+**"KeyError when accessing results"**
+→ Update variable names (`is_invested` → `invested`, etc.)
-# Enable console logging
-fx.CONFIG.Logging.console = True
-fx.CONFIG.Logging.level = 'INFO'
-fx.CONFIG.apply()
-
-# Enable file logging
-fx.CONFIG.Logging.file = 'flixopt.log'
-fx.CONFIG.apply()
-
-# Deprecated: change_logging_level() - will be removed in future
-# fx.change_logging_level('INFO') # ❌ Old way
-```
+**"No logging output"**
+→ Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
---
-## Testing Your Migration
-
-### 1. Check for Deprecation Warnings
-
-Run your code and watch for deprecation warnings:
-
-```python
-import warnings
-warnings.filterwarnings('default', category=DeprecationWarning)
-
-# Run your flixopt code
-# Review any DeprecationWarning messages
-```
-
-### 2. Validate Results
-
-Compare results from v2.x and v3.0.0 to ensure consistency:
-
-```python
-# Save v2.x results before upgrading
-calculation.results.to_file('results_v2.nc')
-
-# After upgrading, compare
-results_v3 = calculation.results
-results_v2 = fx.CalculationResults.from_file('results_v2.nc')
-
-# Check key variables match (within numerical tolerance)
-import numpy as np
-v2_costs = results_v2['effect_values'].sel(effect='costs')
-v3_costs = results_v3['effect_values'].sel(effect='costs')
-np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
-```
-
----
-
-## Common Migration Issues
-
-### Issue: "Effect share parameters not working"
-
-**Solution:** Effect sharing was completely redesigned. Move share definitions to the **receiving** effect using `share_from_temporal` and `share_from_periodic`.
-
-### Issue: "Storage charge state has wrong dimensions"
-
-**Solution:** Remove the extra timestep from charge state bound arrays.
-
-### Issue: "Import error with Bus assignment"
-
-**Solution:** Pass bus labels (strings) instead of Bus objects to `Flow.bus`.
-
-```python
-# Old
-my_bus = fx.Bus('electricity')
-flow = fx.Flow('P_el', bus=my_bus) # ❌
-
-# New
-my_bus = fx.Bus('electricity')
-flow = fx.Flow('P_el', bus='electricity') # ✅
-```
-
-### Issue: "AttributeError: module 'flixopt' has no attribute 'SystemModel'"
-
-**Solution:** Rename `SystemModel` → `FlowSystemModel`
-
-### Issue: "KeyError when accessing results variables"
-
-**Solution:** Variable names have changed. Update your result access:
-
-```python
-# Old variable names
-results.solution['component|is_invested'] # ❌
-results.solution['component|switch_on'] # ❌
-results.solution['component|switch_off'] # ❌
-results.solution['component|switch_on_nr'] # ❌
-
-# New variable names
-results.solution['component|invested'] # ✅
-results.solution['component|switch|on'] # ✅
-results.solution['component|switch|off'] # ✅
-results.solution['component|switch|count'] # ✅
-```
-
-### Issue: "FlowSystem changes affecting multiple calculations"
-
-**Solution:** FlowSystems are now automatically copied for each Calculation. If you need to access the FlowSystem from a calculation, use `calculation.flow_system` instead of keeping a reference to the original.
-
-### Issue: "No logging output"
-
-**Solution:** Logging is disabled by default in v2.2.0+. Enable it explicitly:
-
-```python
-import flixopt as fx
-fx.CONFIG.Logging.console = True
-fx.CONFIG.apply()
-```
-
----
-
-## Getting Help
-
-- **Documentation:** [https://flixopt.github.io/flixopt/](https://flixopt.github.io/flixopt/)
-- **GitHub Issues:** [https://github.com/flixOpt/flixopt/issues](https://github.com/flixOpt/flixopt/issues)
-- **Changelog:** [Full v3.0.0 release notes](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
-
----
-
-## Summary Checklist
-
-**Critical (Breaking Changes):**
+## Migration Checklist
+**Critical:**
- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update effect sharing syntax (no deprecation warning!) - move shares to receiving effect
-- [ ] Update all variable names in result access (`is_invested` → `invested`, `switch_on` → `switch|on`, etc.)
-- [ ] Replace Bus/Effect object assignments with string labels
-- [ ] Remove any code that relies on shared FlowSystem objects across Calculations
-- [ ] Update `Calculation.do_modeling()` usage if accessing return value
-- [ ] Fix storage charge state array dimensions (remove extra timestep)
-
-**Important:**
-
-- [ ] Rename `mode` → `style` in plotting calls
-- [ ] Enable logging explicitly if needed (`fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
-- [ ] Update deprecated parameter names (optional, but recommended)
-
-**Testing:**
-
-- [ ] Test your code thoroughly
-- [ ] Check for deprecation warnings
-- [ ] Validate results match v2.x output (if upgrading)
+- [ ] Update effect sharing syntax
+- [ ] Update result variable names
+- [ ] Replace object assignments with string labels
+- [ ] Fix storage charge state arrays
+- [ ] Update `do_modeling()` usage if needed
+- [ ] Rename plotting `mode` → `style`
+- [ ] Enable logging if needed
+
+**Recommended:**
+- [ ] Update deprecated parameter names
+- [ ] Test thoroughly and validate results
**Optional:**
-
-- [ ] Explore new features (periods, scenarios, enhanced I/O, balanced storage, final charge state control)
+- [ ] Explore new features (periods, scenarios, balanced storage)
**Welcome to flixopt v3.0.0!** 🎉
+---
+
+## Resources
+
+- **Docs:** https://flixopt.github.io/flixopt/latest/
+- **Issues:** https://github.com/flixOpt/flixopt/issues
+- **Changelog:** https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/
From 344cf92c659a6bdc6c1b3b8e2f54c0c4f7dd135e Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 10:46:54 +0200
Subject: [PATCH 04/42] Improve
---
CHANGELOG.md | 4 +-
docs/user-guide/migration-guide-v3.md | 73 ++++++++++++++++++++-------
2 files changed, 57 insertions(+), 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4b0da8ce..f8e4c7a55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -141,7 +141,9 @@ This replaces `specific_share_to_other_effects_*` parameters and inverts the dir
**API and Behavior Changes:**
-- **Effect sharing system redesigned** (no deprecation): The old `specific_share_to_other_effects_*` parameters were completely replaced with the new `share_from_temporal` and `share_from_periodic` syntax (see 🔥 Removed section)
+- **Effect system redesigned** (no deprecation):
+ - **Terminology changes**: Effect domains renamed for clarity: `operation` → `temporal`, `invest`/`investment` → `periodic`
+ - **Sharing system**: The old `specific_share_to_other_effects_*` parameters were completely replaced with the new `share_from_temporal` and `share_from_periodic` syntax (see 🔥 Removed section)
- **FlowSystem independence**: FlowSystems cannot be shared across multiple Calculations anymore. A copy of the FlowSystem is created instead, making every Calculation independent. Each Subcalculation in `SegmentedCalculation` now has its own distinct `FlowSystem` object
- **Bus and Effect object assignment**: Direct assignment of Bus/Effect objects is no longer supported. Use labels (strings) instead:
- `Flow.bus` must receive a string label, not a Bus object
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index f4b6a6d87..eca068ce1 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -14,16 +14,29 @@ Review breaking changes, update deprecated parameters, and test thoroughly.
## Breaking Changes
-### 1. Effect Sharing System Redesign
+### 1. Effect System Redesign
-⚠️ **No deprecation warning** - Effects now "pull" shares instead of "pushing" them.
+⚠️ **Multiple effect-related changes** - terminology and sharing system redesigned.
+
+**Terminology Changes:**
+
+Effect domains have been renamed for clarity:
+
+| Old Term (v2.x) | New Term (v3.0.0) | Meaning |
+|-----------------|-------------------|-------------------------------------------------------------------------|
+| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occuring over time) |
+| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
+
+**Effect Sharing System (⚠️ No deprecation warning):**
+
+Effects now "pull" shares from other effects instead of "pushing" them.
**v2.x:**
```python
CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
- specific_share_to_other_effects_operation={'costs': 0.2})
+ specific_share_to_other_effects_operation={'costs': 0.2}) # operation → temporal
land = fx.Effect('land', 'm²', 'Land usage',
- specific_share_to_other_effects_invest={'costs': 100})
+ specific_share_to_other_effects_invest={'costs': 100}) # invest → periodic
costs = fx.Effect('costs', '€', 'Total costs')
```
@@ -32,14 +45,18 @@ costs = fx.Effect('costs', '€', 'Total costs')
CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
land = fx.Effect('land', 'm²', 'Land usage')
costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}, # From temporal effects
- share_from_periodic={'land': 100}) # From periodic effects
+ share_from_temporal={'CO2': 0.2}, # Pulls from temporal effects
+ share_from_periodic={'land': 100}) # Pulls from periodic effects
```
**Migration:**
-- Move share definitions to receiving effect
-- `specific_share_to_other_effects_operation` → `share_from_temporal`
-- `specific_share_to_other_effects_invest` → `share_from_periodic`
+1. Move share definitions to the receiving effect
+2. Update parameter names:
+ - `specific_share_to_other_effects_operation` → `share_from_temporal`
+ - `specific_share_to_other_effects_invest` → `share_from_periodic`
+3. Update terminology throughout your code:
+ - Replace "operation" with "temporal" in effect-related contexts
+ - Replace "invest/investment" with "periodic" in effect-related contexts
---
@@ -59,26 +76,25 @@ costs = fx.Effect('costs', '€', 'Total costs',
---
-### 3. Use String Labels
+### 3. Bus and Effect Assignment - Use String Labels
Pass string labels instead of objects:
+**Bus Assignment:**
```python
-# Old: flow = fx.Flow('P_el', bus=my_bus)
+# Old: flow = fx.Flow('P_el', bus=my_bus_object)
# New: flow = fx.Flow('P_el', bus='electricity')
```
-Applies to Bus assignments and Effect share dictionaries.
-
----
-
-### 4. FlowSystem Independence
-
-Each `Calculation` now gets its own FlowSystem copy - calculations are fully independent.
+**Effect Shares:**
+```python
+# Old: costs = fx.Effect('costs', '€', share_from_temporal={CO2_object: 0.2})
+# New: costs = fx.Effect('costs', '€', share_from_temporal={'CO2': 0.2})
+```
---
-### 5. Storage Charge State Bounds
+### 4. Storage Charge State Bounds
Array length now matches timesteps (no extra element):
@@ -92,10 +108,29 @@ storage = fx.Storage(
---
+### 5. FlowSystem Independence
+
+Each `Calculation` now gets its own FlowSystem copy - calculations are fully independent.
+
+```python
+# v2.x: FlowSystem was shared across calculations
+flow_system = fx.FlowSystem(time=timesteps)
+calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
+calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
+
+# v3.0.0: Each calculation gets a copy
+flow_system = fx.FlowSystem(time=timesteps)
+calc1 = fx.FullCalculation('calc1', flow_system)
+calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
+```
+
+---
+
### 6. Other Breaking Changes
- **`do_modeling()` return value:** Now returns `Calculation` object (access model via `.model` property)
- **Plotting:** `mode` parameter renamed to `style`
+- **Class names:** `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
---
From fbac19149a36385a0b78664342f2d6ff04b25549 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 10:50:59 +0200
Subject: [PATCH 05/42] Use tabs in mkdocs
---
docs/user-guide/migration-guide-v3.md | 193 ++++++++++++++++++--------
1 file changed, 133 insertions(+), 60 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index eca068ce1..08e06dcaa 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -31,23 +31,25 @@ Effect domains have been renamed for clarity:
Effects now "pull" shares from other effects instead of "pushing" them.
-**v2.x:**
-```python
-CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
- specific_share_to_other_effects_operation={'costs': 0.2}) # operation → temporal
-land = fx.Effect('land', 'm²', 'Land usage',
- specific_share_to_other_effects_invest={'costs': 100}) # invest → periodic
-costs = fx.Effect('costs', '€', 'Total costs')
-```
-
-**v3.0.0:**
-```python
-CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
-land = fx.Effect('land', 'm²', 'Land usage')
-costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}, # Pulls from temporal effects
- share_from_periodic={'land': 100}) # Pulls from periodic effects
-```
+=== "v2.x (Old)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
+ specific_share_to_other_effects_operation={'costs': 0.2}) # operation → temporal
+ land = fx.Effect('land', 'm²', 'Land usage',
+ specific_share_to_other_effects_invest={'costs': 100}) # invest → periodic
+ costs = fx.Effect('costs', '€', 'Total costs')
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ land = fx.Effect('land', 'm²', 'Land usage')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}, # Pulls from temporal effects
+ share_from_periodic={'land': 100}) # Pulls from periodic effects
+ ```
**Migration:**
1. Move share definitions to the receiving effect
@@ -69,42 +71,96 @@ costs = fx.Effect('costs', '€', 'Total costs',
| `switch_off` | `switch\|off` |
| `switch_on_nr` | `switch\|count` |
-```python
-# Old: results.solution['component|is_invested']
-# New: results.solution['component|invested']
-```
+=== "v2.x (Old)"
+
+ ```python
+ # Access investment decision
+ results.solution['component|is_invested']
+
+ # Access switch tracking
+ results.solution['component|switch_on']
+ results.solution['component|switch_off']
+ results.solution['component|switch_on_nr']
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ # Access investment decision
+ results.solution['component|invested']
+
+ # Access switch tracking
+ results.solution['component|switch|on']
+ results.solution['component|switch|off']
+ results.solution['component|switch|count']
+ ```
---
### 3. Bus and Effect Assignment - Use String Labels
-Pass string labels instead of objects:
+Pass string labels instead of objects.
**Bus Assignment:**
-```python
-# Old: flow = fx.Flow('P_el', bus=my_bus_object)
-# New: flow = fx.Flow('P_el', bus='electricity')
-```
+
+=== "v2.x (Old)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+ ```
**Effect Shares:**
-```python
-# Old: costs = fx.Effect('costs', '€', share_from_temporal={CO2_object: 0.2})
-# New: costs = fx.Effect('costs', '€', share_from_temporal={'CO2': 0.2})
-```
+
+=== "v2.x (Old)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={CO2: 0.2}) # ❌ Object
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}) # ✅ String label
+ ```
---
### 4. Storage Charge State Bounds
-Array length now matches timesteps (no extra element):
+Array length now matches timesteps (no extra element).
-```python
-storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # Matches timesteps
- relative_minimum_final_charge_state=0.3 # New: control final state explicitly
-)
-```
+=== "v2.x (Old)"
+
+ ```python
+ # Array had extra timestep
+ storage = fx.Storage(
+ 'storage',
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 values for 4 timesteps
+ )
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ # Array matches timesteps exactly
+ storage = fx.Storage(
+ 'storage',
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
+ relative_minimum_final_charge_state=0.3 # New: control final state explicitly
+ )
+ ```
---
@@ -112,17 +168,25 @@ storage = fx.Storage(
Each `Calculation` now gets its own FlowSystem copy - calculations are fully independent.
-```python
-# v2.x: FlowSystem was shared across calculations
-flow_system = fx.FlowSystem(time=timesteps)
-calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
-calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
-
-# v3.0.0: Each calculation gets a copy
-flow_system = fx.FlowSystem(time=timesteps)
-calc1 = fx.FullCalculation('calc1', flow_system)
-calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
-```
+=== "v2.x (Old)"
+
+ ```python
+ # FlowSystem was shared across calculations
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
+ calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
+ # Changes in calc1's FlowSystem would affect calc2
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ # Each calculation gets a copy
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Gets copy
+ calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
+ # Calculations are now independent
+ ```
---
@@ -175,18 +239,27 @@ calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
### Calculation
Replace `active_timesteps` with FlowSystem selection:
-```python
-# Old: calculation = fx.FullCalculation('calc', flow_system, active_timesteps=[0, 1, 2])
-# New:
-fs_subset = flow_system.isel(time=slice(0, 3))
-calculation = fx.FullCalculation('calc', fs_subset)
-```
+
+=== "v2.x (Deprecated)"
+
+ ```python
+ calculation = fx.FullCalculation('calc', flow_system,
+ active_timesteps=[0, 1, 2])
+ ```
+
+=== "v3.0.0 (Recommended)"
+
+ ```python
+ # Use FlowSystem selection methods
+ fs_subset = flow_system.isel(time=slice(0, 3))
+ calculation = fx.FullCalculation('calc', fs_subset)
+ ```
---
## New Features
-### Multi-Period Investments
+**Multi-Period Investments** - Model transformation pathways with distinct decisions in each period:
```python
periods = pd.Index(['2020', '2030'])
@@ -196,7 +269,7 @@ solar = fx.Source('solar', outputs=[fx.Flow('P_el', bus='electricity',
size=fx.InvestParameters(minimum_size=0, maximum_size=1000))])
```
-### Scenario-Based Stochastic Optimization
+**Scenario-Based Stochastic Optimization** - Handle uncertainty with weighted scenarios:
```python
scenarios = pd.Index(['low', 'base', 'high'], name='scenario')
@@ -205,7 +278,7 @@ flow_system = fx.FlowSystem(time=timesteps, scenarios=scenarios,
scenario_independent_sizes=True) # Optional: scenario-specific capacities
```
-### Enhanced I/O
+**Enhanced I/O** - Save, load, and manipulate FlowSystems:
```python
flow_system.to_netcdf('system.nc')
@@ -214,14 +287,14 @@ fs_subset = flow_system.sel(time=slice('2020-01', '2020-06'))
fs_resampled = flow_system.resample(time='D')
```
-### Effects Per Component
+**Effects Per Component** - Analyze component impacts including indirect effects:
```python
effects_ds = calculation.results.effects_per_component()
print(effects_ds['costs']) # Costs by component
```
-### Balanced Storage
+**Balanced Storage** - Force equal charging and discharging capacities:
```python
storage = fx.Storage('storage',
From ef35d90b2ca0e96af4e5a6798eda5da5d9bfea3b Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 10:59:02 +0200
Subject: [PATCH 06/42] Update varaibel renaming
---
CHANGELOG.md | 3 ++
docs/user-guide/migration-guide-v3.md | 40 +++++++++++++++++++--------
2 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8e4c7a55..e0b44da77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -164,6 +164,9 @@ This replaces `specific_share_to_other_effects_*` parameters and inverts the dir
- `switch_on` → `switch|on`
- `switch_off` → `switch|off`
- `switch_on_nr` → `switch|count`
+- Effect submodel variables (following terminology changes):
+ - `Effect|nontemporal|...` → `Effect|periodic|...`
+ - `Effect|operation|...` → `Effect|temporal|...`
**Data Structure Changes:**
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 08e06dcaa..8d0eeef6c 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -64,35 +64,53 @@ Effects now "pull" shares from other effects instead of "pushing" them.
### 2. Variable Renaming in Results
-| Old (v2.x) | New (v3.0.0) |
-|------------|--------------|
-| `is_invested` | `invested` |
-| `switch_on` | `switch\|on` |
-| `switch_off` | `switch\|off` |
-| `switch_on_nr` | `switch\|count` |
+Multiple variables have been renamed following the terminology changes.
+
+**Quick Reference Table:**
+
+| Category | Old (v2.x) | New (v3.0.0) |
+|------------------|------------------------------------|----------------|
+| Investment | `is_invested` | `invested` |
+| Switch tracking | `switch_on` | `switch\|on` |
+| Switch tracking | `switch_off` | `switch\|off` |
+| Switch tracking | `switch_on_nr` | `switch\|count` |
+| Effect submodels | `Effect(invest)\|total` | `Effect(periodic)` |
+| Effect submodels | `Effect(operation)\|total` | `Effect(temporal)` |
+| Effect submodels | `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_tiemstep` |
+| Effect submodels | `Effect\|total` | `Effect` |
+
+**Examples:**
=== "v2.x (Old)"
```python
- # Access investment decision
+ # Investment decision
results.solution['component|is_invested']
- # Access switch tracking
+ # Switch tracking
results.solution['component|switch_on']
results.solution['component|switch_off']
results.solution['component|switch_on_nr']
+
+ # Effect variables (operation → temporal, nontemporal → periodic)
+ results.solution['costs|nontemporal|total']
+ results.solution['costs|operation|total']
```
=== "v3.0.0 (New)"
```python
- # Access investment decision
+ # Investment decision
results.solution['component|invested']
- # Access switch tracking
+ # Switch tracking
results.solution['component|switch|on']
results.solution['component|switch|off']
results.solution['component|switch|count']
+
+ # Effect variables (with new terminology)
+ results.solution['costs|periodic|total']
+ results.solution['costs|temporal|total']
```
---
@@ -158,7 +176,7 @@ Array length now matches timesteps (no extra element).
storage = fx.Storage(
'storage',
relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
- relative_minimum_final_charge_state=0.3 # New: control final state explicitly
+ #relative_minimum_final_charge_state=0.3 # New: control final state explicitly if its different from the last value above
)
```
From 9f50ca243d695786d6cb011f597c80f465fa70db Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:00:51 +0200
Subject: [PATCH 07/42] Update variable renaming
---
CHANGELOG.md | 6 ++++--
docs/user-guide/migration-guide-v3.md | 22 ++++++++++++++++------
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e0b44da77..c10105538 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -165,8 +165,10 @@ This replaces `specific_share_to_other_effects_*` parameters and inverts the dir
- `switch_off` → `switch|off`
- `switch_on_nr` → `switch|count`
- Effect submodel variables (following terminology changes):
- - `Effect|nontemporal|...` → `Effect|periodic|...`
- - `Effect|operation|...` → `Effect|temporal|...`
+ - `Effect(invest)|total` → `Effect(periodic)`
+ - `Effect(operation)|total` → `Effect(temporal)`
+ - `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
+ - `Effect|total` → `Effect`
**Data Structure Changes:**
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 8d0eeef6c..2b0d3ebe9 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -92,9 +92,11 @@ Multiple variables have been renamed following the terminology changes.
results.solution['component|switch_off']
results.solution['component|switch_on_nr']
- # Effect variables (operation → temporal, nontemporal → periodic)
- results.solution['costs|nontemporal|total']
- results.solution['costs|operation|total']
+ # Effect variables
+ results.solution['costs(invest)|total']
+ results.solution['costs(operation)|total']
+ results.solution['costs(operation)|total_per_timestep']
+ results.solution['costs|total']
```
=== "v3.0.0 (New)"
@@ -109,8 +111,10 @@ Multiple variables have been renamed following the terminology changes.
results.solution['component|switch|count']
# Effect variables (with new terminology)
- results.solution['costs|periodic|total']
- results.solution['costs|temporal|total']
+ results.solution['costs(periodic)']
+ results.solution['costs(temporal)']
+ results.solution['costs(temporal)|per_timestep']
+ results.solution['costs']
```
---
@@ -333,7 +337,13 @@ storage = fx.Storage('storage',
→ Remove extra timestep; use `relative_minimum_final_charge_state`
**"KeyError when accessing results"**
-→ Update variable names (`is_invested` → `invested`, etc.)
+→ Update variable names:
+ - `is_invested` → `invested`
+ - `switch_on` → `switch|on`, `switch_off` → `switch|off`, `switch_on_nr` → `switch|count`
+ - `Effect(invest)|total` → `Effect(periodic)`
+ - `Effect(operation)|total` → `Effect(temporal)`
+ - `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
+ - `Effect|total` → `Effect`
**"No logging output"**
→ Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
From cd3df05bc2093c11649083ecf85c3452389da6a9 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:22:19 +0200
Subject: [PATCH 08/42] From main
---
docs/user-guide/migration-guide-v3.md | 458 +++++++++++++++++++-------
1 file changed, 332 insertions(+), 126 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 2b0d3ebe9..0ba6f8114 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -1,24 +1,18 @@
-# Migration Guide: Upgrading to v3.0.0
+# Migration Guide: v2.x → v3.0.0
Quick guide for migrating flixopt from v2.x to v3.0.0.
-## Quick Start
-
-```bash
-pip install --upgrade flixopt
-```
-
-Review breaking changes, update deprecated parameters, and test thoroughly.
+!!! tip "Quick Start"
+ ```bash
+ pip install --upgrade flixopt
+ ```
+ Review breaking changes below, update deprecated parameters, and test thoroughly.
---
## Breaking Changes
-### 1. Effect System Redesign
-
-⚠️ **Multiple effect-related changes** - terminology and sharing system redesigned.
-
-**Terminology Changes:**
+**Effect System Redesign** - terminology and sharing system redesigned.
Effect domains have been renamed for clarity:
@@ -27,8 +21,6 @@ Effect domains have been renamed for clarity:
| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occuring over time) |
| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
-**Effect Sharing System (⚠️ No deprecation warning):**
-
Effects now "pull" shares from other effects instead of "pushing" them.
=== "v2.x (Old)"
@@ -62,24 +54,20 @@ Effects now "pull" shares from other effects instead of "pushing" them.
---
-### 2. Variable Renaming in Results
-
-Multiple variables have been renamed following the terminology changes.
+**Variable Renaming in Results**
-**Quick Reference Table:**
+Multiple variables renamed following terminology changes.
| Category | Old (v2.x) | New (v3.0.0) |
|------------------|------------------------------------|----------------|
| Investment | `is_invested` | `invested` |
-| Switch tracking | `switch_on` | `switch\|on` |
-| Switch tracking | `switch_off` | `switch\|off` |
-| Switch tracking | `switch_on_nr` | `switch\|count` |
-| Effect submodels | `Effect(invest)\|total` | `Effect(periodic)` |
-| Effect submodels | `Effect(operation)\|total` | `Effect(temporal)` |
-| Effect submodels | `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_tiemstep` |
-| Effect submodels | `Effect\|total` | `Effect` |
-
-**Examples:**
+| Switch tracking | `switch_on` | `switch|on` |
+| Switch tracking | `switch_off` | `switch|off` |
+| Switch tracking | `switch_on_nr` | `switch|count` |
+| Effect submodels | `Effect(invest)|total` | `Effect(periodic)` |
+| Effect submodels | `Effect(operation)|total` | `Effect(temporal)` |
+| Effect submodels | `Effect(operation)|total_per_timestep` | `Effect(temporal)|per_timestep` |
+| Effect submodels | `Effect|total` | `Effect` |
=== "v2.x (Old)"
@@ -119,76 +107,83 @@ Multiple variables have been renamed following the terminology changes.
---
-### 3. Bus and Effect Assignment - Use String Labels
-
-Pass string labels instead of objects.
-
-**Bus Assignment:**
+**Calculation API** - `do_modeling()` now returns `Calculation` object for method chaining
=== "v2.x (Old)"
```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ linopy_model = calculation.do_modeling() # Returned linopy.Model
+
+ # Access model directly from return value
+ print(linopy_model)
```
=== "v3.0.0 (New)"
```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ calculation.do_modeling() # Returns Calculation object
+ linopy_model = calculation.model # Access model via property
+
+ # This enables chaining operations
+ fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
```
-**Effect Shares:**
+---
+
+**Storage Charge State** - Arrays no longer have extra timestep
=== "v2.x (Old)"
```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={CO2: 0.2}) # ❌ Object
+ # Array with extra timestep
+ storage = fx.Storage(
+ 'storage',
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 values for 4 timesteps
+ )
```
=== "v3.0.0 (New)"
```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}) # ✅ String label
+ # Array matches timesteps
+ storage = fx.Storage(
+ 'storage',
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
+ relative_minimum_final_charge_state=0.3 # Specify the final value directly
+ )
```
---
-### 4. Storage Charge State Bounds
-
-Array length now matches timesteps (no extra element).
+**Bus and Effect Assignment** - Use string labels instead of objects
=== "v2.x (Old)"
```python
- # Array had extra timestep
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 values for 4 timesteps
- )
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
+
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={CO2: 0.2}) # ❌ Object
```
=== "v3.0.0 (New)"
```python
- # Array matches timesteps exactly
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
- #relative_minimum_final_charge_state=0.3 # New: control final state explicitly if its different from the last value above
- )
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}) # ✅ String label
```
---
-### 5. FlowSystem Independence
-
-Each `Calculation` now gets its own FlowSystem copy - calculations are fully independent.
+**FlowSystem Independence** - Each Calculation gets its own copy
=== "v2.x (Old)"
@@ -212,30 +207,54 @@ Each `Calculation` now gets its own FlowSystem copy - calculations are fully ind
---
-### 6. Other Breaking Changes
+**Other Breaking Changes:**
-- **`do_modeling()` return value:** Now returns `Calculation` object (access model via `.model` property)
- **Plotting:** `mode` parameter renamed to `style`
- **Class names:** `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
---
-## Deprecated Parameters (Still Work)
+## Deprecated Parameters
+
+!!! info "Still Work"
+ These parameters still work but will be removed in a future version. Deprecation warnings will guide you.
-### InvestParameters
+**InvestParameters:**
-| Old | New |
-|-----|-----|
+| Old Parameter (v2.x) | New Parameter (v3.0.0) |
+|---------------------|----------------------|
| `fix_effects` | `effects_of_investment` |
| `specific_effects` | `effects_of_investment_per_size` |
| `divest_effects` | `effects_of_retirement` |
| `piecewise_effects` | `piecewise_effects_of_investment` |
-### Effect
+=== "v2.x (Deprecated)"
+
+ ```python
+ fx.InvestParameters(
+ fix_effects=1000,
+ specific_effects={'costs': 10},
+ divest_effects=100,
+ piecewise_effects=my_piecewise,
+ )
+ ```
+
+=== "v3.0.0 (Recommended)"
+
+ ```python
+ fx.InvestParameters(
+ effects_of_investment=1000,
+ effects_of_investment_per_size={'costs': 10},
+ effects_of_retirement=100,
+ piecewise_effects_of_investment=my_piecewise,
+ )
+ ```
+
+**Effect:**
-| Old | New |
-|-----|-----|
+| Old Parameter (v2.x) | New Parameter (v3.0.0) |
+|---------------------|----------------------|
| `minimum_investment` | `minimum_periodic` |
| `maximum_investment` | `maximum_periodic` |
| `minimum_operation` | `minimum_temporal` |
@@ -243,87 +262,265 @@ Each `Calculation` now gets its own FlowSystem copy - calculations are fully ind
| `minimum_operation_per_hour` | `minimum_per_hour` |
| `maximum_operation_per_hour` | `maximum_per_hour` |
-### SourceAndSink
+=== "v2.x (Deprecated)"
+
+ ```python
+ fx.Effect(
+ 'my_effect', 'unit', 'description',
+ minimum_investment=10,
+ maximum_investment=100,
+ minimum_operation=5,
+ maximum_operation=50,
+ minimum_operation_per_hour=1,
+ maximum_operation_per_hour=10,
+ )
+ ```
+
+=== "v3.0.0 (Recommended)"
+
+ ```python
+ fx.Effect(
+ 'my_effect', 'unit', 'description',
+ minimum_periodic=10,
+ maximum_periodic=100,
+ minimum_temporal=5,
+ maximum_temporal=50,
+ minimum_per_hour=1,
+ maximum_per_hour=10,
+ )
+ ```
-| Old | New |
-|-----|-----|
-| `source` | `outputs` |
-| `sink` | `inputs` |
-| `prevent_simultaneous_sink_and_source` | `prevent_simultaneous_flow_rates` |
+**Component Parameters:**
-### TimeSeriesData
+=== "v2.x (Deprecated)"
-| Old | New |
-|-----|-----|
-| `agg_group` | `aggregation_group` |
-| `agg_weight` | `aggregation_weight` |
+ ```python
+ fx.Source('my_source', source=flow)
-### Calculation
+ fx.Sink('my_sink', sink=flow)
-Replace `active_timesteps` with FlowSystem selection:
+ fx.SourceAndSink(
+ 'my_source_sink',
+ source=flow1,
+ sink=flow2,
+ prevent_simultaneous_sink_and_source=True
+ )
+ ```
+
+=== "v3.0.0 (Recommended)"
+
+ ```python
+ fx.Source('my_source', outputs=flow)
+
+ fx.Sink('my_sink', inputs=flow)
+
+ fx.SourceAndSink(
+ 'my_source_sink',
+ outputs=flow1,
+ inputs=flow2,
+ prevent_simultaneous_flow_rates=True
+ )
+ ```
+
+**TimeSeriesData:**
=== "v2.x (Deprecated)"
```python
- calculation = fx.FullCalculation('calc', flow_system,
- active_timesteps=[0, 1, 2])
+ fx.TimeSeriesData(
+ agg_group='group1',
+ agg_weight=2.0
+ )
+ ```
+
+=== "v3.0.0 (Recommended)"
+
+ ```python
+ fx.TimeSeriesData(
+ aggregation_group='group1',
+ aggregation_weight=2.0
+ )
+ ```
+
+**Calculation:**
+
+=== "v2.x (Deprecated)"
+
+ ```python
+ calculation = fx.FullCalculation(
+ 'calc',
+ flow_system,
+ active_timesteps=[0, 1, 2]
+ )
```
=== "v3.0.0 (Recommended)"
```python
# Use FlowSystem selection methods
- fs_subset = flow_system.isel(time=slice(0, 3))
- calculation = fx.FullCalculation('calc', fs_subset)
+ flow_system_subset = flow_system.sel(time=slice('2020-01-01', '2020-01-03'))
+ calculation = fx.FullCalculation('calc', flow_system_subset)
+
+ # Or with isel for index-based selection
+ flow_system_subset = flow_system.isel(time=slice(0, 3))
+ calculation = fx.FullCalculation('calc', flow_system_subset)
```
---
## New Features
-**Multi-Period Investments** - Model transformation pathways with distinct decisions in each period:
+**Multi-Period Investments** - Model transformation pathways with distinct decisions per period:
```python
+import pandas as pd
+
+# Define multiple investment periods
periods = pd.Index(['2020', '2030'])
flow_system = fx.FlowSystem(time=timesteps, periods=periods)
-solar = fx.Source('solar', outputs=[fx.Flow('P_el', bus='electricity',
- size=fx.InvestParameters(minimum_size=0, maximum_size=1000))])
+# Components can now invest differently in each period
+solar = fx.Source(
+ 'solar',
+ outputs=[fx.Flow(
+ 'P_el',
+ bus='electricity',
+ size=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=1000,
+ effects_of_investment_per_size={'costs': 100}
+ )
+ )]
+)
```
-**Scenario-Based Stochastic Optimization** - Handle uncertainty with weighted scenarios:
+**Scenario-Based Stochastic Optimization** - Model uncertainty with weighted scenarios:
```python
-scenarios = pd.Index(['low', 'base', 'high'], name='scenario')
-flow_system = fx.FlowSystem(time=timesteps, scenarios=scenarios,
- scenario_weights=[0.2, 0.6, 0.2],
- scenario_independent_sizes=True) # Optional: scenario-specific capacities
+# Define scenarios with probabilities
+scenarios = pd.Index(['low_demand', 'base', 'high_demand'], name='scenario')
+scenario_weights = [0.2, 0.6, 0.2] # Probabilities
+
+flow_system = fx.FlowSystem(
+ time=timesteps,
+ scenarios=scenarios,
+ scenario_weights=scenario_weights
+)
+
+# Define scenario-dependent data
+demand = xr.DataArray(
+ data=[[70, 80, 90], # low_demand scenario
+ [90, 100, 110], # base scenario
+ [110, 120, 130]], # high_demand scenario
+ dims=['scenario', 'time'],
+ coords={'scenario': scenarios, 'time': timesteps}
+)
+
```
**Enhanced I/O** - Save, load, and manipulate FlowSystems:
```python
-flow_system.to_netcdf('system.nc')
-fs = fx.FlowSystem.from_netcdf('system.nc')
+# Save and load FlowSystem
+flow_system.to_netcdf('my_system.nc')
+flow_system_loaded = fx.FlowSystem.from_netcdf('my_system.nc')
+
+# Manipulate FlowSystem
fs_subset = flow_system.sel(time=slice('2020-01', '2020-06'))
-fs_resampled = flow_system.resample(time='D')
+fs_resampled = flow_system.resample(time='D') # Resample to daily
+fs_copy = flow_system.copy()
+
+# Access FlowSystem from results (lazily loaded)
+results = calculation.results
+original_fs = results.flow_system # No manual restoration needed
```
**Effects Per Component** - Analyze component impacts including indirect effects:
```python
+# Get dataset showing contribution of each component to all effects
effects_ds = calculation.results.effects_per_component()
-print(effects_ds['costs']) # Costs by component
+
+print(effects_ds['costs']) # Total costs by component
+print(effects_ds['CO2']) # CO2 emissions by component (including indirect)
+```
+
+**Balanced Storage** - Force equal charging/discharging capacities:
+
+```python
+storage = fx.Storage(
+ 'storage',
+ charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(effects_per_size=100, minimum_size=5)),
+ discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(),
+ balanced=True, # Ensures charge_size == discharge_size
+ capacity_in_flow_hours=100
+)
```
-**Balanced Storage** - Force equal charging and discharging capacities:
+**Final Charge State Control** - Set bounds on storage end state:
```python
-storage = fx.Storage('storage',
- charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(...)),
- discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(...)),
- balanced=True, # Charge size == discharge size
- capacity_in_flow_hours=100)
+storage = fx.Storage(
+ 'storage',
+ charging=fx.Flow('charge', bus='electricity', size=100),
+ discharging=fx.Flow('discharge', bus='electricity', size=100),
+ capacity_in_flow_hours=10,
+ relative_minimum_final_charge_state=0.5, # End at least 50% charged
+ relative_maximum_final_charge_state=0.8 # End at most 80% charged
+)
+```
+
+---
+
+## Configuration
+
+**Logging (v2.2.0+)** - Console and file logging now disabled by default:
+
+```python
+import flixopt as fx
+
+# Enable console logging
+fx.CONFIG.Logging.console = True
+fx.CONFIG.Logging.level = 'INFO'
+fx.CONFIG.apply()
+
+# Enable file logging
+fx.CONFIG.Logging.file = 'flixopt.log'
+fx.CONFIG.apply()
+
+# Deprecated: change_logging_level() - will be removed in future
+# fx.change_logging_level('INFO') # ❌ Old way
+```
+
+---
+
+## Testing
+
+**Check for Deprecation Warnings:**
+
+```python
+import warnings
+warnings.filterwarnings('default', category=DeprecationWarning)
+
+# Run your flixopt code
+# Review any DeprecationWarning messages
+```
+
+**Validate Results:**
+
+```python
+# Save v2.x results before upgrading
+calculation.results.to_file('results_v2.nc')
+
+# After upgrading, compare
+results_v3 = calculation.results
+results_v2 = fx.CalculationResults.from_file('results_v2.nc')
+
+# Check key variables match (within numerical tolerance)
+import numpy as np
+v2_costs = results_v2['effect_values'].sel(effect='costs')
+v3_costs = results_v3['effect_values'].sel(effect='costs')
+np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
```
---
@@ -336,6 +533,19 @@ storage = fx.Storage('storage',
**"Storage charge state has wrong dimensions"**
→ Remove extra timestep; use `relative_minimum_final_charge_state`
+**"Bus assignment error"**
+→ Use string labels instead of Bus objects:
+
+```python
+# Old
+my_bus = fx.Bus('electricity')
+flow = fx.Flow('P_el', bus=my_bus) # ❌
+
+# New
+my_bus = fx.Bus('electricity')
+flow = fx.Flow('P_el', bus='electricity') # ✅
+```
+
**"KeyError when accessing results"**
→ Update variable names:
- `is_invested` → `invested`
@@ -345,35 +555,31 @@ storage = fx.Storage('storage',
- `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
- `Effect|total` → `Effect`
+**"AttributeError: SystemModel"**
+→ Rename `SystemModel` → `FlowSystemModel`
+
**"No logging output"**
→ Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
---
-## Migration Checklist
+## Checklist
-**Critical:**
- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update effect sharing syntax
-- [ ] Update result variable names
-- [ ] Replace object assignments with string labels
-- [ ] Fix storage charge state arrays
-- [ ] Update `do_modeling()` usage if needed
-- [ ] Rename plotting `mode` → `style`
-- [ ] Enable logging if needed
+- [ ] Update effect sharing syntax (no deprecation warning!)
+- [ ] Update `Calculation.do_modeling()` usage
+- [ ] Fix storage charge state array dimensions
+- [ ] Rename `mode` → `style` in plotting calls
+- [ ] Update deprecated parameter names (optional, but recommended)
+- [ ] Enable logging explicitly if needed
+- [ ] Test your code thoroughly
+- [ ] Explore new features (periods, scenarios, enhanced I/O)
-**Recommended:**
-- [ ] Update deprecated parameter names
-- [ ] Test thoroughly and validate results
-
-**Optional:**
-- [ ] Explore new features (periods, scenarios, balanced storage)
-
-**Welcome to flixopt v3.0.0!** 🎉
---
-## Resources
+**Resources:**
+[Documentation](https://flixopt.github.io/flixopt/) •
+[GitHub Issues](https://github.com/flixOpt/flixopt/issues) •
+[Full Changelog](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
-- **Docs:** https://flixopt.github.io/flixopt/latest/
-- **Issues:** https://github.com/flixOpt/flixopt/issues
-- **Changelog:** https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/
+**Welcome to flixopt v3.0.0!** 🎉
From 9390fcd9f5a6164ff55cbefd1c951f998e1c79e2 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:27:03 +0200
Subject: [PATCH 09/42] Update
---
docs/user-guide/migration-guide-v3.md | 443 ++++++++++++++------------
1 file changed, 237 insertions(+), 206 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 0ba6f8114..cae28228a 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -6,73 +6,67 @@ Quick guide for migrating flixopt from v2.x to v3.0.0.
```bash
pip install --upgrade flixopt
```
- Review breaking changes below, update deprecated parameters, and test thoroughly.
+ Review breaking changes, update deprecated parameters, and test thoroughly.
---
## Breaking Changes
-**Effect System Redesign** - terminology and sharing system redesigned.
+### Effect System Redesign
-Effect domains have been renamed for clarity:
+Effect domains renamed and sharing system inverted (no deprecation warnings).
-| Old Term (v2.x) | New Term (v3.0.0) | Meaning |
-|-----------------|-------------------|-------------------------------------------------------------------------|
-| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occuring over time) |
-| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
+**Terminology changes:**
-Effects now "pull" shares from other effects instead of "pushing" them.
+| Old (v2.x) | New (v3.0.0) | Meaning |
+|------------|--------------|---------|
+| `operation` | `temporal` | Time-varying effects (operational costs, emissions) |
+| `invest`/`investment` | `periodic` | Investment effects (fixed costs per period) |
-=== "v2.x (Old)"
+**Sharing system:** Effects now "pull" shares instead of "pushing" them.
+=== "v2.x"
```python
CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
- specific_share_to_other_effects_operation={'costs': 0.2}) # operation → temporal
+ specific_share_to_other_effects_operation={'costs': 0.2})
land = fx.Effect('land', 'm²', 'Land usage',
- specific_share_to_other_effects_invest={'costs': 100}) # invest → periodic
+ specific_share_to_other_effects_invest={'costs': 100})
costs = fx.Effect('costs', '€', 'Total costs')
```
-=== "v3.0.0 (New)"
-
+=== "v3.0.0"
```python
CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
land = fx.Effect('land', 'm²', 'Land usage')
costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}, # Pulls from temporal effects
- share_from_periodic={'land': 100}) # Pulls from periodic effects
+ share_from_temporal={'CO2': 0.2}, # Pulls from temporal
+ share_from_periodic={'land': 100}) # Pulls from periodic
```
-**Migration:**
-1. Move share definitions to the receiving effect
-2. Update parameter names:
- - `specific_share_to_other_effects_operation` → `share_from_temporal`
- - `specific_share_to_other_effects_invest` → `share_from_periodic`
-3. Update terminology throughout your code:
- - Replace "operation" with "temporal" in effect-related contexts
- - Replace "invest/investment" with "periodic" in effect-related contexts
+!!! success "Migration Steps"
+ 1. Move share definitions to receiving effect
+ 2. Rename: `specific_share_to_other_effects_operation` → `share_from_temporal`
+ 3. Rename: `specific_share_to_other_effects_invest` → `share_from_periodic`
+ 4. Replace "operation" → "temporal" and "invest/investment" → "periodic" throughout
---
-**Variable Renaming in Results**
-
-Multiple variables renamed following terminology changes.
+### Variable Names in Results
-| Category | Old (v2.x) | New (v3.0.0) |
-|------------------|------------------------------------|----------------|
-| Investment | `is_invested` | `invested` |
-| Switch tracking | `switch_on` | `switch|on` |
-| Switch tracking | `switch_off` | `switch|off` |
-| Switch tracking | `switch_on_nr` | `switch|count` |
-| Effect submodels | `Effect(invest)|total` | `Effect(periodic)` |
-| Effect submodels | `Effect(operation)|total` | `Effect(temporal)` |
-| Effect submodels | `Effect(operation)|total_per_timestep` | `Effect(temporal)|per_timestep` |
-| Effect submodels | `Effect|total` | `Effect` |
-
-=== "v2.x (Old)"
+| Category | Old (v2.x) | New (v3.0.0) |
+|----------|------------|--------------|
+| Investment | `is_invested` | `invested` |
+| Switch tracking | `switch_on` | `switch\|on` |
+| Switch tracking | `switch_off` | `switch\|off` |
+| Switch tracking | `switch_on_nr` | `switch\|count` |
+| Effect submodels | `Effect(invest)\|total` | `Effect(periodic)` |
+| Effect submodels | `Effect(operation)\|total` | `Effect(temporal)` |
+| Effect submodels | `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_timestep` |
+| Effect submodels | `Effect\|total` | `Effect` |
+=== "v2.x"
```python
- # Investment decision
+ # Investment
results.solution['component|is_invested']
# Switch tracking
@@ -80,17 +74,16 @@ Multiple variables renamed following terminology changes.
results.solution['component|switch_off']
results.solution['component|switch_on_nr']
- # Effect variables
+ # Effects
results.solution['costs(invest)|total']
results.solution['costs(operation)|total']
results.solution['costs(operation)|total_per_timestep']
results.solution['costs|total']
```
-=== "v3.0.0 (New)"
-
+=== "v3.0.0"
```python
- # Investment decision
+ # Investment
results.solution['component|invested']
# Switch tracking
@@ -98,7 +91,7 @@ Multiple variables renamed following terminology changes.
results.solution['component|switch|off']
results.solution['component|switch|count']
- # Effect variables (with new terminology)
+ # Effects
results.solution['costs(periodic)']
results.solution['costs(temporal)']
results.solution['costs(temporal)|per_timestep']
@@ -107,130 +100,158 @@ Multiple variables renamed following terminology changes.
---
-**Calculation API** - `do_modeling()` now returns `Calculation` object for method chaining
+### Bus and Effect Assignment
-=== "v2.x (Old)"
+Use string labels instead of object references.
+=== "v2.x"
```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- linopy_model = calculation.do_modeling() # Returned linopy.Model
+ # Bus assignment
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
- # Access model directly from return value
- print(linopy_model)
+ # Effect shares
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={CO2: 0.2}) # ❌ Object
+ ```
+
+=== "v3.0.0"
+ ```python
+ # Bus assignment
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus='electricity') # ✅ String
+
+ # Effect shares
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}) # ✅ String
```
-=== "v3.0.0 (New)"
+---
+
+### FlowSystem Independence
+Each Calculation now receives its own FlowSystem copy.
+
+=== "v2.x"
```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- calculation.do_modeling() # Returns Calculation object
- linopy_model = calculation.model # Access model via property
+ # FlowSystem was shared
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
+ calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
+ # Changes in calc1's FlowSystem would affect calc2
+ ```
- # This enables chaining operations
- fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
+=== "v3.0.0"
+ ```python
+ # Each calculation gets a copy
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system)
+ calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
+ # Calculations are now independent
```
---
-**Storage Charge State** - Arrays no longer have extra timestep
+### Storage Charge State
-=== "v2.x (Old)"
+Arrays now match timestep count (no extra element).
+=== "v2.x"
```python
# Array with extra timestep
storage = fx.Storage(
'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 values for 4 timesteps
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 for 4 timesteps
)
```
-=== "v3.0.0 (New)"
-
+=== "v3.0.0"
```python
# Array matches timesteps
storage = fx.Storage(
'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
- relative_minimum_final_charge_state=0.3 # Specify the final value directly
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 for 4 timesteps
+ relative_minimum_final_charge_state=0.3 # Control final state explicitly
)
```
---
-**Bus and Effect Assignment** - Use string labels instead of objects
+### Calculation API
-=== "v2.x (Old)"
+`do_modeling()` now returns Calculation object for method chaining.
+=== "v2.x"
```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ linopy_model = calculation.do_modeling() # Returned linopy.Model
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={CO2: 0.2}) # ❌ Object
+ # Access model directly from return value
+ print(linopy_model)
```
-=== "v3.0.0 (New)"
-
+=== "v3.0.0"
```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ calculation.do_modeling() # Returns Calculation object
+ linopy_model = calculation.model # Access model via property
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}) # ✅ String label
+ # Enables method chaining
+ fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
```
---
-**FlowSystem Independence** - Each Calculation gets its own copy
-
-=== "v2.x (Old)"
+### Other Breaking Changes
+=== "Plotting"
```python
- # FlowSystem was shared across calculations
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
- calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
- # Changes in calc1's FlowSystem would affect calc2
- ```
+ # v2.x
+ results.plot_heatmap('component|variable', mode='line')
-=== "v3.0.0 (New)"
+ # v3.0.0
+ results.plot_heatmap('component|variable', style='line')
+ ```
+=== "Class Names"
```python
- # Each calculation gets a copy
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Gets copy
- calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
- # Calculations are now independent
- ```
+ # v2.x
+ from flixopt import SystemModel, Model
----
+ # v3.0.0
+ from flixopt import FlowSystemModel, Submodel
+ ```
-**Other Breaking Changes:**
+=== "Logging"
+ ```python
+ # v2.x - enabled by default
+ # (no explicit configuration needed)
-- **Plotting:** `mode` parameter renamed to `style`
-- **Class names:** `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
-- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
+ # v3.0.0 - disabled by default
+ import flixopt as fx
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.apply()
+ ```
---
## Deprecated Parameters
-!!! info "Still Work"
- These parameters still work but will be removed in a future version. Deprecation warnings will guide you.
+!!! info "Still Supported"
+ These parameters still work but will be removed in a future version. Deprecation warnings guide migration.
-**InvestParameters:**
+### InvestParameters
-| Old Parameter (v2.x) | New Parameter (v3.0.0) |
-|---------------------|----------------------|
+| Old (v2.x) | New (v3.0.0) |
+|------------|--------------|
| `fix_effects` | `effects_of_investment` |
| `specific_effects` | `effects_of_investment_per_size` |
| `divest_effects` | `effects_of_retirement` |
| `piecewise_effects` | `piecewise_effects_of_investment` |
=== "v2.x (Deprecated)"
-
```python
fx.InvestParameters(
fix_effects=1000,
@@ -241,7 +262,6 @@ Multiple variables renamed following terminology changes.
```
=== "v3.0.0 (Recommended)"
-
```python
fx.InvestParameters(
effects_of_investment=1000,
@@ -251,10 +271,12 @@ Multiple variables renamed following terminology changes.
)
```
-**Effect:**
+---
+
+### Effect
-| Old Parameter (v2.x) | New Parameter (v3.0.0) |
-|---------------------|----------------------|
+| Old (v2.x) | New (v3.0.0) |
+|------------|--------------|
| `minimum_investment` | `minimum_periodic` |
| `maximum_investment` | `maximum_periodic` |
| `minimum_operation` | `minimum_temporal` |
@@ -263,7 +285,6 @@ Multiple variables renamed following terminology changes.
| `maximum_operation_per_hour` | `maximum_per_hour` |
=== "v2.x (Deprecated)"
-
```python
fx.Effect(
'my_effect', 'unit', 'description',
@@ -277,7 +298,6 @@ Multiple variables renamed following terminology changes.
```
=== "v3.0.0 (Recommended)"
-
```python
fx.Effect(
'my_effect', 'unit', 'description',
@@ -290,10 +310,17 @@ Multiple variables renamed following terminology changes.
)
```
-**Component Parameters:**
+---
-=== "v2.x (Deprecated)"
+### Component Parameters
+| Old (v2.x) | New (v3.0.0) |
+|------------|--------------|
+| `source` (parameter) | `outputs` |
+| `sink` (parameter) | `inputs` |
+| `prevent_simultaneous_sink_and_source` | `prevent_simultaneous_flow_rates` |
+
+=== "v2.x (Deprecated)"
```python
fx.Source('my_source', source=flow)
@@ -308,7 +335,6 @@ Multiple variables renamed following terminology changes.
```
=== "v3.0.0 (Recommended)"
-
```python
fx.Source('my_source', outputs=flow)
@@ -322,10 +348,16 @@ Multiple variables renamed following terminology changes.
)
```
-**TimeSeriesData:**
+---
+
+### TimeSeriesData
-=== "v2.x (Deprecated)"
+| Old (v2.x) | New (v3.0.0) |
+|------------|--------------|
+| `agg_group` | `aggregation_group` |
+| `agg_weight` | `aggregation_weight` |
+=== "v2.x (Deprecated)"
```python
fx.TimeSeriesData(
agg_group='group1',
@@ -334,7 +366,6 @@ Multiple variables renamed following terminology changes.
```
=== "v3.0.0 (Recommended)"
-
```python
fx.TimeSeriesData(
aggregation_group='group1',
@@ -342,10 +373,11 @@ Multiple variables renamed following terminology changes.
)
```
-**Calculation:**
+---
-=== "v2.x (Deprecated)"
+### Calculation
+=== "v2.x (Deprecated)"
```python
calculation = fx.FullCalculation(
'calc',
@@ -355,7 +387,6 @@ Multiple variables renamed following terminology changes.
```
=== "v3.0.0 (Recommended)"
-
```python
# Use FlowSystem selection methods
flow_system_subset = flow_system.sel(time=slice('2020-01-01', '2020-01-03'))
@@ -370,7 +401,9 @@ Multiple variables renamed following terminology changes.
## New Features
-**Multi-Period Investments** - Model transformation pathways with distinct decisions per period:
+### Multi-Period Investments
+
+Model transformation pathways with distinct decisions per period.
```python
import pandas as pd
@@ -379,7 +412,7 @@ import pandas as pd
periods = pd.Index(['2020', '2030'])
flow_system = fx.FlowSystem(time=timesteps, periods=periods)
-# Components can now invest differently in each period
+# Components can invest differently in each period
solar = fx.Source(
'solar',
outputs=[fx.Flow(
@@ -394,17 +427,22 @@ solar = fx.Source(
)
```
-**Scenario-Based Stochastic Optimization** - Model uncertainty with weighted scenarios:
+---
+
+### Scenario-Based Stochastic Optimization
+
+Model uncertainty with weighted scenarios.
```python
# Define scenarios with probabilities
scenarios = pd.Index(['low_demand', 'base', 'high_demand'], name='scenario')
-scenario_weights = [0.2, 0.6, 0.2] # Probabilities
+scenario_weights = [0.2, 0.6, 0.2]
flow_system = fx.FlowSystem(
time=timesteps,
scenarios=scenarios,
- scenario_weights=scenario_weights
+ scenario_weights=scenario_weights,
+ scenario_independent_sizes=True # Optional: scenario-specific capacities
)
# Define scenario-dependent data
@@ -415,49 +453,63 @@ demand = xr.DataArray(
dims=['scenario', 'time'],
coords={'scenario': scenarios, 'time': timesteps}
)
-
```
-**Enhanced I/O** - Save, load, and manipulate FlowSystems:
+---
+
+### Enhanced I/O
+
+Save, load, and manipulate FlowSystems.
```python
-# Save and load FlowSystem
-flow_system.to_netcdf('my_system.nc')
-flow_system_loaded = fx.FlowSystem.from_netcdf('my_system.nc')
+# Save and load
+flow_system.to_netcdf('system.nc')
+fs = fx.FlowSystem.from_netcdf('system.nc')
-# Manipulate FlowSystem
+# Manipulate
fs_subset = flow_system.sel(time=slice('2020-01', '2020-06'))
fs_resampled = flow_system.resample(time='D') # Resample to daily
fs_copy = flow_system.copy()
-# Access FlowSystem from results (lazily loaded)
-results = calculation.results
-original_fs = results.flow_system # No manual restoration needed
+# Access from results
+original_fs = results.flow_system # Lazily loaded
```
-**Effects Per Component** - Analyze component impacts including indirect effects:
+---
+
+### Effects Per Component
+
+Analyze component impacts including indirect effects through shares.
```python
# Get dataset showing contribution of each component to all effects
-effects_ds = calculation.results.effects_per_component()
+effects_ds = results.effects_per_component()
print(effects_ds['costs']) # Total costs by component
print(effects_ds['CO2']) # CO2 emissions by component (including indirect)
```
-**Balanced Storage** - Force equal charging/discharging capacities:
+---
+
+### Balanced Storage
+
+Force charging and discharging capacities to be equal.
```python
storage = fx.Storage(
'storage',
- charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(effects_per_size=100, minimum_size=5)),
- discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(),
+ charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(...)),
+ discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(...)),
balanced=True, # Ensures charge_size == discharge_size
capacity_in_flow_hours=100
)
```
-**Final Charge State Control** - Set bounds on storage end state:
+---
+
+### Final Charge State Control
+
+Set bounds on storage end state.
```python
storage = fx.Storage(
@@ -472,31 +524,31 @@ storage = fx.Storage(
---
-## Configuration
+## Common Issues
-**Logging (v2.2.0+)** - Console and file logging now disabled by default:
+!!! failure "Effect shares not working"
+ **Solution:** Move shares to receiving effect using `share_from_temporal`/`share_from_periodic`
-```python
-import flixopt as fx
+!!! failure "Storage dimensions wrong"
+ **Solution:** Remove extra timestep; use `relative_minimum_final_charge_state`
-# Enable console logging
-fx.CONFIG.Logging.console = True
-fx.CONFIG.Logging.level = 'INFO'
-fx.CONFIG.apply()
+!!! failure "Bus assignment error"
+ **Solution:** Use string labels: `bus='electricity'` not `bus=my_bus`
-# Enable file logging
-fx.CONFIG.Logging.file = 'flixopt.log'
-fx.CONFIG.apply()
+!!! failure "KeyError in results"
+ **Solution:** Update variable names (see [Variable Names in Results](#variable-names-in-results))
-# Deprecated: change_logging_level() - will be removed in future
-# fx.change_logging_level('INFO') # ❌ Old way
-```
+!!! failure "No logging output"
+ **Solution:** Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
+
+!!! failure "AttributeError: SystemModel"
+ **Solution:** Rename `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
---
## Testing
-**Check for Deprecation Warnings:**
+### Check Deprecation Warnings
```python
import warnings
@@ -506,7 +558,9 @@ warnings.filterwarnings('default', category=DeprecationWarning)
# Review any DeprecationWarning messages
```
-**Validate Results:**
+---
+
+### Validate Results
```python
# Save v2.x results before upgrading
@@ -525,61 +579,38 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
---
-## Common Issues
-
-**"Effect share parameters not working"**
-→ Move shares to receiving effect using `share_from_temporal`/`share_from_periodic`
-
-**"Storage charge state has wrong dimensions"**
-→ Remove extra timestep; use `relative_minimum_final_charge_state`
-
-**"Bus assignment error"**
-→ Use string labels instead of Bus objects:
-
-```python
-# Old
-my_bus = fx.Bus('electricity')
-flow = fx.Flow('P_el', bus=my_bus) # ❌
-
-# New
-my_bus = fx.Bus('electricity')
-flow = fx.Flow('P_el', bus='electricity') # ✅
-```
-
-**"KeyError when accessing results"**
-→ Update variable names:
- - `is_invested` → `invested`
- - `switch_on` → `switch|on`, `switch_off` → `switch|off`, `switch_on_nr` → `switch|count`
- - `Effect(invest)|total` → `Effect(periodic)`
- - `Effect(operation)|total` → `Effect(temporal)`
- - `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
- - `Effect|total` → `Effect`
-
-**"AttributeError: SystemModel"**
-→ Rename `SystemModel` → `FlowSystemModel`
-
-**"No logging output"**
-→ Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
+## Migration Checklist
+
+??? abstract "Critical (Breaking Changes)"
+ - [x] Update flixopt: `pip install --upgrade flixopt`
+ - [ ] Update effect sharing syntax (move to receiving effect)
+ - [ ] Update result variable names (`is_invested` → `invested`, etc.)
+ - [ ] Replace Bus/Effect object assignments with strings
+ - [ ] Fix storage charge state arrays (remove extra timestep)
+ - [ ] Update `do_modeling()` usage if accessing return value
+ - [ ] Rename plotting `mode` → `style`
+ - [ ] Update class names (`SystemModel` → `FlowSystemModel`)
+
+??? tip "Recommended"
+ - [ ] Update deprecated parameter names
+ - [ ] Enable logging explicitly if needed
+ - [ ] Test thoroughly and validate results
+
+??? success "Optional"
+ - [ ] Explore multi-period investments
+ - [ ] Explore scenario-based optimization
+ - [ ] Try enhanced I/O features
+ - [ ] Use balanced storage
+ - [ ] Set final charge state controls
---
-## Checklist
+## Resources
-- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update effect sharing syntax (no deprecation warning!)
-- [ ] Update `Calculation.do_modeling()` usage
-- [ ] Fix storage charge state array dimensions
-- [ ] Rename `mode` → `style` in plotting calls
-- [ ] Update deprecated parameter names (optional, but recommended)
-- [ ] Enable logging explicitly if needed
-- [ ] Test your code thoroughly
-- [ ] Explore new features (periods, scenarios, enhanced I/O)
+:material-book: [Documentation](https://flixopt.github.io/flixopt/)
+:material-github: [GitHub Issues](https://github.com/flixOpt/flixopt/issues)
+:material-text-box: [Full Changelog](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
---
-**Resources:**
-[Documentation](https://flixopt.github.io/flixopt/) •
-[GitHub Issues](https://github.com/flixOpt/flixopt/issues) •
-[Full Changelog](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
-
-**Welcome to flixopt v3.0.0!** 🎉
+!!! success "Welcome to flixopt v3.0.0! 🎉"
From 066804222a64000191dd038348c1144faacd9d1c Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:19:32 +0200
Subject: [PATCH 10/42] Update
---
docs/user-guide/migration-guide-v3.md | 56 +++++++++++++++++++++------
1 file changed, 45 insertions(+), 11 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index cae28228a..81a7399fe 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -179,17 +179,43 @@ Arrays now match timestep count (no extra element).
---
-### Calculation API
+**Bus and Effect Assignment** - Use string labels instead of objects
+
+=== "v2.x (Old)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
+
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={CO2: 0.2}) # ❌ Object
+ ```
+
+=== "v3.0.0 (New)"
+
+ ```python
+ my_bus = fx.Bus('electricity')
+ flow = fx.Flow('P_el', bus='electricity') # ✅ String label
+
+ CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
+ costs = fx.Effect('costs', '€', 'Total costs',
+ share_from_temporal={'CO2': 0.2}) # ✅ String label
+ ```
+
+---
+
+**FlowSystem Independence** - Each Calculation gets its own copy
`do_modeling()` now returns Calculation object for method chaining.
=== "v2.x"
```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- linopy_model = calculation.do_modeling() # Returned linopy.Model
-
- # Access model directly from return value
- print(linopy_model)
+ # FlowSystem was shared across calculations
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
+ calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
+ # Changes in calc1's FlowSystem would affect calc2
```
=== "v3.0.0"
@@ -208,13 +234,21 @@ Arrays now match timestep count (no extra element).
=== "Plotting"
```python
- # v2.x
- results.plot_heatmap('component|variable', mode='line')
-
- # v3.0.0
- results.plot_heatmap('component|variable', style='line')
+ # Each calculation gets a copy
+ flow_system = fx.FlowSystem(time=timesteps)
+ calc1 = fx.FullCalculation('calc1', flow_system) # Gets copy
+ calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
+ # Calculations are now independent
```
+---
+
+**Other Breaking Changes:**
+
+- **Plotting:** `mode` parameter renamed to `style`
+- **Class names:** `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
+- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
+
=== "Class Names"
```python
# v2.x
From 4fb6a6cfa33f5afbf4a5c3eb484420488cd62854 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:34:44 +0200
Subject: [PATCH 11/42] Update
---
docs/user-guide/migration-guide-v3.md | 212 ++++++++++++++++++--------
1 file changed, 152 insertions(+), 60 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 81a7399fe..eb701c82c 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -12,11 +12,14 @@ Quick guide for migrating flixopt from v2.x to v3.0.0.
## Breaking Changes
-### Effect System Redesign
+**Effect System Redesign** - terminology and sharing system redesigned.
Effect domains renamed and sharing system inverted (no deprecation warnings).
-**Terminology changes:**
+| Old Term (v2.x) | New Term (v3.0.0) | Meaning |
+|-----------------|-------------------|-------------------------------------------------------------------------|
+| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occurring over time) |
+| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
| Old (v2.x) | New (v3.0.0) | Meaning |
|------------|--------------|---------|
@@ -43,11 +46,18 @@ Effect domains renamed and sharing system inverted (no deprecation warnings).
share_from_periodic={'land': 100}) # Pulls from periodic
```
-!!! success "Migration Steps"
- 1. Move share definitions to receiving effect
- 2. Rename: `specific_share_to_other_effects_operation` → `share_from_temporal`
- 3. Rename: `specific_share_to_other_effects_invest` → `share_from_periodic`
- 4. Replace "operation" → "temporal" and "invest/investment" → "periodic" throughout
+!!! warning "No Deprecation Warning"
+ This change was made WITHOUT deprecation warnings due to fundamental restructuring.
+
+**Migration:**
+
+1. Move share definitions to the receiving effect
+2. Update parameter names:
+ - `specific_share_to_other_effects_operation` → `share_from_temporal`
+ - `specific_share_to_other_effects_invest` → `share_from_periodic`
+3. Update terminology throughout your code:
+ - Replace "operation" with "temporal" in effect-related contexts
+ - Replace "invest/investment" with "periodic" in effect-related contexts
---
@@ -152,6 +162,9 @@ Each Calculation now receives its own FlowSystem copy.
# Calculations are now independent
```
+!!! tip "Migration"
+ If you used the return value of `do_modeling()`, update to access `.model` property instead.
+
---
### Storage Charge State
@@ -172,11 +185,17 @@ Arrays now match timestep count (no extra element).
# Array matches timesteps
storage = fx.Storage(
'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 for 4 timesteps
- relative_minimum_final_charge_state=0.3 # Control final state explicitly
+ relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
+ relative_minimum_final_charge_state=0.3 # Specify the final value directly if needed
)
```
+!!! note "Final State Control"
+ You only need to specify `relative_minimum_final_charge_state` only if it differs from the last value of `relative_minimum_charge_state`.
+
+!!! info "Impact"
+ If you provided arrays with `len(timesteps) + 1` elements, reduce to `len(timesteps)`.
+
---
**Bus and Effect Assignment** - Use string labels instead of objects
@@ -241,6 +260,14 @@ Arrays now match timestep count (no extra element).
# Calculations are now independent
```
+!!! info "Impact"
+ - Mutations to one calculation's FlowSystem won't affect others
+ - Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
+ - Memory usage may increase slightly due to copying
+
+!!! tip "Migration"
+ If you relied on shared FlowSystem behavior (which you most likely did not or by accident), you should copy the flow_system before passing it to another calculation.
+
---
**Other Breaking Changes:**
@@ -463,9 +490,7 @@ solar = fx.Source(
---
-### Scenario-Based Stochastic Optimization
-
-Model uncertainty with weighted scenarios.
+**Scenario-Based Stochastic Optimization** - Model uncertainty with weighted scenarios:
```python
# Define scenarios with probabilities
@@ -489,9 +514,18 @@ demand = xr.DataArray(
)
```
----
+**Control variable independence:**
+```python
+# By default: investment sizes are shared across scenarios, flow rates vary
+# To make sizes scenario-independent:
+flow_system = fx.FlowSystem(
+ time=timesteps,
+ scenarios=scenarios,
+ scenario_independent_sizes=True # Each scenario gets its own capacity
+)
+```
-### Enhanced I/O
+---
Save, load, and manipulate FlowSystems.
@@ -511,9 +545,7 @@ original_fs = results.flow_system # Lazily loaded
---
-### Effects Per Component
-
-Analyze component impacts including indirect effects through shares.
+**Effects Per Component** - Analyze component impacts including indirect effects:
```python
# Get dataset showing contribution of each component to all effects
@@ -525,15 +557,14 @@ print(effects_ds['CO2']) # CO2 emissions by component (including indirect)
---
-### Balanced Storage
-
-Force charging and discharging capacities to be equal.
+**Balanced Storage** - Force equal charging/discharging capacities:
```python
storage = fx.Storage(
'storage',
- charging=fx.Flow('charge', bus='electricity', size=fx.InvestParameters(...)),
- discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters(...)),
+ charging=fx.Flow('charge', bus='electricity',
+ size=fx.InvestParameters(effects_of_investment_per_size=100, minimum_size=5)),
+ discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters()),
balanced=True, # Ensures charge_size == discharge_size
capacity_in_flow_hours=100
)
@@ -541,9 +572,7 @@ storage = fx.Storage(
---
-### Final Charge State Control
-
-Set bounds on storage end state.
+**Final Charge State Control** - Set bounds on storage end state:
```python
storage = fx.Storage(
@@ -563,20 +592,44 @@ storage = fx.Storage(
!!! failure "Effect shares not working"
**Solution:** Move shares to receiving effect using `share_from_temporal`/`share_from_periodic`
-!!! failure "Storage dimensions wrong"
- **Solution:** Remove extra timestep; use `relative_minimum_final_charge_state`
+=== "v2.1.x and earlier"
+
+ ```python
+ import flixopt as fx
-!!! failure "Bus assignment error"
- **Solution:** Use string labels: `bus='electricity'` not `bus=my_bus`
+ # Logging was enabled by default
+ calculation = fx.FullCalculation('calc', flow_system)
+ calculation.solve() # Logs were shown automatically
+ ```
-!!! failure "KeyError in results"
- **Solution:** Update variable names (see [Variable Names in Results](#variable-names-in-results))
+=== "v2.2.0+ and v3.0.0"
-!!! failure "No logging output"
- **Solution:** Enable explicitly: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`
+ ```python
+ import flixopt as fx
+
+ # Enable console logging explicitly
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.Logging.level = 'INFO'
+ fx.CONFIG.apply()
+
+ # Enable file logging (optional)
+ fx.CONFIG.Logging.file = 'flixopt.log'
+ fx.CONFIG.apply()
+
+ calculation = fx.FullCalculation('calc', flow_system)
+ calculation.solve() # Now logs are shown
+ ```
+
+!!! warning "Breaking Change (from v2.2.0)"
+ If you're upgrading from v2.1.x or earlier to v3.0.0, you may notice that logging output is no longer displayed unless explicitly enabled.
-!!! failure "AttributeError: SystemModel"
- **Solution:** Rename `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
+!!! tip "Migration"
+ Add logging configuration at the start of your scripts if you want to see log output:
+ ```python
+ import flixopt as fx
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.apply()
+ ```
---
@@ -594,7 +647,9 @@ warnings.filterwarnings('default', category=DeprecationWarning)
---
-### Validate Results
+**Validate Results:**
+
+Compare results from v2.x and v3.0.0 to ensure consistency:
```python
# Save v2.x results before upgrading
@@ -613,33 +668,70 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
---
-## Migration Checklist
-
-??? abstract "Critical (Breaking Changes)"
- - [x] Update flixopt: `pip install --upgrade flixopt`
- - [ ] Update effect sharing syntax (move to receiving effect)
- - [ ] Update result variable names (`is_invested` → `invested`, etc.)
- - [ ] Replace Bus/Effect object assignments with strings
- - [ ] Fix storage charge state arrays (remove extra timestep)
- - [ ] Update `do_modeling()` usage if accessing return value
- - [ ] Rename plotting `mode` → `style`
- - [ ] Update class names (`SystemModel` → `FlowSystemModel`)
-
-??? tip "Recommended"
- - [ ] Update deprecated parameter names
- - [ ] Enable logging explicitly if needed
- - [ ] Test thoroughly and validate results
-
-??? success "Optional"
- - [ ] Explore multi-period investments
- - [ ] Explore scenario-based optimization
- - [ ] Try enhanced I/O features
- - [ ] Use balanced storage
- - [ ] Set final charge state controls
+## Common Issues
+
+!!! failure "Effect share parameters not working"
+ **Solution:** Effect sharing was completely redesigned. Move share definitions to the **receiving** effect using `share_from_temporal` and `share_from_periodic`.
+
+!!! failure "Storage charge state has wrong dimensions"
+ **Solution:** Remove the extra timestep from charge state bound arrays.
+
+!!! failure "KeyError when accessing results"
+ **Solution:** Variable names have changed. Update your result access:
+
+ - `is_invested` → `invested`
+ - `switch_on` → `switch|on`
+ - `switch_off` → `switch|off`
+ - `switch_on_nr` → `switch|count`
+ - `Effect(invest)|total` → `Effect(periodic)`
+ - `Effect(operation)|total` → `Effect(temporal)`
+ - `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
+ - `Effect|total` → `Effect`
+
+!!! failure "AttributeError: Element x has no attribute `model`"
+ **Solution:** Rename `.model` → `.submodel`
+
+!!! failure "No logging output"
+ **Solution:** Logging is disabled by default in v2.2.0+. Enable it explicitly:
+ ```python
+ import flixopt as fx
+ fx.CONFIG.Logging.console = True
+ fx.CONFIG.apply()
+ ```
+
+---
+
+## Checklist
+
+**Critical (Breaking Changes):**
+
+- [ ] Update flixopt: `pip install --upgrade flixopt`
+- [ ] Update effect sharing syntax (no deprecation warning!)
+- [ ] Update all variable names in result access
+- [ ] Replace Bus/Effect object assignments with string labels
+- [ ] Remove any code that relies on shared FlowSystem objects across Calculations
+- [ ] Update `Calculation.do_modeling()` usage if accessing return value
+- [ ] Fix storage charge state array dimensions (remove extra timestep)
+- [ ] Rename `mode` → `style` in plotting calls
+
+**Important:**
+
+- [ ] Enable logging explicitly if needed (`fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
+- [ ] Update deprecated parameter names (optional, but recommended)
+
+**Testing:**
+
+- [ ] Test your code thoroughly
+- [ ] Check for deprecation warnings
+- [ ] Validate results match v2.x output (if upgrading)
+
+**Optional:**
+
+- [ ] Explore new features (periods, scenarios, enhanced I/O, balanced storage, final charge state control)
---
-## Resources
+## Getting Help
:material-book: [Documentation](https://flixopt.github.io/flixopt/)
:material-github: [GitHub Issues](https://github.com/flixOpt/flixopt/issues)
From 8cced2ab23b5c52b4b81364a92ed37e98693a22f Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:44:55 +0200
Subject: [PATCH 12/42] Add links
---
docs/user-guide/migration-guide-v3.md | 260 ++++++++++----------------
1 file changed, 98 insertions(+), 162 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index eb701c82c..135e469d7 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -12,7 +12,7 @@ Quick guide for migrating flixopt from v2.x to v3.0.0.
## Breaking Changes
-**Effect System Redesign** - terminology and sharing system redesigned.
+### Effect System Redesign
Effect domains renamed and sharing system inverted (no deprecation warnings).
@@ -21,11 +21,6 @@ Effect domains renamed and sharing system inverted (no deprecation warnings).
| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occurring over time) |
| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
-| Old (v2.x) | New (v3.0.0) | Meaning |
-|------------|--------------|---------|
-| `operation` | `temporal` | Time-varying effects (operational costs, emissions) |
-| `invest`/`investment` | `periodic` | Investment effects (fixed costs per period) |
-
**Sharing system:** Effects now "pull" shares instead of "pushing" them.
=== "v2.x"
@@ -158,10 +153,43 @@ Each Calculation now receives its own FlowSystem copy.
# Each calculation gets a copy
flow_system = fx.FlowSystem(time=timesteps)
calc1 = fx.FullCalculation('calc1', flow_system)
- calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
+ calc2 = fx.FullCalculation('calc2', flow_system) # Gets copy
# Calculations are now independent
```
+!!! info "Impact"
+ - Mutations to one calculation's FlowSystem won't affect others
+ - Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
+ - Memory usage may increase slightly due to copying
+
+!!! tip "Migration"
+ If you relied on shared FlowSystem behavior (which you most likely did not or by accident), you should copy the flow_system before passing it to another calculation.
+
+---
+
+### Calculation API
+
+`do_modeling()` now returns Calculation object for method chaining.
+
+=== "v2.x"
+ ```python
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ linopy_model = calculation.do_modeling() # Returned linopy.Model
+
+ # Access model directly from return value
+ print(linopy_model)
+ ```
+
+=== "v3.0.0"
+ ```python
+ calculation = fx.FullCalculation('my_calc', flow_system)
+ calculation.do_modeling() # Returns Calculation object
+ linopy_model = calculation.model # Access model via property
+
+ # Enables method chaining
+ fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
+ ```
+
!!! tip "Migration"
If you used the return value of `do_modeling()`, update to access `.model` property instead.
@@ -191,90 +219,23 @@ Arrays now match timestep count (no extra element).
```
!!! note "Final State Control"
- You only need to specify `relative_minimum_final_charge_state` only if it differs from the last value of `relative_minimum_charge_state`.
+ You only need to specify `relative_minimum_final_charge_state` if it differs from the last value of `relative_minimum_charge_state`.
!!! info "Impact"
If you provided arrays with `len(timesteps) + 1` elements, reduce to `len(timesteps)`.
---
-**Bus and Effect Assignment** - Use string labels instead of objects
-
-=== "v2.x (Old)"
-
- ```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
-
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={CO2: 0.2}) # ❌ Object
- ```
-
-=== "v3.0.0 (New)"
-
- ```python
- my_bus = fx.Bus('electricity')
- flow = fx.Flow('P_el', bus='electricity') # ✅ String label
-
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}) # ✅ String label
- ```
-
----
-
-**FlowSystem Independence** - Each Calculation gets its own copy
-
-`do_modeling()` now returns Calculation object for method chaining.
-
-=== "v2.x"
- ```python
- # FlowSystem was shared across calculations
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
- calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
- # Changes in calc1's FlowSystem would affect calc2
- ```
-
-=== "v3.0.0"
- ```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- calculation.do_modeling() # Returns Calculation object
- linopy_model = calculation.model # Access model via property
-
- # Enables method chaining
- fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
- ```
-
----
-
### Other Breaking Changes
=== "Plotting"
```python
- # Each calculation gets a copy
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Gets copy
- calc2 = fx.FullCalculation('calc2', flow_system) # Gets separate copy
- # Calculations are now independent
- ```
-
-!!! info "Impact"
- - Mutations to one calculation's FlowSystem won't affect others
- - Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
- - Memory usage may increase slightly due to copying
-
-!!! tip "Migration"
- If you relied on shared FlowSystem behavior (which you most likely did not or by accident), you should copy the flow_system before passing it to another calculation.
-
----
-
-**Other Breaking Changes:**
+ # v2.x
+ results.plot_heatmap('component|variable', mode='line')
-- **Plotting:** `mode` parameter renamed to `style`
-- **Class names:** `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
-- **Logging:** Disabled by default (enable with `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
+ # v3.0.0
+ results.plot_heatmap('component|variable', style='line')
+ ```
=== "Class Names"
```python
@@ -296,6 +257,9 @@ Arrays now match timestep count (no extra element).
fx.CONFIG.apply()
```
+!!! warning "Breaking Change (from v2.2.0)"
+ If you're upgrading from v2.1.x or earlier to v3.0.0, logging output is no longer displayed unless explicitly enabled. See [Configuration](#configuration) for details.
+
---
## Deprecated Parameters
@@ -384,29 +348,17 @@ Arrays now match timestep count (no extra element).
=== "v2.x (Deprecated)"
```python
fx.Source('my_source', source=flow)
-
fx.Sink('my_sink', sink=flow)
-
- fx.SourceAndSink(
- 'my_source_sink',
- source=flow1,
- sink=flow2,
- prevent_simultaneous_sink_and_source=True
- )
+ fx.SourceAndSink('my_source_sink', source=flow1, sink=flow2,
+ prevent_simultaneous_sink_and_source=True)
```
=== "v3.0.0 (Recommended)"
```python
fx.Source('my_source', outputs=flow)
-
fx.Sink('my_sink', inputs=flow)
-
- fx.SourceAndSink(
- 'my_source_sink',
- outputs=flow1,
- inputs=flow2,
- prevent_simultaneous_flow_rates=True
- )
+ fx.SourceAndSink('my_source_sink', outputs=[flow1], inputs=[flow2],
+ prevent_simultaneous_flow_rates=True)
```
---
@@ -420,18 +372,12 @@ Arrays now match timestep count (no extra element).
=== "v2.x (Deprecated)"
```python
- fx.TimeSeriesData(
- agg_group='group1',
- agg_weight=2.0
- )
+ fx.TimeSeriesData(agg_group='group1', agg_weight=2.0)
```
=== "v3.0.0 (Recommended)"
```python
- fx.TimeSeriesData(
- aggregation_group='group1',
- aggregation_weight=2.0
- )
+ fx.TimeSeriesData(aggregation_group='group1', aggregation_weight=2.0)
```
---
@@ -440,11 +386,7 @@ Arrays now match timestep count (no extra element).
=== "v2.x (Deprecated)"
```python
- calculation = fx.FullCalculation(
- 'calc',
- flow_system,
- active_timesteps=[0, 1, 2]
- )
+ calculation = fx.FullCalculation('calc', flow_system, active_timesteps=[0, 1, 2])
```
=== "v3.0.0 (Recommended)"
@@ -490,7 +432,9 @@ solar = fx.Source(
---
-**Scenario-Based Stochastic Optimization** - Model uncertainty with weighted scenarios:
+### Scenario-Based Stochastic Optimization
+
+Model uncertainty with weighted scenarios.
```python
# Define scenarios with probabilities
@@ -500,8 +444,7 @@ scenario_weights = [0.2, 0.6, 0.2]
flow_system = fx.FlowSystem(
time=timesteps,
scenarios=scenarios,
- scenario_weights=scenario_weights,
- scenario_independent_sizes=True # Optional: scenario-specific capacities
+ scenario_weights=scenario_weights
)
# Define scenario-dependent data
@@ -527,6 +470,8 @@ flow_system = fx.FlowSystem(
---
+### Enhanced I/O
+
Save, load, and manipulate FlowSystems.
```python
@@ -545,19 +490,23 @@ original_fs = results.flow_system # Lazily loaded
---
-**Effects Per Component** - Analyze component impacts including indirect effects:
+### Effects Per Component
+
+Analyze component impacts including indirect effects.
```python
# Get dataset showing contribution of each component to all effects
-effects_ds = results.effects_per_component()
+effects_ds = results.effects_per_component
-print(effects_ds['costs']) # Total costs by component
-print(effects_ds['CO2']) # CO2 emissions by component (including indirect)
+print(effects_ds['total'].sel(effect='costs')) # Total costs by component
+print(effects_ds['temporal'].sel(effect='CO2')) # Temporal CO2 emissions by component (including indirect)
```
---
-**Balanced Storage** - Force equal charging/discharging capacities:
+### Balanced Storage
+
+Force equal charging/discharging sizes.
```python
storage = fx.Storage(
@@ -572,7 +521,9 @@ storage = fx.Storage(
---
-**Final Charge State Control** - Set bounds on storage end state:
+### Final Charge State Control
+
+Set bounds on storage end state.
```python
storage = fx.Storage(
@@ -587,13 +538,13 @@ storage = fx.Storage(
---
-## Common Issues
+## Configuration
-!!! failure "Effect shares not working"
- **Solution:** Move shares to receiving effect using `share_from_temporal`/`share_from_periodic`
+### Logging
-=== "v2.1.x and earlier"
+Console and file logging now disabled by default (changed in v2.2.0).
+=== "v2.1.x and earlier"
```python
import flixopt as fx
@@ -603,7 +554,6 @@ storage = fx.Storage(
```
=== "v2.2.0+ and v3.0.0"
-
```python
import flixopt as fx
@@ -620,11 +570,8 @@ storage = fx.Storage(
calculation.solve() # Now logs are shown
```
-!!! warning "Breaking Change (from v2.2.0)"
- If you're upgrading from v2.1.x or earlier to v3.0.0, you may notice that logging output is no longer displayed unless explicitly enabled.
-
-!!! tip "Migration"
- Add logging configuration at the start of your scripts if you want to see log output:
+!!! tip "Quick Enable"
+ Add at the start of your scripts:
```python
import flixopt as fx
fx.CONFIG.Logging.console = True
@@ -647,7 +594,7 @@ warnings.filterwarnings('default', category=DeprecationWarning)
---
-**Validate Results:**
+### Validate Results
Compare results from v2.x and v3.0.0 to ensure consistency:
@@ -670,34 +617,23 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
## Common Issues
-!!! failure "Effect share parameters not working"
- **Solution:** Effect sharing was completely redesigned. Move share definitions to the **receiving** effect using `share_from_temporal` and `share_from_periodic`.
+!!! failure "Effect shares not working"
+ **Solution:** Effect sharing was completely redesigned. See [Effect System Redesign](#effect-system-redesign).
-!!! failure "Storage charge state has wrong dimensions"
- **Solution:** Remove the extra timestep from charge state bound arrays.
+!!! failure "Storage dimensions wrong"
+ **Solution:** Remove extra timestep from charge state arrays. See [Storage Charge State](#storage-charge-state).
-!!! failure "KeyError when accessing results"
- **Solution:** Variable names have changed. Update your result access:
+!!! failure "Bus assignment error"
+ **Solution:** Use string labels instead of Bus objects. See [Bus and Effect Assignment](#bus-and-effect-assignment).
- - `is_invested` → `invested`
- - `switch_on` → `switch|on`
- - `switch_off` → `switch|off`
- - `switch_on_nr` → `switch|count`
- - `Effect(invest)|total` → `Effect(periodic)`
- - `Effect(operation)|total` → `Effect(temporal)`
- - `Effect(operation)|total_per_timestep` → `Effect(temporal)|per_timestep`
- - `Effect|total` → `Effect`
+!!! failure "KeyError when accessing results"
+ **Solution:** Variable names have changed. See [Variable Names in Results](#variable-names-in-results) for the complete mapping.
!!! failure "AttributeError: Element x has no attribute `model`"
- **Solution:** Rename `.model` → `.submodel`
+ **Solution:** Rename `.model` → `.submodel`. See [Other Breaking Changes](#other-breaking-changes).
!!! failure "No logging output"
- **Solution:** Logging is disabled by default in v2.2.0+. Enable it explicitly:
- ```python
- import flixopt as fx
- fx.CONFIG.Logging.console = True
- fx.CONFIG.apply()
- ```
+ **Solution:** Logging is disabled by default. See [Configuration](#configuration) to enable it.
---
@@ -706,28 +642,28 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
**Critical (Breaking Changes):**
- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update effect sharing syntax (no deprecation warning!)
-- [ ] Update all variable names in result access
-- [ ] Replace Bus/Effect object assignments with string labels
-- [ ] Remove any code that relies on shared FlowSystem objects across Calculations
-- [ ] Update `Calculation.do_modeling()` usage if accessing return value
-- [ ] Fix storage charge state array dimensions (remove extra timestep)
-- [ ] Rename `mode` → `style` in plotting calls
+- [ ] Update [effect sharing syntax](#effect-system-redesign) (no deprecation warning!)
+- [ ] Update [variable names in results](#variable-names-in-results)
+- [ ] Update [Bus/Effect assignments](#bus-and-effect-assignment) to use string labels
+- [ ] Update [Calculation API](#calculation-api) usage if accessing return value
+- [ ] Fix [storage charge state](#storage-charge-state) array dimensions
+- [ ] Rename plotting `mode` → `style`
+- [ ] Update class names: `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
**Important:**
-- [ ] Enable logging explicitly if needed (`fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`)
-- [ ] Update deprecated parameter names (optional, but recommended)
+- [ ] Enable [logging](#configuration) explicitly if needed
+- [ ] Update [deprecated parameters](#deprecated-parameters) (optional, but recommended)
**Testing:**
- [ ] Test your code thoroughly
-- [ ] Check for deprecation warnings
-- [ ] Validate results match v2.x output (if upgrading)
+- [ ] Check for [deprecation warnings](#check-deprecation-warnings)
+- [ ] [Validate results](#validate-results) match v2.x output (if upgrading)
**Optional:**
-- [ ] Explore new features (periods, scenarios, enhanced I/O, balanced storage, final charge state control)
+- [ ] Explore [new features](#new-features)
---
From cd87edfb4efabd4b884aca5f8ef23044cc9de6fe Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:46:58 +0200
Subject: [PATCH 13/42] Add emojis
---
docs/user-guide/migration-guide-v3.md | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 135e469d7..73bad903e 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -10,7 +10,7 @@ Quick guide for migrating flixopt from v2.x to v3.0.0.
---
-## Breaking Changes
+## 💥 Breaking Changes
### Effect System Redesign
@@ -262,7 +262,7 @@ Arrays now match timestep count (no extra element).
---
-## Deprecated Parameters
+## 🗑️ Deprecated Parameters
!!! info "Still Supported"
These parameters still work but will be removed in a future version. Deprecation warnings guide migration.
@@ -402,7 +402,7 @@ Arrays now match timestep count (no extra element).
---
-## New Features
+## ✨ New Features
### Multi-Period Investments
@@ -538,7 +538,7 @@ storage = fx.Storage(
---
-## Configuration
+## ⚙️ Configuration
### Logging
@@ -580,7 +580,7 @@ Console and file logging now disabled by default (changed in v2.2.0).
---
-## Testing
+## 🧪 Testing
### Check Deprecation Warnings
@@ -615,7 +615,7 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
---
-## Common Issues
+## 🔧 Common Issues
!!! failure "Effect shares not working"
**Solution:** Effect sharing was completely redesigned. See [Effect System Redesign](#effect-system-redesign).
@@ -637,7 +637,7 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
---
-## Checklist
+## ✅ Checklist
**Critical (Breaking Changes):**
@@ -667,7 +667,7 @@ np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
---
-## Getting Help
+## 📚 Getting Help
:material-book: [Documentation](https://flixopt.github.io/flixopt/)
:material-github: [GitHub Issues](https://github.com/flixOpt/flixopt/issues)
From 0d03660671c0c5277cf34c7d4587eebbd84fd41d Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 11:59:11 +0200
Subject: [PATCH 14/42] compact 2
---
docs/user-guide/migration-guide-v3.md | 658 +++-----------------------
1 file changed, 75 insertions(+), 583 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index 73bad903e..bafce112a 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -1,12 +1,10 @@
# Migration Guide: v2.x → v3.0.0
-Quick guide for migrating flixopt from v2.x to v3.0.0.
-
!!! tip "Quick Start"
```bash
pip install --upgrade flixopt
```
- Review breaking changes, update deprecated parameters, and test thoroughly.
+ Review [breaking changes](#breaking-changes), update [deprecated parameters](#deprecated-parameters), test thoroughly.
---
@@ -14,665 +12,159 @@ Quick guide for migrating flixopt from v2.x to v3.0.0.
### Effect System Redesign
-Effect domains renamed and sharing system inverted (no deprecation warnings).
-
-| Old Term (v2.x) | New Term (v3.0.0) | Meaning |
-|-----------------|-------------------|-------------------------------------------------------------------------|
-| `operation` | `temporal` | Time-varying effects (e.g., operational costs, occurring over time) |
-| `invest` / `investment` | `periodic` | Investment-related effects (e.g., fixed costs per period, annuity, ...) |
-
-**Sharing system:** Effects now "pull" shares instead of "pushing" them.
+Terminology changed: `operation` → `temporal`, `invest/investment` → `periodic`. Sharing inverted: effects now "pull" shares.
=== "v2.x"
```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions',
+ CO2 = fx.Effect('CO2', 'kg', 'CO2',
specific_share_to_other_effects_operation={'costs': 0.2})
- land = fx.Effect('land', 'm²', 'Land usage',
- specific_share_to_other_effects_invest={'costs': 100})
- costs = fx.Effect('costs', '€', 'Total costs')
+ costs = fx.Effect('costs', '€', 'Total')
```
=== "v3.0.0"
```python
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- land = fx.Effect('land', 'm²', 'Land usage')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}, # Pulls from temporal
- share_from_periodic={'land': 100}) # Pulls from periodic
+ CO2 = fx.Effect('CO2', 'kg', 'CO2')
+ costs = fx.Effect('costs', '€', 'Total',
+ share_from_temporal={'CO2': 0.2})
```
-!!! warning "No Deprecation Warning"
- This change was made WITHOUT deprecation warnings due to fundamental restructuring.
-
-**Migration:**
-
-1. Move share definitions to the receiving effect
-2. Update parameter names:
- - `specific_share_to_other_effects_operation` → `share_from_temporal`
- - `specific_share_to_other_effects_invest` → `share_from_periodic`
-3. Update terminology throughout your code:
- - Replace "operation" with "temporal" in effect-related contexts
- - Replace "invest/investment" with "periodic" in effect-related contexts
+!!! warning "No deprecation warning"
+ - Move shares to receiving effect
+ - `specific_share_to_other_effects_operation` → `share_from_temporal`
+ - `specific_share_to_other_effects_invest` → `share_from_periodic`
---
-### Variable Names in Results
-
-| Category | Old (v2.x) | New (v3.0.0) |
-|----------|------------|--------------|
-| Investment | `is_invested` | `invested` |
-| Switch tracking | `switch_on` | `switch\|on` |
-| Switch tracking | `switch_off` | `switch\|off` |
-| Switch tracking | `switch_on_nr` | `switch\|count` |
-| Effect submodels | `Effect(invest)\|total` | `Effect(periodic)` |
-| Effect submodels | `Effect(operation)\|total` | `Effect(temporal)` |
-| Effect submodels | `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_timestep` |
-| Effect submodels | `Effect\|total` | `Effect` |
+### Variable Names
-=== "v2.x"
- ```python
- # Investment
- results.solution['component|is_invested']
-
- # Switch tracking
- results.solution['component|switch_on']
- results.solution['component|switch_off']
- results.solution['component|switch_on_nr']
-
- # Effects
- results.solution['costs(invest)|total']
- results.solution['costs(operation)|total']
- results.solution['costs(operation)|total_per_timestep']
- results.solution['costs|total']
- ```
-
-=== "v3.0.0"
- ```python
- # Investment
- results.solution['component|invested']
-
- # Switch tracking
- results.solution['component|switch|on']
- results.solution['component|switch|off']
- results.solution['component|switch|count']
-
- # Effects
- results.solution['costs(periodic)']
- results.solution['costs(temporal)']
- results.solution['costs(temporal)|per_timestep']
- results.solution['costs']
- ```
+| Old | New | Old | New |
+|-----|-----|-----|-----|
+| `is_invested` | `invested` | `switch_on` | `switch\|on` |
+| `switch_off` | `switch\|off` | `switch_on_nr` | `switch\|count` |
+| `Effect(invest)\|total` | `Effect(periodic)` | `Effect(operation)\|total` | `Effect(temporal)` |
+| `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_timestep` | `Effect\|total` | `Effect` |
---
-### Bus and Effect Assignment
+### String Labels
-Use string labels instead of object references.
+Use strings instead of objects for Bus/Effect references.
=== "v2.x"
```python
- # Bus assignment
- my_bus = fx.Bus('electricity')
flow = fx.Flow('P_el', bus=my_bus) # ❌ Object
-
- # Effect shares
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={CO2: 0.2}) # ❌ Object
+ costs = fx.Effect('costs', '€', share_from_temporal={CO2: 0.2}) # ❌
```
=== "v3.0.0"
```python
- # Bus assignment
- my_bus = fx.Bus('electricity')
flow = fx.Flow('P_el', bus='electricity') # ✅ String
-
- # Effect shares
- CO2 = fx.Effect('CO2', 'kg', 'CO2 emissions')
- costs = fx.Effect('costs', '€', 'Total costs',
- share_from_temporal={'CO2': 0.2}) # ✅ String
+ costs = fx.Effect('costs', '€', share_from_temporal={'CO2': 0.2}) # ✅
```
---
-### FlowSystem Independence
+### FlowSystem & Calculation
-Each Calculation now receives its own FlowSystem copy.
-
-=== "v2.x"
- ```python
- # FlowSystem was shared
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system) # Shared reference
- calc2 = fx.FullCalculation('calc2', flow_system) # Same reference
- # Changes in calc1's FlowSystem would affect calc2
- ```
-
-=== "v3.0.0"
- ```python
- # Each calculation gets a copy
- flow_system = fx.FlowSystem(time=timesteps)
- calc1 = fx.FullCalculation('calc1', flow_system)
- calc2 = fx.FullCalculation('calc2', flow_system) # Gets copy
- # Calculations are now independent
- ```
-
-!!! info "Impact"
- - Mutations to one calculation's FlowSystem won't affect others
- - Each `Subcalculation` in `SegmentedCalculation` has its own distinct FlowSystem
- - Memory usage may increase slightly due to copying
-
-!!! tip "Migration"
- If you relied on shared FlowSystem behavior (which you most likely did not or by accident), you should copy the flow_system before passing it to another calculation.
+- **FlowSystem**: Each `Calculation` gets its own copy (independent)
+- **do_modeling()**: Returns `Calculation` (access model via `.model` property)
+- **Storage**: Arrays match timestep count (no extra element)
+ - Use `relative_minimum_final_charge_state` for final state control
---
-### Calculation API
+### Other Changes
-`do_modeling()` now returns Calculation object for method chaining.
-
-=== "v2.x"
- ```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- linopy_model = calculation.do_modeling() # Returned linopy.Model
-
- # Access model directly from return value
- print(linopy_model)
- ```
-
-=== "v3.0.0"
- ```python
- calculation = fx.FullCalculation('my_calc', flow_system)
- calculation.do_modeling() # Returns Calculation object
- linopy_model = calculation.model # Access model via property
-
- # Enables method chaining
- fx.FullCalculation('my_calc', flow_system).do_modeling().solve()
- ```
-
-!!! tip "Migration"
- If you used the return value of `do_modeling()`, update to access `.model` property instead.
-
----
-
-### Storage Charge State
-
-Arrays now match timestep count (no extra element).
-
-=== "v2.x"
- ```python
- # Array with extra timestep
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # 5 for 4 timesteps
- )
- ```
-
-=== "v3.0.0"
- ```python
- # Array matches timesteps
- storage = fx.Storage(
- 'storage',
- relative_minimum_charge_state=np.array([0.2, 0.2, 0.2, 0.2]), # 4 values for 4 timesteps
- relative_minimum_final_charge_state=0.3 # Specify the final value directly if needed
- )
- ```
-
-!!! note "Final State Control"
- You only need to specify `relative_minimum_final_charge_state` if it differs from the last value of `relative_minimum_charge_state`.
-
-!!! info "Impact"
- If you provided arrays with `len(timesteps) + 1` elements, reduce to `len(timesteps)`.
-
----
-
-### Other Breaking Changes
-
-=== "Plotting"
- ```python
- # v2.x
- results.plot_heatmap('component|variable', mode='line')
-
- # v3.0.0
- results.plot_heatmap('component|variable', style='line')
- ```
-
-=== "Class Names"
- ```python
- # v2.x
- from flixopt import SystemModel, Model
-
- # v3.0.0
- from flixopt import FlowSystemModel, Submodel
- ```
-
-=== "Logging"
- ```python
- # v2.x - enabled by default
- # (no explicit configuration needed)
-
- # v3.0.0 - disabled by default
- import flixopt as fx
- fx.CONFIG.Logging.console = True
- fx.CONFIG.apply()
- ```
-
-!!! warning "Breaking Change (from v2.2.0)"
- If you're upgrading from v2.1.x or earlier to v3.0.0, logging output is no longer displayed unless explicitly enabled. See [Configuration](#configuration) for details.
+| Category | Old | New |
+|----------|-----|-----|
+| Plotting | `mode='line'` | `style='line'` |
+| Classes | `SystemModel`, `Model` | `FlowSystemModel`, `Submodel` |
+| Logging | Enabled by default | Disabled (enable: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`) |
---
## 🗑️ Deprecated Parameters
-!!! info "Still Supported"
- These parameters still work but will be removed in a future version. Deprecation warnings guide migration.
-
-### InvestParameters
-
-| Old (v2.x) | New (v3.0.0) |
-|------------|--------------|
-| `fix_effects` | `effects_of_investment` |
-| `specific_effects` | `effects_of_investment_per_size` |
-| `divest_effects` | `effects_of_retirement` |
-| `piecewise_effects` | `piecewise_effects_of_investment` |
-
-=== "v2.x (Deprecated)"
- ```python
- fx.InvestParameters(
- fix_effects=1000,
- specific_effects={'costs': 10},
- divest_effects=100,
- piecewise_effects=my_piecewise,
- )
- ```
-
-=== "v3.0.0 (Recommended)"
- ```python
- fx.InvestParameters(
- effects_of_investment=1000,
- effects_of_investment_per_size={'costs': 10},
- effects_of_retirement=100,
- piecewise_effects_of_investment=my_piecewise,
- )
- ```
-
----
-
-### Effect
-
-| Old (v2.x) | New (v3.0.0) |
-|------------|--------------|
-| `minimum_investment` | `minimum_periodic` |
-| `maximum_investment` | `maximum_periodic` |
-| `minimum_operation` | `minimum_temporal` |
-| `maximum_operation` | `maximum_temporal` |
-| `minimum_operation_per_hour` | `minimum_per_hour` |
-| `maximum_operation_per_hour` | `maximum_per_hour` |
-
-=== "v2.x (Deprecated)"
- ```python
- fx.Effect(
- 'my_effect', 'unit', 'description',
- minimum_investment=10,
- maximum_investment=100,
- minimum_operation=5,
- maximum_operation=50,
- minimum_operation_per_hour=1,
- maximum_operation_per_hour=10,
- )
- ```
-
-=== "v3.0.0 (Recommended)"
- ```python
- fx.Effect(
- 'my_effect', 'unit', 'description',
- minimum_periodic=10,
- maximum_periodic=100,
- minimum_temporal=5,
- maximum_temporal=50,
- minimum_per_hour=1,
- maximum_per_hour=10,
- )
- ```
-
----
+??? abstract "InvestParameters"
-### Component Parameters
+ `fix_effects` → `effects_of_investment` • `specific_effects` → `effects_of_investment_per_size` • `divest_effects` → `effects_of_retirement` • `piecewise_effects` → `piecewise_effects_of_investment`
-| Old (v2.x) | New (v3.0.0) |
-|------------|--------------|
-| `source` (parameter) | `outputs` |
-| `sink` (parameter) | `inputs` |
-| `prevent_simultaneous_sink_and_source` | `prevent_simultaneous_flow_rates` |
+??? abstract "Effect"
-=== "v2.x (Deprecated)"
- ```python
- fx.Source('my_source', source=flow)
- fx.Sink('my_sink', sink=flow)
- fx.SourceAndSink('my_source_sink', source=flow1, sink=flow2,
- prevent_simultaneous_sink_and_source=True)
- ```
+ `minimum_investment` → `minimum_periodic` • `maximum_investment` → `maximum_periodic` • `minimum_operation` → `minimum_temporal` • `maximum_operation` → `maximum_temporal` • `minimum_operation_per_hour` → `minimum_per_hour` • `maximum_operation_per_hour` → `maximum_per_hour`
-=== "v3.0.0 (Recommended)"
- ```python
- fx.Source('my_source', outputs=flow)
- fx.Sink('my_sink', inputs=flow)
- fx.SourceAndSink('my_source_sink', outputs=[flow1], inputs=[flow2],
- prevent_simultaneous_flow_rates=True)
- ```
+??? abstract "Components"
----
+ `source` → `outputs` • `sink` → `inputs` • `prevent_simultaneous_sink_and_source` → `prevent_simultaneous_flow_rates`
-### TimeSeriesData
+??? abstract "TimeSeriesData & Calculation"
-| Old (v2.x) | New (v3.0.0) |
-|------------|--------------|
-| `agg_group` | `aggregation_group` |
-| `agg_weight` | `aggregation_weight` |
-
-=== "v2.x (Deprecated)"
- ```python
- fx.TimeSeriesData(agg_group='group1', agg_weight=2.0)
- ```
-
-=== "v3.0.0 (Recommended)"
- ```python
- fx.TimeSeriesData(aggregation_group='group1', aggregation_weight=2.0)
- ```
+ - `agg_group` → `aggregation_group`
+ - `agg_weight` → `aggregation_weight`
+ - `active_timesteps` → Use `flow_system.sel()` or `flow_system.isel()`
---
-### Calculation
+## ✨ New Features
-=== "v2.x (Deprecated)"
- ```python
- calculation = fx.FullCalculation('calc', flow_system, active_timesteps=[0, 1, 2])
- ```
+??? success "Multi-Period Investments"
-=== "v3.0.0 (Recommended)"
```python
- # Use FlowSystem selection methods
- flow_system_subset = flow_system.sel(time=slice('2020-01-01', '2020-01-03'))
- calculation = fx.FullCalculation('calc', flow_system_subset)
-
- # Or with isel for index-based selection
- flow_system_subset = flow_system.isel(time=slice(0, 3))
- calculation = fx.FullCalculation('calc', flow_system_subset)
+ periods = pd.Index(['2020', '2030'])
+ flow_system = fx.FlowSystem(time=timesteps, periods=periods)
```
----
-
-## ✨ New Features
-
-### Multi-Period Investments
-
-Model transformation pathways with distinct decisions per period.
-
-```python
-import pandas as pd
-
-# Define multiple investment periods
-periods = pd.Index(['2020', '2030'])
-flow_system = fx.FlowSystem(time=timesteps, periods=periods)
-
-# Components can invest differently in each period
-solar = fx.Source(
- 'solar',
- outputs=[fx.Flow(
- 'P_el',
- bus='electricity',
- size=fx.InvestParameters(
- minimum_size=0,
- maximum_size=1000,
- effects_of_investment_per_size={'costs': 100}
- )
- )]
-)
-```
-
----
-
-### Scenario-Based Stochastic Optimization
-
-Model uncertainty with weighted scenarios.
-
-```python
-# Define scenarios with probabilities
-scenarios = pd.Index(['low_demand', 'base', 'high_demand'], name='scenario')
-scenario_weights = [0.2, 0.6, 0.2]
-
-flow_system = fx.FlowSystem(
- time=timesteps,
- scenarios=scenarios,
- scenario_weights=scenario_weights
-)
-
-# Define scenario-dependent data
-demand = xr.DataArray(
- data=[[70, 80, 90], # low_demand scenario
- [90, 100, 110], # base scenario
- [110, 120, 130]], # high_demand scenario
- dims=['scenario', 'time'],
- coords={'scenario': scenarios, 'time': timesteps}
-)
-```
-
-**Control variable independence:**
-```python
-# By default: investment sizes are shared across scenarios, flow rates vary
-# To make sizes scenario-independent:
-flow_system = fx.FlowSystem(
- time=timesteps,
- scenarios=scenarios,
- scenario_independent_sizes=True # Each scenario gets its own capacity
-)
-```
-
----
-
-### Enhanced I/O
-
-Save, load, and manipulate FlowSystems.
-
-```python
-# Save and load
-flow_system.to_netcdf('system.nc')
-fs = fx.FlowSystem.from_netcdf('system.nc')
-
-# Manipulate
-fs_subset = flow_system.sel(time=slice('2020-01', '2020-06'))
-fs_resampled = flow_system.resample(time='D') # Resample to daily
-fs_copy = flow_system.copy()
-
-# Access from results
-original_fs = results.flow_system # Lazily loaded
-```
-
----
-
-### Effects Per Component
-
-Analyze component impacts including indirect effects.
-
-```python
-# Get dataset showing contribution of each component to all effects
-effects_ds = results.effects_per_component
-
-print(effects_ds['total'].sel(effect='costs')) # Total costs by component
-print(effects_ds['temporal'].sel(effect='CO2')) # Temporal CO2 emissions by component (including indirect)
-```
-
----
-
-### Balanced Storage
+??? success "Scenario-Based Optimization"
-Force equal charging/discharging sizes.
-
-```python
-storage = fx.Storage(
- 'storage',
- charging=fx.Flow('charge', bus='electricity',
- size=fx.InvestParameters(effects_of_investment_per_size=100, minimum_size=5)),
- discharging=fx.Flow('discharge', bus='electricity', size=fx.InvestParameters()),
- balanced=True, # Ensures charge_size == discharge_size
- capacity_in_flow_hours=100
-)
-```
-
----
-
-### Final Charge State Control
-
-Set bounds on storage end state.
-
-```python
-storage = fx.Storage(
- 'storage',
- charging=fx.Flow('charge', bus='electricity', size=100),
- discharging=fx.Flow('discharge', bus='electricity', size=100),
- capacity_in_flow_hours=10,
- relative_minimum_final_charge_state=0.5, # End at least 50% charged
- relative_maximum_final_charge_state=0.8 # End at most 80% charged
-)
-```
-
----
-
-## ⚙️ Configuration
-
-### Logging
-
-Console and file logging now disabled by default (changed in v2.2.0).
-
-=== "v2.1.x and earlier"
```python
- import flixopt as fx
-
- # Logging was enabled by default
- calculation = fx.FullCalculation('calc', flow_system)
- calculation.solve() # Logs were shown automatically
+ scenarios = pd.Index(['low', 'base', 'high'], name='scenario')
+ flow_system = fx.FlowSystem(time=timesteps, scenarios=scenarios,
+ scenario_weights=[0.2, 0.6, 0.2], scenario_independent_sizes=True)
```
-=== "v2.2.0+ and v3.0.0"
- ```python
- import flixopt as fx
+??? success "Enhanced I/O"
- # Enable console logging explicitly
- fx.CONFIG.Logging.console = True
- fx.CONFIG.Logging.level = 'INFO'
- fx.CONFIG.apply()
+ `flow_system.to_netcdf()` • `fx.FlowSystem.from_netcdf()` • `flow_system.sel()` • `flow_system.resample()` • `results.flow_system`
- # Enable file logging (optional)
- fx.CONFIG.Logging.file = 'flixopt.log'
- fx.CONFIG.apply()
-
- calculation = fx.FullCalculation('calc', flow_system)
- calculation.solve() # Now logs are shown
- ```
+??? success "Effects Per Component"
-!!! tip "Quick Enable"
- Add at the start of your scripts:
```python
- import flixopt as fx
- fx.CONFIG.Logging.console = True
- fx.CONFIG.apply()
+ effects_ds = results.effects_per_component
+ print(effects_ds['total'].sel(effect='costs'))
```
----
-
-## 🧪 Testing
-
-### Check Deprecation Warnings
-
-```python
-import warnings
-warnings.filterwarnings('default', category=DeprecationWarning)
-
-# Run your flixopt code
-# Review any DeprecationWarning messages
-```
+??? success "Storage Features"
----
-
-### Validate Results
-
-Compare results from v2.x and v3.0.0 to ensure consistency:
-
-```python
-# Save v2.x results before upgrading
-calculation.results.to_file('results_v2.nc')
-
-# After upgrading, compare
-results_v3 = calculation.results
-results_v2 = fx.CalculationResults.from_file('results_v2.nc')
-
-# Check key variables match (within numerical tolerance)
-import numpy as np
-v2_costs = results_v2['effect_values'].sel(effect='costs')
-v3_costs = results_v3['effect_values'].sel(effect='costs')
-np.testing.assert_allclose(v2_costs, v3_costs, rtol=1e-5)
-```
+ **Balanced**: `balanced=True` ensures charge_size == discharge_size
+ **Final State**: `relative_minimum_final_charge_state=0.5`, `relative_maximum_final_charge_state=0.8`
---
## 🔧 Common Issues
-!!! failure "Effect shares not working"
- **Solution:** Effect sharing was completely redesigned. See [Effect System Redesign](#effect-system-redesign).
-
-!!! failure "Storage dimensions wrong"
- **Solution:** Remove extra timestep from charge state arrays. See [Storage Charge State](#storage-charge-state).
-
-!!! failure "Bus assignment error"
- **Solution:** Use string labels instead of Bus objects. See [Bus and Effect Assignment](#bus-and-effect-assignment).
-
-!!! failure "KeyError when accessing results"
- **Solution:** Variable names have changed. See [Variable Names in Results](#variable-names-in-results) for the complete mapping.
-
-!!! failure "AttributeError: Element x has no attribute `model`"
- **Solution:** Rename `.model` → `.submodel`. See [Other Breaking Changes](#other-breaking-changes).
-
-!!! failure "No logging output"
- **Solution:** Logging is disabled by default. See [Configuration](#configuration) to enable it.
+| Issue | Solution |
+|-------|----------|
+| Effect shares not working | See [Effect System Redesign](#effect-system-redesign) |
+| Storage dimensions wrong | See [FlowSystem & Calculation](#flowsystem-calculation) |
+| Bus assignment error | See [String Labels](#string-labels) |
+| KeyError in results | See [Variable Names](#variable-names) |
+| `AttributeError: model` | Rename `.model` → `.submodel` |
+| No logging | See [Other Changes](#other-changes) |
---
## ✅ Checklist
-**Critical (Breaking Changes):**
-
-- [ ] Update flixopt: `pip install --upgrade flixopt`
-- [ ] Update [effect sharing syntax](#effect-system-redesign) (no deprecation warning!)
-- [ ] Update [variable names in results](#variable-names-in-results)
-- [ ] Update [Bus/Effect assignments](#bus-and-effect-assignment) to use string labels
-- [ ] Update [Calculation API](#calculation-api) usage if accessing return value
-- [ ] Fix [storage charge state](#storage-charge-state) array dimensions
-- [ ] Rename plotting `mode` → `style`
-- [ ] Update class names: `SystemModel` → `FlowSystemModel`, `Model` → `Submodel`
-
-**Important:**
-
-- [ ] Enable [logging](#configuration) explicitly if needed
-- [ ] Update [deprecated parameters](#deprecated-parameters) (optional, but recommended)
-
-**Testing:**
-
-- [ ] Test your code thoroughly
-- [ ] Check for [deprecation warnings](#check-deprecation-warnings)
-- [ ] [Validate results](#validate-results) match v2.x output (if upgrading)
-
-**Optional:**
-
-- [ ] Explore [new features](#new-features)
+- [ ] `pip install --upgrade flixopt`
+- [ ] Update [effect sharing](#effect-system-redesign), [variable names](#variable-names), [string labels](#string-labels)
+- [ ] Fix [storage arrays](#flowsystem-calculation), [Calculation API](#flowsystem-calculation)
+- [ ] Rename `mode` → `style`, update [class names](#other-changes)
+- [ ] Enable [logging](#other-changes) if needed
+- [ ] Update [deprecated parameters](#deprecated-parameters)
+- [ ] Test & validate results
---
-## 📚 Getting Help
-
-:material-book: [Documentation](https://flixopt.github.io/flixopt/)
-:material-github: [GitHub Issues](https://github.com/flixOpt/flixopt/issues)
-:material-text-box: [Full Changelog](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
-
----
+:material-book: [Docs](https://flixopt.github.io/flixopt/) • :material-github: [Issues](https://github.com/flixOpt/flixopt/issues) • :material-text-box: [Changelog](https://flixopt.github.io/flixopt/latest/changelog/99984-v3.0.0/)
!!! success "Welcome to flixopt v3.0.0! 🎉"
From afb0d19711edde93bd29dc0d249ed97902aba1d1 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:02:44 +0200
Subject: [PATCH 15/42] Enable plugin
---
mkdocs.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/mkdocs.yml b/mkdocs.yml
index 72ecbe549..8ed2c4b2c 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -91,6 +91,7 @@ markdown_extensions:
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
+ - pymdownx.details
- pymdownx.superfences
- attr_list
- abbr
From 5cf023e87a586dcc00cd9a16deda2ba6598059e6 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:04:12 +0200
Subject: [PATCH 16/42] Update
---
docs/user-guide/migration-guide-v3.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index bafce112a..c2ff45f93 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -39,10 +39,10 @@ Terminology changed: `operation` → `temporal`, `invest/investment` → `period
| Old | New | Old | New |
|-----|-----|-----|-----|
-| `is_invested` | `invested` | `switch_on` | `switch\|on` |
-| `switch_off` | `switch\|off` | `switch_on_nr` | `switch\|count` |
-| `Effect(invest)\|total` | `Effect(periodic)` | `Effect(operation)\|total` | `Effect(temporal)` |
-| `Effect(operation)\|total_per_timestep` | `Effect(temporal)\|per_timestep` | `Effect\|total` | `Effect` |
+| `is_invested` | `invested` | `switch_on` | `switch|on` |
+| `switch_off` | `switch|off` | `switch_on_nr` | `switch|count` |
+| `Effect(invest)|total` | `Effect(periodic)` | `Effect(operation)|total` | `Effect(temporal)` |
+| `Effect(operation)|total_per_timestep` | `Effect(temporal)|per_timestep` | `Effect|total` | `Effect` |
---
From e61aa0228bb884a4565f088958b274f976eba6f2 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:08:46 +0200
Subject: [PATCH 17/42] Update
---
docs/user-guide/migration-guide-v3.md | 147 ++++++++++++++++++--------
1 file changed, 105 insertions(+), 42 deletions(-)
diff --git a/docs/user-guide/migration-guide-v3.md b/docs/user-guide/migration-guide-v3.md
index c2ff45f93..a98824de1 100644
--- a/docs/user-guide/migration-guide-v3.md
+++ b/docs/user-guide/migration-guide-v3.md
@@ -12,7 +12,14 @@
### Effect System Redesign
-Terminology changed: `operation` → `temporal`, `invest/investment` → `periodic`. Sharing inverted: effects now "pull" shares.
+Terminology changed and sharing system inverted: effects now "pull" shares.
+
+| Concept | Old (v2.x) | New (v3.0.0) |
+|---------|------------|--------------|
+| Time-varying effects | `operation` | `temporal` |
+| Investment effects | `invest` / `investment` | `periodic` |
+| Share to other effects (operation) | `specific_share_to_other_effects_operation` | `share_from_temporal` |
+| Share to other effects (invest) | `specific_share_to_other_effects_invest` | `share_from_periodic` |
=== "v2.x"
```python
@@ -25,30 +32,35 @@ Terminology changed: `operation` → `temporal`, `invest/investment` → `period
```python
CO2 = fx.Effect('CO2', 'kg', 'CO2')
costs = fx.Effect('costs', '€', 'Total',
- share_from_temporal={'CO2': 0.2})
+ share_from_temporal={'CO2': 0.2}) # Pull from CO2
```
!!! warning "No deprecation warning"
- - Move shares to receiving effect
- - `specific_share_to_other_effects_operation` → `share_from_temporal`
- - `specific_share_to_other_effects_invest` → `share_from_periodic`
+ Move shares to receiving effect and update parameter names throughout your code.
---
### Variable Names
-| Old | New | Old | New |
-|-----|-----|-----|-----|
-| `is_invested` | `invested` | `switch_on` | `switch|on` |
-| `switch_off` | `switch|off` | `switch_on_nr` | `switch|count` |
-| `Effect(invest)|total` | `Effect(periodic)` | `Effect(operation)|total` | `Effect(temporal)` |
-| `Effect(operation)|total_per_timestep` | `Effect(temporal)|per_timestep` | `Effect|total` | `Effect` |
+| Category | Old (v2.x) | New (v3.0.0) |
+|---------------------------------|------------|--------------|
+| Investment | `is_invested` | `invested` |
+| Switching | `switch_on` | `switch|on` |
+| Switching | `switch_off` | `switch|off` |
+| Switching | `switch_on_nr` | `switch|count` |
+| Effects | `Effect(invest)|total` | `Effect(periodic)` |
+| Effects | `Effect(operation)|total` | `Effect(temporal)` |
+| Effects | `Effect(operation)|total_per_timestep` | `Effect(temporal)|per_timestep` |
+| Effects | `Effect|total` | `Effect` |
---
### String Labels
-Use strings instead of objects for Bus/Effect references.
+| What | Old (v2.x) | New (v3.0.0) |
+|------|------------|--------------|
+| Bus assignment | `bus=my_bus` (object) | `bus='electricity'` (string) |
+| Effect shares | `{CO2: 0.2}` (object key) | `{'CO2': 0.2}` (string key) |
=== "v2.x"
```python
@@ -66,20 +78,24 @@ Use strings instead of objects for Bus/Effect references.
### FlowSystem & Calculation
-- **FlowSystem**: Each `Calculation` gets its own copy (independent)
-- **do_modeling()**: Returns `Calculation` (access model via `.model` property)
-- **Storage**: Arrays match timestep count (no extra element)
- - Use `relative_minimum_final_charge_state` for final state control
+| Change | Description |
+|--------|-------------|
+| **FlowSystem copying** | Each `Calculation` gets its own copy (independent) |
+| **do_modeling() return** | Returns `Calculation` object (access model via `.model` property) |
+| **Storage arrays** | Arrays match timestep count (no extra element) |
+| **Final charge state** | Use `relative_minimum_final_charge_state` / `relative_maximum_final_charge_state` |
---
### Other Changes
-| Category | Old | New |
-|----------|-----|-----|
-| Plotting | `mode='line'` | `style='line'` |
-| Classes | `SystemModel`, `Model` | `FlowSystemModel`, `Submodel` |
-| Logging | Enabled by default | Disabled (enable: `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()`) |
+| Category | Old (v2.x) | New (v3.0.0) |
+|----------|------------|--------------|
+| Plotting parameter | `mode='line'` | `style='line'` |
+| System model class | `SystemModel` | `FlowSystemModel` |
+| Element submodel | `Model` | `Submodel` |
+| Logging default | Enabled | Disabled |
+| Enable logging | (default) | `fx.CONFIG.Logging.console = True; fx.CONFIG.apply()` |
---
@@ -87,21 +103,44 @@ Use strings instead of objects for Bus/Effect references.
??? abstract "InvestParameters"
- `fix_effects` → `effects_of_investment` • `specific_effects` → `effects_of_investment_per_size` • `divest_effects` → `effects_of_retirement` • `piecewise_effects` → `piecewise_effects_of_investment`
+ | Old (v2.x) | New (v3.0.0) |
+ |------------|--------------|
+ | `fix_effects` | `effects_of_investment` |
+ | `specific_effects` | `effects_of_investment_per_size` |
+ | `divest_effects` | `effects_of_retirement` |
+ | `piecewise_effects` | `piecewise_effects_of_investment` |
??? abstract "Effect"
- `minimum_investment` → `minimum_periodic` • `maximum_investment` → `maximum_periodic` • `minimum_operation` → `minimum_temporal` • `maximum_operation` → `maximum_temporal` • `minimum_operation_per_hour` → `minimum_per_hour` • `maximum_operation_per_hour` → `maximum_per_hour`
+ | Old (v2.x) | New (v3.0.0) |
+ |------------|--------------|
+ | `minimum_investment` | `minimum_periodic` |
+ | `maximum_investment` | `maximum_periodic` |
+ | `minimum_operation` | `minimum_temporal` |
+ | `maximum_operation` | `maximum_temporal` |
+ | `minimum_operation_per_hour` | `minimum_per_hour` |
+ | `maximum_operation_per_hour` | `maximum_per_hour` |
??? abstract "Components"
- `source` → `outputs` • `sink` → `inputs` • `prevent_simultaneous_sink_and_source` → `prevent_simultaneous_flow_rates`
+ | Old (v2.x) | New (v3.0.0) |
+ |------------|--------------|
+ | `source` (parameter) | `outputs` |
+ | `sink` (parameter) | `inputs` |
+ | `prevent_simultaneous_sink_and_source` | `prevent_simultaneous_flow_rates` |
+
+??? abstract "TimeSeriesData"
+
+ | Old (v2.x) | New (v3.0.0) |
+ |------------|--------------|
+ | `agg_group` | `aggregation_group` |
+ | `agg_weight` | `aggregation_weight` |
-??? abstract "TimeSeriesData & Calculation"
+??? abstract "Calculation"
- - `agg_group` → `aggregation_group`
- - `agg_weight` → `aggregation_weight`
- - `active_timesteps` → Use `flow_system.sel()` or `flow_system.isel()`
+ | Old (v2.x) | New (v3.0.0) |
+ |------------|--------------|
+ | `active_timesteps=[0, 1, 2]` | Use `flow_system.sel()` or `flow_system.isel()` |
---
@@ -116,27 +155,51 @@ Use strings instead of objects for Bus/Effect references.
??? success "Scenario-Based Optimization"
+ | Parameter | Description | Example |
+ |-----------|-------------|---------|
+ | `scenarios` | Scenario index | `pd.Index(['low', 'base', 'high'], name='scenario')` |
+ | `scenario_weights` | Probabilities | `[0.2, 0.6, 0.2]` |
+ | `scenario_independent_sizes` | Separate capacities per scenario | `True` / `False` (default) |
+
```python
- scenarios = pd.Index(['low', 'base', 'high'], name='scenario')
- flow_system = fx.FlowSystem(time=timesteps, scenarios=scenarios,
- scenario_weights=[0.2, 0.6, 0.2], scenario_independent_sizes=True)
+ flow_system = fx.FlowSystem(
+ time=timesteps,
+ scenarios=scenarios,
+ scenario_weights=[0.2, 0.6, 0.2],
+ scenario_independent_sizes=True
+ )
```
??? success "Enhanced I/O"
- `flow_system.to_netcdf()` • `fx.FlowSystem.from_netcdf()` • `flow_system.sel()` • `flow_system.resample()` • `results.flow_system`
+ | Method | Description |
+ |--------|-------------|
+ | `flow_system.to_netcdf('file.nc')` | Save FlowSystem |
+ | `fx.FlowSystem.from_netcdf('file.nc')` | Load FlowSystem |
+ | `flow_system.sel(time=slice(...))` | Select by label |
+ | `flow_system.isel(time=slice(...))` | Select by index |
+ | `flow_system.resample(time='D')` | Resample timeseries |
+ | `flow_system.copy()` | Deep copy |
+ | `results.flow_system` | Access from results |
??? success "Effects Per Component"
```python
effects_ds = results.effects_per_component
- print(effects_ds['total'].sel(effect='costs'))
+
+ # Access effect contributions by component
+ print(effects_ds['total'].sel(effect='costs')) # Total effects
+ print(effects_ds['temporal'].sel(effect='CO2')) # Temporal effects
+ print(effects_ds['periodic'].sel(effect='costs')) # Periodic effects
```
??? success "Storage Features"
- **Balanced**: `balanced=True` ensures charge_size == discharge_size
- **Final State**: `relative_minimum_final_charge_state=0.5`, `relative_maximum_final_charge_state=0.8`
+ | Feature | Parameter | Description |
+ |---------|-----------|-------------|
+ | **Balanced storage** | `balanced=True` | Ensures charge_size == discharge_size |
+ | **Final state min** | `relative_minimum_final_charge_state=0.5` | End at least 50% charged |
+ | **Final state max** | `relative_maximum_final_charge_state=0.8` | End at most 80% charged |
---
@@ -155,13 +218,13 @@ Use strings instead of objects for Bus/Effect references.
## ✅ Checklist
-- [ ] `pip install --upgrade flixopt`
-- [ ] Update [effect sharing](#effect-system-redesign), [variable names](#variable-names), [string labels](#string-labels)
-- [ ] Fix [storage arrays](#flowsystem-calculation), [Calculation API](#flowsystem-calculation)
-- [ ] Rename `mode` → `style`, update [class names](#other-changes)
-- [ ] Enable [logging](#other-changes) if needed
-- [ ] Update [deprecated parameters](#deprecated-parameters)
-- [ ] Test & validate results
+| Category | Tasks |
+|----------|-------|
+| **Install** | • `pip install --upgrade flixopt` |
+| **Breaking changes** | • Update [effect sharing](#effect-system-redesign)
• Update [variable names](#variable-names)
• Update [string labels](#string-labels)
• Fix [storage arrays](#flowsystem-calculation)
• Update [Calculation API](#flowsystem-calculation)
• Rename plotting `mode` → `style`
• Update [class names](#other-changes) |
+| **Configuration** | • Enable [logging](#other-changes) if needed |
+| **Deprecated** | • Update [deprecated parameters](#deprecated-parameters) (recommended) |
+| **Testing** | • Test thoroughly
• Validate results match v2.x |
---
From fc8288fd351e910d72dcd6d358a077880e50ac5d Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:15:39 +0200
Subject: [PATCH 18/42] Customize
---
docs/stylesheets/extra.css | 223 ++++++++++++++++++++++++++++++
mkdocs.yml | 272 +++++++++++++++++++++++++++++--------
2 files changed, 438 insertions(+), 57 deletions(-)
create mode 100644 docs/stylesheets/extra.css
diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css
new file mode 100644
index 000000000..085d7f55c
--- /dev/null
+++ b/docs/stylesheets/extra.css
@@ -0,0 +1,223 @@
+/* ============================================================================
+ flixOpt Custom Styling
+ ========================================================================= */
+
+/* Root variables for easy customization */
+:root {
+ /* Spacing */
+ --content-padding: 2rem;
+
+ /* Typography */
+ --heading-font-weight: 600;
+
+ /* Colors - enhance teal theme */
+ --flixopt-teal: #009688;
+ --flixopt-teal-light: #4DB6AC;
+ --flixopt-teal-dark: #00796B;
+}
+
+/* Dark mode adjustments */
+[data-md-color-scheme="slate"] {
+ --md-code-bg-color: #1e1e1e;
+}
+
+/* ============================================================================
+ Typography Improvements
+ ========================================================================= */
+
+/* Better line height for readability */
+.md-typeset {
+ line-height: 1.7;
+}
+
+/* Enhanced headings */
+.md-typeset h1 {
+ font-weight: var(--heading-font-weight);
+ letter-spacing: -0.02em;
+ margin-top: 0;
+}
+
+.md-typeset h2 {
+ font-weight: var(--heading-font-weight);
+ border-bottom: 1px solid var(--md-default-fg-color--lightest);
+ padding-bottom: 0.3em;
+ margin-top: 2em;
+}
+
+/* Better code inline */
+.md-typeset code {
+ padding: 0.15em 0.4em;
+ border-radius: 0.25em;
+ font-size: 0.875em;
+}
+
+/* ============================================================================
+ Navigation Enhancements
+ ========================================================================= */
+
+/* Smooth hover effects on navigation */
+.md-nav__link:hover {
+ opacity: 0.7;
+ transition: opacity 0.2s ease;
+}
+
+/* Active navigation item enhancement */
+.md-nav__link--active {
+ font-weight: 600;
+ border-left: 3px solid var(--md-primary-fg-color);
+ padding-left: calc(1.2rem - 3px) !important;
+}
+
+/* ============================================================================
+ Code Block Improvements
+ ========================================================================= */
+
+/* Better code block styling */
+.md-typeset .highlight {
+ border-radius: 0.5rem;
+ margin: 1.5em 0;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+[data-md-color-scheme="slate"] .md-typeset .highlight {
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+}
+
+/* Line numbers styling */
+.md-typeset .highlight .linenos {
+ user-select: none;
+ opacity: 0.5;
+}
+
+/* Copy button enhancement */
+.md-clipboard {
+ opacity: 0;
+ transition: opacity 0.2s ease;
+}
+
+.highlight:hover .md-clipboard {
+ opacity: 1;
+}
+
+/* ============================================================================
+ Admonitions & Callouts
+ ========================================================================= */
+
+/* Enhanced admonitions */
+.md-typeset .admonition {
+ border-radius: 0.5rem;
+ border-left-width: 0.25rem;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+}
+
+/* ============================================================================
+ Tables
+ ========================================================================= */
+
+/* Better table styling */
+.md-typeset table:not([class]) {
+ border-radius: 0.5rem;
+ overflow: hidden;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+}
+
+.md-typeset table:not([class]) th {
+ background-color: var(--md-primary-fg-color);
+ color: white;
+ font-weight: 600;
+ text-align: left;
+}
+
+.md-typeset table:not([class]) tr:hover {
+ background-color: var(--md-default-fg-color--lightest);
+ transition: background-color 0.2s ease;
+}
+
+/* ============================================================================
+ API Documentation Styling
+ ========================================================================= */
+
+/* Better spacing for API docs */
+.doc-heading {
+ margin-top: 2rem !important;
+}
+
+/* Parameter tables */
+.doc-md-description table {
+ width: 100%;
+ font-size: 0.9em;
+}
+
+/* Signature styling */
+.doc-signature {
+ font-family: var(--md-code-font);
+ background-color: var(--md-code-bg-color);
+ border-radius: 0.5rem;
+ padding: 1rem;
+ overflow-x: auto;
+}
+
+/* ============================================================================
+ Home Page Hero (optional enhancement)
+ ========================================================================= */
+
+.hero {
+ text-align: center;
+ padding: 4rem 2rem;
+ background: linear-gradient(135deg, var(--flixopt-teal-light) 0%, var(--flixopt-teal-dark) 100%);
+ color: white;
+ border-radius: 1rem;
+ margin-bottom: 2rem;
+}
+
+.hero h1 {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+ color: white;
+ border: none;
+}
+
+.hero p {
+ font-size: 1.25rem;
+ opacity: 0.9;
+}
+
+/* ============================================================================
+ Responsive Design
+ ========================================================================= */
+
+@media screen and (max-width: 76.1875em) {
+ .md-typeset h1 {
+ font-size: 2rem;
+ }
+}
+
+@media screen and (max-width: 44.9375em) {
+ :root {
+ --content-padding: 1rem;
+ }
+
+ .hero h1 {
+ font-size: 2rem;
+ }
+
+ .hero p {
+ font-size: 1rem;
+ }
+}
+
+/* ============================================================================
+ Print Styles
+ ========================================================================= */
+
+@media print {
+ .md-typeset {
+ font-size: 0.9rem;
+ }
+
+ .md-header,
+ .md-sidebar,
+ .md-footer {
+ display: none;
+ }
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index 8ed2c4b2c..e67328e1b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,13 +1,16 @@
-# Options:
+# flixOpt Documentation Configuration
# https://mkdocstrings.github.io/python/usage/configuration/docstrings/
# https://squidfunk.github.io/mkdocs-material/setup/
-site_name: flixopt
+site_name: flixOpt
site_description: Energy and Material Flow Optimization Framework
site_url: https://flixopt.github.io/flixopt/
repo_url: https://github.com/flixOpt/flixopt
repo_name: flixOpt/flixopt
+# Copyright and social links
+copyright: Copyright © 2024 flixOpt Contributors
+
nav:
- Home: index.md
- User Guide:
@@ -39,126 +42,281 @@ nav:
- API Reference: api-reference/
- Release Notes: changelog/
-
theme:
name: material
+ language: en
+
palette:
- # Light mode
+ # Palette toggle for automatic mode
+ - media: "(prefers-color-scheme)"
+ toggle:
+ icon: material/brightness-auto
+ name: Switch to light mode
+
+ # Palette toggle for light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
- accent: blue
+ accent: cyan
toggle:
icon: material/brightness-7
name: Switch to dark mode
- # Dark mode
+
+ # Palette toggle for dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
- primary: teal # Can be different from light mode
- accent: blue
+ primary: teal
+ accent: cyan
toggle:
icon: material/brightness-4
- name: Switch to light mode
+ name: Switch to system preference
+
+ font:
+ text: Inter # Modern, readable font
+ code: Fira Code # Beautiful code font with ligatures
+
logo: images/flixopt-icon.svg
favicon: images/flixopt-icon.svg
+
icon:
repo: fontawesome/brands/github
+ edit: material/pencil
+ view: material/eye
+ annotation: material/plus-circle
+
features:
+ # Navigation
- navigation.instant
- navigation.instant.progress
+ - navigation.instant.prefetch
- navigation.tracking
- navigation.tabs
+ - navigation.tabs.sticky
- navigation.sections
+ - navigation.expand # Expand navigation by default
+ - navigation.path # Show breadcrumb path
+ - navigation.prune # Only render visible navigation
+ - navigation.indexes
- navigation.top
- navigation.footer
+
+ # Table of contents
- toc.follow
- - navigation.indexes
+ - toc.integrate # Integrate TOC into navigation (optional)
+
+ # Search
- search.suggest
- search.highlight
+ - search.share
+
+ # Content
- content.action.edit
- content.action.view
- content.code.copy
+ - content.code.select
- content.code.annotate
- content.tooltips
- - navigation.footer.version
+ - content.tabs.link # Link content tabs across pages
+
+ # Header
+ - announce.dismiss # Allow dismissing announcements
markdown_extensions:
+ # Content formatting
+ - abbr
- admonition
- - markdown_include.include:
- base_path: docs
+ - attr_list
+ - def_list
+ - footnotes
+ - md_in_html
+ - tables
+ - toc:
+ permalink: true
+ permalink_title: Anchor link to this section
+ toc_depth: 3
+
+ # Code blocks
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
+ auto_title: true
- pymdownx.inlinehilite
+ - pymdownx.snippets:
+ base_path: ..
+ check_paths: true
+ - pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format
+
+ # Enhanced content
- pymdownx.details
- - pymdownx.superfences
- - attr_list
- - abbr
- - md_in_html
- - footnotes
- - tables
- pymdownx.tabbed:
alternate_style: true
+ combine_header_slug: true
+ - pymdownx.tasklist:
+ custom_checkbox: true
+
+ # Typography
+ - pymdownx.betterem:
+ smart_enable: all
+ - pymdownx.caret
+ - pymdownx.mark
+ - pymdownx.tilde
+ - pymdownx.smartsymbols
+ - pymdownx.keys
+
+ # Math
- pymdownx.arithmatex:
generic: true
+
+ # Icons & emojis
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- - pymdownx.snippets:
- base_path: ..
+ options:
+ custom_icons:
+ - overrides/.icons
+
+ # Legacy support
+ - markdown_include.include:
+ base_path: docs
plugins:
- - search # Enables the search functionality in the documentation
- - table-reader # Allows including tables from external files
+ - search:
+ separator: '[\s\u200b\-_,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
+
+ - table-reader
+
- include-markdown
+
- mike:
+ alias_type: symlink
+ redirect_template: null
+ deploy_prefix: ''
+ canonical_version: null
version_selector: true
+ css_dir: css
+ javascript_dir: js
+
- literate-nav:
nav_file: SUMMARY.md
+ implicit_index: true
+
- gen-files:
scripts:
- - scripts/gen_ref_pages.py
- - mkdocstrings: # Handles automatic API documentation generation
- default_handler: python # Sets Python as the default language
- handlers:
- python: # Configuration for Python code documentation
- options:
- docstring_style: google # Sets google as the docstring style
- modernize_annotations: true # Improves type annotations
- merge_init_into_class: true # Promotes constructor parameters to class-level documentation
- docstring_section_style: table # Renders parameter sections as a table (also: list, spacy)
-
- members_order: source # Orders members as they appear in the source code
- inherited_members: false # Include members inherited from parent classes
- show_if_no_docstring: false # Documents objects even if they don't have docstrings
-
- group_by_category: true
- heading_level: 1 # Sets the base heading level for documented objects
- line_length: 80
- filters: ["!^_", "^__init__$"]
- show_root_heading: true # whether the documented object's name should be displayed as a heading at the beginning of its documentation
- show_source: false # Shows the source code implementation from documentation
- show_object_full_path: false # Displays simple class names instead of full import paths
- show_docstring_attributes: true # Shows class attributes in the documentation
- show_category_heading: true # Displays category headings (Methods, Attributes, etc.) for organization
- show_signature: true # Shows method signatures with parameters
- show_signature_annotations: true # Includes type annotations in the signatures when available
- show_root_toc_entry: false # Whether to show a link to the root of the documentation in the sidebar
- separate_signature: true # Displays signatures separate from descriptions for cleaner layout
-
- extra:
- infer_type_annotations: true # Uses Python type hints to supplement docstring information
+ - scripts/gen_ref_pages.py
+
+ - mkdocstrings:
+ enabled: !ENV [ENABLE_MKDOCSTRINGS, true]
+ default_handler: python
+ handlers:
+ python:
+ paths: [.]
+ import:
+ - https://docs.python.org/3/objects.inv
+ - https://numpy.org/doc/stable/objects.inv
+ - https://pandas.pydata.org/docs/objects.inv
+ options:
+ # Docstring parsing
+ docstring_style: google
+ docstring_section_style: table
+
+ # Member ordering and filtering
+ members_order: source
+ inherited_members: false
+ show_if_no_docstring: false
+ filters: ["!^_", "^__init__$"]
+ group_by_category: true
+
+ # Headings and structure
+ heading_level: 1
+ show_root_heading: true
+ show_root_toc_entry: false
+ show_category_heading: true
+
+ # Signatures
+ show_signature: true
+ show_signature_annotations: true
+ separate_signature: true
+ line_length: 80
+
+ # Source and paths
+ show_source: false
+ show_object_full_path: false
+
+ # Attributes and annotations
+ show_docstring_attributes: true
+ modernize_annotations: true
+ merge_init_into_class: true
+
+ # Improved type hints
+ annotations_path: brief
+
+ # Optional: Add git info
+ - git-revision-date-localized:
+ enable_creation_date: true
+ type: timeago
+ fallback_to_build_date: true
+
+ # Optional: Add better navigation
+ - tags:
+ tags_file: tags.md
+
+ # Optional: Minify HTML in production
+ - minify:
+ minify_html: true
+ minify_js: true
+ minify_css: true
+ htmlmin_opts:
+ remove_comments: true
extra:
version:
provider: mike
default: latest
+ alias: true
+
+ social:
+ - icon: fontawesome/brands/github
+ link: https://github.com/flixOpt/flixopt
+ name: flixOpt on GitHub
+ - icon: fontawesome/brands/python
+ link: https://pypi.org/project/flixopt/
+ name: flixOpt on PyPI
+
+ analytics:
+ provider: google
+ property: !ENV GOOGLE_ANALYTICS_KEY
+ feedback:
+ title: Was this page helpful?
+ ratings:
+ - icon: material/emoticon-happy-outline
+ name: This page was helpful
+ data: 1
+ note: >-
+ Thanks for your feedback!
+ - icon: material/emoticon-sad-outline
+ name: This page could be improved
+ data: 0
+ note: >-
+ Thanks for your feedback! Help us improve by
+ opening an issue.
+
+ status:
+ new: Recently added
+ deprecated: Deprecated
+
+extra_css:
+ - stylesheets/extra.css
extra_javascript:
- - javascripts/mathjax.js # Custom MathJax 3 CDN Configuration
- - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js #MathJax 3 CDN
- - https://polyfill.io/v3/polyfill.min.js?features=es6 #Support for older browsers
+ - javascripts/mathjax.js
+ - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
+ - https://polyfill.io/v3/polyfill.min.js?features=es6
watch:
- flixopt
+ - overrides
From 3d83127a44a334ce2df01498508af36b924d7bec Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:20:12 +0200
Subject: [PATCH 19/42] Customize
---
mkdocs.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/mkdocs.yml b/mkdocs.yml
index e67328e1b..ddfb3dff0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -319,4 +319,3 @@ extra_javascript:
watch:
- flixopt
- - overrides
From 7fb19dd3c6b21a2d7a50b5e5aa52c7f18466876b Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:20:59 +0200
Subject: [PATCH 20/42] Add deps
---
pyproject.toml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 9e1821a4b..0bf559b7d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,9 +34,9 @@ dependencies = [
# Core scientific computing
"numpy >= 1.21.5, < 3",
"pandas >= 2.0.0, < 3",
- "xarray >= 2024.2.0, < 2026.0", # CalVer: allow through next calendar year
+ "xarray >= 2024.2.0, < 2026.0", # CalVer: allow through next calendar year
# Optimization and data handling
- "linopy >= 0.5.1, < 0.6", # Widened from patch pin to minor range
+ "linopy >= 0.5.1, < 0.6", # Widened from patch pin to minor range
"h5netcdf>=1.0.0, < 2",
# Utilities
"pyyaml >= 6.0.0, < 7",
@@ -44,13 +44,11 @@ dependencies = [
"tomli >= 2.0.1, < 3; python_version < '3.11'", # Only needed with python 3.10 or earlier
# Default solver
"highspy >= 1.5.3, < 2",
-
# Visualization
"matplotlib >= 3.5.2, < 4",
"plotly >= 5.15.0, < 7",
-
# Fix for numexpr compatibility issue with numpy 1.26.4 on Python 3.10
- "numexpr >= 2.8.4, < 2.14; python_version < '3.11'", # Avoid 2.14.0 on older Python
+ "numexpr >= 2.8.4, < 2.14; python_version < '3.11'", # Avoid 2.14.0 on older Python
]
[project.optional-dependencies]
@@ -108,6 +106,8 @@ docs = [
"pymdown-extensions==10.16.1",
"pygments==2.19.2",
"mike==2.1.3",
+ "mkdocs-git-revision-date-localized-plugin==1.4.7",
+ "mkdocs-minify-plugin==0.8.0",
]
[project.urls]
From 5b3262743b0b9e5ff7817cc5527ea07c4683b011 Mon Sep 17 00:00:00 2001
From: FBumann <117816358+FBumann@users.noreply.github.com>
Date: Thu, 16 Oct 2025 13:21:10 +0200
Subject: [PATCH 21/42] Make index.md pretty
---
docs/index.md | 343 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 336 insertions(+), 7 deletions(-)
diff --git a/docs/index.md b/docs/index.md
index 6723c4d5e..25cad9719 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,22 +1,351 @@
+---
+title: Home
+hide:
+ - navigation
+ - toc
+---
+
+
+
+
Energy and Material Flow Optimization Framework
+ +Model, optimize, and analyze complex energy systems with a powerful Python framework designed for flexibility and performance. + + + +Efficient optimization algorithms powered by industry-standard solvers for fast computation of complex energy systems
+Flexible component-based architecture allowing you to build systems from flows, buses, storage, and converters
+Support for piecewise linearization, on/off parameters, investment decisions, and duration tracking
+Clean, intuitive interface with comprehensive type hints and excellent documentation
+Extensive guides, mathematical notation, examples, and API reference to get you productive quickly
+MIT licensed and community-driven development with contributions welcome
+New to FlixOpt? Start here with installation and your first model
+ + + +Explore real-world examples from simple to complex systems
+ + + +Detailed documentation of all classes, methods, and parameters
+ + + +Common patterns and best practices for modeling energy systems
+ + + +Understand the mathematical formulations behind the framework
+ + + +See what's coming next and contribute to the future of FlixOpt
+ + +Energy and Material Flow Optimization Framework
-Model, optimize, and analyze complex energy systems with a powerful Python framework designed for flexibility and performance. +Model, optimize, and analyze complex energy systems with a powerful Python framework designed for flexibility and performance.
- +Model, optimize, and analyze complex energy systems with a powerful Python framework designed for flexibility and performance.
@@ -196,42 +196,66 @@ hide: ## :material-star-four-points: Key Features -Efficient optimization algorithms powered by industry-standard solvers for fast computation of complex energy systems
Flexible component-based architecture allowing you to build systems from flows, buses, storage, and converters
+Support for piecewise linearization, on/off parameters, investment decisions, and duration tracking
+Clean, intuitive interface with comprehensive type hints and excellent documentation
+Extensive guides, mathematical notation, examples, and API reference to get you productive quickly
+MIT licensed and community-driven development with contributions welcome
+Ask questions and share your projects with the community
- Join Discussion → +Help improve FlixOpt by contributing code, docs, or examples
- Learn How → +New to FlixOpt? Start here with installation and your first model
- -Explore real-world examples from simple to complex systems
+ + +### :material-lightbulb-on: Examples Gallery + +Explore real-world examples from simple to complex systems + - -Detailed documentation of all classes, methods, and parameters
+ + +### :material-api: API Reference + +Detailed documentation of all classes, methods, and parameters + - -Common patterns and best practices for modeling energy systems
+ + +### :material-book-open-variant: Recipes + +Common patterns and best practices for modeling energy systems + - -Understand the mathematical formulations behind the framework
+ + +### :material-math-integral: Mathematical Notation + +Understand the mathematical formulations behind the framework + - -See what's coming next and contribute to the future of FlixOpt
+ + +### :material-road-variant: Roadmap + +See what's coming next and contribute to the future of FlixOpt +New to FlixOpt? Start here with installation and your first model
+ + + +Explore real-world examples from simple to complex systems
+ + + +Detailed documentation of all classes, methods, and parameters
+ + + +Common patterns and best practices for modeling energy systems
+ + + +Understand the mathematical formulations behind the framework
+ + + +See what's coming next and contribute to the future of FlixOpt
+