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

flixopt/structure.py CHANGED
@@ -7,12 +7,16 @@ from __future__ import annotations
7
7
 
8
8
  import inspect
9
9
  import logging
10
+ import re
10
11
  from dataclasses import dataclass
12
+ from difflib import get_close_matches
11
13
  from io import StringIO
12
14
  from typing import (
13
15
  TYPE_CHECKING,
14
16
  Any,
17
+ Generic,
15
18
  Literal,
19
+ TypeVar,
16
20
  )
17
21
 
18
22
  import linopy
@@ -168,7 +172,7 @@ class FlowSystemModel(linopy.Model, SubmodelsMixin):
168
172
  },
169
173
  'Effects': {
170
174
  effect.label_full: effect.submodel.results_structure()
171
- for effect in sorted(self.flow_system.effects, key=lambda effect: effect.label_full.upper())
175
+ for effect in sorted(self.flow_system.effects.values(), key=lambda effect: effect.label_full.upper())
172
176
  },
173
177
  'Flows': {
174
178
  flow.label_full: flow.submodel.results_structure()
@@ -242,9 +246,7 @@ class FlowSystemModel(linopy.Model, SubmodelsMixin):
242
246
  }
243
247
 
244
248
  # Format sections with headers and underlines
245
- formatted_sections = []
246
- for section_header, section_content in sections.items():
247
- formatted_sections.append(f'{section_header}\n{"-" * len(section_header)}\n{section_content}')
249
+ formatted_sections = fx_io.format_sections_with_headers(sections)
248
250
 
249
251
  title = f'FlowSystemModel ({self.type})'
250
252
  all_sections = '\n'.join(formatted_sections)
@@ -506,6 +508,33 @@ class Interface:
506
508
  unexpected_params = ', '.join(f"'{param}'" for param in extra_kwargs.keys())
507
509
  raise TypeError(f'{class_name}.__init__() got unexpected keyword argument(s): {unexpected_params}')
508
510
 
511
+ @staticmethod
512
+ def _has_value(param: Any) -> bool:
513
+ """Check if a parameter has a meaningful value.
514
+
515
+ Args:
516
+ param: The parameter to check.
517
+
518
+ Returns:
519
+ False for:
520
+ - None
521
+ - Empty collections (dict, list, tuple, set, frozenset)
522
+
523
+ True for all other values, including:
524
+ - Non-empty collections
525
+ - xarray DataArrays (even if they contain NaN/empty data)
526
+ - Scalar values (0, False, empty strings, etc.)
527
+ - NumPy arrays (even if empty - use .size to check those explicitly)
528
+ """
529
+ if param is None:
530
+ return False
531
+
532
+ # Check for empty collections (but not strings, arrays, or DataArrays)
533
+ if isinstance(param, (dict, list, tuple, set, frozenset)) and len(param) == 0:
534
+ return False
535
+
536
+ return True
537
+
509
538
  @classmethod
510
539
  def _resolve_dataarray_reference(
511
540
  cls, reference: str, arrays_dict: dict[str, xr.DataArray]
@@ -793,40 +822,7 @@ class Interface:
793
822
 
794
823
  def __repr__(self):
795
824
  """Return a detailed string representation for debugging."""
796
- try:
797
- # Get the constructor arguments and their current values
798
- init_signature = inspect.signature(self.__init__)
799
- init_args = init_signature.parameters
800
-
801
- # Create a dictionary with argument names and their values, with better formatting
802
- args_parts = []
803
- for name in init_args:
804
- if name == 'self':
805
- continue
806
- value = getattr(self, name, None)
807
- # Truncate long representations
808
- value_repr = repr(value)
809
- if len(value_repr) > 50:
810
- value_repr = value_repr[:47] + '...'
811
- args_parts.append(f'{name}={value_repr}')
812
-
813
- args_str = ', '.join(args_parts)
814
- return f'{self.__class__.__name__}({args_str})'
815
- except Exception:
816
- # Fallback if introspection fails
817
- return f'{self.__class__.__name__}(<repr_failed>)'
818
-
819
- def __str__(self):
820
- """Return a user-friendly string representation."""
821
- try:
822
- data = self.get_structure(clean=True, stats=True)
823
- with StringIO() as output_buffer:
824
- console = Console(file=output_buffer, width=1000) # Adjust width as needed
825
- console.print(Pretty(data, expand_all=True, indent_guides=True))
826
- return output_buffer.getvalue()
827
- except Exception:
828
- # Fallback if structure generation fails
829
- return f'{self.__class__.__name__} instance'
825
+ return fx_io.build_repr_from_init(self, excluded_params={'self', 'label', 'kwargs'})
830
826
 
831
827
  def copy(self) -> Interface:
832
828
  """
@@ -854,6 +850,8 @@ class Interface:
854
850
  class Element(Interface):
855
851
  """This class is the basic Element of flixopt. Every Element has a label"""
856
852
 
853
+ submodel: ElementModel | None
854
+
857
855
  def __init__(self, label: str, meta_data: dict | None = None):
858
856
  """
859
857
  Args:
@@ -862,7 +860,7 @@ class Element(Interface):
862
860
  """
863
861
  self.label = Element._valid_label(label)
864
862
  self.meta_data = meta_data if meta_data is not None else {}
865
- self.submodel: ElementModel | None = None
863
+ self.submodel = None
866
864
 
867
865
  def _plausibility_checks(self) -> None:
868
866
  """This function is used to do some basic plausibility checks for each Element during initialization.
@@ -876,6 +874,10 @@ class Element(Interface):
876
874
  def label_full(self) -> str:
877
875
  return self.label
878
876
 
877
+ def __repr__(self) -> str:
878
+ """Return string representation."""
879
+ return fx_io.build_repr_from_init(self, excluded_params={'self', 'label', 'kwargs'}, skip_default_size=True)
880
+
879
881
  @staticmethod
880
882
  def _valid_label(label: str) -> str:
881
883
  """Checks if the label is valid. If not, it is replaced by the default label.
@@ -895,6 +897,329 @@ class Element(Interface):
895
897
  return label
896
898
 
897
899
 
900
+ # Precompiled regex pattern for natural sorting
901
+ _NATURAL_SPLIT = re.compile(r'(\d+)')
902
+
903
+
904
+ def _natural_sort_key(text):
905
+ """Sort key for natural ordering (e.g., bus1, bus2, bus10 instead of bus1, bus10, bus2)."""
906
+ return [int(c) if c.isdigit() else c.lower() for c in _NATURAL_SPLIT.split(text)]
907
+
908
+
909
+ # Type variable for containers
910
+ T = TypeVar('T')
911
+
912
+
913
+ class ContainerMixin(dict[str, T]):
914
+ """
915
+ Mixin providing shared container functionality with nice repr and error messages.
916
+
917
+ Subclasses must implement _get_label() to extract the label from elements.
918
+ """
919
+
920
+ def __init__(
921
+ self,
922
+ elements: list[T] | dict[str, T] | None = None,
923
+ element_type_name: str = 'elements',
924
+ ):
925
+ """
926
+ Args:
927
+ elements: Initial elements to add (list or dict)
928
+ element_type_name: Name for display (e.g., 'components', 'buses')
929
+ """
930
+ super().__init__()
931
+ self._element_type_name = element_type_name
932
+
933
+ if elements is not None:
934
+ if isinstance(elements, dict):
935
+ for element in elements.values():
936
+ self.add(element)
937
+ else:
938
+ for element in elements:
939
+ self.add(element)
940
+
941
+ def _get_label(self, element: T) -> str:
942
+ """
943
+ Extract label from element. Must be implemented by subclasses.
944
+
945
+ Args:
946
+ element: Element to get label from
947
+
948
+ Returns:
949
+ Label string
950
+ """
951
+ raise NotImplementedError('Subclasses must implement _get_label()')
952
+
953
+ def add(self, element: T) -> None:
954
+ """Add an element to the container."""
955
+ label = self._get_label(element)
956
+ if label in self:
957
+ raise ValueError(
958
+ f'Element with label "{label}" already exists in {self._element_type_name}. '
959
+ f'Each element must have a unique label.'
960
+ )
961
+ self[label] = element
962
+
963
+ def __setitem__(self, label: str, element: T) -> None:
964
+ """Set element with validation."""
965
+ element_label = self._get_label(element)
966
+ if label != element_label:
967
+ raise ValueError(
968
+ f'Key "{label}" does not match element label "{element_label}". '
969
+ f'Use the correct label as key or use .add() method.'
970
+ )
971
+ super().__setitem__(label, element)
972
+
973
+ def __getitem__(self, label: str) -> T:
974
+ """
975
+ Get element by label with helpful error messages.
976
+
977
+ Args:
978
+ label: Label of the element to retrieve
979
+
980
+ Returns:
981
+ The element with the given label
982
+
983
+ Raises:
984
+ KeyError: If element is not found, with suggestions for similar labels
985
+ """
986
+ try:
987
+ return super().__getitem__(label)
988
+ except KeyError:
989
+ # Provide helpful error with close matches suggestions
990
+ suggestions = get_close_matches(label, self.keys(), n=3, cutoff=0.6)
991
+ error_msg = f'Element "{label}" not found in {self._element_type_name}.'
992
+ if suggestions:
993
+ error_msg += f' Did you mean: {", ".join(suggestions)}?'
994
+ else:
995
+ available = list(self.keys())
996
+ if len(available) <= 5:
997
+ error_msg += f' Available: {", ".join(available)}'
998
+ else:
999
+ error_msg += f' Available: {", ".join(available[:5])} ... (+{len(available) - 5} more)'
1000
+ raise KeyError(error_msg) from None
1001
+
1002
+ def __repr__(self) -> str:
1003
+ """Return a string representation similar to linopy.model.Variables."""
1004
+ count = len(self)
1005
+ title = f'{self._element_type_name.capitalize()} ({count} item{"s" if count != 1 else ""})'
1006
+
1007
+ if not self:
1008
+ r = fx_io.format_title_with_underline(title)
1009
+ r += '<empty>\n'
1010
+ else:
1011
+ r = fx_io.format_title_with_underline(title)
1012
+ for name in sorted(self.keys(), key=_natural_sort_key):
1013
+ r += f' * {name}\n'
1014
+
1015
+ return r
1016
+
1017
+
1018
+ class ElementContainer(ContainerMixin[T]):
1019
+ """
1020
+ Container for Element objects (Component, Bus, Flow, Effect).
1021
+
1022
+ Uses element.label_full for keying.
1023
+ """
1024
+
1025
+ def _get_label(self, element: T) -> str:
1026
+ """Extract label_full from Element."""
1027
+ return element.label_full
1028
+
1029
+
1030
+ class ResultsContainer(ContainerMixin[T]):
1031
+ """
1032
+ Container for Results objects (ComponentResults, BusResults, etc).
1033
+
1034
+ Uses element.label for keying.
1035
+ """
1036
+
1037
+ def _get_label(self, element: T) -> str:
1038
+ """Extract label from Results object."""
1039
+ return element.label
1040
+
1041
+
1042
+ T_element = TypeVar('T_element')
1043
+
1044
+
1045
+ class CompositeContainerMixin(Generic[T_element]):
1046
+ """
1047
+ Mixin providing unified dict-like access across multiple typed containers.
1048
+
1049
+ This mixin enables classes that manage multiple containers (e.g., components,
1050
+ buses, effects, flows) to provide a unified interface for accessing elements
1051
+ across all containers, as if they were a single collection.
1052
+
1053
+ Type Parameter:
1054
+ T_element: The type of elements stored in the containers. Can be a union type
1055
+ for containers holding multiple types (e.g., 'ComponentResults | BusResults').
1056
+
1057
+ Key Features:
1058
+ - Dict-like access: `obj['element_name']` searches all containers
1059
+ - Iteration: `for label in obj:` iterates over all elements
1060
+ - Membership: `'element' in obj` checks across all containers
1061
+ - Standard dict methods: keys(), values(), items()
1062
+ - Grouped display: Formatted repr showing elements by type
1063
+ - Type hints: Full IDE and type checker support
1064
+
1065
+ Subclasses must implement:
1066
+ _get_container_groups() -> dict[str, dict]:
1067
+ Returns a dictionary mapping group names (e.g., 'Components', 'Buses')
1068
+ to container dictionaries. Containers are displayed in the order returned.
1069
+
1070
+ Example:
1071
+ ```python
1072
+ class MySystem(CompositeContainerMixin[Component | Bus]):
1073
+ def __init__(self):
1074
+ self.components = {'Boiler': Component(...), 'CHP': Component(...)}
1075
+ self.buses = {'Heat': Bus(...), 'Power': Bus(...)}
1076
+
1077
+ def _get_container_groups(self):
1078
+ return {
1079
+ 'Components': self.components,
1080
+ 'Buses': self.buses,
1081
+ }
1082
+
1083
+
1084
+ system = MySystem()
1085
+ comp = system['Boiler'] # Type: Component | Bus (with proper IDE support)
1086
+ 'Heat' in system # True
1087
+ labels = system.keys() # Type: list[str]
1088
+ elements = system.values() # Type: list[Component | Bus]
1089
+ ```
1090
+
1091
+ Integration with ContainerMixin:
1092
+ This mixin is designed to work alongside ContainerMixin-based containers
1093
+ (ElementContainer, ResultsContainer) by aggregating them into a unified
1094
+ interface while preserving their individual functionality.
1095
+ """
1096
+
1097
+ def _get_container_groups(self) -> dict[str, ContainerMixin[Any]]:
1098
+ """
1099
+ Return ordered dict of container groups to aggregate.
1100
+
1101
+ Returns:
1102
+ Dictionary mapping group names to container objects (e.g., ElementContainer, ResultsContainer).
1103
+ Group names should be capitalized (e.g., 'Components', 'Buses').
1104
+ Order determines display order in __repr__.
1105
+
1106
+ Example:
1107
+ ```python
1108
+ return {
1109
+ 'Components': self.components,
1110
+ 'Buses': self.buses,
1111
+ 'Effects': self.effects,
1112
+ }
1113
+ ```
1114
+ """
1115
+ raise NotImplementedError('Subclasses must implement _get_container_groups()')
1116
+
1117
+ def __getitem__(self, key: str) -> T_element:
1118
+ """
1119
+ Get element by label, searching all containers.
1120
+
1121
+ Args:
1122
+ key: Element label to find
1123
+
1124
+ Returns:
1125
+ The element with the given label
1126
+
1127
+ Raises:
1128
+ KeyError: If element not found, with helpful suggestions
1129
+ """
1130
+ # Search all containers in order
1131
+ for container in self._get_container_groups().values():
1132
+ if key in container:
1133
+ return container[key]
1134
+
1135
+ # Element not found - provide helpful error
1136
+ all_elements = {}
1137
+ for container in self._get_container_groups().values():
1138
+ all_elements.update(container)
1139
+
1140
+ suggestions = get_close_matches(key, all_elements.keys(), n=3, cutoff=0.6)
1141
+ error_msg = f'Element "{key}" not found.'
1142
+
1143
+ if suggestions:
1144
+ error_msg += f' Did you mean: {", ".join(suggestions)}?'
1145
+ else:
1146
+ available = list(all_elements.keys())
1147
+ if len(available) <= 5:
1148
+ error_msg += f' Available: {", ".join(available)}'
1149
+ else:
1150
+ error_msg += f' Available: {", ".join(available[:5])} ... (+{len(available) - 5} more)'
1151
+
1152
+ raise KeyError(error_msg)
1153
+
1154
+ def __iter__(self):
1155
+ """Iterate over all element labels across all containers."""
1156
+ for container in self._get_container_groups().values():
1157
+ yield from container.keys()
1158
+
1159
+ def __len__(self) -> int:
1160
+ """Return total count of elements across all containers."""
1161
+ return sum(len(container) for container in self._get_container_groups().values())
1162
+
1163
+ def __contains__(self, key: str) -> bool:
1164
+ """Check if element exists in any container."""
1165
+ return any(key in container for container in self._get_container_groups().values())
1166
+
1167
+ def keys(self) -> list[str]:
1168
+ """Return all element labels across all containers."""
1169
+ return list(self)
1170
+
1171
+ def values(self) -> list[T_element]:
1172
+ """Return all element objects across all containers."""
1173
+ vals = []
1174
+ for container in self._get_container_groups().values():
1175
+ vals.extend(container.values())
1176
+ return vals
1177
+
1178
+ def items(self) -> list[tuple[str, T_element]]:
1179
+ """Return (label, element) pairs for all elements."""
1180
+ items = []
1181
+ for container in self._get_container_groups().values():
1182
+ items.extend(container.items())
1183
+ return items
1184
+
1185
+ def _format_grouped_containers(self, title: str | None = None) -> str:
1186
+ """
1187
+ Format containers as grouped string representation using each container's repr.
1188
+
1189
+ Args:
1190
+ title: Optional title for the representation. If None, no title is shown.
1191
+
1192
+ Returns:
1193
+ Formatted string with groups and their elements.
1194
+ Empty groups are automatically hidden.
1195
+
1196
+ Example output:
1197
+ ```
1198
+ Components (1 item)
1199
+ -------------------
1200
+ * Boiler
1201
+
1202
+ Buses (2 items)
1203
+ ---------------
1204
+ * Heat
1205
+ * Power
1206
+ ```
1207
+ """
1208
+ parts = []
1209
+
1210
+ if title:
1211
+ parts.append(fx_io.format_title_with_underline(title))
1212
+
1213
+ container_groups = self._get_container_groups()
1214
+ for container in container_groups.values():
1215
+ if container: # Only show non-empty groups
1216
+ if parts: # Add spacing between sections
1217
+ parts.append('')
1218
+ parts.append(repr(container).rstrip('\n'))
1219
+
1220
+ return '\n'.join(parts)
1221
+
1222
+
898
1223
  class Submodel(SubmodelsMixin):
899
1224
  """Stores Variables and Constraints. Its a subset of a FlowSystemModel.
900
1225
  Variables and constraints are stored in the main FlowSystemModel, and are referenced here.
@@ -1056,9 +1381,7 @@ class Submodel(SubmodelsMixin):
1056
1381
  }
1057
1382
 
1058
1383
  # Format sections with headers and underlines
1059
- formatted_sections = []
1060
- for section_header, section_content in sections.items():
1061
- formatted_sections.append(f'{section_header}\n{"-" * len(section_header)}\n{section_content}')
1384
+ formatted_sections = fx_io.format_sections_with_headers(sections)
1062
1385
 
1063
1386
  model_string = f'Submodel "{self.label_of_model}":'
1064
1387
  all_sections = '\n'.join(formatted_sections)
@@ -1102,7 +1425,7 @@ class Submodels:
1102
1425
  def __repr__(self) -> str:
1103
1426
  """Simple representation of the submodels collection."""
1104
1427
  if not self.data:
1105
- return 'flixopt.structure.Submodels:\n----------------------------\n <empty>\n'
1428
+ return fx_io.format_title_with_underline('flixopt.structure.Submodels') + ' <empty>\n'
1106
1429
 
1107
1430
  total_vars = sum(len(submodel.variables) for submodel in self.data.values())
1108
1431
  total_cons = sum(len(submodel.constraints) for submodel in self.data.values())
@@ -1110,18 +1433,15 @@ class Submodels:
1110
1433
  title = (
1111
1434
  f'flixopt.structure.Submodels ({total_vars} vars, {total_cons} constraints, {len(self.data)} submodels):'
1112
1435
  )
1113
- underline = '-' * len(title)
1114
1436
 
1115
- if not self.data:
1116
- return f'{title}\n{underline}\n <empty>\n'
1117
- sub_models_string = ''
1437
+ result = fx_io.format_title_with_underline(title)
1118
1438
  for name, submodel in self.data.items():
1119
1439
  type_name = submodel.__class__.__name__
1120
1440
  var_count = len(submodel.variables)
1121
1441
  con_count = len(submodel.constraints)
1122
- sub_models_string += f'\n * {name} [{type_name}] ({var_count}v/{con_count}c)'
1442
+ result += f' * {name} [{type_name}] ({var_count}v/{con_count}c)\n'
1123
1443
 
1124
- return f'{title}\n{underline}{sub_models_string}\n'
1444
+ return result
1125
1445
 
1126
1446
  def items(self) -> ItemsView[str, Submodel]:
1127
1447
  return self.data.items()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flixopt
3
- Version: 3.2.1
3
+ Version: 3.4.0
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>
@@ -27,6 +27,7 @@ Requires-Dist: linopy<0.6,>=0.5.1
27
27
  Requires-Dist: netcdf4<2,>=1.6.1
28
28
  Requires-Dist: pyyaml<7,>=6.0.0
29
29
  Requires-Dist: rich<15,>=13.0.0
30
+ Requires-Dist: tqdm<5,>=4.66.0
30
31
  Requires-Dist: tomli<3,>=2.0.1; python_version < "3.11"
31
32
  Requires-Dist: highspy<2,>=1.5.3
32
33
  Requires-Dist: matplotlib<4,>=3.5.2
@@ -60,7 +61,7 @@ Requires-Dist: pyvis==0.3.2; extra == "dev"
60
61
  Requires-Dist: tsam==2.3.9; extra == "dev"
61
62
  Requires-Dist: scipy==1.15.1; extra == "dev"
62
63
  Requires-Dist: gurobipy==12.0.3; extra == "dev"
63
- Requires-Dist: dash==3.0.0; extra == "dev"
64
+ Requires-Dist: dash==3.2.0; extra == "dev"
64
65
  Requires-Dist: dash-cytoscape==1.0.2; extra == "dev"
65
66
  Requires-Dist: dash-daq==0.6.0; extra == "dev"
66
67
  Requires-Dist: networkx==3.0.0; extra == "dev"
@@ -0,0 +1,26 @@
1
+ flixopt/__init__.py,sha256=_5d7Buc1ugaip5QbDGc9ebMO8LK0WWAjYHQMX2Th8P0,2217
2
+ flixopt/aggregation.py,sha256=ZE0LcUAZ8xNet13YjxvvMw8BAL7Qo4TcJBwBCE2sHqE,16562
3
+ flixopt/calculation.py,sha256=2jKc2Sma7zra1wJruyJmaNfLouquu1fKk0R4NQAqAWw,32681
4
+ flixopt/color_processing.py,sha256=bSq6iAnreiEBFz4Xf0AIUMyENJsWbJ-5xpiqM7_teUc,9027
5
+ flixopt/commons.py,sha256=ZNlUN1z-h9OGHPo-s-n5OLlJaoPZKVGcAdRyGKpMk4M,1256
6
+ flixopt/components.py,sha256=37JR4jJca7aD40ZWPM83Cyr9w7yotXo7gHUx25UUF8Q,58236
7
+ flixopt/config.py,sha256=vl6drczrsMshCA12kd6FXYE0uBBT3HF08GEF02OeU9Y,28958
8
+ flixopt/core.py,sha256=OG789eUaS5Lu0CjJiMIdtaixqnV5ZtMiKfERjCPRTv8,26366
9
+ flixopt/effects.py,sha256=BZE6Dn3krK9JOX2nn0LohA2GhWGiU9HJUwwp0zEGsb0,34355
10
+ flixopt/elements.py,sha256=2jVqtMgQrP6CO08A-S0JMANLKHddxUfA12KY6VfjZu8,38775
11
+ flixopt/features.py,sha256=kd-fMvADv8GXoKkrXObYjRJLN8toBG-5bOHTuh-59kk,25073
12
+ flixopt/flow_system.py,sha256=foZgjRYEY1qcuqs6c98y5T3Bd84KYtp4CNG2ppPJYJw,43792
13
+ flixopt/interface.py,sha256=TEm1tF24cWwCbP_0yBhhH0aVy_j5Fbgl3LI49H5yOIE,58692
14
+ flixopt/io.py,sha256=cxH3KDetLrfp3b9caOvSSv6A-Vis1dr2w8gRoQ0sZnY,36773
15
+ flixopt/linear_converters.py,sha256=tcz5c1SI36hRFbCX-4NXced12ss9VETg5BE7zOdyeo4,22699
16
+ flixopt/modeling.py,sha256=s0zipbblq-LJrSe7angKT3Imxgr3kIbprG98HUvmkzI,31322
17
+ flixopt/network_app.py,sha256=LnVAlAgzL1BgMYLsJ20a62j6nQUmNccF1zo4ACUXzL4,29433
18
+ flixopt/plotting.py,sha256=C_VyBVQIUP1HYt8roXk__Gz9m17cSSPikXZL4jidIpg,65024
19
+ flixopt/results.py,sha256=KboEmzyu7hv42e8lICaTJMQuV6Rjuejuc_ivdTz2WQo,120518
20
+ flixopt/solvers.py,sha256=rTFuL-lBflpbY_NGVGdXeWB2vLw5AdKemTn-Q0KaG7w,3007
21
+ flixopt/structure.py,sha256=7wjpthFkjFJpSo-OmFov4tF5lFoM6SSNhvDF65ecHdE,58155
22
+ flixopt-3.4.0.dist-info/licenses/LICENSE,sha256=HKsZnbrM_3Rvnr_u9cWSG90cBsj5_slaqI_z_qcxnGI,1118
23
+ flixopt-3.4.0.dist-info/METADATA,sha256=p7zVaOUK8x0umDLWYI1G7Qf-ghvO8wtfKpgC36q1PDM,12886
24
+ flixopt-3.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ flixopt-3.4.0.dist-info/top_level.txt,sha256=fanTzb9NylIXfv6Ic7spU97fVmRgGDPKvI_91tw4S3E,8
26
+ flixopt-3.4.0.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- flixopt/__init__.py,sha256=_5d7Buc1ugaip5QbDGc9ebMO8LK0WWAjYHQMX2Th8P0,2217
2
- flixopt/aggregation.py,sha256=ZE0LcUAZ8xNet13YjxvvMw8BAL7Qo4TcJBwBCE2sHqE,16562
3
- flixopt/calculation.py,sha256=YkVzpWJ4lYxCReP7H-lBYrkNGrza_SggjqGMU3xVf7o,29605
4
- flixopt/color_processing.py,sha256=bSq6iAnreiEBFz4Xf0AIUMyENJsWbJ-5xpiqM7_teUc,9027
5
- flixopt/commons.py,sha256=ZNlUN1z-h9OGHPo-s-n5OLlJaoPZKVGcAdRyGKpMk4M,1256
6
- flixopt/components.py,sha256=0EKnzoehrx4Wk-5b6NokHvmT1i7t1msi0JAMM5BA0WU,57711
7
- flixopt/config.py,sha256=ScqPyYn_URJmOo_aQDViQ-TktF3TZPrcCSoBCQXVpXc,24591
8
- flixopt/core.py,sha256=OG789eUaS5Lu0CjJiMIdtaixqnV5ZtMiKfERjCPRTv8,26366
9
- flixopt/effects.py,sha256=1UZaqmjHEjMahbKBcmgXP3JojIRDhUZKjPgLgOAJvO0,34056
10
- flixopt/elements.py,sha256=92SQ3ax57I9VLjhe0-4L6u3jaYDylrKcmuSFGuzneqI,36371
11
- flixopt/features.py,sha256=kd-fMvADv8GXoKkrXObYjRJLN8toBG-5bOHTuh-59kk,25073
12
- flixopt/flow_system.py,sha256=UCR37soFp1IEdNoATOa_eBFEYEwYdWk5QS63Fy9j9wI,40979
13
- flixopt/interface.py,sha256=ACWFIwdbjVN0x52QukKetpJgM0YGsWpvlBAtFnHgHa4,57925
14
- flixopt/io.py,sha256=1vjwFTyAr2ohkiwqE4qVX9juAG0l1wgxltcWcEPaFcQ,18895
15
- flixopt/linear_converters.py,sha256=tcz5c1SI36hRFbCX-4NXced12ss9VETg5BE7zOdyeo4,22699
16
- flixopt/modeling.py,sha256=s0zipbblq-LJrSe7angKT3Imxgr3kIbprG98HUvmkzI,31322
17
- flixopt/network_app.py,sha256=LnVAlAgzL1BgMYLsJ20a62j6nQUmNccF1zo4ACUXzL4,29433
18
- flixopt/plotting.py,sha256=C_VyBVQIUP1HYt8roXk__Gz9m17cSSPikXZL4jidIpg,65024
19
- flixopt/results.py,sha256=gZAj-BQpb7CHp0CcYy99ZF4_IEZvJnQfTeOEZe2TdCU,118942
20
- flixopt/solvers.py,sha256=m38Smc22MJfHYMiqfNf1MA3OmvbTRm5OWS9nECkDdQk,2355
21
- flixopt/structure.py,sha256=CrMqp1rzo45S-XJTVmJW4kQWh-a_ukz38uBp18LnBLU,47585
22
- flixopt-3.2.1.dist-info/licenses/LICENSE,sha256=HKsZnbrM_3Rvnr_u9cWSG90cBsj5_slaqI_z_qcxnGI,1118
23
- flixopt-3.2.1.dist-info/METADATA,sha256=DD5949y3Ldjxkt08Vb47Hy6oQbDKk6-DGnXmhFCf6GI,12855
24
- flixopt-3.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
- flixopt-3.2.1.dist-info/top_level.txt,sha256=fanTzb9NylIXfv6Ic7spU97fVmRgGDPKvI_91tw4S3E,8
26
- flixopt-3.2.1.dist-info/RECORD,,