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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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/18] 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 7de0ae6fa4569ce9c8ce5211b73cdce1ff36ec46 Mon Sep 17 00:00:00 2001 From: FBumann <117816358+FBumann@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:57:33 +0200 Subject: [PATCH 18/18] Update CHangelog.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c10105538..632fcf7a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ Please keep the format of the changelog consistent with the other releases, so t ### ๐Ÿ“ฆ Dependencies ### ๐Ÿ“ Docs +- Updated Migration Guide and added missing entries. +- Improved Changelog of v3.0.0 ### ๐Ÿ‘ท Development