oemof.solph.components¶
Sink¶
solph version of oemof.network.Sink
- class oemof.solph.components._sink.Sink(label=None, inputs=None, custom_attributes=None)[source]¶
Bases:
Sink
A component which is designed for one input flow.
- Parameters:
label (str) – String holding the label of the Sink object. The label of each object must be unique.
Examples
Defining a Sink:
>>> from oemof import solph >>> bel = solph.buses.Bus(label='electricity')
>>> electricity_export = solph.components.Sink( ... label='el_export', ... inputs={bel: solph.flows.Flow()})
Notes
It is theoretically possible to use the Sink object with multiple inputs. However, we strongly recommend using multiple Sink objects instead.
Source¶
solph version of oemof.network.Source
- class oemof.solph.components._source.Source(label=None, outputs=None, custom_attributes=None)[source]¶
Bases:
Source
A component which is designed for one output flow.
- Parameters:
label (str) – String holding the label of the Source object. The label of each object must be unique.
Examples
Defining a Source:
>>> from oemof import solph >>> bel = solph.buses.Bus(label='electricity')
>>> pv_plant = solph.components.Source( ... label='pp_pv', ... outputs={bel: solph.flows.Flow()})
>>> type(pv_plant) <class 'oemof.solph.components._source.Source'>
>>> pv_plant.label 'pp_pv'
>>> str(pv_plant.outputs[bel].output) 'electricity'
Notes
It is theoretically possible to use the Source object with multiple outputs. However, we strongly recommend using multiple Source objects instead.
Converter¶
solph version of oemof.network.Converter including sets, variables, constraints and parts of the objective function for ConverterBlock objects.
- class oemof.solph.components._converter.Converter(label=None, inputs=None, outputs=None, conversion_factors=None, custom_attributes=None)[source]¶
Bases:
Transformer
A linear ConverterBlock object with n inputs and n outputs.
Node object that relates any number of inflow and outflows with conversion factors. Inputs and outputs must be given as dictinaries.
- Parameters:
inputs (dict) – Dictionary with inflows. Keys must be the starting node(s) of the inflow(s).
outputs (dict) – Dictionary with outflows. Keys must be the ending node(s) of the outflow(s).
conversion_factors (dict) – Dictionary containing conversion factors for conversion of each flow. Keys must be the connected nodes (typically Buses). The dictionary values can either be a scalar or an iterable with individual conversion factors for each time step. Default: 1. If no conversion_factor is given for an in- or outflow, the conversion_factor is set to 1.
Examples
Defining an linear converter:
>>> from oemof import solph >>> bgas = solph.buses.Bus(label='natural_gas') >>> bcoal = solph.buses.Bus(label='hard_coal') >>> bel = solph.buses.Bus(label='electricity') >>> bheat = solph.buses.Bus(label='heat')
>>> trsf = solph.components.Converter( ... label='pp_gas_1', ... inputs={bgas: solph.flows.Flow(), bcoal: solph.flows.Flow()}, ... outputs={bel: solph.flows.Flow(), bheat: solph.flows.Flow()}, ... conversion_factors={bel: 0.3, bheat: 0.5, ... bgas: 0.8, bcoal: 0.2}) >>> print(sorted([x[1][5] for x in trsf.conversion_factors.items()])) [0.2, 0.3, 0.5, 0.8]
>>> type(trsf) <class 'oemof.solph.components._converter.Converter'>
>>> sorted([str(i) for i in trsf.inputs]) ['hard_coal', 'natural_gas']
>>> trsf_new = solph.components.Converter( ... label='pp_gas_2', ... inputs={bgas: solph.flows.Flow()}, ... outputs={bel: solph.flows.Flow(), bheat: solph.flows.Flow()}, ... conversion_factors={bel: 0.3, bheat: 0.5}) >>> trsf_new.conversion_factors[bgas][3] 1
Notes
- The following sets, variables, constraints and objective parts are created
- class oemof.solph.components._converter.ConverterBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the linear relation of nodes with type
ConverterBlock
The following sets are created: (-> see basic sets at
Model
)- CONVERTERS
A set with all
Converter
objects.
The following constraints are created:
- Linear relation
om.ConverterBlock.relation[i,o,t]
- \[\begin{split}P_{i}(p, t) \cdot \eta_{o}(t) = P_{o}(p, t) \cdot \eta_{i}(t), \\ \forall p, t \in \textrm{TIMEINDEX}, \\ \forall n \in \textrm{CONVERTERS}, \\ \forall i \in \textrm{INPUTS}, \\ \forall o \in \textrm{OUTPUTS}\end{split}\]
While INPUTS is the set of Bus objects connected with the input of the Transformer and OUPUTS the set of Bus objects connected with the output of the Transformer. The constraint above will be created for all combinations of INPUTS and OUTPUTS for all TIMESTEPS. A Transformer with two inflows and two outflows for one day with an hourly resolution will lead to 96 constraints.
The index :math: n is the index for the Transformer node itself. Therefore, a flow[i, n, p, t] is a flow from the Bus i to the Transformer n at time index p, t.
symbol
attribute
explanation
\(P_{i,n}(p, t)\)
flow[i, n, p, t]
Converter, inflow
\(P_{n,o}(p, t)\)
flow[n, o, p, t]
Converter, outflow
\(\eta_{i}(t)\)
conversion_factor[i, n, t]
Inflow, efficiency
\(\eta_{o}(t)\)
conversion_factor[n, o, t]
Outflow, efficiency
extractionTurbineCHP¶
ExtractionTurbineCHP and associated individual constraints (blocks) and groupings.
- class oemof.solph.components._extraction_turbine_chp.ExtractionTurbineCHP(conversion_factor_full_condensation, label=None, inputs=None, outputs=None, conversion_factors=None, custom_attributes=None)[source]¶
Bases:
Converter
A CHP with an extraction turbine in a linear model. For a more detailled modelling approach providing more options, also see the
GenericCHP
class.One main output flow has to be defined and is tapped by the remaining flow. The conversion factors have to be defined for the maximum tapped flow ( full CHP mode) and for no tapped flow (full condensing mode). Even though, it is possible to limit the variability of the tapped flow, so that the full condensing mode will never be reached.
- Parameters:
conversion_factors (dict) – Dictionary containing conversion factors for conversion of inflow to specified outflow. Keys are output bus objects. The dictionary values can either be a scalar or a sequence with length of time horizon for simulation.
conversion_factor_full_condensation (dict) – The efficiency of the main flow if there is no tapped flow. Only one key is allowed. Use one of the keys of the conversion factors. The key indicates the main flow. The other output flow is the tapped flow.
Notes
- The following sets, variables, constraints and objective parts are created
ExtractionTurbineCHPBlock
Examples
>>> from oemof import solph >>> bel = solph.buses.Bus(label='electricityBus') >>> bth = solph.buses.Bus(label='heatBus') >>> bgas = solph.buses.Bus(label='commodityBus') >>> et_chp = solph.components.ExtractionTurbineCHP( ... label='variable_chp_gas', ... inputs={bgas: solph.flows.Flow(nominal_value=10e10)}, ... outputs={bel: solph.flows.Flow(), bth: solph.flows.Flow()}, ... conversion_factors={bel: 0.3, bth: 0.5}, ... conversion_factor_full_condensation={bel: 0.5})
- class oemof.solph.components._extraction_turbine_chp.ExtractionTurbineCHPBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for all instances of
_ExtractionTurbineCHP
Variables
The following variables are used:
\(\dot H_{Fuel}\)
Fuel input flow, represented in code as flow[i, n, p, t]
\(P_{el}\)
Electric power outflow, represented in code as flow[n, main_output, p, t]
\(\dot Q_{th}\)
Thermal output flow, represented in code as flow[n, tapped_output, p, t]
Parameters
The following parameters are created as attributes of
om.ExtractionTurbineCHP
:\(\eta_{el,woExtr}\)
Electric efficiency without heat extraction, represented in code as conversion_factor_full_condensation[n, t]
\(\eta_{el,maxExtr}\)
Electric efficiency with maximal heat extraction, represented in code as conversion_factors[main_output][n, t]
\(\eta_{th,maxExtr}\)
Thermal efficiency with maximal heat extraction, represented in code as conversion_factors[tapped_output][n, t]
Constraints
The following constraints are created for all instances of
oemof.solph.components.ExtractionTurbineCHP
:\[\begin{split}& (1)\dot H_{Fuel}(t) = \frac{P_{el}(t) + \dot Q_{th}(t) \cdot \beta(t)} {\eta_{el,woExtr}(t)} \\ & (2)P_{el}(t) \geq \dot Q_{th}(t) \cdot C_b\end{split}\]where:
\[\beta(t) = \frac{\eta_{el,woExtr}(t) - \eta_{el,maxExtr}(t)}{\eta_{th,maxExtr}(t)}\]and:
\[C_b = \frac{\eta_{el,maxExtr}(t)}{\eta_{th,maxExtr}(t)}\]The first equation is the result of the relation between the input flow and the two output flows, the second equation stems from how the two output flows relate to each other, and the symbols used are defined as follows (with Variables (V) and Parameters (P)):
symbol
attribute
type
explanation
\(\dot H_{Fuel}\)
flow[i, n, t]
V
fuel input flow
\(P_{el}\)
flow[n, main_output, t]
V
electric power
\(\dot Q_{th}\)
flow[n, tapped_output, t]
V
thermal output
\(\beta\)
main_flow_loss_index[n, t]
P
power loss index
\(\eta_{el,woExtr}\)
conversion_factor_full_condensation[n, t]
P
- electric efficiency
without heat extraction
\(\eta_{el,maxExtr}\)
conversion_factors[main_output][n, t]
P
- electric efficiency
with max heat extraction
\(\eta_{th,maxExtr}\)
conversion_factors[tapped_output][n, t]
P
- thermal efficiency with
maximal heat extraction
- CONSTRAINT_GROUP = True¶
GenericCHP¶
GenericCHP and associated individual constraints (blocks) and groupings.
- class oemof.solph.components._generic_chp.GenericCHP(fuel_input, electrical_output, heat_output, beta, back_pressure, label=None, custom_attributes=None)[source]¶
Bases:
Transformer
Component GenericCHP to model combined heat and power plants.
Can be used to model (combined cycle) extraction or back-pressure turbines and used a mixed-integer linear formulation. Thus, it induces more computational effort than the ExtractionTurbineCHP for the benefit of higher accuracy.
The full set of equations is described in: Mollenhauer, E., Christidis, A. & Tsatsaronis, G. Evaluation of an energy- and exergy-based generic modeling approach of combined heat and power plants Int J Energy Environ Eng (2016) 7: 167. https://doi.org/10.1007/s40095-016-0204-6
For a general understanding of (MI)LP CHP representation, see: Fabricio I. Salgado, P. Short - Term Operation Planning on Cogeneration Systems: A Survey Electric Power Systems Research (2007) Electric Power Systems Research Volume 78, Issue 5, May 2008, Pages 835-848 https://doi.org/10.1016/j.epsr.2007.06.001
Note
An adaption for the flow parameter H_L_FG_share_max has been made to set the flue gas losses at maximum heat extraction H_L_FG_max as share of the fuel flow H_F e.g. for combined cycle extraction turbines.
The flow parameter H_L_FG_share_min can be used to set the flue gas losses at minimum heat extraction H_L_FG_min as share of the fuel flow H_F e.g. for motoric CHPs.
The boolean component parameter back_pressure can be set to model back-pressure characteristics.
Also have a look at the examples on how to use it.
- Parameters:
fuel_input (dict) – Dictionary with key-value-pair of oemof.solph.Bus and oemof.solph.Flow objects for the fuel input.
electrical_output (dict) – Dictionary with key-value-pair of oemof.solph.Bus and oemof.solph.Flow objects for the electrical output. Related parameters like P_max_woDH are passed as attributes of the oemof.Flow object.
heat_output (dict) – Dictionary with key-value-pair of oemof.solph.Bus and oemof.solph.Flow objects for the heat output. Related parameters like Q_CW_min are passed as attributes of the oemof.Flow object.
beta (list of numerical values) – beta values in same dimension as all other parameters (length of optimization period).
back_pressure (boolean) – Flag to use back-pressure characteristics. Set to True and Q_CW_min to zero for back-pressure turbines. See paper above for more information.
Note
- The following sets, variables, constraints and objective parts are created
Examples
>>> from oemof import solph >>> bel = solph.buses.Bus(label='electricityBus') >>> bth = solph.buses.Bus(label='heatBus') >>> bgas = solph.buses.Bus(label='commodityBus') >>> ccet = solph.components.GenericCHP( ... label='combined_cycle_extraction_turbine', ... fuel_input={bgas: solph.flows.Flow( ... custom_attributes={"H_L_FG_share_max": [0.183]})}, ... electrical_output={bel: solph.flows.Flow( ... custom_attributes={ ... "P_max_woDH": [155.946], ... "P_min_woDH": [68.787], ... "Eta_el_max_woDH": [0.525], ... "Eta_el_min_woDH": [0.444], ... })}, ... heat_output={bth: solph.flows.Flow( ... custom_attributes={"Q_CW_min": [10.552]})}, ... beta=[0.122], back_pressure=False) >>> type(ccet) <class 'oemof.solph.components._generic_chp.GenericCHP'>
- property alphas¶
Compute or return the _alphas attribute.
- class oemof.solph.components._generic_chp.GenericCHPBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the relation of the \(n\) nodes with type class:.GenericCHP.
The following constraints are created:
\[\begin{split}& (1)\qquad \dot{H}_F(t) = fuel\ input \\ & (2)\qquad \dot{Q}(t) = heat\ output \\ & (3)\qquad P_{el}(t) = power\ output\\ & (4)\qquad \dot{H}_F(t) = \alpha_0(t) \cdot Y(t) + \alpha_1(t) \cdot P_{el,woDH}(t)\\ & (5)\qquad \dot{H}_F(t) = \alpha_0(t) \cdot Y(t) + \alpha_1(t) \cdot ( P_{el}(t) + \beta \cdot \dot{Q}(t) )\\ & (6)\qquad \dot{H}_F(t) \leq Y(t) \cdot \frac{P_{el, max, woDH}(t)}{\eta_{el,max,woDH}(t)}\\ & (7)\qquad \dot{H}_F(t) \geq Y(t) \cdot \frac{P_{el, min, woDH}(t)}{\eta_{el,min,woDH}(t)}\\ & (8)\qquad \dot{H}_{L,FG,max}(t) = \dot{H}_F(t) \cdot \dot{H}_{L,FG,sharemax}(t)\\ & (9)\qquad \dot{H}_{L,FG,min}(t) = \dot{H}_F(t) \cdot \dot{H}_{L,FG,sharemin}(t)\\ & (10)\qquad P_{el}(t) + \dot{Q}(t) + \dot{H}_{L,FG,max}(t) + \dot{Q}_{CW, min}(t) \cdot Y(t) = / \leq \dot{H}_F(t)\\\end{split}\]where \(= / \leq\) depends on the CHP being back pressure or not.
The coefficients \(\alpha_0\) and \(\alpha_1\) can be determined given the efficiencies maximal/minimal load:
\[\begin{split}& \eta_{el,max,woDH}(t) = \frac{P_{el,max,woDH}(t)}{\alpha_0(t) \cdot Y(t) + \alpha_1(t) \cdot P_{el,max,woDH}(t)}\\ & \eta_{el,min,woDH}(t) = \frac{P_{el,min,woDH}(t)}{\alpha_0(t) \cdot Y(t) + \alpha_1(t) \cdot P_{el,min,woDH}(t)}\\\end{split}\]For the attribute \(\dot{H}_{L,FG,min}\) being not None, e.g. for a motoric CHP, the following is created:
Constraint:
\[\begin{split}& (11)\qquad P_{el}(t) + \dot{Q}(t) + \dot{H}_{L,FG,min}(t) + \dot{Q}_{CW, min}(t) \cdot Y(t) \geq \dot{H}_F(t)\\[10pt]\end{split}\]The symbols used are defined as follows (with Variables (V) and Parameters (P)):
math. symbol
attribute
type
explanation
\(\dot{H}_{F}\)
H_F[n,t]
V
input of enthalpy through fuel input
\(P_{el}\)
P[n,t]
V
provided electric power
\(P_{el,woDH}\)
P_woDH[n,t]
V
electric power without district heating
\(P_{el,min,woDH}\)
P_min_woDH[n,t]
P
min. electric power without district heating
\(P_{el,max,woDH}\)
P_max_woDH[n,t]
P
max. electric power without district heating
\(\dot{Q}\)
Q[n,t]
V
provided heat
\(\dot{Q}_{CW, min}\)
Q_CW_min[n,t]
P
minimal therm. condenser load to cooling water
\(\dot{H}_{L,FG,min}\)
H_L_FG_min[n,t]
V
flue gas enthalpy loss at min heat extraction
\(\dot{H}_{L,FG,max}\)
H_L_FG_max[n,t]
V
flue gas enthalpy loss at max heat extraction
\(\dot{H}_{L,FG,sharemin}\)
H_L_FG_share_min[n,t]
P
share of flue gas loss at min heat extraction
\(\dot{H}_{L,FG,sharemax}\)
H_L_FG_share_max[n,t]
P
share of flue gas loss at max heat extraction
\(Y\)
Y[n,t]
V
status variable on/off
\(\alpha_0\)
n.alphas[0][n,t]
P
coefficient describing efficiency
\(\alpha_1\)
n.alphas[1][n,t]
P
coefficient describing efficiency
\(\beta\)
beta[n,t]
P
power loss index
\(\eta_{el,min,woDH}\)
Eta_el_min_woDH[n,t]
P
el. eff. at min. fuel flow w/o distr. heating
\(\eta_{el,max,woDH}\)
Eta_el_max_woDH[n,t]
P
el. eff. at max. fuel flow w/o distr. heating
- CONSTRAINT_GROUP = True¶
GenericStorage¶
GenericStorage and associated individual constraints (blocks) and groupings.
- class oemof.solph.components._generic_storage.GenericInvestmentStorageBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for all storages with
Investment
being not None. SeeInvestment
for all parameters of the Investment class.Variables
All Storages are indexed by \(n\) (denoting the respective storage unit), which is omitted in the following for the sake of convenience. The following variables are created as attributes of
om.GenericInvestmentStorageBlock
:\(P_i(p, t)\)
Inflow of the storage (created in
oemof.solph.models.BaseModel
).\(P_o(p, t)\)
Outflow of the storage (created in
oemof.solph.models.BaseModel
).\(E(t)\)
Current storage content (Absolute level of stored energy).
\(E_{invest}(p)\)
Invested (nominal) capacity of the storage in period p.
\(E_{total}(p)\)
Total installed (nominal) capacity of the storage in period p.
\(E_{old}(p)\)
Old (nominal) capacity of the storage to be decommissioned in period p.
\(E_{old,exo}(p)\)
Exogenous old (nominal) capacity of the storage to be decommissioned in period p; existing capacity reaching its lifetime.
\(E_{old,endo}(p)\)
Endogenous old (nominal) capacity of the storage to be decommissioned in period p; endgenous investments reaching their lifetime.
\(E(-1)\)
Initial storage content (before timestep 0). Not applicable for a multi-period model.
\(b_{invest}(p)\)
Binary variable for the status of the investment, if
nonconvex
is True.
Constraints
The following constraints are created for all investment storages:
Storage balance (Same as for
GenericStorageBlock
)\[\begin{split}E(t) = &E(t-1) \cdot (1 - \beta(t)) ^{\tau(t)/(t_u)} \\ &- \gamma(t)\cdot (E_{total}(p)) \cdot {\tau(t)/(t_u)}\\ &- \delta(t) \cdot {\tau(t)/(t_u)}\\ &- \frac{\dot{E}_o(p, t))}{\eta_o(t)} \cdot \tau(t) + \dot{E}_i(p, t) \cdot \eta_i(t) \cdot \tau(t)\end{split}\]Total storage capacity (p > 0 for multi-period model only)
\[\begin{split}& if \quad p=0:\\ & E_{total}(p) = E_{exist} + E_{invest}(p)\\ &\\ & else:\\ & E_{total}(p) = E_{total}(p-1) + E_{invest}(p) - E_{old}(p)\\ &\\ & \forall p \in \textrm{PERIODS}\end{split}\]Old storage capacity (p > 0 for multi-period model only)
\[\begin{split}& E_{old}(p) = E_{old,exo}(p) + E_{old,end}(p)\\ &\\ & if \quad p=0:\\ & E_{old,end}(p) = 0\\ &\\ & else \quad if \quad l \leq year(p):\\ & E_{old,end}(p) = E_{invest}(p_{comm})\\ &\\ & else:\\ & E_{old,end}(p)\\ &\\ & if \quad p=0:\\ & E_{old,exo}(p) = 0\\ &\\ & else \quad if \quad l - a \leq year(p):\\ & E_{old,exo}(p) = E_{exist} (*)\\ &\\ & else:\\ & E_{old,exo}(p) = 0\\ &\\ & \forall p \in \textrm{PERIODS}\end{split}\]whereby:
(*) is only performed for the first period the condition is True. A decommissioning flag is then set to True to prevent having falsely added old capacity in future periods.
\(year(p)\) is the year corresponding to period p
\(p_{comm}\) is the commissioning period of the storage
Depending on the attribute
nonconvex
, the constraints for the bounds of the decision variable \(E_{invest}(p)\) are different:nonconvex = False
\[\begin{split}& E_{invest, min}(p) \le E_{invest}(p) \le E_{invest, max}(p) \\ & \forall p \in \textrm{PERIODS}\end{split}\]nonconvex = True
\[\begin{split}& E_{invest, min}(p) \cdot b_{invest}(p) \le E_{invest}(p)\\ & E_{invest}(p) \le E_{invest, max}(p) \cdot b_{invest}(p)\\ & \forall p \in \textrm{PERIODS}\end{split}\]The following constraints are created depending on the attributes of the
GenericStorage
:initial_storage_level is None
; not applicable for multi-period modelConstraint for a variable initial storage content:
\[E(-1) \le E_{exist} + E_{invest}(0)\]initial_storage_level is not None
; not applicable for multi-period modelAn initial value for the storage content is given:
\[E(-1) = (E_{invest}(0) + E_{exist}) \cdot c(-1)\]balanced=True
; not applicable for multi-period modelThe energy content of storage of the first and the last timestep are set equal:
\[E(-1) = E(t_{last})\]invest_relation_input_capacity is not None
Connect the invest variables of the storage and the input flow:
\[\begin{split}& P_{i,total}(p) = E_{total}(p) \cdot r_{cap,in} \\ & \forall p \in \textrm{PERIODS}\end{split}\]invest_relation_output_capacity is not None
Connect the invest variables of the storage and the output flow:
\[\begin{split}& P_{o,total}(p) = E_{total}(p) \cdot r_{cap,out}\\ & \forall p \in \textrm{PERIODS}\end{split}\]invest_relation_input_output is not None
Connect the invest variables of the input and the output flow:
\[\begin{split}& P_{i,total}(p) = P_{o,total}(p) \cdot r_{in,out}\\ & \forall p \in \textrm{PERIODS}\end{split}\]max_storage_level
Rule for upper bound constraint for the storage content:
\[\begin{split}& E(t) \leq E_{total}(p) \cdot c_{max}(t)\\ & \forall p, t \in \textrm{TIMEINDEX}\end{split}\]min_storage_level
Rule for lower bound constraint for the storage content:
\[\begin{split}& E(t) \geq E_{total}(p) \cdot c_{min}(t)\\ & \forall p, t \in \textrm{TIMEINDEX}\end{split}\]Objective function
Objective terms for a standard model and a multi-period model differ quite strongly. Besides, the part of the objective function added by the investment storages also depends on whether a convex or nonconvex investment option is selected. The following parts of the objective function are created:
Standard model
nonconvex = False
\[E_{invest}(0) \cdot c_{invest,var}(0)\]nonconvex = True
\[\begin{split}E_{invest}(0) \cdot c_{invest,var}(0) + c_{invest,fix}(0) \cdot b_{invest}(0)\\\end{split}\]
Multi-period model
nonconvex = False
\[\begin{split}& E_{invest}(p) \cdot A(c_{invest,var}(p), l, ir) \cdot l \cdot DF^{-p}\\ & \forall p \in \textrm{PERIODS}\end{split}\]nonconvex = True
\[\begin{split}& E_{invest}(p) \cdot A(c_{invest,var}(p), l, ir) \cdot l \cdot DF^{-p} + c_{invest,fix}(p) \cdot b_{invest}(p)\\ & \forall p \in \textrm{PERIODS}\end{split}\]fixed_costs
not None for investments\[\begin{split}& \sum_{pp=year(p)}^{year(p)+l} E_{invest}(p) \cdot c_{fixed}(pp) \cdot DF^{-pp}) \cdot DF^{-p}\\ & \forall p \in \textrm{PERIODS}\end{split}\]fixed_costs
not None for existing capacity\[\sum_{pp=0}^{l-a} E_{exist} \cdot c_{fixed}(pp) \cdot DF^{-pp}\]
whereby:
\(A(c_{invest,var}(p), l, ir)\) A is the annuity for investment expenses \(c_{invest,var}(p)\) lifetime \(l\) and interest rate \(ir\)
\(DF=(1+dr)\) is the discount factor with discount rate math:dr
The annuity hereby is:
\[A(c_{invest,var}(p), l, ir) = c_{invest,var}(p) \cdot \frac {(1+i)^l \cdot i} {(1+i)^l - 1} \cdot\]It is retrieved, using oemof.tools.economics annuity function. The interest rate is defined as a weighted average costs of capital (wacc) and assumed constant over time.
The overall summed cost expressions for all InvestmentFlowBlock objects can be accessed by
om.GenericInvestmentStorageBlock.investment_costs
,om.GenericInvestmentStorageBlock.fixed_costs
andom.GenericInvestmentStorageBlock.costs
.
Their values after optimization can be retrieved by
om.GenericInvestmentStorageBlock.investment_costs()
,om.GenericInvestmentStorageBlock.period_investment_costs
(yielding a dict keyed by periods); note: this is not a Pyomo expression, but calculated,om.GenericInvestmentStorageBlock.fixed_costs()
andom.GenericInvestmentStorageBlock.costs()
.
List of Variables¶ symbol
attribute
explanation
\(P_i(p, t)\)
flow[i[n], n, p, t]
Inflow of the storage
\(P_o(p, t)\)
flow[n, o[n], p, t]
Outflow of the storage
\(E(t)\)
storage_content[n, t]
Current storage content (current absolute stored energy)
\(E_{invest}(p)\)
invest[n, p]
Invested (nominal) capacity of the storage
\(E_{old}(p)\)
old[n, p]
Old (nominal) capacity of the storageto be decommissioned in period p\(E_{old,exo}(p)\)
old_exo[n, p]
Old (nominal) capacity of the storageto be decommissioned in period pwhich was exogenously given by \(E_{exist}\)\(E_{old,end}(p)\)
old_end[n, p]
Old (nominal) capacity of the storageto be decommissioned in period pwhich was endogenously determined by \(E_{invest}(p_{comm})\)whereby \(p_{comm}\) is the commissioning period\(E(-1)\)
init_cap[n]
Initial storage capacity (before timestep 0)
\(b_{invest}(p)\)
invest_status[i, o, p]
Binary variable for the status of investment
\(P_{i,invest}(p)\)
InvestmentFlowBlock.invest[i[n], n, p]
Invested (nominal) inflow (InvestmentFlowBlock)
\(P_{o,invest}\)
InvestmentFlowBlock.invest[n, o[n]]
Invested (nominal) outflow (InvestmentFlowBlock)
List of Parameters¶ symbol
attribute
explanation
\(E_{exist}\)
flows[i, o].investment.existing
Existing storage capacity
\(E_{invest,min}\)
flows[i, o].investment.minimum
Minimum investment value
\(E_{invest,max}\)
flows[i, o].investment.maximum
Maximum investment value
\(P_{i,exist}\)
flows[i[n], n].investment.existing
Existing inflow capacity
\(P_{o,exist}\)
flows[n, o[n]].investment.existing
Existing outflow capacity
\(c_{invest,var}\)
flows[i, o].investment.ep_costs
Variable investment costs
\(c_{invest,fix}\)
flows[i, o].investment.offset
Fix investment costs
\(c_{fixed}\)
flows[i, o].investment.fixed_costs
Fixed costs; only allowed in multi-period model
\(r_{cap,in}\)
invest_relation_input_capacity
Relation of storage capacity and nominal inflow
\(r_{cap,out}\)
invest_relation_output_capacity
Relation of storage capacity and nominal outflow
\(r_{in,out}\)
invest_relation_input_output
Relation of nominal in- and outflow
\(\beta(t)\)
loss_rate[t]
Fraction of lost energy as share of \(E(t)\) per time unit
\(\gamma(t)\)
fixed_losses_relative[t]
Fixed loss of energy relative to \(E_{invest} + E_{exist}\) per time unit
\(\delta(t)\)
fixed_losses_absolute[t]
Absolute fixed loss of energy per time unit
\(\eta_i(t)\)
inflow_conversion_factor[t]
Conversion factor (i.e. efficiency) when storing energy
\(\eta_o(t)\)
outflow_conversion_factor[t]
Conversion factor when (i.e. efficiency) taking stored energy
\(c(-1)\)
initial_storage_level
Initial relative storage content (before timestep 0)
\(c_{max}\)
flows[i, o].max[t]
Normed maximum value of storage content
\(c_{min}\)
flows[i, o].min[t]
Normed minimum value of storage content
\(l\)
flows[i, o].investment.lifetime
Lifetime for investments in storage capacity
\(a\)
flows[i, o].investment.age
Initial age of existing capacity / energy
\(ir\)
flows[i, o].investment.interest_rate
interest rate for investment
\(\tau(t)\)
Duration of time step
\(t_u\)
Time unit of losses \(\beta(t)\), \(\gamma(t)\), \(\delta(t)\) and timeincrement \(\tau(t)\)
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components._generic_storage.GenericStorage(label=None, inputs=None, outputs=None, nominal_storage_capacity=None, initial_storage_level=None, investment=None, invest_relation_input_output=None, invest_relation_input_capacity=None, invest_relation_output_capacity=None, min_storage_level=0, max_storage_level=1, balanced=True, loss_rate=0, fixed_losses_relative=0, fixed_losses_absolute=0, inflow_conversion_factor=1, outflow_conversion_factor=1, fixed_costs=0, storage_costs=None, lifetime_inflow=None, lifetime_outflow=None, custom_attributes=None)[source]¶
Bases:
Component
Component GenericStorage to model with basic characteristics of storages.
The GenericStorage is designed for one input and one output.
- Parameters:
nominal_storage_capacity (numeric, \(E_{nom}\) or) –
oemof.solph.options.Investment
object Absolute nominal capacity of the storage, fixed value or object describing parameter of investment optimisations.invest_relation_input_capacity (numeric or None, \(r_{cap,in}\)) – Ratio between the investment variable of the input Flow and the investment variable of the storage: \(\dot{E}_{in,invest} = E_{invest} \cdot r_{cap,in}\)
invest_relation_output_capacity (numeric or None, \(r_{cap,out}\)) – Ratio between the investment variable of the output Flow and the investment variable of the storage: \(\dot{E}_{out,invest} = E_{invest} \cdot r_{cap,out}\)
invest_relation_input_output (numeric or None, \(r_{in,out}\)) – Ratio between the investment variable of the output Flow and the investment variable of the input flow. This ratio used to fix the flow investments to each other. Values < 1 set the input flow lower than the output and > 1 will set the input flow higher than the output flow. If None no relation will be set: \(\dot{E}_{in,invest} = \dot{E}_{out,invest} \cdot r_{in,out}\)
initial_storage_level (numeric, \(c(-1)\)) – The relative storage content in the timestep before the first time step of optimization (between 0 and 1).
Note: When investment mode is used in a multi-period model, initial_storage_level is not supported. Storage output is forced to zero until the storage unit is invested in.
balanced (boolean) – Couple storage level of first and last time step. (Total inflow and total outflow are balanced.)
loss_rate (numeric (iterable or scalar)) – The relative loss of the storage content per time unit (e.g. hour).
fixed_losses_relative (numeric (iterable or scalar), \(\gamma(t)\)) – Losses per hour that are independent of the storage content but proportional to nominal storage capacity.
Note: Fixed losses are not supported in investment mode.
fixed_losses_absolute (numeric (iterable or scalar), \(\delta(t)\)) – Losses per hour that are independent of storage content and independent of nominal storage capacity.
Note: Fixed losses are not supported in investment mode.
inflow_conversion_factor (numeric (iterable or scalar), \(\eta_i(t)\)) – The relative conversion factor, i.e. efficiency associated with the inflow of the storage.
outflow_conversion_factor (numeric (iterable or scalar), \(\eta_o(t)\)) – see: inflow_conversion_factor
min_storage_level (numeric (iterable or scalar), \(c_{min}(t)\)) – The normed minimum storage content as fraction of the nominal storage capacity or the capacity that has been invested into (between 0 and 1). To set different values in every time step use a sequence.
max_storage_level (numeric (iterable or scalar), \(c_{max}(t)\)) – see: min_storage_level
investment (
oemof.solph.options.Investment
object) – Object indicating if a nominal_value of the flow is determined by the optimization problem. Note: This will refer all attributes to an investment variable instead of to the nominal_storage_capacity. The nominal_storage_capacity should not be set (or set to None) if an investment object is used.storage_costs (numeric (iterable or scalar), \(c_{storage}(t)\)) – Cost (per energy) for having energy in the storage.
lifetime_inflow (int, \(n_{in}\)) – Determine the lifetime of an inflow; only applicable for multi-period models which can invest in storage capacity and have an invest_relation_input_capacity defined
lifetime_outflow (int, \(n_{in}\)) – Determine the lifetime of an outflow; only applicable for multi-period models which can invest in storage capacity and have an invest_relation_output_capacity defined
Notes
- The following sets, variables, constraints and objective parts are created
GenericStorageBlock
(if no Investment object present)GenericInvestmentStorageBlock
(if Investment object present)
Examples
Basic usage examples of the GenericStorage with a random selection of attributes. See the Flow class for all Flow attributes.
>>> from oemof import solph
>>> my_bus = solph.buses.Bus('my_bus')
>>> my_storage = solph.components.GenericStorage( ... label='storage', ... nominal_storage_capacity=1000, ... inputs={my_bus: solph.flows.Flow(nominal_value=200, variable_costs=10)}, ... outputs={my_bus: solph.flows.Flow(nominal_value=200)}, ... loss_rate=0.01, ... initial_storage_level=0, ... max_storage_level = 0.9, ... inflow_conversion_factor=0.9, ... outflow_conversion_factor=0.93)
>>> my_investment_storage = solph.components.GenericStorage( ... label='storage', ... investment=solph.Investment(ep_costs=50), ... inputs={my_bus: solph.flows.Flow()}, ... outputs={my_bus: solph.flows.Flow()}, ... loss_rate=0.02, ... initial_storage_level=None, ... invest_relation_input_capacity=1/6, ... invest_relation_output_capacity=1/6, ... inflow_conversion_factor=1, ... outflow_conversion_factor=0.8)
- class oemof.solph.components._generic_storage.GenericStorageBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Storage without an
Investment
object.The following sets are created: (-> see basic sets at
Model
)- STORAGES
A set with all
GenericStorage
objects, which do not have aninvestment
of typeInvestment
.- STORAGES_BALANCED
A set of all
GenericStorage
objects, with ‘balanced’ attribute set to True.- STORAGES_WITH_INVEST_FLOW_REL
A set with all
GenericStorage
objects with two investment flows coupled with the ‘invest_relation_input_output’ attribute.
The following variables are created:
- storage_content
Storage content for every storage and timestep. The value for the storage content at the beginning is set by the parameter initial_storage_level or not set if initial_storage_level is None. The variable of storage s and timestep t can be accessed by: om.GenericStorageBlock.storage_content[s, t]
The following constraints are created:
- Set storage_content of last time step to one at t=0 if balanced == True
- \[E(t_{last}) = &E(-1)\]
- Storage balance
om.Storage.balance[n, t]
- \[\begin{split}E(t) = &E(t-1) \cdot (1 - \beta(t)) ^{\tau(t)/(t_u)} \\ &- \gamma(t)\cdot E_{nom} \cdot {\tau(t)/(t_u)}\\ &- \delta(t) \cdot {\tau(t)/(t_u)}\\ &- \frac{\dot{E}_o(p, t)}{\eta_o(t)} \cdot \tau(t) + \dot{E}_i(p, t) \cdot \eta_i(t) \cdot \tau(t)\end{split}\]
- Connect the invest variables of the input and the output flow.
- \[\begin{split}InvestmentFlowBlock.invest(source(n), n, p) + existing = \\ (InvestmentFlowBlock.invest(n, target(n), p) + existing) * \\ invest\_relation\_input\_output(n) \\ \forall n \in \textrm{INVEST\_REL\_IN\_OUT} \\ \forall p \in \textrm{PERIODS}\end{split}\]
symbol
explanation
attribute
\(E(t)\)
energy currently stored
storage_content
\(E_{nom}\)
nominal capacity of the energy storage
nominal_storage_capacity
\(c(-1)\)
state before initial time step
initial_storage_level
\(c_{min}(t)\)
minimum allowed storage
min_storage_level[t]
\(c_{max}(t)\)
maximum allowed storage
max_storage_level[t]
\(\beta(t)\)
fraction of lost energy as share of \(E(t)\) per time unit (e.g. hour)
loss_rate[t]
\(\gamma(t)\)
fixed loss of energy relative to \(E_{nom}\) per time unit (e.g. hour)
fixed_losses_relative[t]
\(\delta(t)\)
absolute fixed loss of energy per time unit (e.g. hour)
fixed_losses_absolute[t]
\(\dot{E}_i(t)\)
energy flowing in
inputs
\(\dot{E}_o(t)\)
energy flowing out
outputs
\(\eta_i(t)\)
conversion factor (i.e. efficiency) when storing energy
inflow_conversion_factor[t]
\(\eta_o(t)\)
conversion factor when (i.e. efficiency) taking stored energy
outflow_conversion_factor[t]
\(\tau(t)\)
duration of time step
\(t_u\)
time unit of losses \(\beta(t)\), \(\gamma(t)\) \(\delta(t)\) and timeincrement \(\tau(t)\)
\(c_{storage}(t)\)
costs of having energy stored
storage_costs
The following parts of the objective function are created:
Standard model
- attr:
storage_costs not 0
- ..math::
sum_{t in textrm{TIMESTEPS}} c_{storage}(t) cdot E(t)
Multi-period model
fixed_costs
not None\[\sum_{p \in \textrm{PERIODS}} E_{nom} \cdot c_{fixed}(p) \cdot DF^{-p}\]
whereby: \(DF=(1+dr)\) is the discount factor with discount rate \(dr\)
- CONSTRAINT_GROUP = True¶
OffsetConverter¶
OffsetConverter and associated individual constraints (blocks) and groupings.
- class oemof.solph.components._offset_converter.OffsetConverter(inputs, outputs, label=None, coefficients=None, custom_attributes=None)[source]¶
Bases:
Transformer
An object with one input and one output and two coefficients to model part load behaviour.
- Parameters:
coefficients (tuple, (\(C_0(t)\), \(C_1(t)\))) – Tuple containing the first two polynomial coefficients i.e. the y-intersection and slope of a linear equation. The tuple values can either be a scalar or a sequence with length of time horizon for simulation.
Notes
- The sets, variables, constraints and objective parts are created
Examples
>>> from oemof import solph >>> bel = solph.buses.Bus(label='bel') >>> bth = solph.buses.Bus(label='bth') >>> ostf = solph.components.OffsetConverter( ... label='ostf', ... inputs={bel: solph.flows.Flow()}, ... outputs={bth: solph.flows.Flow( ... nominal_value=60, min=0.5, max=1.0, ... nonconvex=solph.NonConvex())}, ... coefficients=(20, 0.5)) >>> type(ostf) <class 'oemof.solph.components._offset_converter.OffsetConverter'>
- class oemof.solph.components._offset_converter.OffsetConverterBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the relation of nodes with type
OffsetConverter
The following constraints are created:
\[\begin{split}& P_{in}(p, t) = C_1(t) \cdot P_{out}(p, t) + C_0(t) \cdot P_max(p) \cdot Y(t) \\\end{split}\]The symbols used are defined as follows (with Variables (V) and Parameters (P)):
symbol
attribute
type
explanation
\(P_{out}(t)\)
flow[n,o,p,t]
V
Outflow of converter
\(P_{in}(t)\)
flow[i,n,p,t]
V
Inflow of converter
\(Y(t)\)
V
Binary status variable of nonconvex inflow
\(P_{max}(t)\)
V
Maximum Outflow of converter
\(C_1(t)\)
coefficients[1][n,t]
P
Linear coefficient 1 (slope)
\(C_0(t)\)
coefficients[0][n,t]
P
Linear coefficient 0 (y-intersection)
Note that \(P_{max}(t) \cdot Y(t)\) is merged into one variable, called status_nominal[n, o, p, t].
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components._offset_converter.OffsetTransformer(inputs, outputs, label=None, coefficients=None, custom_attributes=None)[source]¶
Bases:
OffsetConverter
Link¶
Link to connect two Busses.
- class oemof.solph.components._link.Link(label=None, inputs=None, outputs=None, conversion_factors=None, custom_attributes=None)[source]¶
Bases:
Transformer
A Link object with 2 inputs and 2 outputs.
- Parameters:
inputs (dict) – Dictionary with inflows. Keys must be the starting node(s) of the inflow(s).
outputs (dict) – Dictionary with outflows. Keys must be the ending node(s) of the outflow(s).
conversion_factors (dict) – Dictionary containing conversion factors for conversion of each flow. Keys are the connected tuples (input, output) bus objects. The dictionary values can either be a scalar or an iterable with length of time horizon for simulation.
Notes
- The sets, variables, constraints and objective parts are created
Examples
>>> from oemof import solph >>> bel0 = solph.buses.Bus(label="el0") >>> bel1 = solph.buses.Bus(label="el1")
>>> link = solph.components.Link( ... label="transshipment_link", ... inputs={bel0: solph.flows.Flow(nominal_value=4), ... bel1: solph.flows.Flow(nominal_value=2)}, ... outputs={bel0: solph.flows.Flow(), ... bel1: solph.flows.Flow()}, ... conversion_factors={(bel0, bel1): 0.8, (bel1, bel0): 0.9}) >>> print(sorted([x[1][5] for x in link.conversion_factors.items()])) [0.8, 0.9]
>>> type(link) <class 'oemof.solph.components._link.Link'>
>>> sorted([str(i) for i in link.inputs]) ['el0', 'el1']
>>> link.conversion_factors[(bel0, bel1)][3] 0.8
- class oemof.solph.components._link.LinkBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the relation of nodes with type
Link
The following constraints are created:
\[\begin{split}& (1) \qquad P_{\mathrm{in},n}(p, t) = c_n(t) \times P_{\mathrm{out},n}(p, t) \quad \forall t \in T, \forall n in {1,2} \\ &\end{split}\]- CONSTRAINT_GROUP = True¶
experimental.ElectricalLine¶
In-development electrical line components.
- class oemof.solph.flows.experimental._electrical_line.ElectricalLine(**kwargs)[source]¶
Bases:
Flow
An ElectricalLine to be used in linear optimal power flow calculations. based on angle formulation. Check out the Notes below before using this component!
- Parameters:
reactance (float or array of floats) – Reactance of the line to be modelled
Note (This component is experimental. Use it with care.)
Notes
To use this object the connected buses need to be of the type
ElectricalBus
.It does not work together with flows that have set the attr.`nonconvex`, i.e. unit commitment constraints are not possible
Input and output of this component are set equal, therefore just use either only the input or the output to parameterize.
Default attribute min of in/outflows is overwritten by -1 if not set differently by the user
- The following sets, variables, constraints and objective parts are created
ElectricalLineBlock
- class oemof.solph.flows.experimental._electrical_line.ElectricalLineBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the linear relation of nodes with type class:.ElectricalLine
Note: This component is experimental. Use it with care.
The following constraints are created:
- Linear relation
om.ElectricalLine.electrical_flow[n,t]
- \[\begin{split}flow(n, o, p, t) = 1 / reactance(n, t) \cdot voltage\_angle(i(n), t) - voltage\_angle(o(n), t), \\ \forall p, t \in \textrm{TIMEINDEX}, \\ \forall n \in \textrm{ELECTRICAL\_LINES}.\end{split}\]
TODO: Add equate constraint of flows
The following variable are created:
TODO: Add voltage angle variable
TODO: Add fix slack bus voltage angle to zero constraint / bound
TODO: Add tests
- CONSTRAINT_GROUP = True¶
- Linear relation
experimental.GenericCAES¶
In-development generic compressed air energy storage.
- class oemof.solph.components.experimental._generic_caes.GenericCAES(*args, **kwargs)[source]¶
Bases:
Transformer
Component GenericCAES to model arbitrary compressed air energy storages.
The full set of equations is described in: Kaldemeyer, C.; Boysen, C.; Tuschy, I. A Generic Formulation of Compressed Air Energy Storage as Mixed Integer Linear Program – Unit Commitment of Specific Technical Concepts in Arbitrary Market Environments Materials Today: Proceedings 00 (2018) 0000–0000 [currently in review]
- Parameters:
electrical_input (dict) – Dictionary with key-value-pair of oemof.Bus and oemof.Flow object for the electrical input.
fuel_input (dict) – Dictionary with key-value-pair of oemof.Bus and oemof.Flow object for the fuel input.
electrical_output (dict) – Dictionary with key-value-pair of oemof.Bus and oemof.Flow object for the electrical output.
Note (This component is experimental. Use it with care.)
Notes
- The following sets, variables, constraints and objective parts are created
GenericCAES
Examples
>>> from oemof import solph >>> bel = solph.buses.Bus(label='bel') >>> bth = solph.buses.Bus(label='bth') >>> bgas = solph.buses.Bus(label='bgas') >>> # dictionary with parameters for a specific CAES plant >>> concept = { ... 'cav_e_in_b': 0, ... 'cav_e_in_m': 0.6457267578, ... 'cav_e_out_b': 0, ... 'cav_e_out_m': 0.3739636077, ... 'cav_eta_temp': 1.0, ... 'cav_level_max': 211.11, ... 'cmp_p_max_b': 86.0918959849, ... 'cmp_p_max_m': 0.0679999932, ... 'cmp_p_min': 1, ... 'cmp_q_out_b': -19.3996965679, ... 'cmp_q_out_m': 1.1066036114, ... 'cmp_q_tes_share': 0, ... 'exp_p_max_b': 46.1294016678, ... 'exp_p_max_m': 0.2528340303, ... 'exp_p_min': 1, ... 'exp_q_in_b': -2.2073411014, ... 'exp_q_in_m': 1.129249765, ... 'exp_q_tes_share': 0, ... 'tes_eta_temp': 1.0, ... 'tes_level_max': 0.0} >>> # generic compressed air energy storage (caes) plant >>> caes = solph.components.experimental.GenericCAES( ... label='caes', ... electrical_input={bel: solph.flows.Flow()}, ... fuel_input={bgas: solph.flows.Flow()}, ... electrical_output={bel: solph.flows.Flow()}, ... params=concept, fixed_costs=0) >>> type(caes) <class 'oemof.solph.components.experimental._generic_caes.GenericCAES'>
- class oemof.solph.components.experimental._generic_caes.GenericCAESBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for nodes of class:.GenericCAES.
Note: This component is experimental. Use it with care.
The following constraints are created:
\[\begin{split}& (1) \qquad P_{cmp}(t) = electrical\_input (t) \quad \forall t \in T \\ & (2) \qquad P_{cmp\_max}(t) = m_{cmp\_max} \cdot CAS_{fil}(t-1) + b_{cmp\_max} \quad \forall t \in\left[1, t_{max}\right] \\ & (3) \qquad P_{cmp\_max}(t) = b_{cmp\_max} \quad \forall t \notin\left[1, t_{max}\right] \\ & (4) \qquad P_{cmp}(t) \leq P_{cmp\_max}(t) \quad \forall t \in T \\ & (5) \qquad P_{cmp}(t) \geq P_{cmp\_min} \cdot ST_{cmp}(t) \quad \forall t \in T \\ & (6) \qquad P_{cmp}(t) = m_{cmp\_max} \cdot CAS_{fil\_max} + b_{cmp\_max} \cdot ST_{cmp}(t) \quad \forall t \in T \\ & (7) \qquad \dot{Q}_{cmp}(t) = m_{cmp\_q} \cdot P_{cmp}(t) + b_{cmp\_q} \cdot ST_{cmp}(t) \quad \forall t \in T \\ & (8) \qquad \dot{Q}_{cmp}(t) = \dot{Q}_{cmp_out}(t) + \dot{Q}_{tes\_in}(t) \quad \forall t \in T \\ & (9) \qquad r_{cmp\_tes} \cdot\dot{Q}_{cmp\_out}(t) = \left(1-r_{cmp\_tes}\right) \dot{Q}_{tes\_in}(t) \quad \forall t \in T \\ & (10) \quad\; P_{exp}(t) = electrical\_output (t) \quad \forall t \in T \\ & (11) \quad\; P_{exp\_max}(t) = m_{exp\_max} CAS_{fil}(t-1) + b_{exp\_max} \quad \forall t \in\left[1, t_{\max }\right] \\ & (12) \quad\; P_{exp\_max}(t) = b_{exp\_max} \quad \forall t \notin\left[1, t_{\max }\right] \\ & (13) \quad\; P_{exp}(t) \leq P_{exp\_max}(t) \quad \forall t \in T \\ & (14) \quad\; P_{exp}(t) \geq P_{exp\_min}(t) \cdot ST_{exp}(t) \quad \forall t \in T \\ & (15) \quad\; P_{exp}(t) \leq m_{exp\_max} \cdot CAS_{fil\_max} + b_{exp\_max} \cdot ST_{exp}(t) \quad \forall t \in T \\ & (16) \quad\; \dot{Q}_{exp}(t) = m_{exp\_q} \cdot P_{exp}(t) + b_{cxp\_q} \cdot ST_{cxp}(t) \quad \forall t \in T \\ & (17) \quad\; \dot{Q}_{exp\_in}(t) = fuel\_input(t) \quad \forall t \in T \\ & (18) \quad\; \dot{Q}_{exp}(t) = \dot{Q}_{exp\_in}(t) + \dot{Q}_{tes\_out}(t)+\dot{Q}_{cxp\_add}(t) \quad \forall t \in T \\ & (19) \quad\; r_{exp\_tes} \cdot \dot{Q}_{exp\_in}(t) = (1 - r_{exp\_tes})(\dot{Q}_{tes\_out}(t) + \dot{Q}_{exp\_add}(t)) \quad \forall t \in T \\ & (20) \quad\; \dot{E}_{cas\_in}(t) = m_{cas\_in}\cdot P_{cmp}(t) + b_{cas\_in}\cdot ST_{cmp}(t) \quad \forall t \in T \\ & (21) \quad\; \dot{E}_{cas\_out}(t) = m_{cas\_out}\cdot P_{cmp}(t) + b_{cas\_out}\cdot ST_{cmp}(t) \quad \forall t \in T \\ & (22) \quad\; \eta_{cas\_tmp} \cdot CAS_{fil}(t) = CAS_{fil}(t-1) + \tau\left(\dot{E}_{cas\_in}(t) - \dot{E}_{cas\_out}(t)\right) \quad \forall t \in\left[1, t_{max}\right] \\ & (23) \quad\; \eta_{cas\_tmp} \cdot CAS_{fil}(t) = \tau\left(\dot{E}_{cas\_in}(t) - \dot{E}_{cas\_out}(t)\right) \quad \forall t \notin\left[1, t_{max}\right] \\ & (24) \quad\; CAS_{fil}(t) \leq CAS_{fil\_max} \quad \forall t \in T \\ & (25) \quad\; TES_{fil}(t) = TES_{fil}(t-1) + \tau\left(\dot{Q}_{tes\_in}(t) - \dot{Q}_{tes\_out}(t)\right) \quad \forall t \in\left[1, t_{max}\right] \\ & (26) \quad\; TES_{fil}(t) = \tau\left(\dot{Q}_{tes\_in}(t) - \dot{Q}_{tes\_out}(t)\right) \quad \forall t \notin\left[1, t_{max}\right] \\ & (27) \quad\; TES_{fil}(t) \leq TES_{fil\_max} \quad \forall t \in T \\ &\end{split}\]Table: Symbols and attribute names of variables and parameters
Variables (V) and Parameters (P)¶ symbol
attribute
type
explanation
\(ST_{cmp}\)
cmp_st[n,t]
V
Status of compression
\({P}_{cmp}\)
cmp_p[n,t]
V
Compression power
\({P}_{cmp\_max}\)
cmp_p_max[n,t]
V
Max. compression power
\(\dot{Q}_{cmp}\)
cmp_q_out_sum[n,t]
V
Summed heat flow in compression
\(\dot{Q}_{cmp\_out}\)
cmp_q_waste[n,t]
V
Waste heat flow from compression
\(ST_{exp}(t)\)
exp_st[n,t]
V
Status of expansion (binary)
\(P_{exp}(t)\)
exp_p[n,t]
V
Expansion power
\(P_{exp\_max}(t)\)
exp_p_max[n,t]
V
Max. expansion power
\(\dot{Q}_{exp}(t)\)
exp_q_in_sum[n,t]
V
Summed heat flow in expansion
\(\dot{Q}_{exp\_in}(t)\)
exp_q_fuel_in[n,t]
V
Heat (external) flow into expansion
\(\dot{Q}_{exp\_add}(t)\)
exp_q_add_in[n,t]
V
Additional heat flow into expansion
\(CAV_{fil}(t)\)
cav_level[n,t]
V
Filling level if CAE
\(\dot{E}_{cas\_in}(t)\)
cav_e_in[n,t]
V
Exergy flow into CAS
\(\dot{E}_{cas\_out}(t)\)
cav_e_out[n,t]
V
Exergy flow from CAS
\(TES_{fil}(t)\)
tes_level[n,t]
V
Filling level of Thermal Energy Storage (TES)
\(\dot{Q}_{tes\_in}(t)\)
tes_e_in[n,t]
V
Heat flow into TES
\(\dot{Q}_{tes\_out}(t)\)
tes_e_out[n,t]
V
Heat flow from TES
\(b_{cmp\_max}\)
cmp_p_max_b[n,t]
P
Specific y-intersection
\(b_{cmp\_q}\)
cmp_q_out_b[n,t]
P
Specific y-intersection
\(b_{exp\_max}\)
exp_p_max_b[n,t]
P
Specific y-intersection
\(b_{exp\_q}\)
exp_q_in_b[n,t]
P
Specific y-intersection
\(b_{cas\_in}\)
cav_e_in_b[n,t]
P
Specific y-intersection
\(b_{cas\_out}\)
cav_e_out_b[n,t]
P
Specific y-intersection
\(m_{cmp\_max}\)
cmp_p_max_m[n,t]
P
Specific slope
\(m_{cmp\_q}\)
cmp_q_out_m[n,t]
P
Specific slope
\(m_{exp\_max}\)
exp_p_max_m[n,t]
P
Specific slope
\(m_{exp\_q}\)
exp_q_in_m[n,t]
P
Specific slope
\(m_{cas\_in}\)
cav_e_in_m[n,t]
P
Specific slope
\(m_{cas\_out}\)
cav_e_out_m[n,t]
P
Specific slope
\(P_{cmp\_min}\)
cmp_p_min[n,t]
P
Min. compression power
\(r_{cmp\_tes}\)
cmp_q_tes_share[n,t]
P
Ratio between waste heat flow and heat flow into TES
\(r_{exp\_tes}\)
exp_q_tes_share[n,t]
P
Ratio between external heat flow into expansionand heat flows from TES and additional source\(\tau\)
m.timeincrement[n,t]
P
Time interval length
\(TES_{fil\_max}\)
tes_level_max[n,t]
P
Max. filling level of TES
\(CAS_{fil\_max}\)
cav_level_max[n,t]
P
Max. filling level of TES
\(\tau\)
cav_eta_tmp[n,t]
P
Temporal efficiency(loss factor to take intertemporal losses into account)\(electrical\_input\)
flow[list(n.electrical_input.keys())[0], p, n, t]
P
Electr. power input into compression
\(electrical\_output\)
flow[n, list(n.electrical_output.keys())[0], p, t]
P
Electr. power output of expansion
\(fuel\_input\)
flow[list(n.fuel_input.keys())[0], n, p, t]
P
Heat input (external) into Expansion
- CONSTRAINT_GROUP = True¶
experimental.PiecewiseLinearConverter¶
In-development Converter with piecewise linear efficiencies.
- class oemof.solph.components.experimental._piecewise_linear_converter.PiecewiseLinearConverter(*args, **kwargs)[source]¶
Bases:
Transformer
Component to model an energy converter with one input and one output and an arbitrary piecewise linear conversion function.
- Parameters:
in_breakpoints (list) – List containing the domain breakpoints, i.e. the breakpoints for the incoming flow.
conversion_function (func) – The function describing the relation between incoming flow and outgoing flow which is to be approximated.
pw_repn (string) – Choice of piecewise representation that is passed to pyomo.environ.Piecewise
Examples
>>> import oemof.solph as solph
>>> b_gas = solph.buses.Bus(label='biogas') >>> b_el = solph.buses.Bus(label='electricity')
>>> pwltf = solph.components.experimental.PiecewiseLinearConverter( ... label='pwltf', ... inputs={b_gas: solph.flows.Flow( ... nominal_value=100, ... variable_costs=1)}, ... outputs={b_el: solph.flows.Flow()}, ... in_breakpoints=[0,25,50,75,100], ... conversion_function=lambda x: x**2, ... pw_repn='CC')
>>> type(pwltf) <class 'oemof.solph.components.experimental._piecewise_linear_converter.PiecewiseLinearConverter'>
- class oemof.solph.components.experimental._piecewise_linear_converter.PiecewiseLinearConverterBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Block for the relation of nodes with type
PiecewiseLinearConverter
The following constraints are created:
- CONSTRAINT_GROUP = True¶
experimental.SinkDSM¶
Implementation of demand-side management (demand response) which allows for
modeling load shifting and/or shedding of a given baseline demand for a demand response portfolio,
assessing both, a pure dispatch and an investment model and
choosing among different (storage-alike) implementations.
- class oemof.solph.components.experimental._sink_dsm.SinkDSM(demand, capacity_up, capacity_down, approach, label=None, inputs=None, shift_interval=None, delay_time=None, shift_time=None, shed_time=None, max_demand=None, max_capacity_down=None, max_capacity_up=None, cost_dsm_up=0, cost_dsm_down_shift=0, cost_dsm_down_shed=0, efficiency=1, recovery_time_shift=None, recovery_time_shed=None, ActivateYearLimit=False, ActivateDayLimit=False, n_yearLimit_shift=None, n_yearLimit_shed=None, t_dayLimit=None, addition=True, fixes=True, shed_eligibility=True, shift_eligibility=True, fixed_costs=0, investment=None, custom_attributes=None)[source]¶
Bases:
Sink
Demand Side Management implemented as a Sink with flexibility potential to deviate from the baseline demand in upwards or downwards direction.
There are several approaches possible which can be selected:
DIW: Based on the paper by Zerrahn, Alexander and Schill, Wolf-Peter (2015): On the representation of demand-side management in power system models, in: Energy (84), pp. 840-845, 10.1016/j.energy.2015.03.037, accessed 08.01.2021, pp. 842-843.
DLR: Based on the PhD thesis of Gils, Hans Christian (2015): Balancing of Intermittent Renewable Power Generation by Demand Response and Thermal Energy Storage, Stuttgart, http://dx.doi.org/10.18419/opus-6888, accessed 08.01.2021, pp. 67-70.
oemof: Created by Julian Endres. A fairly simple DSM representation which demands the energy balance to be levelled out in fixed cycles
An evaluation of different modeling approaches has been carried out and presented at the INREC 2020. Some of the results are as follows:
DIW: A solid implementation with the tendency of slight overestimization of potentials since a shift_time is not included. It may get computationally expensive due to a high time-interlinkage in constraint formulations.
DLR: An extensive modeling approach for demand response which neither leads to an over- nor underestimization of potentials and balances modeling detail and computation intensity. fixes and addition should both be set to True which is the default value.
oemof: A very computationally efficient approach which only requires the energy balance to be levelled out in certain intervals. If demand response is not at the center of the research and/or parameter availability is limited, this approach should be chosen. Note that approach oemof does allow for load shedding, but does not impose a limit on maximum amount of shedded energy.
SinkDSM adds additional constraints that allow to shift energy in certain time window constrained by capacity_up and capacity_down.
- Parameters:
demand (numeric) – original electrical demand (normalized) For investment modeling, it is advised to use the maximum of the demand timeseries and the cumulated (fixed) infeed time series for normalization, because the balancing potential may be determined by both. Else, underinvestments may occur.
capacity_up (int or iterable) – maximum DSM capacity that may be increased (normalized)
capacity_down (int or iterable) – maximum DSM capacity that may be reduced (normalized)
approach (str, one of ‘oemof’, ‘DIW’, ‘DLR’) – Choose one of the DSM modeling approaches. Read notes about which parameters to be applied for which approach.
oemof :
Simple model in which the load shift must be compensated in a predefined fixed interval (shift_interval is mandatory). Within time windows of the length shift_interval DSM up and down shifts are balanced. For details see
SinkDSMOemofBlock
resp.SinkDSMOemofInvestmentBlock
.DIW :
Sophisticated model based on the formulation by Zerrahn & Schill (2015a). The load shift of the component must be compensated in a predefined delay time (delay_time is mandatory). For details see
SinkDSMDIWBlock
resp.SinkDSMDIWInvestmentBlock
.DLR :
Sophisticated model based on the formulation by Gils (2015). The load shift of the component must be compensated in a predefined delay time (delay_time is mandatory). For details see
SinkDSMDLRBlock
resp.SinkDSMDLRInvestmentBlock
.shift_interval (int) – Only used when approach is set to “oemof”. Otherwise, can be None. It’s the interval in which between \(DSM_{t}^{up}\) and \(DSM_{t}^{down}\) have to be compensated.
delay_time (int or iterable) – Only used when
approach
is set to “DIW” or “DLR”. Otherwise, can be None. Iterable only allowed in case approach “DLR” is used. Length of symmetrical time windows around \(t\) in which \(DSM_{t}^{up}\) and \(DSM_{t,tt}^{down}\) have to be compensated. Note: For approach ‘DLR’, if an integer is passed, an iterable is constructed in order to model flexible delay times. In case an iterable is passed, this will be used directly.shift_time (int) – Only used when approach is set to “DLR”. Duration of a single upwards or downwards shift (half a shifting cycle if there is immediate compensation)
shed_time (int) – Only used when shed_eligibility is set to True. Maximum length of a load shedding process at full capacity (used within energy limit constraint)
max_demand (numeric or iterable) – Maximum demand prior to demand response (per period)
max_capacity_down (numeric) – Maximum capacity eligible for downshifts prior to demand response (used only for dispatch mode)
max_capacity_up (numeric) – Maximum capacity eligible for upshifts prior to demand response (used only for dispatch mode)
cost_dsm_up (float) – Cost per unit of DSM activity that increases the demand
cost_dsm_down_shift (float) – Cost per unit of DSM activity that decreases the demand for load shifting
cost_dsm_down_shed (float) – Cost per unit of DSM activity that decreases the demand for load shedding
efficiency (float) – Efficiency factor for load shifts (between 0 and 1)
recovery_time_shift (int) – Only used when approach is set to “DIW”. Minimum time between the end of one load shifting process and the start of another for load shifting processes
recovery_time_shed (int) – Minimum time between the end of one load shifting process and the start of another for load shedding processes
ActivateYearLimit (boolean) – Only used when approach is set to “DLR”. Control parameter; activates constraints for year limit if set to True
ActivateDayLimit (boolean) – Only used when approach is set to “DLR”. Control parameter; activates constraints for day limit if set to True
n_yearLimit_shift (int) – Only used when approach is set to “DLR”. Maximum number of load shifts at full capacity per year, used to limit the amount of energy shifted per year. Optional parameter that is only needed when ActivateYearLimit is True
n_yearLimit_shed (int) – Only used when approach is set to “DLR”. Maximum number of load sheds at full capacity per year, used to limit the amount of energy shedded per year. Mandatory parameter if load shedding is allowed by setting shed_eligibility to True
t_dayLimit (int) – Only used when approach is set to “DLR”. Maximum duration of load shifts at full capacity per day, used to limit the amount of energy shifted per day. Optional parameter that is only needed when ActivateDayLimit is True
addition (boolean) – Only used when approach is set to “DLR”. Boolean parameter indicating whether or not to include additional constraint (which corresponds to Eq. 10 from Zerrahn and Schill (2015a))
fixes (boolean) – Only used when approach is set to “DLR”. Boolean parameter indicating whether or not to include additional fixes. These comprise prohibiting shifts which cannot be balanced within the optimization timeframe
shed_eligibility (boolean) – Boolean parameter indicating whether unit is eligible for load shedding
shift_eligibility (boolean) – Boolean parameter indicating whether unit is eligible for load shifting
fixed_costs (numeric) – Nominal value of fixed costs (per period)
Note
method has been renamed to approach.
As many constraints and dependencies are created in approach “DIW”, computational cost might be high with a large delay_time and with model of high temporal resolution.
The approach “DLR” preforms better in terms of calculation time, compared to the approach “DIW”.
Using approach “DIW” or “DLR” might result in demand shifts that exceed the specified delay time by activating up and down simultaneously in the time steps between to DSM events. Thus, the purpose of this component is to model demand response portfolios rather than individual demand units.
It’s not recommended to assign cost to the flow that connects
SinkDSM
with a bus. Instead, use cost_dsm_up or cost_dsm_down_shift.Variable costs may be attributed to upshifts, downshifts or both. Costs for shedding may deviate from that for shifting (usually costs for shedding are much larger and equal to the value of lost load).
- class oemof.solph.components.experimental._sink_dsm.SinkDSMDIWBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “DIW” approach
The following constraints are created for approach = “DIW”:
\[\begin{split}& (1) \quad DSM_{t}^{up} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & \\ & (2) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (3) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max} + DSM_{t}^{up} - \sum_{tt=t-L}^{t+L} DSM_{tt,t}^{do, shift} - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (4) \quad DSM_{t}^{up} \cdot \eta = \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do, shift} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (5) \quad DSM_{t}^{up} \leq E_{t}^{up} \cdot E_{up, max} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (6) \quad \sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do, shift} + DSM_{tt}^{do, shed} \leq E_{tt}^{do} \cdot E_{do, max} \\ & \quad \quad \quad \quad \forall tt \in \mathbb{T} \\ & \\ & (7) \quad DSM_{tt}^{up} + \sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do, shift} + DSM_{tt}^{do, shed} \leq max \{ E_{tt}^{up} \cdot E_{up, max}, E_{tt}^{do} \cdot E_{do, max} \} \\ & \quad \quad \quad \quad \forall tt \in \mathbb{T} \\ & \\ & (8) \quad \sum_{tt=t}^{t+R_{shi}-1} DSM_{tt}^{up} \leq E_{t}^{up} \cdot E_{up, max} \cdot L \cdot \Delta t \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (9) \quad \sum_{tt=t}^{t+R_{she}-1} DSM_{tt}^{do, shed} \leq E_{t}^{do} \cdot E_{do, max} \cdot t_{shed} \cdot \Delta t \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]Note
For the sake of readability, the handling of indices is not displayed here. E.g. evaluating a variable for t-L may lead to a negative and therefore infeasible index. This is addressed by limiting the sums to non-negative indices within the model index bounds. Please refer to the constraints implementation themselves.
The following parts of the objective function are created:
\[\begin{split}& DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + \sum_{tt=0}^{|T|} DSM_{tt, t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]Table: Symbols and attribute names of variables and parameters
Variables (V), Parameters (P) and Sets (S)¶ symbol
attribute
type
explanation
\(DSM_{t}^{up}\)
dsm_up[g, t]
V
DSM up shift (additional load) in hour t
\(DSM_{t, tt}^{do, shift}\)
dsm_do_shift[g, t, tt]
V
DSM down shift (less load) in hour ttto compensate for upwards shifts in hour t\(DSM_{t}^{do, shed}\)
dsm_do_shed[g, t]
V
DSM shedded (capacity shedded, i.e. not compensated for)
\(\dot{E}_{t}\)
SinkDSM.inputs
V
Energy flowing in from (electrical) inflow bus
\(L\)
delay_time
P
Maximum delay time for load shift(time until the energy balance has to be levelled out again;roundtrip time of one load shifting cycle, i.e. time windowfor upshift and compensating downshift)\(t_{she}\)
shed_time
P
Maximum time for one load shedding process
\(demand_{t}\)
demand[t]
P
(Electrical) demand series (normalized)
\(demand_{max}\)
max_demand
P
Maximum demand value
\(E_{t}^{do}\)
capacity_down[t]
P
Capacity allowed for a load adjustment downwards(normalized; shifting + shedding)\(E_{t}^{up}\)
capacity_up[t]
P
Capacity allowed for a shift upwards (normalized)
\(E_{do, max}\)
max_capacity_down
P
Maximum capacity allowed for a load adjustment downwards(shifting + shedding)\(E_{up, max}\)
max_capacity_up
P
Maximum capacity allowed for a shift upwards
\(\eta\)
efficiency
P
Efficiency for load shifting processes
\(\mathbb{T}\)
S
Time steps of the model
\(e_{shift}\)
shift_eligibility
P
Boolean parameter indicating if unit can be usedfor load shifting\(e_{shed}\)
shed_eligibility
P
Boolean parameter indicating if unit can be usedfor load shedding\(cost_{t}^{dsm, up}\)
cost_dsm_up[t]
P
Variable costs for an upwards shift
\(cost_{t}^{dsm, do, shift}\)
cost_dsm_down_shift[t]
P
Variable costs for a downwards shift (load shifting)
\(cost_{t}^{dsm, do, shed}\)
cost_dsm_down_shift[t]
P
Variable costs for shedding load
\(\omega_{t}\)
P
Objective weighting of the model for timestep t
\(R_{shi}\)
recovery_time_shift
P
Minimum time between the end of one load shifting processand the start of another\(R_{she}\)
recovery_time_shed
P
Minimum time between the end of one load shedding processand the start of another\(\Delta t\)
P
The time increment of the model
\(\omega_{t}\)
P
Objective weighting of the model for timestep t
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components.experimental._sink_dsm.SinkDSMDIWInvestmentBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “DIW” approach and investment defined
The following constraints are created for approach = “DIW” with an investment object defined:
\[\begin{split}& (1) \quad invest_{min}(p) \leq invest(p) \leq invest_{max}(p) \\ & \quad \quad \quad \quad \forall p \in \mathbb{P} & \\ & (2) \quad DSM_{t}^{up} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & \\ & (3) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (4) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max}(p) + DSM_{t}^{up} - \sum_{tt=t-L}^{t+L} DSM_{tt,t}^{do, shift} - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (5) \quad DSM_{t}^{up} \cdot \eta = \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do, shift} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (6) \quad DSM_{t}^{up} \leq E_{t}^{up} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (7) \quad \sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do, shift} + DSM_{tt}^{do, shed} \leq E_{tt}^{do} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (8) \quad DSM_{tt}^{up} + \sum_{t=tt-L}^{tt+L} DSM_{t,tt}^{do, shift} + DSM_{tt}^{do, shed} \\ & \quad \quad \leq max \{ E_{tt}^{up}, E_{tt}^{do} \} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (9) \quad \sum_{tt=t}^{t+R-1} DSM_{tt}^{up} \leq E_{t}^{up} \cdot P_{total}(p) \cdot L \cdot \Delta t \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (10) \quad \sum_{tt=t}^{t+R-1} DSM_{tt}^{do, shed} \leq E_{t}^{do} \cdot P_{total}(p) \cdot t_{shed} \cdot \Delta t \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\\end{split}\]Note
For the sake of readability, the handling of indices is not displayed here. E.g. evaluating a variable for t-L may lead to a negative and therefore infeasible index. This is addressed by limiting the sums to non-negative indices within the model index bounds. Please refer to the constraints implementation themselves.
The following parts of the objective function are created:
Standard model
Investment annuity:
\[P_{invest}(0) \cdot c_{invest}(0)\]Variable costs:
\[\begin{split}& (DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + DSM_{t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]
Multi-period model
Investment annuity:
\[\begin{split}& P_{invest}(p) \cdot A(c_{invest}(p), l, ir) \cdot l \cdot DF^{-p} \\ &\\ & \quad \quad \quad \quad \forall p \in \mathbb{P}\end{split}\]fixed_costs
not None for investments\[\begin{split}& (\sum_{pp=year(p)}^{year(p)+l} P_{invest}(p) \cdot c_{fixed}(pp) \cdot DF^{-pp}) \cdot DF^{-p} \\ &\\ & \quad \quad \quad \quad \forall p \in \mathbb{P}\end{split}\]Variable costs:
\[\begin{split}& (DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + DSM_{t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \cdot DF^{-p} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\\end{split}\]
whereby:
\(A(c_{invest,var}(p), l, ir)\) is the annuity for investment expenses \(c_{invest}(p)\) lifetime \(l\) and interest rate \(ir\)
\(DF=(1+dr)\) is the discount factor with discount rate \(dr\)
See remarks in
oemof.solph.components.experimental._sink_dsm.SinkDSMOemofBlock
.Table: Symbols and attribute names of variables and parameters
Please refer to
oemof.solph.components.experimental._sink_dsm.SinkDSMDIWBlock
for a variables and parameter description.The following variables and parameters are exclusively used for investment modeling:
Variables (V), Parameters (P) and Sets (S)¶ symbol
attribute
type
explanation
\(P_{invest}(p)\)
invest[p]
V
DSM capacity invested into in period p.Equals to the additionally shiftable resp. sheddable capacity.\(invest_{min}(p)\)
investment.minimum[p]
P
minimum investment in period p
\(invest_{max}(p)\)
investment.maximum[p]
P
maximum investment in period p
\(P_{total}\)
investment.total[p]
P
total DSM capacity
\(costs_{invest}(p)\)
investment.ep_costs[p]
P
specific investment annuity (standard model) resp.specific investment expenses (multi-period model)\(\mathbb{P}\)
S
Periods of the model
\(\textrm{TIMEINDEX}\)
S
Timeindex set of the model (periods, timesteps)
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components.experimental._sink_dsm.SinkDSMDLRBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “DLR” approach
The following constraints are created for approach = “DLR”:
\[\begin{split}& (1) \quad DSM_{h, t}^{up} = 0 \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & \\ & (2) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (3) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max} \\ & \quad \quad \quad \quad + \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo} - DSM_{h, t}^{do, shift} - DSM_{h, t}^{balanceUp}) - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (4) \quad DSM_{h, t}^{balanceDo} = \frac{DSM_{h, t - h}^{do, shift}}{\eta} \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in [h..T] \\ & \\ & (5) \quad DSM_{h, t}^{balanceUp} = DSM_{h, t-h}^{up} \cdot \eta \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in [h..T] \\ & \\ & (6) \quad DSM_{h, t}^{do, shift} = 0 \quad \forall h \in H_{DR} \\ & \quad \quad \quad \quad \forall t \in [T - h..T] \\ & \\ & (7) \quad DSM_{h, t}^{up} = 0 \quad \forall h \in H_{DR} \\ & \quad \quad \quad \quad \forall t \in [T - h..T] \\ & \\ & (8) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) + DSM_{t}^{do, shed} \leq E_{t}^{do} \cdot E_{max, do} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (9) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo}) \leq E_{t}^{up} \cdot E_{max, up} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (10) \quad \Delta t \cdot \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} - DSM_{h, t}^{balanceDo} \cdot \eta) = W_{t}^{levelDo} - W_{t-1}^{levelDo} \\ & \quad \quad \quad \quad \forall t \in [1..T] \\ & \\ & (11) \quad \Delta t \cdot \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} \cdot \eta - DSM_{h, t}^{balanceUp}) = W_{t}^{levelUp} - W_{t-1}^{levelUp} \\ & \quad \quad \quad \quad \forall t \in [1..T] \\ & \\ & (12) \quad W_{t}^{levelDo} \leq \overline{E}_{t}^{do} \cdot E_{max, do} \cdot t_{shift} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (13) \quad W_{t}^{levelUp} \leq \overline{E}_{t}^{up} \cdot E_{max, up} \cdot t_{shift} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (14) \quad \displaystyle\sum_{t=0}^{T} DSM_{t}^{do, shed} \leq E_{max, do} \cdot \overline{E}_{t}^{do} \cdot t_{shed} \cdot n^{yearLimitShed} \\ & \\ & (15) \quad \displaystyle\sum_{t=0}^{T} \sum_{h=1}^{H_{DR}} DSM_{h, t}^{do, shift} \leq E_{max, do} \cdot \overline{E}_{t}^{do} \cdot t_{shift} \cdot n^{yearLimitShift} \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (16) \quad \displaystyle\sum_{t=0}^{T} \sum_{h=1}^{H_{DR}} DSM_{h, t}^{up} \leq E_{max, up} \cdot \overline{E}_{t}^{up} \cdot t_{shift} \cdot n^{yearLimitShift} \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (17) \quad \displaystyle\sum_{h=1}^{H_{DR}} DSM_{h, t}^{do, shift} \leq E_{max, do} \cdot \overline{E}_{t}^{do} \cdot t_{shift} - \displaystyle\sum_{t'=1}^{t_{dayLimit}} \sum_{h=1}^{H_{DR}} DSM_{h, t - t'}^{do, shift} \\ & \quad \quad \quad \quad \forall t \in [t-t_{dayLimit}..T] \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (18) \quad \displaystyle\sum_{h=1}^{H_{DR}} DSM_{h, t}^{up} \leq E_{max, up} \cdot \overline{E}_{t}^{up} \cdot t_{shift} - \displaystyle\sum_{t'=1}^{t_{dayLimit}} \sum_{h=1}^{H_{DR}} DSM_{h, t - t'}^{up} \\ & \quad \quad \quad \quad \forall t \in [t-t_{dayLimit}..T] \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (19) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo} + DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) + DSM_{t}^{do, shed} \\ & \quad \quad \leq \max \{E_{t}^{up} \cdot E_{max, up}, E_{t}^{do} \cdot E_{max, do} \} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \quad \quad \textrm{(optional constraint)} \\\end{split}\]Note
For the sake of readability, the handling of indices is not displayed here. E.g. evaluating a variable for t-L may lead to a negative and therefore infeasible index. This is addressed by limiting the sums to non-negative indices within the model index bounds. Please refer to the constraints implementation themselves.
The following parts of the objective function are created:
\[\begin{split}& (\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo}) \cdot cost_{t}^{dsm, up} \\ & + \sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]Table: Symbols and attribute names of variables and parameters
Variables (V), Parameters (P) and (additional) Sets (S)¶ symbol
attribute
type
explanation
\(DSM_{h, t}^{up}\)
dsm_up[g, h, t]
V
DSM up shift (additional load) in hour t with delay time h
\(DSM_{h, t}^{do, shift}\)
dsm_do_shift[g, h, t]
V
DSM down shift (less load) in hour t with delay time h
\(DSM_{h, t}^{balanceUp}\)
balance_dsm_up[g, h, t]
V
DSM down shift (less load) in hour t with delay time hto balance previous upshift\(DSM_{h, t}^{balanceDo}\)
balance_dsm_do[g, h, t]
V
DSM up shift (additional load) in hour t with delay time hto balance previous downshift\(DSM_{t}^{do, shed}\)
dsm_do_shed[g, t]
V
DSM shedded (capacity shedded, i.e. not compensated for)
\(\dot{E}_{t}\)
SinkDSM.inputs
V
Energy flowing in from (electrical) inflow bus
\(h\)
delay_time
P
Maximum delay time for load shift(integer value from set of feasible delay times per DSM portfolio;time until the energy balance has to be levelled out again;roundtrip time of one load shifting cycle, i.e. time windowfor upshift and compensating downshift)\(H_{DR}\)
range(len(delay_time))
S
Set of feasible delay times for load shiftof a certain DSM portfolio\(t_{shift}\)
shift_time
P
Maximum time for a shift in one direction,i. e. maximum time for an upshift or a downshiftin a load shifting cycle\(t_{she}\)
shed_time
P
Maximum time for one load shedding process
\(demand_{t}\)
demand[t]
P
(Electrical) demand series (normalized)
\(demand_{max}\)
max_demand
P
Maximum demand value
\(E_{t}^{do}\)
capacity_down[t]
P
Capacity allowed for a load adjustment downwards(normalized; shifting + shedding)\(E_{t}^{up}\)
capacity_up[t]
P
Capacity allowed for a shift upwards (normalized)
\(E_{do, max}\)
max_capacity_down
P
Maximum capacity allowed for a load adjustment downwards(shifting + shedding)\(E_{up, max}\)
max_capacity_up
P
Maximum capacity allowed for a shift upwards
\(\eta\)
efficiency
P
Efficiency for load shifting processes
\(\mathbb{T}\)
S
Time steps of the model
\(e_{shift}\)
shift_eligibility
P
Boolean parameter indicating if unit can be usedfor load shifting\(e_{shed}\)
shed_eligibility
P
Boolean parameter indicating if unit can be usedfor load shedding\(cost_{t}^{dsm, up}\)
cost_dsm_up[t]
P
Variable costs for an upwards shift
\(cost_{t}^{dsm, do, shift}\)
cost_dsm_down_shift[t]
P
Variable costs for a downwards shift (load shifting)
\(cost_{t}^{dsm, do, shed}\)
cost_dsm_down_shift[t]
P
Variable costs for shedding load
\(\omega_{t}\)
P
Objective weighting of the model for timestep t
\(R_{shi}\)
recovery_time_shift
P
Minimum time between the end of one load shifting processand the start of another\(R_{she}\)
recovery_time_shed
P
Minimum time between the end of one load shedding processand the start of another\(\Delta t\)
P
The time increment of the model
\(\omega_{t}\)
P
Objective weighting of the model for timestep t
\(n_{yearLimitShift}\)
n_yeaLimitShift
P
Maximum allowed number of load shifts (at full capacity)in the optimization timeframe\(n_{yearLimitShed}\)
n_yeaLimitShed
P
Maximum allowed number of load sheds (at full capacity)in the optimization timeframe\(t_{dayLimit}\)
t_dayLimit
P
Maximum duration of load shifts at full capacity per dayresp. in the last hours before the current”- CONSTRAINT_GROUP = True¶
- class oemof.solph.components.experimental._sink_dsm.SinkDSMDLRInvestmentBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “DLR” approach and investment defined
The following constraints are created for approach = “DLR” with an investment object defined:
\[\begin{split}& (1) \quad invest_{min}(p) \leq invest(p) \leq invest_{max}(p) \\ & \quad \quad \quad \quad \forall p \in \mathbb{P} & \\ & (2) \quad DSM_{h, t}^{up} = 0 \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & (3) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (4) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max}(p) \\ & \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo} - DSM_{h, t}^{do, shift} - DSM_{h, t}^{balanceUp}) - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (5) \quad DSM_{h, t}^{balanceDo} = \frac{DSM_{h, t - h}^{do, shift}}{\eta} \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in [h..T] \\ & \\ & (6) \quad DSM_{h, t}^{balanceUp} = DSM_{h, t-h}^{up} \cdot \eta \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in [h..T] \\ & \\ & (7) \quad DSM_{h, t}^{do, shift} = 0 \quad \forall h \in H_{DR} \\ & \quad \quad \quad \quad \forall t \in [T - h..T] \\ & \\ & (8) \quad DSM_{h, t}^{up} = 0 \\ & \quad \quad \quad \quad \forall h \in H_{DR}, t \in [T - h..T] \\ & \\ & (9) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) + DSM_{t}^{do, shed} \leq E_{t}^{do} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (10) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo}) \leq E_{t}^{up} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (11) \quad \Delta t \cdot \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} - DSM_{h, t}^{balanceDo} \cdot \eta) = W_{t}^{levelDo} - W_{t-1}^{levelDo} \\ & \quad \quad \quad \quad \forall t \in [1..T] \\ & \\ & (12) \quad \Delta t \cdot \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} \cdot \eta - DSM_{h, t}^{balanceUp}) = W_{t}^{levelUp} - W_{t-1}^{levelUp} \\ & \quad \quad \quad \quad \forall t \in [1..T] \\ & \\ & (13) \quad W_{t}^{levelDo} \leq \overline{E}_{t}^{do} \cdot P_{total}(p) \cdot t_{shift} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (14) \quad W_{t}^{levelUp} \leq \overline{E}_{t}^{up} \cdot P_{total}(p) \cdot t_{shift} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (15) \quad \displaystyle\sum_{t=0}^{T} DSM_{t}^{do, shed} \leq P_{total}(p) \cdot \overline{E}_{t}^{do} \cdot t_{shed} \cdot n^{yearLimitShed} \\ & \\ & (16) \quad \displaystyle\sum_{t=0}^{T} \sum_{h=1}^{H_{DR}} DSM_{h, t}^{do, shift} \leq P_{total}(p) \cdot \overline{E}_{t}^{do} \cdot t_{shift} \cdot n^{yearLimitShift} \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (17) \quad \displaystyle\sum_{t=0}^{T} \sum_{h=1}^{H_{DR}} DSM_{h, t}^{up} \leq P_{total}(p) \cdot \overline{E}_{t}^{up} \cdot t_{shift} \cdot n^{yearLimitShift} \\ & \quad \quad \textrm{(optional constraint)} \\ & (18) \quad \displaystyle\sum_{h=1}^{H_{DR}} DSM_{h, t}^{do, shift} \leq P_{total}(p) \cdot \overline{E}_{t}^{do} \cdot t_{shift} - \displaystyle\sum_{t'=1}^{t_{dayLimit}} \sum_{h=1}^{H_{DR}} DSM_{h, t - t'}^{do, shift} \\ & \quad \quad \quad \quad \forall t \in [t-t_{dayLimit}..T] \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (19) \quad \displaystyle\sum_{h=1}^{H_{DR}} DSM_{h, t}^{up} \leq (invest + E_{exist}) \cdot \overline{E}_{t}^{up} \cdot t_{shift} - \displaystyle\sum_{t'=1}^{t_{dayLimit}} \sum_{h=1}^{H_{DR}} DSM_{h, t - t'}^{up} \\ & \quad \quad \quad \quad \forall t \in [t-t_{dayLimit}..T] \\ & \quad \quad \textrm{(optional constraint)} \\ & \\ & (20) \quad \displaystyle\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo} + DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) \\ & + DSM_{t}^{shed} \leq \max \{E_{t}^{up}, E_{t}^{do} \} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \quad \quad \textrm{(optional constraint)} \\ &\end{split}\]Note
For the sake of readability, the handling of indices is not displayed here. E.g. evaluating a variable for t-L may lead to a negative and therefore infeasible index. This is addressed by limiting the sums to non-negative indices within the model index bounds. Please refer to the constraints implementation themselves.
The following parts of the objective function are created:
Standard model
Investment annuity:
\[P_{invest}(0) \cdot c_{invest}(0)\]Variable costs:
\[\begin{split}& (\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo}) \cdot cost_{t}^{dsm, up} \\ & + \sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]
Multi-period model
Investment annuity:
\[\begin{split}& P_{invest}(p) \cdot A(c_{invest}(p), l, ir) \cdot l \cdot DF^{-p} \\ &\\ & \forall p \in \mathbb{P}\end{split}\]fixed_costs
not None for investments\[\begin{split}& (\sum_{pp=year(p)}^{year(p)+l} P_{invest}(p) \cdot c_{fixed}(pp) \cdot DF^{-pp}) \cdot DF^{-p} \\ &\\ & \forall p \in \mathbb{P}\end{split}\]Variable costs:
\[\begin{split}& (\sum_{h=1}^{H_{DR}} (DSM_{h, t}^{up} + DSM_{h, t}^{balanceDo}) \cdot cost_{t}^{dsm, up} \\ & + \sum_{h=1}^{H_{DR}} (DSM_{h, t}^{do, shift} + DSM_{h, t}^{balanceUp}) \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \cdot DF^{-p} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\\end{split}\]
whereby:
\(A(c_{invest,var}(p), l, ir)\) A is the annuity for investment expenses \(c_{invest}(p)\) lifetime \(l\) and interest rate \(ir\)
\(DF=(1+dr)\) is the discount factor with discount rate \(dr\)
See remarks in
oemof.solph.components.experimental._sink_dsm.SinkDSMOemofBlock
.Table: Symbols and attribute names of variables and parameters
Please refer to
oemof.solph.components.experimental._sink_dsm.SinkDSMDLRBlock
.The following variables and parameters are exclusively used for investment modeling:
Variables (V), Parameters (P) and Sets (S)¶ symbol
attribute
type
explanation
\(P_{invest}(p)\)
invest[p]
V
DSM capacity invested into in period p.Equals to the additionally shiftable resp. sheddable capacity.\(invest_{min}(p)\)
investment.minimum[p]
P
minimum investment in period p
\(invest_{max}(p)\)
investment.maximum[p]
P
maximum investment in period p
\(P_{total}\)
investment.total[p]
P
total DSM capacity
\(costs_{invest}(p)\)
investment.ep_costs[p]
P
specific investment annuity (standard model) resp.specific investment expenses (multi-period model)\(\mathbb{P}\)
S
Periods of the model
\(\textrm{TIMEINDEX}\)
S
Timeindex set of the model (periods, timesteps)
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components.experimental._sink_dsm.SinkDSMOemofBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “oemof” approach
The following constraints are created for approach = “oemof”:
\[\begin{split}& (1) \quad DSM_{t}^{up} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & \\ & (2) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (3) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max} + DSM_{t}^{up} - DSM_{t}^{do, shift} - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (4) \quad DSM_{t}^{up} \leq E_{t}^{up} \cdot E_{up, max} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (5) \quad DSM_{t}^{do, shift} + DSM_{t}^{do, shed} \leq E_{t}^{do} \cdot E_{do, max} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\ & \\ & (6) \quad \sum_{t=t_s}^{t_s+\tau} DSM_{t}^{up} \cdot \eta = \sum_{t=t_s}^{t_s+\tau} DSM_{t}^{do, shift} \\ & \quad \quad \quad \quad \forall t_s \in \{k \in \mathbb{T} \mid k \mod \tau = 0\} \\\end{split}\]The following parts of the objective function are created:
\[\begin{split}& (DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + DSM_{t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]Table: Symbols and attribute names of variables and parameters
Variables (V), Parameters (P) and Sets (S)¶ symbol
attribute
type
explanation
\(DSM_{t}^{up}\)
dsm_up[g, t]
V
DSM up shift (capacity shifted upwards)
\(DSM_{t}^{do, shift}\)
dsm_do_shift[g, t]
V
DSM down shift (capacity shifted downwards)
\(DSM_{t}^{do, shed}\)
dsm_do_shed[g, t]
V
DSM shedded (capacity shedded, i.e. not compensated for)
\(\dot{E}_{t}\)
SinkDSM.inputs
V
Energy flowing in from (electrical) inflow bus
\(demand_{t}\)
demand[t]
P
(Electrical) demand series before shifting (normalized)
\(demand_{max}(p)\)
max_demand
P
Maximum demand value in period p
\(E_{t}^{do}\)
capacity_down[t]
P
Capacity allowed for a load adjustment downwards(normalized; shifting + shedding)\(E_{t}^{up}\)
capacity_up[t]
P
Capacity allowed for a shift upwards (normalized)
\(E_{do, max}\)
max_capacity_down
P
Maximum capacity allowed for a load adjustment downwards(shifting + shedding)\(E_{up, max}\)
max_capacity_up
P
Maximum capacity allowed for a shift upwards
\(\tau\)
shift_interval
P
interval (time within which theenergy balance must be levelled out)\(\eta\)
efficiency
P
Efficiency for load shifting processes
\(\mathbb{T}\)
S
Time steps of the model
\(e_{shift}\)
shift_eligibility
P
Boolean parameter indicating if unit can be usedfor load shifting\(e_{shed}\)
shed_eligibility
P
Boolean parameter indicating if unit can be usedfor load shedding\(cost_{t}^{dsm, up}\)
cost_dsm_up[t]
P
Variable costs for an upwards shift
\(cost_{t}^{dsm, do, shift}\)
cost_dsm_down_shift[t]
P
Variable costs for a downwards shift (load shifting)
\(cost_{t}^{dsm, do, shed}\)
cost_dsm_down_shift[t]
P
Variable costs for shedding load
\(\omega_{t}\)
P
Objective weighting of the model for timestep t
- CONSTRAINT_GROUP = True¶
- class oemof.solph.components.experimental._sink_dsm.SinkDSMOemofInvestmentBlock(*args, **kwds)[source]¶
Bases:
ScalarBlock
Constraints for SinkDSM with “oemof” approach and investment defined
The following constraints are created for approach = “oemof” with an investment object defined:
\[\begin{split}& (1) \quad invest_{min}(p) \leq invest(p) \leq invest_{max}(p) \\ & \quad \quad \quad \quad \forall p \in \mathbb{P} & \\ & (2) \quad DSM_{t}^{up} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shift} = \textrm{False} \\ & \\ & (3) \quad DSM_{t}^{do, shed} = 0 \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \quad \textrm{if} \quad e_{shed} = \textrm{False} \\ & \\ & (4) \quad \dot{E}_{t} = demand_{t} \cdot demand_{max}(p) + DSM_{t}^{up} - DSM_{t}^{do, shift} - DSM_{t}^{do, shed} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (5) \quad DSM_{t}^{up} \leq E_{t}^{up} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (6) \quad DSM_{t}^{do, shift} + DSM_{t}^{do, shed} \leq E_{t}^{do} \cdot P_{total}(p) \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\ & \\ & (7) \quad \sum_{t=t_s}^{t_s+\tau} DSM_{t}^{up} \cdot \eta = \sum_{t=t_s}^{t_s+\tau} DSM_{t}^{do, shift} \\ & \quad \quad \quad \quad \forall t_s \in \{k \in \mathbb{T} \mid k \mod \tau = 0\} \\\end{split}\]The following parts of the objective function are created:
Standard model
Investment annuity:
\[P_{invest}(0) \cdot c_{invest}(0)\]Variable costs:
\[\begin{split}& (DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + DSM_{t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \\ & \quad \quad \quad \quad \forall t \in \mathbb{T} \\\end{split}\]
Multi-period model
Investment annuity:
\[\begin{split}& P_{invest}(p) \cdot A(c_{invest}(p), l, ir) \cdot l \cdot DF^{-p} \\ &\\ & \forall p \in \mathbb{P}\end{split}\]fixed_costs
not None for investments\[\begin{split}& (\sum_{pp=year(p)}^{year(p)+l} P_{invest}(p) \cdot c_{fixed}(pp) \cdot DF^{-pp}) \cdot DF^{-p} \\ &\\ & \forall p \in \mathbb{P}\end{split}\]Variable costs:
\[\begin{split}& (DSM_{t}^{up} \cdot cost_{t}^{dsm, up} + DSM_{t}^{do, shift} \cdot cost_{t}^{dsm, do, shift} \\ & + DSM_{t}^{do, shed} \cdot cost_{t}^{dsm, do, shed}) \cdot \omega_{t} \cdot DF^{-p} \\ & \quad \quad \quad \quad \forall p, t \in \textrm{TIMEINDEX} \\\end{split}\]
whereby:
\(A(c_{invest,var}(p), l, ir)\) A is the annuity for investment expenses \(c_{invest}(p)\) lifetime \(l\) and interest rate \(ir\)
\(DF=(1+dr)\) is the discount factor with discount rate \(dr\)
See remarks in
oemof.solph.components.experimental._sink_dsm.SinkDSMOemofBlock
.Symbols and attribute names of variables and parameters
Please refer to
oemof.solph.components.experimental._sink_dsm.SinkDSMOemofBlock
. for a variables and parameter description.The following variables and parameters are exclusively used for investment modeling:
Variables (V), Parameters (P) and Sets (S)¶ symbol
attribute
type
explanation
\(P_{invest}(p)\)
invest[p]
V
DSM capacity invested into in period p.Equals to the additionally shiftable resp. sheddable capacity.\(invest_{min}(p)\)
investment.minimum[p]
P
minimum investment in period p
\(invest_{max}(p)\)
investment.maximum[p]
P
maximum investment in period p
\(P_{total}\)
investment.total[p]
P
total DSM capacity
\(costs_{invest}(p)\)
investment.ep_costs[p]
P
specific investment annuity (standard model) resp.specific investment expenses (multi-period model)\(\mathbb{P}\)
S
Periods of the model
\(\textrm{TIMEINDEX}\)
S
Timeindex set of the model (periods, timesteps)
- CONSTRAINT_GROUP = True¶