예제 #1
0
    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()
예제 #2
0
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
예제 #4
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
예제 #5
0
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))
예제 #6
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
예제 #7
0
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)
예제 #8
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
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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
예제 #13
0
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
예제 #14
0
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)
    ])
예제 #15
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
예제 #16
0
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
예제 #17
0
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
예제 #18
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
예제 #19
0
 def __init__(self):
     self.env = QSim()
     self.notifier = MonitorNotifier(self.env)