Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 5 additions & 5 deletions docs/src/links/capacitycostlink.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ with paranthesis.

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

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

### [Constraints](@id links-CapacityCostLink-math-con)

Expand All @@ -117,21 +117,21 @@ All additional constraints are created within a new method for the function [`cr
The capacity utilization constraint tracks the maximum usage within each sub-period:

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

The capacity cost is calculated as:

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

where ``\overline{cap\_price}`` is the average capacity price over the sub-period.

Finally, costs are aggregated to each strategic period:

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

In addition, the energy flow of the constrained resource should not exceed the maximum pipe capacity, which is included through the following constraint:
Expand Down
21 changes: 13 additions & 8 deletions src/link/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
EMB.variables_element(m, ℒˢᵘᵇ::Vector{<:CapacityCostLink}, 𝒯, modeltype::EnergyModel)

Creates the following additional variable for **ALL** capacity cost links:
- `ccl_max_cap_use[l, t]` is a continuous variable describing the maximum capacity
- `ccl_cap_use_max[l, t]` is a continuous variable describing the maximum capacity
usage over sub periods for a [`CapacityCostLink`](@ref) `l` in operational period `t`.
- `ccl_cap_cost[l, t]` is a continuous variable describing the cost over sub periods
- `ccl_cap_use_cost[l, t]` is a continuous variable describing the cost over sub periods
for a [`CapacityCostLink`](@ref) `l` in operational period `t`.
"""
function EMB.variables_element(m, ℒˢᵘᵇ::Vector{<:CapacityCostLink}, 𝒯, ::EnergyModel)
@variable(m, ccl_max_cap_use[ℒˢᵘᵇ, 𝒯] >= 0)
@variable(m, ccl_cap_cost[ℒˢᵘᵇ, 𝒯] >= 0)
@variable(m, ccl_cap_use_max[ℒˢᵘᵇ, 𝒯] >= 0)
@variable(m, ccl_cap_use_cost[ℒˢᵘᵇ, 𝒯] >= 0)
end

"""
Expand Down Expand Up @@ -46,20 +46,25 @@ function EMB.create_link(

# Max capacity use constraints
@constraint(m, [t_sub ∈ 𝒯ˢᵘᵇ, t ∈ t_sub],
m[:link_in][l, t, p_cap] .≤ m[:ccl_max_cap_use][l, t_sub]
m[:link_in][l, t, p_cap] .≤ m[:ccl_cap_use_max][l, t_sub]
)

# Capacity cost constraint
@constraint(m, [t_sub ∈ 𝒯ˢᵘᵇ],
m[:ccl_cap_cost][l, t_sub[end]] ==
m[:ccl_max_cap_use][l, t_sub[end]] * avg_cap_price(l, t_sub)
m[:ccl_cap_use_cost][l, t_sub[end]] ==
m[:ccl_cap_use_max][l, t_sub[end]] * avg_cap_price(l, t_sub)
)

# Sum up costs for each sub_period into the strategic period cost
@constraint(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
m[:link_opex_var][l, t_inv] ==
sum(m[:ccl_cap_cost][l, t] for t ∈ t_inv)
sum(m[:ccl_cap_use_cost][l, t] for t ∈ t_inv)
)

# Fix the fixed OPEX to avoid unconstrainted variables
for t_inv ∈ 𝒯ᴵⁿᵛ
fix(m[:link_opex_fixed][l, t_inv], 0; force = true)
end
end

"""
Expand Down
12 changes: 6 additions & 6 deletions test/link/test_CapacityCostLink.jl
Original file line number Diff line number Diff line change
Expand Up @@ -207,27 +207,27 @@ end
)

# Max capacity use per sub-period:
# link_in[t] ≤ ccl_max_cap_use[t_sub_end]
# link_in[t] ≤ ccl_cap_use_max[t_sub_end]
@test all(
all(
value(m[:link_in][cc_link, t, power]) ≲
value(m[:ccl_max_cap_use][cc_link, t_sub[end]])
value(m[:ccl_cap_use_max][cc_link, t_sub[end]])
for t ∈ t_sub
)
for t_sub ∈ 𝒯ˢᵘᵇ
)

# Capacity cost at end of sub-period: cap_cost == max_cap_use * avg_cap_price
@test all(
value(m[:ccl_cap_cost][cc_link, t_sub[end]]) ≈
value(m[:ccl_max_cap_use][cc_link, t_sub[end]]) * EMF.avg_cap_price(cc_link, t_sub)
value(m[:ccl_cap_use_cost][cc_link, t_sub[end]]) ≈
value(m[:ccl_cap_use_max][cc_link, t_sub[end]]) * EMF.avg_cap_price(cc_link, t_sub)
for t_sub ∈ 𝒯ˢᵘᵇ
)

# Strategic-period sum: link_opex_var == sum(ccl_cap_cost over t_inv)
# Strategic-period sum: link_opex_var == sum(ccl_cap_use_cost over t_inv)
@test all(
value(m[:link_opex_var][cc_link, t_inv]) ≈
sum(value(m[:ccl_cap_cost][cc_link, t]) for t ∈ t_inv)
sum(value(m[:ccl_cap_use_cost][cc_link, t]) for t ∈ t_inv)
for t_inv ∈ 𝒯ᴵⁿᵛ
)

Expand Down