Allow disposal at collection centers

feature/stochastic
Alinson S. Xavier 3 years ago
parent 57b7d09c08
commit e915a57e58

@ -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
[pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0
## [Unreleased]
- Allow product disposal at collection centers
## [0.5.1] -- 2021-07-23
## Added
- Allow user to specify locations as unique identifiers, instead of latitude and longitude (e.g. `us-state:IL` or `2018-us-county:17043`)

@ -1,6 +1,6 @@
JULIA := julia --project=.
SRC_FILES := $(wildcard src/*.jl test/*.jl)
VERSION := 0.5
VERSION := dev
all: docs test

@ -29,6 +29,8 @@ function _compress(instance::Instance)::Instance
for (emission_name, emission_value) in p.transportation_emissions
p.transportation_emissions[emission_name] = [mean(emission_value)]
end
p.disposal_limit = [maximum(p.disposal_limit) * T]
p.disposal_cost = [mean(p.disposal_cost)]
end
# Compress collection centers
@ -58,3 +60,42 @@ function _compress(instance::Instance)::Instance
return compressed
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(
model,
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
)
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
)
model[:store] = Dict(
@ -90,7 +94,7 @@ function create_objective_function!(model::JuMP.Model)
# Process node costs
for n in values(graph.process_nodes), t = 1:T
# Transportation and variable operating costs
# Transportation costs
for a in n.incoming_arcs
c = n.location.input.transportation_cost[t] * a.values["distance"]
add_to_expression!(obj, c, model[:flow][a, t])
@ -137,7 +141,6 @@ function create_objective_function!(model::JuMP.Model)
# Plant shipping node costs
for n in values(graph.plant_shipping_nodes), t = 1:T
# Disposal costs
add_to_expression!(
obj,
@ -148,7 +151,6 @@ function create_objective_function!(model::JuMP.Model)
# Collection shipping node costs
for n in values(graph.collection_shipping_nodes), t = 1:T
# Disposal costs
add_to_expression!(
obj,
@ -170,7 +172,7 @@ function create_shipping_node_constraints!(model::JuMP.Model)
model[:eq_balance][n, t] = @constraint(
model,
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
for prod in model[:instance].products

@ -29,29 +29,32 @@ function solve(
instance::Instance;
optimizer = nothing,
output = nothing,
graph = nothing,
marginal_costs = true,
return_model = false,
)
milp_optimizer = lp_optimizer = optimizer
if optimizer == nothing
if optimizer === nothing
milp_optimizer = _get_default_milp_optimizer()
lp_optimizer = _get_default_lp_optimizer()
end
if graph === nothing
@info "Building graph..."
graph = RELOG.build_graph(instance)
_print_graph_stats(instance, graph)
end
@info "Building optimization model..."
model = RELOG.build_model(instance, graph, milp_optimizer)
@info "Optimizing MILP..."
JuMP.optimize!(model)
if !has_values(model)
error("No solution available")
end
solution = get_solution(model, marginal_costs = false)
if marginal_costs
@info "Re-optimizing with integer variables fixed..."
@ -65,12 +68,15 @@ function solve(
end
end
JuMP.optimize!(model)
end
if has_values(model)
@info "Extracting solution..."
solution = get_solution(model, marginal_costs = marginal_costs)
solution = get_solution(model, marginal_costs = true)
else
@warn "Error computing marginal costs. Ignoring."
end
end
if output != nothing
if output !== nothing
write(solution, output)
end
@ -87,7 +93,7 @@ function solve(filename::AbstractString; heuristic = false, kwargs...)
if heuristic && instance.time > 1
@info "Solving single-period version..."
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..."
selected_pairs = []
for (plant_name, plant_dict) in csol["Plants"]

Loading…
Cancel
Save