flixopt 1.0.12__py3-none-any.whl → 2.0.1__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 (73) hide show
  1. docs/examples/00-Minimal Example.md +5 -0
  2. docs/examples/01-Basic Example.md +5 -0
  3. docs/examples/02-Complex Example.md +10 -0
  4. docs/examples/03-Calculation Modes.md +5 -0
  5. docs/examples/index.md +5 -0
  6. docs/faq/contribute.md +49 -0
  7. docs/faq/index.md +3 -0
  8. docs/images/architecture_flixOpt-pre2.0.0.png +0 -0
  9. docs/images/architecture_flixOpt.png +0 -0
  10. docs/images/flixopt-icon.svg +1 -0
  11. docs/javascripts/mathjax.js +18 -0
  12. docs/release-notes/_template.txt +32 -0
  13. docs/release-notes/index.md +7 -0
  14. docs/release-notes/v2.0.0.md +93 -0
  15. docs/release-notes/v2.0.1.md +12 -0
  16. docs/user-guide/Mathematical Notation/Bus.md +33 -0
  17. docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +132 -0
  18. docs/user-guide/Mathematical Notation/Flow.md +26 -0
  19. docs/user-guide/Mathematical Notation/LinearConverter.md +21 -0
  20. docs/user-guide/Mathematical Notation/Piecewise.md +49 -0
  21. docs/user-guide/Mathematical Notation/Storage.md +44 -0
  22. docs/user-guide/Mathematical Notation/index.md +22 -0
  23. docs/user-guide/Mathematical Notation/others.md +3 -0
  24. docs/user-guide/index.md +124 -0
  25. {flixOpt → flixopt}/__init__.py +5 -2
  26. {flixOpt → flixopt}/aggregation.py +113 -140
  27. flixopt/calculation.py +455 -0
  28. {flixOpt → flixopt}/commons.py +7 -4
  29. flixopt/components.py +630 -0
  30. {flixOpt → flixopt}/config.py +9 -8
  31. {flixOpt → flixopt}/config.yaml +3 -3
  32. flixopt/core.py +970 -0
  33. flixopt/effects.py +386 -0
  34. flixopt/elements.py +534 -0
  35. flixopt/features.py +1042 -0
  36. flixopt/flow_system.py +409 -0
  37. flixopt/interface.py +265 -0
  38. flixopt/io.py +308 -0
  39. flixopt/linear_converters.py +331 -0
  40. flixopt/plotting.py +1340 -0
  41. flixopt/results.py +898 -0
  42. flixopt/solvers.py +77 -0
  43. flixopt/structure.py +630 -0
  44. flixopt/utils.py +62 -0
  45. flixopt-2.0.1.dist-info/METADATA +145 -0
  46. flixopt-2.0.1.dist-info/RECORD +57 -0
  47. {flixopt-1.0.12.dist-info → flixopt-2.0.1.dist-info}/WHEEL +1 -1
  48. flixopt-2.0.1.dist-info/top_level.txt +6 -0
  49. pics/architecture_flixOpt-pre2.0.0.png +0 -0
  50. pics/architecture_flixOpt.png +0 -0
  51. pics/flixopt-icon.svg +1 -0
  52. pics/pics.pptx +0 -0
  53. scripts/gen_ref_pages.py +54 -0
  54. site/release-notes/_template.txt +32 -0
  55. flixOpt/calculation.py +0 -629
  56. flixOpt/components.py +0 -614
  57. flixOpt/core.py +0 -182
  58. flixOpt/effects.py +0 -410
  59. flixOpt/elements.py +0 -489
  60. flixOpt/features.py +0 -942
  61. flixOpt/flow_system.py +0 -351
  62. flixOpt/interface.py +0 -203
  63. flixOpt/linear_converters.py +0 -325
  64. flixOpt/math_modeling.py +0 -1145
  65. flixOpt/plotting.py +0 -712
  66. flixOpt/results.py +0 -563
  67. flixOpt/solvers.py +0 -21
  68. flixOpt/structure.py +0 -733
  69. flixOpt/utils.py +0 -134
  70. flixopt-1.0.12.dist-info/METADATA +0 -174
  71. flixopt-1.0.12.dist-info/RECORD +0 -29
  72. flixopt-1.0.12.dist-info/top_level.txt +0 -3
  73. {flixopt-1.0.12.dist-info → flixopt-2.0.1.dist-info/licenses}/LICENSE +0 -0
flixOpt/elements.py DELETED
@@ -1,489 +0,0 @@
1
- """
2
- This module contains the basic elements of the flixOpt framework.
3
- """
4
-
5
- import logging
6
- from typing import Dict, List, Optional, Tuple, Union
7
-
8
- import numpy as np
9
-
10
- from .config import CONFIG
11
- from .core import Numeric, Numeric_TS, Skalar
12
- from .effects import EffectValues, effect_values_to_time_series
13
- from .features import InvestmentModel, OnOffModel, PreventSimultaneousUsageModel
14
- from .interface import InvestParameters, OnOffParameters
15
- from .math_modeling import Variable, VariableTS
16
- from .structure import (
17
- Element,
18
- ElementModel,
19
- SystemModel,
20
- _create_time_series,
21
- copy_and_convert_datatypes,
22
- create_equation,
23
- create_variable,
24
- )
25
-
26
- logger = logging.getLogger('flixOpt')
27
-
28
-
29
- class Component(Element):
30
- """
31
- basic component class for all components
32
- """
33
-
34
- def __init__(
35
- self,
36
- label: str,
37
- inputs: Optional[List['Flow']] = None,
38
- outputs: Optional[List['Flow']] = None,
39
- on_off_parameters: Optional[OnOffParameters] = None,
40
- prevent_simultaneous_flows: Optional[List['Flow']] = None,
41
- meta_data: Optional[Dict] = None,
42
- ):
43
- """
44
- Parameters
45
- ----------
46
- label : str
47
- name.
48
- meta_data : Optional[Dict]
49
- used to store more information about the element. Is not used internally, but saved in the results
50
- inputs : input flows.
51
- outputs : output flows.
52
- on_off_parameters: Information about on and off state of Component.
53
- Component is On/Off, if all connected Flows are On/Off.
54
- Induces On-Variable in all FLows!
55
- See class OnOffParameters.
56
- prevent_simultaneous_flows: Define a Group of Flows. Only one them can be on at a time.
57
- Induces On-Variable in all FLows!
58
- """
59
- super().__init__(label, meta_data=meta_data)
60
- self.inputs: List['Flow'] = inputs or []
61
- self.outputs: List['Flow'] = outputs or []
62
- self.on_off_parameters = on_off_parameters
63
- self.prevent_simultaneous_flows: List['Flow'] = prevent_simultaneous_flows or []
64
-
65
- self.flows: Dict[str, Flow] = {flow.label: flow for flow in self.inputs + self.outputs}
66
-
67
- def create_model(self) -> 'ComponentModel':
68
- self.model = ComponentModel(self)
69
- return self.model
70
-
71
- def transform_data(self) -> None:
72
- if self.on_off_parameters is not None:
73
- self.on_off_parameters.transform_data(self)
74
-
75
- def register_component_in_flows(self) -> None:
76
- for flow in self.inputs + self.outputs:
77
- flow.comp = self
78
-
79
- def register_flows_in_bus(self) -> None:
80
- for flow in self.inputs:
81
- flow.bus.add_output(flow)
82
- for flow in self.outputs:
83
- flow.bus.add_input(flow)
84
-
85
- def infos(self, use_numpy=True, use_element_label=False) -> Dict:
86
- infos = super().infos(use_numpy, use_element_label)
87
- infos['inputs'] = [flow.infos(use_numpy, use_element_label) for flow in self.inputs]
88
- infos['outputs'] = [flow.infos(use_numpy, use_element_label) for flow in self.outputs]
89
- return infos
90
-
91
-
92
- class Bus(Element):
93
- """
94
- realizing balance of all linked flows
95
- (penalty flow is excess can be activated)
96
- """
97
-
98
- def __init__(
99
- self, label: str, excess_penalty_per_flow_hour: Optional[Numeric_TS] = 1e5, meta_data: Optional[Dict] = None
100
- ):
101
- """
102
- Parameters
103
- ----------
104
- label : str
105
- name.
106
- meta_data : Optional[Dict]
107
- used to store more information about the element. Is not used internally, but saved in the results
108
- excess_penalty_per_flow_hour : none or scalar, array or TimeSeriesData
109
- excess costs / penalty costs (bus balance compensation)
110
- (none/ 0 -> no penalty). The default is 1e5.
111
- (Take care: if you use a timeseries (no scalar), timeseries is aggregated if calculation_type = aggregated!)
112
- """
113
- super().__init__(label, meta_data=meta_data)
114
- self.excess_penalty_per_flow_hour = excess_penalty_per_flow_hour
115
- self.inputs: List[Flow] = []
116
- self.outputs: List[Flow] = []
117
-
118
- def create_model(self) -> 'BusModel':
119
- self.model = BusModel(self)
120
- return self.model
121
-
122
- def transform_data(self):
123
- self.excess_penalty_per_flow_hour = _create_time_series(
124
- 'excess_penalty_per_flow_hour', self.excess_penalty_per_flow_hour, self
125
- )
126
-
127
- def add_input(self, flow) -> None:
128
- flow: Flow
129
- self.inputs.append(flow)
130
-
131
- def add_output(self, flow) -> None:
132
- flow: Flow
133
- self.outputs.append(flow)
134
-
135
- def _plausibility_checks(self) -> None:
136
- if self.excess_penalty_per_flow_hour == 0:
137
- logger.warning(f'In Bus {self.label}, the excess_penalty_per_flow_hour is 0. Use "None" or a value > 0.')
138
-
139
- @property
140
- def with_excess(self) -> bool:
141
- return False if self.excess_penalty_per_flow_hour is None else True
142
-
143
-
144
- class Connection:
145
- # input/output-dock (TODO:
146
- # -> wäre cool, damit Komponenten auch auch ohne Knoten verbindbar
147
- # input wären wie Flow,aber statt bus : connectsTo -> hier andere Connection oder aber Bus (dort keine Connection, weil nicht notwendig)
148
-
149
- def __init__(self):
150
- raise NotImplementedError()
151
-
152
-
153
- class Flow(Element):
154
- """
155
- flows are inputs and outputs of components
156
- """
157
-
158
- def __init__(
159
- self,
160
- label: str,
161
- bus: Bus,
162
- size: Union[Skalar, InvestParameters] = None,
163
- fixed_relative_profile: Optional[Numeric_TS] = None,
164
- relative_minimum: Numeric_TS = 0,
165
- relative_maximum: Numeric_TS = 1,
166
- effects_per_flow_hour: EffectValues = None,
167
- on_off_parameters: Optional[OnOffParameters] = None,
168
- flow_hours_total_max: Optional[Skalar] = None,
169
- flow_hours_total_min: Optional[Skalar] = None,
170
- load_factor_min: Optional[Skalar] = None,
171
- load_factor_max: Optional[Skalar] = None,
172
- previous_flow_rate: Optional[Numeric] = None,
173
- meta_data: Optional[Dict] = None,
174
- ):
175
- r"""
176
- Parameters
177
- ----------
178
- label : str
179
- name of flow
180
- meta_data : Optional[Dict]
181
- used to store more information about the element. Is not used internally, but saved in the results
182
- bus : Bus, optional
183
- bus to which flow is linked
184
- size : scalar, InvestmentParameters, optional
185
- size of the flow. If InvestmentParameters is used, size is optimized.
186
- If size is None, a default value is used.
187
- relative_minimum : scalar, array, TimeSeriesData, optional
188
- min value is relative_minimum multiplied by size
189
- relative_maximum : scalar, array, TimeSeriesData, optional
190
- max value is relative_maximum multiplied by size. If size = max then relative_maximum=1
191
- load_factor_min : scalar, optional
192
- minimal load factor general: avg Flow per nominalVal/investSize
193
- (e.g. boiler, kW/kWh=h; solarthermal: kW/m²;
194
- def: :math:`load\_factor:= sumFlowHours/ (nominal\_val \cdot \Delta t_{tot})`
195
- load_factor_max : scalar, optional
196
- maximal load factor (see minimal load factor)
197
- effects_per_flow_hour : scalar, array, TimeSeriesData, optional
198
- operational costs, costs per flow-"work"
199
- on_off_parameters : OnOffParameters, optional
200
- If present, flow can be "off", i.e. be zero (only relevant if relative_minimum > 0)
201
- Therefore a binary var "on" is used. Further, several other restrictions and effects can be modeled
202
- through this On/Off State (See OnOffParameters)
203
- flow_hours_total_max : TYPE, optional
204
- maximum flow-hours ("flow-work")
205
- (if size is not const, maybe load_factor_max fits better for you!)
206
- flow_hours_total_min : TYPE, optional
207
- minimum flow-hours ("flow-work")
208
- (if size is not const, maybe load_factor_min fits better for you!)
209
- fixed_relative_profile : scalar, array, TimeSeriesData, optional
210
- fixed relative values for flow (if given).
211
- val(t) := fixed_relative_profile(t) * size(t)
212
- With this value, the flow_rate is no opt-variable anymore;
213
- (relative_minimum u. relative_maximum are making sense anymore)
214
- used for fixed load profiles, i.g. heat demand, wind-power, solarthermal
215
- If the load-profile is just an upper limit, use relative_maximum instead.
216
- previous_flow_rate : scalar, array, optional
217
- previous flow rate of the component.
218
- """
219
- super().__init__(label, meta_data=meta_data)
220
- self.size = size or CONFIG.modeling.BIG # Default size
221
- self.relative_minimum = relative_minimum
222
- self.relative_maximum = relative_maximum
223
- self.fixed_relative_profile = fixed_relative_profile
224
-
225
- self.load_factor_min = load_factor_min
226
- self.load_factor_max = load_factor_max
227
- # self.positive_gradient = TimeSeries('positive_gradient', positive_gradient, self)
228
- self.effects_per_flow_hour = effects_per_flow_hour if effects_per_flow_hour is not None else {}
229
- self.flow_hours_total_max = flow_hours_total_max
230
- self.flow_hours_total_min = flow_hours_total_min
231
- self.on_off_parameters = on_off_parameters
232
-
233
- self.previous_flow_rate = previous_flow_rate
234
-
235
- self.bus = bus
236
- self.comp: Optional[Component] = None
237
-
238
- self._plausibility_checks()
239
-
240
- def create_model(self) -> 'FlowModel':
241
- self.model = FlowModel(self)
242
- return self.model
243
-
244
- def transform_data(self):
245
- self.relative_minimum = _create_time_series('relative_minimum', self.relative_minimum, self)
246
- self.relative_maximum = _create_time_series('relative_maximum', self.relative_maximum, self)
247
- self.fixed_relative_profile = _create_time_series('fixed_relative_profile', self.fixed_relative_profile, self)
248
- self.effects_per_flow_hour = effect_values_to_time_series('per_flow_hour', self.effects_per_flow_hour, self)
249
- if self.on_off_parameters is not None:
250
- self.on_off_parameters.transform_data(self)
251
- if isinstance(self.size, InvestParameters):
252
- self.size.transform_data()
253
-
254
- def infos(self, use_numpy=True, use_element_label=False) -> Dict:
255
- infos = super().infos(use_numpy, use_element_label)
256
- infos['is_input_in_component'] = self.is_input_in_comp
257
- return infos
258
-
259
- def _plausibility_checks(self) -> None:
260
- # TODO: Incorporate into Variable? (Lower_bound can not be greater than upper bound
261
- if np.any(self.relative_minimum > self.relative_maximum):
262
- raise Exception(self.label_full + ': Take care, that relative_minimum <= relative_maximum!')
263
-
264
- if (
265
- self.size == CONFIG.modeling.BIG and self.fixed_relative_profile is not None
266
- ): # Default Size --> Most likely by accident
267
- logger.warning(
268
- f'Flow "{self.label}" has no size assigned, but a "fixed_relative_profile". '
269
- f'The default size is {CONFIG.modeling.BIG}. As "flow_rate = size * fixed_relative_profile", '
270
- f'the resulting flow_rate will be very high. To fix this, assign a size to the Flow {self}.'
271
- )
272
-
273
- @property
274
- def label_full(self) -> str:
275
- # Wenn im Erstellungsprozess comp noch nicht bekannt:
276
- comp_label = 'unknownComp' if self.comp is None else self.comp.label
277
- return f'{comp_label}__{self.label}' # z.B. für results_struct (deswegen auch _ statt . dazwischen)
278
-
279
- @property # Richtung
280
- def is_input_in_comp(self) -> bool:
281
- return True if self in self.comp.inputs else False
282
-
283
- @property
284
- def size_is_fixed(self) -> bool:
285
- # Wenn kein InvestParameters existiert --> True; Wenn Investparameter, den Wert davon nehmen
286
- return False if (isinstance(self.size, InvestParameters) and self.size.fixed_size is None) else True
287
-
288
- @property
289
- def invest_is_optional(self) -> bool:
290
- # Wenn kein InvestParameters existiert: # Investment ist nicht optional -> Keine Variable --> False
291
- return False if (isinstance(self.size, InvestParameters) and not self.size.optional) else True
292
-
293
-
294
- class FlowModel(ElementModel):
295
- def __init__(self, element: Flow):
296
- super().__init__(element)
297
- self.element: Flow = element
298
- self.flow_rate: Optional[VariableTS] = None
299
- self.sum_flow_hours: Optional[Variable] = None
300
-
301
- self._on: Optional[OnOffModel] = None
302
- self._investment: Optional[InvestmentModel] = None
303
-
304
- def do_modeling(self, system_model: SystemModel):
305
- # eq relative_minimum(t) * size <= flow_rate(t) <= relative_maximum(t) * size
306
- self.flow_rate = create_variable(
307
- 'flow_rate',
308
- self,
309
- system_model.nr_of_time_steps,
310
- lower_bound=self.absolute_flow_rate_bounds[0] if self.element.on_off_parameters is None else 0,
311
- upper_bound=self.absolute_flow_rate_bounds[1] if self.element.on_off_parameters is None else None,
312
- previous_values=self.element.previous_flow_rate,
313
- )
314
-
315
- # OnOff
316
- if self.element.on_off_parameters is not None:
317
- self._on = OnOffModel(
318
- self.element, self.element.on_off_parameters, [self.flow_rate], [self.absolute_flow_rate_bounds]
319
- )
320
- self._on.do_modeling(system_model)
321
- self.sub_models.append(self._on)
322
-
323
- # Investment
324
- if isinstance(self.element.size, InvestParameters):
325
- self._investment = InvestmentModel(
326
- self.element,
327
- self.element.size,
328
- self.flow_rate,
329
- self.relative_flow_rate_bounds,
330
- fixed_relative_profile=(None
331
- if self.element.fixed_relative_profile is None
332
- else self.element.fixed_relative_profile.active_data),
333
- on_variable=self._on.on if self._on is not None else None,
334
- )
335
- self._investment.do_modeling(system_model)
336
- self.sub_models.append(self._investment)
337
-
338
- # sumFLowHours
339
- self.sum_flow_hours = create_variable(
340
- 'sumFlowHours',
341
- self,
342
- 1,
343
- lower_bound=self.element.flow_hours_total_min,
344
- upper_bound=self.element.flow_hours_total_max,
345
- )
346
- eq_sum_flow_hours = create_equation('sumFlowHours', self, 'eq')
347
- eq_sum_flow_hours.add_summand(self.flow_rate, system_model.dt_in_hours, as_sum=True)
348
- eq_sum_flow_hours.add_summand(self.sum_flow_hours, -1)
349
-
350
- # Load factor
351
- self._create_bounds_for_load_factor(system_model)
352
-
353
- # Shares
354
- self._create_shares(system_model)
355
-
356
- def _create_shares(self, system_model: SystemModel):
357
- # Arbeitskosten:
358
- if self.element.effects_per_flow_hour != {}:
359
- system_model.effect_collection_model.add_share_to_operation(
360
- name='effects_per_flow_hour',
361
- element=self.element,
362
- variable=self.flow_rate,
363
- effect_values=self.element.effects_per_flow_hour,
364
- factor=system_model.dt_in_hours,
365
- )
366
-
367
- def _create_bounds_for_load_factor(self, system_model: SystemModel):
368
- # TODO: Add Variable load_factor for better evaluation?
369
-
370
- # eq: var_sumFlowHours <= size * dt_tot * load_factor_max
371
- if self.element.load_factor_max is not None:
372
- flow_hours_per_size_max = system_model.dt_in_hours_total * self.element.load_factor_max
373
- eq_load_factor_max = create_equation('load_factor_max', self, 'ineq')
374
- eq_load_factor_max.add_summand(self.sum_flow_hours, 1)
375
- # if investment:
376
- if self._investment is not None:
377
- eq_load_factor_max.add_summand(self._investment.size, -1 * flow_hours_per_size_max)
378
- else:
379
- eq_load_factor_max.add_constant(self.element.size * flow_hours_per_size_max)
380
-
381
- # eq: size * sum(dt)* load_factor_min <= var_sumFlowHours
382
- if self.element.load_factor_min is not None:
383
- flow_hours_per_size_min = system_model.dt_in_hours_total * self.element.load_factor_min
384
- eq_load_factor_min = create_equation('load_factor_min', self, 'ineq')
385
- eq_load_factor_min.add_summand(self.sum_flow_hours, -1)
386
- if self._investment is not None:
387
- eq_load_factor_min.add_summand(self._investment.size, flow_hours_per_size_min)
388
- else:
389
- eq_load_factor_min.add_constant(-1 * self.element.size * flow_hours_per_size_min)
390
-
391
- @property
392
- def with_investment(self) -> bool:
393
- """Checks if the element's size is investment-driven."""
394
- return isinstance(self.element.size, InvestParameters)
395
-
396
- @property
397
- def absolute_flow_rate_bounds(self) -> Tuple[Numeric, Numeric]:
398
- """Returns absolute flow rate bounds. Important for OnOffModel"""
399
- rel_min, rel_max = self.relative_flow_rate_bounds
400
- size = self.element.size
401
- if not self.with_investment:
402
- return rel_min * size, rel_max * size
403
- if size.fixed_size is not None:
404
- return rel_min * size.fixed_size, rel_max * size.fixed_size
405
- return rel_min * size.minimum_size, rel_max * size.maximum_size
406
-
407
-
408
- @property
409
- def relative_flow_rate_bounds(self) -> Tuple[Numeric, Numeric]:
410
- """Returns relative flow rate bounds."""
411
- fixed_profile = self.element.fixed_relative_profile
412
- if fixed_profile is None:
413
- return self.element.relative_minimum.active_data, self.element.relative_maximum.active_data
414
- return fixed_profile.active_data, fixed_profile.active_data
415
-
416
-
417
- class BusModel(ElementModel):
418
- def __init__(self, element: Bus):
419
- super().__init__(element)
420
- self.element: Bus
421
- self.excess_input: Optional[VariableTS] = None
422
- self.excess_output: Optional[VariableTS] = None
423
-
424
- def do_modeling(self, system_model: SystemModel) -> None:
425
- self.element: Bus
426
- # inputs = outputs
427
- eq_bus_balance = create_equation('busBalance', self)
428
- for flow in self.element.inputs:
429
- eq_bus_balance.add_summand(flow.model.flow_rate, 1)
430
- for flow in self.element.outputs:
431
- eq_bus_balance.add_summand(flow.model.flow_rate, -1)
432
-
433
- # Fehlerplus/-minus:
434
- if self.element.with_excess:
435
- excess_penalty = np.multiply(
436
- system_model.dt_in_hours, self.element.excess_penalty_per_flow_hour.active_data
437
- )
438
- self.excess_input = create_variable('excess_input', self, system_model.nr_of_time_steps, lower_bound=0)
439
- self.excess_output = create_variable('excess_output', self, system_model.nr_of_time_steps, lower_bound=0)
440
-
441
- eq_bus_balance.add_summand(self.excess_output, -1)
442
- eq_bus_balance.add_summand(self.excess_input, 1)
443
-
444
- fx_collection = system_model.effect_collection_model
445
-
446
- fx_collection.add_share_to_penalty(
447
- f'{self.element.label_full}__excess_input', self.excess_input, excess_penalty
448
- )
449
- fx_collection.add_share_to_penalty(
450
- f'{self.element.label_full}__excess_output', self.excess_output, excess_penalty
451
- )
452
-
453
-
454
- class ComponentModel(ElementModel):
455
- def __init__(self, element: Component):
456
- super().__init__(element)
457
- self.element: Component = element
458
- self._on: Optional[OnOffModel] = None
459
-
460
- def do_modeling(self, system_model: SystemModel):
461
- """Initiates all FlowModels"""
462
- all_flows = self.element.inputs + self.element.outputs
463
- if self.element.on_off_parameters:
464
- for flow in all_flows:
465
- if flow.on_off_parameters is None:
466
- flow.on_off_parameters = OnOffParameters()
467
-
468
- if self.element.prevent_simultaneous_flows:
469
- for flow in self.element.prevent_simultaneous_flows:
470
- if flow.on_off_parameters is None:
471
- flow.on_off_parameters = OnOffParameters()
472
-
473
- self.sub_models.extend([flow.create_model() for flow in all_flows])
474
- for sub_model in self.sub_models:
475
- sub_model.do_modeling(system_model)
476
-
477
- if self.element.on_off_parameters:
478
- flow_rates: List[VariableTS] = [flow.model.flow_rate for flow in all_flows]
479
- bounds: List[Tuple[Numeric, Numeric]] = [flow.model.absolute_flow_rate_bounds for flow in all_flows]
480
- self._on = OnOffModel(self.element, self.element.on_off_parameters, flow_rates, bounds)
481
- self.sub_models.append(self._on)
482
- self._on.do_modeling(system_model)
483
-
484
- if self.element.prevent_simultaneous_flows:
485
- # Simultanious Useage --> Only One FLow is On at a time, but needs a Binary for every flow
486
- on_variables = [flow.model._on.on for flow in self.element.prevent_simultaneous_flows]
487
- simultaneous_use = PreventSimultaneousUsageModel(self.element, on_variables)
488
- self.sub_models.append(simultaneous_use)
489
- simultaneous_use.do_modeling(system_model)