22from random import random
33import os
44from csv import writer
5+ from math import isinf
56
67import networkx as nx
78
@@ -42,6 +43,7 @@ def __init__(self, id_, simulation):
4243 self .class_change = node .class_change_matrix
4344 self .individuals = [[] for _ in
4445 range (simulation .number_of_priority_classes )]
46+ self .number_of_individuals = 0
4547 self .id_number = id_
4648 self .baulking_functions = [self .simulation .network .customer_classes [
4749 clss ].baulking_functions [id_ - 1 ] for clss in range (
@@ -52,7 +54,7 @@ def __init__(self, id_, simulation):
5254 else :
5355 self .next_event_date = float ("Inf" )
5456 self .blocked_queue = []
55- if self .c < float ( 'Inf' ):
57+ if not isinf ( self .c ):
5658 self .servers = self .create_starting_servers ()
5759 self .highest_id = self .c
5860 self .simulation .deadlock_detector .initialise_at_node (self )
@@ -66,11 +68,6 @@ def all_individuals(self):
6668 return [i for priority_class in self .individuals
6769 for i in priority_class ]
6870
69- @property
70- def number_of_individuals (self ):
71- return len (self .all_individuals )
72-
73-
7471 def __repr__ (self ):
7572 """
7673 Representation of a node.
@@ -87,6 +84,7 @@ def accept(self, next_individual, current_time):
8784 next_individual , current_time )
8885 next_individual .queue_size_at_arrival = self .number_of_individuals
8986 self .individuals [next_individual .priority_class ].append (next_individual )
87+ self .number_of_individuals += 1
9088 self .simulation .statetracker .change_state_accept (
9189 self .id_number , next_individual .customer_class )
9290
@@ -106,6 +104,7 @@ def attach_server(self, server, individual):
106104 server .cust = individual
107105 server .busy = True
108106 individual .server = server
107+ server .next_end_service_date = individual .service_end_date
109108 self .simulation .deadlock_detector .action_at_attach_server (
110109 self , server , individual )
111110
@@ -120,24 +119,24 @@ def begin_service_if_possible_accept(self,
120119 next_individual .service_time = self .get_service_time (
121120 next_individual .customer_class , current_time )
122121 if self .free_server ():
123- if self .c < float ('Inf' ):
124- self .attach_server (self .find_free_server (),
125- next_individual )
126122 next_individual .service_start_date = self .get_now (current_time )
127123 next_individual .service_end_date = self .increment_time (
128124 current_time , next_individual .service_time )
125+ if not isinf (self .c ):
126+ self .attach_server (self .find_free_server (),
127+ next_individual )
129128
130129 def begin_interrupted_individuals_service (self , current_time , srvr ):
131130 """
132131 Restarts the next interrupted individual's service (by
133- resampking service time)
132+ resampling service time)
134133 """
135134 ind = [i for i in self .interrupted_individuals ][0 ]
136- self .attach_server (srvr , ind )
137135 ind .service_time = self .get_service_time (ind .customer_class ,
138136 current_time )
139137 ind .service_end_date = self .increment_time (self .get_now (current_time ),
140138 ind .service_time )
139+ self .attach_server (srvr , ind )
141140 self .interrupted_individuals .remove (ind )
142141
143142 def begin_service_if_possible_change_shift (self , current_time ):
@@ -151,26 +150,26 @@ def begin_service_if_possible_change_shift(self, current_time):
151150 self .begin_interrupted_individuals_service (current_time , srvr )
152151 elif len ([i for i in self .all_individuals if not i .server ]) > 0 :
153152 ind = [i for i in self .all_individuals if not i .server ][0 ]
154- self .attach_server (srvr , ind )
155153 ind .service_start_date = self .get_now (current_time )
156154 ind .service_end_date = self .increment_time (
157155 ind .service_start_date , ind .service_time )
156+ self .attach_server (srvr , ind )
158157
159158 def begin_service_if_possible_release (self , current_time ):
160159 """
161160 Begins the service of the next individual, giving
162161 that customer a service time, end date and node.
163162 """
164- if self .free_server () and self .c != float ( 'Inf' ):
163+ if self .free_server () and ( not isinf ( self .c ) ):
165164 srvr = self .find_free_server ()
166165 if len (self .interrupted_individuals ) > 0 :
167166 self .begin_interrupted_individuals_service (current_time , srvr )
168167 elif len ([i for i in self .all_individuals if not i .server ]) > 0 :
169168 ind = [i for i in self .all_individuals if not i .server ][0 ]
170- self .attach_server (srvr , ind )
171169 ind .service_start_date = self .get_now (current_time )
172170 ind .service_end_date = self .increment_time (
173171 ind .service_start_date , ind .service_time )
172+ self .attach_server (srvr , ind )
174173
175174 def block_individual (self , individual , next_node ):
176175 """
@@ -203,7 +202,7 @@ def change_shift(self):
203202 Add servers and deletes or indicates which servers
204203 should go off duty.
205204 """
206- shift = self .next_event_date % self .cyclelength
205+ shift = self .next_event_date % self .cyclelength
207206
208207 try : indx = self .schedule .index (shift )
209208 except :
@@ -254,7 +253,7 @@ def free_server(self):
254253 """
255254 Returns True if a server is available, False otherwise
256255 """
257- if self .c == float ( 'Inf' ):
256+ if isinf ( self .c ):
258257 return True
259258 return len ([svr for svr in self .servers if not svr .busy ]) > 0
260259
@@ -270,9 +269,8 @@ def find_next_individual(self):
270269 """
271270 Finds the next individual that should now finish service
272271 """
273- next_individual_indices = [i for i , x in enumerate (
274- [ind .service_end_date for ind in self .all_individuals ]
275- ) if x == self .next_event_date ]
272+ next_individual_indices = [i for i , ind in enumerate (
273+ self .all_individuals ) if ind .service_end_date == self .next_event_date ]
276274 if len (next_individual_indices ) > 1 :
277275 next_individual_index = random_choice (next_individual_indices )
278276 else :
@@ -283,7 +281,7 @@ def find_server_utilisation(self):
283281 """
284282 Finds the overall server utilisation for the node
285283 """
286- if self .c == float ( 'Inf' ) or self .c == 0 :
284+ if isinf ( self .c ) or self .c == 0 :
287285 self .server_utilisation = None
288286 else :
289287 for server in self .servers :
@@ -299,7 +297,9 @@ def finish_service(self):
299297 self .change_customer_class (next_individual )
300298 next_node = self .next_node (next_individual .customer_class )
301299 next_individual .destination = next_node .id_number
302- if len (next_node .all_individuals ) < next_node .node_capacity :
300+ if not isinf (self .c ):
301+ next_individual .server .next_end_service_date = float ('Inf' )
302+ if next_node .number_of_individuals < next_node .node_capacity :
303303 self .release (next_individual_index , next_node ,
304304 self .next_event_date )
305305 else :
@@ -352,9 +352,10 @@ def release(self, next_individual_index, next_node, current_time):
352352 """
353353 next_individual = self .all_individuals [next_individual_index ]
354354 self .individuals [next_individual .prev_priority_class ].remove (next_individual )
355- next_individual .queue_size_at_departure = len (self .all_individuals )
355+ self .number_of_individuals -= 1
356+ next_individual .queue_size_at_departure = self .number_of_individuals
356357 next_individual .exit_date = current_time
357- if self .c < float ( 'Inf' ):
358+ if not isinf ( self .c ):
358359 self .detatch_server (next_individual .server , next_individual )
359360 self .write_individual_record (next_individual )
360361 self .simulation .statetracker .change_state_release (self .id_number ,
@@ -419,10 +420,14 @@ def update_next_event_date(self, current_time):
419420 """
420421 Finds the time of the next event at this node
421422 """
422- next_end_service = min ([ind .service_end_date
423- for ind in self .all_individuals
424- if not ind .is_blocked
425- if ind .service_end_date >= current_time ] + [float ("Inf" )])
423+ if not isinf (self .c ):
424+ next_end_service = min ([s .next_end_service_date
425+ for s in self .servers ] + [float ("Inf" )])
426+ else :
427+ next_end_service = min ([ind .service_end_date
428+ for ind in self .all_individuals
429+ if not ind .is_blocked
430+ if ind .service_end_date >= current_time ] + [float ("Inf" )])
426431 if self .schedule :
427432 next_shift_change = self .next_shift_change
428433 self .next_event_date = min (
@@ -435,7 +440,7 @@ def wrap_up_servers(self, current_time):
435440 Updates the servers' total_time and busy_time
436441 as the end of the simulation run.
437442 """
438- if self .c != float ( 'Inf' ):
443+ if not isinf ( self .c ):
439444 for srvr in self .servers :
440445 srvr .total_time = self .increment_time (current_time , - srvr .start_date )
441446 if srvr .busy :
@@ -458,15 +463,19 @@ def write_individual_record(self, individual):
458463 - Queue size at arrival
459464 - Queue size at departure
460465 """
461- record = DataRecord (individual .arrival_date ,
462- individual .service_end_date ,
463- individual .service_start_date ,
464- individual .exit_date ,
465- self .id_number ,
466- individual .destination ,
467- individual .previous_class ,
468- individual .queue_size_at_arrival ,
469- individual .queue_size_at_departure )
466+ record = DataRecord (individual .id_number ,
467+ individual .previous_class ,
468+ self .id_number ,
469+ individual .arrival_date ,
470+ individual .service_start_date - individual .arrival_date ,
471+ individual .service_start_date ,
472+ individual .service_end_date - individual .service_start_date ,
473+ individual .service_end_date ,
474+ individual .exit_date - individual .service_end_date ,
475+ individual .exit_date ,
476+ individual .destination ,
477+ individual .queue_size_at_arrival ,
478+ individual .queue_size_at_departure )
470479 individual .data_records .append (record )
471480
472481 individual .arrival_date = False
0 commit comments