def __init__(self): self.Q = EventQueue() self.T = StatusStructure() self.T1 = StatusStructure() self.T2 = StatusStructure() self.intersections = [] self.vertices = [] self.halfedges = [] self.faces = [] self.face1 = [] self.face2 = [] self.cycles = [CycleNode(cycle=None, inf_outer=True)]
class FindIntersections(): def __init__(self): self.Q = EventQueue() self.T = StatusStructure() self.intersections = [] def find_intersections(self, lines): for line in lines: self.Q.insert_line(line) while not self.Q.is_empty(): next_event = self.Q.pop_next_event() self.handle_event_point(next_event) def handle_event_point(self, p): U_p = p.lines L_p, C_p, L_C = self.T.find_segments_contain(p.point) U_C = U_p + C_p L_U_C = L_C + U_p if len(L_U_C) > 1: self.intersections.append(p.point) for line in L_C: self.T.delete(p.point, line) self.T.insert(p.point, U_C) self.T._print_name() if len(U_C) == 0: s_l = self.T.find_left_neighbor(p.point) s_r = self.T.find_right_neighbor(p.point) self.find_new_event(s_l, s_r, p.point) else: s_lm = self.T.find_leftmost(p.point) s_l = self.T.find_left_neighbor(p.point) self.find_new_event(s_lm, s_l, p.point) s_rm = self.T.find_rightmost(p.point) s_r = self.T.find_right_neighbor(p.point) self.find_new_event(s_rm, s_r, p.point) def find_new_event(self, s_l, s_r, p): if s_l is None or s_r is None: return i = s_l.intersect(s_r) if i is None: return x_i, y_i = i x_p, y_p = p if y_i < y_p or (y_i == y_p and x_i > x_p): self.Q.insert(i)
class MapOverlay: def __init__(self): self.Q = EventQueue() self.T = StatusStructure() self.T1 = StatusStructure() self.T2 = StatusStructure() self.intersections = [] self.vertices = [] self.halfedges = [] self.faces = [] self.face1 = [] self.face2 = [] self.cycles = [CycleNode(cycle=None, inf_outer=True)] def find_intersections(self, halfedges): for he in halfedges: self.Q.insert_he(he) while not self.Q.is_empty(): next_event = self.Q.pop_next_event() self.handle_event_point(next_event) def handle_event_point(self, p): def assign_pointer(hedges): root = hedges[0] sorted_hedges = [] dcel1_hedges = [hedge for hedge in hedges if hedge.belong_to == root.belong_to] dcel2_hedges = [hedge for hedge in hedges if hedge.belong_to != root.belong_to] i1 = i2 = 0 i = 1 while i < len(dcel2_hedges): if root.clockwise_angle(dcel2_hedges[i]) < root.clockwise_angle(dcel2_hedges[i-1]): break i += 1 dcel2_hedges = dcel2_hedges[i:] + dcel2_hedges[:i] while (i1 + i2) < len(hedges): if i1 == len(dcel1_hedges): sorted_hedges.extend(dcel2_hedges[i2:]) break elif i2 == len(dcel2_hedges): sorted_hedges.extend(dcel1_hedges[i1:]) break if root.clockwise_angle(dcel1_hedges[i1]) < root.clockwise_angle(dcel2_hedges[i2]): sorted_hedges.append(dcel1_hedges[i1]) i1 += 1 else: sorted_hedges.append(dcel2_hedges[i2]) i2 += 1 for i in range(0, len(sorted_hedges)-1): c_he = sorted_hedges[i] n_he = sorted_hedges[i+1] c_he.twin.set_next(n_he) c_he = sorted_hedges[-1] n_he = sorted_hedges[0] c_he.twin.set_next(n_he) U_p = p.segments_u L_p, C_p, L_C = self.T.find_segments_contain(p.point) U_C = U_p + C_p L_U_C = L_C + U_p if len(L_U_C) > 1: self.intersections.append(p.point) for segment in L_C: self.T.delete(p.point, segment) if segment.belong_to == 'dcel1' and p.point.belong_to == 'dcel1': self.T1.delete(p.point, segment) if segment.belong_to == 'dcel2' and p.point.belong_to == 'dcel2': self.T2.delete(p.point, segment) self.T.insert(p.point, U_C) if p.point.belong_to == 'dcel1': self.T1.insert(p.point, [s for s in U_C if s.belong_to == 'dcel1']) if p.point.belong_to == 'dcel2': self.T2.insert(p.point, [s for s in U_C if s.belong_to == 'dcel2']) if not p.point.involves_both: if p.point.belong_to == 'dcel1': d2_left_he = self.T2.find_left_neighbor(p.point) if d2_left_he is None: p.point.face_contain = None else: p.point.face_contain = d2_left_he.halfedge.incident_face else: d1_left_he = self.T1.find_left_neighbor(p.point) if d1_left_he is None: p.point.face_contain = None else: p.point.face_contain = d1_left_he.halfedge.incident_face if len(U_C) == 0: s_l = self.T.find_left_neighbor(p.point) s_r = self.T.find_right_neighbor(p.point) self.find_new_event(s_l, s_r, p.point) else: s_lm = self.T.find_leftmost(p.point) s_l = self.T.find_left_neighbor(p.point) self.find_new_event(s_lm, s_l, p.point) s_rm = self.T.find_rightmost(p.point) s_r = self.T.find_right_neighbor(p.point) self.find_new_event(s_rm, s_r, p.point) if p.point.involves_both: assign_pointer(p.halfedges) p.point.incident_edge = p.halfedges[0] self.vertices.append(p.point) p.point.left_hedge = s_l.halfedge if s_l is not None else None def find_new_event(self, s_l, s_r, p): def add_new_he(new_l, s_l, i): h_newl = HalfEdge(origin=i) h_sl = HalfEdge(origin=i) h_newl.belong_to = new_l.belong_to h_sl.belong_to = s_l.belong_to h_newl.copy_next(s_l.halfedge) h_sl.copy_next(s_l.halfedge.twin) h_newl.set_twin(s_l.halfedge.twin) h_sl.set_twin(s_l.halfedge) new_l.set_halfedge(h_newl) return h_sl, h_newl if s_l is None or s_r is None: return i = s_l.intersect(s_r) if i is None: return x_i, y_i = i.coordinates x_p, y_p = p.coordinates if y_i < y_p or (y_i == y_p and x_i > x_p): segments=[] he_w_origin_i = [] if s_l.lower_endpoint != i and s_l.upper_endpoint != i: new_l = Segment(s_l.lower_endpoint, i) new_l.belong_to = s_l.belong_to s_l.lower_endpoint = i segments.append(new_l) h1, h2 = add_new_he(new_l, s_l, i) he_w_origin_i.extend([h1, h2]) self.halfedges.extend([h1, h2]) if s_r.lower_endpoint != i and s_r.upper_endpoint != i: new_r = Segment(s_r.lower_endpoint, i) new_r.belong_to = s_r.belong_to s_r.lower_endpoint = i segments.append(new_r) h1, h2 = add_new_he(new_r, s_r, i) he_w_origin_i.extend([h1, h2]) self.halfedges.extend([h1, h2]) self.Q.insert(i, segments=segments, hedges=he_w_origin_i) def plot(self, halfedges): for he in halfedges: x = he.origin y = he.next.origin if he.belong_to == he[0].belong_to: plt.plot((x.coordinates[0], y.coordinates[0]), (x.coordinates[1], y.coordinates[1]), 'ro-') else: plt.plot((x.coordinates[0], y.coordinates[0]), (x.coordinates[1], y.coordinates[1]), 'bo-') for point in self.intersections: plt.plot(point.coordinates[0], point.coordinates[1], marker='x', markersize=10, color="blue") plt.show() def detect_cycle(self): he_set = set(self.halfedges) while len(he_set) != 0: first_he = he_set.pop() current_cycle = [first_he] current_he = first_he while current_he.next != first_he: current_he = current_he.next he_set.remove(current_he) current_cycle.append(current_he) self.cycles.append(CycleNode(current_cycle)) for cycle in self.cycles: if cycle.is_inner_boundary: left_hedge = cycle.find_leftmost_he().next.origin.left_hedge outer_cycle = left_hedge.cycle if left_hedge is not None else self.cycles[0] outer_cycle.links.append(cycle) def compute_faces(self): outer_cycles = [cycle for cycle in self.cycles if not cycle.is_inner_boundary] for outer_cycle in outer_cycles: face = Face() face.outer_component = outer_cycle.cycle[0] if len(outer_cycle.cycle) != 0 else None for inner_cycle in outer_cycle.links: face.inner_components.append(inner_cycle.cycle[0]) face.cycle = outer_cycle self.faces.append(face) he_list = outer_cycle.cycle if len(outer_cycle.cycle) != 0 else outer_cycle.links[0].cycle he_list.append(he_list[0]) for i in range(len(he_list) - 1): prev_hedge = he_list[i] current_hedge = he_list[i+1] if current_hedge.origin.involves_both and prev_hedge.incident_face.belong_to != current_hedge.incident_face.belong_to: f1 = prev_hedge.incident_face.name f2 = current_hedge.incident_face.name face.name = str(f1) + '.' + str(f2) break if face.name is None: he = face.outer_component if face.outer_component is not None else face.inner_components[0] v = he.origin f1 = he.incident_face.name if v.face_contain is None: if v.belong_to == 'dcel1': f2 = [f for f in self.face2 if f.outer_component is None][0].name else: f2 = [f for f in self.face1 if f.outer_component is None][0].name else: f2 = v.face_contain.name face.name = str(f1) + '.' + str(f2) outer_cycle = face.cycle for hedge in outer_cycle.cycle: hedge.incident_face = face for inner_cycle in outer_cycle.links: for hedge in inner_cycle.cycle: hedge.incident_face = face def get_dcel(self): return DCEL(self.vertices, self.halfedges, self.faces) def calculate(self, dcel1, dcel2, plot = False): dcel1.set_name('dcel1') dcel2.set_name('dcel2') h = dcel1.halfedges + dcel2.halfedges self.face1 = dcel1.faces if self.face1[0].name is None: for index, f in enumerate(self.face1): f.name = 'f_'+str(index) self.face2 = dcel2.faces if self.face2[0].name is None: for index, f in enumerate(self.face2): f.name = 'g_'+str(index) if plot: _, ax = plt.subplots(nrows=1, ncols=3) dcel1.plot_dcel(ax[0]) dcel2.plot_dcel(ax[1]) start_time = time.time() self.halfedges = h self.find_intersections(h) print('Find intersection: ', time.time() - start_time) self.detect_cycle() print('Detect cycle: ', time.time() - start_time) self.compute_faces() print('Compute faces:', time.time() - start_time) dcel = self.get_dcel() total_time = time.time() - start_time print('Finish:', total_time) if plot: dcel.plot_dcel(ax[2]) plt.show() return dcel, total_time
def __init__(self): self.pool = SampleTree() self.eventQueue = EventQueue() self.__resetCounts()
class Model(object): def __init__(self): self.pool = SampleTree() self.eventQueue = EventQueue() self.__resetCounts() ################################################################## # there are five kinds of rates: # N: (fixed) number of bases in the model # rll: rate for dcj on the bases in the contig pool # rld: rate for dcj where one break is in the pool # and the other rate is in the garbage # rdd: both in garbage # fl: telomere loss modifier # fg: telomere gain modifier # pgain: dead gain probability ################################################################## def setParameters(self, N, rll, rld = 0, rdd = 0, fl = 0, fg = 0, pgain = 0): self.eventQueue.reset() self.N = N self.fl = fl self.fg = fg self.pgain = pgain if rll > 0: self.eventQueue.addEventType(N * rll, self.__llEvent) if rld > 0: self.eventQueue.addEventType(N * rld, self.__ldEvent) if rdd > 0: self.eventQueue.addEventType(N * rdd, self.__ddEvent) ################################################################## # intitialize the starting state # the the contigs will all have the same sizes (modulo rounding) # in order to satisfy the input parameters exactly ################################################################## def setStartingState(self, garbageSize, numLinear, numCircular): assert self.N > garbageSize + numLinear + numCircular self.pool = SampleTree() numGarbage = 0 if garbageSize > 0: garbage = CircularContig(garbageSize) garbage.setDead() self.pool.insert(garbage, garbage.numBases()) numGarbage = 1 lrat = float(numLinear) / (numLinear + numCircular) crat = float(numCircular) / (numLinear + numCircular) linearBases = math.floor((self.N - garbageSize) * lrat) circularBases = math.ceil((self.N - garbageSize) * crat) assert linearBases + circularBases + garbageSize == self.N if numLinear > 0: linSize = math.floor(linearBases / numLinear) extra = linearBases % numLinear added = 0 for i in range(numLinear): size = linSize if i < extra: size += 1 # plus 1 since number of adjacencies is 1 + number of bases contig = LinearContig(size + 1) self.pool.insert(contig, contig.numBases()) added += contig.size assert added == linearBases + numLinear assert self.pool.size() == numLinear + numGarbage assert self.pool.weight() == linearBases + garbageSize if numCircular > 0: circSize = math.floor(circularBases / numCircular) extra = circularBases % numCircular added = 0 for i in range(numCircular): size = circSize if i < extra: size += 1 contig = CircularContig(size) self.pool.insert(contig, contig.numBases()) added += contig.size assert added == circularBases assert self.pool.size() == numLinear + numCircular + numGarbage assert self.pool.weight() == circularBases + linearBases + \ garbageSize ################################################################## # run the simulation for the specified time ################################################################## def simulate(self, time): self.eventQueue.begin() self.__resetCounts() while True: nextEvent = self.eventQueue.next(time) if nextEvent is not None: nextEvent() else: break ################################################################## # draw (and remove) two random adajcenies and their # contigs from the pool (only if they are not dead) ################################################################## def __drawSamples(self): sampleNode1, offset1 = self.pool.uniformSample() sampleNode2, offset2 = self.pool.uniformSample() # the offset is weighted based on the number of bases # we want to translate this into number of edges (splitting) # the probability between linear and telomere edges. # so for linear contigs with zero offset, we flip a coin to # move it to the other side. if sampleNode1.data.isLinear() and offset1 == 0: if random.random() < 0.5: offset1 = sampleNode1.data.numBases() if sampleNode2 is not sampleNode1 and sampleNode2.data.isLinear() and\ offset2 == 0: if random.random() < 0.5: offset2 = sampleNode2.data.numBases() assert offset1 < sampleNode1.data.size assert offset2 < sampleNode2.data.size return (sampleNode1, offset1, sampleNode2, offset2) ################################################################## #LIVE-LIVE event. Is normal DCJ operation between two live contigs #unless the two breakpoints are identical or on telomeres, in which #case fl and fg parameters are used to use fission operations to #modifiy the number of telomeres ################################################################## def __llEvent(self): if self.pool.size() == 0 or self.pool.weight() == 1: return # draw (and remove) two random adajcenies and their #contigs from the pool (only if they are not dead) sampleNode1, offset1, sampleNode2, offset2 = self.__drawSamples() c1 = sampleNode1.data c2 = sampleNode2.data # don't deal with dead contigs in this event if c1.isDead() == True or c2.isDead() == True: return self.pool.remove(sampleNode1) if c1 is not c2: self.pool.remove(sampleNode2) # case 1) gain of telomere if sampleNode1 is sampleNode2 and offset1 == offset2: return self.__llGain(c1, c2, offset1, offset2) # case 2) loss of telomere elif c1.isLinear() and c2.isLinear() and \ (offset1 == 0 or offset1 == c1.size - 1) and \ (offset2 == 0 or offset2 == c2.size - 1): return self.__llLoss(c1, c2, offset1, offset2) # case 3) no gain or loss self.llCount += 1 forward = random.randint(0, 1) == 1 # do the dcj dcjResult = dcj(c1, offset1, c2, offset2, forward) # add the resulting contigs back to the pool for res in dcjResult: self.pool.insert(res, res.numBases()) ################################################################## # Do the fission telomere gain operation (if fg check passes) ################################################################## def __llGain(self, c1, c2, offset1, offset2): # correct "not composite check below" if c1.isCircular() or (offset1 != 0 and offset1 != c1.size - 1): forward = self.fg > random.random() if forward: self.fgCount += 1 dcjResult = dcj(c1, offset1, c2, offset2, forward) if c1.isCircular(): assert len(dcjResult) == 1 and dcjResult[0].isLinear() else: assert len(dcjResult) == 2 and dcjResult[0].isLinear() \ and dcjResult[1].isLinear() # add the resulting contigs back to the pool for res in dcjResult: self.pool.insert(res, res.numBases()) return self.pool.insert(c1, c1.numBases()) if c2 is not c1: self.pool.insert(c2, c2.numBases()) ################################################################## # Do the fission telomer loss operation (if fl check passes) ################################################################## def __llLoss(self, c1, c2, offset1, offset2): if c1 is c2: forward = self.fl / 4.0 > random.random() else: forward = self.fl / 2.0 > random.random() if forward: c1 = c1.circularize() if c1 is not c2: c2 = c2.circularize() dcjResult = dcj(c1, offset1, c2, offset2, forward) self.flCount += 1 assert len(dcjResult) == 1 if c1 is not c2: assert dcjResult[0].isLinear() else: assert dcjResult[0].isCircular() # add the resulting contigs back to the pool for res in dcjResult: self.pool.insert(res, res.numBases()) else: self.pool.insert(c1, c1.numBases()) if c2 is not c1: self.pool.insert(c2, c2.numBases()) ################################################################## #LIVE-DEAD (or DEAD-LIVE) event. One contig is alive and the #other is the unique dead contig. This can result in a loss of #live contigs and/or change in number of live bases ################################################################## def __ldEvent(self): if self.pool.size() == 0 or self.pool.weight() == 1: return # draw (and remove) two random adajcenies and their #contigs from the pool (only if they are not dead) sampleNode1, offset1, sampleNode2, offset2 = self.__drawSamples() c1 = sampleNode1.data c2 = sampleNode2.data # only deal with live / dead contigs in this event if (c1.isDead() == c2.isDead()): return self.pool.remove(sampleNode1) if c1 is not c2: self.pool.remove(sampleNode2) # make sure c1 is alive and c2 is dead if c1.isDead(): c1, c2 = c2, c1 offset1, offset2 = offset2, offset1 # do the dcj dcjResult = dcj(c1, offset1, c2, offset2, random.randint(0, 1) == 1) deadIdx = 0; if len(dcjResult) == 2 and \ random.randint(0, dcjResult[0].size + dcjResult[1].size) >= \ dcjResult[0].size: deadIdx = 1 dcjResult[deadIdx].setDead(True) if len(dcjResult) == 1: self.ldLossCount += 1 else: self.ldSwapCount += 1 # add the resulting contigs back to the pool deadCount = 0 for res in dcjResult: if res.isDead(): deadCount += 1 self.pool.insert(res, res.numBases()) assert deadCount == 1 ################################################################## #DEAD-DEAD event. The dead contig rearranges with itself. pgain #is used to decide how oftern this oepration breaks off a new circular #live chormosome ################################################################## def __ddEvent(self): if self.pool.size() == 0 or self.pool.weight() == 1: return sampleNode1, offset1, sampleNode2, offset2 = self.__drawSamples() c1 = sampleNode1.data c2 = sampleNode2.data # only deal with dead / dead contigs in this event if (c1.isDead() == False or c2.isDead() == False): return # only support single dead contig assert c1 is c2 # don't know what to do here if (offset1 == offset2): return self.pool.remove(sampleNode1) if c1 is not c2: self.pool.remove(sampleNode2) #forward means do not cut forward = random.random() > self.pgain # do the dcj dcjResult = dcj(c1, offset1, c2, offset2, forward) deadIdx = 0; if len(dcjResult) == 2 and \ random.randint(0, dcjResult[0].size + dcjResult[1].size) \ >= dcjResult[0].size: deadIdx = 1 dcjResult[deadIdx].setDead(True) if forward: self.ddSwapCount += 1 assert len(dcjResult) == 1 else: self.ddGainCount += 1 assert len(dcjResult) == 2 assert not dcjResult[0].isDead() or not dcjResult[1].isDead() # add the resulting contigs back to the pool for res in dcjResult: self.pool.insert(res, res.numBases()) ################################################################## # all counters set to zero. ################################################################## def __resetCounts(self): self.llCount = 0 self.fgCount = 0 self.flCount = 0 self.ldLossCount = 0 self.ldSwapCount = 0 self.ddGainCount = 0 self.ddSwapCount = 0
def simulate(self): t = 0 simulationTime = 10000 simulationLimit = 10000 arrivalDataRate = self.utilization / 0.00302 # = (6040 bits / 2e+6 bits/s) s | lastDataPackageTime = 0 maxEventListSize = 1000 roundSize = 2000 # packages processed transientPhaseSize = 2500 #packages processed numberOfRounds = 10 totalSimulationsPackages = (numberOfRounds * roundSize) + transientPhaseSize consumedEvents = [] eventQueue = EventQueue() voiceChannels = [] voiceQueue = [] dataQueue = [] servedPackages = 0 totalDataWaitingTimePerRound = [0] * numberOfRounds WaitingTimeSamplePerRound = [] for i in range(numberOfRounds): WaitingTimeSamplePerRound.append([]) totalDataProcessingTimePerRound = [0] * numberOfRounds ProcessingTimeSamplePerRound = [] for i in range(numberOfRounds): ProcessingTimeSamplePerRound.append([]) totalVoiceWaitingTimePerRound = [0] * numberOfRounds VoiceWaitingTimeSamplePerRound = [] for i in range(numberOfRounds): VoiceWaitingTimeSamplePerRound.append([]) X2PerRound = [ 0.000256 ] * numberOfRounds # voice package processing time is fixed due to voice package size being fixed # T1 = W1 + X1 | T2 = W2 + X2 Nq1PerRound = [0] * numberOfRounds Nq2PerRound = [0] * numberOfRounds voicePackagesProcessedPerRound = [0] * numberOfRounds dataPackagesProcessedPerRound = [0] * numberOfRounds averageVoiceWaitingPerRound = [] averageDataWaitingPerRound = [] averageDataServingTimePerRound = [] transmissions = [{}] * (constants.VOICE_CHANNELS * numberOfRounds) in_service_package = None # Generating voice channels for i in range(constants.VOICE_CHANNELS): voiceChannels.append(VoiceChannel(i)) currentEvent = None currentRound = -1 servedDataPackages = 0 while servedDataPackages < totalSimulationsPackages: #t < simulationTime and len(consumedEvents) < simulationLimit: # print('Served packages: ' + str(servedPackages)) if servedDataPackages > transientPhaseSize: # We're passed transient phase if currentRound != ( (servedDataPackages - transientPhaseSize) // roundSize): currentRound = (servedDataPackages - transientPhaseSize) // roundSize #print(currentRound) #print(servedPackages) #print(roundSize) self.log(str(currentRound)) if currentRound >= 0 and (( (servedDataPackages + 1) - transientPhaseSize) // roundSize) > currentRound: Nq1PerRound[currentRound] = len(dataQueue) Nq2PerRound[currentRound] = len(voiceQueue) self.log('Simulation time\t' + str(t) + 's\nEvent Queue Size:\t' + str(eventQueue.length())) if currentEvent is not None: consumedEvents.append(currentEvent) self.log('Event consumed\t' + str(currentEvent.type)) # treat evt # if the event is a voice package arrival, the package is created and put in the # voice package queue if currentEvent.type == EventType.CREATE_VOICE_PACKAGE: voiceQueue.append( Package(PackageType.VOICE_PACKAGE, currentEvent.source, t, currentEvent.transmission)) self.log('Voice Package from ' + constants.PACKAGE_SOURCE[currentEvent.source] + ' queued') # if the event type means a voice package should be moved from queue to processing # the first package in the queue is removed and we create an event to finish serving it elif currentEvent.type == EventType.VOICE_PACKAGE_PROCESSING: in_service_package = voiceQueue.pop(0) in_service_package.startServingTime = t if currentRound >= 0: totalVoiceWaitingTimePerRound[currentRound] += ( in_service_package.startServingTime - in_service_package.arrivalTime) VoiceWaitingTimeSamplePerRound[currentRound].append( in_service_package.startServingTime - in_service_package.arrivalTime) # only for plot purpose averageDataServingTimePerRound.append( sum(totalDataProcessingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) averageVoiceWaitingPerRound.append( sum(totalVoiceWaitingTimePerRound) / (sum(voicePackagesProcessedPerRound) + 1)) averageDataWaitingPerRound.append( sum(totalDataWaitingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) eventQueue.add( Event( t + (in_service_package.size / float(constants.CHANNEL_SIZE)), EventType.VOICE_PACKAGE_SERVED, in_service_package.source, in_service_package.transmission)) self.log( 'Voice Package from ' + constants.PACKAGE_SOURCE[in_service_package.source] + 'is in the router') # if the event is a voice package finishing being served we clear the router/server elif currentEvent.type == EventType.VOICE_PACKAGE_SERVED: self.log( 'Voice Package from ' + constants.PACKAGE_SOURCE[in_service_package.source] + ' has finished serving') if currentRound >= 0: voicePackagesProcessedPerRound[currentRound] += 1 servedPackages += 1 if currentRound >= 0 and in_service_package.transmission in transmissions[ (in_service_package.source - 1) + (currentRound * constants.VOICE_CHANNELS)].keys(): transmission = transmissions[ (in_service_package.source - 1) + (currentRound * constants.VOICE_CHANNELS)][ in_service_package.transmission] transmission.processedPackages += 1 if transmission.size < transmission.processedPackages: transmission.endTime = t in_service_package = None # if the event is a data package arrival, the package is created and put in the # data package queue elif currentEvent.type == EventType.CREATE_DATA_PACKAGE: dataQueue.append( Package(PackageType.DATA_PACKAGE, currentEvent.source, t, currentEvent.transmission)) self.log('Data Package from ' + constants.PACKAGE_SOURCE[currentEvent.source] + ' with size ' + str(dataQueue[len(dataQueue) - 1].size) + ' queued') # here we also create the next data package # if the event type means a data package should be moved from queue to processing # the first package in the queue is removed and we create an event to finish serving it elif currentEvent.type == EventType.DATA_PACKAGE_PROCESSING: in_service_package = dataQueue.pop(0) in_service_package.startServingTime = t if currentRound >= 0: totalDataWaitingTimePerRound[currentRound] += ( in_service_package.startServingTime - in_service_package.arrivalTime) WaitingTimeSamplePerRound[currentRound].append( in_service_package.startServingTime - in_service_package.arrivalTime) # only for plot purpose averageDataServingTimePerRound.append( sum(totalDataProcessingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) averageVoiceWaitingPerRound.append( sum(totalVoiceWaitingTimePerRound) / (sum(voicePackagesProcessedPerRound) + 1)) averageDataWaitingPerRound.append( sum(totalDataWaitingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) evt = Event( t + (in_service_package.size / float(constants.CHANNEL_SIZE)), EventType.DATA_PACKAGE_SERVED, in_service_package.source, in_service_package.transmission) if self.preemptive: evt.package_reference = in_service_package eventQueue.add(evt) self.log( 'Data Package from ' + constants.PACKAGE_SOURCE[in_service_package.source] + ' with size ' + str(in_service_package.size) + ' is in the router') # if the event is a data package finishing being served we clear the router/server elif currentEvent.type == EventType.DATA_PACKAGE_SERVED: self.log( 'Data Package from ' + constants.PACKAGE_SOURCE[in_service_package.source] + ' with size ' + str(in_service_package.size) + ' has finished serving') in_service_package.endServingTime = t if currentRound >= 0: totalDataProcessingTimePerRound[currentRound] += ( in_service_package.endServingTime - in_service_package.startServingTime) dataPackagesProcessedPerRound[currentRound] += 1 ProcessingTimeSamplePerRound[currentRound].append( in_service_package.endServingTime - in_service_package.startServingTime) # only for plot purpose averageDataServingTimePerRound.append( sum(totalDataProcessingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) averageVoiceWaitingPerRound.append( sum(totalVoiceWaitingTimePerRound) / (sum(voicePackagesProcessedPerRound) + 1)) averageDataWaitingPerRound.append( sum(totalDataWaitingTimePerRound) / (sum(dataPackagesProcessedPerRound) + 1)) servedPackages += 1 servedDataPackages += 1 in_service_package = None # Note: altough voice and data events could be treated together, the separation will make # things easier to track and change for the preemptive scenario if self.preemptive: if len( voiceQueue ) > 0 and in_service_package is not None and in_service_package.type == PackageType.DATA_PACKAGE: totalDataProcessingTimePerRound[currentRound] += ( t - in_service_package.startServingTime) ProcessingTimeSamplePerRound[currentRound].append( t - in_service_package.startServingTime) pkg = Package(PackageType.DATA_PACKAGE, 0, t + 0.000256, 0) pkg.size = in_service_package.size # - (( t - in_service_package.startServingTime ) * constants.CHANNEL_SIZE) dataQueue.insert(0, pkg) eventQueue.remove_with_package(in_service_package) in_service_package = None if pkg.size < 0: print("ERROR SIZE") # if there's no package being processed if in_service_package is None: # we check if there's any voice packages waiting to be processed if len(voiceQueue) > 0: eventQueue.add( Event(t, EventType.VOICE_PACKAGE_PROCESSING, voiceQueue[0].source, voiceQueue[0].transmission)) # in case there's no voice package to be processed we check if there's any data package # to process # Note: this is due to the fact voice packages have the priority elif len(dataQueue) > 0: eventQueue.add( Event(t, EventType.DATA_PACKAGE_PROCESSING, 0, 0)) # Generate voice arrivals self.log('==================================') for i in range(len(voiceChannels)): if t >= voiceChannels[ i].nextTransmission: # and eventQueue.length() < maxEventListSize: evtTimes = voiceChannels[i].getEventTimes(t)[1:] transmissionId = 0 if currentRound >= 0 and len(evtTimes) > 0: transmission = Transmission(evtTimes[0], 0, (len(evtTimes) - 1), 0) transmissionId = len( transmissions[i + (currentRound * constants.VOICE_CHANNELS)].keys()) transmissions[i + (currentRound * constants.VOICE_CHANNELS )][transmissionId] = transmission for evtTime in evtTimes: evt = Event(evtTime + t, EventType.CREATE_VOICE_PACKAGE, i + 1, transmissionId) # self.log('Voice evt added in ' + str(evt.eventTime) + 's', 0.005) eventQueue.add(evt) self.log('==================================') # Generate data arrivals if t >= lastDataPackageTime: evtTime = lastDataPackageTime + np.random.exponential( 1 / arrivalDataRate) eventQueue.add( Event(evtTime, EventType.CREATE_DATA_PACKAGE, 0, 0)) lastDataPackageTime = evtTime self.log('Data evt added in ' + str(evtTime) + 's') #print('Data evt added in ' + str(evtTime) + 's') # self.log('---------') # for i in range(eventQueue.length()): # self.log(str(eventQueue.get(i).type) + ' ' + str(eventQueue.get(i).eventTime)) # self.log('---------') # getting next event in simulation time and setting simulation time to event's time currentEvent = eventQueue.pop() # self.log('--------- next event ---------') # self.log(str(currentEvent.type) + ' ' + str(currentEvent.eventTime)) # self.log('---------') t = currentEvent.eventTime # GENERATE STATISTICS finalW1 = 0 finalStdW1 = 0 finalW2 = 0 finalStdW2 = 0 finalX1 = 0 finalStdX1 = 0 finalX2 = 0 finalStdX2 = 0 finalT1 = 0 finalStdT1 = 0 finalT2 = 0 finalStdT2 = 0 finalNq1 = 0 finalStdNq1 = 0 finalNq2 = 0 finalStdNq2 = 0 delta = 0 if (self.PLOT): if (not (os.path.exists("images"))): os.mkdir("images") plt.plot(averageDataWaitingPerRound) plt.ylabel('E[W1]') plt.ylabel('Pacotes servidos') plt.title("V.A. W1 com valor rho1 = " + str(self.utilization)) plt.xlim(xmax=servedPackages) plt.savefig('images/W1-' + str(self.utilization) + '.png') plt.clf() plt.plot(averageDataServingTimePerRound) plt.ylabel('E[X1]') plt.ylabel('Pacotes servidos') plt.title("V.A. X1 com valor rho1 = " + str(self.utilization)) plt.xlim(xmax=servedPackages) plt.savefig('images/X1-' + str(self.utilization) + '.png') plt.clf() plt.plot(averageVoiceWaitingPerRound) plt.ylabel('E[W2]') plt.ylabel('Pacotes servidos') plt.title("V.A. W2 com valor rho1 = " + str(self.utilization)) plt.xlim(xmax=servedPackages) plt.savefig('images/W2-' + str(self.utilization) + '.png') plt.clf() stdW1perRound = [] stdW2perRound = [] stdX1perRound = [] stdX2perRound = [] stdT1perRound = [] stdT2perRound = [] stdNq1perRound = [] stdNq2perRound = [] for i in range(numberOfRounds): W1 = totalDataWaitingTimePerRound[ i] / dataPackagesProcessedPerRound[i] X1 = totalDataProcessingTimePerRound[ i] / dataPackagesProcessedPerRound[i] T1 = X1 + W1 stdT1perRound.append(T1) W2 = totalVoiceWaitingTimePerRound[ i] / voicePackagesProcessedPerRound[i] X2 = X2PerRound[i] T2 = X2 + W2 stdT2perRound.append(T2) #print('Round ' + str(i) + ':\nW1: ' + str(W1) + '\tX1: ' + str(X1) + '\tT1: ' + str(T1)) #print('W2: ' + str(W2) + '\tX2: ' + str(X2) + '\tT2: ' + str(T2) + '\n') dt = 0 dt2 = 0 dts = [0] * constants.VOICE_CHANNELS for j in range(len(transmissions) // constants.VOICE_CHANNELS): for k in transmissions[j + (i * constants.VOICE_CHANNELS)].keys(): transmission = transmissions[ j + (i * constants.VOICE_CHANNELS)].get(k) if transmission.endTime > 0: dt += ( (transmission.endTime - transmission.startTime) / (len(transmissions[j + (i * constants.VOICE_CHANNELS)]) - 1)) dts[j] = dt for j in range(len(transmissions) // constants.VOICE_CHANNELS): for k in transmissions[j + (i * constants.VOICE_CHANNELS)].keys(): transmission = transmissions[ j + (i * constants.VOICE_CHANNELS)].get(k) if transmission.endTime > 0: dt2 += ( ((transmission.endTime - transmission.startTime) - dts[j])**2) / (len(transmissions[ j + (i * constants.VOICE_CHANNELS)]) - 1) finalW1 += W1 / numberOfRounds stdW1perRound.append(std(WaitingTimeSamplePerRound[i])) finalW2 += W2 / numberOfRounds stdW2perRound.append(std(VoiceWaitingTimeSamplePerRound[i])) finalX1 += X1 / numberOfRounds stdX1perRound.append(std(ProcessingTimeSamplePerRound[i])) finalX2 += X2 / numberOfRounds finalT1 += T1 / numberOfRounds finalT2 += T2 / numberOfRounds finalNq1 += dataPackagesProcessedPerRound[i] / numberOfRounds finalNq2 += voicePackagesProcessedPerRound[i] / numberOfRounds dt /= (constants.M1 * numberOfRounds) dt2 /= (constants.M2 / (constants.M3 * self.utilization) * numberOfRounds) finalNq1 = arrivalDataRate * finalW1 finalNq2 = constants.VOICE_PACKAGE_ARRIVAL_RATE * finalW2 finalStdW1 = std(stdW1perRound) finalStdW2 = std(stdW2perRound) finalStdX1 = std(stdX1perRound) finalStdX2 = std(X2PerRound) finalStdNq1 = std(dataPackagesProcessedPerRound) finalStdNq2 = std(voicePackagesProcessedPerRound) finalStdT1 = std(stdT1perRound) finalStdT2 = std(stdT2perRound) print('E[W1]: ' + str(finalW1)) print('Std[W1]: ' + str(finalStdW1)) print('IC para W1: ' + str(stats.norm.interval(0.9, loc=finalW1, scale=finalStdW1))) print('E[W2]: ' + str(finalW2)) print('Std[W2]: ' + str(finalStdW2)) print('IC para W2: ' + str(stats.norm.interval(0.9, loc=finalW2, scale=finalStdW2))) print('E[X1]: ' + str(finalX1)) print('Std[X1]: ' + str(finalStdX1)) print('IC para X1: ' + str(stats.norm.interval(0.9, loc=finalX1, scale=finalStdX1))) print('E[X2]: ' + str(finalX2)) print('Std[X2]: ' + str(finalStdX2)) print('IC para X2: ' + str(stats.norm.interval(0.9, loc=finalX2, scale=finalStdX2))) print('E[T1]: ' + str(finalT1)) print('Std[T1]: ' + str(finalStdT1)) print('IC para T1: ' + str(stats.norm.interval(0.9, loc=finalT1, scale=finalStdT1))) print('E[T2]: ' + str(finalT2)) print('Std[T2]: ' + str(finalStdT2)) print('IC para T2: ' + str(stats.norm.interval(0.9, loc=finalT2, scale=finalStdT2))) print('E[Nq1]: ' + str(finalNq1)) print('Std[Nq1]: ' + str(finalStdNq1)) print('IC para Nq1: ' + str(stats.norm.interval(0.9, loc=finalNq1, scale=finalStdNq1))) print('E[Nq2]: ' + str(finalNq2)) print('Std[Nq2]: ' + str(finalStdNq2)) print('IC para Nq2: ' + str(stats.norm.interval(0.9, loc=finalNq2, scale=finalStdNq2))) print('E[Delta]: ' + str(dt)) print('V[Delta]: ' + str(dt2))
def __init__(self): self.Q = EventQueue() self.T = StatusStructure() self.intersections = []