callCenter.py :  » Development » SimPy » SimPy-2.1.0beta » SimPyModels » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » SimPy 
SimPy » SimPy 2.1.0beta » SimPyModels » callCenter.py
"""callCenter.py
Model shows use of get command with a filter function.

Scenario:
A call center runs around the clock. It has a number of agents online with 
different skills/competences.
Calls by clients with different questions arrive at an expected rate of callrate
per minute (expo. distribution). An agent only deals with clients with questions 
in his competence areas. The number of agents online and their skills remain constant -- 
when an agent goes offline, he is replaced by one withe thesame skills.
The expected service time tService[i] per question 
follows an exponential distribution.
Clients are impatient and renege if they don't get service within time 
tImpatience.
 
* Determine the waiting times of clients.
* Determine the percentage renegers
* Determine the percentage load on agents.
"""
from SimPy.Simulation import *
import random as r
## Model components -----------------------------------------------------------
class Client(Process):
    def __init__(self,need):
        Process.__init__(self)
        self.need=need
    def getServed(self,callCenter):
        self.done=SimEvent()
        callsWaiting=callCenter.calls
        self.served=False
        self.tArrive=now()
        yield put,self,callsWaiting,[self]
        yield hold,self,tImpatience
        # get here either after renege or after interrupt of renege==successful call
        if self.interrupted():
            #success, got service
            callCenter.renegeMoni.observe(success)
            # wait for completion of service
            yield waitevent,self,self.done
        else:
            #renege
            callCenter.renegeMoni.observe(renege)
            callsWaiting.theBuffer.remove(self)
            callCenter.waitMoni.observe(now()-self.tArrive)            
            if callsWaiting.monitored:
                callsWaiting.bufferMon.observe(y=len(callsWaiting.theBuffer))
                
class CallGenerator(Process):
    def __init__(self,name,center):
        Process.__init__(self,name)
        self.buffer=center.calls
        self.center=center
    def generate(self):
        while now()<=endTime:
            yield hold,self,r.expovariate(callrate)
            ran=r.random()
            for aNeed in clientNeeds:
                if ran<probNeeds[aNeed]:
                    need=aNeed
                    break
            c=Client(need=need)
            activate(c,c.getServed(callCenter=self.center))        
class Agent(Process):
    def __init__(self,name,skills):
        Process.__init__(self,name)
        self.skills=skills
        self.busyMon=Monitor(name="Load on %s"%self.name)
    def work(self,callCtr):
        incoming=callCtr.calls
        def mySkills(buffer):
            ret=[]
            for client in buffer:
                if client.need in self.skills:
                    ret.append(client)
                    break
            return ret
        self.started=now()
        while True:
            self.busyMon.observe(idle)
            yield get,self,incoming,mySkills
            self.busyMon.observe(busy)
            theClient=self.got[0]
            callCtr.waitMoni.observe(now()-theClient.tArrive)
            self.interrupt(theClient) # interrupt the timeout renege
            yield hold,self,tService[theClient.need]
            theClient.done.signal()

class Callcenter:
    def __init__(self,name):
        self.calls=Store(name=name,unitName="call",monitored=True)
        self.waitMoni=Monitor("Caller waiting time")
        self.agents=[] 
        self.renegeMoni=Monitor("Renegers")
        
renege=1
success=0
busy=1
idle=0
            
## Experiment data ------------------------------------------------------------
centerName="SimCityBank"
clientNeeds=["loan","insurance","credit card","other"]
aSkills=[["loan"],["loan","credit card"],["insurance"],["insurance","other"]]
nrAgents={0:1,1:2,2:2,3:2} #skill:nr agents of that skill
probNeeds={"loan":0.1,"insurance":0.2,"credit card":0.5,"other":1.0}
tService={"loan":3.,"insurance":4.,"credit card":2.,"other":3.} # minutes
tImpatience=3       # minutes
callrate=7./10          # Callers per minute
endTime=10*24*60    # minutes (10 days)
r.seed(12345)

## Model ----------------------------------------------------------------------
def model():
    initialize()
    callC=Callcenter(name=centerName)
    for i in nrAgents.keys(): #loop over skills
        for j in range(nrAgents[i]): # loop over nr agents of that skill
            a=Agent(name="Agent type %s"%i,skills=aSkills[i])
            callC.agents.append(a)
            activate(a,a.work(callCtr=callC))
    cg=CallGenerator(name="Call generator",center=callC)#buffer=callC.calls)
    activate(cg,cg.generate())
    simulate(until=endTime)
    return callC
    
for tImpatience in (0.5,1.,2.,):
    ## Experiment ------------------------------------------------------------------
    callCenter=model()
    ## Analysis/output -------------------------------------------------------------
    print "\ntImpatience=%s minutes"%tImpatience
    print   "=================="
    callCenter.waitMoni.setHistogram(low=0.0,high=float(tImpatience))
    try:
        print callCenter.waitMoni.printHistogram(fmt="%6.1f")
    except:
        pass
    renegers=[1 for x in callCenter.renegeMoni.yseries() if x==renege]
    print "\nPercentage reneging callers: %4.1f\n"\
           %(100.0*sum(renegers)/callCenter.renegeMoni.count())
    for agent in callCenter.agents:
        print "Load on %s (skills= %s): %4.1f percent"\
               %(agent.name,agent.skills,agent.busyMon.timeAverage()*100)


www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.