In Part I, we learned about creating a simple discrete event simulation controller in Python, using a clock that iterated over a minute counter and translated this minute counter to a week using a day-hour-minute clock that we can use to regulate events.

In the second part of the tutorial, we’ll go over queues. Queues are an integral part of many simulations, and used to handle cases where the simulation is used to examine processes where a server or servers are serving customers, handling events, and so forth.

Our eventual goal is to have patrol cars service calls, to see how fast a car will respond to calls when it’s placed in a particular location in a city. To do so, the first thing we’ll add to the script we built in Part I, is a queue. Python has a queue class that’s perfectly suitable for our purposes, and can even handle multi-threading which we aren’t going to use, and you don’t need to worry about right now. At least, I’m not going to go into it. With all that being said, let’s totally ignore the Python queue and write our own queue class. It’s going to look something like this:

class Queue:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return len(self.items)==0

    def enqueue(self, item):
        self.items.insert(0,item)

    def dequeue(self):
        return self.items.pop()

    def get(self, name):
        return_item=None
        object_list=[item for item in self.items if item.name==name]
        if len(object_list) > 0:
            return_item=object_list[0]
        #remove item from list
        self.items=[item for item in self.items if item.name!=name]

        return return_item

    def size(self):
        return len(self.items)

    def peek(self, name):
        return_item = None
        object_list = [item for item in self.items if item.name == name]
        if len(object_list) > 0:
            return_item = object_list[0]
        return return_item

Since this will be at the heart of our sim, some explanation is required. First, the items list will contain the objects waiting for service. Get() is not just going to get the item you want from the queue, it’s going to remove it also. If you just want to to look at it, without removing it, that’s what peek() is for.

You add items to the queue by writing:

queue=Queue()
queue.enqueue(my_item)

Enqueue is different from the Python command queue.items.append(my_item), it will place things at the back of the line. Actually in positions zero, but that’s the back for our purposes.

We are also using latitude and longitude positions for our patrol cars, so we need a latitude-longitude object to hold our positions:

class LatLon(object):
    def __init__(self, lat, lon):
        self.lat=lat
        self.lon=lon

Finally, we’ll need a Patrol Car class as a container for our patrol cars:

class PatrolCar(object):
    def __init__(self,car_number,latlon):
        self.name=car_number
        print("New Car %d assigned pos %.4f %.4f" % (car_number, latlon.lat, latlon.lon))
        self.current_latlon=latlon
        self.patrol_latlon=latlon
        self.call_wait=0
        self.move_wait=0
        self.on_call=False
        self.call=None
        self.car_removed=False

There’s some other things in there that you don’t need to worry about right now. Just know for now, every PatrolCar object will need a LatLon object. When you instantiate the PatrolCar in your script, it’s going to store the LatLon that you give to it in both the PatrolCar’s current position and patrol position. We’ve also given it a number which will be synonymous with id. Here’s what it look’s like when you instantiate it:

car_one = PatrolCar(1,LatLon(33.448,-112.083))

For my model, I’m using the same datum that Google Maps uses, WGS84. Off topic, if you want to know what the WGS84 lat-long for a particular point in a Google map, right click on that spot of the map and choose “What’s Here?” and one of the things that will pop up, will be the WGS84 lat-long.

Here’s the instantiation and enqueuing:

car_pool = Queue()
car_one = PatrolCar(1,LatLon(33.448,-112.083))
car_pool.enqueue(car_one)
car_two = PatrolCar(2,LatLon(33.466,-112.100))
car_pool.enqueue(car_two)

Here’s the entire script:

https://github.com/jenholm/MontePy/blob/master/Sim4.py

In the next installment, we’ll set up a call queue that the patrol cars will respond to. Here’s Part I:

http://enholm.net/2017/09/20/build-discrete-event-simulation-framework-python-part/