Skip to content

Releases: flixOpt/flixopt

v5.0.3

18 Dec 10:10

Choose a tag to compare

Summary: Cleaner notebook outputs and improved CONFIG.notebook() preset.

♻️ Changed

  • CONFIG.notebook() now suppresses linopy progress bars via progress=False in solve calls
  • Downgraded "FlowSystem not connected" message from WARNING to INFO (auto-connects anyway)

πŸ› Fixed

  • Fixed notebooks triggering unnecessary warnings (removed relative_minimum without status_parameters)

πŸ“ Docs

  • Consolidated verbose print statements into concise single-line summaries across all tutorial notebooks
  • Added output suppression (;) to optimize() 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

17 Dec 12:49

Choose a tag to compare

♻️ Changed

  • statistics.plot.effects() now defaults to by=None for aggregated totals; use by='component' for the previous behavior

What's Changed

Full Changelog: v5.0.1...v5.0.2

v5.0.1

17 Dec 07:45

Choose a tag to compare

πŸ‘· Development

  • Fixed docs deployment in CI workflow

Full Changelog: v5.0.0...v5.0.1

v5.0.0

17 Dec 07:14

Choose a tag to compare

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 contributor

Comprehensive 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.heat

Transform 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 works

NetCDF Improvements:

  • Default compression level 5 for smaller files
  • overwrite=False parameter 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 data
  • figure: 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 1e5 to None (strict balance)
  • with_excess β†’ allows_imbalance
  • excess_input β†’ virtual_supply
  • excess_output β†’ virtual_demand

Storage charge_state changes:

  • charge_state no 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_supply and BusModel.excess_output β†’ virtual_demand for 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 β†’ Use flow_system.optimize(solver)
  • ClusteredOptimization β†’ Use flow_system.transform.cluster() then optimize()
  • SegmentedOptimization β†’ Use flow_system.optimize.rolling_horizon()
  • Results β†’ Use flow_system.solution and flow_system.statistics
  • SegmentedResults β†’ Use segment FlowSystems directly

FlowSystem methods deprecated:

  • flow_system.sel() β†’ Use flow_system.transform.sel()
  • flow_system.isel() β†’ Use flow_system.transform.isel()
  • flow_system.resample() β†’ Use flow_system.transform.resample()
  • flow_system.plot_network() β†’ Use flow_system.topology.plot_network()
  • flow_system.start_network_app() β†’ Use flow_system.topology.start_network_app()
  • flow_system.stop_network_app() β†’ Use flow_system.topology.stop_network_app()
  • flow_system.network_infos() β†’ Use flow_system.topology.network_infos()

Results methods deprecated:

  • results.flow_rates() β†’ Use flow_system.statistics.flow_rates
  • results.flow_hours() β†’ Use flow_system.statistics.flow_hours

Migration helpers (temporary, also deprecated):

  • FlowSystem.from_old_results() β†’ ...
Read more

v4.3.4

29 Nov 02:56

Choose a tag to compare

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

27 Nov 21:08

Choose a tag to compare

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

27 Nov 12:57

Choose a tag to compare

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

26 Nov 21:55

Choose a tag to compare

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.json file for Zenodo metadata configuration
    • Repository now ready for DOI assignment upon next release

What's Changed

  • Added Zenodo to repository for citations by @FBumann in #433

Full Changelog: v4.3.0...v4.3.1

v4.3.0

25 Nov 17:45

Choose a tag to compare

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)'] and results.solution['Penalty(periodic)'] if needed

πŸ“ 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

25 Nov 16:13

Choose a tag to compare

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

  • overwrite parameter 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 β†’ Optimization
  • AggregatedCalculation β†’ ClusteredOptimization
  • SegmentedCalculation β†’ SegmentedOptimization
  • CalculationResults β†’ Results
  • SegmentedCalculationResults β†’ SegmentedResults
  • Aggregation β†’ Clustering
  • AggregationParameters β†’ ClusteringParameters
  • AggregationModel β†’ 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 optional ds parameter

πŸ‘· Development

  • Fixed active_timesteps type annotation to include None
  • Fixed xarray truth-value ambiguity in main_results buses with excess filter
  • Added validation for nr_of_previous_values in SegmentedOptimization to 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