From 9e1909cb88429380e2c9c391ba9f12c2ba5ffedb Mon Sep 17 00:00:00 2001 From: Julian Straus <104911227+JulStraus@users.noreply.github.com> Date: Wed, 21 Aug 2024 08:41:22 +0200 Subject: [PATCH] Inclusion of potential for `TransmissionMode` emissions (#26) * Include modeling of emissions based on initial proposal * Changed the structure for inclusion of emissions --------- Co-authored-by: Truls Flatberg --- NEWS.md | 6 +++++ src/constraint_functions.jl | 22 +++++++++++++++++ src/model.jl | 47 +++++++++++++++++++++++++++++++++++++ src/structures/mode.jl | 31 ++++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5f7d4ad..83abd9c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,12 @@ * This approach required `EnergyModelsGeography` to include all functions and type declarations internally. * An extension was introduced to handle these problems. +### Introduced potential for emissions of `TransmissionMode`s + +* As outlined in [Issue 9](https://github.com/EnergyModelsX/EnergyModelsGeography.jl/issues/9), there is a requirement for potential emissions from `TransmissionMode`s. +* The clean approach was not achieved within a certain timeframe, hence, a limited approach is implemented based on the initial provided branches in both [`EMB`](https://github.com/EnergyModelsX/EnergyModelsBase.jl/tree/0.7/emissions) and [`EMG`](https://github.com/EnergyModelsX/EnergyModelsGeography.jl/tree/0.9/emissions). +* The implementation is **not** tested! + ## Version 0.9.1 (2024-05-24) ### Bugfix diff --git a/src/constraint_functions.jl b/src/constraint_functions.jl index bcb232b..1799d7c 100644 --- a/src/constraint_functions.jl +++ b/src/constraint_functions.jl @@ -234,3 +234,25 @@ function constraints_opex_var(m, tm::TransmissionMode, 𝒯ᴡⁿᡛ, modeltype: ) end end + +""" + constraints_emission(m, tm::TransmissionMode, 𝒯, modeltype::EnergyModel) + +Function for creating the constraints on the emissions of a generic `TransmissionMode` `tm`. +This function serves as fallback option if no other function is specified for a +`TransmissionMode`. +""" +function constraints_emission(m, tm::TransmissionMode, 𝒯, modeltype::EnergyModel) + + if is_bidirectional(tm) + @constraint(m, [t ∈ 𝒯, p_em ∈ emit_resources(tm)], + m[:emissions_trans][tm, t, p_em] == + emission(tm, p_em, t) * (m[:trans_pos][tm, t] + m[:trans_neg][tm, t]) + ) + else + @constraint(m, [t ∈ 𝒯, p_em ∈ emit_resources(tm)], + m[:emissions_trans][tm, t, p_em] == + emission(tm, p_em, t) * m[:trans_out][tm, t] + ) + end +end diff --git a/src/model.jl b/src/model.jl index f890927..5bda1fa 100644 --- a/src/model.jl +++ b/src/model.jl @@ -40,11 +40,15 @@ function create_model(case, modeltype::EnergyModel, m::JuMP.Model; check_timepro variables_trans_opex(m, 𝒯, β„³, modeltype) variables_trans_capacity(m, 𝒯, β„³, modeltype) variables_trans_modes(m, 𝒯, β„³, modeltype) + variables_trans_emission(m, 𝒯, β„³, 𝒫, modeltype) # Construction of constraints for areas and transmission corridors constraints_area(m, π’œ, 𝒯, ℒᡗʳᡃⁿ˒, 𝒫, modeltype) constraints_transmission(m, 𝒯, β„³, modeltype) + # Updates the global constraint on total emissions + update_total_emissions(m, 𝒯, β„³, 𝒫, modeltype) + # Updates the objective function update_objective(m, 𝒯, β„³, modeltype) @@ -173,6 +177,27 @@ function variables_trans_mode(m, 𝒯, β„³α΄Έα΄Ύ::Vector{<:PipeLinepackSimple}, @variable(m, linepack_stor_level[β„³α΄Έα΄Ύ, 𝒯] >= 0) end +""" + variables_trans_emission(m, 𝒯, β„³, 𝒫, modeltype) + +Creates variables for the modeling of tranmission emissions. These variables +are only created for transmission modes where emissions are included. +All emission resources that are not included for a type are fixed to a value of 0. + +The emission variables are differentiated in: +* `:emissions_node` - emissions of a transmission mode in an operational period, +""" +function variables_trans_emission(m, 𝒯, β„³, 𝒫, modeltype) + ℳᡉᡐ = filter(m -> has_emissions(m), β„³) + 𝒫ᡉᡐ = EMB.res_sub(𝒫, ResourceEmit) + + @variable(m, emissions_trans[ℳᡉᡐ, 𝒯, 𝒫ᡉᡐ] >= 0) + + # Fix of unused emission variables to avoid free variables + for tm ∈ ℳᡉᡐ, p_em ∈ setdiff(𝒫ᡉᡐ, emit_resources(tm)), t ∈ 𝒯 + fix(m[:emissions_trans][tm, t, p_em], 0; force = true) + end +end """ constraints_area(m, π’œ, 𝒯, ℒᡗʳᡃⁿ˒, 𝒫, modeltype::EnergyModel) @@ -277,6 +302,25 @@ function update_objective(m, 𝒯, β„³, modeltype::EnergyModel) @objective(m, Max, obj) end +""" + update_total_emissions(m, 𝒯, β„³, 𝒫, modeltype::EnergyModel) + +Update the constraints aggregating total emissions in each time period +with contributions from transmission emissions. +""" +function update_total_emissions(m, 𝒯, β„³, 𝒫, modeltype::EnergyModel) + ℳᡉᡐ = filter(m -> has_emissions(m), β„³) + 𝒫ᡉᡐ = EMB.res_sub(𝒫, EMB.ResourceEmit) + + # Modify existing constraints on total emissions by adding contribution from + # transmission emissions. Note the coefficient is set to -1 since the total constraint + # has the variables on the RHS. + for tm ∈ ℳᡉᡐ, p ∈ 𝒫ᡉᡐ, t ∈ 𝒯 + JuMP.set_normalized_coefficient(m[:con_em_tot][t, p], m[:emissions_trans][tm, t, p], -1.0) + end +end + + """ create_transmission_mode(m, tm::TransmissionMode, 𝒯, modeltype::EnergyModel) @@ -299,6 +343,9 @@ function create_transmission_mode(m, tm::TransmissionMode, 𝒯, modeltype::Ener # Call of the function for limiting the capacity to the maximum installed capacity constraints_capacity(m, tm, 𝒯, modeltype) + # Call of the functions for transmission emissions + constraints_emission(m, tm, 𝒯, modeltype) + # Call of the functions for both fixed and variable OPEX constraints introduction constraints_opex_fixed(m, tm, 𝒯ᴡⁿᡛ, modeltype) constraints_opex_var(m, tm, 𝒯ᴡⁿᡛ, modeltype) diff --git a/src/structures/mode.jl b/src/structures/mode.jl index 66bc627..d57d696 100644 --- a/src/structures/mode.jl +++ b/src/structures/mode.jl @@ -2,6 +2,7 @@ abstract type TransmissionMode end Base.show(io::IO, t::TransmissionMode) = print(io, "$(t.id)") + """ A reference dynamic `TransmissionMode`. Generic representation of dynamic transmission modes, using for example truck, ship or railway transport. @@ -279,6 +280,36 @@ Returns the directions of transmission mode `tm`. """ directions(tm::TransmissionMode) = tm.directions +""" + has_emissions(tm::TransmissionMode) + +Returns whether there are emissions associated with transmission mode `tm`. +Default behaviour is no emissions. +""" +has_emissions(tm::TransmissionMode) = false + +""" + emit_resources(m::TransmissionMode) + +Returns the types of emissions associated with transmission mode `tm`. +""" +emit_resources(tm::TransmissionMode) = EMB.ResourceEmit[] + +""" + emission(tm::TransmissionMode, p::EMB.ResourceEmit) + +Returns the emission of transmission mode `tm` of a specific resource `p` as `TimeProfile` +""" +emission(tm::TransmissionMode, p::EMB.ResourceEmit) = 0 + +""" + emission(tm::TransmissionMode, p::EMB.ResourceEmit, t) + +Returns the emission of transmission mode `tm` of a specific resource `p` at time period `t` +per unit transmitted. +""" +emission(tm::TransmissionMode, p::EMB.ResourceEmit, t) = 0 + """ consumption_rate(tm::PipeMode)