flixopt 2.1.6__py3-none-any.whl → 2.1.8__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.

Potentially problematic release.


This version of flixopt might be problematic. Click here for more details.

Files changed (45) hide show
  1. docs/examples/00-Minimal Example.md +1 -1
  2. docs/examples/01-Basic Example.md +1 -1
  3. docs/examples/02-Complex Example.md +1 -1
  4. docs/examples/index.md +1 -1
  5. docs/faq/contribute.md +26 -14
  6. docs/faq/index.md +1 -1
  7. docs/javascripts/mathjax.js +1 -1
  8. docs/user-guide/Mathematical Notation/Bus.md +1 -1
  9. docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +21 -21
  10. docs/user-guide/Mathematical Notation/Flow.md +3 -3
  11. docs/user-guide/Mathematical Notation/InvestParameters.md +3 -0
  12. docs/user-guide/Mathematical Notation/LinearConverter.md +5 -5
  13. docs/user-guide/Mathematical Notation/OnOffParameters.md +3 -0
  14. docs/user-guide/Mathematical Notation/Piecewise.md +1 -1
  15. docs/user-guide/Mathematical Notation/Storage.md +2 -2
  16. docs/user-guide/Mathematical Notation/index.md +1 -1
  17. docs/user-guide/Mathematical Notation/others.md +1 -1
  18. docs/user-guide/index.md +2 -2
  19. flixopt/__init__.py +4 -0
  20. flixopt/aggregation.py +33 -32
  21. flixopt/calculation.py +161 -65
  22. flixopt/components.py +687 -154
  23. flixopt/config.py +17 -8
  24. flixopt/core.py +69 -60
  25. flixopt/effects.py +146 -64
  26. flixopt/elements.py +297 -110
  27. flixopt/features.py +78 -71
  28. flixopt/flow_system.py +72 -50
  29. flixopt/interface.py +952 -113
  30. flixopt/io.py +15 -10
  31. flixopt/linear_converters.py +373 -81
  32. flixopt/network_app.py +445 -266
  33. flixopt/plotting.py +215 -87
  34. flixopt/results.py +382 -209
  35. flixopt/solvers.py +25 -21
  36. flixopt/structure.py +41 -39
  37. flixopt/utils.py +10 -7
  38. {flixopt-2.1.6.dist-info → flixopt-2.1.8.dist-info}/METADATA +64 -53
  39. flixopt-2.1.8.dist-info/RECORD +56 -0
  40. scripts/extract_release_notes.py +5 -5
  41. scripts/gen_ref_pages.py +1 -1
  42. flixopt-2.1.6.dist-info/RECORD +0 -54
  43. {flixopt-2.1.6.dist-info → flixopt-2.1.8.dist-info}/WHEEL +0 -0
  44. {flixopt-2.1.6.dist-info → flixopt-2.1.8.dist-info}/licenses/LICENSE +0 -0
  45. {flixopt-2.1.6.dist-info → flixopt-2.1.8.dist-info}/top_level.txt +0 -0
flixopt/solvers.py CHANGED
@@ -2,9 +2,11 @@
2
2
  This module contains the solvers of the flixopt framework, making them available to the end user in a compact way.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import logging
6
8
  from dataclasses import dataclass, field
7
- from typing import Any, ClassVar, Dict, Optional
9
+ from typing import Any, ClassVar
8
10
 
9
11
  logger = logging.getLogger('flixopt')
10
12
 
@@ -14,41 +16,42 @@ class _Solver:
14
16
  """
15
17
  Abstract base class for solvers.
16
18
 
17
- Attributes:
18
- mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
19
- and the lower bound, which is the theoretically optimal solution (LP)
20
- logfile_name (str): Filename for saving the solver log.
19
+ Args:
20
+ mip_gap: Acceptable relative optimality gap in [0.0, 1.0].
21
+ time_limit_seconds: Time limit in seconds.
22
+ extra_options: Additional solver options merged into `options`.
21
23
  """
22
24
 
23
25
  name: ClassVar[str]
24
26
  mip_gap: float
25
27
  time_limit_seconds: int
26
- extra_options: Dict[str, Any] = field(default_factory=dict)
28
+ extra_options: dict[str, Any] = field(default_factory=dict)
27
29
 
28
30
  @property
29
- def options(self) -> Dict[str, Any]:
31
+ def options(self) -> dict[str, Any]:
30
32
  """Return a dictionary of solver options."""
31
33
  return {key: value for key, value in {**self._options, **self.extra_options}.items() if value is not None}
32
34
 
33
35
  @property
34
- def _options(self) -> Dict[str, Any]:
36
+ def _options(self) -> dict[str, Any]:
35
37
  """Return a dictionary of solver options, translated to the solver's API."""
36
38
  raise NotImplementedError
37
39
 
38
40
 
39
41
  class GurobiSolver(_Solver):
40
42
  """
43
+ Gurobi solver configuration.
44
+
41
45
  Args:
42
- mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
43
- and the lower bound, which is the theoretically optimal solution (LP)
44
- time_limit_seconds (int): Solver's time limit in seconds.
45
- extra_options (str): Filename for saving the solver log.
46
+ mip_gap: Acceptable relative optimality gap in [0.0, 1.0]; mapped to Gurobi `MIPGap`.
47
+ time_limit_seconds: Time limit in seconds; mapped to Gurobi `TimeLimit`.
48
+ extra_options: Additional solver options merged into `options`.
46
49
  """
47
50
 
48
51
  name: ClassVar[str] = 'gurobi'
49
52
 
50
53
  @property
51
- def _options(self) -> Dict[str, Any]:
54
+ def _options(self) -> dict[str, Any]:
52
55
  return {
53
56
  'MIPGap': self.mip_gap,
54
57
  'TimeLimit': self.time_limit_seconds,
@@ -57,19 +60,20 @@ class GurobiSolver(_Solver):
57
60
 
58
61
  class HighsSolver(_Solver):
59
62
  """
60
- Args:
61
- mip_gap (float): Solver's mip gap setting. The MIP gap describes the accepted (MILP) objective,
62
- and the lower bound, which is the theoretically optimal solution (LP)
63
- time_limit_seconds (int): Solver's time limit in seconds.
64
- threads (int): Number of threads to use.
65
- extra_options (str): Filename for saving the solver log.
63
+ HiGHS solver configuration.
64
+
65
+ Attributes:
66
+ mip_gap: Acceptable relative optimality gap in [0.0, 1.0]; mapped to HiGHS `mip_rel_gap`.
67
+ time_limit_seconds: Time limit in seconds; mapped to HiGHS `time_limit`.
68
+ extra_options: Additional solver options merged into `options`.
69
+ threads (int | None): Number of threads to use. If None, HiGHS chooses.
66
70
  """
67
71
 
68
- threads: Optional[int] = None
72
+ threads: int | None = None
69
73
  name: ClassVar[str] = 'highs'
70
74
 
71
75
  @property
72
- def _options(self) -> Dict[str, Any]:
76
+ def _options(self) -> dict[str, Any]:
73
77
  return {
74
78
  'mip_rel_gap': self.mip_gap,
75
79
  'time_limit': self.time_limit_seconds,
flixopt/structure.py CHANGED
@@ -3,25 +3,28 @@ This module contains the core structure of the flixopt framework.
3
3
  These classes are not directly used by the end user, but are used by other modules.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import inspect
7
9
  import json
8
10
  import logging
9
- import pathlib
10
11
  from datetime import datetime
11
12
  from io import StringIO
12
- from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Tuple, Union
13
+ from typing import TYPE_CHECKING, Any, Literal
13
14
 
14
15
  import linopy
15
16
  import numpy as np
16
- import pandas as pd
17
17
  import xarray as xr
18
18
  from rich.console import Console
19
19
  from rich.pretty import Pretty
20
20
 
21
- from .config import CONFIG
22
- from .core import NumericData, Scalar, TimeSeries, TimeSeriesCollection, TimeSeriesData
21
+ from .core import TimeSeries, TimeSeriesData
23
22
 
24
23
  if TYPE_CHECKING: # for type checking and preventing circular imports
24
+ import pathlib
25
+
26
+ import pandas as pd
27
+
25
28
  from .effects import EffectCollectionModel
26
29
  from .flow_system import FlowSystem
27
30
 
@@ -49,7 +52,7 @@ class SystemModel(linopy.Model):
49
52
  It is used to create and store the variables and constraints for the flow_system.
50
53
  """
51
54
 
52
- def __init__(self, flow_system: 'FlowSystem'):
55
+ def __init__(self, flow_system: FlowSystem):
53
56
  """
54
57
  Args:
55
58
  flow_system: The flow_system that is used to create the model.
@@ -57,7 +60,7 @@ class SystemModel(linopy.Model):
57
60
  super().__init__(force_dim_names=True)
58
61
  self.flow_system = flow_system
59
62
  self.time_series_collection = flow_system.time_series_collection
60
- self.effects: Optional[EffectCollectionModel] = None
63
+ self.effects: EffectCollectionModel | None = None
61
64
 
62
65
  def do_modeling(self):
63
66
  self.effects = self.flow_system.effects.create_model(self)
@@ -99,11 +102,11 @@ class SystemModel(linopy.Model):
99
102
  return self.time_series_collection.hours_of_previous_timesteps
100
103
 
101
104
  @property
102
- def coords(self) -> Tuple[pd.DatetimeIndex]:
105
+ def coords(self) -> tuple[pd.DatetimeIndex]:
103
106
  return (self.time_series_collection.timesteps,)
104
107
 
105
108
  @property
106
- def coords_extra(self) -> Tuple[pd.DatetimeIndex]:
109
+ def coords_extra(self) -> tuple[pd.DatetimeIndex]:
107
110
  return (self.time_series_collection.timesteps_extra,)
108
111
 
109
112
 
@@ -112,11 +115,11 @@ class Interface:
112
115
  This class is used to collect arguments about a Model. Its the base class for all Elements and Models in flixopt.
113
116
  """
114
117
 
115
- def transform_data(self, flow_system: 'FlowSystem'):
118
+ def transform_data(self, flow_system: FlowSystem):
116
119
  """Transforms the data of the interface to match the FlowSystem's dimensions"""
117
120
  raise NotImplementedError('Every Interface needs a transform_data() method')
118
121
 
119
- def infos(self, use_numpy: bool = True, use_element_label: bool = False) -> Dict:
122
+ def infos(self, use_numpy: bool = True, use_element_label: bool = False) -> dict:
120
123
  """
121
124
  Generate a dictionary representation of the object's constructor arguments.
122
125
  Excludes default values and empty dictionaries and lists.
@@ -150,7 +153,7 @@ class Interface:
150
153
  details[name] = copy_and_convert_datatypes(value, use_numpy, use_element_label)
151
154
  return details
152
155
 
153
- def to_json(self, path: Union[str, pathlib.Path]):
156
+ def to_json(self, path: str | pathlib.Path):
154
157
  """
155
158
  Saves the element to a json file.
156
159
  This not meant to be reloaded and recreate the object, but rather used to document or compare the object.
@@ -162,7 +165,7 @@ class Interface:
162
165
  with open(path, 'w', encoding='utf-8') as f:
163
166
  json.dump(data, f, indent=4, ensure_ascii=False)
164
167
 
165
- def to_dict(self) -> Dict:
168
+ def to_dict(self) -> dict:
166
169
  """Convert the object to a dictionary representation."""
167
170
  data = {'__class__': self.__class__.__name__}
168
171
 
@@ -200,7 +203,7 @@ class Interface:
200
203
  return {k: self._serialize_value(v) for k, v in d.items()}
201
204
 
202
205
  @classmethod
203
- def _deserialize_dict(cls, data: Dict) -> Union[Dict, 'Interface']:
206
+ def _deserialize_dict(cls, data: dict) -> dict | Interface:
204
207
  if '__class__' in data:
205
208
  class_name = data.pop('__class__')
206
209
  try:
@@ -217,7 +220,7 @@ class Interface:
217
220
  return {k: cls._deserialize_value(v) for k, v in data.items()}
218
221
 
219
222
  @classmethod
220
- def _deserialize_list(cls, data: List) -> List:
223
+ def _deserialize_list(cls, data: list) -> list:
221
224
  return [cls._deserialize_value(value) for value in data]
222
225
 
223
226
  @classmethod
@@ -232,7 +235,7 @@ class Interface:
232
235
  return value
233
236
 
234
237
  @classmethod
235
- def from_dict(cls, data: Dict) -> 'Interface':
238
+ def from_dict(cls, data: dict) -> Interface:
236
239
  """
237
240
  Create an instance from a dictionary representation.
238
241
 
@@ -257,7 +260,7 @@ class Interface:
257
260
  class Element(Interface):
258
261
  """This class is the basic Element of flixopt. Every Element has a label"""
259
262
 
260
- def __init__(self, label: str, meta_data: Dict = None):
263
+ def __init__(self, label: str, meta_data: dict | None = None):
261
264
  """
262
265
  Args:
263
266
  label: The label of the element
@@ -265,13 +268,14 @@ class Element(Interface):
265
268
  """
266
269
  self.label = Element._valid_label(label)
267
270
  self.meta_data = meta_data if meta_data is not None else {}
268
- self.model: Optional[ElementModel] = None
271
+ self.model: ElementModel | None = None
269
272
 
270
273
  def _plausibility_checks(self) -> None:
271
- """This function is used to do some basic plausibility checks for each Element during initialization"""
274
+ """This function is used to do some basic plausibility checks for each Element during initialization.
275
+ This is run after all data is transformed to the correct format/type"""
272
276
  raise NotImplementedError('Every Element needs a _plausibility_checks() method')
273
277
 
274
- def create_model(self, model: SystemModel) -> 'ElementModel':
278
+ def create_model(self, model: SystemModel) -> ElementModel:
275
279
  raise NotImplementedError('Every Element needs a create_model() method')
276
280
 
277
281
  @property
@@ -303,9 +307,7 @@ class Element(Interface):
303
307
  class Model:
304
308
  """Stores Variables and Constraints."""
305
309
 
306
- def __init__(
307
- self, model: SystemModel, label_of_element: str, label: str = '', label_full: Optional[str] = None
308
- ):
310
+ def __init__(self, model: SystemModel, label_of_element: str, label: str = '', label_full: str | None = None):
309
311
  """
310
312
  Args:
311
313
  model: The SystemModel that is used to create the model.
@@ -318,21 +320,21 @@ class Model:
318
320
  self._label = label
319
321
  self._label_full = label_full
320
322
 
321
- self._variables_direct: List[str] = []
322
- self._constraints_direct: List[str] = []
323
- self.sub_models: List[Model] = []
323
+ self._variables_direct: list[str] = []
324
+ self._constraints_direct: list[str] = []
325
+ self.sub_models: list[Model] = []
324
326
 
325
- self._variables_short: Dict[str, str] = {}
326
- self._constraints_short: Dict[str, str] = {}
327
- self._sub_models_short: Dict[str, str] = {}
327
+ self._variables_short: dict[str, str] = {}
328
+ self._constraints_short: dict[str, str] = {}
329
+ self._sub_models_short: dict[str, str] = {}
328
330
  logger.debug(f'Created {self.__class__.__name__} "{self.label_full}"')
329
331
 
330
332
  def do_modeling(self):
331
333
  raise NotImplementedError('Every Model needs a do_modeling() method')
332
334
 
333
335
  def add(
334
- self, item: Union[linopy.Variable, linopy.Constraint, 'Model'], short_name: Optional[str] = None
335
- ) -> Union[linopy.Variable, linopy.Constraint, 'Model']:
336
+ self, item: linopy.Variable | linopy.Constraint | Model, short_name: str | None = None
337
+ ) -> linopy.Variable | linopy.Constraint | Model:
336
338
  """
337
339
  Add a variable, constraint or sub-model to the model
338
340
 
@@ -358,8 +360,8 @@ class Model:
358
360
 
359
361
  def filter_variables(
360
362
  self,
361
- filter_by: Optional[Literal['binary', 'continuous', 'integer']] = None,
362
- length: Literal['scalar', 'time'] = None,
363
+ filter_by: Literal['binary', 'continuous', 'integer'] | None = None,
364
+ length: Literal['scalar', 'time'] | None = None,
363
365
  ):
364
366
  if filter_by is None:
365
367
  all_variables = self.variables
@@ -401,7 +403,7 @@ class Model:
401
403
  return self._model.constraints[self._constraints_direct]
402
404
 
403
405
  @property
404
- def _variables(self) -> List[str]:
406
+ def _variables(self) -> list[str]:
405
407
  all_variables = self._variables_direct.copy()
406
408
  for sub_model in self.sub_models:
407
409
  for variable in sub_model._variables:
@@ -413,7 +415,7 @@ class Model:
413
415
  return all_variables
414
416
 
415
417
  @property
416
- def _constraints(self) -> List[str]:
418
+ def _constraints(self) -> list[str]:
417
419
  all_constraints = self._constraints_direct.copy()
418
420
  for sub_model in self.sub_models:
419
421
  for constraint in sub_model._constraints:
@@ -431,7 +433,7 @@ class Model:
431
433
  return self._model.constraints[self._constraints]
432
434
 
433
435
  @property
434
- def all_sub_models(self) -> List['Model']:
436
+ def all_sub_models(self) -> list[Model]:
435
437
  return [model for sub_model in self.sub_models for model in [sub_model] + sub_model.all_sub_models]
436
438
 
437
439
 
@@ -549,7 +551,7 @@ def copy_and_convert_datatypes(data: Any, use_numpy: bool = True, use_element_la
549
551
  raise TypeError(f'copy_and_convert_datatypes() did get unexpected data of type "{type(data)}": {data=}')
550
552
 
551
553
 
552
- def get_compact_representation(data: Any, array_threshold: int = 50, decimals: int = 2) -> Dict:
554
+ def get_compact_representation(data: Any, array_threshold: int = 50, decimals: int = 2) -> dict:
553
555
  """
554
556
  Generate a compact json serializable representation of deeply nested data.
555
557
  Numpy arrays are statistically described if they exceed a threshold and converted to lists.
@@ -560,7 +562,7 @@ def get_compact_representation(data: Any, array_threshold: int = 50, decimals: i
560
562
  decimals (int): Number of decimal places in which to describe the arrays.
561
563
 
562
564
  Returns:
563
- Dict: A dictionary representation of the data
565
+ dict: A dictionary representation of the data
564
566
  """
565
567
 
566
568
  def format_np_array_if_found(value: Any) -> Any:
@@ -579,7 +581,7 @@ def get_compact_representation(data: Any, array_threshold: int = 50, decimals: i
579
581
  )
580
582
  return value
581
583
 
582
- def describe_numpy_arrays(arr: np.ndarray) -> Union[str, List]:
584
+ def describe_numpy_arrays(arr: np.ndarray) -> str | list:
583
585
  """Shortens NumPy arrays if they exceed the specified length."""
584
586
 
585
587
  def normalized_center_of_mass(array: Any) -> float:
flixopt/utils.py CHANGED
@@ -2,21 +2,24 @@
2
2
  This module contains several utility functions used throughout the flixopt framework.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import logging
6
- from typing import Any, Dict, List, Literal, Optional, Union
8
+ from typing import TYPE_CHECKING, Any, Literal
7
9
 
8
- import numpy as np
9
- import xarray as xr
10
+ if TYPE_CHECKING:
11
+ import numpy as np
12
+ import xarray as xr
10
13
 
11
14
  logger = logging.getLogger('flixopt')
12
15
 
13
16
 
14
- def is_number(number_alias: Union[int, float, str]):
15
- """Returns True is string is a number."""
17
+ def is_number(number_alias: int | float | str) -> bool:
18
+ """Returns True if value is a number or a number-like string."""
16
19
  try:
17
20
  float(number_alias)
18
21
  return True
19
- except ValueError:
22
+ except (ValueError, TypeError):
20
23
  return False
21
24
 
22
25
 
@@ -32,7 +35,7 @@ def round_floats(obj, decimals=2):
32
35
 
33
36
  def convert_dataarray(
34
37
  data: xr.DataArray, mode: Literal['py', 'numpy', 'xarray', 'structure']
35
- ) -> Union[List, np.ndarray, xr.DataArray, str]:
38
+ ) -> list[Any] | np.ndarray | xr.DataArray | str:
36
39
  """
37
40
  Convert a DataArray to a different format.
38
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flixopt
3
- Version: 2.1.6
3
+ Version: 2.1.8
4
4
  Summary: Vector based energy and material flow optimization framework in Python.
5
5
  Author-email: "Chair of Building Energy Systems and Heat Supply, TU Dresden" <peter.stange@tu-dresden.de>, Felix Bumann <felixbumann387@gmail.com>, Felix Panitz <baumbude@googlemail.com>, Peter Stange <peter.stange@tu-dresden.de>
6
6
  Maintainer-email: Felix Bumann <felixbumann387@gmail.com>, Peter Stange <peter.stange@tu-dresden.de>
@@ -18,58 +18,64 @@ Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Intended Audience :: Developers
19
19
  Classifier: Intended Audience :: Science/Research
20
20
  Classifier: Topic :: Scientific/Engineering
21
+ Classifier: License :: OSI Approved :: MIT License
21
22
  Requires-Python: >=3.10
22
23
  Description-Content-Type: text/markdown
23
24
  License-File: LICENSE
24
25
  Requires-Dist: numpy<3,>=1.21.5
25
26
  Requires-Dist: pandas<3,>=2.0.0
26
- Requires-Dist: linopy<0.5.6,>=0.5.1
27
+ Requires-Dist: xarray<2026.0,>=2024.2.0
28
+ Requires-Dist: linopy<0.6,>=0.5.1
27
29
  Requires-Dist: netcdf4<2,>=1.6.1
28
- Requires-Dist: PyYAML<7,>=6.0.0
29
- Requires-Dist: rich>=13.0.0
30
- Requires-Dist: tomli>=2.0.1; python_version < "3.11"
31
- Requires-Dist: highspy>=1.5.3
32
- Requires-Dist: matplotlib<4.0.0,>=3.5.2
33
- Requires-Dist: plotly<6.0.0,>=5.15.0
30
+ Requires-Dist: pyyaml<7,>=6.0.0
31
+ Requires-Dist: rich<15,>=13.0.0
32
+ Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
33
+ Requires-Dist: highspy<2,>=1.5.3
34
+ Requires-Dist: matplotlib<4,>=3.5.2
35
+ Requires-Dist: plotly<7,>=5.15.0
34
36
  Provides-Extra: network-viz
35
- Requires-Dist: dash>=3.0.0; extra == "network-viz"
36
- Requires-Dist: dash-cytoscape>=1.0.0; extra == "network-viz"
37
- Requires-Dist: dash-daq>=0.6.0; extra == "network-viz"
38
- Requires-Dist: networkx>=3.0.0; extra == "network-viz"
39
- Requires-Dist: werkzeug>=3.0.0; extra == "network-viz"
37
+ Requires-Dist: dash<4,>=3.0.0; extra == "network-viz"
38
+ Requires-Dist: dash-cytoscape<2,>=1.0.0; extra == "network-viz"
39
+ Requires-Dist: dash-daq<1,>=0.6.0; extra == "network-viz"
40
+ Requires-Dist: networkx<4,>=3.0.0; extra == "network-viz"
41
+ Requires-Dist: werkzeug<4,>=3.0.0; extra == "network-viz"
42
+ Requires-Dist: flask<4,>=3.0.0; extra == "network-viz"
40
43
  Provides-Extra: full
41
- Requires-Dist: pyvis==0.3.1; extra == "full"
42
- Requires-Dist: tsam<3.0.0,>=2.3.1; extra == "full"
43
- Requires-Dist: scipy<2.0.0,>=1.15.1; extra == "full"
44
- Requires-Dist: gurobipy>=10.0.0; extra == "full"
45
- Requires-Dist: dash>=3.0.0; extra == "full"
46
- Requires-Dist: dash-cytoscape>=1.0.0; extra == "full"
47
- Requires-Dist: dash-daq>=0.6.0; extra == "full"
48
- Requires-Dist: networkx>=3.0.0; extra == "full"
49
- Requires-Dist: werkzeug>=3.0.0; extra == "full"
44
+ Requires-Dist: pyvis==0.3.2; extra == "full"
45
+ Requires-Dist: tsam<3,>=2.3.1; extra == "full"
46
+ Requires-Dist: scipy<2,>=1.15.1; extra == "full"
47
+ Requires-Dist: gurobipy<13,>=10.0.0; extra == "full"
48
+ Requires-Dist: dash<4,>=3.0.0; extra == "full"
49
+ Requires-Dist: dash-cytoscape<2,>=1.0.0; extra == "full"
50
+ Requires-Dist: dash-daq<1,>=0.6.0; extra == "full"
51
+ Requires-Dist: networkx<4,>=3.0.0; extra == "full"
52
+ Requires-Dist: werkzeug<4,>=3.0.0; extra == "full"
53
+ Requires-Dist: flask<4,>=3.0.0; extra == "full"
50
54
  Provides-Extra: dev
51
- Requires-Dist: pytest>=7.0.0; extra == "dev"
52
- Requires-Dist: ruff>=0.9.0; extra == "dev"
53
- Requires-Dist: pyvis==0.3.1; extra == "dev"
54
- Requires-Dist: tsam<3.0.0,>=2.3.1; extra == "dev"
55
- Requires-Dist: scipy<2.0.0,>=1.15.1; extra == "dev"
56
- Requires-Dist: gurobipy>=10.0.0; extra == "dev"
57
- Requires-Dist: dash>=3.0.0; extra == "dev"
58
- Requires-Dist: dash-cytoscape>=1.0.0; extra == "dev"
59
- Requires-Dist: dash-daq>=0.6.0; extra == "dev"
60
- Requires-Dist: networkx>=3.0.0; extra == "dev"
61
- Requires-Dist: werkzeug>=3.0.0; extra == "dev"
55
+ Requires-Dist: pytest==8.4.2; extra == "dev"
56
+ Requires-Dist: nbformat==5.10.4; extra == "dev"
57
+ Requires-Dist: ruff==0.13.0; extra == "dev"
58
+ Requires-Dist: pre-commit==4.3.0; extra == "dev"
59
+ Requires-Dist: pyvis==0.3.2; extra == "dev"
60
+ Requires-Dist: tsam==2.3.1; extra == "dev"
61
+ Requires-Dist: scipy==1.15.1; extra == "dev"
62
+ Requires-Dist: gurobipy==12.0.3; extra == "dev"
63
+ Requires-Dist: dash==3.0.0; extra == "dev"
64
+ Requires-Dist: dash-cytoscape==1.0.2; extra == "dev"
65
+ Requires-Dist: dash-daq==0.6.0; extra == "dev"
66
+ Requires-Dist: networkx==3.0.0; extra == "dev"
67
+ Requires-Dist: werkzeug==3.0.0; extra == "dev"
62
68
  Provides-Extra: docs
63
- Requires-Dist: mkdocs-material<10,>=9.0.0; extra == "docs"
64
- Requires-Dist: mkdocstrings-python>=1.0.0; extra == "docs"
65
- Requires-Dist: mkdocs-table-reader-plugin>=2.0.0; extra == "docs"
66
- Requires-Dist: mkdocs-gen-files>=0.4.0; extra == "docs"
67
- Requires-Dist: mkdocs-include-markdown-plugin>=6.0.0; extra == "docs"
68
- Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == "docs"
69
- Requires-Dist: markdown-include>=0.8.0; extra == "docs"
70
- Requires-Dist: pymdown-extensions>=10.0.0; extra == "docs"
71
- Requires-Dist: pygments>=2.14.0; extra == "docs"
72
- Requires-Dist: mike<2,>=1.1.0; extra == "docs"
69
+ Requires-Dist: mkdocs-material==9.6.19; extra == "docs"
70
+ Requires-Dist: mkdocstrings-python==1.18.2; extra == "docs"
71
+ Requires-Dist: mkdocs-table-reader-plugin==3.1.0; extra == "docs"
72
+ Requires-Dist: mkdocs-gen-files==0.5.0; extra == "docs"
73
+ Requires-Dist: mkdocs-include-markdown-plugin==7.1.7; extra == "docs"
74
+ Requires-Dist: mkdocs-literate-nav==0.6.2; extra == "docs"
75
+ Requires-Dist: markdown-include==0.8.1; extra == "docs"
76
+ Requires-Dist: pymdown-extensions==10.16.1; extra == "docs"
77
+ Requires-Dist: pygments==2.19.2; extra == "docs"
78
+ Requires-Dist: mike==2.1.3; extra == "docs"
73
79
  Dynamic: license-file
74
80
 
75
81
  # FlixOpt: Energy and Material Flow Optimization Framework
@@ -92,7 +98,7 @@ Dynamic: license-file
92
98
 
93
99
  **flixopt** provides a user-friendly interface with options for advanced users.
94
100
 
95
- It was originally developed by [TU Dresden](https://github.com/gewv-tu-dresden) as part of the SMARTBIOGRID project, funded by the German Federal Ministry for Economic Affairs and Energy (FKZ: 03KB159B). Building on the Matlab-based flixOptMat framework (developed in the FAKS project), FlixOpt also incorporates concepts from [oemof/solph](https://github.com/oemof/oemof-solph).
101
+ It was originally developed by [TU Dresden](https://github.com/gewv-tu-dresden) as part of the SMARTBIOGRID project, funded by the German Federal Ministry for Economic Affairs and Energy (FKZ: 03KB159B). Building on the Matlab-based flixOptMat framework (developed in the FAKS project), FlixOpt also incorporates concepts from [oemof/solph](https://github.com/oemof/oemof-solph).
96
102
 
97
103
  ---
98
104
 
@@ -117,7 +123,7 @@ It was originally developed by [TU Dresden](https://github.com/gewv-tu-dresden)
117
123
 
118
124
  - **Calculation Modes**
119
125
  - **Full** - Solve the model with highest accuracy and computational requirements.
120
- - **Segmented** - Speed up solving by using a rolling horizon.
126
+ - **Segmented** - Speed up solving by using a rolling horizon.
121
127
  - **Aggregated** - Speed up solving by identifying typical periods using [TSAM](https://github.com/FZJ-IEK3-VSA/tsam). Suitable for large models.
122
128
 
123
129
  ---
@@ -139,22 +145,27 @@ The documentation is available at [https://flixopt.github.io/flixopt/latest/](ht
139
145
 
140
146
  ---
141
147
 
142
- ## 🛠️ Solver Integration
148
+ ## 🎯️ Solver Integration
143
149
 
144
- By default, FlixOpt uses the open-source solver [HiGHS](https://highs.dev/) which is installed by default. However, it is compatible with additional solvers such as:
150
+ By default, FlixOpt uses the open-source solver [HiGHS](https://highs.dev/) which is installed by default. However, it is compatible with additional solvers such as:
145
151
 
146
- - [Gurobi](https://www.gurobi.com/)
147
- - [CBC](https://github.com/coin-or/Cbc)
152
+ - [Gurobi](https://www.gurobi.com/)
153
+ - [CBC](https://github.com/coin-or/Cbc)
148
154
  - [GLPK](https://www.gnu.org/software/glpk/)
149
155
  - [CPLEX](https://www.ibm.com/analytics/cplex-optimizer)
150
156
 
151
- For detailed licensing and installation instructions, refer to the respective solver documentation.
157
+ For detailed licensing and installation instructions, refer to the respective solver documentation.
158
+
159
+ ---
160
+
161
+ ## 🛠 Development Setup
162
+ Look into our docs for [development setup](https://flixopt.github.io/flixopt/latest/contribute/)
152
163
 
153
164
  ---
154
165
 
155
166
  ## 📖 Citation
156
167
 
157
- If you use FlixOpt in your research or project, please cite the following:
168
+ If you use FlixOpt in your research or project, please cite the following:
158
169
 
159
- - **Main Citation:** [DOI:10.18086/eurosun.2022.04.07](https://doi.org/10.18086/eurosun.2022.04.07)
160
- - **Short Overview:** [DOI:10.13140/RG.2.2.14948.24969](https://doi.org/10.13140/RG.2.2.14948.24969)
170
+ - **Main Citation:** [DOI:10.18086/eurosun.2022.04.07](https://doi.org/10.18086/eurosun.2022.04.07)
171
+ - **Short Overview:** [DOI:10.13140/RG.2.2.14948.24969](https://doi.org/10.13140/RG.2.2.14948.24969)
@@ -0,0 +1,56 @@
1
+ docs/examples/00-Minimal Example.md,sha256=TjtnI8o96YNOCFwRC8BSXFGoVqfB53BtvOG4b29FwkQ,80
2
+ docs/examples/01-Basic Example.md,sha256=sZHonC6A_wtZ2IEy_6BAMY8wViyIcivmcj8GYIZ_qck,78
3
+ docs/examples/02-Complex Example.md,sha256=5cczYkXFpzpQTNp9dkmOEdTXxoWLETKty417q6MyT8s,287
4
+ docs/examples/03-Calculation Modes.md,sha256=FZPBXmrkir6QhQsiXwWp2sOOntIIkODCgh3lVqOrP6w,231
5
+ docs/examples/index.md,sha256=KwXrsxxiHk563bny4I4B2X_CfPNiSXx8TsfI671MLdg,179
6
+ docs/faq/contribute.md,sha256=CL7Z85zyPes1Kl16_8oWLU2RTTbMdPfhmvt4tsnkikU,2508
7
+ docs/faq/index.md,sha256=MH_SPZllm_5npxPP6DHXbJlpLXZc-nbWTFJvMmZYz9Q,50
8
+ docs/images/architecture_flixOpt-pre2.0.0.png,sha256=9RWSA3vys588aadr2437zor-_-xBTQNQ0bAf8xGcu5g,70605
9
+ docs/images/architecture_flixOpt.png,sha256=KjN1bJwESbkHmTW7UsJ7dZyiKZlTO7Dx20dg8KlR1HU,260219
10
+ docs/images/flixopt-icon.svg,sha256=_1a6bk2pDOVEy233LC1nM6jZ35NdzD8Hd3UqGxW1Xpg,135341
11
+ docs/javascripts/mathjax.js,sha256=LJDaO5MM_5W8gI5-S5SiZ17qeMgeoVJO-inMyBNy7UE,402
12
+ docs/user-guide/index.md,sha256=TBO7lk13M95w2A9WiT5asfZn9oU9GZ1O0XW9eUm5GLo,7450
13
+ docs/user-guide/Mathematical Notation/Bus.md,sha256=pqjGa3PZBSmuO4YR44bK21bMmRcWC8dkzP3z0XX-PJw,1613
14
+ "docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md",sha256=vXQWt-UyITOVTJWPkKfjJzucbyml2OTQ6URQiMoc9dU,5671
15
+ docs/user-guide/Mathematical Notation/Flow.md,sha256=zxCp02o0t2EwB-hlwGtmh8aQveRGgcgwqMN8MvLxaI0,1099
16
+ docs/user-guide/Mathematical Notation/InvestParameters.md,sha256=UeuCpAyhOfDS2C3efmi_2EFkaFBK7HcqhHeBXl9BhFw,48
17
+ docs/user-guide/Mathematical Notation/LinearConverter.md,sha256=mKYbpnYxXW9xI2ybVfAyxDJdwahnj7L9ZTY0mnq3_l0,1321
18
+ docs/user-guide/Mathematical Notation/OnOffParameters.md,sha256=QEgxhqb53VlyBifIdExwaQpsdeE0Cyb8aN3-aCHQ21U,47
19
+ docs/user-guide/Mathematical Notation/Piecewise.md,sha256=GgTQ7dVTTb0lq14GFuuZeGYrUXtMy1wkztJLIVchchw,1993
20
+ docs/user-guide/Mathematical Notation/Storage.md,sha256=-QiZN2vA-f-P8JGkQDPYBdt2xt6J0Z2jbKDuk6j-rIs,2201
21
+ docs/user-guide/Mathematical Notation/index.md,sha256=2d6k4zbKET1kg7zBt1fEdKsG8jM5j2IIe6yclMTUlDw,1254
22
+ docs/user-guide/Mathematical Notation/others.md,sha256=z6LOzcnvfI-1qQx0Fg7Q6wSK9tAzH2d34KbW4lYNyCE,48
23
+ flixopt/__init__.py,sha256=xTxHXC-_lWa65roGUM3J3HXfiYcMCJHoQsuL5mS0Xkg,688
24
+ flixopt/aggregation.py,sha256=BFy2ngr0a0By5wfBZet9fX8X5ZPmkn1x6HMRaw1ZsTo,16892
25
+ flixopt/calculation.py,sha256=VBcvpQr7ZXvWZfryfilwUzK161br4ZP3zTwvYHraGjY,24476
26
+ flixopt/commons.py,sha256=ZNlUN1z-h9OGHPo-s-n5OLlJaoPZKVGcAdRyGKpMk4M,1256
27
+ flixopt/components.py,sha256=efUwx_eqgVPsQEn8u0HUrgkvU2eU2tgv7wKwT2eeX_I,54632
28
+ flixopt/config.py,sha256=2GJ9NZl35OKMUvofIpztgKh3kdca1m1wa77RjsUaob0,9509
29
+ flixopt/config.yaml,sha256=imzAnnhcJhIfKNTTXFB5Td7Pvk5ARn5j720k-oGGRug,392
30
+ flixopt/core.py,sha256=HnXnUXnAL8yqBExdsXGgwu5HnfWRH0omjjMKgp_SBKc,37824
31
+ flixopt/effects.py,sha256=HcalPMUaAfuzD2p1OeQ9nLY2vmHv_GxwyGLLeqNGNZ8,19435
32
+ flixopt/elements.py,sha256=IWtr0zyS1GEttYMiBZxC6sEX7y8pCWEbySxok3nDxwI,33535
33
+ flixopt/features.py,sha256=m61ixTFJ_Jh-Emx6QKVxo04Heswm89XsPUqbH8ezNr8,43891
34
+ flixopt/flow_system.py,sha256=qvR4uktXERDKCI40w9tJidkWxt5B36XVoebCw5bJons,20886
35
+ flixopt/interface.py,sha256=e5tom-aTEPfl4FQg8abyDv7g1tTvxeOWiSWg_IGti-g,47575
36
+ flixopt/io.py,sha256=BziCFlHfqx1kWFBhr1EZi-odZaqTVZdfmHhl-_rf5Ug,11367
37
+ flixopt/linear_converters.py,sha256=rKa0AZlJHgDsPF_LVsvrhxhsmVTRanPE0NuKP7OICtg,22668
38
+ flixopt/network_app.py,sha256=JlEbufeg3WK89ILwz2gXq6xdZzHEo5urIcz1eBpgJyc,29456
39
+ flixopt/plotting.py,sha256=cGM8f5QDMOkKuBapgD6-EhN1X-f5WkDqyoxGPberjzI,59661
40
+ flixopt/results.py,sha256=121FoO3WrAuHm18_-OP93_-9JxuCVVm5JWvmC33P3-8,40682
41
+ flixopt/solvers.py,sha256=m38Smc22MJfHYMiqfNf1MA3OmvbTRm5OWS9nECkDdQk,2355
42
+ flixopt/structure.py,sha256=vyD1lc80NH3JLexKJuar9btgHhEbcNEmihCQkBWea8k,26254
43
+ flixopt/utils.py,sha256=a-YKR7C7HtD8dSIcxzlJTgryV5HMS7zELSXNYr_Lz9Q,1775
44
+ flixopt-2.1.8.dist-info/licenses/LICENSE,sha256=HKsZnbrM_3Rvnr_u9cWSG90cBsj5_slaqI_z_qcxnGI,1118
45
+ pics/architecture_flixOpt-pre2.0.0.png,sha256=9RWSA3vys588aadr2437zor-_-xBTQNQ0bAf8xGcu5g,70605
46
+ pics/architecture_flixOpt.png,sha256=KjN1bJwESbkHmTW7UsJ7dZyiKZlTO7Dx20dg8KlR1HU,260219
47
+ pics/flixOpt_plotting.jpg,sha256=zn7ZPAtXm5eRTxtOj86e4-PPhHpCar1jqGh7vMBgQGY,518862
48
+ pics/flixopt-icon.svg,sha256=_1a6bk2pDOVEy233LC1nM6jZ35NdzD8Hd3UqGxW1Xpg,135341
49
+ pics/pics.pptx,sha256=ImWeGGvjtWJ6BGruipsnZYmWtHj5sWdbw1NSFePbkC8,683344
50
+ scripts/extract_release_notes.py,sha256=3UUE4hWhdd2t2m2x0ZpchGP-A0MvfqO2Wc5EdNN-fgE,1249
51
+ scripts/gen_ref_pages.py,sha256=7bxRu2VfqFrnr7wln1BjMAqpQUzuTkLPJSBh83uikIQ,1948
52
+ tests/ressources/Zeitreihen2020.csv,sha256=kbsDTKZS0iUsNZAS7m3DohzZI_OHHWe44s3GwLvcTLw,1918412
53
+ flixopt-2.1.8.dist-info/METADATA,sha256=OMNIQF_kyzEFA1H3d-IUWwEEL84bG4t8KfS2nbW-TTU,8432
54
+ flixopt-2.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ flixopt-2.1.8.dist-info/top_level.txt,sha256=DEuo4R1z7GmEp5R3pjbQEJbaPRjKHFvNX2ceiBnVOL0,32
56
+ flixopt-2.1.8.dist-info/RECORD,,
@@ -11,10 +11,10 @@ from pathlib import Path
11
11
 
12
12
  def extract_release_notes(version: str) -> str:
13
13
  """Extract release notes for a specific version from CHANGELOG.md"""
14
- changelog_path = Path("CHANGELOG.md")
14
+ changelog_path = Path('CHANGELOG.md')
15
15
 
16
16
  if not changelog_path.exists():
17
- print("❌ Error: CHANGELOG.md not found", file=sys.stderr)
17
+ print('❌ Error: CHANGELOG.md not found', file=sys.stderr)
18
18
  sys.exit(1)
19
19
 
20
20
  content = changelog_path.read_text(encoding='utf-8')
@@ -32,8 +32,8 @@ def extract_release_notes(version: str) -> str:
32
32
 
33
33
  def main():
34
34
  if len(sys.argv) != 2:
35
- print("Usage: python extract_release_notes.py <version>")
36
- print("Example: python extract_release_notes.py 2.1.2")
35
+ print('Usage: python extract_release_notes.py <version>')
36
+ print('Example: python extract_release_notes.py 2.1.2')
37
37
  sys.exit(1)
38
38
 
39
39
  version = sys.argv[1]
@@ -41,5 +41,5 @@ def main():
41
41
  print(release_notes)
42
42
 
43
43
 
44
- if __name__ == "__main__":
44
+ if __name__ == '__main__':
45
45
  main()