# Process Constraints¶

**Process Capacity Rule**: The constraint process capacity rule defines the
variable total process capacity \(\kappa_{yvp}\). The variable total
process capacity is defined by the constraint as the sum of the parameter
process capacity installed \(K_{vp}\) and the variable new process
capacity \(\hat{\kappa}_{yvp}\). The mathematical explanation of this rule
is given in Minimal Optimization Model.

In script `model.py`

the constraint process capacity rule is defined and
calculated by the following code fragment:

```
m.def_process_capacity = pyomo.Constraint(
m.pro_tuples,
rule=def_process_capacity_rule,
doc='total process capacity = inst-cap + new capacity')
```

```
def def_process_capacity_rule(m, stf, sit, pro):
if m.mode['int']:
if (sit, pro, stf) in m.inst_pro_tuples:
if (sit, pro, min(m.stf)) in m.pro_const_cap_dict:
cap_pro = m.process_dict['inst-cap'][(stf, sit, pro)]
else:
cap_pro = \
(sum(m.cap_pro_new[stf_built, sit, pro]
for stf_built in m.stf
if (sit, pro, stf_built, stf)
in m.operational_pro_tuples) +
m.process_dict['inst-cap'][(min(m.stf), sit, pro)])
else:
cap_pro = sum(
m.cap_pro_new[stf_built, sit, pro]
for stf_built in m.stf
if (sit, pro, stf_built, stf) in m.operational_pro_tuples)
else:
if (sit, pro, stf) in m.pro_const_cap_dict:
cap_pro = m.process_dict['inst-cap'][(stf, sit, pro)]
else:
cap_pro = (m.cap_pro_new[stf, sit, pro] +
m.process_dict['inst-cap'][(stf, sit, pro)])
return cap_pro
```

**Process Input Rule**: The constraint process input rule defines the variable
process input commodity flow \(\epsilon_{yvcpt}^\text{in}\). The variable
process input commodity flow is defined by the constraint as the product of the
variable process throughput \(\tau_{yvpt}\) and the parameter process input
ratio \(r_{ypc}^\text{in}\).The mathematical explanation of this rule is
given in Minimal Optimization Model.

In script `model.py`

the constraint process input rule is defined and
calculated by the following code fragment:

```
m.def_process_input = pyomo.Constraint(
m.tm, m.pro_input_tuples - m.pro_partial_input_tuples,
rule=def_process_input_rule,
doc='process input = process throughput * input ratio')
```

```
def def_process_input_rule(m, tm, stf, sit, pro, com):
return (m.e_pro_in[tm, stf, sit, pro, com] ==
m.tau_pro[tm, stf, sit, pro] * m.r_in_dict[(stf, pro, com)])
```

**Process Output Rule**: The constraint process output rule defines the variable
process output commodity flow \(\epsilon_{yvcpt}^\text{out}\). The variable
process output commodity flow is defined by the constraint as the product of
the variable process throughput \(\tau_{yvpt}\) and the parameter process
output ratio \(r_{ypc}^\text{out}\). The mathematical explanation of this
rule is given in Minimal Optimization Model.

In script `model.py`

the constraint process output rule is defined and
calculated by the following code fragment:

```
m.def_process_output = pyomo.Constraint(
m.tm, (m.pro_output_tuples - m.pro_partial_output_tuples -
m.pro_timevar_output_tuples),
rule=def_process_output_rule,
doc='process output = process throughput * output ratio')
```

```
def def_process_output_rule(m, tm, stf, sit, pro, com):
return (m.e_pro_out[tm, stf, sit, pro, com] ==
m.tau_pro[tm, stf, sit, pro] * m.r_out_dict[(stf, pro, com)])
```

**Intermittent Supply Rule**: The constraint intermittent supply rule defines
the variable process input commodity flow \(\epsilon_{yvcpt}^\text{in}\)
for processes \(p\) that use a supply intermittent commodity
\(c \in C_\text{sup}\) as input. Therefore this constraint only applies if
a commodity is an intermittent supply commodity \(c \in C_\text{sup}\). The
variable process input commodity flow is defined by the constraint as the
product of the variable total process capacity \(\kappa_{yvp}\) and the
parameter intermittent supply capacity factor \(s_{yvct}\), scaled by the
size of the timesteps \(\Delta t\). The mathematical explanation of this
rule is given in Minimal Optimization Model.

In script `model.py`

the constraint intermittent supply rule is defined and
calculated by the following code fragment:

```
m.def_intermittent_supply = pyomo.Constraint(
m.tm, m.pro_input_tuples,
rule=def_intermittent_supply_rule,
doc='process output = process capacity * supim timeseries')
```

```
def def_intermittent_supply_rule(m, tm, stf, sit, pro, coin):
if coin in m.com_supim:
return (m.e_pro_in[tm, stf, sit, pro, coin] ==
m.cap_pro[stf, sit, pro] * m.supim_dict[(sit, coin)]
[(stf, tm)] * m.dt)
else:
return pyomo.Constraint.Skip
```

**Process Throughput by Capacity Rule**: The constraint process throughput by
capacity rule limits the variable process throughput \(\tau_{yvpt}\). This
constraint prevents processes from exceeding their capacity. The constraint
states that the variable process throughput must be less than or equal to the
variable total process capacity \(\kappa_{yvp}\), scaled by the size
of the timesteps \(\Delta t\). The mathematical explanation of this rule
is given in Minimal Optimization Model.

In script `model.py`

the constraint process throughput by capacity rule is
defined and calculated by the following code fragment:

```
m.res_process_throughput_by_capacity = pyomo.Constraint(
m.tm, m.pro_tuples,
rule=res_process_throughput_by_capacity_rule,
doc='process throughput <= total process capacity')
```

```
def res_process_throughput_by_capacity_rule(m, tm, stf, sit, pro):
return (m.tau_pro[tm, stf, sit, pro] <= m.dt * m.cap_pro[stf, sit, pro])
```

**Process Throughput Gradient Rule**: The constraint process throughput
gradient rule limits the process power gradient
\(\left| \tau_{yvpt} - \tau_{yvp(t-1)} \right|\). This constraint prevents
processes from exceeding their maximal possible change in activity from one
time step to the next. The constraint states that absolute power gradient must
be less than or equal to the maximal power gradient \(\overline{PG}_{yvp}\)
parameter (scaled to capacity and by timestep duration). The mathematical
explanation of this rule is given in Minimal Optimization Model.

In script `model.py`

the constraint process throughput gradient rule is split
into 2 parts and defined and calculated by the following code fragments:

```
m.res_process_maxgrad_lower = pyomo.Constraint(
m.tm, m.pro_maxgrad_tuples,
rule=res_process_maxgrad_lower_rule,
doc='throughput may not decrease faster than maximal gradient')
m.res_process_maxgrad_upper = pyomo.Constraint(
m.tm, m.pro_maxgrad_tuples,
rule=res_process_maxgrad_upper_rule,
doc='throughput may not increase faster than maximal gradient')
```

```
def res_process_maxgrad_lower_rule(m, t, stf, sit, pro):
return (m.tau_pro[t - 1, stf, sit, pro] -
m.cap_pro[stf, sit, pro] *
m.process_dict['max-grad'][(stf, sit, pro)] * m.dt <=
m.tau_pro[t, stf, sit, pro])
```

```
def res_process_maxgrad_upper_rule(m, t, stf, sit, pro):
return (m.tau_pro[t - 1, stf, sit, pro] +
m.cap_pro[stf, sit, pro] *
m.process_dict['max-grad'][(stf, sit, pro)] * m.dt >=
m.tau_pro[t, stf, sit, pro])
```

**Process Capacity Limit Rule**: The constraint process capacity limit rule
limits the variable total process capacity \(\kappa_{yvp}\). This
constraint restricts a process \(p\) in a site \(v\) and support
timeframe \(y\) from having more total capacity than an upper bound and
having less than a lower bound. The constraint states that the variable total
process capacity \(\kappa_{yvp}\) must be greater than or equal to the
parameter process capacity lower bound \(\underline{K}_{yvp}\) and less
than or equal to the parameter process capacity upper bound
\(\overline{K}_{yvp}\). The mathematical explanation of this rule is given
in Minimal Optimization Model.

In script `model.py`

the constraint process capacity limit rule is defined
and calculated by the following code fragment:

```
m.res_process_capacity = pyomo.Constraint(
m.pro_tuples,
rule=res_process_capacity_rule,
doc='process.cap-lo <= total process capacity <= process.cap-up')
```

```
def res_process_capacity_rule(m, stf, sit, pro):
return (m.process_dict['cap-lo'][stf, sit, pro],
m.cap_pro[stf, sit, pro],
m.process_dict['cap-up'][stf, sit, pro])
```

**Sell Buy Symmetry Rule**: The constraint sell buy symmetry rule defines the
total process capacity \(\kappa_{yvp}\) of a process \(p\) in a site
\(v\) and support timeframe \(y\) that uses either sell or buy
commodities ( \(c \in C_\text{sell} \vee C_\text{buy}\)), therefore this
constraint only applies to processes that use sell or buy commodities. The
constraint states that the total process capacities \(\kappa_{yvp}\) of
processes that use complementary buy and sell commodities must be equal. Buy
and sell commodities are complementary, when a commodity \(c\) is an output
of a process where the buy commodity is an input, and at the same time the
commodity \(c\) is an input commodity of a process where the sell commodity
is an output. The mathematical explanation of this rule is given in
Trading with an External Market.

In script `BuySellPrice.py`

the constraint sell buy symmetry rule is defined
and calculated by the following code fragment:

```
m.res_sell_buy_symmetry = pyomo.Constraint(
m.pro_input_tuples,
rule=res_sell_buy_symmetry_rule,
doc='total power connection capacity must be symmetric in both '
'directions')
```

```
def res_sell_buy_symmetry_rule(m, stf, sit_in, pro_in, coin):
# constraint only for sell and buy processes
# and the processes must be in the same site
if coin in m.com_buy:
sell_pro = search_sell_buy_tuple(m, stf, sit_in, pro_in, coin)
if sell_pro is None:
return pyomo.Constraint.Skip
else:
return (m.cap_pro[stf, sit_in, pro_in] ==
m.cap_pro[stf, sit_in, sell_pro])
else:
return pyomo.Constraint.Skip
```

**Process Time Variable Output Rule**: This constraint multiplies the process
efficiency with the parameter time series \(f_{yvpt}^\text{out}\). The
process output for all commodities is thus manipulated depending on time. This
constraint is not valid for environmental commodities since these are typically
linked to an input commodity flow rather than an output commodity flow. The
mathematical explanation of this rule is given in Time Variable Efficiency.

In script `TimeVarEff.py`

the constraint process time variable output rule is
defined and calculated by the following code fragment:

```
m.def_process_timevar_output = pyomo.Constraint(
m.tm, m.pro_timevar_output_tuples,
rule=def_pro_timevar_output_rule,
doc='e_pro_out = tau_pro * r_out * eff_factor')
```

```
def def_pro_timevar_output_rule(m, tm, stf, sit, pro, com):
return(m.e_pro_out[tm, stf, sit, pro, com] ==
m.tau_pro[tm, stf, sit, pro] * m.r_out_dict[(stf, pro, com)] *
m.eff_factor_dict[(sit, pro)][stf, tm])
```

## Process Constraints for Partial Operation¶

The process constraints for partial operation described in the following are
only activated if in the input file there is a value set in the column
**ratio-min** for an **input commodity** in the **process-commodity** sheet for
the process in question. Values for **output commodities** in the **ratio_min**
column do not have any effect.

The partial load feature can only be used for processes that are never meant to be shut down and are always operating only between a given part load state and full load. It is important to understand that this partial load formulation can only work if its accompanied by a non-zero value for the minimum partial load fraction \(\underline{P}_{yvp}\).

**Throughput by Min Fraction Rule**: This constraint limits the minimal
operational state of a process downward, making sure that the minimal part load
fraction is honored. The mathematical explanation of this rule is given in
Minimal Optimization Model.

In script `model.py`

this constraint is defined and calculated by the
following code fragment:

```
m.res_throughput_by_capacity_min = pyomo.Constraint(
m.tm, m.pro_partial_tuples,
rule=res_throughput_by_capacity_min_rule,
doc='cap_pro * min-fraction <= tau_pro')
```

```
def res_throughput_by_capacity_min_rule(m, tm, stf, sit, pro):
return (m.tau_pro[tm, stf, sit, pro] >=
m.cap_pro[stf, sit, pro] *
m.process_dict['min-fraction'][(stf, sit, pro)] * m.dt)
```

**Partial Process Input Rule**: The link between operational state
\(\tau_{yvpt}\) and commodity in/outputs is changed from a simple
linear behavior to a more complex one. Instead of constant in- and output
ratios these are now interpolated linearly between the value for full operation
\(r^{\text{in/out}}_{yvp}\) at full load and the minimum in/output ratios
\(\underline{r}^{\text{in/out}}_{yvp}\) at the minimum operation point. The
mathematical explanation of this rule is given in Minimal Optimization Model.

In script `model.py`

this expression is written in the following way for the
input ratio (and analogous for the output ratios):

```
m.def_partial_process_input = pyomo.Constraint(
m.tm, m.pro_partial_input_tuples,
rule=def_partial_process_input_rule,
doc='e_pro_in = cap_pro * min_fraction * (r - R) / (1 - min_fraction)'
'+ tau_pro * (R - min_fraction * r) / (1 - min_fraction)')
```

```
def def_partial_process_input_rule(m, tm, stf, sit, pro, coin):
# input ratio at maximum operation point
R = m.r_in_dict[(stf, pro, coin)]
# input ratio at lowest operation point
r = m.r_in_min_fraction_dict[stf, pro, coin]
min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]
online_factor = min_fraction * (r - R) / (1 - min_fraction)
throughput_factor = (R - min_fraction * r) / (1 - min_fraction)
return (m.e_pro_in[tm, stf, sit, pro, coin] ==
m.dt * m.cap_pro[stf, sit, pro] * online_factor +
m.tau_pro[tm, stf, sit, pro] * throughput_factor)
```

In case of a process where also a time variable output efficiency is given the code for the output changes to.

```
m.def_process_partial_timevar_output = pyomo.Constraint(
m.tm, m.pro_partial_output_tuples & m.pro_timevar_output_tuples,
rule=def_pro_partial_timevar_output_rule,
doc='e_pro_out = tau_pro * r_out * eff_factor')
```

```
def def_pro_partial_timevar_output_rule(m, tm, stf, sit, pro, coo):
# input ratio at maximum operation point
R = m.r_out_dict[stf, pro, coo]
# input ratio at lowest operation point
r = m.r_out_min_fraction_dict[stf, pro, coo]
min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]
online_factor = min_fraction * (r - R) / (1 - min_fraction)
throughput_factor = (R - min_fraction * r) / (1 - min_fraction)
return (m.e_pro_out[tm, stf, sit, pro, coo] ==
(m.dt * m.cap_pro[stf, sit, pro] * online_factor +
m.tau_pro[tm, stf, sit, pro] * throughput_factor) *
m.eff_factor_dict[(sit, pro)][(stf, tm)])
```