flixopt 2.2.0b0__py3-none-any.whl → 2.2.0rc2__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.
- docs/examples/00-Minimal Example.md +1 -1
- docs/examples/01-Basic Example.md +1 -1
- docs/examples/02-Complex Example.md +1 -1
- docs/examples/index.md +1 -1
- docs/faq/contribute.md +26 -14
- docs/faq/index.md +1 -1
- docs/javascripts/mathjax.js +1 -1
- docs/user-guide/Mathematical Notation/Bus.md +1 -1
- docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +13 -13
- docs/user-guide/Mathematical Notation/Flow.md +1 -1
- docs/user-guide/Mathematical Notation/LinearConverter.md +2 -2
- docs/user-guide/Mathematical Notation/Piecewise.md +1 -1
- docs/user-guide/Mathematical Notation/Storage.md +1 -1
- docs/user-guide/Mathematical Notation/index.md +1 -1
- docs/user-guide/Mathematical Notation/others.md +1 -1
- docs/user-guide/index.md +2 -2
- flixopt/__init__.py +5 -0
- flixopt/aggregation.py +0 -1
- flixopt/calculation.py +40 -72
- flixopt/commons.py +10 -1
- flixopt/components.py +326 -154
- flixopt/core.py +459 -966
- flixopt/effects.py +67 -270
- flixopt/elements.py +76 -84
- flixopt/features.py +172 -154
- flixopt/flow_system.py +70 -99
- flixopt/interface.py +315 -147
- flixopt/io.py +27 -56
- flixopt/linear_converters.py +3 -3
- flixopt/network_app.py +755 -0
- flixopt/plotting.py +16 -34
- flixopt/results.py +108 -806
- flixopt/structure.py +11 -67
- flixopt/utils.py +9 -6
- {flixopt-2.2.0b0.dist-info → flixopt-2.2.0rc2.dist-info}/METADATA +63 -42
- flixopt-2.2.0rc2.dist-info/RECORD +54 -0
- {flixopt-2.2.0b0.dist-info → flixopt-2.2.0rc2.dist-info}/WHEEL +1 -1
- scripts/extract_release_notes.py +45 -0
- docs/release-notes/_template.txt +0 -32
- docs/release-notes/index.md +0 -7
- docs/release-notes/v2.0.0.md +0 -93
- docs/release-notes/v2.0.1.md +0 -12
- docs/release-notes/v2.1.0.md +0 -31
- docs/release-notes/v2.2.0.md +0 -55
- docs/user-guide/Mathematical Notation/Investment.md +0 -115
- flixopt-2.2.0b0.dist-info/RECORD +0 -59
- {flixopt-2.2.0b0.dist-info → flixopt-2.2.0rc2.dist-info}/licenses/LICENSE +0 -0
- {flixopt-2.2.0b0.dist-info → flixopt-2.2.0rc2.dist-info}/top_level.txt +0 -0
flixopt/io.py
CHANGED
|
@@ -23,7 +23,7 @@ def replace_timeseries(obj, mode: Literal['name', 'stats', 'data'] = 'name'):
|
|
|
23
23
|
return [replace_timeseries(v, mode) for v in obj]
|
|
24
24
|
elif isinstance(obj, TimeSeries): # Adjust this based on the actual class
|
|
25
25
|
if obj.all_equal:
|
|
26
|
-
return obj.
|
|
26
|
+
return obj.active_data.values[0].item()
|
|
27
27
|
elif mode == 'name':
|
|
28
28
|
return f'::::{obj.name}'
|
|
29
29
|
elif mode == 'stats':
|
|
@@ -44,7 +44,7 @@ def insert_dataarray(obj, ds: xr.Dataset):
|
|
|
44
44
|
return [insert_dataarray(v, ds) for v in obj]
|
|
45
45
|
elif isinstance(obj, str) and obj.startswith('::::'):
|
|
46
46
|
da = ds[obj[4:]]
|
|
47
|
-
if
|
|
47
|
+
if da.isel(time=-1).isnull():
|
|
48
48
|
return da.isel(time=slice(0, -1))
|
|
49
49
|
return da
|
|
50
50
|
else:
|
|
@@ -79,17 +79,15 @@ def _save_to_yaml(data, output_file='formatted_output.yaml'):
|
|
|
79
79
|
output_file (str): Path to output YAML file
|
|
80
80
|
"""
|
|
81
81
|
# Process strings to normalize all newlines and handle special patterns
|
|
82
|
-
processed_data =
|
|
82
|
+
processed_data = _process_complex_strings(data)
|
|
83
83
|
|
|
84
84
|
# Define a custom representer for strings
|
|
85
85
|
def represent_str(dumper, data):
|
|
86
|
-
# Use literal block style (|) for
|
|
86
|
+
# Use literal block style (|) for any string with newlines
|
|
87
87
|
if '\n' in data:
|
|
88
|
-
# Clean up formatting for literal block style
|
|
89
|
-
data = data.strip() # Remove leading/trailing whitespace
|
|
90
88
|
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
|
|
91
89
|
|
|
92
|
-
# Use quoted style for strings with special characters
|
|
90
|
+
# Use quoted style for strings with special characters to ensure proper parsing
|
|
93
91
|
elif any(char in data for char in ':`{}[]#,&*!|>%@'):
|
|
94
92
|
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
|
|
95
93
|
|
|
@@ -99,80 +97,53 @@ def _save_to_yaml(data, output_file='formatted_output.yaml'):
|
|
|
99
97
|
# Add the string representer to SafeDumper
|
|
100
98
|
yaml.add_representer(str, represent_str, Dumper=yaml.SafeDumper)
|
|
101
99
|
|
|
102
|
-
# Configure dumper options for better formatting
|
|
103
|
-
class CustomDumper(yaml.SafeDumper):
|
|
104
|
-
def increase_indent(self, flow=False, indentless=False):
|
|
105
|
-
return super(CustomDumper, self).increase_indent(flow, False)
|
|
106
|
-
|
|
107
100
|
# Write to file with settings that ensure proper formatting
|
|
108
101
|
with open(output_file, 'w', encoding='utf-8') as file:
|
|
109
102
|
yaml.dump(
|
|
110
103
|
processed_data,
|
|
111
104
|
file,
|
|
112
|
-
Dumper=
|
|
105
|
+
Dumper=yaml.SafeDumper,
|
|
113
106
|
sort_keys=False, # Preserve dictionary order
|
|
114
107
|
default_flow_style=False, # Use block style for mappings
|
|
115
|
-
width=
|
|
108
|
+
width=float('inf'), # Don't wrap long lines
|
|
116
109
|
allow_unicode=True, # Support Unicode characters
|
|
117
|
-
indent=2, # Set consistent indentation
|
|
118
110
|
)
|
|
119
111
|
|
|
120
112
|
|
|
121
|
-
def
|
|
113
|
+
def _process_complex_strings(data):
|
|
122
114
|
"""
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
Handles dictionaries, lists, and strings, applying various text normalization
|
|
126
|
-
rules while preserving important formatting elements.
|
|
115
|
+
Process dictionary data recursively with comprehensive string normalization.
|
|
116
|
+
Handles various types of strings and special formatting.
|
|
127
117
|
|
|
128
118
|
Args:
|
|
129
|
-
data:
|
|
119
|
+
data: The data to process (dict, list, str, or other)
|
|
130
120
|
|
|
131
121
|
Returns:
|
|
132
|
-
|
|
122
|
+
Processed data with normalized strings
|
|
133
123
|
"""
|
|
134
124
|
if isinstance(data, dict):
|
|
135
|
-
return {
|
|
136
|
-
|
|
125
|
+
return {k: _process_complex_strings(v) for k, v in data.items()}
|
|
137
126
|
elif isinstance(data, list):
|
|
138
|
-
return [
|
|
139
|
-
|
|
127
|
+
return [_process_complex_strings(item) for item in data]
|
|
140
128
|
elif isinstance(data, str):
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
else:
|
|
144
|
-
return data
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def _normalize_string_content(text):
|
|
148
|
-
"""
|
|
149
|
-
Apply comprehensive string normalization rules.
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
text: The string to normalize
|
|
129
|
+
# Step 1: Normalize line endings to \n
|
|
130
|
+
normalized = data.replace('\r\n', '\n').replace('\r', '\n')
|
|
153
131
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"""
|
|
157
|
-
# Standardize line endings
|
|
158
|
-
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
|
132
|
+
# Step 2: Handle escaped newlines with robust regex
|
|
133
|
+
normalized = re.sub(r'(?<!\\)\\n', '\n', normalized)
|
|
159
134
|
|
|
160
|
-
|
|
161
|
-
|
|
135
|
+
# Step 3: Handle unnecessary double backslashes
|
|
136
|
+
normalized = re.sub(r'\\\\(n)', r'\\\1', normalized)
|
|
162
137
|
|
|
163
|
-
|
|
164
|
-
|
|
138
|
+
# Step 4: Ensure proper formatting of "[time: N]:\n---------"
|
|
139
|
+
normalized = re.sub(r'(\[time: \d+\]):\s*\\?n', r'\1:\n', normalized)
|
|
165
140
|
|
|
166
|
-
|
|
167
|
-
|
|
141
|
+
# Step 5: Ensure "Constraint `...`" patterns are properly formatted
|
|
142
|
+
normalized = re.sub(r'Constraint `([^`]+)`\\?n', r'Constraint `\1`\n', normalized)
|
|
168
143
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# Limit consecutive newlines (max 2)
|
|
173
|
-
text = re.sub(r'\n{3,}', '\n\n', text)
|
|
174
|
-
|
|
175
|
-
return text.strip()
|
|
144
|
+
return normalized
|
|
145
|
+
else:
|
|
146
|
+
return data
|
|
176
147
|
|
|
177
148
|
|
|
178
149
|
def document_linopy_model(model: linopy.Model, path: pathlib.Path = None) -> Dict[str, str]:
|
flixopt/linear_converters.py
CHANGED
|
@@ -165,7 +165,7 @@ class CoolingTower(LinearConverter):
|
|
|
165
165
|
label,
|
|
166
166
|
inputs=[P_el, Q_th],
|
|
167
167
|
outputs=[],
|
|
168
|
-
conversion_factors=[{P_el.label:
|
|
168
|
+
conversion_factors=[{P_el.label: 1, Q_th.label: -specific_electricity_demand}],
|
|
169
169
|
on_off_parameters=on_off_parameters,
|
|
170
170
|
meta_data=meta_data,
|
|
171
171
|
)
|
|
@@ -177,12 +177,12 @@ class CoolingTower(LinearConverter):
|
|
|
177
177
|
|
|
178
178
|
@property
|
|
179
179
|
def specific_electricity_demand(self):
|
|
180
|
-
return self.conversion_factors[0][self.Q_th.label]
|
|
180
|
+
return -self.conversion_factors[0][self.Q_th.label]
|
|
181
181
|
|
|
182
182
|
@specific_electricity_demand.setter
|
|
183
183
|
def specific_electricity_demand(self, value):
|
|
184
184
|
check_bounds(value, 'specific_electricity_demand', self.label_full, 0, 1)
|
|
185
|
-
self.conversion_factors[0][self.Q_th.label] = value
|
|
185
|
+
self.conversion_factors[0][self.Q_th.label] = -value
|
|
186
186
|
|
|
187
187
|
|
|
188
188
|
@register_class_for_io
|