LoadShiftingNode

LoadShiftingNode is a specialized Sink node that allows for batch-wise load shifting. It is designed for demand profiles where discrete production batches can be rescheduled within defined working shifts. This flexibility allows modeling of industrial processes that can shift load within operational constraints. LoadShiftingNodes introduce integer and continuous variables to allow demand shifting across time, subject to batching, balance, and capacity constraints.

Warning

This node is designed for uniform timestep durations. Irregular durations may cause misalignment of shifted loads.

Experimental node

The node is experimental and has in its current version a lot of prerequisites:

  • This node is designed for uniform timestep durations. Irregular durations may cause misalignment of shifted loads.
  • The node utilizes the indices of the operational period. It cannot be used with OperationalScenarios and RepresentativePeriods.

Its application should be carefully evaluated.

Introduced type and its fields

The LoadShiftingNode extends the basic Sink with load shifting logic based on indexed operational periods and discrete batch shifts.

The fields of a LoadShiftingNode are:

  • id:
    Identifier for the node.
  • cap::TimeProfile:
    The original, unshifted demand profile.
  • penalty::Dict{Symbol,<:TimeProfile}:
    Penalties for :surplus and :deficit, though not actively used in the load shifting formulation.
  • input::Dict{<:Resource,<:Real}:
    Resource inputs and their conversion factors.
  • load_shift_times::Vector{<:Int}:
    Indices of time steps where batches may be shifted from/to.
  • load_shifts_per_period::Int:
    Maximum number of batch shifts allowed within each load shifting group.
  • load_shift_duration::Int:
    Number of consecutive periods each load shift lasts.
  • load_shift_magnitude::Real:
    The magnitude of demand shifted per period in a batch.
  • load_shift_times_per_period::Int:
    Number of time steps per shift group in which shifts may occur.
  • data::Vector{Data}:
    Optional metadata (e.g., emissions, investment data).
Warning

This node is designed for uniform timestep durations. Irregular durations may cause misalignment of shifted loads.

No investments

Investments are not implemented for this node.

Mathematical description

In the following mathematical equations, we use the name for variables and functions used in the model. Variables are in general represented as

$\texttt{var\_example}[index_1, index_2]$

with square brackets, while functions are represented as

$func\_example(index_1, index_2)$

with paranthesis.

Variables

In addition to standard Sink variables:

the node introduces:

  • $\texttt{load\_shift\_from}[n, t]$:
    Integer variable for number of batches shifted away from operational period $t$. This variable is only defined for the operational periods given by the vector load_shift_times.
  • $\texttt{load\_shift\_to}[n, t]$:
    Integer variable for number of batches shifted to operational period $t$. This variable is only defined for the operational periods given by the vector load_shift_times.
  • $\texttt{load\_shifted}[n, t]$:
    Continuous variable representing the net capacity added or removed via load shifting at operational period $t$.

Constraints

The following sections omit the direct inclusion of the vector of LoadShiftingNode nodes. Instead, it is implicitly assumed that the constraints are valid $\forall n ∈ N$ for all LoadShiftingNode types if not stated differently. In addition, all constraints are valid $\forall t \in T$ (that is in all operational periods) or $\forall t_{inv} \in T^{Inv}$ (that is in all investment periods).

Standard constraints

Load shifting nodes nodes utilize in general the standard constraints described on Constraint functions. In fact, they use the same create_node function as a RefSource node. These standard constraints are:

  • constraints_flow_in:

    \[\texttt{flow\_in}[n, t, p] = inputs(n, p) \times \texttt{cap\_use}[n, t] \qquad \forall p \in inputs(n)\]

    Multiple inputs

    The constrained above allows for the utilization of multiple inputs with varying ratios. It is however necessary to deliver the fixed ratio of all inputs.

  • constraints_opex_fixed:
    The current implementation fixes the fixed operating expenses of a sink to 0.

    \[\texttt{opex\_fixed}[n, t_{inv}] = 0\]

  • constraints_opex_var:

    \[\begin{aligned} \texttt{opex\_var}[n, t_{inv}] = & \\ \sum_{t \in t_{inv}} & surplus\_penalty(n, t) \times \texttt{sink\_surplus}[n, t] + \\ & deficit\_penalty(n, t) \times \texttt{sink\_deficit}[n, t] \times \\ & scale\_op\_sp(t_{inv}, t) \end{aligned}\]

    The function `scale_op_sp`

    The function $scale\_op\_sp(t_{inv}, t)$ calculates the scaling factor between operational and investment periods. It also takes into account potential operational scenarios and their probability as well as representative periods.

  • constraints_data:
    This function is only called for specified additional data, see above.

The function constraints_capacity receives a new method to handle the load shifting constraints:

  • constraints_capacity

    • Group-level limits on load shifts:

      For each group of $n.load\_shift\_times\_per\_period$ steps:

      \[\sum \texttt{load\_shift\_from}[n, \text{group}] \leq n.load\_shifts\_per\_period\]

      \[\sum \texttt{load\_shift\_to}[n, \text{group}] \leq n.load\_shifts\_per\_period\]

      \[\sum \texttt{load\_shift\_from}[n, \text{group}] = \sum \texttt{load\_shift\_to}[n, \text{group}]\]

      This ensures no net addition or removal of demand—only rescheduling.

    • Define shifted load across duration:

      For each time $t$ in $n.load\_shift\_times$, and for each period $t+i$ in $n.load\_shift\_duration$:

      \[\texttt{load\_shifted}[n, t+i] = n.load\_shift\_magnitude \times (\texttt{load\_shift\_to}[n, t] - \texttt{load\_shift\_from}[n, t])\]

    • Zero shifted load outside batch duration periods:

      \[\texttt{load\_shifted}[n, t] = 0 \qquad \forall t \notin \text{shifted batch times}\]

    • Final demand with shifted load:

      \[\texttt{cap\_use}[n, t] = \texttt{cap\_inst}[n, t] + \texttt{load\_shifted}[n, t]\]

    Batch interpretation

    Each shift moves a batch of demand of fixed size and duration. Shifted batches cannot be split or partially allocated—this preserves discrete process modeling.

    Integer programming

    Load shifting relies on integer variables (load_shift_from, load_shift_to), making this a mixed-integer problem (MIP).