Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Refine time index of Flows #1077

Merged
merged 20 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/flexible_modelling/add_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,26 +123,26 @@ def run_add_constraints_example(solver="cbc", nologg=False):
# add the sub-model to the oemof Model instance
om.add_component("MyBlock", myblock)

def _inflow_share_rule(m, s, e, p, t):
def _inflow_share_rule(m, s, e, t):
"""pyomo rule definition: Here we can use all objects from the block or
the om object, in this case we don't need anything from the block
except the newly defined set MYFLOWS.
"""
expr = om.flow[s, e, p, t] >= om.flows[s, e].outflow_share[t] * sum(
om.flow[i, o, p, t] for (i, o) in om.FLOWS if o == e
expr = om.flow[s, e, t] >= om.flows[s, e].outflow_share[t] * sum(
om.flow[i, o, t] for (i, o) in om.FLOWS if o == e
)
return expr

myblock.inflow_share = po.Constraint(
myblock.MYFLOWS, om.TIMEINDEX, rule=_inflow_share_rule
myblock.MYFLOWS, om.TIMESTEPS, rule=_inflow_share_rule
)
# add emission constraint
myblock.emission_constr = po.Constraint(
expr=(
sum(
om.flow[i, o, p, t]
om.flow[i, o, t]
for (i, o) in myblock.COMMODITYFLOWS
for p, t in om.TIMEINDEX
for t in om.TIMESTEPS
)
<= emission_limit
)
Expand Down
24 changes: 12 additions & 12 deletions src/oemof/solph/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,33 +461,33 @@ def _add_parent_block_sets(self):
def _add_parent_block_variables(self):
"""Add the parent block variables, which is the `flow` variable,
indexed by FLOWS and TIMEINDEX."""
self.flow = po.Var(self.FLOWS, self.TIMEINDEX, within=po.Reals)
self.flow = po.Var(self.FLOWS, self.TIMESTEPS, within=po.Reals)

for o, i in self.FLOWS:
if self.flows[o, i].nominal_value is not None:
if self.flows[o, i].fix[self.TIMESTEPS.at(1)] is not None:
for p, t in self.TIMEINDEX:
self.flow[o, i, p, t].value = (
for t in self.TIMESTEPS:
self.flow[o, i, t].value = (
self.flows[o, i].fix[t]
* self.flows[o, i].nominal_value
)
self.flow[o, i, p, t].fix()
self.flow[o, i, t].fix()
else:
for p, t in self.TIMEINDEX:
self.flow[o, i, p, t].setub(
for t in self.TIMESTEPS:
self.flow[o, i, t].setub(
self.flows[o, i].max[t]
* self.flows[o, i].nominal_value
)
if not self.flows[o, i].nonconvex:
for p, t in self.TIMEINDEX:
self.flow[o, i, p, t].setlb(
for t in self.TIMESTEPS:
self.flow[o, i, t].setlb(
self.flows[o, i].min[t]
* self.flows[o, i].nominal_value
)
elif (o, i) in self.UNIDIRECTIONAL_FLOWS:
for p, t in self.TIMEINDEX:
self.flow[o, i, p, t].setlb(0)
for t in self.TIMESTEPS:
self.flow[o, i, t].setlb(0)
else:
if (o, i) in self.UNIDIRECTIONAL_FLOWS:
for p, t in self.TIMEINDEX:
self.flow[o, i, p, t].setlb(0)
for t in self.TIMESTEPS:
self.flow[o, i, t].setlb(0)
30 changes: 15 additions & 15 deletions src/oemof/solph/buses/_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class BusBlock(ScalarBlock):
Bus balance: `om.Bus.balance[i, o, t]`
.. math::
\sum_{i \in INPUTS(n)} P_{i}(p, t) =
\sum_{o \in OUTPUTS(n)} P_{o}(p, t), \\
\forall p, t \in \textrm{TIMEINDEX}, \\
\sum_{i \in INPUTS(n)} P_{i}(t) =
\sum_{o \in OUTPUTS(n)} P_{o}(t), \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall i \in \textrm{INPUTS}, \\
\forall o \in \textrm{OUTPUTS}
Expand All @@ -89,17 +89,17 @@ class BusBlock(ScalarBlock):
output of the Bus object.
The index :math:`n` is the index for the Bus node itself. Therefore,
a :math:`flow[i, n, p, t]` is a flow from the Component i to the Bus n at
a :math:`flow[i, n, t]` is a flow from the Component i to the Bus n at
time index p, t.
====================== ============================ ====================
symbol attribute explanation
====================== ============================ ====================
:math:`P_{i}(p, t)` `flow[i, n, p, t]` Bus, inflow
====================== ========================= ====================
symbol attribute explanation
====================== ========================= ====================
:math:`P_{i}(p, t)` `flow[i, n, t]` Bus, inflow
:math:`P_{o}(p, t)` `flow[n, o, p, t]` Bus, outflow
:math:`P_{o}(p, t)` `flow[n, o, t]` Bus, outflow
====================== ============================ ====================
====================== ========================= ====================
"""

def __init__(self, *args, **kwargs):
Expand All @@ -126,14 +126,14 @@ def _create(self, group=None):
outs[n] = [o for o in n.outputs]

def _busbalance_rule(block):
for p, t in m.TIMEINDEX:
for t in m.TIMESTEPS:
for g in group:
lhs = sum(m.flow[i, g, p, t] for i in ins[g])
rhs = sum(m.flow[g, o, p, t] for o in outs[g])
lhs = sum(m.flow[i, g, t] for i in ins[g])
rhs = sum(m.flow[g, o, t] for o in outs[g])
expr = lhs == rhs
# no inflows no outflows yield: 0 == 0 which is True
if expr is not True:
block.balance.add((g, p, t), expr)
block.balance.add((g, t), expr)

self.balance = Constraint(group, m.TIMEINDEX, noruleinit=True)
self.balance = Constraint(group, m.TIMESTEPS, noruleinit=True)
self.balance_build = BuildAction(rule=_busbalance_rule)
24 changes: 12 additions & 12 deletions src/oemof/solph/components/_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ class ConverterBlock(ScalarBlock):
Linear relation :attr:`om.ConverterBlock.relation[i,o,t]`
.. math::
P_{i}(p, t) \cdot \eta_{o}(t) =
P_{o}(p, t) \cdot \eta_{i}(t), \\
\forall p, t \in \textrm{TIMEINDEX}, \\
P_{i}(t) \cdot \eta_{o}(t) =
P_{o}(t) \cdot \eta_{i}(t), \\
\forall t \in \textrm{TIMESTEPS}, \\
\forall n \in \textrm{CONVERTERS}, \\
\forall i \in \textrm{INPUTS}, \\
\forall o \in \textrm{OUTPUTS}
Expand All @@ -196,15 +196,15 @@ class ConverterBlock(ScalarBlock):
constraints.
The index :math: n is the index for the Transformer node itself. Therefore,
a `flow[i, n, p, t]` is a flow from the Bus i to the Transformer n at
a `flow[i, n, t]` is a flow from the Bus i to the Transformer n at
time index p, t.
====================== ============================ ====================
symbol attribute explanation
====================== ============================ ====================
:math:`P_{i,n}(p, t)` `flow[i, n, p, t]` Converter, inflow
:math:`P_{i,n}(p, t)` `flow[i, n, t]` Converter, inflow
:math:`P_{n,o}(p, t)` `flow[n, o, p, t]` Converter, outflow
:math:`P_{n,o}(p, t)` `flow[n, o, t]` Converter, outflow
:math:`\eta_{i}(t)` `conversion_factor[i, n, t]` Inflow, efficiency
Expand Down Expand Up @@ -243,8 +243,8 @@ def _create(self, group=None):

self.relation = Constraint(
[
(n, i, o, p, t)
for p, t in m.TIMEINDEX
(n, i, o, t)
for t in m.TIMESTEPS
for n in group
for o in out_flows[n]
for i in in_flows[n]
Expand All @@ -253,17 +253,17 @@ def _create(self, group=None):
)

def _input_output_relation(block):
for p, t in m.TIMEINDEX:
for t in m.TIMESTEPS:
for n in group:
for o in out_flows[n]:
for i in in_flows[n]:
try:
lhs = (
m.flow[i, n, p, t]
m.flow[i, n, t]
* n.conversion_factors[o][t]
)
rhs = (
m.flow[n, o, p, t]
m.flow[n, o, t]
* n.conversion_factors[i][t]
)
except ValueError:
Expand All @@ -273,6 +273,6 @@ def _input_output_relation(block):
n.label, o.label
),
)
block.relation.add((n, i, o, p, t), (lhs == rhs))
block.relation.add((n, i, o, t), (lhs == rhs))

self.relation_build = BuildAction(rule=_input_output_relation)
28 changes: 14 additions & 14 deletions src/oemof/solph/components/_extraction_turbine_chp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,17 @@ class ExtractionTurbineCHPBlock(ScalarBlock):
* :math:`\dot H_{Fuel}`
Fuel input flow, represented in code as `flow[i, n, p, t]`
Fuel input flow, represented in code as `flow[i, n, t]`
* :math:`P_{el}`
Electric power outflow, represented in code as
`flow[n, main_output, p, t]`
`flow[n, main_output, t]`
* :math:`\dot Q_{th}`
Thermal output flow, represented in code as
`flow[n, tapped_output, p, t]`
`flow[n, tapped_output, t]`
**Parameters**
Expand Down Expand Up @@ -242,36 +242,36 @@ def _create(self, group=None):

def _input_output_relation_rule(block):
"""Connection between input, main output and tapped output."""
for p, t in m.TIMEINDEX:
for t in m.TIMESTEPS:
for g in group:
lhs = m.flow[g.inflow, g, p, t]
lhs = m.flow[g.inflow, g, t]
rhs = (
m.flow[g, g.main_output, p, t]
+ m.flow[g, g.tapped_output, p, t]
m.flow[g, g.main_output, t]
+ m.flow[g, g.tapped_output, t]
* g.main_flow_loss_index[t]
) / g.conversion_factor_full_condensation_sq[t]
block.input_output_relation.add((g, p, t), (lhs == rhs))
block.input_output_relation.add((g, t), (lhs == rhs))

self.input_output_relation = Constraint(
group, m.TIMEINDEX, noruleinit=True
group, m.TIMESTEPS, noruleinit=True
)
self.input_output_relation_build = BuildAction(
rule=_input_output_relation_rule
)

def _out_flow_relation_rule(block):
"""Relation between main and tapped output in full chp mode."""
for p, t in m.TIMEINDEX:
for t in m.TIMESTEPS:
for g in group:
lhs = m.flow[g, g.main_output, p, t]
lhs = m.flow[g, g.main_output, t]
rhs = (
m.flow[g, g.tapped_output, p, t]
m.flow[g, g.tapped_output, t]
* g.flow_relation_index[t]
)
block.out_flow_relation.add((g, p, t), (lhs >= rhs))
block.out_flow_relation.add((g, t), (lhs >= rhs))

self.out_flow_relation = Constraint(
group, m.TIMEINDEX, noruleinit=True
group, m.TIMESTEPS, noruleinit=True
)
self.out_flow_relation_build = BuildAction(
rule=_out_flow_relation_rule
Expand Down
18 changes: 9 additions & 9 deletions src/oemof/solph/components/_generic_chp.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,37 +338,37 @@ def _create(self, group=None):
self.Y = Var(self.GENERICCHPS, m.TIMESTEPS, within=Binary)

# constraint rules
def _H_flow_rule(block, n, p, t):
def _H_flow_rule(block, n, t):
"""Link fuel consumption to component inflow."""
expr = 0
expr += self.H_F[n, t]
expr += -m.flow[list(n.fuel_input.keys())[0], n, p, t]
expr += -m.flow[list(n.fuel_input.keys())[0], n, t]
return expr == 0

self.H_flow = Constraint(
self.GENERICCHPS, m.TIMEINDEX, rule=_H_flow_rule
self.GENERICCHPS, m.TIMESTEPS, rule=_H_flow_rule
)

def _Q_flow_rule(block, n, p, t):
def _Q_flow_rule(block, n, t):
"""Link heat flow to component outflow."""
expr = 0
expr += self.Q[n, t]
expr += -m.flow[n, list(n.heat_output.keys())[0], p, t]
expr += -m.flow[n, list(n.heat_output.keys())[0], t]
return expr == 0

self.Q_flow = Constraint(
self.GENERICCHPS, m.TIMEINDEX, rule=_Q_flow_rule
self.GENERICCHPS, m.TIMESTEPS, rule=_Q_flow_rule
)

def _P_flow_rule(block, n, p, t):
def _P_flow_rule(block, n, t):
"""Link power flow to component outflow."""
expr = 0
expr += self.P[n, t]
expr += -m.flow[n, list(n.electrical_output.keys())[0], p, t]
expr += -m.flow[n, list(n.electrical_output.keys())[0], t]
return expr == 0

self.P_flow = Constraint(
self.GENERICCHPS, m.TIMEINDEX, rule=_P_flow_rule
self.GENERICCHPS, m.TIMESTEPS, rule=_P_flow_rule
)

def _H_F_1_rule(block, n, t):
Expand Down
20 changes: 10 additions & 10 deletions src/oemof/solph/components/_generic_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ def _storage_content_bound_rule(block, n, t):

# ************* Constraints ***************************

def _storage_balance_rule(block, n, p, t):
def _storage_balance_rule(block, n, t):
"""
Rule definition for the storage balance of every storage n and
every timestep.
Expand All @@ -526,15 +526,15 @@ def _storage_balance_rule(block, n, p, t):
)
expr += n.fixed_losses_absolute[t] * m.timeincrement[t]
expr += (
-m.flow[i[n], n, p, t] * n.inflow_conversion_factor[t]
-m.flow[i[n], n, t] * n.inflow_conversion_factor[t]
) * m.timeincrement[t]
expr += (
m.flow[n, o[n], p, t] / n.outflow_conversion_factor[t]
m.flow[n, o[n], t] / n.outflow_conversion_factor[t]
) * m.timeincrement[t]
return expr == 0

self.balance = Constraint(
self.STORAGES, m.TIMEINDEX, rule=_storage_balance_rule
self.STORAGES, m.TIMESTEPS, rule=_storage_balance_rule
)

def _balanced_storage_rule(block, n):
Expand Down Expand Up @@ -1258,7 +1258,7 @@ def _storage_investvar_bound_rule(block, n, p):
i = {n: [i for i in n.inputs][0] for n in group}
o = {n: [o for o in n.outputs][0] for n in group}

reduced_periods_timesteps = [(p, t) for (p, t) in m.TIMEINDEX if t > 0]
reduced_periods_timeindex = [(p, t) for (p, t) in m.TIMEINDEX if t > 0]
jokochems marked this conversation as resolved.
Show resolved Hide resolved

# Handle unit lifetimes
def _total_storage_capacity_rule(block):
Expand Down Expand Up @@ -1507,10 +1507,10 @@ def _storage_balance_first_rule(block, n):
)
expr += n.fixed_losses_absolute[0] * m.timeincrement[0]
expr += (
-m.flow[i[n], n, 0, 0] * n.inflow_conversion_factor[0]
-m.flow[i[n], n, 0] * n.inflow_conversion_factor[0]
) * m.timeincrement[0]
expr += (
m.flow[n, o[n], 0, 0] / n.outflow_conversion_factor[0]
m.flow[n, o[n], 0] / n.outflow_conversion_factor[0]
) * m.timeincrement[0]
return expr == 0

Expand All @@ -1536,16 +1536,16 @@ def _storage_balance_rule(block, n, p, t):
)
expr += n.fixed_losses_absolute[t] * m.timeincrement[t]
expr += (
-m.flow[i[n], n, p, t] * n.inflow_conversion_factor[t]
-m.flow[i[n], n, t] * n.inflow_conversion_factor[t]
) * m.timeincrement[t]
expr += (
m.flow[n, o[n], p, t] / n.outflow_conversion_factor[t]
m.flow[n, o[n], t] / n.outflow_conversion_factor[t]
) * m.timeincrement[t]
return expr == 0

self.balance = Constraint(
self.INVESTSTORAGES,
reduced_periods_timesteps,
reduced_periods_timeindex,
rule=_storage_balance_rule,
)

Expand Down
Loading
Loading