Skip to content

Commit 5fd9ff5

Browse files
committed
Feature/excess rename (#501)
* | File | Changes | |-------------------------|----------------------------------------------------------------------------------| | flixopt/elements.py | Renamed attributes excess_input → virtual_supply, excess_output → virtual_demand | | flixopt/optimization.py | Updated attribute access and result keys | | tests/test_bus.py | Updated variable name strings in assertions | | docs/.../Bus.md | Updated description of φ symbols | The variable names in the optimization model are now: - {BusName}|virtual_supply (was excess_input) - {BusName}|virtual_demand (was excess_output) * Renamed excess_penalty_per_flow_hour → imbalance_penalty_per_flow_hour * rename excess_penalty to imbalance_penalty * Change default to None * Added self._validate_kwargs(kwargs) to catch typos and unexpected arguments * Renamed with_excess → allows_imbalance * Fix docstring * 1. docs/user-guide/mathematical-notation/elements/Bus.md - Fixed three typos: - "a imbalance_penalty_per_flow_hour" → "an imbalance_penalty_per_flow_hour" - "usefull" → "useful" - "ifeasiblity" → "infeasibility" 2. tests/test_bus.py - Updated comments to use the new imbalance terminology instead of the old "excess" terminology 3. flixopt/elements.py (BusModel) - Improved code clarity: - Changed eq_bus_balance.lhs -= -self.virtual_supply + self.virtual_demand to the more readable eq_bus_balance.lhs += self.virtual_supply - self.virtual_demand - Added a comment explaining the equation: # Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand - Combined the two separate add_share_to_effects calls into a single call with the combined expression (self.virtual_supply + self.virtual_demand) * imbalance_penalty All 12 bus tests pass with these changes.
1 parent 60a3e65 commit 5fd9ff5

10 files changed

Lines changed: 82 additions & 71 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,18 @@ Use find-and-replace to update your code with the mappings above. The functional
121121
122122
A partial backwards compatibility wrapper would be misleading, so we opted for a clean breaking change.
123123
124+
- `Bus.imbalance_penalty_per_flow_hour` now defaults to `None` (strict balance) instead of `1e5`
125+
124126
### ♻️ Changed
125127
128+
- Renamed `BusModel.excess_input` → `virtual_supply` and `BusModel.excess_output` → `virtual_demand` for clearer semantics
129+
- Renamed `Bus.excess_penalty_per_flow_hour` → `imbalance_penalty_per_flow_hour`
130+
- Renamed `Bus.with_excess` → `allows_imbalance`
131+
126132
### 🗑️ Deprecated
127133
134+
- `Bus.excess_penalty_per_flow_hour` → use `imbalance_penalty_per_flow_hour`
135+
128136
### 🔥 Removed
129137
130138
**Modules removed:**

docs/user-guide/mathematical-notation/effects-penalty-objective.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ Where:
197197
- $s_{l \rightarrow \Phi, \text{per}}$ is the periodic penalty share from element $l$
198198
- $s_{l \rightarrow \Phi, \text{temp}}(\text{t}_i)$ is the temporal penalty share from element $l$ at timestep $\text{t}_i$
199199

200-
**Primary usage:** Penalties occur in [Buses](elements/Bus.md) via the `excess_penalty_per_flow_hour` parameter, which allows nodal imbalances at a high cost, and in time series aggregation to allow period flexibility.
200+
**Primary usage:** Penalties occur in [Buses](elements/Bus.md) via the `imbalance_penalty_per_flow_hour` parameter, which allows nodal imbalances at a high cost, and in time series aggregation to allow period flexibility.
201201

202202
**Key properties:**
203203
- Penalty shares are added via `add_share_to_effects(name, expressions={fx.PENALTY_EFFECT_LABEL: ...}, target='temporal'/'periodic')`

docs/user-guide/mathematical-notation/elements/Bus.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ $$ \label{eq:bus_balance}
55
\sum_{f_\text{out} \in \mathcal{F}_\text{out}} p_{f_\text{out}}(\text{t}_i)
66
$$
77

8-
Optionally, a Bus can have a `excess_penalty_per_flow_hour` parameter, which allows to penaltize the balance for missing or excess flow-rates.
9-
This is usefull as it handles a possible ifeasiblity gently.
8+
Optionally, a Bus can have an `imbalance_penalty_per_flow_hour` parameter, which allows to penalize the balance for missing or excess flow-rates.
9+
This is useful as it handles a possible infeasibility gently.
1010

1111
This changes the balance to
1212

@@ -27,10 +27,10 @@ With:
2727

2828
- $\mathcal{F}_\text{in}$ and $\mathcal{F}_\text{out}$ being the set of all incoming and outgoing flows
2929
- $p_{f_\text{in}}(\text{t}_i)$ and $p_{f_\text{out}}(\text{t}_i)$ being the flow-rate at time $\text{t}_i$ for flow $f_\text{in}$ and $f_\text{out}$, respectively
30-
- $\phi_\text{in}(\text{t}_i)$ and $\phi_\text{out}(\text{t}_i)$ being the missing or excess flow-rate at time $\text{t}_i$, respectively
30+
- $\phi_\text{in}(\text{t}_i)$ and $\phi_\text{out}(\text{t}_i)$ being the virtual supply and virtual demand at time $\text{t}_i$, respectively
3131
- $\text{t}_i$ being the time step
3232
- $s_{b \rightarrow \Phi}(\text{t}_i)$ being the penalty term
33-
- $\text a_{b \rightarrow \Phi}(\text{t}_i)$ being the penalty coefficient (`excess_penalty_per_flow_hour`)
33+
- $\text a_{b \rightarrow \Phi}(\text{t}_i)$ being the penalty coefficient (`imbalance_penalty_per_flow_hour`)
3434

3535
---
3636

examples/02_Complex/complex_example.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# --- Experiment Options ---
1414
# Configure options for testing various parameters and behaviors
1515
check_penalty = False
16-
excess_penalty = 1e5
16+
imbalance_penalty = 1e5
1717
use_chp_with_piecewise_conversion = True
1818
time_indices = None # Define specific time steps for custom optimizations, or use the entire series
1919

@@ -34,9 +34,9 @@
3434
# --- Define Energy Buses ---
3535
# Represent node balances (inputs=outputs) for the different energy carriers (electricity, heat, gas) in the system
3636
flow_system.add_elements(
37-
fx.Bus('Strom', excess_penalty_per_flow_hour=excess_penalty),
38-
fx.Bus('Fernwärme', excess_penalty_per_flow_hour=excess_penalty),
39-
fx.Bus('Gas', excess_penalty_per_flow_hour=excess_penalty),
37+
fx.Bus('Strom', imbalance_penalty_per_flow_hour=imbalance_penalty),
38+
fx.Bus('Fernwärme', imbalance_penalty_per_flow_hour=imbalance_penalty),
39+
fx.Bus('Gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
4040
)
4141

4242
# --- Define Effects ---

examples/03_Optimization_modes/example_optimization_modes.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def get_solutions(optimizations: list, variable: str) -> xr.Dataset:
4141
penalty_of_period_freedom=0,
4242
)
4343
keep_extreme_periods = True
44-
excess_penalty = 1e5 # or set to None if not needed
44+
imbalance_penalty = 1e5 # or set to None if not needed
4545

4646
# Data Import
4747
data_import = pd.read_csv(
@@ -67,10 +67,10 @@ def get_solutions(optimizations: list, variable: str) -> xr.Dataset:
6767

6868
flow_system = fx.FlowSystem(timesteps)
6969
flow_system.add_elements(
70-
fx.Bus('Strom', excess_penalty_per_flow_hour=excess_penalty),
71-
fx.Bus('Fernwärme', excess_penalty_per_flow_hour=excess_penalty),
72-
fx.Bus('Gas', excess_penalty_per_flow_hour=excess_penalty),
73-
fx.Bus('Kohle', excess_penalty_per_flow_hour=excess_penalty),
70+
fx.Bus('Strom', imbalance_penalty_per_flow_hour=imbalance_penalty),
71+
fx.Bus('Fernwärme', imbalance_penalty_per_flow_hour=imbalance_penalty),
72+
fx.Bus('Gas', imbalance_penalty_per_flow_hour=imbalance_penalty),
73+
fx.Bus('Kohle', imbalance_penalty_per_flow_hour=imbalance_penalty),
7474
)
7575

7676
# Effects

flixopt/elements.py

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,9 @@ class Bus(Element):
195195
196196
Args:
197197
label: The label of the Element. Used to identify it in the FlowSystem.
198-
excess_penalty_per_flow_hour: Penalty costs for bus balance violations.
199-
When None, no excess/deficit is allowed (hard constraint). When set to a
200-
value > 0, allows bus imbalances at penalty cost. Default is 1e5 (high penalty).
198+
imbalance_penalty_per_flow_hour: Penalty costs for bus balance violations.
199+
When None (default), no imbalance is allowed (hard constraint). When set to a
200+
value > 0, allows bus imbalances at penalty cost.
201201
meta_data: Used to store additional information. Not used internally but saved
202202
in results. Only use Python native types.
203203
@@ -207,7 +207,7 @@ class Bus(Element):
207207
```python
208208
electricity_bus = Bus(
209209
label='main_electrical_bus',
210-
excess_penalty_per_flow_hour=None, # No imbalance allowed
210+
imbalance_penalty_per_flow_hour=None, # No imbalance allowed
211211
)
212212
```
213213
@@ -216,7 +216,7 @@ class Bus(Element):
216216
```python
217217
heat_network = Bus(
218218
label='district_heating_network',
219-
excess_penalty_per_flow_hour=1000, # €1000/MWh penalty for imbalance
219+
imbalance_penalty_per_flow_hour=1000, # €1000/MWh penalty for imbalance
220220
)
221221
```
222222
@@ -225,14 +225,14 @@ class Bus(Element):
225225
```python
226226
material_hub = Bus(
227227
label='material_processing_hub',
228-
excess_penalty_per_flow_hour=waste_disposal_costs, # Time series
228+
imbalance_penalty_per_flow_hour=waste_disposal_costs, # Time series
229229
)
230230
```
231231
232232
Note:
233-
The bus balance equation enforced is: Σ(inflows) = Σ(outflows) + excess - deficit
233+
The bus balance equation enforced is: Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand
234234
235-
When excess_penalty_per_flow_hour is None, excess and deficit are forced to zero.
235+
When imbalance_penalty_per_flow_hour is None, virtual_supply and virtual_demand are forced to zero.
236236
When a penalty cost is specified, the optimization can choose to violate the
237237
balance if economically beneficial, paying the penalty.
238238
The penalty is added to the objective directly.
@@ -246,11 +246,16 @@ class Bus(Element):
246246
def __init__(
247247
self,
248248
label: str,
249-
excess_penalty_per_flow_hour: Numeric_TPS | None = 1e5,
249+
imbalance_penalty_per_flow_hour: Numeric_TPS | None = None,
250250
meta_data: dict | None = None,
251+
**kwargs,
251252
):
252253
super().__init__(label, meta_data=meta_data)
253-
self.excess_penalty_per_flow_hour = excess_penalty_per_flow_hour
254+
imbalance_penalty_per_flow_hour = self._handle_deprecated_kwarg(
255+
kwargs, 'excess_penalty_per_flow_hour', 'imbalance_penalty_per_flow_hour', imbalance_penalty_per_flow_hour
256+
)
257+
self._validate_kwargs(kwargs)
258+
self.imbalance_penalty_per_flow_hour = imbalance_penalty_per_flow_hour
254259
self.inputs: list[Flow] = []
255260
self.outputs: list[Flow] = []
256261

@@ -267,25 +272,25 @@ def _set_flow_system(self, flow_system) -> None:
267272

268273
def transform_data(self, name_prefix: str = '') -> None:
269274
prefix = '|'.join(filter(None, [name_prefix, self.label_full]))
270-
self.excess_penalty_per_flow_hour = self._fit_coords(
271-
f'{prefix}|excess_penalty_per_flow_hour', self.excess_penalty_per_flow_hour
275+
self.imbalance_penalty_per_flow_hour = self._fit_coords(
276+
f'{prefix}|imbalance_penalty_per_flow_hour', self.imbalance_penalty_per_flow_hour
272277
)
273278

274279
def _plausibility_checks(self) -> None:
275-
if self.excess_penalty_per_flow_hour is not None:
276-
zero_penalty = np.all(np.equal(self.excess_penalty_per_flow_hour, 0))
280+
if self.imbalance_penalty_per_flow_hour is not None:
281+
zero_penalty = np.all(np.equal(self.imbalance_penalty_per_flow_hour, 0))
277282
if zero_penalty:
278283
logger.warning(
279-
f'In Bus {self.label_full}, the excess_penalty_per_flow_hour is 0. Use "None" or a value > 0.'
284+
f'In Bus {self.label_full}, the imbalance_penalty_per_flow_hour is 0. Use "None" or a value > 0.'
280285
)
281286
if len(self.inputs) == 0 and len(self.outputs) == 0:
282287
raise ValueError(
283288
f'Bus "{self.label_full}" has no Flows connected to it. Please remove it from the FlowSystem'
284289
)
285290

286291
@property
287-
def with_excess(self) -> bool:
288-
return False if self.excess_penalty_per_flow_hour is None else True
292+
def allows_imbalance(self) -> bool:
293+
return self.imbalance_penalty_per_flow_hour is not None
289294

290295
def __repr__(self) -> str:
291296
"""Return string representation."""
@@ -856,8 +861,8 @@ class BusModel(ElementModel):
856861
element: Bus # Type hint
857862

858863
def __init__(self, model: FlowSystemModel, element: Bus):
859-
self.excess_input: linopy.Variable | None = None
860-
self.excess_output: linopy.Variable | None = None
864+
self.virtual_supply: linopy.Variable | None = None
865+
self.virtual_demand: linopy.Variable | None = None
861866
super().__init__(model, element)
862867

863868
def _do_modeling(self):
@@ -870,39 +875,38 @@ def _do_modeling(self):
870875
outputs = sum([flow.submodel.flow_rate for flow in self.element.outputs])
871876
eq_bus_balance = self.add_constraints(inputs == outputs, short_name='balance')
872877

873-
# Add excess to balance and penalty if needed
874-
if self.element.with_excess:
875-
excess_penalty = np.multiply(self._model.hours_per_step, self.element.excess_penalty_per_flow_hour)
878+
# Add virtual supply/demand to balance and penalty if needed
879+
if self.element.allows_imbalance:
880+
imbalance_penalty = np.multiply(self._model.hours_per_step, self.element.imbalance_penalty_per_flow_hour)
876881

877-
self.excess_input = self.add_variables(lower=0, coords=self._model.get_coords(), short_name='excess_input')
882+
self.virtual_supply = self.add_variables(
883+
lower=0, coords=self._model.get_coords(), short_name='virtual_supply'
884+
)
878885

879-
self.excess_output = self.add_variables(
880-
lower=0, coords=self._model.get_coords(), short_name='excess_output'
886+
self.virtual_demand = self.add_variables(
887+
lower=0, coords=self._model.get_coords(), short_name='virtual_demand'
881888
)
882889

883-
eq_bus_balance.lhs -= -self.excess_input + self.excess_output
890+
# Σ(inflows) + virtual_supply = Σ(outflows) + virtual_demand
891+
eq_bus_balance.lhs += self.virtual_supply - self.virtual_demand
884892

885893
# Add penalty shares as temporal effects (time-dependent)
886894
from .effects import PENALTY_EFFECT_LABEL
887895

896+
total_imbalance_penalty = (self.virtual_supply + self.virtual_demand) * imbalance_penalty
888897
self._model.effects.add_share_to_effects(
889898
name=self.label_of_element,
890-
expressions={PENALTY_EFFECT_LABEL: self.excess_input * excess_penalty},
891-
target='temporal',
892-
)
893-
self._model.effects.add_share_to_effects(
894-
name=self.label_of_element,
895-
expressions={PENALTY_EFFECT_LABEL: self.excess_output * excess_penalty},
899+
expressions={PENALTY_EFFECT_LABEL: total_imbalance_penalty},
896900
target='temporal',
897901
)
898902

899903
def results_structure(self):
900904
inputs = [flow.submodel.flow_rate.name for flow in self.element.inputs]
901905
outputs = [flow.submodel.flow_rate.name for flow in self.element.outputs]
902-
if self.excess_input is not None:
903-
inputs.append(self.excess_input.name)
904-
if self.excess_output is not None:
905-
outputs.append(self.excess_output.name)
906+
if self.virtual_supply is not None:
907+
inputs.append(self.virtual_supply.name)
908+
if self.virtual_demand is not None:
909+
outputs.append(self.virtual_demand.name)
906910
return {
907911
**super().results_structure(),
908912
'inputs': inputs,

flixopt/flow_system.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class FlowSystem(Interface, CompositeContainerMixin[Element]):
7777
>>>
7878
>>> # Add elements to the system
7979
>>> boiler = fx.Component('Boiler', inputs=[heat_flow], status_parameters=...)
80-
>>> heat_bus = fx.Bus('Heat', excess_penalty_per_flow_hour=1e4)
80+
>>> heat_bus = fx.Bus('Heat', imbalance_penalty_per_flow_hour=1e4)
8181
>>> costs = fx.Effect('costs', is_objective=True, is_standard=True)
8282
>>> flow_system.add_elements(boiler, heat_bus, costs)
8383

flixopt/optimization.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,15 @@ def main_results(self) -> dict[str, int | float | dict]:
309309
'Buses with excess': [
310310
{
311311
bus.label_full: {
312-
'input': bus.submodel.excess_input.solution.sum('time'),
313-
'output': bus.submodel.excess_output.solution.sum('time'),
312+
'virtual_supply': bus.submodel.virtual_supply.solution.sum('time'),
313+
'virtual_demand': bus.submodel.virtual_demand.solution.sum('time'),
314314
}
315315
}
316316
for bus in self.flow_system.buses.values()
317-
if bus.with_excess
317+
if bus.allows_imbalance
318318
and (
319-
bus.submodel.excess_input.solution.sum().item() > 1e-3
320-
or bus.submodel.excess_output.solution.sum().item() > 1e-3
319+
bus.submodel.virtual_supply.solution.sum().item() > 1e-3
320+
or bus.submodel.virtual_demand.solution.sum().item() > 1e-3
321321
)
322322
],
323323
}

tests/test_bus.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class TestBusModel:
99
def test_bus(self, basic_flow_system_linopy_coords, coords_config):
1010
"""Test that flow model constraints are correctly generated."""
1111
flow_system, coords_config = basic_flow_system_linopy_coords, coords_config
12-
bus = fx.Bus('TestBus', excess_penalty_per_flow_hour=None)
12+
bus = fx.Bus('TestBus', imbalance_penalty_per_flow_hour=None)
1313
flow_system.add_elements(
1414
bus,
1515
fx.Sink('WärmelastTest', inputs=[fx.Flow('Q_th_Last', 'TestBus')]),
@@ -28,7 +28,7 @@ def test_bus(self, basic_flow_system_linopy_coords, coords_config):
2828
def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
2929
"""Test that flow model constraints are correctly generated."""
3030
flow_system, coords_config = basic_flow_system_linopy_coords, coords_config
31-
bus = fx.Bus('TestBus')
31+
bus = fx.Bus('TestBus', imbalance_penalty_per_flow_hour=1e5)
3232
flow_system.add_elements(
3333
bus,
3434
fx.Sink('WärmelastTest', inputs=[fx.Flow('Q_th_Last', 'TestBus')]),
@@ -37,26 +37,26 @@ def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
3737
model = create_linopy_model(flow_system)
3838

3939
assert set(bus.submodel.variables) == {
40-
'TestBus|excess_input',
41-
'TestBus|excess_output',
40+
'TestBus|virtual_supply',
41+
'TestBus|virtual_demand',
4242
'WärmelastTest(Q_th_Last)|flow_rate',
4343
'GastarifTest(Q_Gas)|flow_rate',
4444
}
4545
assert set(bus.submodel.constraints) == {'TestBus|balance'}
4646

4747
assert_var_equal(
48-
model.variables['TestBus|excess_input'], model.add_variables(lower=0, coords=model.get_coords())
48+
model.variables['TestBus|virtual_supply'], model.add_variables(lower=0, coords=model.get_coords())
4949
)
5050
assert_var_equal(
51-
model.variables['TestBus|excess_output'], model.add_variables(lower=0, coords=model.get_coords())
51+
model.variables['TestBus|virtual_demand'], model.add_variables(lower=0, coords=model.get_coords())
5252
)
5353

5454
assert_conequal(
5555
model.constraints['TestBus|balance'],
5656
model.variables['GastarifTest(Q_Gas)|flow_rate']
5757
- model.variables['WärmelastTest(Q_th_Last)|flow_rate']
58-
+ model.variables['TestBus|excess_input']
59-
- model.variables['TestBus|excess_output']
58+
+ model.variables['TestBus|virtual_supply']
59+
- model.variables['TestBus|virtual_demand']
6060
== 0,
6161
)
6262

@@ -65,8 +65,7 @@ def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
6565
assert 'TestBus->Penalty(temporal)' in model.constraints
6666
assert 'TestBus->Penalty(temporal)' in model.variables
6767

68-
# The penalty share should equal the excess times the penalty cost
69-
# Note: Each excess (input and output) creates its own share constraint, so we have two
68+
# The penalty share should equal the imbalance (virtual_supply + virtual_demand) times the penalty cost
7069
# Let's verify the total penalty contribution by checking the effect's temporal model
7170
penalty_effect = flow_system.effects.penalty_effect
7271
assert penalty_effect.submodel is not None
@@ -75,14 +74,14 @@ def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
7574
assert_conequal(
7675
model.constraints['TestBus->Penalty(temporal)'],
7776
model.variables['TestBus->Penalty(temporal)']
78-
== model.variables['TestBus|excess_input'] * 1e5 * model.hours_per_step
79-
+ model.variables['TestBus|excess_output'] * 1e5 * model.hours_per_step,
77+
== model.variables['TestBus|virtual_supply'] * 1e5 * model.hours_per_step
78+
+ model.variables['TestBus|virtual_demand'] * 1e5 * model.hours_per_step,
8079
)
8180

8281
def test_bus_with_coords(self, basic_flow_system_linopy_coords, coords_config):
8382
"""Test bus behavior across different coordinate configurations."""
8483
flow_system, coords_config = basic_flow_system_linopy_coords, coords_config
85-
bus = fx.Bus('TestBus', excess_penalty_per_flow_hour=None)
84+
bus = fx.Bus('TestBus', imbalance_penalty_per_flow_hour=None)
8685
flow_system.add_elements(
8786
bus,
8887
fx.Sink('WärmelastTest', inputs=[fx.Flow('Q_th_Last', 'TestBus')]),

tests/test_functional.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ def flow_system_base(timesteps: pd.DatetimeIndex) -> fx.FlowSystem:
6666

6767
flow_system = fx.FlowSystem(timesteps)
6868
flow_system.add_elements(
69-
fx.Bus('Fernwärme', excess_penalty_per_flow_hour=None),
70-
fx.Bus('Gas', excess_penalty_per_flow_hour=None),
69+
fx.Bus('Fernwärme', imbalance_penalty_per_flow_hour=None),
70+
fx.Bus('Gas', imbalance_penalty_per_flow_hour=None),
7171
)
7272
flow_system.add_elements(fx.Effect('costs', '€', 'Kosten', is_standard=True, is_objective=True))
7373
flow_system.add_elements(

0 commit comments

Comments
 (0)