Allow product disposal at collection centers

feature/collection-disposal
Alinson S. Xavier 4 years ago
parent ee58af73f0
commit a03b9169fd

@ -4,73 +4,132 @@
}, },
"products": { "products": {
"P1": { "P1": {
"transportation cost ($/km/tonne)": [0.015, 0.015], "transportation cost ($/km/tonne)": [
"transportation energy (J/km/tonne)": [0.12, 0.11], 0.015,
0.015
],
"transportation energy (J/km/tonne)": [
0.12,
0.11
],
"transportation emissions (tonne/km/tonne)": { "transportation emissions (tonne/km/tonne)": {
"CO2": [0.052, 0.050], "CO2": [
"CH4": [0.003, 0.002] 0.052,
0.050
],
"CH4": [
0.003,
0.002
]
}, },
"initial amounts": { "initial amounts": {
"C1": { "C1": {
"latitude (deg)": 7.0, "latitude (deg)": 7.0,
"longitude (deg)": 7.0, "longitude (deg)": 7.0,
"amount (tonne)": [934.56, 934.56] "amount (tonne)": [
934.56,
934.56
]
}, },
"C2": { "C2": {
"latitude (deg)": 7.0, "latitude (deg)": 7.0,
"longitude (deg)": 19.0, "longitude (deg)": 19.0,
"amount (tonne)": [198.95, 198.95] "amount (tonne)": [
198.95,
198.95
]
}, },
"C3": { "C3": {
"latitude (deg)": 84.0, "latitude (deg)": 84.0,
"longitude (deg)": 76.0, "longitude (deg)": 76.0,
"amount (tonne)": [212.97, 212.97] "amount (tonne)": [
212.97,
212.97
]
}, },
"C4": { "C4": {
"latitude (deg)": 21.0, "latitude (deg)": 21.0,
"longitude (deg)": 16.0, "longitude (deg)": 16.0,
"amount (tonne)": [352.19, 352.19] "amount (tonne)": [
352.19,
352.19
]
}, },
"C5": { "C5": {
"latitude (deg)": 32.0, "latitude (deg)": 32.0,
"longitude (deg)": 92.0, "longitude (deg)": 92.0,
"amount (tonne)": [510.33, 510.33] "amount (tonne)": [
510.33,
510.33
]
}, },
"C6": { "C6": {
"latitude (deg)": 14.0, "latitude (deg)": 14.0,
"longitude (deg)": 62.0, "longitude (deg)": 62.0,
"amount (tonne)": [471.66, 471.66] "amount (tonne)": [
471.66,
471.66
]
}, },
"C7": { "C7": {
"latitude (deg)": 30.0, "latitude (deg)": 30.0,
"longitude (deg)": 83.0, "longitude (deg)": 83.0,
"amount (tonne)": [785.21, 785.21] "amount (tonne)": [
785.21,
785.21
]
}, },
"C8": { "C8": {
"latitude (deg)": 35.0, "latitude (deg)": 35.0,
"longitude (deg)": 40.0, "longitude (deg)": 40.0,
"amount (tonne)": [706.17, 706.17] "amount (tonne)": [
706.17,
706.17
]
}, },
"C9": { "C9": {
"latitude (deg)": 74.0, "latitude (deg)": 74.0,
"longitude (deg)": 52.0, "longitude (deg)": 52.0,
"amount (tonne)": [30.08, 30.08] "amount (tonne)": [
30.08,
30.08
]
}, },
"C10": { "C10": {
"latitude (deg)": 22.0, "latitude (deg)": 22.0,
"longitude (deg)": 54.0, "longitude (deg)": 54.0,
"amount (tonne)": [536.52, 536.52] "amount (tonne)": [
536.52,
536.52
]
} }
} },
"disposal limit (tonne)": [
1.0,
1.0
],
"disposal cost ($/tonne)": [
-1000,
-1000
]
}, },
"P2": { "P2": {
"transportation cost ($/km/tonne)": [0.02, 0.02] "transportation cost ($/km/tonne)": [
0.02,
0.02
]
}, },
"P3": { "P3": {
"transportation cost ($/km/tonne)": [0.0125, 0.0125] "transportation cost ($/km/tonne)": [
0.0125,
0.0125
]
}, },
"P4": { "P4": {
"transportation cost ($/km/tonne)": [0.0175, 0.0175] "transportation cost ($/km/tonne)": [
0.0175,
0.0175
]
} }
}, },
"plants": { "plants": {
@ -80,10 +139,19 @@
"P2": 0.2, "P2": 0.2,
"P3": 0.5 "P3": 0.5
}, },
"energy (GJ/tonne)": [0.12, 0.11], "energy (GJ/tonne)": [
0.12,
0.11
],
"emissions (tonne/tonne)": { "emissions (tonne/tonne)": {
"CO2": [0.052, 0.050], "CO2": [
"CH4": [0.003, 0.002] 0.052,
0.050
],
"CH4": [
0.003,
0.002
]
}, },
"locations": { "locations": {
"L1": { "L1": {
@ -91,24 +159,54 @@
"longitude (deg)": 0.0, "longitude (deg)": 0.0,
"disposal": { "disposal": {
"P2": { "P2": {
"cost ($/tonne)": [-10.0, -10.0], "cost ($/tonne)": [
"limit (tonne)": [1.0, 1.0] -10.0,
-10.0
],
"limit (tonne)": [
1.0,
1.0
]
}, },
"P3": { "P3": {
"cost ($/tonne)": [-10.0, -10.0], "cost ($/tonne)": [
"limit (tonne)": [1.0, 1.0] -10.0,
-10.0
],
"limit (tonne)": [
1.0,
1.0
]
} }
}, },
"capacities (tonne)": { "capacities (tonne)": {
"250.0": { "250.0": {
"opening cost ($)": [500.0, 500.0], "opening cost ($)": [
"fixed operating cost ($)": [30.0, 30.0], 500.0,
"variable operating cost ($/tonne)": [30.0, 30.0] 500.0
],
"fixed operating cost ($)": [
30.0,
30.0
],
"variable operating cost ($/tonne)": [
30.0,
30.0
]
}, },
"1000.0": { "1000.0": {
"opening cost ($)": [1250.0, 1250.0], "opening cost ($)": [
"fixed operating cost ($)": [30.0, 30.0], 1250.0,
"variable operating cost ($/tonne)": [30.0, 30.0] 1250.0
],
"fixed operating cost ($)": [
30.0,
30.0
],
"variable operating cost ($/tonne)": [
30.0,
30.0
]
} }
} }
}, },
@ -117,14 +215,32 @@
"longitude (deg)": 0.5, "longitude (deg)": 0.5,
"capacities (tonne)": { "capacities (tonne)": {
"0.0": { "0.0": {
"opening cost ($)": [1000, 1000], "opening cost ($)": [
"fixed operating cost ($)": [50.0, 50.0], 1000,
"variable operating cost ($/tonne)": [50.0, 50.0] 1000
],
"fixed operating cost ($)": [
50.0,
50.0
],
"variable operating cost ($/tonne)": [
50.0,
50.0
]
}, },
"10000.0": { "10000.0": {
"opening cost ($)": [10000, 10000], "opening cost ($)": [
"fixed operating cost ($)": [50.0, 50.0], 10000,
"variable operating cost ($/tonne)": [50.0, 50.0] 10000
],
"fixed operating cost ($)": [
50.0,
50.0
],
"variable operating cost ($/tonne)": [
50.0,
50.0
]
} }
} }
} }
@ -142,14 +258,26 @@
"longitude (deg)": 65.0, "longitude (deg)": 65.0,
"disposal": { "disposal": {
"P3": { "P3": {
"cost ($/tonne)": [100.0, 100.0] "cost ($/tonne)": [
100.0,
100.0
]
} }
}, },
"capacities (tonne)": { "capacities (tonne)": {
"1000.0": { "1000.0": {
"opening cost ($)": [3000, 3000], "opening cost ($)": [
"fixed operating cost ($)": [50.0, 50.0], 3000,
"variable operating cost ($/tonne)": [50.0, 50.0] 3000
],
"fixed operating cost ($)": [
50.0,
50.0
],
"variable operating cost ($/tonne)": [
50.0,
50.0
]
} }
} }
}, },
@ -158,9 +286,18 @@
"longitude (deg)": 0.20, "longitude (deg)": 0.20,
"capacities (tonne)": { "capacities (tonne)": {
"10000": { "10000": {
"opening cost ($)": [3000, 3000], "opening cost ($)": [
"fixed operating cost ($)": [50.0, 50.0], 3000,
"variable operating cost ($/tonne)": [50.0, 50.0] 3000
],
"fixed operating cost ($)": [
50.0,
50.0
],
"variable operating cost ($/tonne)": [
50.0,
50.0
]
} }
} }
} }
@ -174,9 +311,18 @@
"longitude (deg)": 100.0, "longitude (deg)": 100.0,
"capacities (tonne)": { "capacities (tonne)": {
"15000": { "15000": {
"opening cost ($)": [0.0, 0.0], "opening cost ($)": [
"fixed operating cost ($)": [0.0, 0.0], 0.0,
"variable operating cost ($/tonne)": [-15.0, -15.0] 0.0
],
"fixed operating cost ($)": [
0.0,
0.0
],
"variable operating cost ($/tonne)": [
-15.0,
-15.0
]
} }
} }
} }
@ -190,9 +336,18 @@
"longitude (deg)": 50.0, "longitude (deg)": 50.0,
"capacities (tonne)": { "capacities (tonne)": {
"10000": { "10000": {
"opening cost ($)": [0.0, 0.0], "opening cost ($)": [
"fixed operating cost ($)": [0.0, 0.0], 0.0,
"variable operating cost ($/tonne)": [-15.0, -15.0] 0.0
],
"fixed operating cost ($)": [
0.0,
0.0
],
"variable operating cost ($/tonne)": [
-15.0,
-15.0
]
} }
} }
} }

@ -36,6 +36,8 @@ The **products** section describes all products and subproducts in the simulatio
|`transportation energy (J/km/tonne)` | The energy required to transport this product. Must be a time series. Optional. |`transportation energy (J/km/tonne)` | The energy required to transport this product. Must be a time series. Optional.
|`transportation emissions (tonne/km/tonne)` | A dictionary mapping the name of each greenhouse gas, produced to transport one tonne of this product along one kilometer, to the amount of gas produced (in tonnes). Must be a time series. Optional. |`transportation emissions (tonne/km/tonne)` | A dictionary mapping the name of each greenhouse gas, produced to transport one tonne of this product along one kilometer, to the amount of gas produced (in tonnes). Must be a time series. Optional.
|`initial amounts` | A dictionary mapping the name of each location to its description (see below). If this product is not initially available, this key may be omitted. Must be a time series. |`initial amounts` | A dictionary mapping the name of each location to its description (see below). If this product is not initially available, this key may be omitted. Must be a time series.
| `disposal limit (tonne)` | Total amount of product that can be disposed of across all collection centers. If omitted, all product must be processed. This parameter has no effect on product disposal at plants.
| `disposal cost ($/tonne)` | Cost of disposing one tonne of this product at a collection center. If omitted, defaults to zero. This parameter has no effect on product disposal costs at plants.
Each product may have some amount available at the beginning of each time period. In this case, the key `initial amounts` maps to a dictionary with the following keys: Each product may have some amount available at the beginning of each time period. In this case, the key `initial amounts` maps to a dictionary with the following keys:
@ -73,7 +75,9 @@ Each product may have some amount available at the beginning of each time period
"transportation emissions (tonne/km/tonne)": { "transportation emissions (tonne/km/tonne)": {
"CO2": [0.052, 0.050], "CO2": [0.052, 0.050],
"CH4": [0.003, 0.002] "CH4": [0.003, 0.002]
} },
"disposal cost ($/tonne)": [-10.0, -12.0],
"disposal limit (tonne)": [1.0, 1.0],
}, },
"P2": { "P2": {
"transportation cost ($/km/tonne)": [0.022, 0.020] "transportation cost ($/km/tonne)": [0.022, 0.020]

@ -147,6 +147,7 @@ Report showing primary product amounts, locations and marginal costs. Generated
| `longitude (deg)` | Longitude of the collection center. | `longitude (deg)` | Longitude of the collection center.
| `year` | What year this row corresponds to. This reports includes one row for each year. | `year` | What year this row corresponds to. This reports includes one row for each year.
| `amount (tonne)` | Amount of product available at this collection center. | `amount (tonne)` | Amount of product available at this collection center.
| `amount disposed (tonne)` | Amount of product disposed of at this collection center.
| `marginal cost ($/tonne)` | Cost to process one additional tonne of this product coming from this collection center. | `marginal cost ($/tonne)` | Cost to process one additional tonne of this product coming from this collection center.

@ -18,6 +18,7 @@ function build_graph(instance::Instance)::Graph
collection_shipping_nodes = ShippingNode[] collection_shipping_nodes = ShippingNode[]
name_to_process_node_map = Dict{Tuple{AbstractString,AbstractString},ProcessNode}() name_to_process_node_map = Dict{Tuple{AbstractString,AbstractString},ProcessNode}()
collection_center_to_node = Dict()
process_nodes_by_input_product = process_nodes_by_input_product =
Dict(product => ProcessNode[] for product in instance.products) Dict(product => ProcessNode[] for product in instance.products)
@ -27,6 +28,7 @@ function build_graph(instance::Instance)::Graph
for center in instance.collection_centers for center in instance.collection_centers
node = ShippingNode(next_index, center, center.product, [], []) node = ShippingNode(next_index, center, center.product, [], [])
next_index += 1 next_index += 1
collection_center_to_node[center] = node
push!(collection_shipping_nodes, node) push!(collection_shipping_nodes, node)
end end
@ -83,6 +85,7 @@ function build_graph(instance::Instance)::Graph
collection_shipping_nodes, collection_shipping_nodes,
arcs, arcs,
name_to_process_node_map, name_to_process_node_map,
collection_center_to_node,
) )
end end

@ -33,6 +33,7 @@ mutable struct Graph
collection_shipping_nodes::Vector{ShippingNode} collection_shipping_nodes::Vector{ShippingNode}
arcs::Vector{Arc} arcs::Vector{Arc}
name_to_process_node_map::Dict{Tuple{AbstractString,AbstractString},ProcessNode} name_to_process_node_map::Dict{Tuple{AbstractString,AbstractString},ProcessNode}
collection_center_to_node::Dict{CollectionCenter,ShippingNode}
end end
function Base.show(io::IO, instance::Graph) function Base.show(io::IO, instance::Graph)

@ -37,6 +37,8 @@ function parse(json)::Instance
cost = product_dict["transportation cost (\$/km/tonne)"] cost = product_dict["transportation cost (\$/km/tonne)"]
energy = zeros(T) energy = zeros(T)
emissions = Dict() emissions = Dict()
disposal_limit = zeros(T)
disposal_cost = zeros(T)
if "transportation energy (J/km/tonne)" in keys(product_dict) if "transportation energy (J/km/tonne)" in keys(product_dict)
energy = product_dict["transportation energy (J/km/tonne)"] energy = product_dict["transportation energy (J/km/tonne)"]
@ -46,7 +48,25 @@ function parse(json)::Instance
emissions = product_dict["transportation emissions (tonne/km/tonne)"] emissions = product_dict["transportation emissions (tonne/km/tonne)"]
end end
product = Product(product_name, cost, energy, emissions) if "disposal limit (tonne)" in keys(product_dict)
disposal_limit = product_dict["disposal limit (tonne)"]
end
if "disposal cost (\$/tonne)" in keys(product_dict)
disposal_cost = product_dict["disposal cost (\$/tonne)"]
end
prod_centers = []
product = Product(
product_name,
cost,
energy,
emissions,
disposal_limit,
disposal_cost,
prod_centers,
)
push!(products, product) push!(products, product)
prod_name_to_product[product_name] = product prod_name_to_product[product_name] = product
@ -66,6 +86,7 @@ function parse(json)::Instance
product, product,
center_dict["amount (tonne)"], center_dict["amount (tonne)"],
) )
push!(prod_centers, center)
push!(collection_centers, center) push!(collection_centers, center)
end end
end end

@ -13,6 +13,9 @@ mutable struct Product
transportation_cost::Vector{Float64} transportation_cost::Vector{Float64}
transportation_energy::Vector{Float64} transportation_energy::Vector{Float64}
transportation_emissions::Dict{String,Vector{Float64}} transportation_emissions::Dict{String,Vector{Float64}}
disposal_limit::Vector{Float64}
disposal_cost::Vector{Float64}
collection_centers::Vector
end end
mutable struct CollectionCenter mutable struct CollectionCenter

@ -20,13 +20,17 @@ function create_vars!(model::JuMP.Model)
graph, T = model[:graph], model[:instance].time graph, T = model[:graph], model[:instance].time
model[:flow] = model[:flow] =
Dict((a, t) => @variable(model, lower_bound = 0) for a in graph.arcs, t = 1:T) Dict((a, t) => @variable(model, lower_bound = 0) for a in graph.arcs, t = 1:T)
model[:dispose] = Dict( model[:plant_dispose] = Dict(
(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(
(n, t) => @variable(model, lower_bound = 0,) for
n in values(graph.collection_shipping_nodes), t = 1:T
)
model[:store] = Dict( model[:store] = Dict(
(n, t) => (n, t) =>
@variable(model, lower_bound = 0, upper_bound = n.location.storage_limit) @variable(model, lower_bound = 0, upper_bound = n.location.storage_limit)
@ -131,14 +135,25 @@ function create_objective_function!(model::JuMP.Model)
end end
end end
# 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,
n.location.disposal_cost[n.product][t], n.location.disposal_cost[n.product][t],
model[:dispose][n, t], model[:plant_dispose][n, t],
)
end
# Collection shipping node costs
for n in values(graph.collection_shipping_nodes), t = 1:T
# Disposal costs
add_to_expression!(
obj,
n.location.product.disposal_cost[t],
model[:collection_dispose][n, t],
) )
end end
@ -154,16 +169,29 @@ function create_shipping_node_constraints!(model::JuMP.Model)
for n in graph.collection_shipping_nodes for n in graph.collection_shipping_nodes
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) == n.location.amount[t] sum(model[:flow][a, t] for a in n.outgoing_arcs) ==
n.location.amount[t] + model[:collection_dispose][n, t]
) )
end end
for prod in model[:instance].products
if isempty(prod.collection_centers)
continue
end
expr = AffExpr()
for center in prod.collection_centers
n = graph.collection_center_to_node[center]
add_to_expression!(expr, model[:collection_dispose][n, t])
end
@constraint(model, expr <= prod.disposal_limit[t])
end
# Plants # Plants
for n in graph.plant_shipping_nodes for n in graph.plant_shipping_nodes
@constraint( @constraint(
model, model,
sum(model[:flow][a, t] for a in n.incoming_arcs) == sum(model[:flow][a, t] for a in n.incoming_arcs) ==
sum(model[:flow][a, t] for a in n.outgoing_arcs) + model[:dispose][n, t] sum(model[:flow][a, t] for a in n.outgoing_arcs) +
model[:plant_dispose][n, t]
) )
end end
end end

@ -39,21 +39,24 @@ function get_solution(model::JuMP.Model; marginal_costs = true)
end end
# Products # Products
if marginal_costs for n in graph.collection_shipping_nodes
for n in graph.collection_shipping_nodes location_dict = OrderedDict{Any,Any}(
location_dict = OrderedDict{Any,Any}( "Latitude (deg)" => n.location.latitude,
"Marginal cost (\$/tonne)" => [ "Longitude (deg)" => n.location.longitude,
round(abs(JuMP.shadow_price(model[:eq_balance][n, t])), digits = 2) for t = 1:T "Amount (tonne)" => n.location.amount,
], "Dispose (tonne)" =>
"Latitude (deg)" => n.location.latitude, [JuMP.value(model[:collection_dispose][n, t]) for t = 1:T],
"Longitude (deg)" => n.location.longitude, )
"Amount (tonne)" => n.location.amount, if marginal_costs
) location_dict["Marginal cost (\$/tonne)"] = [
if n.product.name keys(output["Products"]) round(abs(JuMP.shadow_price(model[:eq_balance][n, t])), digits = 2) for
output["Products"][n.product.name] = OrderedDict() t = 1:T
end ]
output["Products"][n.product.name][n.location.name] = location_dict end
if n.product.name keys(output["Products"])
output["Products"][n.product.name] = OrderedDict()
end end
output["Products"][n.product.name][n.location.name] = location_dict
end end
# Plants # Plants
@ -178,13 +181,14 @@ function get_solution(model::JuMP.Model; marginal_costs = true)
plant_dict["Total output"][product_name] = zeros(T) plant_dict["Total output"][product_name] = zeros(T)
plant_dict["Output"]["Send"][product_name] = product_dict = OrderedDict() plant_dict["Output"]["Send"][product_name] = product_dict = OrderedDict()
disposal_amount = [JuMP.value(model[:dispose][shipping_node, t]) for t = 1:T] disposal_amount =
[JuMP.value(model[:plant_dispose][shipping_node, t]) for t = 1:T]
if sum(disposal_amount) > 1e-5 if sum(disposal_amount) > 1e-5
skip_plant = false skip_plant = false
plant_dict["Output"]["Dispose"][product_name] = plant_dict["Output"]["Dispose"][product_name] =
disposal_dict = OrderedDict() disposal_dict = OrderedDict()
disposal_dict["Amount (tonne)"] = disposal_dict["Amount (tonne)"] =
[JuMP.value(model[:dispose][shipping_node, t]) for t = 1:T] [JuMP.value(model[:plant_dispose][shipping_node, t]) for t = 1:T]
disposal_dict["Cost (\$)"] = [ disposal_dict["Cost (\$)"] = [
disposal_dict["Amount (tonne)"][t] * disposal_dict["Amount (tonne)"][t] *
plant.disposal_cost[shipping_node.product][t] for t = 1:T plant.disposal_cost[shipping_node.product][t] for t = 1:T

@ -13,6 +13,7 @@ function products_report(solution; marginal_costs = true)::DataFrame
df."longitude (deg)" = Float64[] df."longitude (deg)" = Float64[]
df."year" = Int[] df."year" = Int[]
df."amount (tonne)" = Float64[] df."amount (tonne)" = Float64[]
df."amount disposed (tonne)" = Float64[]
df."marginal cost (\$/tonne)" = Float64[] df."marginal cost (\$/tonne)" = Float64[]
T = length(solution["Energy"]["Plants (GJ)"]) T = length(solution["Energy"]["Plants (GJ)"])
for (prod_name, prod_dict) in solution["Products"] for (prod_name, prod_dict) in solution["Products"]
@ -22,6 +23,7 @@ function products_report(solution; marginal_costs = true)::DataFrame
latitude = round(location_dict["Latitude (deg)"], digits = 6) latitude = round(location_dict["Latitude (deg)"], digits = 6)
longitude = round(location_dict["Longitude (deg)"], digits = 6) longitude = round(location_dict["Longitude (deg)"], digits = 6)
amount = location_dict["Amount (tonne)"][year] amount = location_dict["Amount (tonne)"][year]
amount_disposed = location_dict["Dispose (tonne)"][year]
push!( push!(
df, df,
[ [
@ -32,6 +34,7 @@ function products_report(solution; marginal_costs = true)::DataFrame
year, year,
amount, amount,
marginal_cost, marginal_cost,
amount_disposed,
], ],
) )
end end

@ -169,6 +169,12 @@
}, },
"initial amounts": { "initial amounts": {
"$ref": "#/definitions/InitialAmount" "$ref": "#/definitions/InitialAmount"
},
"disposal limit (tonne)": {
"$ref": "#/definitions/TimeSeries"
},
"disposal cost ($/tonne)": {
"$ref": "#/definitions/TimeSeries"
} }
}, },
"required": [ "required": [

@ -6,23 +6,23 @@ Logging.disable_logging(Logging.Info)
mkpath("build") mkpath("build")
printstyled("Generating precompilation statements...\n", color=:light_green) printstyled("Generating precompilation statements...\n", color = :light_green)
run(`julia --project=. --trace-compile=build/precompile.jl $ARGS`) run(`julia --project=. --trace-compile=build/precompile.jl $ARGS`)
printstyled("Finding dependencies...\n", color=:light_green) printstyled("Finding dependencies...\n", color = :light_green)
project = TOML.parsefile("Project.toml") project = TOML.parsefile("Project.toml")
manifest = TOML.parsefile("Manifest.toml") manifest = TOML.parsefile("Manifest.toml")
deps = Symbol[] deps = Symbol[]
for dep in keys(project["deps"]) for dep in keys(project["deps"])
if "path" in keys(manifest[dep][1]) if "path" in keys(manifest[dep][1])
printstyled(" skip $(dep)\n", color=:light_black) printstyled(" skip $(dep)\n", color = :light_black)
else else
println(" add $(dep)") println(" add $(dep)")
push!(deps, Symbol(dep)) push!(deps, Symbol(dep))
end end
end end
printstyled("Building system image...\n", color=:light_green) printstyled("Building system image...\n", color = :light_green)
create_sysimage( create_sysimage(
deps, deps,
precompile_statements_file = "build/precompile.jl", precompile_statements_file = "build/precompile.jl",

@ -40,7 +40,14 @@ using RELOG
@test plant.sizes[2].fixed_operating_cost == [30, 30] @test plant.sizes[2].fixed_operating_cost == [30, 30]
@test plant.sizes[2].variable_operating_cost == [30, 30] @test plant.sizes[2].variable_operating_cost == [30, 30]
p1 = product_name_to_product["P1"]
@test p1.disposal_limit == [1.0, 1.0]
@test p1.disposal_cost == [-1000.0, -1000.0]
p2 = product_name_to_product["P2"] p2 = product_name_to_product["P2"]
@test p2.disposal_limit == [0.0, 0.0]
@test p2.disposal_cost == [0.0, 0.0]
p3 = product_name_to_product["P3"] p3 = product_name_to_product["P3"]
@test length(plant.output) == 2 @test length(plant.output) == 2
@test plant.output[p2] == 0.2 @test plant.output[p2] == 0.2

@ -18,7 +18,7 @@ using RELOG, Cbc, JuMP, Printf, JSON, MathOptInterface.FileFormats
) )
@test length(model[:flow]) == 76 @test length(model[:flow]) == 76
@test length(model[:dispose]) == 16 @test length(model[:plant_dispose]) == 16
@test length(model[:open_plant]) == 12 @test length(model[:open_plant]) == 12
@test length(model[:capacity]) == 12 @test length(model[:capacity]) == 12
@test length(model[:expansion]) == 12 @test length(model[:expansion]) == 12
@ -32,7 +32,7 @@ using RELOG, Cbc, JuMP, Printf, JSON, MathOptInterface.FileFormats
@test lower_bound(v) == 0.0 @test lower_bound(v) == 0.0
@test upper_bound(v) == 750.0 @test upper_bound(v) == 750.0
v = model[:dispose][shipping_node_by_loc_and_prod_names["L1", "P2"], 1] v = model[:plant_dispose][shipping_node_by_loc_and_prod_names["L1", "P2"], 1]
@test lower_bound(v) == 0.0 @test lower_bound(v) == 0.0
@test upper_bound(v) == 1.0 @test upper_bound(v) == 1.0
end end

@ -26,6 +26,15 @@ basedir = dirname(@__FILE__)
@test "F2" in keys(solution["Plants"]) @test "F2" in keys(solution["Plants"])
@test "F3" in keys(solution["Plants"]) @test "F3" in keys(solution["Plants"])
@test "F4" in keys(solution["Plants"]) @test "F4" in keys(solution["Plants"])
@test "Products" in keys(solution)
@test "P1" in keys(solution["Products"])
@test "C1" in keys(solution["Products"]["P1"])
@test "Dispose (tonne)" in keys(solution["Products"]["P1"]["C1"])
total_disposal =
sum([loc["Dispose (tonne)"] for loc in values(solution["Products"]["P1"])])
@test total_disposal == [1.0, 1.0]
end end
@testset "solve (heuristic)" begin @testset "solve (heuristic)" begin

Loading…
Cancel
Save