flixopt 3.0.1__py3-none-any.whl → 6.0.0rc7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flixopt/__init__.py +57 -49
- flixopt/carrier.py +159 -0
- flixopt/clustering/__init__.py +51 -0
- flixopt/clustering/base.py +1746 -0
- flixopt/clustering/intercluster_helpers.py +201 -0
- flixopt/color_processing.py +372 -0
- flixopt/comparison.py +819 -0
- flixopt/components.py +848 -270
- flixopt/config.py +853 -496
- flixopt/core.py +111 -98
- flixopt/effects.py +294 -284
- flixopt/elements.py +484 -223
- flixopt/features.py +220 -118
- flixopt/flow_system.py +2026 -389
- flixopt/interface.py +504 -286
- flixopt/io.py +1718 -55
- flixopt/linear_converters.py +291 -230
- flixopt/modeling.py +304 -181
- flixopt/network_app.py +2 -1
- flixopt/optimization.py +788 -0
- flixopt/optimize_accessor.py +373 -0
- flixopt/plot_result.py +143 -0
- flixopt/plotting.py +1177 -1034
- flixopt/results.py +1331 -372
- flixopt/solvers.py +12 -4
- flixopt/statistics_accessor.py +2412 -0
- flixopt/stats_accessor.py +75 -0
- flixopt/structure.py +954 -120
- flixopt/topology_accessor.py +676 -0
- flixopt/transform_accessor.py +2277 -0
- flixopt/types.py +120 -0
- flixopt-6.0.0rc7.dist-info/METADATA +290 -0
- flixopt-6.0.0rc7.dist-info/RECORD +36 -0
- {flixopt-3.0.1.dist-info → flixopt-6.0.0rc7.dist-info}/WHEEL +1 -1
- flixopt/aggregation.py +0 -382
- flixopt/calculation.py +0 -672
- flixopt/commons.py +0 -51
- flixopt/utils.py +0 -86
- flixopt-3.0.1.dist-info/METADATA +0 -209
- flixopt-3.0.1.dist-info/RECORD +0 -26
- {flixopt-3.0.1.dist-info → flixopt-6.0.0rc7.dist-info}/licenses/LICENSE +0 -0
- {flixopt-3.0.1.dist-info → flixopt-6.0.0rc7.dist-info}/top_level.txt +0 -0
flixopt/__init__.py
CHANGED
|
@@ -2,68 +2,76 @@
|
|
|
2
2
|
This module bundles all common functionality of flixopt and sets up the logging
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import logging
|
|
6
6
|
from importlib.metadata import PackageNotFoundError, version
|
|
7
7
|
|
|
8
8
|
try:
|
|
9
9
|
__version__ = version('flixopt')
|
|
10
|
-
except PackageNotFoundError:
|
|
10
|
+
except (PackageNotFoundError, TypeError):
|
|
11
11
|
# Package is not installed (development mode without editable install)
|
|
12
12
|
__version__ = '0.0.0.dev0'
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
# Import commonly used classes and functions
|
|
15
|
+
# Register xarray accessors:
|
|
16
|
+
# - xr.Dataset.plotly / xr.DataArray.plotly (from xarray_plotly package)
|
|
17
|
+
# - xr.Dataset.fxstats (from stats_accessor)
|
|
18
|
+
import xarray_plotly as _xpx # noqa: F401
|
|
19
|
+
|
|
20
|
+
from . import clustering, linear_converters, plotting, results, solvers
|
|
21
|
+
from . import stats_accessor as _fxstats # noqa: F401
|
|
22
|
+
from .carrier import Carrier, CarrierContainer
|
|
23
|
+
from .comparison import Comparison
|
|
24
|
+
from .components import (
|
|
24
25
|
LinearConverter,
|
|
25
|
-
OnOffParameters,
|
|
26
|
-
Piece,
|
|
27
|
-
Piecewise,
|
|
28
|
-
PiecewiseConversion,
|
|
29
|
-
PiecewiseEffects,
|
|
30
|
-
SegmentedCalculation,
|
|
31
26
|
Sink,
|
|
32
27
|
Source,
|
|
33
28
|
SourceAndSink,
|
|
34
29
|
Storage,
|
|
35
|
-
TimeSeriesData,
|
|
36
30
|
Transmission,
|
|
37
|
-
change_logging_level,
|
|
38
|
-
linear_converters,
|
|
39
|
-
plotting,
|
|
40
|
-
results,
|
|
41
|
-
solvers,
|
|
42
31
|
)
|
|
32
|
+
from .config import CONFIG
|
|
33
|
+
from .core import TimeSeriesData
|
|
34
|
+
from .effects import PENALTY_EFFECT_LABEL, Effect
|
|
35
|
+
from .elements import Bus, Flow
|
|
36
|
+
from .flow_system import FlowSystem
|
|
37
|
+
from .interface import InvestParameters, Piece, Piecewise, PiecewiseConversion, PiecewiseEffects, StatusParameters
|
|
38
|
+
from .optimization import Optimization, SegmentedOptimization
|
|
39
|
+
from .plot_result import PlotResult
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
'
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
41
|
+
__all__ = [
|
|
42
|
+
'TimeSeriesData',
|
|
43
|
+
'CONFIG',
|
|
44
|
+
'Carrier',
|
|
45
|
+
'CarrierContainer',
|
|
46
|
+
'Comparison',
|
|
47
|
+
'Flow',
|
|
48
|
+
'Bus',
|
|
49
|
+
'Effect',
|
|
50
|
+
'PENALTY_EFFECT_LABEL',
|
|
51
|
+
'Source',
|
|
52
|
+
'Sink',
|
|
53
|
+
'SourceAndSink',
|
|
54
|
+
'Storage',
|
|
55
|
+
'LinearConverter',
|
|
56
|
+
'Transmission',
|
|
57
|
+
'FlowSystem',
|
|
58
|
+
'Optimization',
|
|
59
|
+
'SegmentedOptimization',
|
|
60
|
+
'InvestParameters',
|
|
61
|
+
'StatusParameters',
|
|
62
|
+
'Piece',
|
|
63
|
+
'Piecewise',
|
|
64
|
+
'PiecewiseConversion',
|
|
65
|
+
'PiecewiseEffects',
|
|
66
|
+
'PlotResult',
|
|
67
|
+
'clustering',
|
|
68
|
+
'plotting',
|
|
69
|
+
'results',
|
|
70
|
+
'linear_converters',
|
|
71
|
+
'solvers',
|
|
72
|
+
]
|
|
66
73
|
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
# Initialize logger with default configuration (silent: WARNING level, NullHandler).
|
|
75
|
+
logger = logging.getLogger('flixopt')
|
|
76
|
+
logger.setLevel(logging.WARNING)
|
|
77
|
+
logger.addHandler(logging.NullHandler())
|
flixopt/carrier.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Carrier class for energy/material type definitions.
|
|
2
|
+
|
|
3
|
+
Carriers represent types of energy or materials that flow through buses,
|
|
4
|
+
such as electricity, heat, gas, or water. They provide consistent styling
|
|
5
|
+
and metadata across visualizations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from .structure import ContainerMixin, Interface, register_class_for_io
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@register_class_for_io
|
|
14
|
+
class Carrier(Interface):
|
|
15
|
+
"""Definition of an energy or material carrier type.
|
|
16
|
+
|
|
17
|
+
Carriers represent the type of energy or material flowing through a Bus.
|
|
18
|
+
They provide consistent color, unit, and description across all visualizations
|
|
19
|
+
and can be shared between multiple buses of the same type.
|
|
20
|
+
|
|
21
|
+
Inherits from Interface to provide serialization capabilities.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
name: Identifier for the carrier (e.g., 'electricity', 'heat', 'gas').
|
|
25
|
+
color: Hex color string for visualizations (e.g., '#FFD700').
|
|
26
|
+
unit: Unit string for display (e.g., 'kW', 'kW_th', 'm³/h').
|
|
27
|
+
description: Optional human-readable description.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
Creating custom carriers:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import flixopt as fx
|
|
34
|
+
|
|
35
|
+
# Define custom carriers
|
|
36
|
+
electricity = fx.Carrier('electricity', '#FFD700', 'kW', 'Electrical power')
|
|
37
|
+
district_heat = fx.Carrier('district_heat', '#FF6B6B', 'kW_th', 'District heating')
|
|
38
|
+
hydrogen = fx.Carrier('hydrogen', '#00CED1', 'kg/h', 'Hydrogen fuel')
|
|
39
|
+
|
|
40
|
+
# Register with FlowSystem
|
|
41
|
+
flow_system.add_carrier(electricity)
|
|
42
|
+
flow_system.add_carrier(district_heat)
|
|
43
|
+
|
|
44
|
+
# Use with buses (just reference by name)
|
|
45
|
+
elec_bus = fx.Bus('MainGrid', carrier='electricity')
|
|
46
|
+
heat_bus = fx.Bus('HeatingNetwork', carrier='district_heat')
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Using predefined carriers from CONFIG:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# Access built-in carriers
|
|
53
|
+
elec = fx.CONFIG.Carriers.electricity
|
|
54
|
+
heat = fx.CONFIG.Carriers.heat
|
|
55
|
+
|
|
56
|
+
# Use directly
|
|
57
|
+
bus = fx.Bus('Grid', carrier='electricity')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Adding custom carriers to CONFIG:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Add a new carrier globally
|
|
64
|
+
fx.CONFIG.Carriers.add(fx.Carrier('biogas', '#228B22', 'kW', 'Biogas'))
|
|
65
|
+
|
|
66
|
+
# Now available as
|
|
67
|
+
fx.CONFIG.Carriers.biogas
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Note:
|
|
71
|
+
Carriers are compared by name for equality, allowing flexible usage
|
|
72
|
+
patterns where the same carrier type can be referenced by name string
|
|
73
|
+
or Carrier object interchangeably.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
77
|
+
self,
|
|
78
|
+
name: str,
|
|
79
|
+
color: str = '',
|
|
80
|
+
unit: str = '',
|
|
81
|
+
description: str = '',
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Initialize a Carrier.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
name: Identifier for the carrier (normalized to lowercase).
|
|
87
|
+
color: Hex color string for visualizations.
|
|
88
|
+
unit: Unit string for display.
|
|
89
|
+
description: Optional human-readable description.
|
|
90
|
+
"""
|
|
91
|
+
self.name = name.lower()
|
|
92
|
+
self.color = color
|
|
93
|
+
self.unit = unit
|
|
94
|
+
self.description = description
|
|
95
|
+
|
|
96
|
+
def transform_data(self, name_prefix: str = '') -> None:
|
|
97
|
+
"""Transform data to match FlowSystem dimensions.
|
|
98
|
+
|
|
99
|
+
Carriers don't have time-series data, so this is a no-op.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
name_prefix: Ignored for Carrier.
|
|
103
|
+
"""
|
|
104
|
+
pass # Carriers have no data to transform
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def label(self) -> str:
|
|
108
|
+
"""Label for container keying (alias for name)."""
|
|
109
|
+
return self.name
|
|
110
|
+
|
|
111
|
+
def __hash__(self):
|
|
112
|
+
return hash(self.name)
|
|
113
|
+
|
|
114
|
+
def __eq__(self, other):
|
|
115
|
+
if isinstance(other, Carrier):
|
|
116
|
+
return self.name == other.name
|
|
117
|
+
if isinstance(other, str):
|
|
118
|
+
return self.name == other.lower()
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
def __repr__(self):
|
|
122
|
+
return f"Carrier('{self.name}', color='{self.color}', unit='{self.unit}')"
|
|
123
|
+
|
|
124
|
+
def __str__(self):
|
|
125
|
+
return self.name
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class CarrierContainer(ContainerMixin['Carrier']):
|
|
129
|
+
"""Container for Carrier objects.
|
|
130
|
+
|
|
131
|
+
Uses carrier.name for keying. Provides dict-like access to carriers
|
|
132
|
+
registered with a FlowSystem.
|
|
133
|
+
|
|
134
|
+
Examples:
|
|
135
|
+
```python
|
|
136
|
+
# Access via FlowSystem
|
|
137
|
+
carriers = flow_system.carriers
|
|
138
|
+
|
|
139
|
+
# Dict-like access
|
|
140
|
+
elec = carriers['electricity']
|
|
141
|
+
'heat' in carriers # True/False
|
|
142
|
+
|
|
143
|
+
# Iteration
|
|
144
|
+
for name in carriers:
|
|
145
|
+
print(name)
|
|
146
|
+
```
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def __init__(self, carriers: list[Carrier] | dict[str, Carrier] | None = None):
|
|
150
|
+
"""Initialize a CarrierContainer.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
carriers: Initial carriers to add.
|
|
154
|
+
"""
|
|
155
|
+
super().__init__(elements=carriers, element_type_name='carriers')
|
|
156
|
+
|
|
157
|
+
def _get_label(self, carrier: Carrier) -> str:
|
|
158
|
+
"""Extract name from Carrier for keying."""
|
|
159
|
+
return carrier.name
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Time Series Aggregation Module for flixopt.
|
|
3
|
+
|
|
4
|
+
This module provides wrapper classes around tsam's clustering functionality:
|
|
5
|
+
- Clustering: Top-level class stored on FlowSystem after clustering
|
|
6
|
+
- ClusteringResults: Manages collection of tsam ClusteringResult objects (for IO)
|
|
7
|
+
|
|
8
|
+
Example usage:
|
|
9
|
+
|
|
10
|
+
# Cluster a FlowSystem to reduce timesteps
|
|
11
|
+
from tsam import ExtremeConfig
|
|
12
|
+
|
|
13
|
+
fs_clustered = flow_system.transform.cluster(
|
|
14
|
+
n_clusters=8,
|
|
15
|
+
cluster_duration='1D',
|
|
16
|
+
extremes=ExtremeConfig(method='new_cluster', max_value=['Demand|fixed_relative_profile']),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Access clustering structure (available before AND after IO)
|
|
20
|
+
clustering = fs_clustered.clustering
|
|
21
|
+
print(f'Number of clusters: {clustering.n_clusters}')
|
|
22
|
+
print(f'Dims: {clustering.dims}') # e.g., ('period', 'scenario')
|
|
23
|
+
print(f'Coords: {clustering.coords}') # e.g., {'period': [2024, 2025]}
|
|
24
|
+
|
|
25
|
+
# Access tsam AggregationResult for detailed analysis
|
|
26
|
+
# NOTE: Only available BEFORE saving/loading. Lost after IO.
|
|
27
|
+
result = clustering.sel(period=2024, scenario='high')
|
|
28
|
+
result.cluster_representatives # DataFrame with aggregated time series
|
|
29
|
+
result.accuracy # AccuracyMetrics (rmse, mae)
|
|
30
|
+
result.plot.compare() # tsam's built-in comparison plot
|
|
31
|
+
|
|
32
|
+
# Iterate over all results (only before IO)
|
|
33
|
+
for key, result in clustering.items():
|
|
34
|
+
print(f'{key}: {result.n_clusters} clusters')
|
|
35
|
+
|
|
36
|
+
# Save and load - structure preserved, AggregationResult access lost
|
|
37
|
+
fs_clustered.to_netcdf('system.nc')
|
|
38
|
+
# Use include_original_data=False for smaller files (~38% reduction)
|
|
39
|
+
fs_clustered.to_netcdf('system.nc', include_original_data=False)
|
|
40
|
+
|
|
41
|
+
# Expand back to full resolution
|
|
42
|
+
fs_expanded = fs_clustered.transform.expand()
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
from .base import AggregationResults, Clustering, ClusteringResults
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
'ClusteringResults',
|
|
49
|
+
'AggregationResults',
|
|
50
|
+
'Clustering',
|
|
51
|
+
]
|