Skip to content

Commit ce7f2bb

Browse files
authored
Feature/rename investparameter optional to mandatory (#358)
* Change .optional to .mandatory * Change .optional to .mandatory * Remove not needed properties
1 parent 6452f28 commit ce7f2bb

3 files changed

Lines changed: 35 additions & 18 deletions

File tree

flixopt/elements.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -486,11 +486,6 @@ def size_is_fixed(self) -> bool:
486486
# Wenn kein InvestParameters existiert --> True; Wenn Investparameter, den Wert davon nehmen
487487
return False if (isinstance(self.size, InvestParameters) and self.size.fixed_size is None) else True
488488

489-
@property
490-
def invest_is_optional(self) -> bool:
491-
# Wenn kein InvestParameters existiert: # Investment ist nicht optional -> Keine Variable --> False
492-
return False if (isinstance(self.size, InvestParameters) and not self.size.optional) else True
493-
494489

495490
class FlowModel(ElementModel):
496491
def __init__(self, model: SystemModel, element: Flow):
@@ -650,7 +645,7 @@ def flow_rate_lower_bound(self) -> NumericData:
650645
if self.element.on_off_parameters is not None:
651646
return 0
652647
if isinstance(self.element.size, InvestParameters):
653-
if self.element.size.optional:
648+
if not self.element.size.mandatory:
654649
return 0
655650
return self.flow_rate_lower_bound_relative * self.element.size.minimum_size
656651
return self.flow_rate_lower_bound_relative * self.element.size

flixopt/features.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(
4646
self.parameters = parameters
4747

4848
def do_modeling(self):
49-
if self.parameters.fixed_size and not self.parameters.optional:
49+
if self.parameters.fixed_size and self.parameters.mandatory:
5050
self.size = self.add(
5151
self._model.add_variables(
5252
lower=self.parameters.fixed_size, upper=self.parameters.fixed_size, name=f'{self.label_full}|size'
@@ -56,15 +56,15 @@ def do_modeling(self):
5656
else:
5757
self.size = self.add(
5858
self._model.add_variables(
59-
lower=0 if self.parameters.optional else self.parameters.minimum_size,
59+
lower=0 if not self.parameters.mandatory else self.parameters.minimum_size,
6060
upper=self.parameters.maximum_size,
6161
name=f'{self.label_full}|size',
6262
),
6363
'size',
6464
)
6565

66-
# Optional
67-
if self.parameters.optional:
66+
# Optional (not mandatory)
67+
if not self.parameters.mandatory:
6868
self.is_invested = self.add(
6969
self._model.add_variables(binary=True, name=f'{self.label_full}|is_invested'), 'is_invested'
7070
)
@@ -89,7 +89,7 @@ def _create_shares(self):
8989
target='invest',
9090
)
9191

92-
if self.parameters.divest_effects != {} and self.parameters.optional:
92+
if self.parameters.divest_effects != {} and not self.parameters.mandatory:
9393
# share: divest_effects - isInvested * divest_effects
9494
self._model.effects.add_share_to_effects(
9595
name=self.label_of_element,

flixopt/interface.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
import logging
9+
import warnings
910
from typing import TYPE_CHECKING
1011

1112
from .config import CONFIG
@@ -655,9 +656,10 @@ class InvestParameters(Interface):
655656
maximum_size: Upper bound for continuous sizing decisions. Defaults to a large
656657
value (CONFIG.modeling.BIG) representing unlimited capacity.
657658
Ignored when fixed_size is specified.
658-
optional: Controls whether investment is required. When True (default),
659-
optimization can choose not to invest. When False, forces investment
659+
mandatory: Controls whether investment is required. When True, forces investment
660660
to occur (useful for mandatory upgrades or replacement decisions).
661+
When False (default), optimization can choose not to invest.
662+
optional: DEPRECATED. Use `mandatory` instead. Opposite of `mandatory`.
661663
fix_effects: Fixed costs incurred once if investment is made, regardless
662664
of size. Dictionary mapping effect names to values
663665
(e.g., {'cost': 10000, 'CO2_construction': 500}).
@@ -687,7 +689,7 @@ class InvestParameters(Interface):
687689
```python
688690
solar_investment = InvestParameters(
689691
fixed_size=100, # 100 kW system (binary decision)
690-
optional=True,
692+
mandatory=False, # Investment is optional
691693
fix_effects={
692694
'cost': 25000, # Installation and permitting costs
693695
'CO2': -50000, # Avoided emissions over lifetime
@@ -705,7 +707,7 @@ class InvestParameters(Interface):
705707
battery_investment = InvestParameters(
706708
minimum_size=10, # Minimum viable system size (kWh)
707709
maximum_size=1000, # Maximum installable capacity
708-
optional=True,
710+
mandatory=False, # Investment is optional
709711
fix_effects={
710712
'cost': 5000, # Grid connection and control system
711713
'installation_time': 2, # Days for fixed components
@@ -737,7 +739,7 @@ class InvestParameters(Interface):
737739
boiler_replacement = InvestParameters(
738740
minimum_size=50,
739741
maximum_size=200,
740-
optional=True, # Can choose not to replace
742+
mandatory=False, # Can choose not to replace
741743
fix_effects={
742744
'cost': 15000, # Installation costs
743745
'disruption': 3, # Days of downtime
@@ -821,26 +823,46 @@ def __init__(
821823
fixed_size: int | float | None = None,
822824
minimum_size: int | float | None = None,
823825
maximum_size: int | float | None = None,
824-
optional: bool = True, # Investition ist weglassbar
826+
mandatory: bool = False,
825827
fix_effects: EffectValuesUserScalar | None = None,
826828
specific_effects: EffectValuesUserScalar | None = None, # costs per Flow-Unit/Storage-Size/...
827829
piecewise_effects: PiecewiseEffects | None = None,
828830
divest_effects: EffectValuesUserScalar | None = None,
831+
# Backwards compatibility - deprecated parameter
832+
optional: bool | None = None,
829833
):
830834
self.fix_effects: EffectValuesUserScalar = fix_effects or {}
831835
self.divest_effects: EffectValuesUserScalar = divest_effects or {}
832836
self.fixed_size = fixed_size
833-
self.optional = optional
834837
self.specific_effects: EffectValuesUserScalar = specific_effects or {}
835838
self.piecewise_effects = piecewise_effects
836839
self._minimum_size = minimum_size if minimum_size is not None else CONFIG.modeling.EPSILON
837840
self._maximum_size = maximum_size if maximum_size is not None else CONFIG.modeling.BIG # default maximum
841+
self.mandatory = mandatory
842+
843+
# Handle backwards compatibility for optional parameter
844+
if optional is not None:
845+
self.optional = optional
838846

839847
def transform_data(self, flow_system: FlowSystem):
840848
self.fix_effects = flow_system.effects.create_effect_values_dict(self.fix_effects)
841849
self.divest_effects = flow_system.effects.create_effect_values_dict(self.divest_effects)
842850
self.specific_effects = flow_system.effects.create_effect_values_dict(self.specific_effects)
843851

852+
@property
853+
def optional(self) -> bool:
854+
"""DEPRECATED: Use 'mandatory' property instead. Returns the opposite of 'mandatory'."""
855+
import warnings
856+
857+
warnings.warn("Property 'optional' is deprecated. Use 'mandatory' instead.", DeprecationWarning, stacklevel=2)
858+
return not self.mandatory
859+
860+
@optional.setter
861+
def optional(self, value: bool):
862+
"""DEPRECATED: Use 'mandatory' property instead. Sets the opposite of the given value to 'mandatory'."""
863+
warnings.warn("Property 'optional' is deprecated. Use 'mandatory' instead.", DeprecationWarning, stacklevel=2)
864+
self.mandatory = not value
865+
844866
@property
845867
def minimum_size(self):
846868
return self.fixed_size or self._minimum_size

0 commit comments

Comments
 (0)