def __init__(self): """Initialize simulator object. Creates environment and MonitorNotifier """ self.env = QSim() self.notifier = MonitorNotifier(self.env) self.node_dict = OrderedDict() self.contact_dict = OrderedDict() self.generator_list = list() self.packet_counter = -1 self.overall_capacity = 0 self.capacity_dict = dict() self.final_capacity_dict = dict()
def test_proximate_nodes_edt_after_deadline(mod): # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and deadline set to 35 bundle = Packet('node1', 'node8', 1, 35) # Route bundle from node1 to node 8 with size 1 and deadline set to 30 bundle2 = Packet('node1', 'node8', 1, 30) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] \ .register_simulator(dummy) # Now generate a proximate node list with current time set to 0 proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 0, contact_list) # Make sure that only one route is found, (1->3->7->8) will not reach the # target within the deadline assert len(proximate_nodes) == 1 # Assert that the correct proximate node (and route) is returned assert proximate_nodes[0].route.transmission_plan == ([('node1', 'node2', 30, 90, 1000, 0), ('node2', 'node6', 10, 40, 1000, 0), ('node6', 'node8', 0, 100, 1000, 0)]) assert proximate_nodes[0].contact == (('node1', 'node2', 30, 90, 1000, 0)) # Now generate a proximate node list with current time set to 0 proximate_nodes2 = mod.identify_proximate_node_list( 'node1', bundle2, contact_graph, route_list, [], 0, contact_list) # Make sure that only one route is found, (1->3->7->8) will not reach the # target within the deadline assert not proximate_nodes2
def test_remove_subscriber(): """Test unsubscribing functionality.""" # Create environment env = QSim() # Create MonitorNotifier notifier = MonitorNotifier(env) # Create Monitor monitor = Monitor(env) # First, we add the proper monitor notifier.add_subscriber(monitor) # We then try to remove a monitor, which was never added. notifier.remove_subscriber(object()) # We check that the first proper subscriber is still present once again assert len(notifier.subscribers) == 1 # We remove the proper monitor and check that it was removed notifier.remove_subscriber(monitor) assert len(notifier.subscribers) == 0 # We try to remove the proper monitor, which was already removed. notifier.remove_subscriber(monitor) # We check that the subscribers list is still empty. assert len(notifier.subscribers) == 0
def test_proximate_nodes_base(mod): """Test function that tests the identify_proximate_node_list.""" # First, create an contact plan that is then converted to the contact graph # representation and later processed by identify_proximate_node_list # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .register_simulator(dummy) # Now generate a proximate node list proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 0, contact_list) # Make sure that two routes are found assert len(proximate_nodes) == 2 # Check individual EDT and hops node1 = proximate_nodes[0] assert node1.route.edt == 30 assert node1.route.hops == 3 node2 = proximate_nodes[1] assert node2.route.edt == 40 assert node2.route.hops == 3
def test_proximate_nodes_past_route(mod): """Test function that verifys that identify_proximate_node_list() ignores routes thats' feasibility ended in the past. """ # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] \ .register_simulator(dummy) # Now generate a proximate node list with current time set to 50 proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 50, contact_list) # Make sure that only one route is found, (1->2->6->8) has already expired # at t=50 assert len(proximate_nodes) == 1 # Assert that the correct proximate node (and route) is returned assert proximate_nodes[0].route.transmission_plan == ([('node1', 'node3', 0, 100, 1000, 0), ('node3', 'node7', 40, 80, 1000, 0), ('node7', 'node8', 30, 90, 1000, 0)]) assert proximate_nodes[0].contact == (('node1', 'node3', 0, 100, 1000, 0))
def test_cgr_base(mod): # First, create an contact plan that is then converted to the contact # graph representation and later processed by cgr() # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create limbo list limbo = list() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2', debug=True) contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3', debug=True) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1', debug=True) # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .register_simulator(dummy) # Now run cgr for the bundle (with current time set to 0) mod.cgr(bundle, 'node1', contact_graph, route_list, contact_list, 0, limbo) # Make sure that the bundle is enqueue for the correct contact assert len(contact_list[('node1', 'node2', 30, 90, 1000, 0)] \ .packet_queue) == 1 assert len(contact_list[('node1', 'node3', 0, 100, 1000, 0)] \ .packet_queue) == 0 assert len(contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .packet_queue) == 0 assert contact_list[('node1', 'node2', 30, 90, 1000, 0)] \ .packet_queue[0] == bundle
def test_proximate_nodes_excluded_nodes(mod): # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and deadline set to # infinity bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] \ .register_simulator(dummy) # Now generate a proximate node list with ('node1', 'node2', 30, 90) being # in the excluded node list proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, ['node2'], 0, contact_list) # Make sure that only one route is found, (1->3->7->8) will not reach the # target within the deadline assert len(proximate_nodes) == 1 assert proximate_nodes[0].route.transmission_plan == ([('node1', 'node3', 0, 100, 1000, 0), ('node3', 'node7', 40, 80, 1000, 0), ('node7', 'node8', 30, 90, 1000, 0)]) assert proximate_nodes[0].contact == ('node1', 'node3', 0, 100, 1000, 0)
def test_contact_test_sorting(): """Test function to verify correct sorting behaviour for Contact objects""" env = QSim() contactlist = [] c1 = Contact(150, 310, 100, 'source', 'peer') c2 = Contact(100, 320, 100, 'source', 'peer') c3 = Contact(250, 330, 100, 'source', 'peer') contactlist.append(c1) contactlist.append(c2) contactlist.append(c3) assert (len(contactlist) == 3) sorted_contactlist = sorted(contactlist) assert (sorted_contactlist.pop(0) == c2) assert (sorted_contactlist.pop(0) == c1) assert (sorted_contactlist.pop(0) == c3)
def test_add_subscriber(): """Test subscribing functionality.""" # Create environment env = QSim() # Create MonitorNotifier notifier = MonitorNotifier(env) # Create Monitor monitor = Monitor(env) notifier.add_subscriber(monitor) assert len(notifier.subscribers) == 1 # We try to add the monitor, which is already subscribed. notifier.add_subscriber(monitor) # We check that the first proper subscriber is still present once again assert len(notifier.subscribers) == 1
def test_callback(): """Test callback functionality.""" # Create environment env = QSim() # Create MonitorNotifier notifier = MonitorNotifier(env) # Create proper and faulty Monitor monitor = Monitor(env) # First, we add the proper monitor notifier.subscribers.append(monitor) packet = 0 notifier.packet_routed(packet, None, None, None, 0) # Make sure that callback function of subscribed object was called assert monitor.was_called
def test_verify_capacity_calculation_consistency(): """Test function that verifies that the capacity calculations in CGR and the Contact object correspond to each other. """ # The following topology is tested in this test case: # +---+ # | 2 | # +-+-+ # | # [30:90]| # | # +-+-+ # | 1 | # +---+ # Create contact plan and add single contact contact_plan = ContactPlan(1, 20) contact_plan.add_contact('node1', 'node2', 30000, 90000) # Generate contact graph representation contact_graph = ContactGraph(contact_plan) # Create Simulation Environment (dummy, simulation will not be # executed) env = QSim() # Create a Contact object that represents the one edge of the contact # graph and should have the same capacity value calculated as the CGR # functions contact = Contact(30000, 90000, 1, 'node1', 'node2', delay=20) # Now generate possible routes route_list_node12 = cgr.load_route_list(contact_graph, 'node1', 'node2', 0) # There should be only one possible route assert len(route_list_node12) == 1 assert route_list_node12[0].edt == 30000 assert route_list_node12[0].capacity == 60000 assert route_list_node12[0].to_time == 90000 assert route_list_node12[0].transmission_plan == ([('node1', 'node2', 30000, 90000, 1, 20)]) # Verify that the capacities that were calculated are equal (as no packet # has been enqueue yet, the capacity value can be checked) assert contact.capacity == route_list_node12[0].capacity
def test_cgr_limbo(mod): # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create limbo list limbo = list() # Create Simulation Environment (dummy, will not be run) env = QSim() # Create a fake proximate node list to isolate the cgr() function's # behaviour and test it, no entries this time to force in insertion into # limbo proximate_nodes = [] # Now run cgr for the bundle (with current time set to 0) mod.cgr( bundle, 'node1', None, route_list, contact_list, 0, limbo, proximate_nodes=proximate_nodes) # Make sure that the bundle is enqueued in the queue with the best edt assert len(limbo) == 1 assert limbo[0] == bundle
def test_cgr_critical_bundle(mod): # First, create an contact plan that is then converted to the contact graph # representation and later processed by identify_proximate_node_list # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and no deadline, but with # being critical bundle = Packet('node1', 'node8', 1000, math.inf, False, True) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create limbo list limbo = list() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2', debug=True) contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3', debug=True) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1', debug=True) # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .register_simulator(dummy) mod.cgr(bundle, 'node1', contact_graph, route_list, contact_list, 0, limbo) # Make sure that the bundle is enqueued in all feasible contacts to # neighbors assert len(contact_list[('node1', 'node2', 30, 90, 1000, 0)].packet_queue) == 1 assert len(contact_list[('node1', 'node3', 0, 100, 1000, 0)].packet_queue) == 1 contact_graph2 = generate_test_graph(True) # Route bundle from node1 to node 8 with size 1 and no deadline, but with # being critical bundle2 = Packet('node1', 'node8', 1, math.inf, False, True) # Reset route list route_list = dict() mod.cgr(bundle2, 'node1', contact_graph2, route_list, contact_list, 0, limbo) # Make sure that only neighbors are considered that can reach the # destination (based on the contact graph knowledge) assert len(contact_list[('node1', 'node2', 30, 90, 1000, 0)].packet_queue) == 1 assert len(contact_list[('node1', 'node3', 0, 100, 1000, 0)].packet_queue) == 2
def test_proximate_nodes_optimize_proximate_node(mod): # Create contact graph of test topology contact_graph = generate_test_graph() # Route bundle from node1 to node 8 with size 1 and deadline set to # infinity bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create some fake routes that can later be used for optimizing the # proximate node values route_list['node8'] = [] # First, add route with worse EDT (50) route_list['node8'].append( create_route(([('node1', 'node3', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0)], (50, 40, 70)))) # Then add route with better EDT (30) route_list['node8'].append( create_route(([('node1', 'node3', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0)], (30, 40, 70)))) # First, add route with 5 hops route_list['node8'].append( create_route(([('node1', 'node2', 30, 90, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0)], (30, 40, 70)))) # Then add route with only 4 hops route_list['node8'].append( create_route(([('node1', 'node2', 30, 90, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0)], (30, 40, 70)))) # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 10, 0)] = Contact( 30, 90, 10, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 10, 0)] = Contact( 0, 100, 10, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, 10, 0)] = Contact( 0, math.inf, 10, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 10, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 10, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, 10, 0)].register_simulator(dummy) # Now generate a proximate node list with ('node1', 'node2', 30, 90) being # in the excluded node list proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 0, contact_list) # Make sure that two feasible proximate nodes are found assert len(proximate_nodes) == 2 # Assert that the proximate nodes are returned with the correct, optimized # characteristics assert proximate_nodes[0].contact == ('node1', 'node3', 0, 100, 10, 0) assert proximate_nodes[0].route.edt == 30 assert proximate_nodes[0].route.hops == 3 assert proximate_nodes[0].route.transmission_plan == ([('node1', 'node3', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0)]) assert proximate_nodes[1].contact == ('node1', 'node2', 30, 90, 10, 0) assert proximate_nodes[1].route.edt == 30 assert proximate_nodes[1].route.hops == 4 assert proximate_nodes[1].route.transmission_plan == ([ ('node1', 'node2', 30, 90, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node3', 'node4', 0, 100, 10, 0), ('node4', 'node5', 30, 70, 10, 0) ])
class Simulator(): """Simulator object used for running simulations. Attributes: env (simulation env): Simulation environment (backend). notifier (MonitorNotifier): Notifier object for relaying events to monitors. node_dict (dict): Dict of registered nodes (identifier is key). contact_dict (set): Dict of registered contact objects (characteristic values are key) """ def __init__(self): """Initialize simulator object. Creates environment and MonitorNotifier """ self.env = QSim() self.notifier = MonitorNotifier(self.env) self.node_dict = OrderedDict() self.contact_dict = OrderedDict() self.generator_list = list() self.packet_counter = -1 self.overall_capacity = 0 self.capacity_dict = dict() self.final_capacity_dict = dict() def run_simulation(self, duration, starttime=0, output=Output.NO_OUTPUT, tqdm_position=0, tqdm_desc=None, name=""): """Run the simulation using the simulation backend. Args: duration (int): Simulation duration in milliseconds. starttime (int): Time in seconds from which on the simulation will run for the also provided duration. Required if TVG imports use a certain epoch.Defaults to 0. .. note:: It is recommended to fix the TVG import values instead of setting a custom start time! It has to be considered, that this custom start time has to be used for generator configuration as well. output (Output): Specify if and how the progress of the simulation should be presented to the user. Defaults to no output. tqdm_position (int): Determine row position of tqdm progress bar. Helpful when multiple scenarios are simulated in parallel. Defaults to 0. tqdm_desc (string): Descriptor of the tqdm progress bar. Defaults to None. name (string): Descriptor of the simulation. Is used in print output. Defaults to "". """ # Calculate the overall available capacity for contact in self.contact_dict: capacity = self.contact_dict[contact].capacity self.overall_capacity += capacity self.capacity_dict[contact] = capacity print(f"Running simulation {name} for {duration} ms ...") # Signal to monitors that simulation started self.notifier.simulation_started() starttime_ms = starttime * 1000 # Determine the simulation steps (we use a 1% of the overall # simulation time to speed up the run) steps = round(duration / 100) steps_pbar = int(round(steps / 1000)) # Disable tdqm if not desired if output == Output.TQDM: # Create a custom tqdm progress bar object that displays the # progress in seconds rather than milliseconds. pbar = tqdm(total=int(round(duration / 1000)), position=tqdm_position, desc=tqdm_desc) # Run the simulation for i in range(0, duration, steps): self.env.run_simulation(until=starttime_ms + i + steps) pbar.update(steps_pbar) # Close the progress bar (ensures correct output) pbar.close() elif output == Output.TEXTUAL: # Determine the simulation steps (we use a 1% of the overall # simulation time to speed up the run) steps = round(duration / 100) # Run the simulation for i in range(0, duration, steps): self.env.run_simulation(until=starttime_ms + i + steps) print(f"Simulation {name} at {(i/steps)}%") else: self.env.run_simulation(until=duration) # Signal to monitors that simulation ended self.notifier.simulation_ended() self.__print_stats() def register_node(self, node): """Register node in simulation environment. Args: node (Node): The registered node. Raises: ValueError: When a node with the same identifier already exists in the environment. """ # Check if node already added to simulation or node with same # identifier already exists if node.identifier in self.node_dict: raise ValueError("Node with name '{}' already exists in " "environment".format(node.identifier)) # Append to node set self.node_dict[node.identifier] = node def register_contact(self, contact): """Register contact in simulation environment. Adds the contact as generator to the simulation environment. Args: contact (Contact): The registered contact. """ # Add contact to contact set, multiple contacts with the same # characteristics are allowed, one cannot add the same contact # object multiple times (enforced by set) self.contact_dict[contact.get_identifier()] = contact # Register the contact as generator object with the simulation # environment contact.register_simulator(self) def register_generator(self, generator): """Add packet generator to the simulation environment. Args: generator (object): The packet generator that should be added to the simulation environment. """ # Add the generator object to the list of generators. We use a list # here because one can potentially add the same generator object to # an simulation environment multiple times. self.generator_list.append(generator) generator.register_simulator(self) def register_monitor(self, monitor): """Add monitor to the simulation environment. Args: monitor (object): The monitor that should be added to the simulation environment. """ self.notifier.add_subscriber(monitor) def __print_stats(self): """Print very basic informations about the simulation to stdout.""" print("Simulation Results:") # Sum up the total number of generated packets total_packet_count = 0 for generator in self.generator_list: total_packet_count += generator.get_packet_count() print("- total number of packets generated: {:d}".format( total_packet_count)) packets_in_limbo = 0 for node in self.node_dict.values(): if node.limbo: packets_in_limbo += len(node.limbo) print("- total number of packets enqueued in limbos: {:d}".format( packets_in_limbo)) packets_in_contacts = 0 for contact in self.contact_dict.values(): packets_in_contacts += contact.len_packet_queue print("- total number of packets enqueued in contacts: {:d}".format( packets_in_contacts)) remaining_capacity = 0 for contact in self.contact_dict: local_rem_cap = self.contact_dict[contact].capacity remaining_capacity += local_rem_cap self.final_capacity_dict[contact] = local_rem_cap capacity_utilization = round( (((self.overall_capacity - remaining_capacity) / self.overall_capacity) * 100), 2) print("- contact capacity utilization: {} %".format( capacity_utilization)) def get_utilization_list(self, ignore_inter_hotspot_contact=False, hotspots=None): """Generate a list of the utilizations of all contacts. Returns: list: A list of the utilizations of every individual contact. Raises: ValueError: If inter hotspot contacts should be excluded, but no hot spot list is provided. """ if ignore_inter_hotspot_contact and hotspots is None: raise ValueError( "Ignoring Hotspot Contacts, but no hotspot list " + "provided!") utilization_list = list() for contact in self.contact_dict: if (ignore_inter_hotspot_contact and contact[0] in hotspots and contact[1] in hotspots): continue utilization = round((((self.capacity_dict[contact] - self.final_capacity_dict[contact]) / self.capacity_dict[contact]) * 100), 2) utilization_list.append(utilization) return utilization_list def get_stats(self): """Return very basic informations about the simulation.""" # Sum up the total number of generated packets total_packet_count = 0 for generator in self.generator_list: total_packet_count += generator.get_packet_count() packets_in_limbo = 0 for node in self.node_dict.values(): if node.limbo: packets_in_limbo += len(node.limbo) packets_in_contacts = 0 for contact in self.contact_dict.values(): packets_in_contacts += contact.len_packet_queue return (total_packet_count, packets_in_limbo, packets_in_contacts) def hand_over_packet(self, peer, packet): """Hand over transmitted packet to peer node. Args: peer (string): Description of parameter `peer`. packet (pydtnsim.Packet): Transmitted packet. Raises: ValueError: If the packet was forwarded to a node that does not exist! """ # Check if peer node does exist if peer not in self.node_dict: raise ValueError("Packet was forwarded to node '{}' that does not " "exist".format(peer)) # Perform routing operation at peer node self.node_dict[peer].route_packet(packet, self.env.now) def get_contact_dict(self, contact_list): """Return dict that maps contact identifiers to contact objects. Args: contact_list (list): List of contacts (in string format) for which a dict mapping the string to the Contact object will be provided. Raises: ValueError: If one of the contact identifiers in the list does not exist as contact object. Returns: dict: A dict mapping the string identifier of a contact to the corresponding Contact object. """ list_contact_dict = OrderedDict() # Iterate over all contacts in contact_list for contact in contact_list: # Check if contact exists in contact_dict, otherwise raise error if contact not in self.contact_dict: raise ValueError( "Contact '{}' listed in the contact " "list does not exist as a contact object".format( contact.get_identifier())) # Add contact object to subdict list_contact_dict[contact] = self.contact_dict[contact] # Return subdict return list_contact_dict def get_unique_packet_identifier(self): """Return an packet identifier (int) that is unique in the scenario.""" self.packet_counter += 1 return self.packet_counter def get_node_dict(self, node_list): """Return dict that maps node identifiers to node objects. Args: node_list (list): List of nodes (in string identifer format) for which a dict mapping the string to the Contact object will be provided. Raises: ValueError: If one of the node identifiers in the list does not exist as contact object. Returns: dict: A dict mapping the string identifier of a node to the corresponding Node object. """ list_node_dict = OrderedDict() # Iterate over all contacts in contact_list for node in node_list: # Check if contact exists in contact_dict, otherwise raise error if node not in self.node_dict: raise ValueError("Node '{}' listed in the node list does not " "exist as a contact object".format(node)) # Add node object to subdict list_node_dict[node] = self.node_dict[node] # Return subdict return list_node_dict
def test_proximate_nodes_route_capacity(mod): # Create contact graph of test topology contact_graph = generate_test_graph() # Create bundle from node1 to node 8 with size 40 and deadline set to # infinity bundle = Packet('node1', 'node8', 40000, math.inf) # Create bundle from node1 to node 8 with size 41 and deadline set to # infinity bundle2 = Packet('node1', 'node8', 41000, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 30, 90, 1000, 0)] = Contact( 30, 90, 1000, 'node1', 'node2') contact_list[('node1', 'node3', 0, 100, 1000, 0)] = Contact( 0, 100, 1000, 'node1', 'node3') contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1') # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 30, 90, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node3', 0, 100, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, math.inf, 0)] \ .register_simulator(dummy) # Now generate a proximate node list for 'bundle' proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 0, contact_list) # Make sure that routes are found as the bundle is not exceeding the # capacities of the routes' contacts assert len(proximate_nodes) == 1 # Now generate a proximate node list for 'bundle2' proximate_nodes = mod.identify_proximate_node_list( 'node1', bundle2, contact_graph, route_list, [], 0, contact_list) # Make sure that routes are not found as the bundle's size is larger than # the capacities of all available routes assert len(proximate_nodes) == 0 # Enqueue that packet to trigger the capacity recalculation contact_list[('node1', 'node2', 30, 90, 1000, 0)].cap_rem = 10000 # Enqueue that packet to trigger the capacity recalculation contact_list[('node1', 'node3', 0, 100, 1000, 0)].cap_rem = 40000 # Now generate a proximate node list for 'bundle' proximate_nodes = cgr_basic.identify_proximate_node_list( 'node1', bundle, contact_graph, route_list, [], 0, contact_list) # Make sure that one route is found as the bundle is still fitting into # the queue of the 1->3 contact assert len(proximate_nodes) == 1 assert proximate_nodes[0].route.transmission_plan == ([('node1', 'node3', 0, 100, 1000, 0), ('node3', 'node7', 40, 80, 1000, 0), ('node7', 'node8', 30, 90, 1000, 0)]) assert proximate_nodes[0].contact == ('node1', 'node3', 0, 100, 1000, 0) # Now generate a proximate node list for 'bundle2' proximate_nodes = cgr_basic.identify_proximate_node_list( 'node1', bundle2, contact_graph, route_list, [], 0, contact_list) # Make sure that routes are not found as the bundle's size is larger than # the remaining capacities of all feasible contacts to neighbors assert not proximate_nodes
def test_cgr_base_no_route(mod): # First, create an contact plan that is then converted to the contact # graph representation and later processed by cgr() # The following topology is tested in this test case: # +---+ +---+ +---+ +---+ # | 1 +---------+ 2 +---------+ 3 +---------+ 4 | # +---+ 35:40 +---+ 20:40 +---+ 20:25 +---+ contact_plan = ContactPlan(1000, 0) contact_plan.add_contact('node1', 'node2', 35, 40) contact_plan.add_contact('node2', 'node3', 20, 40) contact_plan.add_contact('node3', 'node4', 20, 25) # Generate contact graph representation contact_graph = ContactGraph(contact_plan) # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node4', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create limbo list limbo = list() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 35, 40, 1000, 0)] = Contact( 35, 40, 1000, 'node1', 'node2', debug=True) contact_list[('node2', 'node3', 20, 40, 1000, 0)] = Contact( 20, 40, 1000, 'node2', 'node3', debug=True) contact_list[('node3', 'node4', 20, 25, 1000, 0)] = Contact( 20, 25, 1000, 'node3', 'node4', debug=True) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] = Contact( 0, math.inf, 1000, 'node1', 'node1', debug=True) # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 35, 40, 1000, 0)].register_simulator(dummy) contact_list[('node2', 'node3', 20, 40, 1000, 0)].register_simulator(dummy) contact_list[('node3', 'node4', 20, 25, 1000, 0)].register_simulator(dummy) contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .register_simulator(dummy) # Now run cgr for the bundle (with current time set to 0) mod.cgr(bundle, 'node1', contact_graph, route_list, contact_list, 0, limbo) # Make sure that the bundle is enqueue for the correct contact assert len(limbo) == 1 assert len(contact_list[('node1', 'node2', 35, 40, 1000, 0)] \ .packet_queue) == 0 assert len(contact_list[('node2', 'node3', 20, 40, 1000, 0)] \ .packet_queue) == 0 assert len(contact_list[('node3', 'node4', 20, 25, 1000, 0)] \ .packet_queue) == 0 assert len(contact_list[('node1', 'node1', 0, math.inf, 1000, 0)] \ .packet_queue) == 0
def test_cgr_optimization(mod): # Route bundle from node1 to node 8 with size 1 and no deadline bundle = Packet('node1', 'node8', 1, math.inf) # Create empty route_list dictionary so route list for destination will be # regenerated route_list = dict() # Create contact list object contact_list = dict() # Create limbo list limbo = list() # Create Simulation Environment (dummy, will not be run) env = QSim() contact_list[('node1', 'node2', 10, 100, 1000, 0)] = Contact( 10, 100, 1000, 'node1', 'node2', debug=True) contact_list[('node1', 'node3', 10, 100, 1000, 0)] = Contact( 20, 100, 1000, 'node1', 'node3', debug=True) # Add dummy simulator to the contacts dummy = DummySimulator() contact_list[('node1', 'node2', 10, 100, 1000, 0)] \ .register_simulator(dummy) contact_list[('node1', 'node3', 10, 100, 1000, 0)] \ .register_simulator(dummy) # Create a fake proximate node list to isolate the cgr() function's # behaviour and test it proximate_nodes = [(('node1', 'node2', 10, 100, 1000, 0), 10, 2, [('node1', 'node2', 10, 100, 1000, 0)]), (('node1', 'node3', 10, 100, 1000, 0), 20, 2, [('node1', 'node3', 10, 100, 1000, 0)])] proximate_nodes = generate_neighbors(proximate_nodes) # Now run cgr for the bundle (with current time set to 0) mod.cgr( bundle, 'node1', None, route_list, contact_list, 0, limbo, proximate_nodes=proximate_nodes) # Reset bundle so it can be routed from the same node again without # throwing an exception bundle.current_node = 'inserted' # Make sure that the bundle is enqueued in the queue with the best edt assert len(contact_list[('node1', 'node2', 10, 100, 1000, 0)] \ .packet_queue) == 1 assert not contact_list[('node1', 'node3', 10, 100, 1000, 0)] \ .packet_queue assert contact_list[('node1', 'node2', 10, 100, 1000, 0)] \ .packet_queue[0] == bundle # Alter proximate node list so that edt is equal and hops is the relevant # value proximate_nodes = [(('node1', 'node2', 10, 100, 1000, 0), 20, 3, [('node1', 'node2', 10, 100, 1000, 0)]), (('node1', 'node3', 10, 100, 1000, 0), 20, 2, [('node1', 'node3', 10, 100, 1000, 0)])] proximate_nodes = generate_neighbors(proximate_nodes) # Now run cgr for the bundle (with current time set to 0) mod.cgr( bundle, 'node1', None, route_list, contact_list, 0, limbo, proximate_nodes=proximate_nodes) # Reset bundle so it can be routed from the same node again without # throwing an exception bundle.current_node = 'inserted' # Make sure that the bundle is enqueued in the queue with the best edt assert len(contact_list[('node1', 'node2', 10, 100, 1000, 0)].packet_queue) == 1 assert len(contact_list[('node1', 'node3', 10, 100, 1000, 0)].packet_queue) == 1 assert contact_list[('node1', 'node3', 10, 100, 1000, 0)] \ .packet_queue[0] == bundle # Alter proximate node list so that edt and hops are equal and hash is the # deciding value proximate_nodes = [(('node1', 'node2', 10, 100, 1000, 0), 20, 4, [('node1', 'node2', 10, 100, 1000, 0)]), (('node1', 'node3', 10, 100, 1000, 0), 20, 4, [('node1', 'node3', 10, 100, 1000, 0)])] proximate_nodes = generate_neighbors(proximate_nodes) # Now run cgr for the bundle (with current time set to 0) mod.cgr( bundle, 'node1', None, route_list, contact_list, 0, limbo, proximate_nodes=proximate_nodes) # Reset bundle so it can be routed from the same node again without # throwing an exception bundle.current_node = 'inserted' if hash('node2') > hash('node3'): node_a = ('node1', 'node2', 10, 100, 1000, 0) node_b = ('node1', 'node3', 10, 100, 1000, 0) else: node_b = ('node1', 'node2', 10, 100, 1000, 0) node_a = ('node1', 'node3', 10, 100, 1000, 0) # Make sure that the bundle is enqueued in the queue with the best edt if len(contact_list[node_a].packet_queue) == 1: assert len(contact_list[node_b].packet_queue) == 2 assert contact_list[node_b].packet_queue[1] == bundle elif len(contact_list[node_a].packet_queue) == 2: assert len(contact_list[node_b].packet_queue) == 1 assert contact_list[node_a].packet_queue[1] == bundle
def __init__(self): self.env = QSim() self.notifier = MonitorNotifier(self.env)