Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Storage Investment #33

Merged
merged 21 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 80 additions & 44 deletions src/oemof/tabular/facades.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,46 +98,69 @@ def _nominal_value(self):
return self.capacity

def _investment(self):
if self.expandable is True:
if self.capacity_cost is None:
msg = (
"If you set `expandable`to True you need to set "
"attribute `capacity_cost` of component {}!"
if not self.expandable:
self.investment = None
return self.investment
if self.capacity_cost is None:
msg = (
"If you set `expandable`to True you need to set "
"attribute `capacity_cost` of component {}!"
)
raise ValueError(msg.format(self.label))
if isinstance(self, GenericStorage):
if self.storage_capacity_cost is not None:
self.investment = Investment(
ep_costs=self.storage_capacity_cost,
maximum=self._get_maximum_additional_invest(
"storage_capacity_potential", "storage_capacity"
),
minimum=getattr(
self, "minimum_storage_capacity", 0
),
existing=getattr(self, "storage_capacity", 0),
)
raise ValueError(msg.format(self.label))
else:
if isinstance(self, GenericStorage):
if self.storage_capacity_cost is not None:
self.investment = Investment(
ep_costs=self.storage_capacity_cost,
maximum=getattr(
self,
"storage_capacity_potential",
float("+inf"),
),
minimum=getattr(
self, "minimum_storage_capacity", 0
),
existing=getattr(self, "storage_capacity", 0),
)
else:
self.investment = Investment()
else:
self.investment = Investment(
ep_costs=self.capacity_cost,
maximum=getattr(
self, "capacity_potential", float("+inf")
),
minimum=getattr(
self, "capacity_minimum", 0
),
existing=getattr(self, "capacity", 0),
)
self.investment = Investment()
else:
self.investment = None

self.investment = Investment(
ep_costs=self.capacity_cost,
maximum=self._get_maximum_additional_invest(
"capacity_potential", "capacity"
),
minimum=getattr(
self, "capacity_minimum", 0
),
existing=getattr(self, "capacity", 0),
)
return self.investment

def _get_maximum_additional_invest(self, attr_potential, attr_existing):
r"""
Calculates maximum additional investment by
substracting existing from potential.

Throws an error if existing is larger than potential.
"""
_potential = getattr(
self,
attr_potential,
float("+inf"),
)
_existing = getattr(
self,
attr_existing,
0,
)

maximum = _potential - _existing

if maximum < 0:
raise ValueError(
f"Existing {attr_existing}={_existing} is larger"
f" than {attr_potential}={_potential}.")

return maximum

def update(self):
self.build_solph_components()

Expand Down Expand Up @@ -374,7 +397,9 @@ def __init__(self, *args, **kwargs):

self.capacity = kwargs.get("capacity")

self.capacity_potential = kwargs.get("capacity_potential")
self.capacity_potential = kwargs.get(
"capacity_potential", float("+inf")
)

self.marginal_cost = kwargs.get("marginal_cost", 0)

Expand Down Expand Up @@ -496,7 +521,10 @@ def __init__(self, *args, **kwargs):

self.capacity = kwargs.get("capacity")

self.capacity_potential = kwargs.get("capacity_potential")
self.capacity_potential = kwargs.get(
"capacity_potential",
float("+inf")
)

self.capacity_minimum = kwargs.get("capacity_minimum")

Expand Down Expand Up @@ -931,7 +959,10 @@ def __init__(self, *args, **kwargs):

self.carrier_cost = kwargs.get("carrier_cost", 0)

self.capacity_potential = kwargs.get("capacity_potential")
self.capacity_potential = kwargs.get(
"capacity_potential",
float("+inf")
)

self.capacity_minimum = kwargs.get("capacity_minimum")

Expand Down Expand Up @@ -995,7 +1026,7 @@ class HeatPump(Transformer, Facade):
expandable: boolean or numeric (binary)
True, if capacity can be expanded within optimization. Default: False.
capacity_potential: numeric
Maximum invest capacity in unit of output capacity.
Maximum invest capacity in unit of output capacity. Default: +inf.
low_temperature_parameters: dict (optional)
Set parameters on the input edge of the heat pump unit
(see oemof.solph for more information on possible parameters)
Expand Down Expand Up @@ -1068,7 +1099,10 @@ def __init__(self, *args, **kwargs):

self.expandable = bool(kwargs.get("expandable", False))

self.capacity_potential = kwargs.get("capacity_potential")
self.capacity_potential = kwargs.get(
"capacity_potential",
float("+inf")
)

self.low_temperature_parameters = kwargs.get(
"low_temperature_parameters", {}
Expand Down Expand Up @@ -1202,9 +1236,9 @@ class Storage(GenericStorage, Facade):
expandable: boolean
True, if capacity can be expanded within optimization. Default: False.
storage_capacity_potential: numeric
Potential of the investment for storage capacity in MWh
Potential of the investment for storage capacity in MWh. Default: +inf.
capacity_potential: numeric
Potential of the investment for capacity in MW
Potential of the investment for capacity in MW. Default: +inf.
input_parameters: dict (optional)
Set parameters on the input edge of the storage (see oemof.solph for
more information on possible parameters)
Expand Down Expand Up @@ -1320,14 +1354,16 @@ def build_solph_components(self):
fi = Flow(
investment=Investment(
ep_costs=self.capacity_cost,
maximum=self.capacity_potential,
maximum=self._get_maximum_additional_invest(
"capacity_potential", "capacity"
),
existing=self.capacity,
),
**self.input_parameters
)
# set investment, but no costs (as relation input / output = 1)
fo = Flow(
investment=Investment(),
investment=Investment(existing=self.capacity),
variable_costs=self.marginal_cost,
**self.output_parameters
)
Expand Down
123 changes: 123 additions & 0 deletions tests/_files/lp_files/storage_investment_brown_field.lp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
\* Source Pyomo model name=Model *\

min
objective:
+1300 GenericInvestmentStorageBlock_invest(storage)
+240 InvestmentFlow_invest(electricity_storage)

s.t.

c_e_Bus_balance(electricity_0)_:
-1 flow(electricity_storage_0)
+1 flow(storage_electricity_0)
= 0

c_e_Bus_balance(electricity_1)_:
-1 flow(electricity_storage_1)
+1 flow(storage_electricity_1)
= 0

c_e_Bus_balance(electricity_2)_:
-1 flow(electricity_storage_2)
+1 flow(storage_electricity_2)
= 0

c_u_InvestmentFlow_max(electricity_storage_0)_:
-1 InvestmentFlow_invest(electricity_storage)
+1 flow(electricity_storage_0)
<= 1

c_u_InvestmentFlow_max(electricity_storage_1)_:
-1 InvestmentFlow_invest(electricity_storage)
+1 flow(electricity_storage_1)
<= 1

c_u_InvestmentFlow_max(electricity_storage_2)_:
-1 InvestmentFlow_invest(electricity_storage)
+1 flow(electricity_storage_2)
<= 1

c_u_InvestmentFlow_max(storage_electricity_0)_:
-1 InvestmentFlow_invest(storage_electricity)
+1 flow(storage_electricity_0)
<= 1

c_u_InvestmentFlow_max(storage_electricity_1)_:
-1 InvestmentFlow_invest(storage_electricity)
+1 flow(storage_electricity_1)
<= 1

c_u_InvestmentFlow_max(storage_electricity_2)_:
-1 InvestmentFlow_invest(storage_electricity)
+1 flow(storage_electricity_2)
<= 1

c_u_GenericInvestmentStorageBlock_init_content_limit(storage)_:
+1 GenericInvestmentStorageBlock_init_content(storage)
-1 GenericInvestmentStorageBlock_invest(storage)
<= 2

c_e_GenericInvestmentStorageBlock_balance_first(storage)_:
-1 GenericInvestmentStorageBlock_init_content(storage)
+1 GenericInvestmentStorageBlock_storage_content(storage_0)
-0.90000000000000002 flow(electricity_storage_0)
+1.1111111111111112 flow(storage_electricity_0)
= 0

c_e_GenericInvestmentStorageBlock_balance(storage_1)_:
-1 GenericInvestmentStorageBlock_storage_content(storage_0)
+1 GenericInvestmentStorageBlock_storage_content(storage_1)
-0.90000000000000002 flow(electricity_storage_1)
+1.1111111111111112 flow(storage_electricity_1)
= 0

c_e_GenericInvestmentStorageBlock_balance(storage_2)_:
-1 GenericInvestmentStorageBlock_storage_content(storage_1)
+1 GenericInvestmentStorageBlock_storage_content(storage_2)
-0.90000000000000002 flow(electricity_storage_2)
+1.1111111111111112 flow(storage_electricity_2)
= 0

c_e_GenericInvestmentStorageBlock_balanced_cstr(storage)_:
-1 GenericInvestmentStorageBlock_init_content(storage)
+1 GenericInvestmentStorageBlock_storage_content(storage_2)
= 0

c_e_GenericInvestmentStorageBlock_power_coupled(storage)_:
-1 InvestmentFlow_invest(electricity_storage)
+1 InvestmentFlow_invest(storage_electricity)
= 0

c_u_GenericInvestmentStorageBlock_max_storage_content(storage_0)_:
-1 GenericInvestmentStorageBlock_invest(storage)
+1 GenericInvestmentStorageBlock_storage_content(storage_0)
<= 2

c_u_GenericInvestmentStorageBlock_max_storage_content(storage_1)_:
-1 GenericInvestmentStorageBlock_invest(storage)
+1 GenericInvestmentStorageBlock_storage_content(storage_1)
<= 2

c_u_GenericInvestmentStorageBlock_max_storage_content(storage_2)_:
-1 GenericInvestmentStorageBlock_invest(storage)
+1 GenericInvestmentStorageBlock_storage_content(storage_2)
<= 2

c_e_ONE_VAR_CONSTANT:
ONE_VAR_CONSTANT = 1.0

bounds
0 <= flow(electricity_storage_0) <= +inf
0 <= flow(electricity_storage_1) <= +inf
0 <= flow(electricity_storage_2) <= +inf
0 <= flow(storage_electricity_0) <= +inf
0 <= flow(storage_electricity_1) <= +inf
0 <= flow(storage_electricity_2) <= +inf
0 <= InvestmentFlow_invest(electricity_storage) <= 4
0 <= InvestmentFlow_invest(storage_electricity) <= +inf
0 <= GenericInvestmentStorageBlock_storage_content(storage_0) <= +inf
0 <= GenericInvestmentStorageBlock_storage_content(storage_1) <= +inf
0 <= GenericInvestmentStorageBlock_storage_content(storage_2) <= +inf
0 <= GenericInvestmentStorageBlock_invest(storage) <= 8
0 <= GenericInvestmentStorageBlock_init_content(storage) <= +inf
end
Loading