Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructuring of function flow #48

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
14 changes: 6 additions & 8 deletions docs/src/library/internals/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ CurrentModule = EnergyModelsBase

```@docs
create_link
objective(m, 𝒩, 𝒯, 𝒫, ℒ, modeltype::EnergyModel)
objective(m, 𝒳, 𝒫, 𝒯, modeltype::EnergyModel)
objective_operational
emissions_operational
```

## Constraint functions
Expand All @@ -33,15 +35,11 @@ constraints_level_bounds

```@docs
variables_capacity
variables_capex(m, 𝒩, 𝒯, modeltype::EnergyModel)
variables_emission
variables_flow
variables_opex
variables_nodes
variables_links
variables_links_capacity
variables_links_opex
variables_links_capex(m, ℒ, 𝒯, modeltype::EnergyModel)
variables_capex(m, 𝒩::Vector{<:Node}, 𝒯, modeltype::EnergyModel)
variables_emission
variables_elements
```

## Check functions
Expand Down
6 changes: 3 additions & 3 deletions docs/src/library/internals/reference_EMIExt.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ StorageInvData

```@docs
check_inv_data
objective_invest
```

## EnergyModelsBase

### Methods

```@docs
EMB.variables_capex(m, 𝒩, 𝒯, modeltype::AbstractInvestmentModel)
EMB.variables_links_capex(m, , 𝒯, modeltype::AbstractInvestmentModel)
EMB.variables_capex(m, 𝒩::Vector{<:EMB.Node}, 𝒯, modeltype::AbstractInvestmentModel)
EMB.objective(m, 𝒳, 𝒫, 𝒯, modeltype::AbstractInvestmentModel)
EMB.constraints_capacity_installed(m, n::EMB.Node, 𝒯::TimeStructure, modeltype::AbstractInvestmentModel)
EMB.objective(m, 𝒩, 𝒯, 𝒫, ℒ, modeltype::AbstractInvestmentModel)
EMB.check_node_data(n::EMB.Node, data::InvestmentData, 𝒯, modeltype::AbstractInvestmentModel, check_timeprofiles::Bool)
```

Expand Down
114 changes: 66 additions & 48 deletions ext/EMIExt/objective.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
EMB.objective(m, 𝒩, 𝒯, 𝒫, , modeltype::AbstractInvestmentModel)
EMB.objective(m, 𝒳, 𝒫, 𝒯, modeltype::AbstractInvestmentModel)

Create objective function overloading the default from EMB for `AbstractInvestmentModel`.

Expand All @@ -14,68 +14,86 @@ These variables would need to be introduced through the package `SparsVariables`
Both are not necessary, as it is possible to include them through the OPEX values, but it
would be beneficial for a better separation and simpler calculations from the results.
"""
function EMB.objective(m, 𝒩, 𝒯, 𝒫, , modeltype::AbstractInvestmentModel)
function EMB.objective(m, 𝒳, 𝒫, 𝒯, modeltype::AbstractInvestmentModel)

# Extraction of the individual subtypes for investments in nodes
𝒯ᴵⁿᵛ = strategic_periods(𝒯)

# Filtering through the individual nodes
𝒩ᶜᵃᵖ = EMB.nodes_not_av(𝒩) # Nodes with capacity
𝒩ᴵⁿᵛ = filter(has_investment, filter(!EMB.is_storage, 𝒩))
𝒩ˢᵗᵒʳ = filter(EMB.is_storage, 𝒩)
𝒩ˡᵉᵛᵉˡ = filter(n -> has_investment(n, :level), 𝒩ˢᵗᵒʳ)
𝒩ᶜʰᵃʳᵍᵉ = filter(n -> has_investment(n, :charge), 𝒩ˢᵗᵒʳ)
𝒩ᵈⁱˢᶜʰᵃʳᵍᵉ = filter(n -> has_investment(n, :discharge), 𝒩ˢᵗᵒʳ)

# Filtering through the individual links
ℒᵒᵖᵉˣ = filter(has_opex, ℒ)
ℒᴵⁿᵛ = filter(has_investment, ℒ)

𝒫ᵉᵐ = filter(EMB.is_resource_emit, 𝒫) # Emissions resources

disc = Discounter(discount_rate(modeltype), 𝒯)

# Calculation of the OPEX contribution
opex = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum((m[:opex_var][n, t_inv] + m[:opex_fixed][n, t_inv]) for n ∈ 𝒩ᶜᵃᵖ)
)
# Calculation of the OPEX and CAPEX contributions
opex = JuMP.Containers.DenseAxisArray[]
capex = JuMP.Containers.DenseAxisArray[]
for elements ∈ 𝒳
push!(opex, EMB.objective_operational(m, elements, 𝒯ᴵⁿᵛ, modeltype))
push!(capex, objective_invest(m, elements, 𝒯ᴵⁿᵛ, modeltype))
end
push!(opex, EMB.objective_operational(m, 𝒫, 𝒯ᴵⁿᵛ,modeltype))

link_opex = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum((m[:link_opex_var][l, t_inv] + m[:link_opex_fixed][l, t_inv]) for l ∈ ℒᵒᵖᵉˣ)
)

# Calculation of the emission costs contribution
emissions = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum(
m[:emissions_strategic][t_inv, p] * emission_price(modeltype, p, t_inv) for
p ∈ 𝒫ᵉᵐ
)
)

# Calculation of the capital cost contribution of standard nodes
capex_cap = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum(m[:cap_capex][n, t_inv] for n ∈ 𝒩ᴵⁿᵛ)
# Calculation of the objective function.
@objective(m, Max,
-sum(
sum(elements[t_inv] for elements ∈ opex) *
duration_strat(t_inv) * objective_weight(t_inv, disc; type = "avg") +
sum(elements[t_inv] for elements ∈ capex) *
objective_weight(t_inv, disc)
for t_inv ∈ 𝒯ᴵⁿᵛ)
)
end
"""
objective_invest(m, elements, 𝒯ᴵⁿᵛ::TS.AbstractStratPers, modeltype::EnergyModel)

Create JuMP expressions indexed over the investment periods `𝒯ᴵⁿᵛ` for different elements.
The expressions correspond to the investments into the different elements. They are not
discounted and do not take the duration of the investment periods into account.

By default, objective expressions are included for:
- `elements = 𝒩::Vector{<:Node}`. In the case of a vector of nodes, the function returns the
sum of the capital expenditures for all nodes whose method of the function
[`has_investment`](@ref) returns true. In the case of [`Storage`](@ref) nodes, all capacity
investments are considired
- `elements = 𝒩::Vector{<:Link}`. In the case of a vector of links, the function returns the
sum of the capital expenditures for all links whose method of the function
[`has_investment`](@ref) returns true.

!!! note "Default function"
It is also possible to provide a tuple `𝒳` for only operational or only investment
objective contributions. In this situation, the expression returns a value of 0 for all
investment periods.
"""
function objective_invest(
m,
𝒩::Vector{<:EMB.Node},
𝒯ᴵⁿᵛ::TS.AbstractStratPers,
modeltype::AbstractInvestmentModel,
)
# Declaration of the required subsets
𝒩ᴵⁿᵛ = filter(has_investment, filter(!EMB.is_storage, 𝒩))
𝒩ˢᵗᵒʳ = filter(EMB.is_storage, 𝒩)
𝒩ˡᵉᵛᵉˡ = filter(n -> has_investment(n, :level), 𝒩ˢᵗᵒʳ)
𝒩ᶜʰᵃʳᵍᵉ = filter(n -> has_investment(n, :charge), 𝒩ˢᵗᵒʳ)
𝒩ᵈⁱˢᶜʰᵃʳᵍᵉ = filter(n -> has_investment(n, :discharge), 𝒩ˢᵗᵒʳ)

# Calculation of the capital cost contribution of storage nodes
capex_stor = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
return @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum(m[:cap_capex][n, t_inv] for n ∈ 𝒩ᴵⁿᵛ) +
sum(m[:stor_level_capex][n, t_inv] for n ∈ 𝒩ˡᵉᵛᵉˡ) +
sum(m[:stor_charge_capex][n, t_inv] for n ∈ 𝒩ᶜʰᵃʳᵍᵉ) +
sum(m[:stor_discharge_capex][n, t_inv] for n ∈ 𝒩ᵈⁱˢᶜʰᵃʳᵍᵉ)
)
end
function objective_invest(
m,
ℒ::Vector{<:Link},
𝒯ᴵⁿᵛ::TS.AbstractStratPers,
modeltype::AbstractInvestmentModel,
)
# Declaration of the required subsets
ℒᴵⁿᵛ = filter(has_investment, ℒ)

# Calculation of the capital cost contribution of Links
capex_link = @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
return @expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ],
sum(m[:link_cap_capex][l, t_inv] for l ∈ ℒᴵⁿᵛ)
)

# Calculation of the objective function.
@objective(m, Max,
-sum(
(opex[t_inv] + link_opex[t_inv] + emissions[t_inv]) *
duration_strat(t_inv) * objective_weight(t_inv, disc; type = "avg") +
(capex_cap[t_inv] + capex_stor[t_inv] + capex_link[t_inv]) *
objective_weight(t_inv, disc)
for t_inv ∈ 𝒯ᴵⁿᵛ)
)
end
objective_invest(m, _, 𝒯ᴵⁿᵛ::TS.AbstractStratPers, _::AbstractInvestmentModel) =
@expression(m, [t_inv ∈ 𝒯ᴵⁿᵛ], 0)
72 changes: 34 additions & 38 deletions ext/EMIExt/variables_capex.jl
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
"""
EMB.variables_capex(m, 𝒩, 𝒯, modeltype::AbstractInvestmentModel)
EMB.variables_capex(m, 𝒩::Vector{<:EMB.Node}, 𝒯, modeltype::AbstractInvestmentModel)
EMB.variables_capex(m, ℒ::Vector{<:Link}, 𝒯, modeltype::AbstractInvestmentModel)

Create variables for the capital costs for the investments in storage and technology nodes.
Declaration of different capital expenditures (CAPEX) variables for the element types
introduced in `EnergyModelsBase`. CAPEX variables are only introduced for elements that have
in investments as identified through the function
[`EMI.has_investment`](@ref EnergyModelsInvestments.has_investment). All investment
variables are declared for all investment periods.

Additional variables for investment in capacity:
* `:cap_capex` - CAPEX costs for a technology
* `:cap_current` - installed capacity for storage in each strategic period
* `:cap_add` - added capacity
* `:cap_rem` - removed capacity
* `:cap_invest_b` - binary variable whether investments in capacity are happening
* `:cap_remove_b` - binary variable whether investments in capacity are removed
`EnergyModelsBase` introduces two elements for an energy system, and hence, provides the
user with two individual methods for both `𝒩::Vector{<:EMB.Node}` and 𝒩::Vector{<:Link}.

!!! note "Variables and naming conventions"
The individual capacities require the same variable although with different names.
Hence, `**prefix**` should be replaced in the following to

Additional variables for investment in storage:
* `:stor_level_capex` - CAPEX costs for increases in the capacity of a storage
* `:stor_level_current` - installed capacity for storage in each strategic period
* `:stor_level_add` - added capacity
* `:stor_level_rem` - removed capacity
* `:stor_level_invest_b` - binary variable whether investments in capacity are happening
* `:stor_level_remove_b` - binary variable whether investments in capacity are removed
- `cap` for all nodes with investments except for [`Storage`](@ref) and
[`Availability`](@ref) nodes,
- `stor_level` for the storage level capacity of [`Storage`](@ref) nodes,
- `stor_charge` for the charge capacity of [`Storage`](@ref) nodes,
- `stor_discharge` for the discharge capacity of [`Storage`](@ref) nodes, and
- `link_cap` for [`Link`]s.

* `:stor_charge_capex` - CAPEX costs for increases in the rate of a storage
* `:stor_charge_current` - installed rate for storage in each strategic period
* `:stor_charge_add` - added rate
* `:stor_charge_rem` - removed rate
* `:stor_charge_invest_b` - binary variable whether investments in rate are happening
* `:stor_charge_remove_b` - binary variable whether investments in rate are removed
The individual variables are then given by:

- `**prefix**_capex` are the capital expenditures in node `n` in investment period
`t_inv`. The CAPEX variable take into account the invested capacity.
- `**prefix**_current` is the capacity of node `n` in investment period `t_inv`. It is
introduced in addition to `cap_inst` to simplify the model design.
- `**prefix**_add` are the additions in the installed capacity of node `n` in investment
period `t_inv`. Capacity additions are occuring at the beginning of an investment period.
- `**prefix**_rem` are the reduction in the installed capacity of node `n` in investment
period `t_inv`. Capacity reductions are occuring at the end of an investment period.
- `**prefix**_invest_b` is an auxiliary variable used in some investment modes for the
additions in capacities.
- `**prefix**_remove_b` is an auxiliary variable used in some investment modes for the
reduction of capacities.
"""
function EMB.variables_capex(m, 𝒩, 𝒯, modeltype::AbstractInvestmentModel)
function EMB.variables_capex(m, 𝒩::Vector{<:EMB.Node}, 𝒯, modeltype::AbstractInvestmentModel)
𝒩ᴵⁿᵛ = filter(has_investment, filter(!EMB.is_storage, 𝒩))
𝒩ˢᵗᵒʳ = filter(EMB.is_storage, 𝒩)
𝒩ˡᵉᵛᵉˡ = filter(n -> has_investment(n, :level), 𝒩ˢᵗᵒʳ)
Expand Down Expand Up @@ -73,21 +83,7 @@ function EMB.variables_capex(m, 𝒩, 𝒯, modeltype::AbstractInvestmentModel)
container = IndexedVarArray
)
end

"""
EMB.variables_links_capex(m, ℒ, 𝒯, modeltype::AbstractInvestmentModel)

Create variables for the capital costs for the investments in [`Link`](@ref)s.

Additional variables for investment in capacity:
* `:link_cap_capex` - CAPEX costs for a technology
* `:link_cap_current` - installed capacity for storage in each strategic period
* `:link_cap_add` - added capacity
* `:link_cap_rem` - removed capacity
* `:link_cap_invest_b` - binary variable whether investments in capacity are happening
* `:link_cap_remove_b` - binary variable whether investments in capacity are removed
"""
function EMB.variables_links_capex(m, ℒ, 𝒯, modeltype::AbstractInvestmentModel)
function EMB.variables_capex(m, ℒ::Vector{<:Link}, 𝒯, modeltype::AbstractInvestmentModel)
ℒᴵⁿᵛ = filter(has_investment, ℒ)
𝒯ᴵⁿᵛ = strategic_periods(𝒯)

Expand Down
Loading
Loading