oemof.solph.constraints

Additional constraints to be used in an oemof energy model.

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._models.Model.invest_limit_${keyword}().

\[\sum_{p \in \textrm{PERIODS}} \sum_{i \in IF} P_{i}(p) \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}(p)\)

InvestmentFlowBlock.invest[i, o, p]

V

invested capacity of investment flow in period p

\(w_i\)

keyword

P

weight given to investment flow named according to keyword

\(limit\)

limit

P

global limit given by keyword limit

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.

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=6, freq='H')
>>> es = solph.EnergySystem(
...     timeindex=date_time_index,
...     infer_last_interval=False,
... )
>>> bus = solph.buses.Bus(label='bus_1')
>>> sink = solph.components.Sink(label="sink", inputs={bus:
...     solph.flows.Flow(nominal_value=10, fix=[10, 20, 30, 40, 50])})
>>> src1 = solph.components.Source(
...     label='source_0', outputs={bus: solph.flows.Flow(
...         nominal_value=solph.Investment(
...             ep_costs=50, custom_attributes={"space": 4},
...         ))
...     })
>>> src2 = solph.components.Source(
...     label='source_1', outputs={bus: solph.flows.Flow(
...         nominal_value=solph.Investment(
...              ep_costs=100, custom_attributes={"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”. Can be used to impose an emissions budget limit in a multi-period model.

Note

Flow objects require an attribute “emission_factor”!

oemof.solph.constraints.equate_flows(model, flows1, flows2, factor1=1, name='equate_flows')[source]

Adds a constraint to the given model that sets the sum of two groups of flows equal or proportional by a factor for each timestep.

The following constraints are built:

\[\text{factor\_1} \cdot \sum_{\text{flow in flows1}} \text{flow}_{t} = \sum_{\text{flow in flows2}} \text{flow}_t \forall t\]
Parameters:
  • model (oemof.solph.Model) – Model to which the constraint is added.

  • flows1 (iterable) – First group of flows, to be set to equal with Var2 and multiplied with factor1.

  • flows2 (iterable) – Second group of flows, to be set equal to (Var1 * factor1).

  • factor1 (numeric, default=1) – Factor to define the proportion between the two groups.

  • name (str, default=’equate_flows’) – Name for the equation e.g. in the LP file.

Returns:

the updated model.

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

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

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._models.Model) – Model to which the constraint is added.

The following constraints are build:

\[var_1 \cdot factor_1 = var_1\]

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

symbol

attribute

type

explanation

\(var_1\)

pyomo.environ.Var`

V

First variable, to be set to equal with \(var_2\) and \(var_1\) multiplied with \(factor_1\)

\(var_2\)

pyomo.environ.Var`

V

Second variable, to be set equal to \(var_1 \cdot factor_1\)

\(factor_1\)

float

P

Factor to define the proportion between the variables. The default value is 1.

name

str

P

Optional name for the equation e.g. in the LP file.
By default the name is: equate + string representation of \(var_1\) and \(var_2\).

model

oemof.solph.Model

P

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=6, freq='H')
>>> energysystem = solph.EnergySystem(
...     timeindex=date_time_index,
...     infer_last_interval=False,
... )
>>> bel1 = solph.buses.Bus(label='electricity1')
>>> bel2 = solph.buses.Bus(label='electricity2')
>>> energysystem.add(bel1, bel2)
>>> energysystem.add(solph.components.Converter(
...    label='powerline_1_2',
...    inputs={bel1: solph.flows.Flow()},
...    outputs={bel2: solph.flows.Flow(
...        nominal_value=solph.Investment(ep_costs=20))}))
>>> energysystem.add(solph.components.Converter(
...    label='powerline_2_1',
...    inputs={bel2: solph.flows.Flow()},
...    outputs={bel1: solph.flows.Flow(
...        nominal_value=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.InvestmentFlowBlock.invest[line12, bel2, 0],
...    om.InvestmentFlowBlock.invest[line21, bel1, 0])
oemof.solph.constraints.generic_integral_limit(om, keyword, flows=None, limit=None)[source]

Set a global limit for flows weighted by attribute named keyword. The attribute named 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._models.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 (string) – attribute to consider

  • limit (numeric) – Absolute limit of keyword attribute for the energy system.

Note

Flow objects require an attribute named like keyword!

Constraint:

\[\sum_{i \in F_E} \sum_{t \in T} P_i(p, 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(p, t)\)

V

power flow \(n\) at time index \(p, 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=6, freq='H')
>>> energysystem = solph.EnergySystem(
...     timeindex=date_time_index,
...     infer_last_interval=False,
... )
>>> bel = solph.buses.Bus(label='electricityBus')
>>> flow1 = solph.flows.Flow(
...     nominal_value=100,
...     custom_attributes={"my_factor": 0.8},
... )
>>> flow2 = solph.flows.Flow(nominal_value=50)
>>> src1 = solph.components.Source(label='source1', outputs={bel: flow1})
>>> src2 = solph.components.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 (over all periods in case of a multi-period model):

\[\sum_{investment\_costs} \leq limit\]
Parameters:
  • model (oemof.solph._models.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 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

SimpleFlowBlock 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)):

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

upper_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

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. (\(v_i(t)\))

  • 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 (\(w_i(t)\))

  • lower_limit (numeric) – the lower limit (\(l_\mathrm{low}\))

  • upper_limit (numeric) – the upper limit (\(l_\mathrm{up}\))

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=6, freq='H')
>>> energysystem = solph.EnergySystem(
...     timeindex=date_time_index,
...     infer_last_interval=False,
... )
>>> b1 = solph.buses.Bus(label="Party1Bus")
>>> b2 = solph.buses.Bus(label="Party2Bus")
>>> storage1 = solph.components.GenericStorage(
...     label="Party1Storage",
...     nominal_storage_capacity=5,
...     inputs={b1: solph.flows.Flow()},
...     outputs={b1: solph.flows.Flow()}
... )
>>> storage2 = solph.components.GenericStorage(
...     label="Party2Storage",
...     nominal_storage_capacity=5,
...     inputs={b1: solph.flows.Flow()},
...     outputs={b1: solph.flows.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.constraints.storage_level_constraint(model, name, storage_component, multiplexer_bus, input_levels, output_levels)[source]

Add constraints to implement storage content based access.

As a GenericStorage just allows exactly one input and one output, an additional bus, the multiplexer_bus, is used for the connections. Note that all Flow objects connected to the multiplexer_bus have to have a nominal_value.

Parameters:
  • model (oemof.solph.Model) – Model to which the constraint is added.

  • name (string) – Name of the multiplexer.

  • storage_component (oemof.solph.components.GenericStorage) – Storage component whose content should mandate the possible inputs and outputs.

  • multiplexer_bus (oemof.solph.Bus) – Bus which connects the input and output levels to the storage.

  • input_levels (dictionary with oemof.solph.Bus as keys and float as values) – Dictionary of buses which act as inputs and corresponding levels

  • output_levels (dictionary with oemof.solph.Bus as keys and float as values) – Dictionary of buses which act as outputs and corresponding level

  • Verbose description can be found in https (//arxiv.org/abs/2211.14080)