14 Simulator tool
The ODL Live simulator is available to self-hosting subscribers through the command line interface. It allows you to simulate realtime planning problems, by simulating the evolution of the planning process as new jobs are created, vehicles travel and complete jobs etc. The simulator works by having a simulated time where only those jobs known at the time are considered in the plan, and having simulated vehicles which travel, start and complete jobs. In the simulator the optimiser runs bursts at regular intervals (say for every one minute of simulated time), planning the jobs known and then dispatching stops to the simulated vehicle when the vehicles are close to finishing their current stop. In-between optimiser bursts the simulator will update the state of the vehicles - for example updating their current simulated GPS coordinate or sending stop arrived or completed events to the planner. As the vehicles have a simulated state which is separate to the planner data held by the optimiser, you can even simulate delays in communication between the vehicle and the optimiser server.
As the simulator may perform hundreds or even thousands of optimisation bursts during a single simulator run, running the simulator can take considerable time. Ideally you should only run the simulator on smaller problems if possible (e.g. < 200 live jobs at once), although if you leave it running longer (e.g. overnight) you can run it on larger problems. If you have sufficient CPUs and memory on your computer, you can run multiple command line simulations in-parallel at once, by starting the command line multiple times. If you’re looking to get statistics from the simulator run (e.g. average travel time in a ‘what-if’ scenario), especially if you’re modelling uncertainty in travel time or stop duration, you will need to run the same simulator model multiple times to get decent statistics as random fluctuations will occur per simulator run.
14.1 Walkthrough
The simulator uses the command line tool which is also used by the traffic learner. To start using the simulator, first work through the section on setting up the command line. As per this section you should (1) create a new directory on your computer, (2) copy the file odl.live.commandline.jar into it and (3) open a command line prompt in this directory. Then try running the command line help:
java -Xmx4G -jar odl.live.commandline.jar -help
You should see a list of the available simulator (and other) commands. Simulator commands begin with ‘sim’.
14.1.1 Creating the simulation case file
The simulator takes a JSON simulation case file as input. The simulation case contains the sort of objects you’re already familiar with from the JSON model - e.g. jobs, vehicles - as well as some new fields and objects required by the simulation. In this walkthrough, we’ll use a simulation case that is created by a demo mode embedded within the simulator. In the command prompt you opened before, enter the following command to create this demo simulation case file:
java -Xmx4G -jar odl.live.commandline.jar -simCreateDemoData1 demosimcase.json
A simulation case file called demosimcase.json should now be in your folder. The simulation case file is a JSON with the following structure:
{
"customers" : [
... array of customers, only used if testing planning queries in the sim
],
"model" : {
... a normal ODL Live JSON model
},
"simParams" : {
"vehicleEvents" : {
... parameters to do with vehicle events in the sim
},
"burstOptimisation" : {
... parameters defining when the optimiser runs in the sim
},
"randomisation" : {
... parameters to do with randomising times
},
"times" : {
... parameters defining when the sim runs
},
"reporting" : {
... parameters defining what data is recorded during the sim
}
}
}
14.1.1.1 SimParams object in the simulation case
You are advised to set the vehicleEvents object JSON in simParams to the values from the example JSON:
"vehicleEvents" : {
"millisecondsFrequencyVehicleSync" : 60000,
"vehicleSyncSuccessProbablity" : 1.0,
"vehicleGPSTraces" : true,
"stopArrivals" : true
}
This defines that the simulated vehicle will sync with the simulated optimiser server every simulated minute (i.e. 60,000 milliseconds). During a sync, the vehicle’s GPS location will be updated within the optimiser, new arrived and completed events will be sent and any new dispatches will be received from the optimiser. The sync process allows us to model that communication between a mobile worker (e.g. driver, engineer) and the central server is not instantaneous. For example, there may be a delay whilst their driver’s app on their phone syncs with the central server. You are advised to set vehicleSyncSuccessProbablity to 1.0. The sync probability can model communications delays due to - for example - lack of mobile phone coverage. Setting it to < 1 means that sync events will sometimes fail and communication delays will occur.
The burstOptimisation object defines how and when the optimiser runs. See the following example from the demo:
"burstOptimisation" : {
"burstBudget" : {
"maxMillis" : 9223372036854775807,
"minItPerSlot" : 25,
"minItPerSlotWithoutImprovement" : 0,
"maxItPerSlot" : 25,
"maxTotalIt" : 2147483647,
"minTotalIt" : 0
},
"nbBurstsToRunAtStart" : 10,
"startOptNMillisBeforeNextEvent" : 3600000,
"millisBetweenBursts" : 1200000
},
The large numbers set to maxMillis and maxTotalIt can be ignored, these are just set to the maximum values for int and long numbers of the java platform and are therefore effectively turned off. The relevant fields to understand from this JSON are:
minItPerSlot. This is the minimum number of iterations that will be done in a single burst, for each optimiser ‘slot’. By default the optimiser does several searches in-parallel (these are called ‘slots’), although the default configuration turns this off for larger problems. For smaller problems you would therefore normally have 3 slots running in-parallel and for larger, only 1 slot.
maxItPerSlot. The maximum number of iterations an optimiser slot will be perform in a single burst. As we set both minItPerSlot and maxItPerSlot to 25, each slot will run exactly 25 iterations on each burst.
nbBurstsToRunAtStart. The number of optimisation bursts to run at the start of the simulation. If you have a significant number of jobs which are known at the start of the simulation, this allows you to run a number of bursts at the very beginning to ensure you start off with a good solution, which you then keep updated by running further bursts during the sim every once-in-a-while.
startOptNMillisBeforeNextEvent. If there’s no simulator events for a while (e.g. the simulated time is 3am and nothing happens until 8am), this allows the simulator to fast-forward in-time without running the optimiser (making the simulation run quicker for multi-day problems). If startOptNMillisBeforeNextEvent = 3600000 than as 3,600,000 milliseconds is equal to 1 hour, if no simulated events are due for at least another hour, the simulator will fast-forward until an hour before the next simulated events. Simulated events are changes in state such as a vehicle arriving at a job, a new job being created etc.
millisBetweenBursts. The milliseconds in simulated time between optimisation bursts. If millisBetweenBursts = 1, 200, 000 then the optimiser will run every 20 minutes. For realistic modelling, you are advised to run the optimiser at least every few minutes. To make the demo run quickly, we have set this number to be too high; you should use a smaller value for your own modelling.
The randomisation object allows you to randomise travel time and stop duration, to model their uncertainty. In the demo data, randomisation if turned off. See later section for details on setting up randomisation.
The times object defines when the simulation will run until. Consider the example object from the demo simulation case:
"times" : {
"simulationEndTime" : "2019-02-28T00:00",
"millisecondsStartBeforeFirstEvent" : 600000
}
This specifies the simulation should end on 2019-02-28T00:00. If you omitted the simulationEndTime field, the simulated would instead keep running until it decided there was nothing else left to do - e.g. no pending jobs etc. Depending on your modelling setup - for example if you’re modelling a dummy artificially-long final day - the simulator may not stop simulating without an explicit simulationEndTime being set.
millisecondsStartBeforeFirstEvent defined how long before the first simulation event the simulator should start running. You are advised to leave this set at 600000. If millisecondsStartBeforeFirstEvent is larger than startOptNMillisBeforeNextEvent, the simulator may still fast-forward until startOptNMillisBeforeNextEvent.
The reporting object contains some options for additional data that can be included in the output JSON file after the simulation runs. In our example, we have these turned off:
"reporting" : {
"savePlansOnEachBurst" : false,
"savePlansOnEachChange" : false,
"logGPSEvents" : false
}
If savePlansOnEachBurst is true, a plan object (containing all planned routes) will be saved on each optimisation burst. If savePlansOnEachChange is true, the plan object (again containing all planned routes) will be saved whenever one or more stops is reassigned in the optimiser. These options can result in a very large JSON file, so use them with caution. logGPSEvents is also turned off. When logGPSEvents is false the simulator will still model GPS events but it will not report them in the list of simulated events after running the optimiser (it is best not to output them they’re generally not very informative and there tends to be a lot of them).
There is a further reporting option (not shown in the JSON), which is useful for debugging but can also result in very large files. You can set a field called saveDataSnapshotsEveryNMillis to save both the model and optimiser plan every X simulated milliseconds. The model will be a ‘snapshot’ at the current simulated time, so it only contains those jobs known at the time, the simulated arrivals and completions known at the time, etc.
14.1.1.2 Model object in the simulation case file
The model object is identical to the model objects you’re already using, except it can contain a couple of extra fields used only by the simulator.
14.1.1.2.1 Job object setup
The most important new field in the model is the createdTime field on a job JSON:
{
"stops" : [ {
....
],
"_id" : "High22",
"createdTime" : "2019-02-26T10:16:45",
}
If this is not set, the job will be created when the simulation starts running, otherwise it will be created during the simulation.
The createdTime allows you to model several different versions of a job, which change as the simulated time changes. If you do this, for each version the job id must be the same across all versions and the stop ids should be the same too. If you have a job included multiple times in the input model, then provided the job id is the same, these versions will be created in order of the createdTime field and overwrite each other. The second version of the job will simply overwrite (i.e. totally replace) the first version of the job when it’s created, and so-on for the third version, etc.
We demonstrate this in the following JSON array of job objects:
[
{
"_id": "High1",
"properties": {
"MyNote": "This version is created when sim starts"
},
"stops": [
...
]
},
{
"_id": "High1",
"properties": {
"MyNote": "This version replaces the 1st version"
},
"stops": [
...
],
"createdTime": "2019-02-26T00:00"
},
{
"_id": "High1",
"properties": {
"MyNote": "This version replaces the 2nd version"
},
"stops": [
....
],
"createdTime": "2019-02-27T00:00"
}
]
The first version of the job has no createdTime and will be created before the simulator starts. The second version replaces this first version at 2019-02-26T00:00 and the 3rd version replaces the second at 2019-02-26T00:00. The properties object can be used to store your own data (e.g. notes etc.) so here we’ve stored a string under our own field MyNote. When you run the demo, if you set the reporting to create model snapshots every hour (for example), then in each model snapshot you will see only one version of the job with id High1, and it will have the correct version of properties.MyNote for the simulated time of the snapshot.
14.1.1.2.2 Model configuration setup
The model.configuration.distances object in the demo simulation case is not set to use road network distances. If you want to use road network distances, copy the distances object over from your production model distances object, ensuring you update the path to the location of the road network data on the computer you’re using. If you update the path remember that on Windows computers in the JSON the directory separator should be ‘\\’ not ‘\’ as JSON treats ‘\’ as a special character:
"graphDirectory": "C:\\ODLLive\\RoadData\\UK-graph"
There are two other fields in the model configuration you should be aware when running simulations, dispatchBufferMilliseconds and dispatchIfWaitingTimeLessThanMillis.
model.configuration.dispatchBufferMilliseconds
When the simulator runs, the dispatch for the next planned stop will
be sent from the planner to the simulated vehicle when the vehicle is
within dispatchBufferMilliseconds of needing to travel to
this next stop. For example if dispatchBufferMilliseconds
is set to 600,000 millis = 10 minutes, then
10 minutes before the planner thinks the vehicle is due to finish its
current job, it will be sent a new job. This allows jobs to be
‘spoon-fed’ to the vehicle. Be aware that as dispatches are only
calculated in the optimisation burst, you should ensure that the
simulated time between bursts is significantly smaller than
dispatchBufferMilliseconds (e.g. run optimiser every 5
simulated minutes and set dispatchBufferMilliseconds equal
to 20 minutes). If the time between bursts is similar to or larger than
dispatchBufferMilliseconds, your simulated vehicle may not
receive the next dispatch before it finishes its last stop, and may
therefore wait around for more work when it should already be driving to
a job.
model.configuration.dispatchIfWaitingTimeLessThanMillis
A dispatch will not be sent from the planner to the simulated vehicle
until the estimated time spent waiting at the next stop for its
openTime is less than
dispatchIfWaitingTimeLessThanMillis.
14.1.2 Running the simulation case file
Do not run the ODL Live simulator on your production server. The simulator uses significant CPU and RAM resources and may effect your live system if you run it on the same computer.
When you run the simulator, there are 3 options for outputting information from the simulation:
CSV. This output a CSV file with a list of all events that happened in the simulation.
JSON. This outputs a JSON file containing the events in JSON form and other data.
Zip. This includes both the CSV and JSON, in a zip file. It also includes an additional CSV file that contains summaries of the travel done for each vehicle. The output files can be large so pre-zipping them can be useful.
We will run the CSV option. Enter the following command into the command prompt:
java -Xmx4G -jar odl.live.commandline.jar -simoutputcsv -simrun demosimcase.json events.csv
Here we are telling java it can run with a maximum of 4GB memory (-Xmx4G). For larger problems or large road network graph files you may need to increase this and/or change the global distances cache settings (see commands simdistcachetargbytes and simdistcachetrigbytes in the list of simulator commands and the self-hosting guide document). We then telling the simulator to output to CSV (the command -simoutputcsv) and then to run the simulator (simrun) with the input file demosimcase.json and writing to the output file events.csv.
Once you’ve told the simulator to run, you should see the simulator printing out details of each event as it runs. As the demo data is small, with bursts set only every 20 simulated minutes and only 25 iterations per burst, the simulator runs in 10 seconds or so.
The first events are as follows:
Mon 03:17:44: processing event Add record for vehicle Veh1Day1 to planner
Mon 03:17:44: processing event Add record for vehicle Veh1Day2 to planner
Mon 03:17:44: processing event Add record for vehicle Veh1Day3 to planner
Mon 03:17:44: processing event Add record for vehicle Veh1Day4 to planner
Mon 03:17:44: processing event Add record for job High1 to planner
Mon 03:17:44: processing event Add record for job Low24 to planner
Mon 03:17:44: processing event Add record for job High32 to planner
Mon 03:17:44: processing event Add record for job Low42 to planner
These events occur before the simulation starts to run properly. It is adding four vehicles to the simulator, which are actually identical except they run on four different days (day1, …, day4). As the simulator has records for multiple days, when it is simulating day 1, it is also thinking about the routes for days 2, 3 and 4 as well. As a result when simulating day 1, it will also be grouping stops intelligently for day 2, day 3 etc.
The simulator then adds four jobs - High1, Low24 etc.. - which don’t have createdTime fields and are therefore assumed to be created before the simulator starts calling the optimiser. In this scenario we have two sorts of jobs - high priority jobs and low priority jobs.
The simulator then runs its initial optimisation bursts before starting the simulation proper:
Mon 03:17:44: Initial opt. burst 1/10, cost=247.541 routes=2 planStops=4 notLoadJobs=0
Mon 03:17:44: Initial opt. burst 2/10, cost=247.541 routes=2 planStops=4 notLoadJobs=0
...
Mon 03:17:44: Initial opt. burst 10/10, cost=247.541 routes=2 planStops=4 notLoadJobs=0
As the demo problem is very small - initially only 4 jobs - the very first burst finds the best solution (cost=247.541 routes=2 planStops=4 notLoadJobs=0) and does not find a better solution on subsequent bursts. Ideally you should set your number of initial bursts such that the cost value and notLoadJobs do not change for the last 5 or 10 bursts before the simulation starts. This indicates you have a stable solution when the simulator starts.
At 03:27:44 simulated time the simulator than has its first real event - it adds the new job with id High1 at it’s createdTime, so now we have 5 planned jobs:
Mon 03:27:44: processing event Add record for job High11 to planner
The createdTime of this job actually determined the start time of the simulator, as it’s the first ‘in-simulation’ event and so the creation of vehicles and jobs at the very start were performed 10 minutes before it (as per the millisecondsStartBeforeFirstEvent setting). The simulator then fast-forwards as it sees there’s no more events for a while, and then runs some more optimisation bursts:
Mon 03:27:44: Fast-forwarding from Mon 03:27:44 to Mon 04:19:54
Mon 04:19:54: Opt. burst, cost=687.21 routes=2 planStops=5 notLoadJobs=0
Mon 04:39:54: Opt. burst, cost=682.698 routes=2 planStops=5 notLoadJobs=0
Next, another job is added:
Mon 05:19:54: processing event Add record for job High18 to planner
At 8am the single vehicle starts working (the demo only has a single vehicle working per day) and we get another event:
Mon 08:00:00: processing event Start vehicle Veh1Day1
Although this logic is not viewable directly in the console output, internally to the simulator the vehicle will actually wait at the depot for a while as its first stop doesn’t open until 9am (as defined in the stop’s openTime). By default when running the simulator the optimiser will dispatch a stop to a vehicle such that it arrives no more than 20 minutes earlier than the opening time of the stop (this behaviour is set in the model.configuration.dispatchIfWaitingTimeLessThanMillis field). Before this dispatch is received, the vehicle will sit at its current location waiting for new dispatched stops.
Next we see more events printed when (1) the vehicle arrives at its first stop, (2) the vehicle finishes waiting for the stop to open, (3) the vehicle finishes serving the stop and (4) the vehicle finishes travelling to its next stop:
Mon 08:42:11: processing event Vehicle Veh1Day1 completes Travelling to High11
Mon 09:00:00: processing event Vehicle Veh1Day1 completes Waiting for open time
Mon 11:00:00: processing event Vehicle Veh1Day1 completes Servicing High11
Mon 11:03:15: processing event Vehicle Veh1Day1 completes Travelling to High1
The vehicle continues to serve jobs throughout the day, serving the high priority jobs first (called ‘HighXX’) and only serving the low priority jobs (called ‘LowXX’) when either there’s no high priority jobs left or it can fit in a low priority job on the way home, but can’t fit in a high priority job.
Currently in the simulator, the planner will take account of the vehicle’s required return journey back to base, and will not schedule any jobs which would prevent the vehicle returning before it’s closeTime, however the back-to-base movement is not simulated. No statistics are therefore available through the simulator related to the back-to-base-movement. Instead the simulator (but not the planner) assumes that once a vehicle finishes a stop, if no next stop is pending, the vehicle stays at the location of the current stop.
We set our vehicle to have a hard closeTime of 19:00, so the simulation stops simulating it at 19:00 and then just after this, the simulator fast-forwards in time until an hour before the next job is added:
Mon 19:01:00: Fast-forwarding from Mon 19:01:00 to Mon 21:16:47
If you don’t have jobs being added during the night (unlike our demo data, where vehicles don’t work overnight but jobs can still be added), then fast-forwarding can save considerable time spent running the simulation as you don’t bother running optimisation bursts overnight. Fast-forwarding will not occur whilst vehicles are syncing though, and only reaching the hard closeTime will stop the vehicle syncing.
The demo data contains several versions of each job. At midnight, we replace the versions of the current known jobs with their next versions according to the jobs’ createdTime fields:
Tue 00:00:00: processing event Add record for job High18 to planner
Tue 00:00:00: processing event Add record for job Low35 to planner
Tue 00:00:00: processing event Add record for job Low8 to planner
....
Jobs that have been completed are also replaced, however as they have already been served the new job versions will just be ignored by the optimiser (providing the stop ids are identical in the new version).
At 8am on the next day, the vehicle (corresponding to a different vehicle record), starts again:
Tue 08:00:00: processing event Start vehicle Veh1Day2
Again the vehicle serves more jobs, high priority first. It then finishes and starts again for a 3rd day. When we hit the simulation end time (defined in the simulation case parameters) on the 3rd day, we output the CSV file:
Writing CSV to C:\mydirectory\events.csv
14.1.3 Reading the output CSV file
The output CSV file stores details of the events which happened in the simulation and can be used as a data source for further analysis of a run.
Each event has a type, which is pretty self-explanatory (e.g. “VEHICLE_STARTS_WORK”), together with a time, associated vehicle, job and stop id, latitude and longitude of the vehicle when the event occurred and travel statistics. Here are some example of important events from the output CSV:
type,vehicleId,jobId,stopId,customerId,time,latitude,longitude,message,travelSeconds,travelMetres
"VEHICLE_STARTS_WORK","Veh1Day1",,,,2019-02-25T08:00,,,,0.0,0.0
"VEHICLE_STARTS_WAITING_FOR_JOBS","Veh1Day1",,,,2019-02-25T08:00,52.4776,-1.8942,,0.0,0.0
"PLANNER_DISPATCHED_STOP","Veh1Day1","High11","High11",,2019-02-25T08:40,,,"Dispatched stop High11 to vehicle Veh1Day1",0.0,0.0
"VEHICLE_RECEIVES_STOP_RECORD","Veh1Day1",,"High11",,2019-02-25T08:40,,,,0.0,0.0
"VEHICLE_STARTS_TRAVELLING_TO_STOP","Veh1Day1",,"High11",,2019-02-25T08:40,52.4776,-1.8942,,0.0,0.0
"VEHICLE_ARRIVES_AT_STOP","Veh1Day1",,"High11",,2019-02-25T08:42:11.888,52.5030348457331,-1.90648304699137,,131.888,2947.9621582031255
"PLANNER_RECEIVES_ARRIVES_AT_STOP","Veh1Day1",,"High11",,2019-02-25T08:42:11.888,,,,0.0,0.0
"VEHICLE_STARTS_SERVICING_STOP","Veh1Day1",,"High11",,2019-02-25T09:00,52.5030348457331,-1.90648304699137,,0.0,0.0
"PLANNER_DISPATCHED_STOP","Veh1Day1","High1","High1",,2019-02-25T11:00,,,"Dispatched stop High1 to vehicle Veh1Day1",0.0,0.0
"VEHICLE_COMPLETES_STOP","Veh1Day1",,"High11",,2019-02-25T11:00,52.5030348457331,-1.90648304699137,,0.0,0.0
"PLANNER_RECEIVES_COMPLETES_STOP","Veh1Day1",,"High11",,2019-02-25T11:00,,,,0.0,0.0
Events types starting ‘VEHICLE_’ refer to something the simulated vehicle did whereas event types starting ‘PLANNER_” refer to something the planner (a.k.a. the simulated ODL Live optimiser server) did. We see events when the planner or vehicle sends or receives information - for example a new dispatch record is created in the planner in the ’PLANNER_DISPATCHED_STOP’ event and received by the vehicle in the ‘VEHICLE_RECEIVES_STOP_RECORD’ event.
14.1.3.1 VEHICLE_ARRIVES_AT_STOP event
90% of analysis work you do will just use the event type VEHICLE_ARRIVES_AT_STOP. Event type VEHICLE_ARRIVES_AT_STOP is an event which happens when (surprisingly enough), the vehicle arrives at a stop. It has the arrival time in the time field (e.g. 2019-02-25T08:42:11.888), ids of both the stop and job which owns the stop, the latitude and longitude of the stop and crucially the fields travelSeconds and travelMetres which list the travel time and distance to get to the stop. The very first VEHICLE_ARRIVES_AT_STOP event will therefore have the travel time and distance to get to the first stop from the depot. Also, the sum of all travel times over all VEHICLE_ARRIVES_AT_STOP events will be the total travel time the vehicle did, apart from the return-to-depot journey (for the travel metres field).
14.1.4 Including fields in output filename
The following special strings can be included in the output filename, which are then replaced by the command line when it runs:
%TIMESTAMP%. A timestamp will be added to the output filename.
%MODELID%. The model id from simulationcase.model.id will be added to the filename.
%RANDOMID%. A random id will be added.
Try the following command which uses all three:
java -Xmx4G -jar odl.live.commandline.jar -simoutputcsv -simrun demosimcase.json events_%TIMESTAMP%_%MODELID%_%RANDOMID%.csv
This outputs a file of the form:
events_20190304202120673_UKServiceDemo_m4DHhORf.csv
where:
20190304202120673 is a timestamp - 2019 (year), 03 (month), 04 (day), 20 (hour), 21 (minute-of-hour), 20 (second-of-minute) and 673 (millisecond).
UKServiceDemo is the value of simulationcase.model.id.
m4DHhORf is a random id.
If you’re running the simulator many times with the same input data, this functionality can create different output filenames for each run.
14.1.5 Output to JSON instead
If instead we wanted to output the JSON we would use:
java -Xmx4G -jar odl.live.commandline.jar -simoutputjson -simrun demosimcase.json output.json
The output json is of the form:
{
"events" : [
... list of events which happened (i.e. the csv contents in JSON form)
],
"vehicleSummaries" : [
... list containing a summary for each vehicle
],
"startTime" : "2019-02-25T03:17:44",
"endTime" : "2019-02-27T19:01",
"postSimState" : {
"model" : {
... state of the model when the simulator finished
},
"optimiserState" : {
... state of the optimiser (e.g. plan) when the simulator finished
}
},
"systemStats" : {
... stats related to the operation of the system (e.g. distances cache)
}
}
If you’ve set the simulation reporting parameters to output the evolving plans as well, there is an additional field plansSavedOnEachChange containing a list of plans. Similarly if you’ve set the parameters to regularly output snapshots of the data state (e.g. model etc), there is another extra field dataSnapshots containing a list of data snapshots.
The JSON below is an example element from the vehicleSummaries list:
{
"vehicleId" : "Veh1Day1",
"nbCompleteStops" : 3,
"totalTravelHours" : 0.20739222222222223,
"totalTravelKm" : 16.688266357421874,
"lastDepotReturnTime" : "2019-02-25T15:10:34.791"
}
Note that the movement of the vehicle back to depot will not be simulated unless explicitly turned on (see section on simulated vehicle behaviour). If this return-to-depot movement is not simulated, it will not be included in totalTravelHours or totalTravelKm and lastDepotReturnTime will not be set. lastDepotReturnTime is called lastDepotReturnTime not depotReturnTime as when this logic is activated a vehicle can return to the depot but then be called out again.
14.1.6 Output to zip instead
To output to the zip instead we would use:
java -Xmx4G -jar odl.live.commandline.jar -simoutputzip -simrun demosimcase.json output.zip
The output zip file contains both the csv content in a file called “events.csv” and the JSON in a file called “all.json”. The zile file also contains an additional file called “vehiclesummaries.csv” which has identical content to the vehicleSummaries list in the JSON object except formatted as CSV instead. Zipping the output can shrink the size of the output JSON by 20 times or more.
14.2 Outputting a video
The simulator can output an MP4 video and/or launch a UI panel showing this video when its running. For small to medium sized simulations, running the video (either UI or output video) can slow things down considerably, so you are not advised to run it if you’re running lots of simulations.
The simulation video is more suited for viewing smaller problems with smaller number of live vehicles, as with too many vehicles on-screen it may be difficult to see what’s happening. Using the simulation video you can visualise which stops are dispatched and which stops are planned but not dispatched yet. A bold line is drawn from the current vehicle location to its pending dispatched-but-not-yet-complete stops. A dotted line is then drawn from its last dispatched-but-not-yet-complete stop to its planned (i.e. undispatched) stops. When stops are dispatched, the dotted line to them turns bold.
If you have your directory containing odl.live.commandline.jar setup, then from a command prompt in this directory create the demo simulation case file:
java -Xmx4G -jar odl.live.commandline.jar -simCreateDemoData1 demosimcase.json
Then enter the following command to run it and show the video panel (i.e. UI):
java -Xmx4G -jar odl.live.commandline.jar -simvidpanel true -simoutputcsv -simrun demosimcase.json events.csv
The command simvidpanel must be before simrun or the panel will not show. After a small wait, you should see a frame appear with output similar to:
The following command will run the simulation and output a video to output.mp4 with a frame taken every ten minutes (600000 milliseconds) of simulated time:
java -Xmx4G -jar odl.live.commandline.jar -simvidoutput output.m4p -simvidsimtimemillisperframe 600000 -simoutputcsv -simrun demosimcase.json events.csv
You will need to decide how often in simulated time you want to output video frames, using the command simvidsimtimemillisperframe (see list of simulator commands). You will also need to decide the frames-per-second that the video should play these frames at, which is set with the simvidfps command.
Your computer needs internet access to download the background OpenStreetMap map tiles. The command line uses a default URL to download tiles from (run help command to see this URL, under simvidtileurl). If this free tile service changes you may need to set tiles to download from a different location using the simvidtileurl command (see list of simulator commands). When tiles are downloaded they are stored in a temporary directory on your computer. This directory can be set using the simvidtilecachedir command. If you run help, the command listing for the simvidtilecachedir will tell you the default directory that will be used unless you set a different one.
Note that video frames are not created when vehicles are not working - i.e. if for the current simulation time t there are no vehicles whose open time is after t and close time is before t, no frames will be output. Therefore frames will not be created until the simulated time when vehicles start work and if you have a period (e.g. overnight) when vehicles are not working, the video will skip ahead until they start working again.
14.2.1 Controlling stop and vehicle appearance in the video
By default, the label on the stop takes the first of these fields which is non-null:
stop.simData.appearance.label
stop.name
stop.id
In this following job JSON we have set the label on the stop to be “Hello world!” instead and to use the symbol “PERSON” instead of a circle:
{
"_id": "High1",
"stops": [
{
"type": "SERVICE",
"durationMillis": 7200000,
"coordinate": {
"latitude": 52.4639679393079,
"longitude": -1.89969195960177
},
"simData": {
"appearance": {
"label": "Hello world!",
"symbol" : "PERSON"
}
},
"_id": "High1"
}
]
}
The following symbol types are available and can be set in the stop.simData.appearance.symbol field:
- BIG_TRUCK
- BOX_PACKAGE
- CAR
- CIRCLE
- DIAMOND
- FAST_FOOD
- FAT_STAR
- HEXAGON
- HOUSE
- INVERTED_TRIANGLE
- PENTAGON
- PERSON
- SHOPPING_BAG
- SHOPPING_CART
- SQUARE
- STAR
- TAXI
- TRIANGLE
- TRUCK1
- TRUCK2
Similarly for the vehicle the label takes the first non-null of these:
vehicle.definition.simAppearance.label
vehicle.id
We set the label and symbol for the vehicle in the following JSON:
{
"_id": "Veh1Day1",
"definition": {
"start": {
...
},
"end": {
....
},
"simAppearance": {
"label": "Hello again!",
"symbol" : "TAXI"
}
}
}
An additional field symbolBadge can be set in both vehicle.definition.simAppearance and stop.simData.appearance. Its possible values are:
“AUTO” - a white circle badge is shown beneath the symbol if the symbol is not a basic shape (e.g. circle, square etc).
“NONE” - no badge is shown beneath the symbol.
“WHITE_CIRCLE” - a white circle badge is always shown beneath the symbol.
14.3 Randomising stop duration and travel time
Both the stop time and travel time can be randomised when running the simulation, to simulate their uncertainty. In the object simulationCase.simParams.randomisation, the user can set a minimum and maximum fraction to multiply the stop time and/or travel time by (separate for stop time and travel time). On each run of the simulator, the simulator then chooses a random multiplication fraction with equal probability in-between the minimum and maximum fraction and multiplies the raw time by this fraction. Each run will choose a different value.
If s is the original stop duration, fmin the minimum fraction, fmax the maximum fraction and rand() is a function that generates a random number between 0 and 1, then the new stop duration s′ is defined by:
The same equation applies for travel time. The following simulation case object has a randomisation object which sets the stop duration to be between 0.7 and 1.3 times larger (i.e. between 70% and 130% of original value) and travel time to be between 1.1 and 1.5 of large (e.g. between 110% and 150% of original value). So stop time can be 30% less than or greater than the original value but travel time will be between 10% and 50% greater:
{
"model" : {
....
},
"simParams" : {
"vehicleEvents" : {
....
},
"burstOptimisation" : {
....
},
"randomisation" : {
"stopDurationMultiplierFrac" : {
"min" : 0.7,
"max" : 1.3
},
"travelTimeMultiplierFrac" : {
"min" : 1.1,
"max" : 1.5
}
},
"times" : {
....
},
"reporting" : {
.....
}
}
}
14.4 Simulated vehicle behaviour when waiting for jobs
Simulated vehicles can operate in two modes:
Wait at current location for new jobs. This is the default mode. When a simulated vehicle has no pending stops in its dispatch list, it waits at its current location for new dispatched stops (typically the location of its last job). The optimiser will respect the vehicle’s hard close time (when it needs to return to the depot by). As a result the optimiser won’t dispatch any stop to the vehicle which would mean it can’t return to the end depot by its hard close time. However after its last job the simulated vehicle will still wait at its last location instead of driving back to the depot, and as a result no statistics will be available concerning the drive back to depot, and this travel time and distance will not be included in the total travel time and distance.
Return to depot when there’s no new jobs. When there are no new jobs available the vehicle will start driving back to the depot as soon as it finishes its last job. If the optimiser assigns a new job to the vehicle whilst it’s en-route back to the depot, the vehicle will be diverted and instead go to serve that job (creating a VEHICLE_INTERRUPTED_RETURN_2_DEPOT event in the event log). Travel time and distance statistics related to the return to depot will be available.
When using the return-to-depot mode, you should ensure that your simulation is configured so that simulated vehicles don’t accidentally run out of pending dispatched stops when there are pending stops still in its optimiser plan. The simulated vehicle only sees the stops which have been dispatched to it, it doesn’t see undispatched stops which are in its optimiser plan (i.e. the simulated vehicle has no direct knowledge of the optimiser plan, by design). Dispatches are only calculated when the optimisation runs, the frequency of which is determined by the variable:
simcase.simParams.burstOptimisation.millisBetweenBursts
Stops are only dispatched to the vehicle when they need to be actioned by the simulated vehicle (i.e. it needs to start driving to them) within the defined milliseconds buffer:
simcase.model.configuration.dispatchBufferMilliseconds
And stops will not be dispatched to the vehicle if it’s going to be waiting too long for the stop to open, according to:
simcase.model.configuration.dispatchIfWaitingTimeLessThanMillis
So if dispatchBufferMilliseconds or dispatchIfWaitingTimeLessThanMillis are set too high compared to millisBetweenBursts (i.e. they’re more than say half of millisBetweenBursts), the simulated vehicle can run out of pending stops purely because the dispatch hasn’t been calculated and sent to it, even if the optimiser plan does have planned stops for it. As a result, the vehicle will start driving back to the depot for no reason, only to be interrupted and diverted to the new job a few minutes later.
To enable the return-to-depot mode, you need to set sendBack2DepotIfNoWork in the vehicleEvents configuration JSON to true, as shown below:
{
"millisecondsFrequencyVehicleSync" : 60000,
"vehicleSyncSuccessProbablity" : 1.0,
"vehicleGPSTraces" : true,
"stopArrivals" : true,
"sendBack2DepotIfNoWork" : true
}
In return-to-depot mode, three additional events can appear in the events log:
VEHICLE_STARTS_RETURN_2_DEPOT. This event occurs directly after the vehicle has started waiting for jobs (usually on the next vehicle sync event).
VEHICLE_INTERRUPTED_RETURN_2_DEPOT. This can happen if the vehicle is en-route to the depot but is redirected to serve a job.
VEHICLE_FINISHED_RETURN_2_DEPOT. This event occurs when the vehicle arrives at the depot location.
14.5 Work breaks
The simulator treats breaks in a slightly simplified manner compared to the optimiser (i.e. compared to normal usage of ODL Live in a real-life production system). Autobreaks (e.g. based EU law) are not supported at all. Work breaks defined in the vehicle’s preloadedStops list are supported, but in a simplified manner compared to the optimiser configuration.
Assume a vehicle has a break defined in its preloadedStops called break1 and two stops in its plan called stopA and stopB. The planned route for the vehicle could be stopA, break1 and stopB. In the plan generated by the optimiser, if the openTime of break1 happens after the vehicle departs stopA, the vehicle can take a break ‘enroute’ - e.g. it could (1) leave stopA, (2) drive for a while, (3) take break1, (4) drive some more and then (5) arrive at stopB. However when running the simulation, the simulated vehicle will instead (1) leave stopA, (2) wait until the break openTime, (3) take break1, (4) do entire drive to stopB, (5) arrive at stopB. The simulation can therefore overestimate the time associated with work breaks compared to the optimiser plan.
14.6 List of simulator commands
Various commands are available for the simulator. For a command to change the operation of the simrun command (e.g. for it to change the output type), it must be called before the simrun command. For example, the following command changes the output type to CSV, adds the modelId as a field to the CSV and then runs the sim:
java -Xmx4G -jar odl.live.commandline.jar -simoutputcsv -simcsvmodelid -simrun demosimcase.json events.csv
The following command has simoutputcsv and simcsvmodelid after simrun, so these options will be completely ignored:
java -Xmx4G -jar odl.live.commandline.jar -simrun demosimcase.json events.csv -simoutputcsv -simcsvmodelid
The following simulator commands are available. This list can also be viewed by running:
java -Xmx4G -jar odl.live.commandline.jar -help
-simcreatedemodata1
Create the demo 1 simulation case file and save to disk. Usage -simCreateDemoData1 outputJSONFilename
-simcsvmodelid
Set the output CSV to include the modelId (from the model in the simulation case) as a field. Set to true or false. Usage -simCSVModelId true
-simdistcachetargbytes
Set the distances cache target bytes for reducing the size of the A-to-B distances cache when a purge is triggered. See self-hosting guide document for more information. Usage -simDistCacheTargBytes nbOfBytes
-simdistcachetrigbytes
Set the distances cache trigger bytes for triggering a purge of the A-to-B distances cache. See self-hosting guide document for more information. Usage -simDistCacheTrigBytes nbOfBytes
-simnbthreads
Set the number of CPU threads to be used when optimising. Recursive splits must be used and configured correctly for multithreading to give a speedup. Usage -simNbThreads nbOfThreads
-simoutputcsv
Set that the simulation output should be CSV. Usage -simOutputCSV
-simoutputjson
Set that the simulation output should be JSON. Usage -simOutputJSON
-simoutputzip
Set that the simulation output should be ZIP. Usage -simOutputZip
-simrun
Run the simulation. Usage -simRun inputFilename outputJSONFilename
simvidfps Set the frames per second that the simulation output video should be played at. This value should be between 1 and 100. The default value if you don’t override this value is 25. Usage -simVidFPS 25
simvidoutput Set the simulation to output an mp4 video to the filename. For small and medium sized simulations, this will make the simulation run considerably slower. The simulator tool must be able to download map tiles from the internet for the video to work correctly. Usage -simVidOutput outvideofilename.mp4
simvidpanel If set to true, a panel will be shown when the simulation is running with the video output. You can choose to just show the panel, just create the output video, or do both. For small and medium sized simulations, this will make the simulation run slower. The simulator tool must be able to download map tiles from the internet for the video to work correctly. The default value if you don’t override this value is false. Usage -simVidPanel true
simvidsimtimemillisperframe Set milliseconds in simulated time between output frames in the simulation output video or viewer panel. Dependent on how quickly your vehicles complete stops, you are advised to set this somewhere between 10 seconds and a few minutes. The default value if you don’t override this value is 30000. Usage -simVidSimTimeMillisPerFrame 60000
simvidtilecachedir Set the directory on your computer to keep a cache of downloaded map tiles, which are used when creating the simulation video output. The ODL Live simulator tool must be able to write to this directory or an error will be thrown. The default value if you don’t override this value is C:\temp-dir-on-your-computer\odl-live-sim\tile-cache. Usage -simVidTileCacheDir “c:\my-cache-dir”
simvidtileurl Set the URL to download OpenStreetMap style background map tiles from, which are used when creating the simulation video output. The default value if you don’t override this value is http://tile.openstreetmap.org. Usage -simVidTileURL http://url-for-tiles.com