Skip to content

Commit 2aed14c

Browse files
Merge pull request #128 from CiwPython/server_overtime
Server overtime
2 parents 0248170 + 37159a8 commit 2aed14c

4 files changed

Lines changed: 57 additions & 0 deletions

File tree

ciw/node.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def __init__(self, id_, simulation):
4848
self.simulation.network.number_of_classes)]
4949
if self.schedule:
5050
self.next_event_date = self.next_shift_change
51+
self.overtime = []
5152
else:
5253
self.next_event_date = float("Inf")
5354
self.blocked_queue = []
@@ -330,6 +331,8 @@ def kill_server(self, srvr):
330331
Kills server.
331332
"""
332333
srvr.total_time = self.increment_time(self.next_event_date, -srvr.start_date)
334+
self.overtime.append(
335+
self.increment_time(self.next_event_date, -srvr.shift_end))
333336
self.all_servers_busy.append(srvr.busy_time)
334337
self.all_servers_total.append(srvr.total_time)
335338
indx = self.servers.index(srvr)
@@ -394,13 +397,15 @@ def take_servers_off_duty(self):
394397
if not self.preempt:
395398
to_delete = []
396399
for srvr in self.servers:
400+
srvr.shift_end = self.next_event_date
397401
if srvr.busy:
398402
srvr.offduty = True
399403
else:
400404
to_delete.append(srvr)
401405
else:
402406
to_delete = self.servers[::1] # copy
403407
for s in self.servers:
408+
s.shift_end = self.next_event_date
404409
if s.cust is not False:
405410
self.interrupted_individuals.append(s.cust)
406411
self.interrupted_individuals[-1].service_end_date = False

ciw/server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def __init__(self, node, id_number, start_date=0.0):
1717
self.start_date = start_date
1818
self.busy_time = False
1919
self.total_time = False
20+
self.shift_end = False
2021

2122
@property
2223
def utilisation(self):

ciw/tests/test_scheduling.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import unittest
22
import ciw
3+
from decimal import Decimal
4+
35

46
class TestScheduling(unittest.TestCase):
57

@@ -251,3 +253,30 @@ def test_full_preemptive_simulation(self):
251253
# finishing at time 12.5 (total: 9.5 time units). Then server goes off duty
252254
# for 4.5 time units (total: 14 time units). Then resample service time and
253255
# get serviced for another 10 time units (total: 24 time units).
256+
257+
258+
def test_overtime(self):
259+
N = ciw.create_network(
260+
Arrival_distributions=[['Sequential', [1.0, 0.0, 0.0, 8.0, 0.0, 3.0, 10000.0]]],
261+
Service_distributions=[['Sequential', [5.0, 7.0, 9.0, 4.0, 5.0, 5.0]]],
262+
Number_of_servers=[([[3, 7.0], [2, 11.0], [1, 20.0]], False)]
263+
)
264+
Q = ciw.Simulation(N)
265+
Q.simulate_until_max_time(19.0)
266+
267+
nd = Q.transitive_nodes[0]
268+
self.assertEqual(nd.overtime, [0.0, 1.0, 3.0, 2.0, 3.0])
269+
self.assertEqual(sum(nd.overtime)/len(nd.overtime), 1.8)
270+
271+
def test_overtime_exact(self):
272+
N = ciw.create_network(
273+
Arrival_distributions=[['Sequential', [1.0, 0.0, 0.0, 8.0, 0.0, 3.0, 10000.0]]],
274+
Service_distributions=[['Sequential', [5.0, 7.0, 9.0, 4.0, 5.0, 5.0]]],
275+
Number_of_servers=[([[3, 7.0], [2, 11.0], [1, 20.0]], False)]
276+
)
277+
Q = ciw.Simulation(N, exact=26)
278+
Q.simulate_until_max_time(19.0)
279+
280+
nd = Q.transitive_nodes[0]
281+
self.assertEqual(nd.overtime, [Decimal('0.0'), Decimal('1.0'), Decimal('3.0'), Decimal('2.0'), Decimal('3.0')])
282+
self.assertEqual(sum(nd.overtime)/len(nd.overtime), Decimal('1.8'))

docs/Guides/server_schedule.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,25 @@ Ciw defaults to non-pre-emptive schedules, and so the following code implies a n
6868

6969
Number_of_servers=[[[2, 10], [0, 30], [1, 100]]] # non-preemptive
7070

71+
72+
73+
Overtime
74+
--------
75+
76+
Non-preemptive schedules allow for the possibility of overtime, that is servers working after their shift has ended in order to complete a customer's service.
77+
The amount of overtime each server works is recorded in the Node object's :code:`overtime` attribute.
78+
Consider the following example::
79+
80+
>>> import ciw
81+
>>> N = ciw.create_network(
82+
... Arrival_distributions=[['Deterministic', 3.0]],
83+
... Service_distributions=[['Deterministic', 5.0]],
84+
... Number_of_servers=[[[1, 4.0], [2, 10.0], [0, 100.0]]]
85+
... )
86+
>>> Q = ciw.Simulation(N)
87+
>>> Q.simulate_until_max_time(20.0)
88+
89+
>>> Q.transitive_nodes[0].overtime
90+
[4.0, 1.0, 4.0]
91+
92+
Here we see that the first server that went off duty worked 4.0 time units of overtime, the second worked 1.0 time unit of overtime, and the third worked 4.0 time units of overtime.

0 commit comments

Comments
 (0)