CapacityCostLink

CapacityCostLink links model the transport of energy between two nodes with capacity-dependent operational costs applied to a specified resource. Unlike standard Direct links, they enable cost modeling based on maximum capacity utilization over defined time periods. This is useful for applications such as transmission networks, pipelines, or interconnectors where usage fees scale with peak capacity demands.

In addition, they only allow the transport of a single, specified Resource.

Changed behavior between 0.3 and 0.4

The meaning of the field cap_period_duration was changed when moving from 0.3 to 0.4:

  1. When specifying a number, the previous meaning of the number of operational periods was changed to the sum of the durations of the operational periods. The reason for this change is to make the link behavior less dependent on the operational resolution. The following change is hence required if you have operational durations differing from 1:

    # time structure
    ts = SimpleTimes(10, 2)
    
    # old behavior, corresponding to 2 periods
    cap_period_duration = 2
    
    # new behavior, corresponding to periods whocse duration sums to at least 4
    cap_period_duration = 4
  2. When specifying a vector, the previous scaling based on the chosen value of op_per_strat was removed as it is in our opinion more straightforward to base it on the actual operational time structure. The following change is hence required:

    # time structure
    ts = Twolevel(2, 1, SimpleTimes(10, 2); op_per_strat=8760.0)
    
    # old behavior, corresponding to 5 periods a 1752 duration based on `op_per_strat`
    cap_period_duration = [1752, 1752, 1752, 1752, 1752]
    
    # new behavior, corresponding to 5 periods a 4 duration based on `SimpleTimes`
    cap_period_duration = [4, 4, 4, 4, 4]

CapacityCostLink is implemented as equivalent to an abstract type Link. Hence, it utilizes the same functions declared in EnergyModelsBase.

CapacityCostLink has the following standard fields, equivalent to a Direct link:

  • id :
    The field id is only used for providing a name to the link.
  • from::Node :
    The node from which there is flow into the link.
  • to::Node :
    The node to which there is flow out of the link.
  • formulation::Formulation :
    The used formulation of links. If not specified, a Linear link is assumed.
    Different formulations

    The current implementation of links does not provide another formulation. Our aim is in a later stage to allow the user to switch fast through different formulations to increase or decrese the complexity of the model.

The following additional fields are included for CapacityCostLink links:

  • cap::TimeProfile :
    The maximum transport capacity of the link for the cap_resource. If the link should contain investments through the application of EnergyModelsInvestments, it is important to note that you can only use FixedProfile or StrategicProfile for the capacity, but not RepresentativeProfile or OperationalProfile. In addition, all values have to be non-negative.

  • cap_price::TimeProfile :
    The price per unit of maximum capacity usage over the sub-periods. This value is averaged over sub-periods as defined by cap_price_periods. All values have to be non-negative.

    Price values

    The value given in cap_price is interpreted on the strategic-period scale (e.g., if a strategic-period duration of 1 corresponds to 1 year, then the natural unit is €/GW/year). Capacity costs are calculated per sub-period and then summed over the strategic period. This means a constant value (e.g., €/GW/year) is effectively applied once for each sub-period (based on the peak within that sub-period), and is not automatically scaled by sub-period duration.

    Example:

    # Modelling a full year with hourly resolution
    ts = TwoLevel(1, 1, SimpleTimes(8760, 1); op_per_strat=8760.0)
    
     # 12 price periods corresponding to months
    cap_price_periods = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] .* 24
    
    cap_price = 100 # €/GW/year

    If the peak usage is 1 GW in each month, the model computes a total cost of 12 × 100 = 1200 €/year.

    To achieve seasonal/monthly peak charges, define multiple cap_price_periods and provide cap_price values that represent the intended charge per sub-period (or scale the values accordingly).

    It is planned to change this behavior in the future. The change corresponds to a breaking change as we change the behavior of the model.

  • cap_period_duration::TimeProfile :
    Defines the total duration of a capacity price period.
    For instance, if the duration of 1 of the operational time structure is 1 hour and period_duration = FixedProfile(24), then each capacity price period spans one day. The capacity price of this node (for a given day, see below) is the given by the maximum capacity usage within a day.
    Due to a constructor, it can either be specified as number (the same duration in all capacity price periods), as a vector (varying duration of each capacity price period), or as a time profile (e.g., varying period durations due to varying operational time structures). It cannot be specified as OperationalProfile and must be positive for each individual value.

    Duration of capacity price periods

    For investment periods with many operational periods, consider decreasing cap_period_duration. The CapacityCostLink capacity constraints couple operational periods and can significantly increase solve time. Splitting the horizon into multiple sub-periods reduces this coupling and often makes the problem much easier to solve. In some cases, this also means using more than one capacity price period even if capacity costs occur only annually in reality, depending on model size and complexity.

  • cap_resource::Resource :
    The Resource for which capacity-dependent costs are applied. This Resource is the only transported Resource by a CapacityCostLink.

  • data::Vector{<:ExtensionData}:
    An entry for providing additional data to the model. In the current version, it is used for providing additional investment data when EnergyModelsInvestments is used.

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 parantheses.

CapacityCostLink utilizes standard variables from the Link type, as described on the page Optimization variables:

Two additional variables track capacity utilization and associated costs over sub-periods:

  • $\texttt{ccl\_cap\_use\_max}[l, t_{pd}]$: Maximum capacity usage in sub-period $t_{pd}$ for link $l$.
  • $\texttt{ccl\_cap\_use\_cost}[l, t_{pd}]$: Operational cost in sub-period $t_{pd}$ for link $l$.

The applied standard constraint for capacity installed is:

\[\texttt{link\_cap\_inst}[l, t] = capacity(l, t)\]

and the no-loss constraint

\[\texttt{link\_out}[l, t, p] = \texttt{link\_in}[l, t, p] \quad \forall p \in inputs(l)\]

All additional constraints are created within a new method for the function create_link.

The capacity utilization constraint tracks the maximum usage within each sub-period $t_{sub}$:

\[\texttt{link\_in}[l, t, cap\_resource(l)] \leq \texttt{ccl\_cap\_use\_max}[l, t_{pd}]\]

The capacity cost is calculated as:

\[\texttt{ccl\_cap\_use\_cost}[l, t_{pd}] = \texttt{ccl\_cap\_use\_max}[l, t_{pd}] \times \overline{cap\_price}(l, t_{pd})\]

where $\overline{cap\_price}$ is the average capacity price over the sub-period calculated as:

\[\overline{cap\_price}(l, t_{pd}) = \frac{\sum_{t \in t_{pd}} cap\_price(l, t) \times duration(t)}{\sum_{t \in t_{pd}} duration(t)}\]

Finally, costs are aggregated to each strategic period:

\[\texttt{link\_opex\_var}[l, t_{inv}] = \sum_{t_{pd} \in t_{inv}} \texttt{ccl\_cap\_use\_cost}[l, t_{pd}]\]

In addition, the energy flow of the constrained resource should not exceed the maximum capacity, which is included through the following constraint:

\[\texttt{flow\_in}[l, t, cap\_resource(l)] \leq \texttt{link\_cap\_inst}[l, t]\]