コード例 #1
0
    def createDemand(self):
        def determineStartingInterval():
            start_interval = P_constrain(np.random.normal(), -3.0, 3.0)
            start_interval = P_map(start_interval, -3.0, 3.0, 15 * 60, self.MAX_INTERVAL - self.MAX_DURATION - 1)
            start_interval = int(P_constrain(start_interval, 0, self.MAX_INTERVAL - self.MAX_DURATION - 1))
            return start_interval

        def determineSkillAssignments():
            SKILLS = ['LEVEL_1', 'LEVEL_2', 'LEVEL_3']
            skill = random.choice(SKILLS)
            return skill

        def determineDuration():
            return int(P_map(P_constrain(np.random.normal(), -3.0, 3.0), -3.0, 3.0, 5, self.MAX_DURATION))

        print('Creating demand list...')
        toolbar_width = 40
        pb = ProgressBar(toolbar_width=toolbar_width)
        for x_ in range(self.NUM_CALLS):
            pb.update(x_, self.NUM_CALLS)

            start_interval = determineStartingInterval()
            duration = determineDuration()
            skill = determineSkillAssignments()

            self.addDemand({'id': x_ + 10, 'interval': start_interval, 'duration': duration, 'skill': skill})

        pb.update(1, 1)
        pb.clean()
コード例 #2
0
 def runSimulation(self):
     abort = False
     toolbar_width = 40
     pb = ProgressBar(toolbar_width=toolbar_width)
     for k, demand in enumerate(self.demandList):
         if k % round((self.NUM_CALLS / 40)) == 0:
             # print(round(k * 100 / self.NUM_CALLS))
             pb.update(k, len(self.demandList))
         if demand['skill'] in self.exhaustedSkills:
             continue
         assigned = self.findAvailableResource(demand)
         if assigned == 'FAIL' or assigned == 'FAIL_EXHAUSTED':
             if demand['skill'] not in self.exhaustedSkills and assigned == 'FAIL_EXHAUSTED':
                 self.exhaustedSkills.append(demand['skill'])
                 # print('No employees available beginning at interval: ' + str(demand['interval']) + ' for skill: ' + demand['skill'])
                 # turned off due to max interval code interfering with this logic
             if len(self.exhaustedSkills) == self.NUM_SKILLS:
                 pb.update(1, 1)
                 print(f'\nAll skills exhausted. Simulated {k} out of {self.NUM_CALLS} demand events.')
                 abort = True  # switch
             if abort:
                 pb.update(1, 1)
                 break
     pb.update(k + 1, len(self.demandList))
     pb.clean()
コード例 #3
0
    def createResources(self):

        def determineStartingInterval():
            start_interval = P_constrain(np.random.normal(), -3.0, 3.0)
            start_interval = P_map(start_interval, -3.0, 3.0, 0, 3.999)
            start_interval = int(start_interval * 60 * 60)
            return start_interval

        def determineSchedule(start_interval):
            # Build out the employee's schedule
            # Prefill 0's from the beginning of the day until the start of this employee's shift
            temp_sch = [0 for x in range(start_interval)]
            # Fill in 1's for the duration of this employee's shift
            temp_sch.extend([1 for x in range(self.SHIFT_LENGTH)])
            # Fill in 0's from the end of this employee's shift until the end of the day
            temp_sch.extend([0 for x in range(self.NUM_INTERVALS - self.SHIFT_LENGTH - start_interval)])
            return temp_sch

        def determineSkillAssignments():
            SKILLS = ['LEVEL_1', 'LEVEL_2', 'LEVEL_3']
            skill = [random.choice(SKILLS)]
            if random.randint(0, 100) <= 30:
                skill.append(random.choice([x_ for x_ in list(set(SKILLS) - set(skill))]))
            return skill

        print('Creating employee list...')
        toolbar_width = 40
        pb = ProgressBar(toolbar_width=toolbar_width)

        for x_ in range(self.NUM_RESOURCES):
            pb.update(x_, self.NUM_RESOURCES)

            # Select the start time for this employee's shift
            start_interval = determineStartingInterval()

            # Build out the employee's schedule
            schedule = determineSchedule(start_interval)

            utilization = [0 for x in range(self.NUM_INTERVALS)]

            skillset = determineSkillAssignments()

            self.addResource({'id': x_ + 10, 'schedule': schedule, 'utilization': utilization, 'skills': skillset})
        pb.update(1, 1)
        pb.clean()
コード例 #4
0
    def printStatistics(self):
        SERVICE_LEVEL = 20
        total_calls = len(self.demandList)
        missed_calls = 0
        delay = 0
        total_delay = 0
        max_delay = 0
        out_svl = 0
        unanswered_calls = 0
        print('Calculating demand statistics...')
        for call in self.demandList:
            if 'answered_interval' not in call:
                unanswered_calls += 1
                missed_calls += 1
                out_svl += 1
            else:
                if call['interval'] != call['answered_interval']:
                    missed_calls += 1
                    delay = call['answered_interval'] - call['interval']
                    total_delay += delay
                    if delay > max_delay:
                        max_delay = delay
                    if delay > SERVICE_LEVEL:
                        out_svl += 1

        print('Calculating resource statistics...')
        utilization = 0
        available = 0
        for res in self.resourceList:
            available += self.SHIFT_LENGTH
            for moment in res['utilization']:
                if moment > 1:
                    utilization += 1
        res_utilization = round(100 * utilization / available, 2)

        if missed_calls > 0:
            avg_delay = round(total_delay / missed_calls, 2)
            asa = round(total_delay / total_calls, 0)
        else:
            avg_delay = 0
            asa = 0

        unanswered_perc = round(100 * unanswered_calls / total_calls, 2)
        calc_svl = round(100 - (100 * out_svl / total_calls), 2)
        delayed_perc = round(100 * missed_calls / total_calls, 2)

        print(f'Total calls: {total_calls}')
        print(f'Number of resources: {self.NUM_RESOURCES}')
        print(f'Service level ({SERVICE_LEVEL}): {calc_svl}%')
        print(f'Delayed calls: {missed_calls} ({delayed_perc}%)')
        print(f'Unanswered calls: {unanswered_calls} ({unanswered_perc}%)')
        print(f'Average seconds to answer: {asa:.0f}')
        print(f'Average delay: {avg_delay}')
        print(f'Max delay: {max_delay}')
        print(f'Resource Utilization: {res_utilization}%')

        if self.WRITE_TO_FILE:
            import sqlite3
            import csv
            conn = sqlite3.connect('perfmodel.db')
            crsr = conn.cursor()
            crsr.execute("""DROP TABLE IF EXISTS tblDemand;""")
            conn.commit()
            crsr.execute("""CREATE TABLE tblDemand (ID BIGINT PRIMARY KEY, INTERVAL BIGINT, DURATION BIGINT, SKILL STRING);""")
            conn.commit()

            print('Writing to file...')
            with open('demand_stats.csv', 'w') as csv_file:
                writer = csv.DictWriter(csv_file, fieldnames=self.demandList[0].keys(), lineterminator="\n")
                writer.writeheader()
                for w_ in self.demandList:
                    writer.writerow(w_)
                    # print(f"""INSERT INTO tblDemand VALUES ({w_['id']}, {w_['interval']}, {w_['duration']},'{w_['skill']}');""")
                    # crsr.execute(f"""INSERT INTO tblDemand VALUES ({w_['id']}, {w_['interval']}, {w_['duration']},'{w_['skill']}');""")
            conn.commit()

            crsr.execute("""DROP TABLE IF EXISTS tblResources;""")
            conn.commit()
            crsr.execute("""CREATE TABLE tblResources (ID BIGINT, SCHEDULE TINYINT, UTILIZATION BIGINT, SKILLS STRING);""")
            conn.commit()

            toolbar_width = 40
            pb = ProgressBar(toolbar_width=toolbar_width)
            with open('resource_stats.csv', 'w') as csv_file:
                writer = csv.DictWriter(csv_file, fieldnames=['id', 'interval', 'schedule', 'utilization'], lineterminator="\n")
                writer.writeheader()
                for k, w_ in enumerate(self.resourceList):
                    # print(f"""INSERT INTO tblResources VALUES ({w_['id']}, '{w_['skills'][0]}');""")
                    # crsr.execute(f"""INSERT INTO tblResources VALUES ({w_['id']}, '{w_['skills'][0]}');""")
                    pb.update(k, len(self.resourceList))
                    for i_ in range(self.NUM_INTERVALS):
                        row = {'id': w_['id'], 'interval': str(i_), 'schedule': w_['schedule'][i_], 'utilization': w_['utilization'][i_]}
                        # crsr.execute(f"""INSERT INTO tblResources VALUES ({w_['id']}, {w_['schedule'][i_]}, {w_['utilization'][i_]}, '{w_['skills'][0]}');""")
                        writer.writerow(row)
            pb.update(1, 1)
            pb.clean()
            conn.commit()
            conn.close()