oemof.solph package

Submodules

oemof.solph.blocks module

Creating sets, variables, constraints and parts of the objective function for the specified groups.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Patrik Schönfeldt SPDX-FileCopyrightText: Birgit Schachler SPDX-FileCopyrightText: jnnr SPDX-FileCopyrightText: jmloenneberga

SPDX-License-Identifier: MIT

class oemof.solph.blocks.Bus(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for all balanced buses.

The following constraints are build:

Bus balance om.Bus.balance[i, o, t]

\sum_{i \in INPUTS(n)} flow(i, n, t) =
\sum_{o \in OUTPUTS(n)} flow(n, o, t), \\
\forall n \in \textrm{BUSES},
\forall t \in \textrm{TIMESTEPS}.

class oemof.solph.blocks.Flow(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Flow block with definitions for standard flows.

The following variables are created:

negative_gradient :
Difference of a flow in consecutive timesteps if flow is reduced indexed by NEGATIVE_GRADIENT_FLOWS, TIMESTEPS.
positive_gradient :
Difference of a flow in consecutive timesteps if flow is increased indexed by NEGATIVE_GRADIENT_FLOWS, TIMESTEPS.

The following sets are created: (-> see basic sets at Model )

SUMMED_MAX_FLOWS
A set of flows with the attribute summed_max being not None.
SUMMED_MIN_FLOWS
A set of flows with the attribute summed_min being not None.
NEGATIVE_GRADIENT_FLOWS
A set of flows with the attribute negative_gradient being not None.
POSITIVE_GRADIENT_FLOWS
A set of flows with the attribute positive_gradient being not None
INTEGER_FLOWS
A set of flows where the attribute integer is True (forces flow to only take integer values)

The following constraints are build:

Flow max sum om.Flow.summed_max[i, o]

\sum_t flow(i, o, t) \cdot \tau
    \leq summed\_max(i, o) \cdot nominal\_value(i, o), \\
\forall (i, o) \in \textrm{SUMMED\_MAX\_FLOWS}.

Flow min sum om.Flow.summed_min[i, o]

\sum_t flow(i, o, t) \cdot \tau
    \geq summed\_min(i, o) \cdot nominal\_value(i, o), \\
\forall (i, o) \in \textrm{SUMMED\_MIN\_FLOWS}.

Negative gradient constraint
om.Flow.negative_gradient_constr[i, o]:

flow(i, o, t-1) - flow(i, o, t) \geq \
negative\_gradient(i, o, t), \\
\forall (i, o) \in \textrm{NEGATIVE\_GRADIENT\_FLOWS}, \\
\forall t \in \textrm{TIMESTEPS}.

Positive gradient constraint
om.Flow.positive_gradient_constr[i, o]:

flow(i, o, t) - flow(i, o, t-1) \geq \
positive\__gradient(i, o, t), \\
\forall (i, o) \in \textrm{POSITIVE\_GRADIENT\_FLOWS}, \\
\forall t \in \textrm{TIMESTEPS}.

The following parts of the objective function are created:

If variable_costs are set by the user:

\sum_{(i,o)} \sum_t flow(i, o, t) \cdot variable\_costs(i, o, t)

The expression can be accessed by om.Flow.variable_costs and their value after optimization by om.Flow.variable_costs() .

class oemof.solph.blocks.InvestmentFlow(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for all flows with Investment being not None.

See oemof.solph.options.Investment for all parameters of the Investment class.

See oemof.solph.network.Flow for all parameters of the Flow class.

Variables

All InvestmentFlow are indexed by a starting and ending node (i, o), which is omitted in the following for the sake of convenience. The following variables are created:

  • P(t)

    Actual flow value (created in oemof.solph.models.BaseModel).

  • P_{invest}

    Value of the investment variable, i.e. equivalent to the nominal value of the flows after optimization.

  • b_{invest}

    Binary variable for the status of the investment, if nonconvex is True.

Constraints

Depending on the attributes of the InvestmentFlow and Flow, different constraints are created. The following constraint is created for all InvestmentFlow:

Upper bound for the flow value

P(t) \le ( P_{invest} + P_{exist} ) \cdot f_{max}(t)

Depeding on the attribute nonconvex, the constraints for the bounds of the decision variable P_{invest} are different:

  • nonconvex = False

P_{invest, min} \le P_{invest} \le P_{invest, max}

  • nonconvex = True

&
P_{invest, min} \cdot b_{invest} \le P_{invest}\\
&
P_{invest} \le P_{invest, max} \cdot b_{invest}\\

For all InvestmentFlow (independent of the attribute nonconvex), the following additional constraints are created, if the appropriate attribute of the Flow (see oemof.solph.network.Flow) is set:

  • fix is not None

    Actual value constraint for investments with fixed flow values

P(t) = ( P_{invest} + P_{exist} ) \cdot f_{fix}(t)

  • min != 0

    Lower bound for the flow values

P(t) \geq ( P_{invest} + P_{exist} ) \cdot f_{min}(t)

  • summed_max is not None

    Upper bound for the sum of all flow values (e.g. maximum full load hours)

\sum_t P(t) \cdot \tau(t) \leq ( P_{invest} + P_{exist} )
\cdot f_{sum, min}

  • summed_min is not None

    Lower bound for the sum of all flow values (e.g. minimum full load hours)

\sum_t P(t) \cdot \tau(t) \geq ( P_{invest} + P_{exist} )
\cdot f_{sum, min}

Objective function

The part of the objective function added by the InvestmentFlow also depends on whether a convex or nonconvex InvestmentFlow is selected. The following parts of the objective function are created:

  • nonconvex = False

    P_{invest} \cdot c_{invest,var}

  • nonconvex = True

    P_{invest} \cdot c_{invest,var}
+ c_{invest,fix} \cdot b_{invest}\\

The total value of all costs of all InvestmentFlow can be retrieved calling om.InvestmentFlow.investment_costs.expr().

List of Variables (in csv table syntax)
symbol attribute explanation
P(t) flow[n, o, t] Actual flow value
P_{invest} invest[i, o] Invested flow capacity
b_{invest} invest_status[i, o] Binary status of investment

List of Variables (in rst table syntax):

symbol attribute explanation
P(t) flow[n, o, t] Actual flow value
P_{invest} invest[i, o] Invested flow capacity
b_{invest} invest_status[i, o] Binary status of investment

Grid table style:

symbol attribute explanation
P(t) flow[n, o, t] Actual flow value
P_{invest} invest[i, o] Invested flow capacity
b_{invest} invest_status[i, o] Binary status of investment
List of Parameters
symbol attribute explanation
P_{exist} flows[i, o].investment.existing Existing flow capacity
P_{invest,min} flows[i, o].investment.minimum Minimum investment capacity
P_{invest,max} flows[i, o].investment.maximum Maximum investment capacity
c_{invest,var} flows[i, o].investment.ep_costs Variable investment costs
c_{invest,fix} flows[i, o].investment.offset Fix investment costs
f_{actual} flows[i, o].fix[t] Normed fixed value for the flow variable
f_{max} flows[i, o].max[t] Normed maximum value of the flow
f_{min} flows[i, o].min[t] Normed minimum value of the flow
f_{sum,max} flows[i, o].summed_max Specific maximum of summed flow values (per installed capacity)
f_{sum,min} flows[i, o].summed_min Specific minimum of summed flow values (per installed capacity)
\tau(t) timeincrement[t] Time step width for each time step

Note

In case of a nonconvex investment flow (nonconvex=True), the existing flow capacity P_{exist} needs to be zero. At least, it is not tested yet, whether this works out, or makes any sense at all.

class oemof.solph.blocks.NonConvexFlow(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

The following sets are created: (-> see basic sets at
Model )
A set of flows with the attribute nonconvex of type
options.NonConvex.
MIN_FLOWS
A subset of set NONCONVEX_FLOWS with the attribute min being not None in the first timestep.
ACTIVITYCOSTFLOWS
A subset of set NONCONVEX_FLOWS with the attribute activity_costs being not None.
STARTUPFLOWS
A subset of set NONCONVEX_FLOWS with the attribute maximum_startups or startup_costs being not None.
MAXSTARTUPFLOWS
A subset of set STARTUPFLOWS with the attribute maximum_startups being not None.
SHUTDOWNFLOWS
A subset of set NONCONVEX_FLOWS with the attribute maximum_shutdowns or shutdown_costs being not None.
MAXSHUTDOWNFLOWS
A subset of set SHUTDOWNFLOWS with the attribute maximum_shutdowns being not None.
MINUPTIMEFLOWS
A subset of set NONCONVEX_FLOWS with the attribute minimum_uptime being not None.
MINDOWNTIMEFLOWS
A subset of set NONCONVEX_FLOWS with the attribute minimum_downtime being not None.

The following variables are created:

Status variable (binary) om.NonConvexFlow.status:
Variable indicating if flow is >= 0 indexed by FLOWS
Startup variable (binary) om.NonConvexFlow.startup:
Variable indicating startup of flow (component) indexed by STARTUPFLOWS
Shutdown variable (binary) om.NonConvexFlow.shutdown:
Variable indicating shutdown of flow (component) indexed by SHUTDOWNFLOWS

The following constraints are created:

Minimum flow constraint om.NonConvexFlow.min[i,o,t]

flow(i, o, t) \geq min(i, o, t) \cdot nominal\_value \
    \cdot status(i, o, t), \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall (i, o) \in \textrm{NONCONVEX\_FLOWS}.

Maximum flow constraint om.NonConvexFlow.max[i,o,t]

flow(i, o, t) \leq max(i, o, t) \cdot nominal\_value \
    \cdot status(i, o, t), \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall (i, o) \in \textrm{NONCONVEX\_FLOWS}.

Startup constraint om.NonConvexFlow.startup_constr[i,o,t]

startup(i, o, t) \geq \
    status(i,o,t) - status(i, o, t-1) \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall (i,o) \in \textrm{STARTUPFLOWS}.

Maximum startups constraint
om.NonConvexFlow.max_startup_constr[i,o,t]

\sum_{t \in \textrm{TIMESTEPS}} startup(i, o, t) \leq \
    N_{start}(i,o)
\forall (i,o) \in \textrm{MAXSTARTUPFLOWS}.

Shutdown constraint om.NonConvexFlow.shutdown_constr[i,o,t]

shutdown(i, o, t) \geq \
    status(i, o, t-1) - status(i, o, t) \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall (i, o) \in \textrm{SHUTDOWNFLOWS}.

Maximum shutdowns constraint
om.NonConvexFlow.max_startup_constr[i,o,t]

\sum_{t \in \textrm{TIMESTEPS}} startup(i, o, t) \leq \
    N_{shutdown}(i,o)
\forall (i,o) \in \textrm{MAXSHUTDOWNFLOWS}.

Minimum uptime constraint om.NonConvexFlow.uptime_constr[i,o,t]

(status(i, o, t)-status(i, o, t-1)) \cdot minimum\_uptime(i, o) \\
\leq \sum_{n=0}^{minimum\_uptime-1} status(i,o,t+n) \\
\forall t \in \textrm{TIMESTEPS} | \\
t \neq \{0..minimum\_uptime\} \cup \
\{t\_max-minimum\_uptime..t\_max\} , \\
\forall (i,o) \in \textrm{MINUPTIMEFLOWS}.
\\ \\
status(i, o, t) = initial\_status(i, o) \\
\forall t \in \textrm{TIMESTEPS} | \\
t = \{0..minimum\_uptime\} \cup \
\{t\_max-minimum\_uptime..t\_max\} , \\
\forall (i,o) \in \textrm{MINUPTIMEFLOWS}.

Minimum downtime constraint om.NonConvexFlow.downtime_constr[i,o,t]

(status(i, o, t-1)-status(i, o, t)) \
\cdot minimum\_downtime(i, o) \\
\leq minimum\_downtime(i, o) \
- \sum_{n=0}^{minimum\_downtime-1} status(i,o,t+n) \\
\forall t \in \textrm{TIMESTEPS} | \\
t \neq \{0..minimum\_downtime\} \cup \
\{t\_max-minimum\_downtime..t\_max\} , \\
\forall (i,o) \in \textrm{MINDOWNTIMEFLOWS}.
\\ \\
status(i, o, t) = initial\_status(i, o) \\
\forall t \in \textrm{TIMESTEPS} | \\
t = \{0..minimum\_downtime\} \cup \
\{t\_max-minimum\_downtime..t\_max\} , \\
\forall (i,o) \in \textrm{MINDOWNTIMEFLOWS}.

The following parts of the objective function are created:

If nonconvex.startup_costs is set by the user:

\sum_{i, o \in STARTUPFLOWS} \sum_t  startup(i, o, t) \
\cdot startup\_costs(i, o)

If nonconvex.shutdown_costs is set by the user:

\sum_{i, o \in SHUTDOWNFLOWS} \sum_t shutdown(i, o, t) \
    \cdot shutdown\_costs(i, o)

If nonconvex.activity_costs is set by the user:

\sum_{i, o \in ACTIVITYCOSTFLOWS} \sum_t status(i, o, t) \
    \cdot activity\_costs(i, o)

class oemof.solph.blocks.Transformer(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for the linear relation of nodes with type Transformer

The following sets are created: (-> see basic sets at Model )

TRANSFORMERS
A set with all Transformer objects.

The following constraints are created:

Linear relation om.Transformer.relation[i,o,t]

flow(i, n, t) / conversion\_factor(n, i, t) = \
flow(n, o, t) / conversion\_factor(n, o, t), \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall n \in \textrm{TRANSFORMERS}, \\
\forall i \in \textrm{INPUTS(n)}, \\
\forall o \in \textrm{OUTPUTS(n)}.

oemof.solph.components module

This module is designed to hold components with their classes and associated individual constraints (blocks) and groupings. Therefore this module holds the class definition and the block directly located by each other.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Patrik Schönfeldt SPDX-FileCopyrightText: FranziPl SPDX-FileCopyrightText: jnnr SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: FabianTU SPDX-FileCopyrightText: Johannes Röder

SPDX-License-Identifier: MIT

class oemof.solph.components.ExtractionTurbineCHP(conversion_factor_full_condensation, *args, **kwargs)[source]

Bases: oemof.solph.network.Transformer

A CHP with an extraction turbine in a linear model. For more options 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.

Note

The following sets, variables, constraints and objective parts are created

Examples

>>> from oemof import solph
>>> bel = solph.Bus(label='electricityBus')
>>> bth = solph.Bus(label='heatBus')
>>> bgas = solph.Bus(label='commodityBus')
>>> et_chp = solph.components.ExtractionTurbineCHP(
...    label='variable_chp_gas',
...    inputs={bgas: solph.Flow(nominal_value=10e10)},
...    outputs={bel: solph.Flow(), bth: solph.Flow()},
...    conversion_factors={bel: 0.3, bth: 0.5},
...    conversion_factor_full_condensation={bel: 0.5})
constraint_group()[source]
class oemof.solph.components.ExtractionTurbineCHPBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for the linear relation of nodes with type ExtractionTurbineCHP

The following two constraints are created:

&
(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 =
   \dot Q_{th}(t) \cdot
   \frac{\eta_{el,maxExtr}(t)}
     {\eta_{th,maxExtr}(t)}

where \beta is defined as:

\beta(t) = \frac{\eta_{el,woExtr}(t) -
\eta_{el,maxExtr}(t)}{\eta_{th,maxExtr}(t)}

where 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
class oemof.solph.components.GenericCHP(*args, **kwargs)[source]

Bases: oemof.network.network.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.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. 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.Bus and oemof.Flow object 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.Bus(label='electricityBus')
>>> bth = solph.Bus(label='heatBus')
>>> bgas = solph.Bus(label='commodityBus')
>>> ccet = solph.components.GenericCHP(
...    label='combined_cycle_extraction_turbine',
...    fuel_input={bgas: solph.Flow(
...        H_L_FG_share_max=[0.183])},
...    electrical_output={bel: solph.Flow(
...        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.Flow(
...        Q_CW_min=[10.552])},
...    Beta=[0.122], back_pressure=False)
>>> type(ccet)
<class 'oemof.solph.components.GenericCHP'>
alphas

Compute or return the _alphas attribute.

constraint_group()[source]
class oemof.solph.components.GenericCHPBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for the relation of the n nodes with type class:.GenericCHP.

The following constraints are created:

&
(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)\\

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:

&
\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)}\\

For the attribute \dot{H}_{L,FG,min} being not None, e.g. for a motoric CHP, the following is created:

Constraint:

&
(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]

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
class oemof.solph.components.GenericInvestmentStorageBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for all storages with Investment being not None. See oemof.solph.options.Investment for all parameters of the Investment class.

Variables

All Storages are indexed by n, which is omitted in the following for the sake of convenience. The following variables are created as attributes of om.InvestmentStorage:

  • P_i(t)

    Inflow of the storage (created in oemof.solph.models.BaseModel).

  • P_o(t)

    Outflow of the storage (created in oemof.solph.models.BaseModel).

  • E(t)

    Current storage content (Absolute level of stored energy).

  • E_{invest}

    Invested (nominal) capacity of the storage.

  • E(-1)

    Initial storage content (before timestep 0).

  • b_{invest}

    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)

E(t) = &E(t-1) \cdot
(1 - \beta(t)) ^{\tau(t)/(t_u)} \\
&- \gamma(t)\cdot (E_{exist} + E_{invest}) \cdot {\tau(t)/(t_u)}\\
&- \delta(t) \cdot {\tau(t)/(t_u)}\\
&- \frac{P_o(t)}{\eta_o(t)} \cdot \tau(t)
+ P_i(t) \cdot \eta_i(t) \cdot \tau(t)

Depending on the attribute nonconvex, the constraints for the bounds of the decision variable E_{invest} are different:

  • nonconvex = False

E_{invest, min} \le E_{invest} \le E_{invest, max}

  • nonconvex = True

&
E_{invest, min} \cdot b_{invest} \le E_{invest}\\
&
E_{invest} \le E_{invest, max} \cdot b_{invest}\\

The following constraints are created depending on the attributes of the components.GenericStorage:

  • initial_storage_level is None

    Constraint for a variable initial storage content:

E(-1) \le E_{invest} + E_{exist}

  • initial_storage_level is not None

    An initial value for the storage content is given:

E(-1) = (E_{invest} + E_{exist}) \cdot c(-1)

  • balanced=True

    The 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:

P_{i,invest} + P_{i,exist} =
(E_{invest} + E_{exist}) \cdot r_{cap,in}

  • invest_relation_output_capacity is not None

    Connect the invest variables of the storage and the output flow:

P_{o,invest} + P_{o,exist} =
(E_{invest} + E_{exist}) \cdot r_{cap,out}

  • invest_relation_input_output is not None

    Connect the invest variables of the input and the output flow:

P_{i,invest} + P_{i,exist} =
(P_{o,invest} + P_{o,exist}) \cdot r_{in,out}

  • max_storage_level

    Rule for upper bound constraint for the storage content:

E(t) \leq E_{invest} \cdot c_{max}(t)

  • min_storage_level

    Rule for lower bound constraint for the storage content:

E(t) \geq E_{invest} \cdot c_{min}(t)

Objective function

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:

  • nonconvex = False

    E_{invest} \cdot c_{invest,var}

  • nonconvex = True

    E_{invest} \cdot c_{invest,var}
+ c_{invest,fix} \cdot b_{invest}\\

The total value of all investment costs of all InvestmentStorages can be retrieved calling om.GenericInvestmentStorageBlock.investment_costs.expr().

List of Variables
symbol attribute explanation
P_i(t) flow[i[n], n, t] Inflow of the storage
P_o(t) flow[n, o[n], t] Outlfow of the storage
E(t) storage_content[n, t] Current storage content (current absolute stored energy)
E_{invest} invest[n, t] Invested (nominal) capacity of the storage
E(-1) init_cap[n] Initial storage capacity (before timestep 0)
b_{invest} invest_status[i, o] Binary variable for the status of investment
P_{i,invest} InvestmentFlow.invest[i[n], n] Invested (nominal) inflow (Investmentflow)
P_{o,invest} InvestmentFlow.invest[n, o[n]] Invested (nominal) outflow (Investmentflow)
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 outlfow capacity
c_{invest,var} flows[i, o].investment.ep_costs Variable investment costs
c_{invest,fix} flows[i, o].investment.offset Fix investment costs
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 relativ 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
\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.GenericStorage(*args, max_storage_level=1, min_storage_level=0, **kwargs)[source]

Bases: oemof.network.network.Transformer

Component GenericStorage to model with basic characteristics of storages.

Parameters:
  • nominal_storage_capacity (numeric, E_{nom}) – Absolute nominal capacity of the storage
  • 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).
  • 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.
  • fixed_losses_relative (numeric (iterable or scalar), \gamma(t)) – Losses independent of state of charge between two consecutive timesteps relative to nominal storage capacity.
  • fixed_losses_absolute (numeric (iterable or scalar), \delta(t)) – Losses independent of state of charge and independent of nominal storage capacity between two consecutive timesteps.
  • 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 (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.

Note

The following sets, variables, constraints and objective parts are created

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.Bus('my_bus')
>>> my_storage = solph.components.GenericStorage(
...     label='storage',
...     nominal_storage_capacity=1000,
...     inputs={my_bus: solph.Flow(nominal_value=200, variable_costs=10)},
...     outputs={my_bus: solph.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.Flow()},
...     outputs={my_bus: solph.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)
constraint_group()[source]
class oemof.solph.components.GenericStorageBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Storage without an Investment object.

The following sets are created: (-> see basic sets at Model )

STORAGES
A set with all Storage objects, which do not have an
attr:investment of type Investment.
STORAGES_BALANCED
A set of all Storage objects, with ‘balanced’ attribute set to True.
STORAGES_WITH_INVEST_FLOW_REL
A set with all Storage 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.Storage.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]

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(t)}{\eta_o(t)} \cdot \tau(t)
+ \dot{E}_i(t) \cdot \eta_i(t) \cdot \tau(t)

Connect the invest variables of the input and the output flow.

InvestmentFlow.invest(source(n), n) + existing = \\
(InvestmentFlow.invest(n, target(n)) + existing) * \\
invest\_relation\_input\_output(n) \\
\forall n \in \textrm{INVEST\_REL\_IN\_OUT}

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 loss_rate[t]
\gamma(t) fixed loss of energy relative to E_{nom} per time unit fixed_losses_relative[t]
\delta(t) absolute fixed loss of energy per time unit 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)  

The following parts of the objective function are created:

Nothing added to the objective function.

CONSTRAINT_GROUP = True
class oemof.solph.components.OffsetTransformer(*args, **kwargs)[source]

Bases: oemof.network.network.Transformer

An object with one input and one output.

Parameters:coefficients (tuple) – 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.Bus(label='bel')
>>> bth = solph.Bus(label='bth')
>>> ostf = solph.components.OffsetTransformer(
...    label='ostf',
...    inputs={bel: solph.Flow(
...        nominal_value=60, min=0.5, max=1.0,
...        nonconvex=solph.NonConvex())},
...    outputs={bth: solph.Flow()},
...    coefficients=(20, 0.5))
>>> type(ostf)
<class 'oemof.solph.components.OffsetTransformer'>
constraint_group()[source]
class oemof.solph.components.OffsetTransformerBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for the relation of nodes with type OffsetTransformer

The following constraints are created:

&
P_{out}(t) = C_1(t) \cdot P_{in}(t) + C_0(t) \cdot Y(t) \\

Variables (V) and Parameters (P)
symbol attribute type explanation
P_{out}(t) flow[n, o, t] V Power of output
P_{in}(t) flow[i, n, t] V Power of input
Y(t) status[i, n, t] V binary status variable of nonconvex input flow
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)
CONSTRAINT_GROUP = True

oemof.solph.constraints module

Additional constraints to be used in an oemof energy model.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Patrik Schönfeldt SPDX-FileCopyrightText: Johannes Röder

SPDX-License-Identifier: MIT

oemof.solph.constraints.additional_investment_flow_limit(model, keyword, limit=None)[source]

Global limit for investment flows weighted by an attribute keyword.

This constraint is only valid for Flows not for components such as an investment storage.

The attribute named by keyword has to be added to every Investment attribute of the flow you want to take into account. Total value of keyword attributes after optimization can be retrieved calling the oemof.solph.Model.invest_limit_${keyword}().

Parameters:
  • model (oemof.solph.Model) – Model to which constraints are added.
  • keyword (attribute to consider) – All flows with Investment attribute containing the keyword will be used.
  • limit (numeric) – Global limit of keyword attribute for the energy system.

\sum_{i \in IF}  P_i \cdot w_i \leq limit

With IF being the set of InvestmentFlows considered for the integral limit.

The symbols used are defined as follows (with Variables (V) and Parameters (P)):

symbol attribute type explanation
P_{i} InvestmentFlow.invest[i, o] V installed capacity of investment flow
w_i keyword P weight given to investment flow named according to keyword
limit limit P global limit given by keyword limit

Note

The Investment attribute of the considered (Investment-)flows requires an attribute named like keyword!

Examples

>>> import pandas as pd
>>> from oemof import solph
>>> date_time_index = pd.date_range('1/1/2020', periods=5, freq='H')
>>> es = solph.EnergySystem(timeindex=date_time_index)
>>> bus = solph.Bus(label='bus_1')
>>> sink = solph.Sink(label="sink", inputs={bus:
...     solph.Flow(nominal_value=10, fix=[10, 20, 30, 40, 50])})
>>> src1 = solph.Source(label='source_0', outputs={bus: solph.Flow(
...     investment=solph.Investment(ep_costs=50, space=4))})
>>> src2 = solph.Source(label='source_1', outputs={bus: solph.Flow(
...     investment=solph.Investment(ep_costs=100, space=1))})
>>> es.add(bus, sink, src1, src2)
>>> model = solph.Model(es)
>>> model = solph.constraints.additional_investment_flow_limit(
...     model, "space", limit=1500)
>>> a = model.solve(solver="cbc")
>>> int(round(model.invest_limit_space()))
1500
oemof.solph.constraints.emission_limit(om, flows=None, limit=None)[source]

Short handle for generic_integral_limit() with keyword=”emission_factor”.

Note

Flow objects required an attribute “emission_factor”!

oemof.solph.constraints.equate_variables(model, var1, var2, factor1=1, name=None)[source]

Adds a constraint to the given model that set two variables to equal adaptable by a factor.

The following constraints are build:

var\textit{1} \cdot factor\textit{1} = var\textit{2}

Parameters:
  • var1 (pyomo.environ.Var) – First variable, to be set to equal with Var2 and multiplied with factor1.
  • var2 (pyomo.environ.Var) – Second variable, to be set equal to (Var1 * factor1).
  • factor1 (float) – Factor to define the proportion between the variables.
  • name (str) – Optional name for the equation e.g. in the LP file. By default the name is: equate + string representation of var1 and var2.
  • model (oemof.solph.Model) – Model to which the constraint is added.

Examples

The following example shows how to define a transmission line in the investment mode by connecting both investment variables. Note that the equivalent periodical costs (epc) of the line are 40. You could also add them to one line and set them to 0 for the other line.

>>> import pandas as pd
>>> from oemof import solph
>>> date_time_index = pd.date_range('1/1/2012', periods=5, freq='H')
>>> energysystem = solph.EnergySystem(timeindex=date_time_index)
>>> bel1 = solph.Bus(label='electricity1')
>>> bel2 = solph.Bus(label='electricity2')
>>> energysystem.add(bel1, bel2)
>>> energysystem.add(solph.Transformer(
...    label='powerline_1_2',
...    inputs={bel1: solph.Flow()},
...    outputs={bel2: solph.Flow(
...        investment=solph.Investment(ep_costs=20))}))
>>> energysystem.add(solph.Transformer(
...    label='powerline_2_1',
...    inputs={bel2: solph.Flow()},
...   outputs={bel1: solph.Flow(
...       investment=solph.Investment(ep_costs=20))}))
>>> om = solph.Model(energysystem)
>>> line12 = energysystem.groups['powerline_1_2']
>>> line21 = energysystem.groups['powerline_2_1']
>>> solph.constraints.equate_variables(
...    om,
...    om.InvestmentFlow.invest[line12, bel2],
...    om.InvestmentFlow.invest[line21, bel1])
oemof.solph.constraints.generic_integral_limit(om, keyword, flows=None, limit=None)[source]

Set a global limit for flows weighted by attribute called keyword. The attribute named by keyword has to be added to every flow you want to take into account.

Total value of keyword attributes after optimization can be retrieved calling the om.oemof.solph.Model.integral_limit_${keyword}().

Parameters:
  • om (oemof.solph.Model) – Model to which constraints are added.
  • flows (dict) – Dictionary holding the flows that should be considered in constraint. Keys are (source, target) objects of the Flow. If no dictionary is given all flows containing the keyword attribute will be used.
  • keyword (attribute to consider)
  • limit (numeric) – Absolute limit of keyword attribute for the energy system.

Note

Flow objects required an attribute named like keyword!

Constraint:

\sum_{i \in F_E} \sum_{t \in T} P_i(t) \cdot w_i(t)
\cdot \tau(t) \leq M

With F_I being the set of flows considered for the integral limit and T being the set of time steps.

The symbols used are defined as follows (with Variables (V) and Parameters (P)):

math. symbol type explanation
P_n(t) V power flow n at time step t
w_N(t) P weight given to Flow named according to keyword
\tau(t) P width of time step t
L P global limit given by keyword limit

Examples

>>> import pandas as pd
>>> from oemof import solph
>>> date_time_index = pd.date_range('1/1/2012', periods=5, freq='H')
>>> energysystem = solph.EnergySystem(timeindex=date_time_index)
>>> bel = solph.Bus(label='electricityBus')
>>> flow1 = solph.Flow(nominal_value=100, my_factor=0.8)
>>> flow2 = solph.Flow(nominal_value=50)
>>> src1 = solph.Source(label='source1', outputs={bel: flow1})
>>> src2 = solph.Source(label='source2', outputs={bel: flow2})
>>> energysystem.add(bel, src1, src2)
>>> model = solph.Model(energysystem)
>>> flow_with_keyword = {(src1, bel): flow1, }
>>> model = solph.constraints.generic_integral_limit(
...     model, "my_factor", flow_with_keyword, limit=777)
oemof.solph.constraints.investment_limit(model, limit=None)[source]

Set an absolute limit for the total investment costs of an investment optimization problem:

\sum_{investment\_costs} \leq limit

Parameters:
  • model (oemof.solph.Model) – Model to which the constraint is added
  • limit (float) – Absolute limit of the investment (i.e. RHS of constraint)
oemof.solph.constraints.limit_active_flow_count(model, constraint_name, flows, lower_limit=0, upper_limit=None)[source]

Set limits (lower and/or upper) for the number of concurrently active NonConvex flows. The flows are given as a list.

Total actual counts after optimization can be retrieved calling the om.oemof.solph.Model.$(constraint_name)_count().

Parameters:
  • model (oemof.solph.Model) – Model to which constraints are added
  • constraint_name (string) – name for the constraint
  • flows (list of flows) – flows (have to be NonConvex) in the format [(in, out)]
  • lower_limit (integer) – minimum number of active flows in the list
  • upper_limit (integer) – maximum number of active flows in the list
Returns:

the updated model

Note

Flow objects required to be NonConvex

Constraint:

N_{X,min} \le \sum_{n \in F} X_n(t)
\le N_{X,max} \forall t \in T

With F being the set of considered flows and T being the set of time steps.

The symbols used are defined as follows (with Variables (V) and Parameters (P)):

math. symbol type explanation
X_n(t) V status (0 or 1) of the flow n at time step t
N_{X,min} P lower_limit
N_{X,max} P lower_limit
oemof.solph.constraints.limit_active_flow_count_by_keyword(model, keyword, lower_limit=0, upper_limit=None)[source]

This wrapper for limit_active_flow_count allows to set limits to the count of concurrently active flows by using a keyword instead of a list. The constraint will be named $(keyword)_count.

Parameters:
  • model (oemof.solph.Model) – Model to which constraints are added
  • keyword (string) – keyword to consider (searches all NonConvexFlows)
  • lower_limit (integer) – minimum number of active flows having the keyword
  • upper_limit (integer) – maximum number of active flows having the keyword
Returns:

the updated model

See also

limit_active_flow_count(), constraint_name(), flows()

oemof.solph.constraints.shared_limit(model, quantity, limit_name, components, weights, lower_limit=0, upper_limit=None)[source]

Adds a constraint to the given model that restricts the weighted sum of variables to a corridor.

The following constraints are build:

l_\mathrm{low} \le \sum v_i(t) \times w_i(t) \le l_\mathrm{up}
\forall t

Parameters:
  • model (oemof.solph.Model) – Model to which the constraint is added.
  • limit_name (string) – Name of the constraint to create
  • quantity (pyomo.core.base.var.IndexedVar) – Shared Pyomo variable for all components of a type.
  • components (list of components) – list of components of the same type
  • weights (list of numeric values) – has to have the same length as the list of components
  • lower_limit (numeric) – the lower limit
  • upper_limit (numeric) – the lower limit

Examples

The constraint can e.g. be used to define a common storage that is shared between parties but that do not exchange energy on balance sheet. Thus, every party has their own bus and storage, respectively, to model the energy flow. However, as the physical storage is shared, it has a common limit.

>>> import pandas as pd
>>> from oemof import solph
>>> date_time_index = pd.date_range('1/1/2012', periods=5, freq='H')
>>> energysystem = solph.EnergySystem(timeindex=date_time_index)
>>> b1 = solph.Bus(label="Party1Bus")
>>> b2 = solph.Bus(label="Party2Bus")
>>> storage1 = solph.components.GenericStorage(
...     label="Party1Storage",
...     nominal_storage_capacity=5,
...     inputs={b1: solph.Flow()},
...     outputs={b1: solph.Flow()})
>>> storage2 = solph.components.GenericStorage(
...     label="Party2Storage",
...     nominal_storage_capacity=5,
...     inputs={b1: solph.Flow()},
...     outputs={b1: solph.Flow()})
>>> energysystem.add(b1, b2, storage1, storage2)
>>> components = [storage1, storage2]
>>> model = solph.Model(energysystem)
>>> solph.constraints.shared_limit(
...    model,
...    model.GenericStorageBlock.storage_content,
...    "limit_storage", components,
...    [1, 1], upper_limit=5)

oemof.solph.console_scripts module

This module can be used to check the installation.

This is not an illustrated example.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: jnnr

SPDX-License-Identifier: MIT

oemof.solph.console_scripts.check_oemof_installation(silent=False)[source]

oemof.solph.custom module

This module is designed to hold custom components with their classes and associated individual constraints (blocks) and groupings.

Therefore this module holds the class definition and the block directly located by each other.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Patrik Schönfeldt SPDX-FileCopyrightText: Johannes Röder SPDX-FileCopyrightText: jakob-wo SPDX-FileCopyrightText: gplssm

SPDX-License-Identifier: MIT

class oemof.solph.custom.ElectricalBus(*args, **kwargs)[source]

Bases: oemof.solph.network.Bus

A electrical bus object. Every node has to be connected to Bus. This Bus is used in combination with ElectricalLine objects for linear optimal power flow (lopf) calculations.

Parameters:
  • slack (boolean) – If True Bus is slack bus for network
  • v_max (numeric) – Maximum value of voltage angle at electrical bus
  • v_min (numeric) – Mininum value of voltag angle at electrical bus
  • Note (This component is experimental. Use it with care.)

Notes

The following sets, variables, constraints and objective parts are created
The objects are also used inside:
class oemof.solph.custom.ElectricalLine(*args, **kwargs)[source]

Bases: oemof.solph.network.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
constraint_group()[source]
class oemof.solph.custom.ElectricalLineBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

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]

flow(n, o, t) =  1 / reactance(n, t) \\cdot ()
voltage_angle(i(n), t) - volatage_angle(o(n), t), \\
\forall t \\in \\textrm{TIMESTEPS}, \\
\forall n \\in \\textrm{ELECTRICAL\_LINES}.

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
class oemof.solph.custom.GenericCAES(*args, **kwargs)[source]

Bases: oemof.network.network.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

TODO: Add description for constraints. See referenced paper until then!

Examples

>>> from oemof import solph
>>> bel = solph.Bus(label='bel')
>>> bth = solph.Bus(label='bth')
>>> bgas = solph.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.custom.GenericCAES(
...    label='caes',
...    electrical_input={bel: solph.Flow()},
...    fuel_input={bgas: solph.Flow()},
...    electrical_output={bel: solph.Flow()},
...    params=concept, fixed_costs=0)
>>> type(caes)
<class 'oemof.solph.custom.GenericCAES'>
constraint_group()[source]
class oemof.solph.custom.GenericCAESBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for nodes of class:.GenericCAES.

Note: This component is experimental. Use it with care.

The following constraints are created:

&
(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 \\
&

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 expansion and 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], n, t] P Electr. power input into compression
electrical\_output flow[n, list(n.electrical_output.keys())[0], t] P Electr. power output of expansion
fuel\_input flow[list(n.fuel_input.keys())[0], n, t] P
Heat input
(external) into Expansion
CONSTRAINT_GROUP = True

Bases: oemof.solph.network.Transformer

A Link object with 1…2 inputs and 1…2 outputs.

Parameters:
  • 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.
  • Note (This component is experimental. Use it with care.)

Notes

The sets, variables, constraints and objective parts are created

Examples

>>> from oemof import solph
>>> bel0 = solph.Bus(label="el0")
>>> bel1 = solph.Bus(label="el1")
>>> link = solph.custom.Link(
...    label="transshipment_link",
...    inputs={bel0: solph.Flow(), bel1: solph.Flow()},
...    outputs={bel0: solph.Flow(), bel1: solph.Flow()},
...    conversion_factors={(bel0, bel1): 0.92, (bel1, bel0): 0.99})
>>> print(sorted([x[1][5] for x in link.conversion_factors.items()]))
[0.92, 0.99]
>>> type(link)
<class 'oemof.solph.custom.Link'>
>>> sorted([str(i) for i in link.inputs])
['el0', 'el1']
>>> link.conversion_factors[(bel0, bel1)][3]
0.92
constraint_group()[source]
class oemof.solph.custom.LinkBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Block for the relation of nodes with type Link

Note: This component is experimental. Use it with care.

The following constraints are created:

TODO: Add description for constraints TODO: Add tests

CONSTRAINT_GROUP = True
class oemof.solph.custom.SinkDSM(demand, capacity_up, capacity_down, method, shift_interval=None, delay_time=None, cost_dsm_up=0, cost_dsm_down=0, **kwargs)[source]

Bases: oemof.solph.network.Sink

Demand Side Management implemented as Sink with flexibility potential.

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 17.09.2019, pp. 842-843.

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

  • capacity_up (int or array) – maximum DSM capacity that may be increased

  • capacity_down (int or array) – maximum DSM capacity that may be reduced

  • method (‘interval’ , ‘delay’) – Choose one of the DSM modelling approaches. Read notes about which parameters to be applied for which approach.

    interval :

    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. See SinkDSMIntervalBlock for details.

    delay :

    Sophisticated model based on the formulation by Zerrahn & Schill (2015). The load-shift of the component must be compensated in a predefined delay-time (delay_time is mandatory). For details see SinkDSMDelayBlock.

  • shift_interval (int) – Only used when method is set to ‘interval’. 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) – Only used when method is set to ‘delay’. Otherwise, can be None. Length of symmetrical time windows around t in which DSM_{t}^{up} and DSM_{t,tt}^{down} have to be compensated.

  • cost_dsm_up (int) – Cost per unit of DSM activity that increases the demand

  • cost_dsm_down (int) – Cost per unit of DSM activity that decreases the demand

Note

  • This component is a candidate component. It’s implemented as a custom component for users that like to use and test the component at early stage. Please report issues to improve the component.
  • As many constraints and dependencies are created in method ‘delay’, computational cost might be high with a large ‘delay_time’ and with model of high temporal resolution
  • Using method ‘delay’ 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.
  • 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
constraint_group()[source]
class oemof.solph.custom.SinkDSMDelayBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Constraints for SinkDSM with “delay” method

The following constraints are created for method = ‘delay’:

&
(1) \quad \dot{E}_{t} = demand_{t} + DSM_{t}^{up} -
\sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do}  \quad \forall t \in \mathbb{T} \\
&
(2) \quad DSM_{t}^{up} = \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do}
\quad \forall t \in \mathbb{T} \\
&
(3) \quad DSM_{t}^{up} \leq  E_{t}^{up} \quad \forall t \in
\mathbb{T} \\
&
(4) \quad \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do}  \leq E_{t}^{do}
\quad \forall t \in \mathbb{T} \\
&
(5) \quad DSM_{t}^{up}  + \sum_{tt=t-L}^{t+L} DSM_{t,tt}^{do}
\leq max \{ E_{t}^{up}, E_{t}^{do} \}\quad \forall t \in \mathbb{T} \\
&

Table: Symbols and attribute names of variables and parameters

Variables (V) and Parameters (P)
symbol attribute type explanation
DSM_{t}^{up} dsm_do[g,t,tt] V DSM up shift (additional load)
DSM_{t,tt}^{do} dsm_up[g,t] V DSM down shift (less load)
\dot{E}_{t} flow[g,t] V Energy flowing in from electrical bus
L delay_time P Delay time for load shift
demand_{t} demand[t] P Electrical demand series
E_{t}^{do} capacity_down[tt] P Capacity DSM down shift
E_{t}^{up} capacity_up[tt] P Capacity DSM up shift
\mathbb{T}   P Time steps
CONSTRAINT_GROUP = True
class oemof.solph.custom.SinkDSMIntervalBlock(*args, **kwargs)[source]

Bases: pyomo.core.base.block.SimpleBlock

Constraints for SinkDSM with “interval” method

The following constraints are created for method = ‘interval’:

&
(1) \quad \dot{E}_{t} = demand_{t} + DSM_{t}^{up} - DSM_{t}^{do}
\quad \forall t \in \mathbb{T}\\
&
(2) \quad  DSM_{t}^{up} \leq E_{t}^{up} \quad \forall t \in
\mathbb{T}\\
&
(3) \quad DSM_{t}^{do} \leq  E_{t}^{do} \quad \forall t \in
\mathbb{T}\\
&
(4) \quad  \sum_{t=t_s}^{t_s+\tau} DSM_{t}^{up} =
\sum_{t=t_s}^{t_s+\tau} DSM_{t}^{do} \quad \forall t_s \in \{k
\in \mathbb{T} \mid k \mod \tau = 0\} \\
&

Table: Symbols and attribute names of variables and parameters

Variables (V) and Parameters (P)
symbol attribute type explanation
DSM_{t}^{up} capacity_up V DSM up shift
DSM_{t}^{do} capacity_down V DSM down shift
\dot{E}_{t} inputs V Energy flowing in from electrical bus
demand_{t} demand[t] P Electrical demand series
E_{t}^{do} capacity_down[tt] P Capacity DSM down shift capacity
E_{t}^{up} capacity_up[tt] P Capacity DSM up shift
\tau shift_interval P Shift interval
\mathbb{T}   P Time steps
CONSTRAINT_GROUP = True

oemof.solph.groupings module

Groupings needed on an energy system for it to work with solph.

If you want to use solph on an energy system, you need to create it with these groupings specified like this:

from oemof.network import EnergySystem import solph

energy_system = EnergySystem(groupings=solph.GROUPINGS)

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Stephan Günther

SPDX-License-Identifier: MIT

oemof.solph.groupings.constraint_grouping(node, fallback=<function <lambda>>)[source]

Grouping function for constraints.

This function can be passed in a list to groupings of oemof.solph.network.EnergySystem.

Parameters:
  • node (Node <oemof.network.Node) – The node for which the figure out a constraint group.
  • fallback (callable, optional) – A function of one argument. If node doesn’t have a constraint_group attribute, this is used to group the node instead. Defaults to not group the node at all.

oemof.solph.helpers module

This is a collection of helper functions which work on their own and can be used by various classes. If there are too many helper-functions, they will be sorted in different modules.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Caroline Möller SPDX-FileCopyrightText: henhuy SPDX-FileCopyrightText: gplssm SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: elisapap

SPDX-License-Identifier: MIT

oemof.solph.helpers.calculate_timeincrement(timeindex, fill_value=None)[source]

Calculates timeincrement for timeindex

Parameters:
  • timeindex (pd.DatetimeIndex) – timeindex of energysystem
  • fill_value (numerical) – timeincrement for first timestep in hours
oemof.solph.helpers.extend_basic_path(subfolder)[source]

Returns a path based on the basic oemof path and creates it if necessary. The subfolder is the name of the path extension.

oemof.solph.helpers.flatten(d, parent_key='', sep='_')[source]

Flatten dictionary by compressing keys.

See: https://stackoverflow.com/questions/6027558/
flatten-nested-python-dictionaries-compressing-keys

d : dictionary sep : separator for flattening keys

Returns:dict
oemof.solph.helpers.get_basic_path()[source]

Returns the basic oemof path and creates it if necessary. The basic path is the ‘.oemof’ folder in the $HOME directory.

oemof.solph.models module

Solph Optimization Models.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: gplssm

SPDX-License-Identifier: MIT

class oemof.solph.models.BaseModel(energysystem, **kwargs)[source]

Bases: pyomo.core.base.PyomoModel.ConcreteModel

The BaseModel for other solph-models (Model, MultiPeriodModel, etc.)

Parameters:
  • energysystem (EnergySystem object) – Object that holds the nodes of an oemof energy system graph
  • constraint_groups (list (optional)) – Solph looks for these groups in the given energy system and uses them to create the constraints of the optimization problem. Defaults to Model.CONSTRAINTS
  • objective_weighting (array like (optional)) – Weights used for temporal objective function expressions. If nothing is passed timeincrement will be used which is calculated from the freq length of the energy system timeindex .
  • auto_construct (boolean) – If this value is true, the set, variables, constraints, etc. are added, automatically when instantiating the model. For sequential model building process set this value to False and use methods _add_parent_block_sets, _add_parent_block_variables, _add_blocks, _add_objective
  • Attributes
  • ———–
  • timeincrement (sequence) – Time increments.
  • flows (dict) – Flows of the model.
  • name (str) – Name of the model.
  • es (solph.EnergySystem) – Energy system of the model.
  • meta (pyomo.opt.results.results_.SolverResults or None) – Solver results.
  • dual (… or None)
  • rc (… or None)
CONSTRAINT_GROUPS = []
receive_duals()[source]

Method sets solver suffix to extract information about dual variables from solver. Shadow prices (duals) and reduced costs (rc) are set as attributes of the model.

relax_problem()[source]

Relaxes integer variables to reals of optimization model self.

results()[source]

Returns a nested dictionary of the results of this optimization

solve(solver='cbc', solver_io='lp', **kwargs)[source]

Takes care of communication with solver to solve the model.

Parameters:
  • solver (string) – solver to be used e.g. “glpk”,”gurobi”,”cplex”
  • solver_io (string) – pyomo solver interface file format: “lp”,”python”,”nl”, etc.
  • **kwargs (keyword arguments) – Possible keys can be set see below:
Other Parameters:
 
  • solve_kwargs (dict) – Other arguments for the pyomo.opt.SolverFactory.solve() method Example : {“tee”:True}
  • cmdline_options (dict) – Dictionary with command line options for solver e.g. {“mipgap”:”0.01”} results in “–mipgap 0.01” {“interior”:” “} results in “–interior” Gurobi solver takes numeric parameter values such as {“method”: 2}
class oemof.solph.models.Model(energysystem, **kwargs)[source]

Bases: oemof.solph.models.BaseModel

An energy system model for operational and investment optimization.

Parameters:
  • energysystem (EnergySystem object) – Object that holds the nodes of an oemof energy system graph
  • constraint_groups (list) – Solph looks for these groups in the given energy system and uses them to create the constraints of the optimization problem. Defaults to Model.CONSTRAINTS
  • **The following basic sets are created**
  • NODES – A set with all nodes of the given energy system.
  • TIMESTEPS – A set with all timesteps of the given time horizon.
  • FLOWS – A 2 dimensional set with all flows. Index: (source, target)
  • **The following basic variables are created**
  • flow – Flow from source to target indexed by FLOWS, TIMESTEPS. Note: Bounds of this variable are set depending on attributes of the corresponding flow object.
CONSTRAINT_GROUPS = [<class 'oemof.solph.blocks.Bus'>, <class 'oemof.solph.blocks.Transformer'>, <class 'oemof.solph.blocks.InvestmentFlow'>, <class 'oemof.solph.blocks.Flow'>, <class 'oemof.solph.blocks.NonConvexFlow'>]

oemof.solph.network module

Classes used to model energy supply systems within solph.

Classes are derived from oemof core network classes and adapted for specific optimization tasks. An energy system is modelled as a graph/network of nodes with very specific constraints on which types of nodes are allowed to be connected.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: Birgit Schachler

SPDX-License-Identifier: MIT

class oemof.solph.network.Bus(*args, **kwargs)[source]

Bases: oemof.network.network.Bus

A balance object. Every node has to be connected to Bus.

Notes

The following sets, variables, constraints and objective parts are created
constraint_group()[source]
class oemof.solph.network.EnergySystem(**kwargs)[source]

Bases: oemof.network.energy_system.EnergySystem

A variant of EnergySystem specially tailored to solph.

In order to work in tandem with solph, instances of this class always use solph.GROUPINGS <oemof.solph.GROUPINGS>. If custom groupings are supplied via the groupings keyword argument, solph.GROUPINGS <oemof.solph.GROUPINGS> is prepended to those.

If you know what you are doing and want to use solph without solph.GROUPINGS <oemof.solph.GROUPINGS>, you can just use core's EnergySystem directly.

class oemof.solph.network.Flow(**kwargs)[source]

Bases: oemof.network.network.Edge

Defines a flow between two nodes.

Keyword arguments are used to set the attributes of this flow. Parameters which are handled specially are noted below. For the case where a parameter can be either a scalar or an iterable, a scalar value will be converted to a sequence containing the scalar value at every index. This sequence is then stored under the paramter’s key.

Parameters:
  • nominal_value (numeric, P_{nom}) – The nominal value of the flow. If this value is set the corresponding optimization variable of the flow object will be bounded by this value multiplied with min(lower bound)/max(upper bound).

  • max (numeric (iterable or scalar), f_{max}) – Normed maximum value of the flow. The flow absolute maximum will be calculated by multiplying nominal_value with max

  • min (numeric (iterable or scalar), f_{min}) – Normed minimum value of the flow (see max).

  • fix (numeric (iterable or scalar), f_{actual}) – Normed fixed value for the flow variable. Will be multiplied with the nominal_value to get the absolute value. If fixed is set to True the flow variable will be fixed to fix * nominal_value, i.e. this value is set exogenous.

  • positive_gradient (dict, default: {‘ub’: None, ‘costs’: 0}) –

    A dictionary containing the following two keys:

    • ‘ub’: numeric (iterable, scalar or None), the normed upper bound on the positive difference (flow[t-1] < flow[t]) of two consecutive flow values.
    • ‘costs`: numeric (scalar or None), the gradient cost per unit.
  • negative_gradient (dict, default: {‘ub’: None, ‘costs’: 0}) –

    A dictionary containing the following two keys:

    • ‘ub’: numeric (iterable, scalar or None), the normed upper bound on the negative difference (flow[t-1] > flow[t]) of two consecutive flow values.
    • ‘costs`: numeric (scalar or None), the gradient cost per unit.
  • summed_max (numeric, f_{sum,max}) – Specific maximum value summed over all timesteps. Will be multiplied with the nominal_value to get the absolute limit.

  • summed_min (numeric, f_{sum,min}) – see above

  • variable_costs (numeric (iterable or scalar)) – The costs associated with one unit of the flow. If this is set the costs will be added to the objective expression of the optimization problem.

  • fixed (boolean) – Boolean value indicating if a flow is fixed during the optimization problem to its ex-ante set value. Used in combination with the fix.

  • investment (Investment) – 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_value. The nominal_value should not be set (or set to None) if an investment object is used.

  • nonconvex (NonConvex) – If a nonconvex flow object is added here, the flow constraints will be altered significantly as the mathematical model for the flow will be different, i.e. constraint etc. from NonConvexFlow will be used instead of Flow. Note: at the moment this does not work if the investment attribute is set .

Notes

The following sets, variables, constraints and objective parts are created

Examples

Creating a fixed flow object:

>>> f = Flow(fix=[10, 4, 4], variable_costs=5)
>>> f.variable_costs[2]
5
>>> f.fix[2]
4

Creating a flow object with time-depended lower and upper bounds:

>>> f1 = Flow(min=[0.2, 0.3], max=0.99, nominal_value=100)
>>> f1.max[1]
0.99
class oemof.solph.network.Sink(*args, **kwargs)[source]

Bases: oemof.network.network.Sink

An object with one input flow.

constraint_group()[source]
class oemof.solph.network.Source(*args, **kwargs)[source]

Bases: oemof.network.network.Source

An object with one output flow.

constraint_group()[source]
class oemof.solph.network.Transformer(*args, **kwargs)[source]

Bases: oemof.network.network.Transformer

A linear Transformer object with n inputs and n outputs.

Parameters:conversion_factors (dict) – Dictionary containing conversion factors for conversion of each flow. Keys are the connected bus objects. The dictionary values can either be a scalar or an iterable with length of time horizon for simulation.

Examples

Defining an linear transformer:

>>> from oemof import solph
>>> bgas = solph.Bus(label='natural_gas')
>>> bcoal = solph.Bus(label='hard_coal')
>>> bel = solph.Bus(label='electricity')
>>> bheat = solph.Bus(label='heat')
>>> trsf = solph.Transformer(
...    label='pp_gas_1',
...    inputs={bgas: solph.Flow(), bcoal: solph.Flow()},
...    outputs={bel: solph.Flow(), bheat: solph.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.network.Transformer'>
>>> sorted([str(i) for i in trsf.inputs])
['hard_coal', 'natural_gas']
>>> trsf_new = solph.Transformer(
...    label='pp_gas_2',
...    inputs={bgas: solph.Flow()},
...    outputs={bel: solph.Flow(), bheat: solph.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
constraint_group()[source]

oemof.solph.options module

Optional classes to be added to a network class.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: Patrik Schönfeldt SPDX-FileCopyrightText: jmloenneberga

SPDX-License-Identifier: MIT

class oemof.solph.options.Investment(maximum=inf, minimum=0, ep_costs=0, existing=0, nonconvex=False, offset=0, **kwargs)[source]

Bases: object

Parameters:
  • maximum (float, P_{invest,max} or E_{invest,max}) – Maximum of the additional invested capacity
  • minimum (float, P_{invest,min} or E_{invest,min}) – Minimum of the additional invested capacity. If nonconvex is True, minimum defines the threshold for the invested capacity.
  • ep_costs (float, c_{invest,var}) – Equivalent periodical costs for the investment per flow capacity.
  • existing (float, P_{exist} or E_{exist}) – Existing / installed capacity. The invested capacity is added on top of this value. Not applicable if nonconvex is set to True.
  • nonconvex (bool) – If True, a binary variable for the status of the investment is created. This enables additional fix investment costs (offset) independent of the invested flow capacity. Therefore, use the offset parameter.
  • offset (float, c_{invest,fix}) – Additional fix investment costs. Only applicable if nonconvex is set to True.

For the variables, constraints and parts of the objective function, which are created, see oemof.solph.blocks.InvestmentFlow and oemof.solph.components.GenericInvestmentStorageBlock.

class oemof.solph.options.NonConvex(**kwargs)[source]

Bases: object

Parameters:
  • startup_costs (numeric (iterable or scalar)) – Costs associated with a start of the flow (representing a unit).
  • shutdown_costs (numeric (iterable or scalar)) – Costs associated with the shutdown of the flow (representing a unit).
  • activity_costs (numeric (iterable or scalar)) – Costs associated with the active operation of the flow, independently from the actual output.
  • minimum_uptime (numeric (1 or positive integer)) – Minimum time that a flow must be greater then its minimum flow after startup. Be aware that minimum up and downtimes can contradict each other and may lead to infeasible problems.
  • minimum_downtime (numeric (1 or positive integer)) – Minimum time a flow is forced to zero after shutting down. Be aware that minimum up and downtimes can contradict each other and may to infeasible problems.
  • maximum_startups (numeric (0 or positive integer)) – Maximum number of start-ups.
  • maximum_shutdowns (numeric (0 or positive integer)) – Maximum number of shutdowns.
  • initial_status (numeric (0 or 1)) – Integer value indicating the status of the flow in the first time step (0 = off, 1 = on). For minimum up and downtimes, the initial status is set for the respective values in the edge regions e.g. if a minimum uptime of four timesteps is defined, the initial status is fixed for the four first and last timesteps of the optimization period. If both, up and downtimes are defined, the initial status is set for the maximum of both e.g. for six timesteps if a minimum downtime of six timesteps is defined in addition to a four timestep minimum uptime.
max_up_down

Compute or return the _max_up_down attribute.

oemof.solph.plumbing module

Plumbing stuff.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: henhuy

SPDX-License-Identifier: MIT

oemof.solph.plumbing.sequence(iterable_or_scalar)[source]

Tests if an object is iterable (except string) or scalar and returns a the original sequence if object is an iterable and a ‘emulated’ sequence object of class _Sequence if object is a scalar or string.

Parameters:iterable_or_scalar (iterable or None or int or float)

Examples

>>> sequence([1,2])
[1, 2]
>>> x = sequence(10)
>>> x[0]
10
>>> x[10]
10
>>> print(x)
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

oemof.solph.processing module

Modules for providing a convenient data structure for solph results.

Information about the possible usage is provided within the examples.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: henhuy

SPDX-License-Identifier: MIT

oemof.solph.processing.convert_keys_to_strings(result, keep_none_type=False)[source]

Convert the dictionary keys to strings.

All (tuple) keys of the result object e.g. results[(pp1, bus1)] are converted into strings that represent the object labels e.g. results[(‘pp1’,’bus1’)].

oemof.solph.processing.create_dataframe(om)[source]

Create a result dataframe with all optimization data.

Results from Pyomo are written into pandas DataFrame where separate columns are created for the variable index e.g. for tuples of the flows and components or the timesteps.

oemof.solph.processing.get_timestep(x)[source]

Get the timestep from oemof tuples.

The timestep from tuples (n, n, int), (n, n), (n, int) and (n,) is fetched as the last element. For time-independent data (scalars) zero ist returned.

oemof.solph.processing.get_tuple(x)[source]

Get oemof tuple within iterable or create it.

Tuples from Pyomo are of type (n, n, int), (n, n) and (n, int). For single nodes n a tuple with one object (n,) is created.

oemof.solph.processing.meta_results(om, undefined=False)[source]

Fetch some meta data from the Solver. Feel free to add more keys.

Valid keys of the resulting dictionary are: ‘objective’, ‘problem’, ‘solver’.

om : oemof.solph.Model
A solved Model.
undefined : bool
By default (False) only defined keys can be found in the dictionary. Set to True to get also the undefined keys.
Returns:dict
oemof.solph.processing.parameter_as_dict(system, exclude_none=True)[source]

Create a result dictionary containing node parameters.

Results are written into a dictionary of pandas objects where a Series holds all scalar values and a dataframe all sequences for nodes and flows. The dictionary is keyed by flows (n, n) and nodes (n, None), e.g. parameter[(n, n)][‘sequences’] or parameter[(n, n)][‘scalars’].

Parameters:
  • system (energy_system.EnergySystem) – A populated energy system.
  • exclude_none (bool) – If True, all scalars and sequences containing None values are excluded
Returns:

dict (Parameters for all nodes and flows)

oemof.solph.processing.remove_timestep(x)[source]

Remove the timestep from oemof tuples.

The timestep is removed from tuples of type (n, n, int) and (n, int).

oemof.solph.processing.results(om)[source]

Create a result dictionary from the result DataFrame.

Results from Pyomo are written into a dictionary of pandas objects where a Series holds all scalar values and a dataframe all sequences for nodes and flows. The dictionary is keyed by the nodes e.g. results[idx][‘scalars’] and flows e.g. results[n, n][‘sequences’].

oemof.solph.views module

Modules for providing convenient views for solph results.

Information about the possible usage is provided within the examples.

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de> SPDX-FileCopyrightText: Simon Hilpert SPDX-FileCopyrightText: Cord Kaldemeyer SPDX-FileCopyrightText: Stephan Günther SPDX-FileCopyrightText: henhuy

SPDX-License-Identifier: MIT

class oemof.solph.views.NodeOption[source]

Bases: str, enum.Enum

An enumeration.

All = 'all'
HasInputs = 'has_inputs'
HasOnlyInputs = 'has_only_inputs'
HasOnlyOutputs = 'has_only_outputs'
HasOutputs = 'has_outputs'
oemof.solph.views.convert_to_multiindex(group, index_names=None, droplevel=None)[source]

Convert dict to pandas DataFrame with multiindex

Parameters:
  • group (dict) – Sequences of the oemof.solph.Model.results dictionary
  • index_names (arraylike) – Array with names of the MultiIndex
  • droplevel (arraylike) – List containing levels to be dropped from the dataframe
oemof.solph.views.filter_nodes(results, option=<NodeOption.All: 'all'>, exclude_busses=False)[source]

Get set of nodes from results-dict for given node option.

This function filters nodes from results for special needs. At the moment, the following options are available:

Additionally, busses can be excluded by setting exclude_busses to True.

Parameters:
  • results (dict)
  • option (NodeOption)
  • exclude_busses (bool) – If set, all bus nodes are excluded from the resulting node set.
Returns:

set – A set of Nodes.

oemof.solph.views.get_node_by_name(results, *names)[source]

Searches results for nodes

Names are looked up in nodes from results and either returned single node (in case only one name is given) or as list of nodes. If name is not found, None is returned.

oemof.solph.views.net_storage_flow(results, node_type)[source]

Calculates the net storage flow for storage models that have one input edge and one output edge both with flows within the domain of non-negative reals.

Parameters:
  • results (dict) – A result dictionary from a solved oemof.solph.Model object
  • node_type (oemof.solph class) – Specifies the type for which (storage) type net flows are calculated
Returns:

  • pandas.DataFrame object with multiindex colums. Names of levels of columns
  • are (from, to, net_flow.)

Examples

import oemof.solph as solph from oemof.outputlib import views

# solve oemof solph model ‘m’ # Then collect node weights views.net_storage_flow(m.results(), node_type=solph.GenericStorage)

oemof.solph.views.node(results, node, multiindex=False, keep_none_type=False)[source]

Obtain results for a single node e.g. a Bus or Component.

Either a node or its label string can be passed. Results are written into a dictionary which is keyed by ‘scalars’ and ‘sequences’ holding respective data in a pandas Series and DataFrame.

oemof.solph.views.node_input_by_type(results, node_type, droplevel=None)[source]

Gets all inputs for all nodes of the type node_type and returns a dataframe.

Parameters:
  • results (dict) – A result dictionary from a solved oemof.solph.Model object
  • node_type (oemof.solph class) – Specifies the type of the node for that inputs are selected
  • droplevel (list)

Notes

from oemof import solph from oemof.outputlib import views

# solve oemof solph model ‘m’ # Then collect node weights views.node_input_by_type(m.results(), node_type=solph.Sink)

oemof.solph.views.node_output_by_type(results, node_type, droplevel=None)[source]

Gets all outputs for all nodes of the type node_type and returns a dataframe.

Parameters:
  • results (dict) – A result dictionary from a solved oemof.solph.Model object
  • node_type (oemof.solph class) – Specifies the type of the node for that outputs are selected
  • droplevel (list)

Notes

import oemof.solph as solph from oemof.outputlib import views

# solve oemof solph model ‘m’ # Then collect node weights views.node_output_by_type(m.results(), node_type=solph.Transformer)

oemof.solph.views.node_weight_by_type(results, node_type)[source]

Extracts node weights (if exist) of all components of the specified node_type.

Node weight are endogenous optimzation variables associated with the node and not the edge between two node, foxample the variable representing the storage level.

Parameters:
  • results (dict) – A result dictionary from a solved oemof.solph.Model object
  • node_type (oemof.solph class) – Specifies the type for which node weights should be collected

Example

from oemof.outputlib import views

# solve oemof model ‘m’ # Then collect node weights views.node_weight_by_type(m.results(), node_type=solph.GenericStorage)