Skip to content
Advertisement

SimPy, How to incorporate a break for resources?

At the moment I am creating doctors as following:

doctor = simpy.Resource(self.env, capacity=3)

These doctors are requested for a flow of patients using the following:

with self.doctor.request() as req:
    yield req2
    *patient encounter*

What I would like to do, is initialize the doctors with some kind of fatigue level (and other characteristics) like:

# Class representing a doctor and their characteristics
class Doctor(object):
    def __init__(self, env, id, exp_level, fatigue):
        self.env = env
        self.id = id
        self.exp_level = exp_level
        self.fatigue = fatigue 
        self.isAvailable = True

Then in the encounter I would like to access the doctor to add fatigue such as:

with self.doctor.request() as req:
    yield req2
    *patient encounter*
    self.doctor.fatigue += 5

Where once the fatigue crosses a threshold the doctor goes on break and the fatigue is reset, such as:

def monitor_break(self): 
    while True:
        if Doctor.fatigue > 9:
            Doctor.fatigue = 0
            yield self.env.timeout(15)

Any idea on how to do this?

Advertisement

Answer

First I would use a store for your docs instead of using a resource. Second I would decorate the store with a get override to check if the doc needs a nap

something like this

"""
    A simple sim where Doctors put themselves on break when they get tired

    Programmer Michael R. Gibbs
"""

import simpy
import random

class Doctor():
    """
        Doctor that get tired
    """

    def __init__(self, env, id):
        self.env = env
        self.id = id
        self.fatigue = 0

class Doc_Pool():
    """
        decorates a simpy store
        to chekc a doc's fatigue level
        and doing a timeout if fatigue is too 
        high before returning the doc to the pool
    """

    def __init__(self, env, num_of_docs, max_fatigue):

        self.env = env

        self.store = simpy.Store(env)
        self.store.items = [Doctor(env, i+1) for i in range(num_of_docs)]
        self.max_fatigue = max_fatigue

    def get(self):
        """
            get a doc from the real store
        """

        return self.store.get() 

    def put(self, doc):
        """
            put a doc in the store
            unless the doc needs a break
        """

        if doc.fatigue > self.max_fatigue:
            # needs a break
            self.env.process(self._doc_timeout(doc))

        else:
            self.store.put(doc)


    def _doc_timeout(self, doc):
        """
            gives the doc a break, then put in store
        """

        print(f'{self.env.now:.0f} doctor {doc.id} starting break with fatigue {doc.fatigue:0.2f}')

        yield self.env.timeout(doc.fatigue)

        doc.fatigue = 0

        self.store.put(doc)

        print(f'{self.env.now:.0f} doctor {doc.id} ending break')


class Patient():
    """
        Simple class to track patients
    """

    next_id = 1

    def __init__(self):

        self.id = self.get_next_id()

    @classmethod
    def get_next_id (cls):
        id =cls.next_id
        cls.next_id += 1
        return id

def gen_pats(env, doc_store):
    """
        Generates the arrival off patients
        and queue them up for a doctor visit
    """

    while True:
        pat = Patient()
        print(f'{env.now:.0f} patient {pat.id} has arrived')

        yield env.timeout(random.uniform(1,5))

        env.process(doc_visit(env, pat, doc_store))

def doc_visit(env, pat, doc_store):
    """
        gets a doc, do visit, add fatigue to doc, end visit
    """

    doc = yield doc_store.get()

    print(f'{env.now:.0f} patient {pat.id} is visiting doctor {doc.id}')

    env.timeout(random.uniform(1,6))

    doc.fatigue += random.uniform(1,5)

    doc_store.put(doc)

    print(f'{env.now:.0f} patient {pat.id} visiting doctor {doc.id} has ended')


# boot up sim
env = simpy.Environment()

doc_store = Doc_Pool(env, 3, 10)

env.process(gen_pats(env, doc_store))

env.run(200)

print('end of simulation')
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement