Switch from Euclidean to approximate driving distance

This commit is contained in:
2022-12-15 09:49:38 -06:00
parent 23b3b33146
commit 48bd3c403f
9 changed files with 109 additions and 15 deletions

View File

@@ -5,19 +5,19 @@
module RELOG
include("instance/structs.jl")
include("graph/structs.jl")
include("instance/geodb.jl")
include("graph/dist.jl")
include("graph/build.jl")
include("graph/csv.jl")
include("instance/compress.jl")
include("instance/geodb.jl")
include("instance/parse.jl")
include("instance/validate.jl")
include("model/build.jl")
include("model/getsol.jl")
include("model/solve.jl")
include("model/resolve.jl")
include("model/solve.jl")
include("reports/plant_emissions.jl")
include("reports/plant_outputs.jl")
include("reports/plants.jl")

View File

@@ -2,14 +2,6 @@
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
using Geodesy
function calculate_distance(source_lat, source_lon, dest_lat, dest_lon)::Float64
x = LLA(source_lat, source_lon, 0.0)
y = LLA(dest_lat, dest_lon, 0.0)
return round(euclidean_distance(x, y) / 1000.0, digits = 2)
end
function build_graph(instance::Instance)::Graph
arcs = []
next_index = 0
@@ -48,13 +40,15 @@ function build_graph(instance::Instance)::Graph
end
# Build arcs from collection centers to plants, and from one plant to another
metric = _KnnDrivingDistance()
for source in [collection_shipping_nodes; plant_shipping_nodes]
for dest in process_nodes_by_input_product[source.product]
distance = calculate_distance(
distance = _calculate_distance(
source.location.latitude,
source.location.longitude,
dest.location.latitude,
dest.location.longitude,
metric,
)
values = Dict("distance" => distance)
arc = Arc(source, dest, values)

69
src/graph/dist.jl Normal file
View File

@@ -0,0 +1,69 @@
# RELOG: Reverse Logistics Optimization
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.
using Geodesy
using NearestNeighbors
using DataFrames
Base.@kwdef mutable struct _KnnDrivingDistance
tree = nothing
ratios = nothing
end
mutable struct _EuclideanDistance end
function _calculate_distance(
source_lat,
source_lon,
dest_lat,
dest_lon,
::_EuclideanDistance,
)::Float64
x = LLA(source_lat, source_lon, 0.0)
y = LLA(dest_lat, dest_lon, 0.0)
return round(euclidean_distance(x, y) / 1000.0, digits = 3)
end
function _calculate_distance(
source_lat,
source_lon,
dest_lat,
dest_lon,
metric::_KnnDrivingDistance,
)::Float64
if metric.tree === nothing
basedir = joinpath(dirname(@__FILE__), "..", "..", "data")
csv_filename = joinpath(basedir, "dist_driving.csv")
# Download pre-computed driving data
if !isfile(csv_filename)
_download_zip(
"https://axavier.org/RELOG/0.6/data/dist_driving_0b9a6ad6.zip",
basedir,
csv_filename,
0x0b9a6ad6,
)
end
# Fit kNN model
df = DataFrame(CSV.File(csv_filename))
coords = Matrix(df[!, [:source_lat, :source_lon, :dest_lat, :dest_lon]])'
metric.ratios = Matrix(df[!, [:ratio]])
metric.tree = KDTree(coords)
end
# Compute Euclidean distance
dist_euclidean = _calculate_distance(
source_lat,
source_lon,
dest_lat,
dest_lon,
_EuclideanDistance(),
)
# Predict ratio
idxs, _ = knn(metric.tree, [source_lat, source_lon, dest_lat, dest_lon], 5)
ratio_pred = mean(metric.ratios[idxs])
return round(dist_euclidean * ratio_pred, digits = 3)
end