diff --git a/instances/s1.json b/instances/s1.json index 32bb671..e88e8c5 100644 --- a/instances/s1.json +++ b/instances/s1.json @@ -1,188 +1,198 @@ { - "Parameters": { - "Time horizon (years)": 2 + "parameters": { + "time horizon (years)": 2 }, - "Products": { + "products": { "P1": { - "Transportation cost ($/km/tonne)": [0.015, 0.015], - "Initial amounts": { + "transportation cost ($/km/tonne)": [0.015, 0.015], + "transportation energy (J/km/tonne)": [0.12, 0.11], + "transportation emissions (tonne/km/tonne)": { + "CO2": [0.052, 0.050], + "CH4": [0.003, 0.002] + }, + "initial amounts": { "C1": { - "Latitude (deg)": 7.0, - "Longitude (deg)": 7.0, - "Amount (tonne)": [934.56, 934.56] + "latitude (deg)": 7.0, + "longitude (deg)": 7.0, + "amount (tonne)": [934.56, 934.56] }, "C2": { - "Latitude (deg)": 7.0, - "Longitude (deg)": 19.0, - "Amount (tonne)": [198.95, 198.95] + "latitude (deg)": 7.0, + "longitude (deg)": 19.0, + "amount (tonne)": [198.95, 198.95] }, "C3": { - "Latitude (deg)": 84.0, - "Longitude (deg)": 76.0, - "Amount (tonne)": [212.97, 212.97] + "latitude (deg)": 84.0, + "longitude (deg)": 76.0, + "amount (tonne)": [212.97, 212.97] }, "C4": { - "Latitude (deg)": 21.0, - "Longitude (deg)": 16.0, - "Amount (tonne)": [352.19, 352.19] + "latitude (deg)": 21.0, + "longitude (deg)": 16.0, + "amount (tonne)": [352.19, 352.19] }, "C5": { - "Latitude (deg)": 32.0, - "Longitude (deg)": 92.0, - "Amount (tonne)": [510.33, 510.33] + "latitude (deg)": 32.0, + "longitude (deg)": 92.0, + "amount (tonne)": [510.33, 510.33] }, "C6": { - "Latitude (deg)": 14.0, - "Longitude (deg)": 62.0, - "Amount (tonne)": [471.66, 471.66] + "latitude (deg)": 14.0, + "longitude (deg)": 62.0, + "amount (tonne)": [471.66, 471.66] }, "C7": { - "Latitude (deg)": 30.0, - "Longitude (deg)": 83.0, - "Amount (tonne)": [785.21, 785.21] + "latitude (deg)": 30.0, + "longitude (deg)": 83.0, + "amount (tonne)": [785.21, 785.21] }, "C8": { - "Latitude (deg)": 35.0, - "Longitude (deg)": 40.0, - "Amount (tonne)": [706.17, 706.17] + "latitude (deg)": 35.0, + "longitude (deg)": 40.0, + "amount (tonne)": [706.17, 706.17] }, "C9": { - "Latitude (deg)": 74.0, - "Longitude (deg)": 52.0, - "Amount (tonne)": [30.08, 30.08] + "latitude (deg)": 74.0, + "longitude (deg)": 52.0, + "amount (tonne)": [30.08, 30.08] }, "C10": { - "Latitude (deg)": 22.0, - "Longitude (deg)": 54.0, - "Amount (tonne)": [536.52, 536.52] + "latitude (deg)": 22.0, + "longitude (deg)": 54.0, + "amount (tonne)": [536.52, 536.52] } } }, "P2": { - "Transportation cost ($/km/tonne)": [0.02, 0.02] + "transportation cost ($/km/tonne)": [0.02, 0.02] }, "P3": { - "Transportation cost ($/km/tonne)": [0.0125, 0.0125] + "transportation cost ($/km/tonne)": [0.0125, 0.0125] }, "P4": { - "Transportation cost ($/km/tonne)": [0.0175, 0.0175] + "transportation cost ($/km/tonne)": [0.0175, 0.0175] } }, - "Plants": { + "plants": { "F1": { - "Input": "P1", - "Outputs (tonne)": { + "input": "P1", + "outputs (tonne/tonne)": { "P2": 0.2, "P3": 0.5 }, - "Locations": { + "energy (GJ/tonne)": [0.12, 0.11], + "emissions (tonne/tonne)": { + "CO2": [0.052, 0.050], + "CH4": [0.003, 0.002] + }, + "locations": { "L1": { - "Latitude (deg)": 0.0, - "Longitude (deg)": 0.0, - "Disposal": { + "latitude (deg)": 0.0, + "longitude (deg)": 0.0, + "disposal": { "P2": { - "Cost ($/tonne)": [-10.0, -10.0], - "Limit (tonne)": [1.0, 1.0] + "cost ($/tonne)": [-10.0, -10.0], + "limit (tonne)": [1.0, 1.0] }, "P3": { - "Cost ($/tonne)": [-10.0, -10.0], - "Limit (tonne)": [1.0, 1.0] + "cost ($/tonne)": [-10.0, -10.0], + "limit (tonne)": [1.0, 1.0] } }, - "Capacities (tonne)": { + "capacities (tonne)": { "250.0": { - "Opening cost ($)": [500.0, 500.0], - "Fixed operating cost ($)": [30.0, 30.0], - "Variable operating cost ($/tonne)": [30.0, 30.0] + "opening cost ($)": [500.0, 500.0], + "fixed operating cost ($)": [30.0, 30.0], + "variable operating cost ($/tonne)": [30.0, 30.0] }, "1000.0": { - "Opening cost ($)": [1250.0, 1250.0], - "Fixed operating cost ($)": [30.0, 30.0], - "Variable operating cost ($/tonne)": [30.0, 30.0] + "opening cost ($)": [1250.0, 1250.0], + "fixed operating cost ($)": [30.0, 30.0], + "variable operating cost ($/tonne)": [30.0, 30.0] } } }, "L2": { - "Latitude (deg)": 0.5, - "Longitude (deg)": 0.5, - "Capacities (tonne)": { + "latitude (deg)": 0.5, + "longitude (deg)": 0.5, + "capacities (tonne)": { "0.0": { - "Opening cost ($)": [1000, 1000], - "Fixed operating cost ($)": [50.0, 50.0], - "Variable operating cost ($/tonne)": [50.0, 50.0] + "opening cost ($)": [1000, 1000], + "fixed operating cost ($)": [50.0, 50.0], + "variable operating cost ($/tonne)": [50.0, 50.0] }, "10000.0": { - "Opening cost ($)": [10000, 10000], - "Fixed operating cost ($)": [50.0, 50.0], - "Variable operating cost ($/tonne)": [50.0, 50.0] + "opening cost ($)": [10000, 10000], + "fixed operating cost ($)": [50.0, 50.0], + "variable operating cost ($/tonne)": [50.0, 50.0] } } } } }, "F2": { - "Input": "P2", - "Outputs (tonne)": { + "input": "P2", + "outputs (tonne/tonne)": { "P3": 0.05, "P4": 0.80 }, - "Locations": { + "locations": { "L3": { - "Latitude (deg)": 25.0, - "Longitude (deg)": 65.0, - "Disposal": { + "latitude (deg)": 25.0, + "longitude (deg)": 65.0, + "disposal": { "P3": { - "Cost ($/tonne)": [100.0, 100.0] + "cost ($/tonne)": [100.0, 100.0] } }, - "Capacities (tonne)": { + "capacities (tonne)": { "1000.0": { - "Opening cost ($)": [3000, 3000], - "Fixed operating cost ($)": [50.0, 50.0], - "Variable operating cost ($/tonne)": [50.0, 50.0] + "opening cost ($)": [3000, 3000], + "fixed operating cost ($)": [50.0, 50.0], + "variable operating cost ($/tonne)": [50.0, 50.0] } } }, "L4": { - "Latitude (deg)": 0.75, - "Longitude (deg)": 0.20, - "Capacities (tonne)": { + "latitude (deg)": 0.75, + "longitude (deg)": 0.20, + "capacities (tonne)": { "10000": { - "Opening cost ($)": [3000, 3000], - "Fixed operating cost ($)": [50.0, 50.0], - "Variable operating cost ($/tonne)": [50.0, 50.0] + "opening cost ($)": [3000, 3000], + "fixed operating cost ($)": [50.0, 50.0], + "variable operating cost ($/tonne)": [50.0, 50.0] } } } } }, "F3": { - "Input": "P4", - "Locations": { + "input": "P4", + "locations": { "L5": { - "Latitude (deg)": 100.0, - "Longitude (deg)": 100.0, - "Capacities (tonne)": { + "latitude (deg)": 100.0, + "longitude (deg)": 100.0, + "capacities (tonne)": { "15000": { - "Opening cost ($)": [0.0, 0.0], - "Fixed operating cost ($)": [0.0, 0.0], - "Variable operating cost ($/tonne)": [-15.0, -15.0] + "opening cost ($)": [0.0, 0.0], + "fixed operating cost ($)": [0.0, 0.0], + "variable operating cost ($/tonne)": [-15.0, -15.0] } } } } }, "F4": { - "Input": "P3", - "Locations": { + "input": "P3", + "locations": { "L6": { - "Latitude (deg)": 50.0, - "Longitude (deg)": 50.0, - "Capacities (tonne)": { + "latitude (deg)": 50.0, + "longitude (deg)": 50.0, + "capacities (tonne)": { "10000": { - "Opening cost ($)": [0.0, 0.0], - "Fixed operating cost ($)": [0.0, 0.0], - "Variable operating cost ($/tonne)": [-15.0, -15.0] + "opening cost ($)": [0.0, 0.0], + "fixed operating cost ($)": [0.0, 0.0], + "variable operating cost ($/tonne)": [-15.0, -15.0] } } } diff --git a/src/instance.jl b/src/instance.jl index 9c87c52..f6e4bf7 100644 --- a/src/instance.jl +++ b/src/instance.jl @@ -70,67 +70,67 @@ function load(path::String)::Instance throw(msg) end - T = json["Parameters"]["Time horizon (years)"] + T = json["parameters"]["time horizon (years)"] plants = Plant[] products = Product[] collection_centers = CollectionCenter[] prod_name_to_product = Dict{String, Product}() # Create products - for (product_name, product_dict) in json["Products"] - product = Product(product_name, product_dict["Transportation cost (\$/km/tonne)"]) + for (product_name, product_dict) in json["products"] + product = Product(product_name, product_dict["transportation cost (\$/km/tonne)"]) push!(products, product) prod_name_to_product[product_name] = product # Create collection centers - if "Initial amounts" in keys(product_dict) - for (center_name, center_dict) in product_dict["Initial amounts"] + if "initial amounts" in keys(product_dict) + for (center_name, center_dict) in product_dict["initial amounts"] center = CollectionCenter(length(collection_centers) + 1, center_name, - center_dict["Latitude (deg)"], - center_dict["Longitude (deg)"], + center_dict["latitude (deg)"], + center_dict["longitude (deg)"], product, - center_dict["Amount (tonne)"]) + center_dict["amount (tonne)"]) push!(collection_centers, center) end end end # Create plants - for (plant_name, plant_dict) in json["Plants"] - input = prod_name_to_product[plant_dict["Input"]] + for (plant_name, plant_dict) in json["plants"] + input = prod_name_to_product[plant_dict["input"]] output = Dict() # Plant outputs - if "Outputs (tonne)" in keys(plant_dict) + if "outputs (tonne/tonne)" in keys(plant_dict) output = Dict(prod_name_to_product[key] => value - for (key, value) in plant_dict["Outputs (tonne)"] + for (key, value) in plant_dict["outputs (tonne/tonne)"] if value > 0) end - for (location_name, location_dict) in plant_dict["Locations"] + for (location_name, location_dict) in plant_dict["locations"] sizes = PlantSize[] disposal_limit = Dict(p => [0.0 for t in 1:T] for p in keys(output)) disposal_cost = Dict(p => [0.0 for t in 1:T] for p in keys(output)) # Disposal - if "Disposal" in keys(location_dict) - for (product_name, disposal_dict) in location_dict["Disposal"] + if "disposal" in keys(location_dict) + for (product_name, disposal_dict) in location_dict["disposal"] limit = [1e8 for t in 1:T] - if "Limit (tonne)" in keys(disposal_dict) - limit = disposal_dict["Limit (tonne)"] + if "limit (tonne)" in keys(disposal_dict) + limit = disposal_dict["limit (tonne)"] end disposal_limit[prod_name_to_product[product_name]] = limit - disposal_cost[prod_name_to_product[product_name]] = disposal_dict["Cost (\$/tonne)"] + disposal_cost[prod_name_to_product[product_name]] = disposal_dict["cost (\$/tonne)"] end end # Capacities - for (capacity_name, capacity_dict) in location_dict["Capacities (tonne)"] + for (capacity_name, capacity_dict) in location_dict["capacities (tonne)"] push!(sizes, PlantSize(parse(Float64, capacity_name), - capacity_dict["Variable operating cost (\$/tonne)"], - capacity_dict["Fixed operating cost (\$)"], - capacity_dict["Opening cost (\$)"])) + capacity_dict["variable operating cost (\$/tonne)"], + capacity_dict["fixed operating cost (\$)"], + capacity_dict["opening cost (\$)"])) end length(sizes) > 1 || push!(sizes, sizes[1]) sort!(sizes, by = x -> x.capacity) @@ -148,8 +148,8 @@ function load(path::String)::Instance location_name, input, output, - location_dict["Latitude (deg)"], - location_dict["Longitude (deg)"], + location_dict["latitude (deg)"], + location_dict["longitude (deg)"], disposal_limit, disposal_cost, sizes) diff --git a/src/model.jl b/src/model.jl index fb942de..2e55cd7 100644 --- a/src/model.jl +++ b/src/model.jl @@ -20,7 +20,6 @@ function build_model(instance::Instance, graph::Graph, optimizer)::Manufacturing create_objective_function!(model) create_shipping_node_constraints!(model) create_process_node_constraints!(model) - JuMP.write_to_file(model.mip, "model.lp") return model end @@ -194,7 +193,7 @@ function create_process_node_constraints!(model::ManufacturingModel) end end -function solve(filename::String; optimizer=Cbc.Optimizer, lp_optimizer=Clp.Optimizer) +function solve(filename::String; milp_optimizer=Cbc.Optimizer, lp_optimizer=Clp.Optimizer) println("Reading $filename...") instance = RELOG.load(filename) @@ -202,7 +201,7 @@ function solve(filename::String; optimizer=Cbc.Optimizer, lp_optimizer=Clp.Optim graph = RELOG.build_graph(instance) println("Building optimization model...") - model = RELOG.build_model(instance, graph, optimizer) + model = RELOG.build_model(instance, graph, milp_optimizer) println("Optimizing MILP...") JuMP.optimize!(model.mip) diff --git a/src/schemas/input.json b/src/schemas/input.json index 1617591..abc7e90 100644 --- a/src/schemas/input.json +++ b/src/schemas/input.json @@ -12,10 +12,10 @@ "Parameters": { "type": "object", "properties": { - "Time horizon (years)": { "type": "number" } + "time horizon (years)": { "type": "number" } }, "required": [ - "Time horizon (years)" + "time horizon (years)" ] }, "Plant": { @@ -23,16 +23,21 @@ "additionalProperties": { "type": "object", "properties": { - "Input": { "type": "string" }, - "Outputs (tonne)": { + "input": { "type": "string" }, + "outputs (tonne/tonne)": { "type": "object", "additionalProperties": { "type": "number" } }, - "Locations": { "$ref": "#/definitions/PlantLocation" } + "energy (GJ/tonne)": { "$ref": "#/definitions/TimeSeries" }, + "emissions (tonne/tonne)": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/TimeSeries" } + }, + "locations": { "$ref": "#/definitions/PlantLocation" } }, "required": [ - "Input", - "Locations" + "input", + "locations" ] } }, @@ -41,42 +46,42 @@ "additionalProperties": { "type": "object", "properties": { - "Latitude (deg)": { "type": "number" }, - "Longitude (deg)": { "type": "number" }, - "Disposal": { + "latitude (deg)": { "type": "number" }, + "longitude (deg)": { "type": "number" }, + "disposal": { "type": "object", "additionalProperties": { "type": "object", "properties": { - "Cost ($/tonne)": { "$ref": "#/definitions/TimeSeries" }, - "Limit (tonne)": { "$ref": "#/definitions/TimeSeries" } + "cost ($/tonne)": { "$ref": "#/definitions/TimeSeries" }, + "limit (tonne)": { "$ref": "#/definitions/TimeSeries" } }, "required": [ - "Cost ($/tonne)" + "cost ($/tonne)" ] } }, - "Capacities (tonne)": { + "capacities (tonne)": { "type": "object", "additionalProperties": { "type": "object", "properties": { - "Variable operating cost ($/tonne)": { "$ref": "#/definitions/TimeSeries" }, - "Fixed operating cost ($)": { "$ref": "#/definitions/TimeSeries" }, - "Opening cost ($)": { "$ref": "#/definitions/TimeSeries" } + "variable operating cost ($/tonne)": { "$ref": "#/definitions/TimeSeries" }, + "fixed operating cost ($)": { "$ref": "#/definitions/TimeSeries" }, + "opening cost ($)": { "$ref": "#/definitions/TimeSeries" } }, "required": [ - "Variable operating cost ($/tonne)", - "Fixed operating cost ($)", - "Opening cost ($)" + "variable operating cost ($/tonne)", + "fixed operating cost ($)", + "opening cost ($)" ] } } }, "required": [ - "Latitude (deg)", - "Longitude (deg)", - "Capacities (tonne)" + "latitude (deg)", + "longitude (deg)", + "capacities (tonne)" ] } }, @@ -85,14 +90,14 @@ "additionalProperties": { "type": "object", "properties": { - "Latitude (deg)": { "type": "number" }, - "Longitude (deg)": { "type": "number" }, - "Amount (tonne)": { "$ref": "#/definitions/TimeSeries" } + "latitude (deg)": { "type": "number" }, + "longitude (deg)": { "type": "number" }, + "amount (tonne)": { "$ref": "#/definitions/TimeSeries" } }, "required": [ - "Latitude (deg)", - "Longitude (deg)", - "Amount (tonne)" + "latitude (deg)", + "longitude (deg)", + "amount (tonne)" ] } }, @@ -101,24 +106,29 @@ "additionalProperties": { "type": "object", "properties": { - "Transportation cost ($/km/tonne)": { "$ref": "#/definitions/TimeSeries" }, - "Initial amounts": { "$ref": "#/definitions/InitialAmount" } + "transportation cost ($/km/tonne)": { "$ref": "#/definitions/TimeSeries" }, + "transportation energy (J/km/tonne)": { "$ref": "#/definitions/TimeSeries" }, + "transportation emissions (tonne/km/tonne)": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/TimeSeries" } + }, + "initial amounts": { "$ref": "#/definitions/InitialAmount" } }, "required": [ - "Transportation cost ($/km/tonne)" + "transportation cost ($/km/tonne)" ] } } }, "type": "object", "properties": { - "Parameters": { "$ref": "#/definitions/Parameters" }, - "Plants": { "$ref": "#/definitions/Plant" }, - "Products": { "$ref": "#/definitions/Product" } + "parameters": { "$ref": "#/definitions/Parameters" }, + "plants": { "$ref": "#/definitions/Plant" }, + "products": { "$ref": "#/definitions/Product" } }, "required": [ - "Parameters", - "Plants", - "Products" + "parameters", + "plants", + "products" ] } \ No newline at end of file diff --git a/test/model_test.jl b/test/model_test.jl index 8aa06f1..740a6d7 100644 --- a/test/model_test.jl +++ b/test/model_test.jl @@ -36,9 +36,9 @@ using RELOG, Cbc, JuMP, Printf, JSON, MathOptInterface.FileFormats @test lower_bound(v) == 0.0 @test upper_bound(v) == 1.0 - dest = FileFormats.Model(format = FileFormats.FORMAT_LP) - MOI.copy_to(dest, model.mip) - MOI.write_to_file(dest, "model.lp") + #dest = FileFormats.Model(format = FileFormats.FORMAT_LP) + #MOI.copy_to(dest, model.mip) + #MOI.write_to_file(dest, "model.lp") end @testset "solve" begin