ADHB Orderly Simulation Project
-Use historical data out of the INFRA transit booking system to develop a simulation of in-patient transit between Radilogy and other departments with the assistance of orderlies.
-Once the simulation has been developed and validated, use it to explore different scheduling scenarios.
Summary of ADHB Meeting 25/11/10
-Ethics approval required as particular patients may be identified from the data
-Radiology Sites-Level 5 (main site), Level 2 (Emergency), Level 9 (Maternity)
-Focussed on inpatients, those already admitted. These patients are moved to/from radiology. This could be from any ward/theater/critical care.
-Two orderly teams. We are focussing on the non-maternity team.
-Transfers are scheduled using an online booking system by the MRT imagers.
-Bookings may not be communicated correctly, but we will assume they are for the purposes of this project
-The booking system is known as INFRA
-The time taken for the radiography procedures is relatively reliable, the main variability is in the set-up times for different patients, which depends on the condition of the patient.
-Approximately 2/3 of patients can be taken by orderlies on their own, and around 1/4 or more require the presence of a transit nurse due to the condition of the patient.
-Specific nurses are assigned to be transit nurses for a particular shift. The ratio of transit nurses to orderlies is around 1:4.
-The target is for a patient to reach their destination within 15 minutes of the scheduled time.
-As a measure of the arrival time, we use the time the orderly calls the dispatcher to report the job completed-assume that this is the arrival time, no delay from orderly.
-Dispatcher will schedule MRIs in preference to X-rays
-Return+transit jobs are handled by the same scheduler
-Need to do return jobs-if too many people are left waiting then beds fill up and people cannot be transferred into Radiology.
-Possible thing to explore with simulation: what happens if the orderly stays with the patient throughout the radiology procedure
-First step in simulation-use historical data.
Discrete Event Orderly Simulation
1. Daily plan/schedule created?
Radiologist books an appointment for a patient
Triggers: Next booking event (if random?)
For each booking: Appointment booked is scheduled into list
by the dispatcher (use list container to hold sequence of transits?)
Time of scheduled transit reached
Check if any free orderlies (Orderly class with isfree attribute)
If not, wait until an orderly is free
When there is a free orderly, the orderly travels to the patient
(Record current location of orderly in orderly class)
The orderly then takes the patient to their destination, and is freed
Use stochasticity for travel times
Attribute isfree-stores whether the orderly is free
Attribute currentLocation-stores the current location of th
Hospital Visit 17/12/10
-8 Orderlies and 2 Nurses per shift
-If jobs conflict, the priority is MRI-CT-Ultrasound-X-ray
-CT, angio etc are scheduled at 6pm the night before. X-ray and return transits arrive throughout the day.
-2 jobs given per orderly at one time-one up from Radiology to the wards, and one down to the wards from Radiology. Second job picked by estimating time taken for first job and looking ahead in schedule.
-Computer system-list of jobs-new jobs pop in all the time
-Orderlies radio in to dispatcher when job has been completed
-Orderly free near wards-job coming down close to them-give job to them
-Orderly completed job and no further jobs-back to base.
The Transit Nurses:
-Have to wait at ward destination to hand patient over to next nurse
-Takes time to find patient notes
-Dispatched by dispatcher and sometimes have to wait at ward for orderly to be free/arrive
-Problem when nurse not there when arrive-need to wait + happens often
-Return to base when no jobs-can be dispatched in nurse-orderly pair or individually
-Go back to base when no more jobs
-Can get jobs at base from the dispatcher or via RTs
This project was a joint project between the Department of Engineering Science and the Auckland District Health Board (ADHB) in order to try and improve the percentage of patients in the Radiology department reaching their appointments on time. Currently only 40% of patients reach their appointments within 15 minutes of their specified appointment time. The goal of this project was thus to investigate how the orderly transit system could be changed in order to improve this percentage. It was decided to do this using a simulation.
In order to do this a simulation would have to be created to represent the orderly transit system in Radiology the way it currently is. This simulation would then be validated using historical patient transit request data as well as actual route data from the hospital. This validation would be done by reading in an excel file containing historical patient transit requests into the simulation, and then seeing if the patient arrival times outputted by the simulation matched those in the historical data. Once the simulation model had been validated then stochasticity would be added to model the arrival of transits, travel times etc. Finally, once the model had been completed, parameters for the simulation could be changed in order to see the effect on patient arrivals. My part of the project was focussed on creating a simulation model to represent the current state of the system.
The Orderly Transit System
The first step in creating a simulation to represent the orderly transit system was to learn in detail how the system works. This was done through both meetings with the ADHB Improvements Department and Orderly Supervisor to learn about the system, and by spending a day in the hospital shadowing orderlies, dispatchers and transit nurses in order to see the system in action.
The Radiology Department in Auckland City hospital is mainly located on the 5th
floor. This is where patients are taken for MRI, CAT scan and ultrasound procedures. The orderly base is also located there. Orderlies and transit nurses are both located in the orderly base when they do not have a job, and return to the base after having completed a job. The emergency X-Ray department is located on the 2nd
floor. The patients are located mainly in wards on the 6th
floors of the main building, with some also located on the 13th
floor of Building 1 of the hospital.
All MRI, CAT scan and ultrasound appointments are generally scheduled by 6pm the night before the appointment. X-Ray appointments are scheduled throughout the day, as are return transits for patients after their procedures have finished. Patient transit jobs are given to the orderlies by a dispatcher who sits in the orderly base. Generally orderlies are given two transit jobs at a time: one a return transit for a patient from Radiology back to the wards, and one back down from the wards to Radiology. In order to decide on the second transit to assign to the orderly the dispatcher will judge how long the first one will take and look that far ahead in his schedule of transits to see if there is one scheduled for around that time. Some patients require a transit nurse in addition to an orderly for their transit due to their condition, such as if they have an IV. Transit nurses are also given transits by the dispatcher. Transits requiring a transit nurse take priority over those only requiring an orderly. There are usually 8 orderlies and 2 transit nurses working at one time.
The Logic of a Transit
When an orderly receives their two transit jobs, they first travel from the orderly base to the patient in Radiology. The patient will be located in one of two waiting bays. The orderly will then take the patient up to the wards via the elevator. When the orderly drops the patient off at the wards they must hand over the patient and patient information to the ward staff. Once this job is complete, the orderly must then travel to the ward in which their next patient is located, pick up the patient and take them back down to Radiology. Before dropping off the patient in one of the two waiting bays the orderly must take them to reception. If there are no jobs queued up when the orderly has finished their transit jobs, then they return to base. If there are jobs queued up, then the orderly will be sent to do these jobs. The transit nurse transits work similarly to this, except when the transit nurses pick up and drop off patients they need to spend time doing a hand-over of the patient to or from the ward nurses. This often causes significant delays due to ward nurses being busy. When a transit nurse job time is reached then the transit nurse will be dispatched immediately, so may have to wait up in the wards for an orderly to be freed. As transit nurses work pretty much constantly, transit nurses and orderlies will often be paired up for the duration of the transit nurses shift.
The System Flow Chart
Once the system had been observed in detail, the next step was to create a flow chart to represent the logic in the system. This flow chart is shown in Appendix 1. For this flow chart the simplification was made that the orderlies only have one job at a time, in order to simplify the initial coding of the simulation and get the basic logic established and verified. The orderlies doing two jobs could then be added in later.
Coding the Simulation
Stochastic simulation in Java
The simulation was coded as an event-based simulation. An event-based simulation is one in which events, for example an orderly reaching a patient, are scheduled in a simulation calendar and then an action associated with the event, such as scheduling the next event, occurs when the scheduled time is reached. For example, an orderly transit time could be scheduled at 11:00am in the simulation calendar. When 11:00am was reached in the simulation time, an event for the orderly travelling to the patient would then be scheduled, which would then schedule an event for that orderly reaching the patient and so on. The coding for the simulation was done in the Java language, using the Stochastic Simulation in Java (SSJ) package. This package contains the simulation calendar and event classes.
The Coding Process
The first step in coding the simulation was to code in the logic shown in the flow chart in Appendix 1. Initially it was decided to remove transit nurses from the system and get the logic working for the orderlies fist, as once this was done it would not be too difficult to extend the working orderly-only system to include transit nurses. To do this, classes were created to represent orderlies, patients and requests, and event classes created to represent events show in the flow chart. Initially distances between locations were stored in an array, the orderlies just ‘jumping’ between locations rather than following routes. A ‘toy problem’, hard-coded data for a simplified version of the hospital system, was used to verify that this initial simulation logic had been implemented correctly. Next, code was added to model the hospital map as a network of nodes and make the orderlies travel on routes (a sequence of nodes). The final step was to add code to animate the simulation.
The Simulation Objects
The main class in the code is the OrderlySim
class, which contains all of the other classes, as well as the main function, which is executed when the program is run. The main objects within the simulation, the orderlies, patients and requests are also represented by classes within the simulation. There is also an info class, which stores the current state of the orderly (whether they have a patient or not) and their destination, and a co-ordinate class, which simply contains x, y, and z variables. For the orderly routes, there are two main classes, the node class and the next class.
Each orderly is represented in the simulation by an orderly object. The orderly class contains several main variables which store information about the orderly. It contains an id string, which stores the name of the orderly, and an object of the schedule class type, which stores the shifts that the orderly will be working. The class also contains several variables which store information about the orderly’s location and progress on their current route through the hospital, such as the last ‘node’ that the orderly entered, and the time that this occurred, the orderly’s destination, the next node the orderly will enter, and the orderly’s current location. Each patient is similarly represented, but the patient class contains much less information, as the request class is used for the events rather than the patient class in general. The patient class just contains a string for the patient id as well as a co-ordinate object to store the patient’s current location.
Each request within the code is represented by an object of the request class. The request class contains variables which store key information about the particular request. It contains a patient object, representing the patient who the transit request is for, two node objects representing the node that the request is from i.e. the patient pickup location and the node that the request is to i.e. the patient drop-off location. It also contains a Boolean variable to represent whether a transit nurse is required for the request or not.
Within the simulation, the Info class is used to store information about the current state of an orderly. It contains a node object storing the current destination of the orderly. Within the class file, an enum is also defined for the state of the orderly. There are three possible defined states: with patient, without patient and with transit nurse. The info class contains a state object specifying the current state the orderly is in.
The schedule class is used to store the schedule of shifts for an orderly. Within it is defined a shift class, representing one shift for an orderly. Each schedule contains a linked list of shifts, the shifts within that schedule.
Coding the Routes
In the simulation, the hospital is modelled as a network of nodes connected by straight lines. All key locations, such as the orderly base and radiology are modelled by nodes, as well as the intersections between corridors in the hospital. All of the route information between locations is stored on this network of nodes. Each node contains information about which node an orderly should go to after that node, given the current state and destination of the orderly. Three main simulation classes are used for the orderly routes. The Node class is used to represent the hospital locations. The Next class specifies the next node an orderly should go to, and the Coord class is used to specify the x, y ,z location of a node, orderly or patient.
The Node class contains a Coord object, specifying the location of the node, as well as a HashMap
, mapping from Info to Next objects. This map thus stores the information about which node an orderly should go to next given their current state (stored in the Info object inside the orderly class. The Next class contains a Node object (the node the orderly should go to next), as well as variables storing the distance to this next node, and the total distance to the destination. Each Next object is defined when the HashMap
for a Node object is created, so the specified distances are from the Node object.
Running the Simulation
Initialising the simulation
The main function first creates a new instance of the OrderlySim
class, and then executes the simulateOneRun function. The constructor for the OrderlySim
class reads in the orderly, map, route and request information from the files specified when the class is created. This is done using the readOrderlyFile, readMapFile, readRouteFile and readRequestFile functions. Currently in the code however, these functions contain hard-coded data rather than reading from files.
The readOrderlyFile function creates three main linked lists (ordered lists of objects) which the orderly objects will move between in the simulation: OrderliesBusy
, the list of all orderlies who currently have transit jobs, OrderliesAvailable
, the list of all orderlies currently on their shifts who do not currently have transit jobs, and Orderlies Unavailable, the list of all orderlies currently not on their shifts. The function next adds the orderly objects, either hard-coded in or read in from a file, to the list of unavailable orderlies at the start of the simulation. The readRequestFile function creates linked lists to store the current hospital patients and transit requests, as well as the request queue linked list, and then adds the requests and patients, either read from a file or hard-coded in, to these. The readRouteFile creates two hashmaps, both mapping from a string to a location, the string being the ID for the location. The first hashmap, Locations, stores the main locations such as the orderly base and radiology, and the second InterNodes
, the nodes on the hospital map which are not key locations, such as corridor intersections.
Once the OrderlySim
object has been constructed, the main function then calls the simulateOneRun function, the purpose of which is to run through the simulation once. Before the simulation can be started it first needs to be initialised. First the Sim.init() function is called to initialise the simulation object. Next the initialiseMap function is called. This function sets up the JFrame window which is used to display the simulation animation, initialising its boundaries, and adding blue squares representing the orderlies to their initial locations at the beginning of the simulation. The next step is to schedule the transit requests and the start and stopping times of the orderlies. The scheduleRequests function runs through all of the requests read in or hard-coded in by the readRequestFile function, and schedules a RequestTransit
event for each one. The startOrderlies function runs through all of the orderlies in the OrderliesUnavailable
linked list, and schedules OrderlyStart
events for each orderly. Finally the first animation event is scheduled, as is the end of the simulation, and then the simulation is started using the Sim.start() function, which starts the simulation running through the scheduled events.
The Simulation Events
event is used to start the orderlies working. Each OrderlyStart
event has an orderly object associated with it, the orderly who is starting their shift. When the start time of the orderly is reached, the orderly is removed from the list of unavailable orderlies. If the size for the request queue is greater than zero i.e. there is a transit request waiting to be dealt with, then the orderly is assigned to deal with the request, and a SendOrderly
event is scheduled. If the request queue is empty then the orderly is added to the list of available orderlies.
event is used to represent when a patient transit time is reached, and to assign an orderly to that request. Each RequestTransit
event has a patient transit request associated with it, the request for which the transit time has been reached. When a RequestTransit
event is reached, the closest orderly to the patient associated with the request is first found. The distance from each available orderly to the patient in the request is found using the findDistance function. An available orderly will either be located at the orderly base, or travelling back to the base after having finished a patient transit job. For an orderly located at the orderly base, findDistance will always return a positive distance, as there is only one possible route. An orderly travelling back to base will be between two nodes, and will thus have two possible routes to travel to the patient. In this case, the findDistance function will return a positive value for the distance if the shortest route is that where the orderly continues in their current direction, and a negative value if the closest route starts with the orderly returning to the node they just left. The closest orderly is then assigned to travel to the patient. It is removed from the list of available orderlies and added to the list of busy orderlies, and a SendOrderly
event is then scheduled. If the distance returned by findDistance was positive the boolean variable named ‘back’ used in the constructor is set to true, and if it was negative to false. If there are no available orderlies at the time of the RequestTransit
event, then the request is added to the request queue.
event represents an orderly being dispatched to a patient. Each SendOrderly
event has a transit request and an orderly associated with it, as well as a boolean variable called ‘back’. When a SendOrderly
event is reached, it is checked whether the orderly is at the orderly base or not. If they are, then an OrderlyReachesNode
event for the orderly ‘reaching’ the orderly base is scheduled immediately. If they are not, then this means the orderly is returning to base having completed a transit. The orderly will then be between two nodes. The back variable specifies whether the orderly should continue the way they are currently travelling, or go back to the previous node, when they are being re-routed to travel to the patient. An OrderlyReachesNode
event is thus scheduled for the node that they need to travel to.
event represents an orderly reaching a node within the hospital map. Each OrderlyReachesNode
event has a request, orderly and node associated with it. When this event is reached, the last node entered by the orderly and the time this happened are both updated. If the orderly has reached their destination, then either a PickupPatient
event is scheduled immediately. If they have not, then another OrderlyReachesNode
event is scheduled for the next node in the orderly’s route.
event represents an orderly picking up a patient. Each PickupPatient
event has a request and an orderly associated with it. This event updates the orderly’s destination and state, and schedules a new OrderlyReachesNode
event represents an orderly dropping off a patient. It has a request and an orderly associated with it. The last location entered by the orderly and the time in which it was entered are updated when the event is reached. If the orderly has not finished their shift and the request queue is not empty, then the orderly is assigned to do the first request in the queue, a new SendOrderly
event being scheduled. If the request queue is empty, then the orderly is removed from the list of busy orderlies, added to the list of available orderlies and their destination updated to the orderly base, and a new OrderlyReachesNode
event scheduled. If the orderly is not currently working then the orderly is removed from the list of busy orderlies and added to the list of unavailable orderlies.
event represents the end of the orderly’s shift being reached. It has an orderly object associated with it, the orderly whose shift is ending. The orderly object is set to not be currently working. If the orderly is not busy, it is removed from the list of available orderlies and added to the list of unavailable orderlies.
A simple example of the simulation in action
For this example, consider a system with two orderlies, Ord1 and Ord2, and three patients, Patients 1, 2 and 3. The hospital is a simplified version of the real hospital, with the layout show in the diagram below. Ord1 and Ord2 both start at 9:00 am and finish at 5:00pm, and the patient transits are at 11:00am, 11:15am and 11:30pm. Patients 1 and 2 are located in Ward 1 and Patient 3 in Ward 2. The patient transits take 45, 45 and 60 minutes respectively.
The first events scheduled in the simulation calendar will be the OrderlyStart
events for Ord1 and Ord2 at 9:00am, adding both of them to the list of available orderlies. The next event will be the RequestTransit
event for Patient 1 at 11:00 am. As both Ord1 and Ord2 are located at the orderly base, they are both the same distance away from the patient, so Ord1 will be dispatched to the patient. A SendOrderly
event is thus scheduled immediately for Ord1, this scheduling OrderlyReachesNode
events for Ord1, until he reaches the patient, a PickupPatient
event being scheduled immediately. This then schedules OrderlyReachesNode
events until Ord1 and the patient reach their destination, when a DropoffPatient
event is scheduled.
While Ord1 is transporting Patient1, the transit time for Patient 2 is reached, Ord2 being assigned to Patient 2, and undergoing the same transit process as Ord2. As the transit time for Patient 3 is reached while both Ord1 and Ord2 are busy, the transit request is added to the request queue. When Ord1 is freed he is thus assigned the transit request to Patient 3, and undergoes the same transit procedure as before. When Ord1 and Ord2 complete these jobs they are added back to the list of available orderlies as there are no more requests in the queue, and OrderlyReachesNode
events are scheduled for them until they reach the orderly base.
Verifying the model: The ‘Toy Problem’
In order to verify that both the simulation logic and route code had been implemented correctly, a ‘toy problem’ was used. This was a simplified version of the hospital system, with the map layout shown in the diagram below.
The OB and RAD nodes represent the orderly base and radiology respectively, and the W1 and W2 nodes ward 1 and ward 2. ELE1 and ELE2 represent the entry points of an elevator connecting the two floors. This map and route data was hard-coded into the simulation in the readRouteFile function.
Orderly, patient and request objects were hard-coded in for this simplified system, the system containing two orderlies, and four patients and requests. The times of the requests were chosen so that request queuing would occur, in order to test that this was working correctly. Print statements were added to the code to print out when all of the events occurred, and this was worked through in order to check that the simulation was functioning correctly.
Animating the Simulation
Once the simulation logic had been verified and the routes added in, the next step was to animate the simulation. This was done using an Animate event. The first Animate event is scheduled at time 0 for the simulation, and each Animate event schedules a new Animate event for some time in the future. The simulation is thus animated at regular time intervals. Each time an Animate event is reached, the updateMap() function is called, which determines the current positions of all orderlies and displays them within the JFrame animation window. The function first determines the positions of all busy orderlies. First it checks to see if the orderly is currently moving within a floor, or if it is moving between floors by checking the difference in z coordinates between the nodes the orderly is currently travelling between. If the orderly is travelling within a floor, the time since it left the last node is calculated, and this and the speed of the orderly used to work out the distance it has travelled, trigonometry being used to work out the x and y distances. The orderly is then redrawn in the JFrame window as a blue square. The current z coordinate of the orderly is added to the x coordinate when it is drawn in order to create separate floors in the animation window, there being two floors for the toy problem.
If the orderly is moving between floors the distance it has travelled is worked out in the same way, this being the z distance. The drawOrderlyz function is used to draw the orderly in the animation window. When the orderly is moving between floors it is represented as a yellow rectangle moving vertically in the animation window, between the two floors. The z distance is thus translated into a y distance for the purposes of drawing the orderly. A similar procedure is used for animating the available orderlies returning to base as is used for the busy orderlies. A screenshot of the animation is shown below. Trails are included to make it easier to see the movement of the orderlies in a static picture.
The triangle on the left is the first floor, the vertical yellow line in the middle the elevator, and the triangle on the right the second floor. The blue trails represent the movement of busy orderlies around the hospital map. The red trail represents the movement of available orderlies from Radiology back to the orderly base after having completed their jobs. The yellow trail represents the movement of orderlies up and down the elevator.
Conclusions and Future Work
In conclusion, good progress was made towards the goal of having a simulation model to represent the current orderly transit system. The current simulation model is working and animating correctly for the orderly transit system (excluding transit nurses) for the toy problem discussed earlier, with the exception of the orderlies currently only being given one patient transit job at a time instead of two.
There is still a lot of work to be done on the simulation model before it will be of use to ADHB. The next step in writing the simulation would be to change the simulation logic so that orderlies are assigned two transit jobs at once instead of one. Then the next step would be to take the route data from the actual hospital and code that into the system, and read in the historical patient request data was well, in order to get the simulation running for the actual hospital system. Once the simulation was working for the orderlies in the actual hospital system, the transit nurses could then be added into the simulation, and the transit nurse logic verified. Once the simulation logic had been validated, stochasticity could then be added, and finally simulation parameters could be changed to see the effect on patient arrival times.
First I would like to thank my supervisors Dr Mike O’Sullivan and Dr Cameron Walker for giving me the opportunity to do this project and for all of their help throughout it. I would also like to thank Andrew Peterson and Tim Winstone from the ADHB Improvements Department for giving me the opportunity to work on a real-life application of simulation within the health sector, and for giving me their time to discuss the project and the workings of the hospital. I would also like to than the orderly supervisor Feroz Buksh for all of his help in discussing the orderly transit system and organizing my shadowing of the orderlies, dispatcher and transit nurses. Finally I would like to thank all of the orderlies, transit nurses and dispatches who I shadowed, who took the time to answer all of my questions and help explain the transit system to me.