mirror of
https://github.com/ANL-CEEESA/RELOG.git
synced 2025-12-06 07:48:50 -06:00
Allow disposal at collection centers
This commit is contained in:
@@ -11,6 +11,10 @@ All notable changes to this project will be documented in this file.
|
|||||||
[semver]: https://semver.org/spec/v2.0.0.html
|
[semver]: https://semver.org/spec/v2.0.0.html
|
||||||
[pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0
|
[pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Allow product disposal at collection centers
|
||||||
|
|
||||||
## [0.5.1] -- 2021-07-23
|
## [0.5.1] -- 2021-07-23
|
||||||
## Added
|
## Added
|
||||||
- Allow user to specify locations as unique identifiers, instead of latitude and longitude (e.g. `us-state:IL` or `2018-us-county:17043`)
|
- Allow user to specify locations as unique identifiers, instead of latitude and longitude (e.g. `us-state:IL` or `2018-us-county:17043`)
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
|||||||
JULIA := julia --project=.
|
JULIA := julia --project=.
|
||||||
SRC_FILES := $(wildcard src/*.jl test/*.jl)
|
SRC_FILES := $(wildcard src/*.jl test/*.jl)
|
||||||
VERSION := 0.5
|
VERSION := dev
|
||||||
|
|
||||||
all: docs test
|
all: docs test
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ function _compress(instance::Instance)::Instance
|
|||||||
for (emission_name, emission_value) in p.transportation_emissions
|
for (emission_name, emission_value) in p.transportation_emissions
|
||||||
p.transportation_emissions[emission_name] = [mean(emission_value)]
|
p.transportation_emissions[emission_name] = [mean(emission_value)]
|
||||||
end
|
end
|
||||||
|
p.disposal_limit = [maximum(p.disposal_limit) * T]
|
||||||
|
p.disposal_cost = [mean(p.disposal_cost)]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Compress collection centers
|
# Compress collection centers
|
||||||
@@ -58,3 +60,42 @@ function _compress(instance::Instance)::Instance
|
|||||||
|
|
||||||
return compressed
|
return compressed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _slice(instance::Instance, T::UnitRange)::Instance
|
||||||
|
sliced = deepcopy(instance)
|
||||||
|
sliced.time = length(T)
|
||||||
|
|
||||||
|
for p in sliced.products
|
||||||
|
p.transportation_cost = p.transportation_cost[T]
|
||||||
|
p.transportation_energy = p.transportation_energy[T]
|
||||||
|
for (emission_name, emission_value) in p.transportation_emissions
|
||||||
|
p.transportation_emissions[emission_name] = emission_value[T]
|
||||||
|
end
|
||||||
|
p.disposal_limit = p.disposal_limit[T]
|
||||||
|
p.disposal_cost = p.disposal_cost[T]
|
||||||
|
end
|
||||||
|
|
||||||
|
for c in sliced.collection_centers
|
||||||
|
c.amount = c.amount[T]
|
||||||
|
end
|
||||||
|
|
||||||
|
for plant in sliced.plants
|
||||||
|
plant.energy = plant.energy[T]
|
||||||
|
for (emission_name, emission_value) in plant.emissions
|
||||||
|
plant.emissions[emission_name] = emission_value[T]
|
||||||
|
end
|
||||||
|
for s in plant.sizes
|
||||||
|
s.variable_operating_cost = s.variable_operating_cost[T]
|
||||||
|
s.opening_cost = s.opening_cost[T]
|
||||||
|
s.fixed_operating_cost = s.fixed_operating_cost[T]
|
||||||
|
end
|
||||||
|
for (prod_name, disp_limit) in plant.disposal_limit
|
||||||
|
plant.disposal_limit[prod_name] = disp_limit[T]
|
||||||
|
end
|
||||||
|
for (prod_name, disp_cost) in plant.disposal_cost
|
||||||
|
plant.disposal_cost[prod_name] = disp_cost[T]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return sliced
|
||||||
|
end
|
||||||
@@ -24,11 +24,15 @@ function create_vars!(model::JuMP.Model)
|
|||||||
(n, t) => @variable(
|
(n, t) => @variable(
|
||||||
model,
|
model,
|
||||||
lower_bound = 0,
|
lower_bound = 0,
|
||||||
upper_bound = n.location.disposal_limit[n.product][t]
|
upper_bound = n.location.disposal_limit[n.product][t],
|
||||||
) for n in values(graph.plant_shipping_nodes), t = 1:T
|
) for n in values(graph.plant_shipping_nodes), t = 1:T
|
||||||
)
|
)
|
||||||
model[:collection_dispose] = Dict(
|
model[:collection_dispose] = Dict(
|
||||||
(n, t) => @variable(model, lower_bound = 0,) for
|
(n, t) => @variable(
|
||||||
|
model,
|
||||||
|
lower_bound = 0,
|
||||||
|
upper_bound = n.location.amount[t],
|
||||||
|
) for
|
||||||
n in values(graph.collection_shipping_nodes), t = 1:T
|
n in values(graph.collection_shipping_nodes), t = 1:T
|
||||||
)
|
)
|
||||||
model[:store] = Dict(
|
model[:store] = Dict(
|
||||||
@@ -90,7 +94,7 @@ function create_objective_function!(model::JuMP.Model)
|
|||||||
# Process node costs
|
# Process node costs
|
||||||
for n in values(graph.process_nodes), t = 1:T
|
for n in values(graph.process_nodes), t = 1:T
|
||||||
|
|
||||||
# Transportation and variable operating costs
|
# Transportation costs
|
||||||
for a in n.incoming_arcs
|
for a in n.incoming_arcs
|
||||||
c = n.location.input.transportation_cost[t] * a.values["distance"]
|
c = n.location.input.transportation_cost[t] * a.values["distance"]
|
||||||
add_to_expression!(obj, c, model[:flow][a, t])
|
add_to_expression!(obj, c, model[:flow][a, t])
|
||||||
@@ -137,7 +141,6 @@ function create_objective_function!(model::JuMP.Model)
|
|||||||
|
|
||||||
# Plant shipping node costs
|
# Plant shipping node costs
|
||||||
for n in values(graph.plant_shipping_nodes), t = 1:T
|
for n in values(graph.plant_shipping_nodes), t = 1:T
|
||||||
|
|
||||||
# Disposal costs
|
# Disposal costs
|
||||||
add_to_expression!(
|
add_to_expression!(
|
||||||
obj,
|
obj,
|
||||||
@@ -148,7 +151,6 @@ function create_objective_function!(model::JuMP.Model)
|
|||||||
|
|
||||||
# Collection shipping node costs
|
# Collection shipping node costs
|
||||||
for n in values(graph.collection_shipping_nodes), t = 1:T
|
for n in values(graph.collection_shipping_nodes), t = 1:T
|
||||||
|
|
||||||
# Disposal costs
|
# Disposal costs
|
||||||
add_to_expression!(
|
add_to_expression!(
|
||||||
obj,
|
obj,
|
||||||
@@ -170,7 +172,7 @@ function create_shipping_node_constraints!(model::JuMP.Model)
|
|||||||
model[:eq_balance][n, t] = @constraint(
|
model[:eq_balance][n, t] = @constraint(
|
||||||
model,
|
model,
|
||||||
sum(model[:flow][a, t] for a in n.outgoing_arcs) ==
|
sum(model[:flow][a, t] for a in n.outgoing_arcs) ==
|
||||||
n.location.amount[t] + model[:collection_dispose][n, t]
|
n.location.amount[t] - model[:collection_dispose][n, t],
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
for prod in model[:instance].products
|
for prod in model[:instance].products
|
||||||
|
|||||||
@@ -29,29 +29,32 @@ function solve(
|
|||||||
instance::Instance;
|
instance::Instance;
|
||||||
optimizer = nothing,
|
optimizer = nothing,
|
||||||
output = nothing,
|
output = nothing,
|
||||||
|
graph = nothing,
|
||||||
marginal_costs = true,
|
marginal_costs = true,
|
||||||
return_model = false,
|
return_model = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
milp_optimizer = lp_optimizer = optimizer
|
milp_optimizer = lp_optimizer = optimizer
|
||||||
if optimizer == nothing
|
if optimizer === nothing
|
||||||
milp_optimizer = _get_default_milp_optimizer()
|
milp_optimizer = _get_default_milp_optimizer()
|
||||||
lp_optimizer = _get_default_lp_optimizer()
|
lp_optimizer = _get_default_lp_optimizer()
|
||||||
end
|
end
|
||||||
|
|
||||||
@info "Building graph..."
|
if graph === nothing
|
||||||
graph = RELOG.build_graph(instance)
|
@info "Building graph..."
|
||||||
_print_graph_stats(instance, graph)
|
graph = RELOG.build_graph(instance)
|
||||||
|
_print_graph_stats(instance, graph)
|
||||||
|
end
|
||||||
|
|
||||||
@info "Building optimization model..."
|
@info "Building optimization model..."
|
||||||
model = RELOG.build_model(instance, graph, milp_optimizer)
|
model = RELOG.build_model(instance, graph, milp_optimizer)
|
||||||
|
|
||||||
@info "Optimizing MILP..."
|
@info "Optimizing MILP..."
|
||||||
JuMP.optimize!(model)
|
JuMP.optimize!(model)
|
||||||
|
|
||||||
if !has_values(model)
|
if !has_values(model)
|
||||||
error("No solution available")
|
error("No solution available")
|
||||||
end
|
end
|
||||||
|
solution = get_solution(model, marginal_costs = false)
|
||||||
|
|
||||||
if marginal_costs
|
if marginal_costs
|
||||||
@info "Re-optimizing with integer variables fixed..."
|
@info "Re-optimizing with integer variables fixed..."
|
||||||
@@ -65,12 +68,15 @@ function solve(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
JuMP.optimize!(model)
|
JuMP.optimize!(model)
|
||||||
|
if has_values(model)
|
||||||
|
@info "Extracting solution..."
|
||||||
|
solution = get_solution(model, marginal_costs = true)
|
||||||
|
else
|
||||||
|
@warn "Error computing marginal costs. Ignoring."
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@info "Extracting solution..."
|
if output !== nothing
|
||||||
solution = get_solution(model, marginal_costs = marginal_costs)
|
|
||||||
|
|
||||||
if output != nothing
|
|
||||||
write(solution, output)
|
write(solution, output)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -87,7 +93,7 @@ function solve(filename::AbstractString; heuristic = false, kwargs...)
|
|||||||
if heuristic && instance.time > 1
|
if heuristic && instance.time > 1
|
||||||
@info "Solving single-period version..."
|
@info "Solving single-period version..."
|
||||||
compressed = _compress(instance)
|
compressed = _compress(instance)
|
||||||
csol = solve(compressed; output = nothing, marginal_costs = false, kwargs...)
|
csol, model = solve(compressed; output = nothing, marginal_costs = false, return_model = true, kwargs...)
|
||||||
@info "Filtering candidate locations..."
|
@info "Filtering candidate locations..."
|
||||||
selected_pairs = []
|
selected_pairs = []
|
||||||
for (plant_name, plant_dict) in csol["Plants"]
|
for (plant_name, plant_dict) in csol["Plants"]
|
||||||
|
|||||||
Reference in New Issue
Block a user