Releases: flixOpt/flixopt
v5.0.3
Summary: Cleaner notebook outputs and improved CONFIG.notebook() preset.
β»οΈ Changed
CONFIG.notebook()now suppresses linopy progress bars viaprogress=Falsein solve calls- Downgraded "FlowSystem not connected" message from WARNING to INFO (auto-connects anyway)
π Fixed
- Fixed notebooks triggering unnecessary warnings (removed
relative_minimumwithoutstatus_parameters)
π Docs
- Consolidated verbose print statements into concise single-line summaries across all tutorial notebooks
- Added output suppression (
;) tooptimize()calls for cleaner cell output - Fixed notebook 07 parameters so CHP investment produces interesting results (was 0 kW, now 100 kW)
What's Changed
- feat: better notebooks, removed obsolete warnings and remove progres bars when not logging solve to console by @FBumann in #536
Full Changelog: v5.0.2...v5.0.3
v5.0.2
β»οΈ Changed
statistics.plot.effects()now defaults toby=Nonefor aggregated totals; useby='component'for the previous behavior
What's Changed
Full Changelog: v5.0.1...v5.0.2
v5.0.1
v5.0.0
Summary: This is a major release that introduces the new FlowSystem-centric API, dramatically simplifying workflows by integrating optimization, results access, and visualization directly into the FlowSystem object. This release also completes the terminology standardization (OnOff β Status) and deprecates the old Optimization/Results workflow (to be removed in v6.0.0).
!!! tip "Migration Guide"
See the [Migration Guide v5](https://flixopt.github.io/flixopt/latest/user-guide/migration-guide-v5/) for step-by-step upgrade instructions.
β¨ Added
FlowSystem-Centric Architecture: The FlowSystem is now the central hub for all operations:
import flixopt as fx
# Create and configure your system
flow_system = fx.FlowSystem(timesteps)
flow_system.add_elements(boiler, heat_bus, costs)
# Optimize directly on FlowSystem
flow_system.optimize(fx.solvers.HighsSolver())
# Access results via solution Dataset
total_costs = flow_system.solution['costs'].item()
flow_rate = flow_system.solution['Boiler(Q_th)|flow_rate'].values
# Plot with new accessor API
flow_system.statistics.plot.balance('HeatBus')
flow_system.statistics.plot.sankey.flows()New Accessor-Based API: Four accessor patterns provide organized, discoverable interfaces:
| Accessor | Purpose | Example |
|---|---|---|
flow_system.statistics |
Data access (flow rates, sizes, effects) | flow_system.statistics.flow_rates |
flow_system.statistics.plot |
Visualization methods | flow_system.statistics.plot.balance('Bus') |
flow_system.transform |
FlowSystem transformations | flow_system.transform.cluster(params) |
flow_system.topology |
Network structure & visualization | flow_system.topology.plot_network() |
Statistics Accessor: Access aggregated results data with clean, consistent naming:
stats = flow_system.statistics
# Flow data (clean labels, no |flow_rate suffix needed)
stats.flow_rates['Boiler(Q_th)']
stats.flow_hours['Boiler(Q_th)']
stats.sizes['Boiler(Q_th)']
stats.charge_states['Battery']
# Effect breakdown by contributor
stats.temporal_effects['costs'] # Per timestep, per contributor
stats.periodic_effects['costs'] # Investment costs per contributor
stats.total_effects['costs'] # Total per contributorComprehensive Plotting API: All plots return PlotResult objects with chainable methods:
# Balance plots for buses and components
flow_system.statistics.plot.balance('ElectricityBus')
flow_system.statistics.plot.balance('Boiler', mode='area')
# Storage visualization with charge state
flow_system.statistics.plot.storage('Battery')
# Heatmaps with automatic time reshaping
flow_system.statistics.plot.heatmap('Boiler(Q_th)|flow_rate', reshape=('D', 'h'))
# Flow-based Sankey diagrams
flow_system.statistics.plot.sankey.flows()
flow_system.statistics.plot.sankey.flows(select={'bus': 'ElectricityBus'})
# Effect contribution Sankey
flow_system.statistics.plot.sankey.effects('costs')
# Method chaining for customization and export
flow_system.statistics.plot.balance('Bus') \
.update(title='Custom Title', height=600) \
.to_html('plot.html') \
.to_csv('data.csv') \
.show()Carrier Management: New Carrier class for consistent styling across visualizations:
# Define custom carriers
electricity = fx.Carrier('electricity', '#FFD700', 'kW', 'Electrical power')
district_heat = fx.Carrier('district_heat', '#FF6B6B', 'kW_th')
# Register with FlowSystem
flow_system.add_carrier(electricity)
# Use with buses (reference by name)
elec_bus = fx.Bus('MainGrid', carrier='electricity')
# Or use predefined carriers from CONFIG
fx.CONFIG.Carriers.electricity
fx.CONFIG.Carriers.heatTransform Accessor: Transformations that create new FlowSystem instances:
# Time selection and resampling
fs_subset = flow_system.transform.sel(time=slice('2023-01-01', '2023-06-30'))
fs_resampled = flow_system.transform.resample(time='4h', method='mean')
# Clustered optimization
params = fx.ClusteringParameters(hours_per_period=24, nr_of_periods=8)
clustered_fs = flow_system.transform.cluster(params)
clustered_fs.optimize(solver)Rolling Horizon Optimization: Decompose large operational problems into sequential segments:
# Solve with rolling horizon
segments = flow_system.optimize.rolling_horizon(
solver,
horizon=192, # Timesteps per segment
overlap=48, # Lookahead for storage optimization
)
# Combined solution available on original FlowSystem
total_cost = flow_system.solution['costs'].item()
# Individual segments also available
for seg in segments:
print(seg.solution['costs'].item())Solution Persistence: FlowSystem now stores and persists solutions:
# Optimize and save with solution
flow_system.optimize(solver)
flow_system.to_netcdf('results/my_model.nc4')
# Load FlowSystem with solution intact
loaded_fs = fx.FlowSystem.from_netcdf('results/my_model.nc4')
print(loaded_fs.solution['costs'].item()) # Solution is available!Migration Helper for Old Results (deprecated, temporary):
# Migrate old result files to new FlowSystem format
fs = fx.FlowSystem.from_old_results('results_folder', 'my_model')
# Or convert Results object directly
fs = results.convert_to_flow_system()FlowSystem Locking: FlowSystem automatically locks after optimization to prevent accidental modifications:
flow_system.optimize(solver)
# This would raise an error:
# flow_system.add_elements(new_component) # Locked!
# Call reset() to unlock for modifications
flow_system.reset()
flow_system.add_elements(new_component) # Now worksNetCDF Improvements:
- Default compression level 5 for smaller files
overwrite=Falseparameter to prevent accidental overwrites- Solution data included in FlowSystem NetCDF files
- Automatic name assignment from filename
PlotResult Class: All plotting methods return a PlotResult object containing both:
data: An xarray Dataset with the prepared datafigure: A Plotly Figure object
Component color parameter: Components now accept a color parameter for consistent visualization styling.
π₯ Breaking Changes
Renamed OnOffParameters β StatusParameters: Complete terminology update to align with industry standards (PyPSA, unit commitment). Old NetCDF files with OnOffParameters are automatically converted on load.
| Old Term | New Term |
|---|---|
OnOffParameters |
StatusParameters |
on_off_parameters |
status_parameters |
on variable |
status |
switch_on |
startup |
switch_off |
shutdown |
switch_on_nr |
startup_count |
on_hours_total |
active_hours |
consecutive_on_hours |
uptime |
consecutive_off_hours |
downtime |
effects_per_switch_on |
effects_per_startup |
effects_per_running_hour |
effects_per_active_hour |
consecutive_on_hours_min |
min_uptime |
consecutive_on_hours_max |
max_uptime |
consecutive_off_hours_min |
min_downtime |
consecutive_off_hours_max |
max_downtime |
switch_on_total_max |
startup_limit |
force_switch_on |
force_startup_tracking |
on_hours_min |
active_hours_min |
on_hours_max |
active_hours_max |
Bus imbalance terminology and default changed:
excess_penalty_per_flow_hourβimbalance_penalty_per_flow_hour- Default changed from
1e5toNone(strict balance) with_excessβallows_imbalanceexcess_inputβvirtual_supplyexcess_outputβvirtual_demand
Storage charge_state changes:
charge_stateno longer has an extra timestep- Final charge state is now a separate variable:
charge_state|final
Effect.description now defaults to '' (empty string) instead of None.
Stricter I/O: NetCDF loading is stricter to prevent silent errors. Missing or corrupted data now raises explicit errors.
Validation: Component with status_parameters now validates that all flows have sizes (required for big-M constraints).
β»οΈ Changed
- Renamed
BusModel.excess_inputβvirtual_supplyandBusModel.excess_outputβvirtual_demandfor clearer semantics - Renamed
Bus.excess_penalty_per_flow_hourβimbalance_penalty_per_flow_hour - Renamed
Bus.with_excessβallows_imbalance
ποΈ Deprecated
All deprecated items will be removed in v6.0.0.
Old Optimization Workflow - Use FlowSystem methods instead:
# Old (deprecated, still works with warning)
optimization = fx.Optimization('model', flow_system)
optimization.do_modeling()
optimization.solve(solver)
results = optimization.results
costs = results.model['costs'].solution.item()
# New (recommended)
flow_system.optimize(solver)
costs = flow_system.solution['costs'].item()Classes deprecated:
Optimizationβ Useflow_system.optimize(solver)ClusteredOptimizationβ Useflow_system.transform.cluster()thenoptimize()SegmentedOptimizationβ Useflow_system.optimize.rolling_horizon()Resultsβ Useflow_system.solutionandflow_system.statisticsSegmentedResultsβ Use segment FlowSystems directly
FlowSystem methods deprecated:
flow_system.sel()β Useflow_system.transform.sel()flow_system.isel()β Useflow_system.transform.isel()flow_system.resample()β Useflow_system.transform.resample()flow_system.plot_network()β Useflow_system.topology.plot_network()flow_system.start_network_app()β Useflow_system.topology.start_network_app()flow_system.stop_network_app()β Useflow_system.topology.stop_network_app()flow_system.network_infos()β Useflow_system.topology.network_infos()
Results methods deprecated:
results.flow_rates()β Useflow_system.statistics.flow_ratesresults.flow_hours()β Useflow_system.statistics.flow_hours
Migration helpers (temporary, also deprecated):
FlowSystem.from_old_results()β ...
v4.3.4
Summary: Fix zenodo again
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
What's Changed
Full Changelog: v4.3.3...v4.3.4
v4.3.3
Summary: Fix zenodo again
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
Full Changelog: v4.3.2...v4.3.3
v4.3.2
Summary: Fix zenodo
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
Full Changelog: v4.3.1...v4.3.2
v4.3.1
Summary: Add zenodo for better citations and archiving.
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
π Docs
- Added Zenodo DOI badge to README.md (placeholder, to be updated after first Zenodo release)
π· Development
- Added Zenodo integration for automatic archival and citation
- Created
.zenodo.jsonfile for Zenodo metadata configuration - Repository now ready for DOI assignment upon next release
- Created
What's Changed
Full Changelog: v4.3.0...v4.3.1
v4.3.0
Summary: Penalty is now a first-class Effect - add penalty contributions anywhere (e.g., effects_per_flow_hour={'Penalty': 2.5}) and optionally define bounds as with any other effect.
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
β¨ Added
- Penalty as first-class Effect: Users can now add Penalty contributions anywhere effects are used:
fx.Flow('Q', 'Bus', effects_per_flow_hour={'Penalty': 2.5}) fx.InvestParameters(..., effects_of_investment={'Penalty': 100})
- User-definable Penalty: Optionally define custom Penalty with constraints (auto-created if not defined):
penalty = fx.Effect(fx.PENALTY_EFFECT_LABEL, unit='β¬', maximum_total=1e6) flow_system.add_elements(penalty)
β»οΈ Changed
- Penalty is now a standard Effect with temporal/periodic dimensions, and periodic weights in the objective
- Results structure: Penalty now has same structure as other effects in solution Dataset
- Use
results.solution['Penalty']for total penalty value (same as before, but now it's an effect variable) - Access components via
results.solution['Penalty(temporal)']andresults.solution['Penalty(periodic)']if needed
- Use
π Docs
- Updated mathematical notation for Penalty as Effect
π· Development
- Unified interface: Penalty uses same
add_share_to_effects()as other effects (internal only)
What's Changed
Full Changelog: v4.2.0...v4.3.0
v4.2.0
Summary: Renamed classes and parameters related to Calculation, Aggregation and Results. Fully backwards compatible
If upgrading from v2.x, see the v3.0.0 release notes and Migration Guide.
β¨ Added
overwriteparameter when saving results to file. If True, overwrite existing files.
β»οΈ Changed
- Now creates the Results folder even if parents didnt exist
ποΈ Deprecated
Class and module renaming:
FullCalculationβOptimizationAggregatedCalculationβClusteredOptimizationSegmentedCalculationβSegmentedOptimizationCalculationResultsβResultsSegmentedCalculationResultsβSegmentedResultsAggregationβClusteringAggregationParametersβClusteringParametersAggregationModelβClusteringModel- Module:
calculation.pyβoptimization.py - Module:
aggregation.pyβclustering.py
Old names remain available with deprecation warnings (removed in v5.0.0).
π Fixed
- Fixed
fix_sizes()docstring/implementation inconsistency for optionaldsparameter
π· Development
- Fixed
active_timestepstype annotation to includeNone - Fixed xarray truth-value ambiguity in
main_resultsbuses with excess filter - Added validation for
nr_of_previous_valuesinSegmentedOptimizationto prevent silent indexing bugs
What's Changed
- chore(deps): update dependency dash to v3.3.0 by @renovate[bot] in #491
- chore(deps): update dependency astral-sh/uv to v0.9.10 by @renovate[bot] in #490
- Feature/rename calculation 2 by @FBumann in #484
Full Changelog: v4.1.4...v4.2.0