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):
    if com == 'electricity-reactive':
        return pyomo.Constraint.Skip
    else:
        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 time steps :math: 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 time steps :math: 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 the absolute power gradient must be less than or equal to the maximal power ramp up gradient \(overline{PG}_{yvp}^\text{up}\) parameter when increasing power or to the maximal power ramp down gradient \(\overline{PG}_{yvp}^\text{up}\) parameter (both scaled to capacity and by time step 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_rampdown = pyomo.Constraint(
    m.tm, m.pro_rampdowngrad_tuples,
    rule=res_process_rampdown_rule,
    doc='throughput may not decrease faster than maximal ramp down gradient')
m.res_process_rampup = pyomo.Constraint(
    m.tm, m.pro_rampupgrad_tuples,
    rule=res_process_rampup_rule,
    doc='throughput may not increase faster than maximal ramp up gradient')
def res_process_rampdown_rule(m, t, stf, sit, pro):
    return (m.tau_pro[t - 1, stf, sit, pro] -
            m.cap_pro[stf, sit, pro] *
            m.process_dict['ramp-down-grad'][(stf, sit, pro)] * m.dt <=
            m.tau_pro[t, stf, sit, pro])
def res_process_rampup_rule(m, t, stf, sit, pro):
    return (m.tau_pro[t - 1, stf, sit, pro] +
            m.cap_pro[stf, sit, pro] *
            m.process_dict['ramp-up-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 Advanced Processes.

In script AdvancedProcesses.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 or for an output commodity in the process-commodity sheet for the process in question.

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

Without activating the on/off feature in the process sheet, 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. Please see the next chapter for the combined on/off and partial operation features.

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 Advanced Processes.

In script AdvancedProcesses.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 Advanced Processes.

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, com):
    # input ratio at maximum operation point
    R = m.r_in_dict[(stf, pro, com)]
    # input ratio at lowest operation point
    r = m.r_in_min_fraction_dict[stf, pro, com]
    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, com] ==
            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, com):
# input ratio at maximum operation point
    R = m.r_out_dict[stf, pro, com]
    # input ratio at lowest operation point
    r = m.r_out_min_fraction_dict[stf, pro, com]
    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, com] ==
            (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])

Process Constraints for the on/off feature

The process constraints for the on/off feature described in this chapter are only activated if, in the input file, the value „1” is set is set in the column on-off for a process in the process sheet.

Process Throughput and On/Off Coupling Rule: These two constraints couple the variables process throughput \(\tau_{yvpt}\) and process on/off marker \(\omicron_{yvpt}\). This is done by turning the marker on (boolean value 1) when the throughput is greater than the minimum load of the process.The mathematical explanation of this rule is given in Advanced Processes.

In script AdvancedProcesses.py this constraint is defined and calculated by the following code fragment:

m.res_throughput_by_on_off_lower = pyomo.Constraint(
    m.tm, m.pro_on_off_tuples | m.pro_partial_on_off_tuples,
    rule=res_throughput_by_on_off_lower_rule,
    doc='tau_pro >= min-fraction * cap_pro * on_off')
m.res_throughput_by_on_off_upper = pyomo.Constraint(
    m.tm, m.pro_on_off_tuples | m.pro_partial_on_off_tuples,
    rule=res_throughput_by_on_off_upper_rule,
    doc='tau_pro <='
        'cap_pro * on_off + min-fraction * cap_pro * (1 - on_off)')
def res_throughput_by_on_off_lower_rule(m, tm, stf, sit, pro):
    return (m.tau_pro[tm, stf, sit, pro] >=
            m.min_fraction_dict[stf, sit, pro] * m.cap_pro[stf, sit, pro] *
            m.dt * m.on_off[tm, stf, sit, pro])
def res_throughput_by_on_off_upper_rule(m, tm, stf, sit, pro):
    return (m.tau_pro[tm, stf, sit, pro] <=
            m.cap_pro[stf, sit, pro] * m.dt * m.on_off[tm, stf, sit, pro] +
            m.min_fraction_dict[stf, sit, pro] * m.cap_pro[stf, sit, pro] *
            m.dt * (1 - m.on_off[tm, stf, sit, pro]))

Process On/Off Output Rule: This constraint modifies the process output commodity flow \(\epsilon_{yvcpt}^\text{out}\) when compared to the original version without the on/off feature in two ways by differentiating between the output commodity type \(q\). When the commodity type is Env, the output remains the same as without the on/off feature. Otherwise, the original output equation is multiplied with the variable process on/off marker \(\omicron_{yvpt}\). The mathematical explanation of this rule is given in Advanced Processes.

In script AdvancedProcesses.py the constraint process on/off output rule is defined and calculated by the following code fragment:

m.def_process_on_off_output = pyomo.Constraint(
    m.tm, m.pro_on_off_output_tuples - m.pro_timevar_output_tuples -
          m.pro_partial_on_off_output_tuples,
    rule=def_process_on_off_output_rule,
    doc='e_pro_out = tau_pro * r_out * on_off')
def def_process_on_off_output_rule(m, tm, stf, sit, pro, com):
    r = m.r_out_dict[(stf, pro, com)]
    if com in m.com_env:
        return (m.e_pro_out[tm, stf, sit, pro, com] ==
                m.tau_pro[tm, stf, sit, pro] * r)
    else:
        return (m.e_pro_out[tm, stf, sit, pro, com] ==
                m.tau_pro[tm, stf, sit, pro] * r * m.on_off[tm, stf, sit, pro])

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

m.def_process_on_off_timevar_output = pyomo.Constraint(
    m.tm, m.pro_timevar_output_tuples & m.pro_on_off_output_tuples -
          m.pro_partial_on_off_output_tuples,
    rule=def_process_on_off_timevar_output_rule,
    doc='e_pro_out == tau_pro * r_out * on_off * eff_factor')
def def_process_on_off_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.on_off[tm, stf, sit, pro] *
            m.eff_factor_dict[(sit, pro)][stf, tm])

Process On/Off Partial Input Rule: This constraint modifies the process input commodity flow \(\epsilon_{yvcpt}^\text{in}\) when compared to the original partial operation version without the on/off feature in by differentiating between two possible input functions, depending on the process on/off marker \(\omicron_{yvpt}\). When the marker is on, the input function is the same as in the case of simple partial operation. When the marker is off, the input function becomes the product of the variable process throughput \(\tau_{yvpt}\) and the parameter process partial input ratio \(\underline{r}_{ypc}^\text{in}\). the output commodity type \(q\). When the commodity type. The mathematical explanation of this rule is given in Advanced Processes.

In script AdvancedProcesses.py the constraint process on/off output rule is defined and calculated by the following code fragment:

m.def_partial_process_on_off_input = pyomo.Constraint(
    m.tm, m.pro_partial_on_off_input_tuples,
    rule=def_partial_process_on_off_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_on_off_input_rule(m, tm, stf, sit, pro, com):
    # input ratio at maximum operation point
    R = m.r_in_dict[(stf, pro, com)]
    # input ratio at lowest operation point
    r = m.r_in_min_fraction_dict[stf, pro, com]
    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, com] ==
            (m.dt * m.cap_pro[stf, sit, pro] * online_factor +
              m.tau_pro[tm, stf, sit, pro] * throughput_factor) *
              m.on_off[tm, stf, sit, pro] +
              m.tau_pro[tm, stf, sit, pro] * r *
              (1 - m.on_off[tm, stf, sit, pro]))

Process On/Off Partial Output Rule: This constraint modifies the process output commodity flow \(\epsilon_{yvcpt}^\text{out}\) when compared to the original partial operation version without the on/off feature in two ways by differentiating between the output commodity type \(q\). When the commodity type is not Env, the output remains the same as for the partial operation without the on/off feature. Otherwise, the original output equation is changes depending on the variable process on/off marker \(\omicron_{yvpt}\). When the marker is off, the output function becomes the product of the variable process throughput \(\tau_{yvpt}\) and the parameter process partial output ratio \(\underline{r}_{ypc}^\text{out}\). When the marker is on, the output function for Env type commodities remains the same as for the partial operation without the on/off feature. The mathematical explanation of this rule is given in Advanced Processes.

m.def_partial_process_on_off_output = pyomo.Constraint(
    m.tm, m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=def_partial_process_on_off_output_rule,
    doc='e_pro_out = on_off *'
        ' (cap_pro * min_fraction * (r - R) / (1 - min_fraction) '
        '+ tau_pro * (R - min_fraction * r) / (1 - min_fraction)) ')
def def_partial_process_on_off_output_rule(m, tm, stf, sit, pro, com):
    # input ratio at maximum operation point
    R = m.r_out_dict[stf, pro, com]
    # input ratio at lowest operation point
    r = m.r_out_min_fraction_dict[stf, pro, com]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]
    on_off = m.on_off[tm, stf, sit, pro]

    online_factor = min_fraction * (r - R) / (1 - min_fraction)
    throughput_factor = (R - min_fraction * r) / (1 - min_fraction)
    if com in m.com_env:
        return(m.e_pro_out[tm, stf, sit, pro, com] ==
               (m.dt * m.cap_pro[stf, sit, pro] * online_factor +
               m.tau_pro[tm, stf, sit, pro] * throughput_factor) * on_off +
               m.tau_pro[tm, stf, sit, pro] * r *
               (1 - on_off))
    else:
        return (m.e_pro_out[tm, stf, sit, pro, com] ==
                (m.dt * m.cap_pro[stf, sit, pro] * online_factor +
                m.tau_pro[tm, stf, sit, pro] * throughput_factor) * on_off)

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

m.def_process_partial_on_off_timevar_output = pyomo.Constraint(
    m.tm, m.pro_partial_on_off_output_tuples & m.pro_timevar_output_tuples,
    rule=def_pro_partial_on_off_timevar_output_rule,
    doc='e_pro_out == tau_pro * r_out * on_off * eff_factor')
def def_partial_process_on_off_output_rule(m, tm, stf, sit, pro, com):
    # input ratio at maximum operation point
    R = m.r_out_dict[stf, pro, com]
    # input ratio at lowest operation point
    r = m.r_out_min_fraction_dict[stf, pro, com]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]
    on_off = m.on_off[tm, stf, sit, pro]

    online_factor = min_fraction * (r - R) / (1 - min_fraction)
    throughput_factor = (R - min_fraction * r) / (1 - min_fraction)
    if com in m.com_env:
        return(m.e_pro_out[tm, stf, sit, pro, com] ==
               (m.dt * m.cap_pro[stf, sit, pro] * online_factor +
               m.tau_pro[tm, stf, sit, pro] * throughput_factor) * on_off +
               m.tau_pro[tm, stf, sit, pro] * r *
               (1 - on_off))
    else:
        return (m.e_pro_out[tm, stf, sit, pro, com] ==
                (m.dt * m.cap_pro[stf, sit, pro] * online_factor +
                m.tau_pro[tm, stf, sit, pro] * throughput_factor) * on_off)

Process Starting Ramp-up Rule: This constraint replaces the process throughput ramping rule when the parameter process starting time \(\overline{ST}_{yvp}^\text{start}\) is defined in the input process sheet. This is done only until the variable process throughput \(\tau_{yvpt}\) reaches the minimum load value and only while increasing the process throughput \(\tau_{yvpt}\). The mathematical explanation of this rule is given in Advanced Processes.

In script AdvancedProcesses.py the constraint process starting ramp-up rule is defined and calculated by the following code fragment:

m.res_starting_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_start_tuples,
    rule=res_starting_rampup_rule,
    doc='throughput may not increase faster than maximal starting ramp up '
        'gradient until reaching minimum capacity')
def res_starting_rampup_rule(m, t, stf, sit, pro):
    min_fraction = m.min_fraction_dict[stf, sit, pro]
    start_time = m.process_dict['start-time'][(stf, sit, pro)]
    starting_ramp =min_fraction / start_time
    return (m.tau_pro[t - 1, stf, sit, pro] +
            m.cap_pro[stf, sit, pro] *
            m.process_dict['ramp-up-grad'][(stf, sit, pro)] * m.dt *
            m.on_off[t - 1, stf, sit, pro] +
            m.cap_pro[stf, sit, pro] *
            starting_ramp * m.dt *
            (1 - m.on_off[t - 1, stf, sit, pro])
            >=
            m.tau_pro[t, stf, sit, pro])

Process Output Ramping Rule: These constraints act as a limiter for the process output \(\epsilon_{yvcpt}^\text{out}\) with the on/off feature because the process on/off marker \(\omicron_{yvpt}\) can be both on and off in the minimum load point. There are three possible cases, as follows, defined in the script AdvanceProcesses.py. The mathematical explanation of this rule is given in Advanced Processes

Case I: The parameter process minimum load fraction \(\underline{P}_{yvp}\) is greater than the parameter process maximum power ramp up gradient \(\overline{PG}_{yvp}^\text{up}\) and is divisible with it. It is defined and calculated by the following code fragment:

m.res_output_minfraction_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_divides_minfraction_output_tuples -
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_output_minfraction_rampup_rule,
    doc='Output may not increase faster than the minimal working capacity')
def res_output_minfraction_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['min-fraction'][(stf, sit, pro)] *
                m.r_out_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has partial operation, the code changes to:

m.res_partial_output_minfraction_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_divides_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_partial_output_minfraction_rampup_rule,
    doc='Output may not increase faster than the minimal working capacity')
def res_partial_output_minfraction_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['min-fraction'][(stf, sit, pro)] *
                m.r_out_min_fraction_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has time variable efficiency, the code changes to:

m.res_timevar_output_minfraction_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_divides_minfraction_output_tuples &
          m.pro_timevar_output_tuples - m.pro_partial_on_off_output_tuples,
    rule=res_timevar_output_minfraction_rampup_rule,
    doc='Output may not increase faster than the minimal working capacity')
def res_timevar_output_minfraction_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['min-fraction'][(stf, sit, pro)] *
                m.r_out_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has both partial operation and time variable efficiency, the code changes to:

m.res_partial_timevar_output_minfraction_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_divides_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples & m.pro_timevar_output_tuples,
    rule=res_partial_timevar_output_minfraction_rampup_rule,
    doc='Output may not increase faster than the minimal working capacity')
def res_partial_timevar_output_minfraction_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['min-fraction'][(stf, sit, pro)] *
                m.r_out_min_fraction_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

Case II: The parameter process minimum load fraction \(\underline{P}_{yvp}\) is greater than the parameter process maximum power ramp up gradient \(\overline{PG}_{yvp}^\text{up}\), but is not divisible with it. It is defined and calculated by the following code fragment:

m.res_output_minfraction_rampup_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_not_divides_minfraction_output_tuples -
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_output_minfraction_rampup_rampup_rule,
    doc='Output may not increase faster than the first multiple of the'
        'ramping up gradient greater than the minimal working capacity')
def res_output_minfraction_rampup_rampup_rule(m, tm, stf, sit, pro, com):
    ramp_up = m.process_dict['ramp-up-grad'][(stf, sit, pro)]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]

    first_output_value = (math.floor(min_fraction / ramp_up) + 1) * ramp_up
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                first_output_value *
                m.r_out_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has partial operation, the code changes to:

m.res_partial_output_minfraction_rampup_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_not_divides_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_partial_output_minfraction_rampup_rampup_rule,
    doc='Output may not increase faster than the first multiple of the'
        'ramping up gradient greater than the minimal working capacity')
def res_partial_output_minfraction_rampup_rampup_rule(m, tm, stf, sit, pro, com):
    ramp_up = m.process_dict['ramp-up-grad'][(stf, sit, pro)]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]

    first_output_value = (math.floor(min_fraction / ramp_up) + 1) * ramp_up
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                first_output_value *
                m.r_out_min_fraction_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has time variable efficiency, the code changes to:

m.res_timevar_output_minfraction_rampup_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_not_divides_minfraction_output_tuples &
          m.pro_timevar_output_tuples - m.pro_partial_on_off_output_tuples,
    rule=res_timevar_output_minfraction_rampup_rampup_rule,
    doc='Output may not increase faster than the first multiple of the'
        'ramping up gradient greater than the minimal working capacity')
def res_timevar_output_minfraction_rampup_rampup_rule(m, tm, stf, sit, pro, com):
    ramp_up = m.process_dict['ramp-up-grad'][(stf, sit, pro)]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]

    first_output_value = (math.floor(min_fraction / ramp_up) + 1) * ramp_up
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                first_output_value *
                m.r_out_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has both partial operation and time variable efficiency, the code changes to:

m.res_partial_timevar_output_minfraction_rampup_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_not_divides_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples & m.pro_timevar_output_tuples,
    rule=res_partial_timevar_output_minfraction_rampup_rampup_rule,
    doc='Output may not increase faster than the first multiple of the'
        'ramping up gradient greater than the minimal working capacity')
def res_partial_timevar_output_minfraction_rampup_rampup_rule(m, tm, stf, sit, pro, com):
    ramp_up = m.process_dict['ramp-up-grad'][(stf, sit, pro)]
    min_fraction = m.process_dict['min-fraction'][(stf, sit, pro)]

    first_output_value = (math.floor(min_fraction / ramp_up) + 1) * ramp_up
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                first_output_value *
                m.r_out_min_fraction_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

Case III: The parameter process minimum load fraction \(\underline{P}_{yvp}\) is smaller than the parameter process maximum power ramp up gradient \(\overline{PG}_{yvp}^\text{up}\). It is defined and calculated by the following code fragment:

m.res_output_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_bigger_minfraction_output_tuples -
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_output_rampup_rule,
    doc='Output may not increase faster than the ramping up gradient')
def res_output_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['ramp-up-grad'][(stf, sit, pro)] *
                m.r_out_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has partial operation, the code changes to:

m.res_partial_output_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_bigger_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples - m.pro_timevar_output_tuples,
    rule=res_partial_output_rampup_rule,
    doc='Output may not increase faster than the ramping up gradient')
def res_partial_output_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['ramp-up-grad'][(stf, sit, pro)] *
                m.r_out_min_fraction_dict[(stf, pro, com)] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has time variable efficiency, the code changes to:

m.res_timevar_output_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_bigger_minfraction_output_tuples &
          m.pro_timevar_output_tuples - m.pro_partial_on_off_output_tuples,
    rule=res_timevar_output_rampup_rule,
    doc='Output may not increase faster than the ramping up gradient')
def res_timevar_output_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['ramp-up-grad'][(stf, sit, pro)] *
                m.r_out_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

If the process has both partial operation and time variable efficiency, the code changes to:

m.res_partial_timevar_output_rampup = pyomo.Constraint(
    m.tm, m.pro_rampup_bigger_minfraction_output_tuples &
          m.pro_partial_on_off_output_tuples & m.pro_timevar_output_tuples,
    rule=res_partial_timevar_output_rampup_rule,
    doc='Output may not increase faster than the ramping up gradient')
def res_partial_timevar_output_rampup_rule(m, tm, stf, sit, pro, com):
    if tm != m.timesteps[1]:
        return (m.e_pro_out[tm - 1, stf, sit, pro, com] +
                m.cap_pro[stf, sit, pro] * m.dt *
                m.process_dict['ramp-up-grad'][(stf, sit, pro)] *
                m.r_out_min_fraction_dict[(stf, pro, com)] *
                m.eff_factor_dict[(sit, pro)][stf, tm] >=
                m.e_pro_out[tm, stf, sit, pro, com])
    else:
        return pyomo.Constraint.Skip

Process Start-Up Rule: The constraint process start-up rule marks in the variable process start marker \(\sigma_{yvpt}\) whether a process \(p\) started in timestep \(t\) or not. The mathematical explanation of this rule is given in Advanced Processes.

In script AdvancedProcesses.py the constraint process start ups rule is defined and calculated by the following code fragment:

m.res_start_up = pyomo.Constraint(
    m.tm, m.pro_start_up_tuples,
    rule=res_start_ups_rule,
    doc='start >= on_off(t) - on_off(t-1)')
def res_start_up_rule(m, t, stf, sit, pro):
    return (m.start_up[t, stf, sit, pro] >= m.on_off[t, stf, sit, pro] -
                                             m.on_off[t - 1, stf, sit, pro])