Add emission limits and penalties

This commit is contained in:
2025-09-17 15:03:51 -05:00
parent 003922ac70
commit f35c84abe9
8 changed files with 183 additions and 38 deletions

View File

@@ -128,6 +128,19 @@ function parse(json)::Instance
plants_by_name[name] = plant
end
# Read emissions
emissions = Emissions[]
emissions_by_name = OrderedDict{String,Emissions}()
if haskey(json, "emissions")
for (name, edict) in json["emissions"]
limit = timeseries(edict["limit (tonne)"], null_val = Inf)
penalty = timeseries(edict["penalty (\$/tonne)"])
emission = Emissions(; name, limit, penalty)
push!(emissions, emission)
emissions_by_name[name] = emission
end
end
return Instance(;
time_horizon,
building_period,
@@ -138,5 +151,7 @@ function parse(json)::Instance
centers_by_name,
plants,
plants_by_name,
emissions,
emissions_by_name,
)
end

View File

@@ -54,6 +54,12 @@ Base.@kwdef struct Plant
initial_capacity::Float64
end
Base.@kwdef struct Emissions
name::String
limit::Vector{Float64}
penalty::Vector{Float64}
end
Base.@kwdef struct Instance
building_period::Vector{Int}
centers_by_name::OrderedDict{String,Center}
@@ -64,4 +70,6 @@ Base.@kwdef struct Instance
time_horizon::Int
plants::Vector{Plant}
plants_by_name::OrderedDict{String,Plant}
emissions_by_name::OrderedDict{String,Emissions}
emissions::Vector{Emissions}
end

View File

@@ -119,15 +119,15 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
end
# Transportation emissions by greenhouse gas
z_tr_em = _init(model, :z_tr_em)
z_em_tr = _init(model, :z_em_tr)
for (p1, p2, m) in E, t in T, g in keys(m.tr_emissions)
z_tr_em[g, p1.name, p2.name, m.name, t] = @variable(model, lower_bound = 0)
z_em_tr[g, p1.name, p2.name, m.name, t] = @variable(model, lower_bound = 0)
end
# Plant emissions by greenhouse gas
z_plant_em = _init(model, :z_plant_em)
z_em_plant = _init(model, :z_em_plant)
for p in plants, t in T, g in keys(p.emissions)
z_plant_em[g, p.name, t] = @variable(model, lower_bound = 0)
z_em_plant[g, p.name, t] = @variable(model, lower_bound = 0)
end
@@ -192,6 +192,30 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
)
end
# Emissions penalty cost
for emission in instance.emissions, t in T
# Plant emissions penalty
for p in plants
if emission.name in keys(p.emissions)
add_to_expression!(
obj,
emission.penalty[t],
z_em_plant[emission.name, p.name, t],
)
end
end
# Transportation emissions penalty
for (p1, p2, m) in E
if emission.name in keys(m.tr_emissions)
add_to_expression!(
obj,
emission.penalty[t],
z_em_tr[emission.name, p1.name, p2.name, m.name, t],
)
end
end
end
@objective(model, Min, obj)
# Constraints
@@ -323,25 +347,41 @@ function build_model(instance::Instance; optimizer, variable_names::Bool = false
end
# Transportation emissions
eq_tr_em = _init(model, :eq_tr_em)
eq_emission_tr = _init(model, :eq_emission_tr)
for (p1, p2, m) in E, t in T, g in keys(m.tr_emissions)
eq_tr_em[g, p1.name, p2.name, m.name, t] = @constraint(
eq_emission_tr[g, p1.name, p2.name, m.name, t] = @constraint(
model,
z_tr_em[g, p1.name, p2.name, m.name, t] ==
z_em_tr[g, p1.name, p2.name, m.name, t] ==
distances[p1, p2, m] * m.tr_emissions[g][t] * y[p1.name, p2.name, m.name, t]
)
end
# Plant emissions
eq_plant_em = _init(model, :eq_plant_em)
eq_emission_plant = _init(model, :eq_emission_plant)
for p in plants, t in T, g in keys(p.emissions)
eq_plant_em[g, p.name, t] = @constraint(
eq_emission_plant[g, p.name, t] = @constraint(
model,
z_plant_em[g, p.name, t] ==
z_em_plant[g, p.name, t] ==
p.emissions[g][t] * sum(y[src.name, p.name, m.name, t] for (src, m) in E_in[p])
)
end
# Global emissions limit
eq_emission_limit = _init(model, :eq_emission_limit)
for emission in instance.emissions, t in T
isfinite(emission.limit[t]) || continue
eq_emission_limit[emission.name, t] = @constraint(
model,
sum(
z_em_plant[emission.name, p.name, t] for
p in plants if emission.name in keys(p.emissions)
) + sum(
z_em_tr[emission.name, p1.name, p2.name, m.name, t] for
(p1, p2, m) in E if emission.name in keys(m.tr_emissions)
) <= emission.limit[t]
)
end
if variable_names
_set_names!(model)
end