mirror of
https://github.com/ANL-CEEESA/RELOG.git
synced 2025-12-06 07:48:50 -06:00
Make distance metric configurable; fix building period bug
This commit is contained in:
@@ -12,8 +12,11 @@ All notable changes to this project will be documented in this file.
|
|||||||
[pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0
|
[pkjjl]: https://pkgdocs.julialang.org/v1/compatibility/#compat-pre-1.0
|
||||||
|
|
||||||
# [0.6.0] -- 2022-12-15
|
# [0.6.0] -- 2022-12-15
|
||||||
### Changed
|
### Added
|
||||||
- Switch from Euclidean distance to approximate driving distance
|
- Allow RELOG to calculate approximate driving distances, instead of just straight-line distances between points.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fix bug that caused building period parameter to be ignored
|
||||||
|
|
||||||
## [0.5.2] -- 2022-08-26
|
## [0.5.2] -- 2022-08-26
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ The **parameters** section describes details about the simulation itself.
|
|||||||
|:--------------------------|:---------------|
|
|:--------------------------|:---------------|
|
||||||
|`time horizon (years)` | Number of years in the simulation.
|
|`time horizon (years)` | Number of years in the simulation.
|
||||||
|`building period (years)` | List of years in which we are allowed to open new plants. For example, if this parameter is set to `[1,2,3]`, we can only open plants during the first three years. By default, this equals `[1]`; that is, plants can only be opened during the first year. |
|
|`building period (years)` | List of years in which we are allowed to open new plants. For example, if this parameter is set to `[1,2,3]`, we can only open plants during the first three years. By default, this equals `[1]`; that is, plants can only be opened during the first year. |
|
||||||
|
|`distance metric` | Metric used to compute distances between pairs of locations. Valid options are: `"Euclidean"`, for the straight-line distance between points; or `"driving"` for an approximated driving distance. If not specified, defaults to `"Euclidean"`.
|
||||||
|
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
@@ -21,7 +22,8 @@ The **parameters** section describes details about the simulation itself.
|
|||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"time horizon (years)": 2,
|
"time horizon (years)": 2,
|
||||||
"building period (years)": [1]
|
"building period (years)": [1],
|
||||||
|
"distance metric": "driving",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -220,6 +222,7 @@ Database | Description | Examples
|
|||||||
* Plants can be expanded at any time, even long after they are open.
|
* Plants can be expanded at any time, even long after they are open.
|
||||||
* All material available at the beginning of a time period must be entirely processed by the end of that time period. It is not possible to store unprocessed materials from one time period to the next.
|
* All material available at the beginning of a time period must be entirely processed by the end of that time period. It is not possible to store unprocessed materials from one time period to the next.
|
||||||
* Up to two plant sizes are currently supported. Variable operating costs must be the same for all plant sizes.
|
* Up to two plant sizes are currently supported. Variable operating costs must be the same for all plant sizes.
|
||||||
|
* Accurate driving distances are only available for the continental United States.
|
||||||
|
|
||||||
## Output Data Format (JSON)
|
## Output Data Format (JSON)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"time horizon (years)": 2
|
"time horizon (years)": 2,
|
||||||
|
"distance metric": "driving"
|
||||||
},
|
},
|
||||||
"products": {
|
"products": {
|
||||||
"P1": {
|
"P1": {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ function build_graph(instance::Instance)::Graph
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Build arcs from collection centers to plants, and from one plant to another
|
# 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 source in [collection_shipping_nodes; plant_shipping_nodes]
|
||||||
for dest in process_nodes_by_input_product[source.product]
|
for dest in process_nodes_by_input_product[source.product]
|
||||||
distance = _calculate_distance(
|
distance = _calculate_distance(
|
||||||
@@ -48,7 +47,7 @@ function build_graph(instance::Instance)::Graph
|
|||||||
source.location.longitude,
|
source.location.longitude,
|
||||||
dest.location.latitude,
|
dest.location.latitude,
|
||||||
dest.location.longitude,
|
dest.location.longitude,
|
||||||
metric,
|
instance.distance_metric,
|
||||||
)
|
)
|
||||||
values = Dict("distance" => distance)
|
values = Dict("distance" => distance)
|
||||||
arc = Arc(source, dest, values)
|
arc = Arc(source, dest, values)
|
||||||
|
|||||||
@@ -6,19 +6,12 @@ using Geodesy
|
|||||||
using NearestNeighbors
|
using NearestNeighbors
|
||||||
using DataFrames
|
using DataFrames
|
||||||
|
|
||||||
Base.@kwdef mutable struct _KnnDrivingDistance
|
|
||||||
tree = nothing
|
|
||||||
ratios = nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
mutable struct _EuclideanDistance end
|
|
||||||
|
|
||||||
function _calculate_distance(
|
function _calculate_distance(
|
||||||
source_lat,
|
source_lat,
|
||||||
source_lon,
|
source_lon,
|
||||||
dest_lat,
|
dest_lat,
|
||||||
dest_lon,
|
dest_lon,
|
||||||
::_EuclideanDistance,
|
::EuclideanDistance,
|
||||||
)::Float64
|
)::Float64
|
||||||
x = LLA(source_lat, source_lon, 0.0)
|
x = LLA(source_lat, source_lon, 0.0)
|
||||||
y = LLA(dest_lat, dest_lon, 0.0)
|
y = LLA(dest_lat, dest_lon, 0.0)
|
||||||
@@ -30,7 +23,7 @@ function _calculate_distance(
|
|||||||
source_lon,
|
source_lon,
|
||||||
dest_lat,
|
dest_lat,
|
||||||
dest_lon,
|
dest_lon,
|
||||||
metric::_KnnDrivingDistance,
|
metric::KnnDrivingDistance,
|
||||||
)::Float64
|
)::Float64
|
||||||
if metric.tree === nothing
|
if metric.tree === nothing
|
||||||
basedir = joinpath(dirname(@__FILE__), "..", "..", "data")
|
basedir = joinpath(dirname(@__FILE__), "..", "..", "data")
|
||||||
@@ -54,13 +47,8 @@ function _calculate_distance(
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Compute Euclidean distance
|
# Compute Euclidean distance
|
||||||
dist_euclidean = _calculate_distance(
|
dist_euclidean =
|
||||||
source_lat,
|
_calculate_distance(source_lat, source_lon, dest_lat, dest_lon, EuclideanDistance())
|
||||||
source_lon,
|
|
||||||
dest_lat,
|
|
||||||
dest_lon,
|
|
||||||
_EuclideanDistance(),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Predict ratio
|
# Predict ratio
|
||||||
idxs, _ = knn(metric.tree, [source_lat, source_lon, dest_lat, dest_lon], 5)
|
idxs, _ = knn(metric.tree, [source_lat, source_lon, dest_lat, dest_lon], 5)
|
||||||
|
|||||||
@@ -23,10 +23,23 @@ function parse(json)::Instance
|
|||||||
validate(json, Schema(json_schema))
|
validate(json, Schema(json_schema))
|
||||||
|
|
||||||
building_period = [1]
|
building_period = [1]
|
||||||
if "building period (years)" in keys(json)
|
if "building period (years)" in keys(json["parameters"])
|
||||||
building_period = json["building period (years)"]
|
building_period = json["parameters"]["building period (years)"]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
distance_metric = EuclideanDistance()
|
||||||
|
if "distance metric" in keys(json["parameters"])
|
||||||
|
metric_name = json["parameters"]["distance metric"]
|
||||||
|
if metric_name == "driving"
|
||||||
|
distance_metric = KnnDrivingDistance()
|
||||||
|
elseif metric_name == "Euclidean"
|
||||||
|
# nop
|
||||||
|
else
|
||||||
|
error("Unknown distance metric: $metric_name")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@show distance_metric
|
||||||
|
|
||||||
plants = Plant[]
|
plants = Plant[]
|
||||||
products = Product[]
|
products = Product[]
|
||||||
collection_centers = CollectionCenter[]
|
collection_centers = CollectionCenter[]
|
||||||
@@ -176,5 +189,12 @@ function parse(json)::Instance
|
|||||||
@info @sprintf("%12d collection centers", length(collection_centers))
|
@info @sprintf("%12d collection centers", length(collection_centers))
|
||||||
@info @sprintf("%12d candidate plant locations", length(plants))
|
@info @sprintf("%12d candidate plant locations", length(plants))
|
||||||
|
|
||||||
return Instance(T, products, collection_centers, plants, building_period)
|
return Instance(
|
||||||
|
T,
|
||||||
|
products,
|
||||||
|
collection_centers,
|
||||||
|
plants,
|
||||||
|
building_period,
|
||||||
|
distance_metric,
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -48,10 +48,21 @@ mutable struct Plant
|
|||||||
storage_cost::Vector{Float64}
|
storage_cost::Vector{Float64}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
abstract type DistanceMetric end
|
||||||
|
|
||||||
|
Base.@kwdef mutable struct KnnDrivingDistance <: DistanceMetric
|
||||||
|
tree = nothing
|
||||||
|
ratios = nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
mutable struct EuclideanDistance <: DistanceMetric end
|
||||||
|
|
||||||
mutable struct Instance
|
mutable struct Instance
|
||||||
time::Int64
|
time::Int64
|
||||||
products::Vector{Product}
|
products::Vector{Product}
|
||||||
collection_centers::Vector{CollectionCenter}
|
collection_centers::Vector{CollectionCenter}
|
||||||
plants::Vector{Plant}
|
plants::Vector{Plant}
|
||||||
building_period::Vector{Int64}
|
building_period::Vector{Int64}
|
||||||
|
distance_metric::DistanceMetric
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"time horizon (years)": {
|
"time horizon (years)": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"distance metric": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ using RELOG
|
|||||||
-87.656,
|
-87.656,
|
||||||
39.764,
|
39.764,
|
||||||
-86.148,
|
-86.148,
|
||||||
RELOG._EuclideanDistance(),
|
RELOG.EuclideanDistance(),
|
||||||
) == 265.818
|
) == 265.818
|
||||||
|
|
||||||
# Approximate driving distance between Chicago and Indianapolis
|
# Approximate driving distance between Chicago and Indianapolis
|
||||||
@@ -20,6 +20,6 @@ using RELOG
|
|||||||
-87.656,
|
-87.656,
|
||||||
39.764,
|
39.764,
|
||||||
-86.148,
|
-86.148,
|
||||||
RELOG._KnnDrivingDistance(),
|
RELOG.KnnDrivingDistance(),
|
||||||
) == 316.43
|
) == 316.43
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user