Introduction
Optimisation of assets including vehicles, goods, people and energy. Our powerful algorithms cut costs and emissions while improving productivity. Trakm8 Vortex is a suite of algorithms that solve Vehicle Routing Problems.
Trakm8 Vortex API supports both REST and WebSocket communication protocols. The request and response payload format uses JSON.
Vehicle routing problems can take a long time to solve as they are computationally intensive.
A key challenge that faces the logistics sector is the underlying complexity of managing mobile assets efficiently while meeting business objectives. Fleets are become larger, interacting with and adopting new technologies such as electric vehicles and eventually self-driving vehicles. The need for optimisation algorithms which produce realistic solutions, given ever more complex constraints, is growing exponentially.
The challenge is creating effective algorithms which scale. This is where Trakm8 Vortex excels. With our cloud based, highly scalable algorithms we are a recognised world leader in optimisation solutions.
The constrained vehicle routing problem (CVRP) is a combinatorial challenge that requires solving the following two problems together: 1. decide which vehicles will do which tasks 2. for each vehicle, decide the best sequence for the tasks assigned to it. The tasks can be deliveries, collections, transfers, engineering or maintenance visits, or any of a variety of other jobs to be done at some specific location; there maybe many constraints such as time-windows, tools, load and waiting times, capacity & weight, operator & driver skills, vehicle characteristics (e.g. lift or crane), battery charging time, battery capacity, vehicle range and many more constraints.
The routing uses a connected graph to mathematically model the segments of a road network and this has its own constraints such as speed limits, turn restrictions, truck restrictions (e.g. width, height, weight), legal restrictions, traffic patterns, weather and so on. Given all of these constraints the challenge is to quickly calculate good solutions for CVRPs that may have, typically, from 5 to 500 vehicles and from 10s to 10000s of jobs per day. Computationally this is a big challenge; however the use of cloud computing, parallel processing and centralised web-services has allowed significant computational capacity to be deployed. Even small vehicle fleets can access huge computational power which would otherwise be unaffordable.
Licence
The use of this application is subject to the Trakm8 End User License Agreement (EULA) and by accessing the application, you agree that any use you make of the application shall be in strict compliance with the EULA. The EULA is available on request. Contact information for Trakm8 Limited is available at www.trakm8.com. Software distributed under the EULA is distributed on an "AS IS" basis WITHOUT WARRANTY OF ANY KIND, either express or implied. Copyright © 1999-2019 Trakm8 Limited. All Rights Reserved. Use of this application is also subject to certain third party terms which are available at: https://legal.here.com/terms/b2bserviceterms/en
Background
The algorithms available are mainly ‘metaheuristic’ algorithms. This class of algorithm includes: genetic algorithms,evolutionary algorithms, tabu search and simulated annealing. Vortex also includes algorithms that are hybrids, combining aspects of more than one different algorithm.
Some examples in the Vortex algorithms suite include:
opt_vrptw_genetic_indirect_md
: this is an evolutionary algorithm that runs with a large set of genetic operators (subroutines that make take existing solutions and make slight changes that improve them). This algorithm has an ‘indirect encoding’, which means that it does not search for solutions directly, instead it searches for mini-algorithms that will build solutions to the problem at hand. This is an example of a ‘hyper-heuristic’ approach to solving a combinatorial problem. It is a multi-objective algorithm, which means it finishes with a collection of alternative solutions that have different characteristics. E.g. one may be best for overall mileage, while another may have a few percent more mileage but have the lowest cost; another may be a little worse on cost and mileage, but have the lowest level of overtime, and so on.opt_vrptw_tabu_single_objective
: This uses a metaheuristic called 'tabu search', and only returns a single solution; this means it specialises in finding low-cost solutions, but will generally not perform as well as the above algorithm on larger-scale problems. With these and others forming a suite of algorithms that can cater for all sizes and flavours of CVRP, Vortex can efficiently solve an extremely wide variety of vehicle routing problems.
RESTful API
The API is based on the principles of a RESTFul web services. The payload is a JSON encoded format. The calculation of an optimised schedule can take several minutes. Large and complex requests with constraints and hundreds of vehicles will take longer to execute. For this reason the initial HTTP Post request returns immediately with a unique ID for this request. The client must use this ID to poll the server until a solution is available. Polling of the server with the ID will provide progress updates.
POST https://DOMAIN:PORT/RESOURCE?APIKEY=xxxxxx
The content payload is JSON
In summary the client process is:
- Client sends HTTPS POST Request with the JSON payload; the server returns with a request ID; the algorithm calculation starts.
- Client repeatedly sends HTTPS GET Request with the request ID appended in the URL; the sever replies with progress update.
- Finally, the client send a HTTPS GET Requests with the request ID; the server replies with the complete schedule.
The recommended poll rate is that the client should not send requests more frequently than 10 seconds. The server responds with HTTP status code 200. The final results is stored for a short time (~ 1 hour), so the client may make subsequent poll requests.
The payload format is defined later.
Convert JSON V1 to V2
For JSON v1 to v2 migration purposes, it is sometimes helpful to convert a Vortex JSON V1 request to V2.
This can be done by the v1tov2
end-point. However, this way is not recommended to be used in production as this is only designed to help Vortex users to migrate to V2 JSON with less hassle.
Convert V1 to V2 example
import json
import requests
data = '{"ContinueWithoutImprovementTime":9,"PlanDate":"02/01/2019","TotalRunTime":1200,"Depots":[{"Latitude":51.5319517,"Longitude":0.1078958,"Tag":"2|DEPOT"}],"Drivers":[{"Tag":"250|DRIVER","MaximumDrivingDuration":"09:07:00"}],"Requests":[{"Latitude":51.6003284,"Longitude":0.3166651,"Tag":"268887|ORDER"}],"Vehicles":[{"Depot":"2|DEPOT","Driver":"250|DRIVER","Tag":"250|VEHICLE"}]}'
r = requests.post(url = "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1tov2?apikey=APIKEY", data = data)
print(r.status_code, r.text)
var data = {"ContinueWithoutImprovementTime":9,"PlanDate":"02/01/2019","TotalRunTime":1200
,"Depots":[{"Latitude":51.5319517,"Longitude":0.1078958,"Tag":"2|DEPOT"}],"Drivers":[{"Tag":"250|DRIVER","MaximumDrivingDuration":"09:07:00"}],"Requests":[{"Latitude":51.6003284,"Longitude":0.3166651,"Tag":"2688
87|ORDER"}],"Vehicles":[{"Depot":"2|DEPOT","Driver":"250|DRIVER","Tag":"250|VEHICLE"}]};
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
console.log(JSON.stringify(this))
}
};
xmlhttp.open("POST", "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1tov2?apikey=APIKEY");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
curl -XPOST "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1tov2?apikey=APIKEY" -d '{"ContinueWithoutImprovementTime":9,"PlanDate":"02/01/2019","TotalRunTime":1200
,"Depots":[{"Latitude":51.5319517,"Longitude":0.1078958,"Tag":"2|DEPOT"}],"Drivers":[{"Tag":"250|DRIVER","MaximumDrivingDuration":"09:07:00"}],"Requests":[{"Latitude":51.6003284,"Longitude":0.3166651,"Tag":"2688
87|ORDER"}],"Vehicles":[{"Depot":"2|DEPOT","Driver":"250|DRIVER","Tag":"250|VEHICLE"}]}'
Terminate a schedule
You can stop the scheduling request at any time of the execution as long as you know the RequestId
.
This can be done by sending a DELETE
RESTFul request to the service.
DELETE https://DOMAIN:PORT/REQUEST_ID?APIKEY=xxxxxx
Please note that when there is no active process dealing with the targeted scheduling request, the service would return an error message with HTTP status code 404
Not Found
.
Terminate Example
You can terminate a running V2 schedule request with RequestId
= f06fa1bd248f5759ee86dc49fbe14c35b3cda3e41ce3fac0e04cb0b461bdd7c1
.
Terminate a schedule as Follows:
import requests
r = requests.delete(url = "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/f06fa1bd248f5759ee86dc49fbe14c35b3cda3e41ce3fac0e04cb0b461bdd7c1?apikey=APIKEY")
print(r.status_code)
print(r.text)
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
console.log(JSON.stringify(this))
}
};
xmlhttp.open("DELETE", "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/f06fa1bd248f5759ee86dc49fbe14c35b3cda3e41ce3fac0e04cb0b461bdd7c1?apikey=APIKEY");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(null);
curl -XDELETE "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/f06fa1bd248f5759ee86dc49fbe14c35b3cda3e41ce3fac0e04cb0b461bdd7c1?apikey=APIKEY"
V1 JSON Request
Supports RESTful only.
This API format and algorithm is identical to the Route Monkey quantum format and algorithm. The tm8rmscheduler service is a trakm8 service for solving the vehicle routing problems. Given a list of depots, vehicles, drivers and job requests, the service should be able to find a near optimal plan.
import requests
r = requests.get("http://[API_END_POINT]/")
if r.status_code == 200:
print("alive")
curl -I "http://[API_END_POINT]/"
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
alert("Alive");
else
alert("dead");
}
};
xhttp.open("GET", "http://[API_END_POINT]/", true);
xhttp.send();
Make sure to replace
http://[API_END_POINT]/
with the actual endpoint url.
This endpoint is an alive test, it can be used to check if the service is up and running
In order to use the scheduler API, one should first post the input problem to the endpoint: http://[API_END_POINT]/
.
If the request is valid and good to go, the scheduler then return with http status code 200
and a unique request id which can be used to retrieve the result later.
The end user should keep polling the service for the result using the request id generated earlier.
In other words, there are two parts required to get a plan:
- Make a Schedule Request:
POST
the input request to the service - Polling for Result:
GET
the response from the service by frequent polling attempts.
RESTFul V1 Example
- POST the JSON Request, which would return a request id.
Post JSON request example:
import json
import requests
data = {"ContinueWithoutImprovementTime":30,"Depots":[{"Characteristics":"","ClosingTime":"23:00:00","Latitude":54.3323,"LoadingTime":"00:00:30","LocationGeohash":"gcwj1dgu","Longitude":-2.7413,"MaximumVehiclesNumber":5,"OpeningTime":"05:00:00","Tag":"Depot_1"}],"Drivers":[{"BreakDuration":"00:45:00","BreifingTime":"00:15:00","CostPerDay":22,"CostPerHour":3.5,"DebreifingTime":"00:00:00","EarliestBreakTime":"04:30:00","MaxOvernights":2,"MaximumDrivingDuration":"10:00:00","MaximumOvertime":"01:30:00","MaximumWorkingTime":"11:00:00","MinOvernightDrivingDistanceKM":180,"OvernightCost":75,"OvertimeCostPerHour":7,"PossibleDays":"1","RequestCharacteristics":"driverskill_1","SecondManEffect":1,"SecondManFixedCost":0,"ShiftEarlyStart":"06:00:00","ShiftLateStart":"08:00:00","Tag":"Driver_1"}],"EnableIntermediateResults":true,"Locations":[{"Latitude":54.3323,"LocationGeohash":"gcwj1dgu","Longitude":-2.7413},{"Latitude":51.4904,"LocationGeohash":"gcnhzjd3","Longitude":-2.5016}],"RequestId":"257116863fc9c1e92f2456a13ae040857eb6dde36e971e20ddabf4f6756d7683","Requests":[{"CanSplitOverCompartment":false,"DepotCharacteristics":"","DriverCharacteristics":"","FixedVistDuration":"00:15:00","Id":1,"Latitude":51.4904,"LoadTimePerUnit":"00:00:00","LocationGeohash":"gcnhzjd3","Longitude":-2.5016,"MatchAllTractor":true,"MatchAllTrailer":false,"MatchAlldepot":false,"MatchAlldriver":false,"PossibleVistDays":"1","Quantity1":1,"Quantity2":40,"Quantity3":0,"Quantity4":0,"RevenueIncome":10000,"Service":0,"Tag":"Job_2","TimeWindows":"07:00:00,12:30:00,13:30:00,19:30:00","TractorCharacteristics":"","TrailerCharacteristics":"","TransportSeperately":false,"Weight":0}],"SpeedProfiles":[],"TotalRunTime":120,"Vehicles":[{"Backhaul":false,"Capacity1":12,"Capacity2":400,"Capacity3":0,"Capacity4":0,"CarryingWeightKg":1200,"CharacteristicsRequest":"resourceskill_1","CostPerKm":3.5,"Costperday":30,"CostperdayOfNonUse":20,"Depot":"Depot_1","DepotLoadingTime":"00:05:00","Driver":"Driver_1","EndLatitude":54.3323,"EndLocationGeohash":"gcwj1dgu","EndLongitude":-2.7413,"HandlingTimePerUnit":"00:00:00","LegalDrivingDuration":"04:30:00","LegalRestDuration":"00:30:00","MaximumLoadUnloadTime":"00:30:00","MaximumWorkingTime":"15:00:00","MinRestDuration":"00:15:00","OpenEnd":false,"OpenStart":false,"OperatingRadiusKM":1000000,"PossibleDays":"1","PreLoad":false,"StartLatitude":54.3323,"StartLocationGeohash":"gcwj1dgu","StartLongitude":-2.7413,"StartTime":"04:00:00","SurpressDepotReload":false,"Tag":"Resource_1","UnloadAfterShift":true}]}
r = requests.post(url = "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v2?apikey=APIKEY", data = json.dumps(data))
if r.status_code == 200:
print(r.text)
var data = {"ContinueWithoutImprovementTime":30,"Depots":[{"Characteristics":"","ClosingTime":"23:00:00","Latitude":54.3323,"LoadingTime":"00:00:30","LocationGeohash":"gcwj1dgu","Longitude":-2.7413,"MaximumVehiclesNumber":5,"OpeningTime":"05:00:00","Tag":"Depot_1"}],"Drivers":[{"BreakDuration":"00:45:00","BreifingTime":"00:15:00","CostPerDay":22,"CostPerHour":3.5,"DebreifingTime":"00:00:00","EarliestBreakTime":"04:30:00","MaxOvernights":2,"MaximumDrivingDuration":"10:00:00","MaximumOvertime":"01:30:00","MaximumWorkingTime":"11:00:00","MinOvernightDrivingDistanceKM":180,"OvernightCost":75,"OvertimeCostPerHour":7,"PossibleDays":"1","RequestCharacteristics":"driverskill_1","SecondManEffect":1,"SecondManFixedCost":0,"ShiftEarlyStart":"06:00:00","ShiftLateStart":"08:00:00","Tag":"Driver_1"}],"EnableIntermediateResults":true,"Locations":[{"Latitude":54.3323,"LocationGeohash":"gcwj1dgu","Longitude":-2.7413},{"Latitude":51.4904,"LocationGeohash":"gcnhzjd3","Longitude":-2.5016}],"RequestId":"257116863fc9c1e92f2456a13ae040857eb6dde36e971e20ddabf4f6756d7683","Requests":[{"CanSplitOverCompartment":false,"DepotCharacteristics":"","DriverCharacteristics":"","FixedVistDuration":"00:15:00","Id":1,"Latitude":51.4904,"LoadTimePerUnit":"00:00:00","LocationGeohash":"gcnhzjd3","Longitude":-2.5016,"MatchAllTractor":true,"MatchAllTrailer":false,"MatchAlldepot":false,"MatchAlldriver":false,"PossibleVistDays":"1","Quantity1":1,"Quantity2":40,"Quantity3":0,"Quantity4":0,"RevenueIncome":10000,"Service":0,"Tag":"Job_2","TimeWindows":"07:00:00,12:30:00,13:30:00,19:30:00","TractorCharacteristics":"","TrailerCharacteristics":"","TransportSeperately":false,"Weight":0}],"SpeedProfiles":[],"TotalRunTime":120,"Vehicles":[{"Backhaul":false,"Capacity1":12,"Capacity2":400,"Capacity3":0,"Capacity4":0,"CarryingWeightKg":1200,"CharacteristicsRequest":"resourceskill_1","CostPerKm":3.5,"Costperday":30,"CostperdayOfNonUse":20,"Depot":"Depot_1","DepotLoadingTime":"00:05:00","Driver":"Driver_1","EndLatitude":54.3323,"EndLocationGeohash":"gcwj1dgu","EndLongitude":-2.7413,"HandlingTimePerUnit":"00:00:00","LegalDrivingDuration":"04:30:00","LegalRestDuration":"00:30:00","MaximumLoadUnloadTime":"00:30:00","MaximumWorkingTime":"15:00:00","MinRestDuration":"00:15:00","OpenEnd":false,"OpenStart":false,"OperatingRadiusKM":1000000,"PossibleDays":"1","PreLoad":false,"StartLatitude":54.3323,"StartLocationGeohash":"gcwj1dgu","StartLongitude":-2.7413,"StartTime":"04:00:00","SurpressDepotReload":false,"Tag":"Resource_1","UnloadAfterShift":true}]};
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
console.log(JSON.stringify(this))
}
};
xmlhttp.open("POST", "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v2?apikey=APIKEY");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
curl -XPOST "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1?apikey=APIKEY" -d '{"ContinueWithoutImprovementTime":30,"Depots":[{"Characteristics":"","ClosingTime":"23:00:00","Latitude":54.3323,"LoadingTime":"00:00:30","LocationGeohash":"gcwj1dgu","Longitude":-2.7413,"MaximumVehiclesNumber":5,"OpeningTime":"05:00:00","Tag":"Depot_1"}],"Drivers":[{"BreakDuration":"00:45:00","BreifingTime":"00:15:00","CostPerDay":22,"CostPerHour":3.5,"DebreifingTime":"00:00:00","EarliestBreakTime":"04:30:00","MaxOvernights":2,"MaximumDrivingDuration":"10:00:00","MaximumOvertime":"01:30:00","MaximumWorkingTime":"11:00:00","MinOvernightDrivingDistanceKM":180,"OvernightCost":75,"OvertimeCostPerHour":7,"PossibleDays":"1","RequestCharacteristics":"driverskill_1","SecondManEffect":1,"SecondManFixedCost":0,"ShiftEarlyStart":"06:00:00","ShiftLateStart":"08:00:00","Tag":"Driver_1"}],"EnableIntermediateResults":true,"Locations":[{"Latitude":54.3323,"LocationGeohash":"gcwj1dgu","Longitude":-2.7413},{"Latitude":51.4904,"LocationGeohash":"gcnhzjd3","Longitude":-2.5016}],"RequestId":"257116863fc9c1e92f2456a13ae040857eb6dde36e971e20ddabf4f6756d7683","Requests":[{"CanSplitOverCompartment":false,"DepotCharacteristics":"","DriverCharacteristics":"","FixedVistDuration":"00:15:00","Id":1,"Latitude":51.4904,"LoadTimePerUnit":"00:00:00","LocationGeohash":"gcnhzjd3","Longitude":-2.5016,"MatchAllTractor":true,"MatchAllTrailer":false,"MatchAlldepot":false,"MatchAlldriver":false,"PossibleVistDays":"1","Quantity1":1,"Quantity2":40,"Quantity3":0,"Quantity4":0,"RevenueIncome":10000,"Service":0,"Tag":"Job_2","TimeWindows":"07:00:00,12:30:00,13:30:00,19:30:00","TractorCharacteristics":"","TrailerCharacteristics":"","TransportSeperately":false,"Weight":0}],"SpeedProfiles":[],"TotalRunTime":120,"Vehicles":[{"Backhaul":false,"Capacity1":12,"Capacity2":400,"Capacity3":0,"Capacity4":0,"CarryingWeightKg":1200,"CharacteristicsRequest":"resourceskill_1","CostPerKm":3.5,"Costperday":30,"CostperdayOfNonUse":20,"Depot":"Depot_1","DepotLoadingTime":"00:05:00","Driver":"Driver_1","EndLatitude":54.3323,"EndLocationGeohash":"gcwj1dgu","EndLongitude":-2.7413,"HandlingTimePerUnit":"00:00:00","LegalDrivingDuration":"04:30:00","LegalRestDuration":"00:30:00","MaximumLoadUnloadTime":"00:30:00","MaximumWorkingTime":"15:00:00","MinRestDuration":"00:15:00","OpenEnd":false,"OpenStart":false,"OperatingRadiusKM":1000000,"PossibleDays":"1","PreLoad":false,"StartLatitude":54.3323,"StartLocationGeohash":"gcwj1dgu","StartLongitude":-2.7413,"StartTime":"04:00:00","SurpressDepotReload":false,"Tag":"Resource_1","UnloadAfterShift":true}]}'
This returns with a request Id:
{
"RequestId":"5ad316ecb44c597d180676010e32be72304540014f0d0bdffe22b845bc935e83"
}
- GET the response using previous request Id, which would return the result plan with status:
HTTP/1.1 200 OK
. If the results are not ready yet, the service response with status:HTTP/1.1 202 Accepted
and may return any intermediate results if there are any.
Get JSON response using request Id:
import requests
r = requests.get("https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1/5ad316ecb44c597d180676010e32be72304540014f0d0bdffe22b845bc935e83?apikey=APIKEY")
if r.status_code == 200:
print(r.text)
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
console.log(JSON.stringify(this));
}
};
xhttp.open("GET", "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1/5ad316ecb44c597d180676010e32be72304540014f0d0bdffe22b845bc935e83?apikey=APIKEY", true);
xhttp.send();
curl -v -XGET "https://api-core01.trakm8.net:8443/bdservices/vortex/api/latest/v1/5ad316ecb44c597d180676010e32be72304540014f0d0bdffe22b845bc935e83?apikey=APIKEY"
JSON response:
{
"RequestId": "5ad316ecb44c597d180676010e32be72304540014f0d0bdffe22b845bc935e83",
"Cost": 2648.7859393439312,
"Miles": 456.31693105407209,
"UnPlanned": 0,
"ExecutionTimeSecond": 0,
"UnplannedRequests": [],
"Data": [
{
"Tag": null,
"RunOrder": 0,
"RunNo": "0",
"Day": 1,
"Eta": 360.0,
"Duration": 0.0,
"Vehicle": "Resource_1",
"Miles": 0.0,
"Task": "TSKSHIFTSTART"
},
{
"Tag": "Resource_1",
"RunOrder": 1,
"RunNo": "0",
"Day": 1,
"Eta": 360.0,
"Duration": 15.0,
"Vehicle": "Resource_1",
"Miles": 0.0,
"Task": "TSKBRIEFING"
},
{
"Tag": null,
"RunOrder": 2,
"RunNo": "0",
"Day": 1,
"Eta": 375.0,
"Duration": 189.63103519624377,
"Vehicle": "Resource_1",
"Miles": 228.09277804951685,
"Task": "TSKTRAVEL"
},
{
"Tag": "Job_2",
"RunOrder": 3,
"RunNo": "0",
"Day": 1,
"Eta": 564.63103519624383,
"Duration": 15.0,
"Vehicle": "Resource_1",
"Miles": 228.09277804951685,
"Task": "TSKSERVICE"
},
{
"Tag": null,
"RunOrder": 4,
"RunNo": "0",
"Day": 1,
"Eta": 579.63103519624383,
"Duration": 50.368964803756228,
"Vehicle": "Resource_1",
"Miles": 60.67942893695286,
"Task": "TSKTRAVEL"
},
{
"Tag": null,
"RunOrder": 5,
"RunNo": "0",
"Day": 1,
"Eta": 630.0,
"Duration": 45.0,
"Vehicle": "Resource_1",
"Miles": 288.77220698646971,
"Task": "TSKLUNCH"
},
{
"Tag": null,
"RunOrder": 6,
"RunNo": "0",
"Day": 1,
"Eta": 675.0,
"Duration": 30.0,
"Vehicle": "Resource_1",
"Miles": 36.140962499448307,
"Task": "TSKTRAVEL"
},
{
"Tag": null,
"RunOrder": 7,
"RunNo": "0",
"Day": 1,
"Eta": 705.0,
"Duration": 109.07603379696371,
"Vehicle": "Resource_1",
"Miles": 131.40376156815404,
"Task": "TSKTRAVEL"
},
{
"Tag": "Resource_1",
"RunOrder": 8,
"RunNo": "0",
"Day": 1,
"Eta": 814.07603379696366,
"Duration": 0.0,
"Vehicle": "Resource_1",
"Miles": 456.31693105407209,
"Task": "TSKDEBRIEFING"
},
{
"Tag": null,
"RunOrder": 9,
"RunNo": "0",
"Day": 1,
"Eta": 814.07603379696366,
"Duration": 0.0,
"Vehicle": "Resource_1",
"Miles": 456.31693105407209,
"Task": "TSKSHIFTEND"
}
]
}
Part 1: Make a Schedule Request
This endpoint allow users to send input to the scheduler, the input should define a vehicle routing problem. This can be done by defining a list of Depots, Drivers, Vehicles, and Requests. As a result, the service respond with a unique request ID which can be used later to retrieve the plan. For more details please check Part 1 HTTP Response.
Input request has the following JSON format
{
"ContinueWithoutImprovementTime": 5,
"TotalRunTime": 1200,
"Depots": [
{
"Latitude": 51.5319518,
"Longitude": 0.1078958,
"Tag": "2|DEPOT"
}
],
"Drivers": [
{
"BreakDuration": "00:30:00",
"CostPerDay": 131.43,
"CostPerHour": 16.43,
"EarliestBreakTime": "04:00:00",
"MaximumDrivingDuration": "09:00:00",
"MaximumWorkingTime": "18:00:00",
"PossibleDays": "1",
"ShiftEarlyStart": "06:00:00",
"Tag": "250|DRIVER"
}
],
"Requests": [
{
"AdditionalTag": "",
"FixedVisitDuration": "00:04:00",
"Latitude": 51.6003284,
"Longitude": 0.3166651,
"PossibleVisitDays": "1",
"Quantity1": 49.38,
"RevenueIncome": 1000,
"Service": 1,
"Tag": "268887|ORDER",
"TimeWindows": "06:00:00,18:00:00",
"TractorCharacteristics": ""
}
],
"SpeedProfile": {
"Catergory1KPH": 80,
"Catergory2KPH": 56,
"Catergory3KPH": 48,
"Catergory4KPH": 45,
"Catergory5KPH": 35,
"Catergory6KPH": 29
},
"SpeedProfiles": [
{
"Catergory1KPH": 101,
"Catergory2KPH": 87,
"Catergory3KPH": 72,
"Catergory4KPH": 58,
"Catergory5KPH": 43,
"Catergory6KPH": 29,
"Tag": "1|SPEED_PROFILE"
}
],
"Vehicles": [
{
"Capacity1": 1500,
"CharacteristicsRequest": "250",
"CostPerKm": 0.1,
"CostPerDay": 4.8,
"Depot": "2|DEPOT",
"Driver": "250|DRIVER",
"LegalDrivingDuration": "04:30:00",
"MaximumLoadUnloadTime": "05:00:00",
"PossibleDays": "1",
"SpeedProfile": "1|SPEED_PROFILE",
"Tag": "250|VEHICLE"
}
]
}
import json
import requests
data = {"ContinueWithoutImprovementTime":5,"Depots":[{"Latitude":51.5319518,"Longitude":0.1078958,"Tag":"2|DEPOT"}],"Drivers":[{"BreakDuration":"00:30:00","CostPerDay":131.43,"CostPerHour":16.43,"EarliestBreakTime":"04:00:00","MaximumDrivingDuration":"09:00:00","MaximumWorkingTime":"18:00:00","PossibleDays":"1","ShiftEarlyStart":"06:00:00","Tag":"250|DRIVER"}],"Requests":[{"AdditionalTag":"","FixedVisitDuration":"00:04:00","Latitude":51.6003284,"Longitude":0.3166651,"PossibleVisitDays":"1","Quantity1":49.38,"RevenueIncome":1000,"Service":1,"Tag":"268887|ORDER","TimeWindows":"06:00:00,18:00:00","TractorCharacteristics":""}],"SpeedProfile":{"Catergory1KPH":80,"Catergory2KPH":56,"Catergory3KPH":48,"Catergory4KPH":45,"Catergory5KPH":35,"Catergory6KPH":29},"SpeedProfiles":[{"Catergory1KPH":101,"Catergory2KPH":87,"Catergory3KPH":72,"Catergory4KPH":58,"Catergory5KPH":43,"Catergory6KPH":29,"Tag":"1|SPEED_PROFILE"}],"TotalRunTime":1200,"Vehicles":[{"Capacity1":1500,"CharacteristicsRequest":"250","CostPerKm":0.1,"CostPerDay":4.8,"Depot":"2|DEPOT","Driver":"250|DRIVER","LegalDrivingDuration":"04:30:00","MaximumLoadUnloadTime":"05:00:00","PossibleDays":"1","SpeedProfile":"1|SPEED_PROFILE","Tag":"250|VEHICLE"}]}
r = requests.post(url = "http://[API_END_POINT]/", data = json.dumps(data))
if r.status_code == 200:
print(r.text)
curl -X POST \
http://[API_END_POINT]/ \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{"SpeedProfile": {"Catergory4KPH": 45, "Catergory5KPH": 35, "Catergory6KPH": 29, "Catergory1KPH": 80, "Catergory2KPH": 56, "Catergory3KPH": 48}, "SpeedProfiles": [{"Catergory4KPH": 58, "Catergory5KPH": 43, "Catergory6KPH": 29, "Tag": "1|SPEED_PROFILE", "Catergory1KPH": 101, "Catergory2KPH": 87, "Catergory3KPH": 72}], "Requests": [{"Service": 1, "TractorCharacteristics": "", "Longitude": 0.3166651, "AdditionalTag": "", "Latitude": 51.6003284, "FixedVisitDuration": "00:04:00", "TimeWindows": "06:00:00,18:00:00", "Tag": "268887|ORDER", "PossibleVisitDays": "1", "RevenueIncome": 1000, "Quantity1": 49.38}], "TotalRunTime": 1200, "Vehicles": [{"CostPerDay": 4.8, "MaximumLoadUnloadTime": "05:00:00", "SpeedProfile": "1|SPEED_PROFILE", "Depot": "2|DEPOT", "Capacity1": 1500, "CharacteristicsRequest": "250", "Driver": "250|DRIVER", "LegalDrivingDuration": "04:30:00", "Tag": "250|VEHICLE", "PossibleDays": "1", "CostPerKm": 0.1}], "ContinueWithoutImprovementTime": 5, "Drivers": [{"CostPerDay": 131.43, "Tag": "250|DRIVER", "BreakDuration": "00:30:00", "CostPerHour": 16.43, "MaximumWorkingTime": "18:00:00", "MaximumDrivingDuration": "09:00:00", "ShiftEarlyStart": "06:00:00", "EarliestBreakTime": "04:00:00", "PossibleDays": "1"}], "Depots": [{"Latitude": 51.5319518, "Tag": "2|DEPOT", "Longitude": 0.1078958}]}'
var data = {"ContinueWithoutImprovementTime":5,"Depots":[{"Latitude":51.5319518,"Longitude":0.1078958,"Tag":"2|DEPOT"}],"Drivers":[{"BreakDuration":"00:30:00","CostPerDay":131.43,"CostPerHour":16.43,"EarliestBreakTime":"04:00:00","MaximumDrivingDuration":"09:00:00","MaximumWorkingTime":"18:00:00","PossibleDays":"1","ShiftEarlyStart":"06:00:00","Tag":"250|DRIVER"}],"Requests":[{"AdditionalTag":"","FixedVisitDuration":"00:04:00","Latitude":51.6003284,"Longitude":0.3166651,"PossibleVisitDays":"1","Quantity1":49.38,"RevenueIncome":1000,"Service":1,"Tag":"268887|ORDER","TimeWindows":"06:00:00,18:00:00","TractorCharacteristics":""}],"SpeedProfile":{"Catergory1KPH":80,"Catergory2KPH":56,"Catergory3KPH":48,"Catergory4KPH":45,"Catergory5KPH":35,"Catergory6KPH":29},"SpeedProfiles":[{"Catergory1KPH":101,"Catergory2KPH":87,"Catergory3KPH":72,"Catergory4KPH":58,"Catergory5KPH":43,"Catergory6KPH":29,"Tag":"1|SPEED_PROFILE"}],"TotalRunTime":1200,"Vehicles":[{"Capacity1":1500,"CharacteristicsRequest":"250","CostPerKm":0.1,"CostPerDay":4.8,"Depot":"2|DEPOT","Driver":"250|DRIVER","LegalDrivingDuration":"04:30:00","MaximumLoadUnloadTime":"05:00:00","PossibleDays":"1","SpeedProfile":"1|SPEED_PROFILE","Tag":"250|VEHICLE"}]};
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
console.log(JSON.stringify(this))
}
};
xmlhttp.open("POST", "http://[API_END_POINT]/");
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send(JSON.stringify(data));
The above code return the following JSON structure:
{
"RequestId": "a429a8e4-ecf9-4089-bdd6-f74fe7ad9808"
}
HTTP Request
POST http://[API_END_POINT]/ DATA
HTTP Response
As a result of sending a request, tm8rmscheduler
service returns with a unique request ID.
Part 1 response has the following JSON format:
{
"RequestId": "a802a998-e3c1-48f9-a8ca-619888f4adf0"
}
Key | Value description |
---|---|
RequestId |
A unique request ID which can be used for polling the result plan from the service. |
Key/Value Pairs in the POST DATA
Arguments which are required are marked as mandatory
. Optional arguments are provided with their default values. It's recommended that you explicitly set all arguments as default arguments can change.
Key | Default value | Value Description |
---|---|---|
ContinueWithoutImprovementTime |
mandatory |
The run time of the second part of the algorithm since the last overall improvement was found. |
TotalRunTime |
mandatory |
Specify the total time in seconds which is allowed for the algorithm to take before it terminates, thus execution time can be up to this value depending on the input problem. |
LocationPrecisionMetre |
1 | This is a positive integer represents the precision vortex would use for input problem's locations. Less precision values mean that more adjacent locations might be considered as same location. Based on the LocationPrecisionMetre value, Vortex is clustering problem's locations into clusters each with maximum size of LocationPrecisionMetre in meters. When Vortex identify a group of geographic locations which can be located in a circle with diameter less than LocationPrecisionMetre value, all these geographic locations are represented by one of the group's locations; usually, the location in the centre is used to represent other group's locations. |
EnableIntermediateResults |
false |
A boolean flag to determine whether the algorithm is sending intermediate results back during its execution. Intermediate results are returned with HTTP status: Accepted and status code: 202 . |
PriorRequestID |
null |
This can be optionally populated using the requestID of a previous (very similar), or slightly modified request. Consequently, when populated, Vortex would be able to reuse previous distance and time matrices. |
CacheMatrices |
false |
This is a boolean value to determine whether or not to cache distance and time matrices. It is useful to turn this flag on when current request is likely to be modified in the future and run again; in this scenario, caching matrices on current request would help Vortex to calculate modified future requests' matrices faster. |
Depots |
mandatory |
Specify a list of depots, for more info please check Depot Key/Value pairs. Note: there should always be at least one depot. |
Drivers |
mandatory |
Specify a list of drivers, for more info please check Driver Key/Value pairs. Note: a 'driver' in this context will not normally refer to an individual person. Instead, it can be a profile which is inherited by resources. For example, there might be two drivers, one named "EarlyShift" and one named "LateShift", holding the respective operating constraints. |
Vehicles |
mandatory |
Specify a list of vehicles. For example, if the client has 25 vehicles available today, then there will be 25 vehicles in this array. For more info please refer to Vehicle Key/Value pairs. |
Requests |
Specify a list of job requests, each item has the format specified in Request Key/Value pairs. | |
SpeedProfile |
SpeedProfile Key/Value pairs | Optionally specify the default speed profile which is used for all vehicles by default. The default values are defined by the SpeedProfile Key/Value pairs. |
SpeedProfiles |
null |
Specify the list of speed profiles which are used for specific vehicles to override the default SpeedProfile. The speed profiles from this list when linked to vehicles override the default speed profile. For more info please refer to SpeedProfile Key/Value pairs. |
Depots Key/Value pairs
The depot represents locations where resources are loaded/exchanged/unloaded and in most instances where vehicles start and end.
"Depots": [{
"Tag": "2|DEPOT",
"OpeningTime": "00:00:00",
"ClosingTime": "23:59:59",
"Characteristics": null,
"Latitude": 51.5319518,
"Longitude": 0.1078958
}
]
Key | Default value | Value Description |
---|---|---|
Tag |
mandatory |
A unique ID for the depot. |
OpeningTime |
"00:00:00" |
A string represents the opening time of the depot in the format HH:mm:ss , e.g. 08:00:00 represents eight o'clock in the morning and 20:00:00 represents eight o'clock in the evening. |
ClosingTime |
"23:59:59" |
A string represents the closing time of the depot in the format HH:mm:ss , e.g. 08:00:00 represents eight o'clock in the morning and 20:00:00 represents eight o'clock in the evening. |
LoadingTime |
"00:00:00" |
Loading time (in string format HH:mm:ss ) for this depot. This time will be added to other loading times for a resource and a job request. This is a single fixed cost to add when the algorithm loads or unloads a resource (NOT per item loaded/unloaded). |
Characteristics |
null |
Characteristics which are matched against Tractor object to ensure it can operate from this site. Multiple characteristics need to be separated by a comma. |
Latitude |
mandatory |
The geographical location latitude value of this depot. The format is degrees and decimal minutes e.g. 51.5319518. |
Longitude |
mandatory |
The geographical location longitude value of this depot. . The format is degrees and decimal minutes e.g. 0.1078958. |
Drivers Key/Value pairs
Drivers contain all the detail on when a driver is available , for how long and at what cost. You can set the system up so it uses a single generic driver, i.e. this is a driver of shift pattern 1 or you can set a profile up specific to a driver i.e. this relates specifically to John Smith.
"Drivers": [{
"Tag": "250-DRIVER",
"BreakDuration": "00:30:00",
"EarliestBreakTime": "04:00:00",
"BriefingTime":"00:00:00",
"DeBriefingTime":"00:00:00",
"RequestCharacteristics":null,
"CostPerDay": 131.43,
"CostPerHour": 16.43,
"MaximumWorkingTime": "18:00:00",
"MaximumDrivingDuration": "09:00:00",
"PossibleDays": "1",
"ShiftEarlyStart": "06:00:00",
"ShiftLateStart": "06:30:00"
}, {
"Tag": "251-DRIVER",
"BreakDuration": "00:30:00",
"EarliestBreakTime": "04:00:00",
"BriefingTime":"00:00:00",
"DeBriefingTime":"00:00:00",
"RequestCharacteristics":null,
"CostPerDay": 80,
"CostPerHour": 10,
"MaximumWorkingTime": "18:00:00",
"MaximumDrivingDuration": "09:00:00",
"PossibleDays": "1",
"ShiftEarlyStart": "06:00:00",
"ShiftLateStart": "06:30:00"
}
]
Key | Default value | Value Description |
---|---|---|
Tag |
mandatory |
A unique ID for the driver. This could be a driver's name, but normally it will indicate a type of driver - e.g. "MorningShift", "SubContractorCompany1", ... |
BreakDuration |
"00:00:00" |
Drivers normally will often be required to have a break of length BreakDuration during their shift. This is a time interval in the string format HH:mm:ss . |
EarliestBreakTime |
"04:00:00" |
Drivers must take a break of BreakDuration at the first opportunity after they have worked for at least this amount of time. (Work means driving + briefing + unloading/loading). |
BriefingTime |
"00:00:00" |
Time interval string with format HH:mm:ss representing the briefing duration at the beginning of driver's shift in seconds. |
DeBriefingTime |
"00:00:00" |
Time interval string format HH:mm:ss representing the debriefing time needed by the driver at the end of their shift. |
RequestCharacteristics |
null |
Characteristics that are matched against the request to check this driver can complete this work, this is a comma separated string of skills. |
CostPerDay |
0 |
Daily cost of the driver, this is a fixed cost amount added in the days when the driver is hired. |
CostPerHour |
0 |
Hourly cost of the driver. |
MaximumWorkingTime |
"11:00:00" |
Maximum duration of the driver's working shift in string time interval format HH:mm:ss . |
MaximumDrivingDuration |
"10:00:00" |
Maximum time a driver can drive during their shift in string time interval format HH:mm:ss . |
MaximumOvertime |
"00:00:00" |
String time interval represents maximum overtime duration (beyond MaximumWorkingTime ) which the driver can do in one shift. |
OvertimeCostPerHour |
0 |
Hourly cost for overtime. |
MaxOvernights |
0 |
The maximum number of overnight stops that the driver can take during this scheduling run. The value zero indicates that overnight settings is turned off for this driver. |
SecondManEffect |
1.0 |
The percentage effect on the request duration that having a second man will have e.g. 0.7 a 30% reduction in time. if not second ma set to 1.0 . |
SecondManFixedCost |
0 |
The increase in cost for have a second man, if no second man is used set to 0.0 . |
MinOvernightDrivingDistanceKM |
0 |
If a driver is going to stay overnight at a location, this location must be at least MinOvernightDrivingDistanceKM from the driver's end location. The end location comes from the resource that this driver is assigned to; normally it will be the resource's depot, or it could refer to the nearest of the allowed depots. |
OvernightCost |
0 |
The cost associated with having to stay out between shifts, typically a hotel night. |
PossibleDays |
"1" |
The days during the scheduling horizon which this driver is available. Multiple days should be separated by a comma, and the first day is set to a 1 . Example: If today is Monday and we set a value of "1,2,4" the plan will be for Tues, Weds and Friday. |
ShiftEarlyStart |
"00:00:00" |
The earliest time in string format HH:mm:ss for the driver to start their shift. |
ShiftLateStart |
"00:00:00" |
The latest time in string format HH:mm:ss for the driver to start their shift. |
Vehicles Key/Value pairs
Vehicles cover all moveable physical assets, a vehicle is made up of a tractor unit and a trailer. In turn the trailer is made up of one or more compartments.
"Vehicles": [{
"Capacity1": 1500,
"CostPerDay": 4.8,
"CostPerKm": 0.1,
"Depot": "2|DEPOT",
"SpeedProfile": "1|SPEED_PROFILE",
"Driver": "250|DRIVER",
"CharacteristicsRequest": "250",
"LegalDrivingDuration": "04:30:00",
"MaximumLoadUnloadTime": "05:00:00",
"EndLatitude": null,
"EndLongitude": null,
"PossibleDays": "1",
"Tag": "250|VEHICLE"
}, {
"Capacity1": 1500,
"CostPerDay": 4.8,
"CostPerKm": 0.1,
"Depot": "2|DEPOT",
"SpeedProfile": "1|SPEED_PROFILE",
"Driver": "251|DRIVER",
"CharacteristicsRequest": "251",
"LegalDrivingDuration": "04:30:00",
"MaximumLoadUnloadTime": "05:00:00",
"EndLatitude": null,
"EndLongitude": null,
"PossibleDays": "1",
"Tag": "251|VEHICLE"
}
]
Key | Default value | Value description |
---|---|---|
Tag |
mandatory |
Unique name for this Vehicle/trailer/tractor within the run of the algorithm. |
Driver |
mandatory |
The Tag of the driver that is allocated to drive this vehicle/Tractor. |
Depot |
mandatory |
The Tag of the depot that this vehicle/tractor starts and finishes at. |
Compartments |
null |
The list of compartments that make up this trailer. |
StartLatitude |
null |
The start location latitude of the vehicle. If left empty, the vehicle starts from the associated depot. When OpenStart is on the vehicle starts from its first job request. |
StartLongitude |
null |
The start location longitude of the vehicle. If left empty, the vehicle starts from the associated depot. When OpenStart is on the vehicle starts from its first job request. |
EndLatitude |
null |
The end location longitude of the vehicle. If left empty, the vehicle finishes at the associated depot. When OpenEnd is on the vehicle finishes at its last job request. |
EndLongitude |
null |
The end location longitude of the vehicle. If left empty, the vehicle finishes at the associated depot. When OpenEnd is on the vehicle finishes at its last job request. |
CostPerKm |
0 |
The cost per KM for running the Vehicle/Tractor. |
CostPerDay |
0 |
This is the cost incurred if the vehicle/tractor is used in a given day, even if it is only used for a single minute. |
CostPerDayOfNonUse |
0 |
This is the cost incurred if the vehicle/tractor is not used in a given day. |
StartTime |
"00:00:00" |
The start time of the vehicle in a string format HH:mm:ss . |
MaximumWorkingTime |
23:59:59 |
A string time interval with the format HH:mm:ss which represents maximum time that the vehicle can work. |
LegalDrivingDuration |
"04:30:00" |
Sets the legal maximum driving time allowed before a breaks must be taken. |
LegalRestDuration |
"00:30:00" |
Sets the legal break required once the maximum driving time allowed before a breaks must be taken. |
MinRestDuration |
"00:15:00" |
Sets the minimum length of time that a legal break can be so that waiting times lunch breaks can be included a breaks from driving. |
PossibleDays |
"1" |
The days during the scheduling horizon which this Vehicle/tractor/trailer is available. Multiple days should be separated by a comma, and the first day is set a 1 . |
CharacteristicsRequest |
null |
Characteristics that need to be matched against the request characteristics to detect suitability for vehicle/Tractor/Trailer. This is a comma separated string, e.g. CAT1,CAT2 . |
HandlingTimePerUnit |
00:00:00 |
This is used in conjunction with request service times and depot loading times. |
UnloadAfterShift |
false |
indicates whether the unloading is done outside of the drivers working time. |
PreLoad |
false |
indicates whether the loading is done outside of the drivers working time. |
DepotLoadingTime |
00:00:00 |
Set a fixed depot loading time for this vehicle, this is a time interval using the string format HH:mm:ss . |
CarryingWeight |
null |
The maximum carrying weight over all the compartments in the trailer. |
Backhaul |
false |
Indicates whether the vehicle/trailer needs to be empty of deliveries before any collections can be made. |
SuppressDepotReload |
false |
Set to true it means the vehicle can not complete a depot reload during the shift. |
MaximumLoadUnloadTime |
"10:00:00" |
The upper limit to depot time the time at depot is the minimum of this and the fixed loading/unloading times with the variable ones as well. |
OpenStart |
false |
true or false to define whether the vehicle can start from the location of first job it is servicing. |
OpenEnd |
false |
true or false to define whether the vehicle can finish at the location of the last job it is servicing. |
Capacity1 |
0 |
Specify a capacity value for the vehicle, this can be width, weight, volume, etc. |
Capacity2 |
0 |
Specify a capacity value for the vehicle, this can be weight, volume, etc. |
Capacity3 |
0 |
Specify a capacity value for the vehicle, this can be weight, volume, etc. |
Capacity4 |
0 |
Specify a capacity value for the vehicle, this can be weight, volume, etc. |
SpeedProfile |
null |
Defines a speed profile associated with this vehicle, if not specified the default speed profile is used. |
Compartments Key/Value pairs
The compartment is simply a separate section within the trailer, one open trailer simply has one compartment. A fuel distribution truck could have many different compartments. There is no limit to the number of compartments; it depends on the vehicle. Each compartment has capacity dimensions and the number of dimensions used is definable.
For example we may choose to map maximum (width 3.4m, length 15m, height 4.5m, weight 5000 kg) onto capacity1, capacity2, capacity3 and capacity4 respectively. Capacity1 being width, Capacity2 being length and so on.
"Compartments": [{
"Capacity1": 3.4,
"Capacity2": 15,
"Capacity3": 4.5,
"Capacity4": 5000
}]
Equally we may simply map Capacity1 to volume (litres) and not use the other dimensions; this would be ideal for liquids such as fuels. This is an example of how to specify two compartments with 1000 litres of volume:
"Compartments": [{
"Capacity1": 1000
}, {
"Capacity1": 1000
}
]
All constraints for each compartment will need to be satisfied. So for example if we map (width, length, height, weight) to capacity1..4, the requested (parcel) must satisy each capacity dimension to fit on the truck.
Key | Default value | Value Description |
---|---|---|
Capacity1 |
0 |
The capacity is used a limiting factor of Quantity1 in requests, e.g. 1000 . If we have defined Compartments we must have at least 1 capacity defined. |
Capacity2 |
0 |
The capacity is used a limiting factor of Quantity2 in requests, e.g. 1000 . |
Capacity3 |
0 |
The capacity is used a limiting factor of Quantity3 in requests, e.g. 1000 . |
Capacity4 |
0 |
The capacity is used a limiting factor of Quantity4 in requests, e.g. 1000 . |
PhohibitedType |
null |
This Request.StockType can not be placed in this compartment, e.g. "DIESEL" . |
Requests Key/Value pairs
In order to complete a plan a list of requests need to be added to the scheduler. There are many options that can be used within the process trying to replicate most of the scenarios where this could be required.
"Requests": [{
"Service": 1,
"Longitude": 0.3166651,
"Latitude": 51.6003284,
"FixedVisitDuration": "00:04:00",
"Tag": "268887-ORDER",
"Quantity1": 49.38,
"TimeWindows": "06:00:00,18:00:00",
"PossibleVisitDays": "1",
"TractorCharacteristics": "260",
"AdditionalTag": "1,260659179_CM133RZ_THORNDONCOUNTRYPARK,1,,0",
"RevenueIncome": 1000
}, {
"Service": 1,
"Longitude": 0.2998903,
"Latitude": 51.615578,
"FixedVisitDuration": "00:04:00",
"Tag": "269874-ORDER",
"Quantity1": 3.3,
"TimeWindows": "06:00:00,18:00:00",
"PossibleVisitDays": "1",
"TractorCharacteristics": "260",
"AdditionalTag": "1,260805221_CM144LX_KINGSHOUSE,1,,0",
"RevenueIncome": 1000
}
]
Key | Default value | Value description |
---|---|---|
Tag |
mandatory |
The Unique reference for this item (unique amongst Depot, Request, Driver, Vehicle, Tractor and Trailer objects). |
AdditionalTag |
null |
It has the following format {1/0},<TAG_ID>,<SEQ_NO>,<VEH_TAG>,{1/0} , where <TAG_ID> is a unique string which can be used to tag two or more job requests together, <SEQ_NO> is an integer represents the run order for these jobs requests, and <VEH_TAG> is preserved to specify the carrying vehicle (This is not implemeted yet, please leave it empty). Thus, AdditionalTag does many things: 1. links collections and deliveries together, 2. sequences a complete days work on the same vehicle, 3. links work to a specific vehicle e.g. #1,TEXT1,#2,TEXT2,#3 #1 (0 ,1 ) 0 =other orders can be placed in between the linked ones 1 =cannot. TEXT1 = the linking text all orders with the same text are linked #2 (0 , n ) = sequences orders must be visited in. TEXT2 = this is not implemented yet and must be empty, this is preserved for future to specify vehicle Tag that must service the request, empty string means any vehicle can do the request. #3(0 , 1 ) 0 = not the same product (collection and delivery order doesn't matter), 1 = same product (collection then delivery) |
Latitude |
mandatory |
The Latitude of the job request location. |
Longitude |
mandatory |
The Longitude of the job request location. |
TractorCharacteristics |
null |
Characteristics which are matched against Tractor object to ensure it can service this request. Multiple characteristics need to be separated by a comma. |
TrailerCharacteristics |
null |
Characteristics which are matched against Trailer object to ensure it can service this request. Multiple characteristics need to be separated by a comma. |
DriverCharacteristics |
null |
Characteristics which are matched against Driver object to ensure it can service this request. Multiple characteristics need to be separated by a comma. |
DepotCharacteristics |
null |
Characteristics which are matched against Depot object to ensure they can service this request. Multiple characteristics need to be separated by a comma. |
MatchAllTractor |
false |
Set true to indicate that all characteristics of the request need to be matched by the tractor. |
MatchAllTrailer |
false |
Set true to indicate that all characteristics of the request need to be matched by the trailer. |
MatchAllDriver |
false |
Set true to indicate that all characteristics of the request need to be matched by the driver. |
MatchAllDepot |
false |
Set true to indicate that all characteristics of the request need to be matched by the depot. |
ProhibitedStock |
null |
Any products of type A cannot be planned on the same trip as this order. |
Quantity1 |
0 |
A quantity that is measured against the Capacity1 of the vehicle. |
Quantity2 |
0 |
A quantity that is measured against the Capacity2 of the vehicle. |
Quantity3 |
0 |
A quantity that is measured against the Capacity3 of the vehicle. |
Quantity4 |
0 |
A quantity that is measured against the Capacity4 of the vehicle. |
FixedVisitDuration |
00:00:00 |
This indicates how long the vehicle will remain on site at the request location, can be used alone or in conjunction with the loading time per unit, meaning you can have a paper work time and a physical loading time. Expected in the form of "hh:mm:ss" e.g. "00:05:00" . |
UnitQuantity |
20 |
The amount of quantity used in conjunction with LoadTimePerUnit . |
LoadTimePerUnit |
00:00:00 |
Average amount of time required at the location to complete all or part f the service, used in conjunction with fixed visit duration. |
PossibleVisitDays |
mandatory |
The days during the scheduling horizon which this request can be serviced on, if left as null all days are acceptable. Multiple days should be separated by a comma, and the first day is set a 1 . e.g. "1,2,3" . |
RevenueIncome |
0 |
A cost implication to not completing this request. |
Service |
0 |
indicates whether as request is a collection or a delivery. 0 means Collection , 1 is Delivery and 2 is visit . |
TransportSeparately |
false |
This indicates with the stock for this request needs to travel in its own compartment in the trailer. |
StockType |
null |
A type of product used for determining which compartments can do what. |
TimeWindows |
null |
The time windows available on every day for this request to be serviced. Expected in the form 08:00,12:00,13:00,17:00 would represent two windows 8am-12pm and 1pm-5pm. |
CanSplitOverCompartment |
false |
The goods do not need to transported in the same compartment and can be split over compartments in order to ensure good trailer utilisation. It indicates that this order is made up of small objects which can be spread over different compartments on the same trailer. |
Weight |
0 |
the weight of the order to determine that the carrying wait of the trailer is not broken. |
Speed Profiles Key/Value pairs
The speed profile is used to apply various speeds to resources, each resource can have multiple speed profiles for different times of the day. This method applies a generic cross fleet speed profile.
There is a default speed profile - although this is likely to be faster than most fleets would require.
"SpeedProfiles": [{
"Catergory1KPH": 80,
"Catergory2KPH": 56,
"Catergory3KPH": 48,
"Catergory4KPH": 45,
"Catergory5KPH": 35,
"Catergory6KPH": 29,
"Catergory7KPH": 10,
"Tag": "1|SPEED_PROFILE"
}
]
Key | Default value | Value description |
---|---|---|
Tag |
The speed profile ID, this can be used to assign a customised speed profile for a vehicle. | |
Catergory1KPH |
120 |
This property allows the value to be get or set for the speed in KMH, for the fastest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory2KPH |
95 |
This property allows the value to be get or set for the speed in KMH, for the next fastest type of roads2. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory3KPH |
80 |
This property allows the value to be get or set for the speed in KMH, for the next fastest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory4KPH |
60 |
This property allows the value to be get or set for the speed in KMH, for the next fastest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory5KPH |
40 |
This property allows the value to be get or set for the speed in KMH, for the next fastest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory6KPH |
20 |
This property allows the value to be get or set for the speed in KMH, for the next fastest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Catergory7KPH |
8 |
This property allows the value to be get or set for the speed in KMH, for the slowest type of roads. If a value less than 0 or greater than 200 is used it will not be accepted. |
Part 2: Polling for Result
Given a request ID the end user need to keep polling the service until the result plan is computed. Depending on the size of the problem this might take hours.
HTTP Request
GET http://[API_END_POINT]/<RequestId>
URL Parameters
Parameter | Description |
---|---|
RequestId |
The ID of request which is sent earlier. This is the tm8rmscheduler service response to the input request in part 1. |
import requests
r = requests.get("http://[API_END_POINT]/a802a998-e3c1-48f9-a8ca-619888f4adf0")
if r.status_code == 200:
print(r.text)
curl "http://[API_END_POINT]/a802a998-e3c1-48f9-a8ca-619888f4adf0"
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200)
console.log(JSON.stringify(this));
}
};
xhttp.open("GET", "http://[API_END_POINT]/a802a998-e3c1-48f9-a8ca-619888f4adf0", true);
xhttp.send();
The response from the server is empty string if the result is not ready yet, and a full plan when the result is ready:
{
"Cost": 154.75249428200416,
"Miles": 36.112359750100978,
"RequestId": "a802a998-e3c1-48f9-a8ca-619888f4adf0",
"UnPlanned": 0,
"UnplannedRequests": [],
"Data": [
{
"Day": 1,
"Duration": 0.0,
"Eta": 360.0,
"Miles": 0.0,
"RunNo": "0",
"RunOrder": 0,
"Tag": null,
"Task": "TSKSHIFTSTART",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 0.0,
"Eta": 360.0,
"Miles": 0.0,
"RunNo": "0",
"RunOrder": 1,
"Tag": "2|DEPOT",
"Task": "TSKBRIEFING",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 22.370801254603453,
"Eta": 360.0,
"Miles": 18.587216473612767,
"RunNo": "0",
"RunOrder": 2,
"Tag": null,
"Task": "TSKTRAVEL",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 4.0,
"Eta": 382.37080125460346,
"Miles": 18.587216473612767,
"RunNo": "0",
"RunOrder": 3,
"Tag": "268887|ORDER",
"Task": "TSKDELIVERY",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 20.0471174513327,
"Eta": 386.37080125460346,
"Miles": 17.525143276488208,
"RunNo": "0",
"RunOrder": 4,
"Tag": null,
"Task": "TSKTRAVEL",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 0.0,
"Eta": 406.41791870593619,
"Miles": 36.112359750100978,
"RunNo": "0",
"RunOrder": 5,
"Tag": "2|DEPOT",
"Task": "TSKDEBRIEFING",
"Vehicle": "250|VEHICLE"
},
{
"Day": 1,
"Duration": 0.0,
"Eta": 406.41791870593619,
"Miles": 36.112359750100978,
"RunNo": "0",
"RunOrder": 6,
"Tag": null,
"Task": "TSKSHIFTEND",
"Vehicle": "250|VEHICLE"
}
]
}
V1 JSON Response
URL Parameters
The server shall response with empty string message if the plan result is not ready yet.
HTTP Response Key/Value pairs:
Key | Value description |
---|---|
Cost |
The total cost of the plan. |
Miles |
The total mileage of the plan. |
RequestId |
The request ID generated when the input is posted to the server. |
UnPlanned |
Total number of unplanned job requests |
UnplannedRequests |
List of unplanned job requests Tags. |
Data |
This is a list of items represents the actual itineraries of the plan. Please refer to Data Key/Value pairs for more info. |
Data Key/Value pairs
Key | Value description |
---|---|
Day |
The day of the action |
Duration |
the duration of the action in minutes |
Eta |
The expected time of the arrival of the action, this is represented as total number of minutes passed since the midnight of the Day . |
Miles |
Accumulative mileage when this action takes place. |
RunNo |
The number of itinerary, this is an integer representing the actual itineraries |
RunOrder |
The order of the action inside the itinerary, this represents the order which itinerary actions should take place by. |
Tag |
The ID of the object involved in the action. This can be a depot when action is Briefing or Loading and a job request Tag ID when the action is Collection or Delievery for example. |
Task |
The action type which can be one of the following: TSKTRAVEL , TSKSERVICE , TSKDELIVERY , TSKCOLLECTION , TSKBRIEFING , TSKDEBRIEFING , TSKLUNCH , TSKDRIVINGBREAK , TSKDEPOTLOAD , TSKWAITING , TSKNIGHTOUTSTOP , TSKNIGHTOUTSTART , TSKSHIFTSTART , TSKSHIFTEND . |
Vehicle |
Represents the vehicle which is doing the itinerary. |