diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..298ea9e --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/architecture.rst b/docs/architecture.rst new file mode 100644 index 0000000..b75c3ab --- /dev/null +++ b/docs/architecture.rst @@ -0,0 +1,2 @@ +Architecture Overview +===================== diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..7854207 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../..')) + + +# -- Project information ----------------------------------------------------- + +project = 'pyDTNsim' +copyright = '2019, Robert Wiewel' +author = 'Robert Wiewel' + +# The short X.Y version +version = '' +# The full version, including alpha/beta/rc tags +release = '0.1.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon', +# 'sphinxcontrib.bibtex', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pyDTNsimdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'pyDTNsim.tex', 'pyDTNsim Documentation', + 'Robert Wiewel', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pydtnsim', 'pyDTNsim Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'pyDTNsim', 'pyDTNsim Documentation', + author, 'pyDTNsim', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + +# -- Extension configuration ------------------------------------------------- diff --git a/docs/data_processing.rst b/docs/data_processing.rst new file mode 100644 index 0000000..931f7ce --- /dev/null +++ b/docs/data_processing.rst @@ -0,0 +1,2 @@ +Simulation Data Processing +========================== diff --git a/docs/development_guide.rst b/docs/development_guide.rst new file mode 100644 index 0000000..a06f5ad --- /dev/null +++ b/docs/development_guide.rst @@ -0,0 +1,2 @@ +Development Guide +================= diff --git a/docs/examples.rst b/docs/examples.rst new file mode 100644 index 0000000..bac945d --- /dev/null +++ b/docs/examples.rst @@ -0,0 +1,2 @@ +Examples +======== diff --git a/docs/getting_started.rst b/docs/getting_started.rst new file mode 100644 index 0000000..39cfc29 --- /dev/null +++ b/docs/getting_started.rst @@ -0,0 +1,329 @@ +.. _getting_started: + +Getting started with pyDTNsim +============================= + +With *pyDTNsim* installed, we can start with running simulations using the library. In this section, a hands-on introduction into the features and the instrumentation procedure of the library module will be provided. + +The goal of this introduction is to simulate the simple intermittently connected network topology as depicted below and to generate key characteristics of this simulation run. + +Simulation Scenario +------------------- + +The following network topology shall be simulated for 1000 seconds: + +.. image:: resources/getting_started/topology.svg + :width: 100% + +The annotations at the arrows represent available contact between the two (physical) network nodes that an arrow is connecting in `mathematical interval notation `_ in seconds. All contacts are considered to allow for a transmission of data with 100 KBps. + +.. note:: The propagation delays are considered neglible in this scenario. This is in line with the current configuration of *pyDTNsim* which is not supporting (individual or global) delays at the moment. + +The nodes ``A`` and ``C`` are representing *"active"* endpoints which are both continuously inserting packets of 100 KB with a data generation rate of 10 KBps, addressed at node ``A`` and ``C`` respectively. The data generation will continue throughout the entire simulation period. + +Node ``B`` is functioning as intermediary node that is solely forwarding packets received from ``A`` and ``B``. It is neither the destination of any packets nor is it injecting any packets. + +*Contact Graph Routing (CGR)* will be used as routing mechanism. See :ref:`routing_mechanisms` for more details on provided mechanisms and their implementation. + +The characteristics that should be acquired with the simulation run are + +- the overall **average delivery time** of all delivered packets during the simulation run, +- the **number of packets** enqueued into the **limbo** (i.e., packets that could not be scheduled for transmission with CGR) and +- a **histogram** of the **average delivery time** of all delivered packets throughout the simulation run. + +Creating a simulation script +---------------------------- +As *pyDTNsim* is a library module, we have to create a simulation script ourselves to leverage the invoke the module's functionality. + +Just create a new python script file with your favorite editor or type + +.. code-block:: sh + + touch dtn_simulation.py + vim dtn_simulation.py + +With the script created, we can now start to import the libraries components. We start with creating a :class:`pydtnsim.simulator.Simulator` object. This object represents the event-oriented simulation environment that keeps track of the simulations components and is later invoked for the actual simulation run. Details about the abstract concept of the simulation environment can be found in :doc:`architecture`. + +The :class:`Simulator` can then be used to perform a simulation using it's member function :py:meth:`.Simulator.run_simulation`. For now, it is sufficient to provide this function with the simulation duration in milliseconds. It will then run a simulation from 0 ms to that provided parameter. + +The following code snippet shows the most basic simulation script using the :class:`.Simulator` class. Please add this snippet to your script file. + + + +.. code-block:: python + + from pydtnsim import Simulator + + def main(): + """Simulate basic scenario.""" + # Create simulation environment + simulator = Simulator() + + # Run the simulation for 1000 seconds (1000000 ms) + simulator.run_simulation(1000000) + + if __name__ == "__main__": + main() + +As no nodes or contacts were added to the :class:`.Simulator` object, nothing has to be simulated. When running the script, the output is as follows: + +.. code-block:: none + :linenos: + + > python3 dtn_simulation.py + Running simulation for 1000000 ms ... + Simulation completed! + Simulation Results: + - total number of packets generated: 0 + - total number of packets enqueued in limbos: 0 + - total number of packets enqueued in contacts: 0 + +Hooray, that was the first "successful" pyDTNsim simulation run! We didn't actually simulate any network but we can change that by adding simulation elements in the next step. + +But first, let's have a look at the output provided by the :class:`.Simulator` object: besides the message that the simulation was completed the output also provides some simple statistics about the performed simulation run in lines *(5-7)*. In our case, no packets were generated and subsequently, no packets remained in limbos or contacts at the end of the simulation run. + + +Adding simulation elements +-------------------------- + +In order to not just simulate empty scenarios, we now have to add (active and passive) simulation elements to the simulation environment. In particular, two elements have to be represented in the environment: physical network nodes (e.g., :class:`.SimpleCGRNode`) and contacts in between those nodes (:class:`.Contact`). + +.. note:: + + Both classes/objects referenced in the paragraph above are exemplary. Depending on the simulated routing mechanisms, the instantiated network node objects have to vary (and might even have to be implemented oneself for novel routing concepts). An opportunistic routing approach might have differing processing requirements both in terms of gathered knowledge at the physical nodes and the forwarding behavior during node contacts. + +.. warning:: + + With the development focus of this simulation environment having been CGR, the generalization in terms of applicable routing mechanisms has not been fully implemented in this area of the application. For now, only CGR implementations are provided and no abstract parent class exists for the easy adoption with other routing approaches. This improvement will likely be implemented in the near future. + +For the simulation elements including their helper classes, we need to add the following imports: + +.. code-block:: python + + from pydtnsim import ContactPlan, ContactGraph, Contact + from pydtnsim.nodes import SimpleCGRNode + from pydtnsim.routing import cgr_basic + from pydtnsim.packet_generators import ContinuousPacketGenerator + +The imported objects will be explained in the following paragraphs. + +Network Topology +^^^^^^^^^^^^^^^^ + +As the network node need to be aware about the network topology since we are using :abbr:`CGR (Contact Graph Routing)` as routing mechanism, we have to provide such information during the instantiation. + +We provide the topology knowledge as a :class:`.ContactGraph` object. This object represents the topology as a time-invariant graph and can be easily generated from a :class:`.ContactPlan` object. This object holds the same information as the :class:`.ContactGraph`, but is easier to understand and modify for humans. More details on the reasoning behind the :class:`.ContactPlan` and the :class:`.ContactGraph` in the context of :abbr:`CGR (Contact Graph Routing)` is provided in :doc:`routing/cgr`. + +As outlined before, we first create the :class:`.ContactPlan` (line 2). The parameters provided during the instantiation are the default data rate in bits per millisecond (10 bits per millisecond, i.e. 10 KBps) and the default propagation delay in milliseconds (50 ms). + +.. warning:: + + The propagation delay is currently not factored in when simulating networks. The interface for providing such information is already implemented, but the simulation logic is not implemented yet. This is future work, so for now, the propagation delay is always neglected. + +.. code-block:: python + :linenos: + + # Generate empty contact plan + contact_plan = ContactPlan(10, 50) + + # Add the contacts + contact_plan.add_contact('node_a', 'node_b', 0, 100000) + contact_plan.add_contact('node_a', 'node_b', 500000, 750000) + contact_plan.add_contact('node_b', 'node_c', 0, 200000) + contact_plan.add_contact('node_b', 'node_c', 350000, 400000) + contact_plan.add_contact('node_b', 'node_c', 950000, 990000) + +In lines 5 to 9, the contacts based on our previously outlined scenario are added to the ``contact_plan`` object using :py:meth:`.ContactPlan.add_contact`. The parameters are + +- the source node, +- the destination node, +- the start time in milliseconds and +- the end time in milliseconds. + +As no additional optional parameters for the data rate and the delay were provided, the default values of the ``contact_plan`` object are used. + +Finally, we can simply convert the filled :class:`.ContactPlan` object into a :class:`.ContactGraph` object: + +.. code-block:: python + + # Convert contact plan to contact graph + contact_graph = ContactGraph(contact_plan) + +Contacts +^^^^^^^^ + +The contacts available in between network nodes throughout the simulation are simulated using the :class:`.Contact` object. These objects are an integral part of the simulation environment as they are one of two active **generator** elements that drive the simulation (and generate events, hence the name). Contacts are activated upon their contact start time and then perform handover operations from one node to another during their time active. At the end of a handover of a packet to another node, the routing mechanism on that other node is called to determine the future forwarding. + +With the information about the contacts already being available in the ``contact_plan`` object of the previous step, we can iterate over that information to generate our :class:`.Contact` objects: + +.. code-block:: python + :linenos: + + # Generate contact objects and register them + for planned_contact in contact_plan.get_contacts(): + # Create a Contact simulation object based on the ContactPlan + # information + contact = Contact(planned_contact.from_time, planned_contact.to_time, + planned_contact.datarate, planned_contact.from_node, + planned_contact.to_node, planned_contact.delay) + # Register the contact as a generator object in the simulation + # environment + simulator.register_contact(contact) + +In addition to the instantiation of the contacts in lines 5 to 7, in line 10, the respective contact also has to be registered with the simulation environment. This is to allow the simulation environment to call the contact upon its start time. + + +Network Nodes +^^^^^^^^^^^^^ + +With the topology information available in the correct format, we can add the network nodes. For all three nodes, we will use :class:`.SimpleCGRNode` as representation in the simulation environment. Again, we can use the `contact_plan` object that we instantiated and filled earlier to gather the relevant information for the instantiation: + +.. code-block:: python + :linenos: + + # Generate network node objects and register them + for planned_node in contact_plan.get_nodes(): + # Generate contact list of node + contact_list = contact_plan.get_outbound_contacts_of_node(planned_node) + # Create a dict that maps the contact identifiers to Contact simulation + # objects + contact_dict = simulator.get_contact_dict(contact_list) + # Create a node simulation object + SimpleCGRNode(planned_node, contact_dict, cgr_basic.cgr, contact_graph, + simulator, []) + +In line 2, we get a list of all network nodes in the topology using :py:meth:`.ContactPlan.get_nodes`. We then iterate over this list and create the individual nodes: + +1. We first have to get a list of all outbound nodes that the individual + network node has. This is done calling + :py:meth:`.ContactPlan.get_outbound_contacts_of_node`. +2. This list is then used to get a ``contact_dict`` from the + :class:`.Simulator` object. As this object is aware of all contacts and + their registered instantiations, it can map the textual list entries of the + outbound contacts from the previous step to actual :class:`.Contact` + objects. So by calling :py:meth:`.Simulator.get_contact_dict`, we get a + ``dict`` mapping a contacts identifier to the instantiation in the + simulation context. +3. With the ``contact_dict`` available, we can instantiate the actual network + node object as :class:`.SimpleCGRNode` with the following parameters: + + - the node identifier (e.g. ``node_a``), + - the ``contact_dict``, + - the routing mechanism's main function ``cgr_basic.cgr``, + - the topology information (in this case as :class:`.ContactGraph` object) + and + - the :class:`.Simulator` object. + +Packet Generators +^^^^^^^^^^^^^^^^^ + +Finally, we have to add packet generators that are injecting packets into the simulated network. Without them, regardless of the specified topology, no packets would be forwarded and thus, no non-trivial network behavior would be simulated. + +Currently, there two different packet generators provided in the simulation environment, the :class:`.BatchPacketGenerator` and the :class:`.ContinuousPacketGenerator`. Both are children of the parent :class:`.BasePacketGenerator`. + +The injection behavior of the two generators is depicted in the following figure: + +.. image:: resources/getting_started/injection_methods.svg + :width: 80% + :align: center + +The :class:`.BatchPacketGenerator` injects a specified number of packets at specified points in time whereas the :class:`.ContinuousPacketGenerator` injects packets continuously throughout the simulation period with a defined generation data rate. + +Depending on the scenario, one of them might be used for the simulation conducted. Alternatively, an own generator can be implemented based on the :class:`.BasePacketGenerator`. + +For our scenario, we will use the :class:`.ContinuousPacketGenerator` to inject packets for the routes ``node_a -> node_c`` and ``node_c -> node_a`` at a specified data generation rate of 10 KBps and with a packet size of 100 KB: + +.. code-block:: python + :linenos: + + # Generate packet generator 1 and register them + generator1 = ContinuousPacketGenerator( + 10, # Data Generation Rate: 10 Bytes per ms + 100000, # Packet Size: 100 KB + ['node_a'], # From 'node_a' + ['node_c'], # To 'node_c' + 0, # Start injection at simulation time 0s + 1000000) # End injection at simulation end (1000s) + + # Generate packet generator 2 and register them + generator2 = ContinuousPacketGenerator( + 10, # Data Generation Rate: 10 Bytes per ms + 100000, # Packet Size: 100 KB + ['node_c'], # From 'node_c' + ['node_a'], # To 'node_a' + 0, # Start injection at simulation time 0s + 1000000) # End injection at simulation end (1000s) + + # Register the generators as a generator objects in the simulation + # environment + simulator.register_generator(generator1) + simulator.register_generator(generator2) + +.. warning:: + + The implementation of the packet generator configuration is currently requiring the instantiation of two distinct generators to accomplish the bidirectional injection of packets between ``node_a <-> node_c``. This will be changed in a future release (likely ``v0.3.0``). + +.. warning:: + Also, the registration procedure for the generators is currently inconsistent with the other simulation elements. Therefore, a consistent registration procedure will be established in a future release as well. + +Two generators have to be instantiated, one for the injection of packets traveling from `node_a` to `node_c` and one for the reverse direction from `node_c` to `node_a`. + +The two instantiations in lines 2 to 8 and 11 to 17 are provided with several parameters: + +- the data generation rate, +- the packet size, +- a ``list`` of (``string``) node identifiers identifying all source nodes that the generator should inject packets with the given parameters and data rate, +- a ``list`` of (``string``) node identifiers identifying all destination nodes that the generator should address packets to with the given parameters and data rate, +- the injection start time (in ms absolute to the simulation start time) and +- the injection end time (in ms absolute to the simulation start time). + +With ``list``'s used for identifying source and destination nodes, the the generator injects for every element of the source node list packets with the given characteristics and rates to all elements of the destination node list. This injection scheme is also depicted in the following diagram: + +.. image:: resources/getting_started/packet_injection_scheme.svg + :width: 100% + :align: center + +With the two generators instantiated an configured, we have to register them with the simulation environment. This is done in lines 21 and 22. + +We now have all simulation elements in place and can run the simulation again. If you don't want to copy all code snippets from this documentation, you can also download the file created up to this point of the tutorial at :download:`this link `. + +If we run this extended script, we get the following output: + +.. code-block:: none + :linenos: + + > python3 dtn_simulation_elements.py + Running simulation for 1000000 ms ... + Simulation completed! + Simulation Results: + - total number of packets generated: 198 + - total number of packets enqueued in limbos: 165 + - total number of packets enqueued in contacts: 0 + +You can see that the generators properly generated packets and injected them into the network. The number of generated packets seems about right: with the configuration provided, the generators inject a packet to the (single) destination every 10 seconds. With 1000 seconds being simulated, this results in 99 injected packets per generator and 198 in total. As the simulation ends when 1000s is reached (excluding the termination value), the 100th packet of each generator that would be due at time 1000s is not added. + +Also, we can see in line 6, that only a fraction of the injected packets is actually forwarded and 165 of the 198 packets are enqueued in one of the nodes' limbos. A limbo is a queue that holds packets that cannot be forwarded to their destination nodes based on the available topology information. Every node has a limbo that is used for such packets. + +.. note:: + + The number of "discarded" packets can be directly attributed to the selected topology, the contact times and the nodes configuration (including the injection rates) and does not represent an (programming) error. + +As our contact plan has the same validity period as our simulation duration, no packets should remain scheduled in contacts after the simulation end. This is the case as can be seen in line 7. + +.. warning:: + + If the validity period of topology information exceeds the simulated period (e.g., a 1 hour simulation is conducted with a contact plan containing the computed contacts for 48 hours), packets can remain enqueued in *future* (i.e., beyond the simulation end time) contacts and will appear in the simulation results summary (in our example in line 7). + +In this section, we successfully simulated our specified simulation scenario. We even got some bits of information about what happened during the simulation (e.g., that a large number of packets was at some point enqueued into a node's limbo). + +However, usually when running a network simulation (especially in the academic context), more detailed analyses and key values are required. The next section will cope with the monitoring interface of pyDTNsim that allows for an extraction of arbitrary such values. + + +Monitoring of the Simulation +---------------------------- + +Running a Simulation +-------------------- + +Post Processing and Evaluation +------------------------------ diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 0000000..1159665 --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,9 @@ +.. _glossary: + +Glossary +======== + +.. glossary:: + + Packet + In the context of this module, the term *Packet* is used synonymously with *Bundle*. That means that whenever *Packet* is used, it refers to the data unit used on the overlay network layer created by the `Bundle Protocol `_. It refers **NOT** to packets of all underlying layers like on the transport layer of the Convergence Layers. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..1f226aa --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,40 @@ +.. pyDTNsim documentation master file, created by + sphinx-quickstart on Tue Dec 11 18:24:57 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +pyDTNsim - a DTN simulation environment +======================================= + +*pyDTNsim* provides a simulation environment that allows the simulation of arbitrary Delay Tolerant Networking (DTN) scenarios on a packet level. *pyDTNsim* provides users with the ability to evaluate the performance of various routing approaches and to detect possibly occurring overload situations. Currently, the focus lies on deterministic Contact-Graph-based routing approaches, but there might be other approaches available in the future. The clear modularization allows users to easily implement routing approaches on their own. + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + :caption: User Guide + + install + getting_started + examples + scenario_setup + routing/index + monitoring + data_processing + API pyDTNsim + +.. toctree:: + :maxdepth: 2 + :caption: Development Guide + + architecture + development_guide + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` +* :ref:`glossary` diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..58a36e2 --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,143 @@ +Installation +============ +Depending on the intended use case, the installation procedure for the library differs. If the library modules should only be invoked by custom scripts, installing ``pyDTNsim`` via the Python package index PyPi_ is sufficient. If the simulation modules have to be altered, downloading the source code and installing ``pyDTNsim`` as editable python module is required. + +.. _PyPi: https://pypi.org/ + +Module Dependencies +------------------- +The following modules are used in various contexts of ``pyDTNsim``. However, some are only necessary for the development of the module and not for running simulations. + +.. _dependency_table: + ++-------------------+-----------+-----------------------------+-----------+ +| Python Module | License | Purpose | Dev? [1]_ | ++===================+===========+=============================+===========+ +| networkx | BSD | Library allows the export | | +| | | of networkx ``DiGraph`` | | +| | | objects for additional | | +| | | graph analyses. | | ++-------------------+-----------+-----------------------------+-----------+ +| tqdm | MIT | Used for displaying the | | +| | | simulation progress (i.e. | | +| | | elapsed simulated seconds). | | ++-------------------+-----------+-----------------------------+-----------+ +| jsonschema | MIT | Validation of JSON schemes | | +| | | in the loaded topology | | +| | | files. | | ++-------------------+-----------+-----------------------------+-----------+ +| pytest | MIT | Used for running the | x | +| | | modules unit tests. Only | | +| | | executed in CI, | | +| | | not integrated otherwise. | | ++-------------------+-----------+-----------------------------+-----------+ +| sphinx | BSD | Generation of this | x | +| | | documentation. Not | | +| | | invoked by the module. | | ++-------------------+-----------+-----------------------------+-----------+ +| sphinx_rtd_theme | MIT | Theme for ``sphinx``. | x | ++-------------------+-----------+-----------------------------+-----------+ +| pylint | GPL | Tool for detecting source | x | +| | | code issues. Only | | +| | | executed in CI, | | +| | | not integrated otherwise. | | ++-------------------+-----------+-----------------------------+-----------+ +| pydocstyle | MIT | Tool for validating | x | +| | | docstrings in source code. | | ++-------------------+-----------+-----------------------------+-----------+ +| termcolor | MIT | Provides colorful shell | x | +| | | output when testing | | +| | | the examples of the module. | | ++-------------------+-----------+-----------------------------+-----------+ + +.. [1] Modules with 'Dev?' checked are only relevant in the development context of this module. + +pyDTNsim uses new Python features, in particular + +- `Data Classes `_ (3.7), +- `Formatted String Literals `_ (3.6) and +- `Insertion-Order Preservation `_ of items added to a ``dict`` object. (3.7). + +Therefore, **Python 3.7+** is currently required for using this library. + +.. note:: + + It is planned to establish compatibility with older versions (especially 2.7) in the future. + + +PyPi Installation +----------------- +The latest version of *pyDTNsim* can be installed with ``pip3``: + +.. code-block:: sh + + $ pip3 install pydtnsim + +Thats it, ``pip3`` will download the module from PyPi_ and install it locally. Check if the module was installed correctly by invoking a Python shell and importing the module: + +.. code-block:: python + + > import pydtnsim + +If no error occurs, the installation was successful. Continue with the with the section :ref:`getting_started`. + +Source Code Installation +------------------------ +Alternatively, the module can be made available in the local Python instance by downloading it from `Github `_ and then installing it as editable package. + +This more advanced installation is necessary when the library module (or parts of it) have to be altered. For example, this is the case if contributing to the module is intended. + +Archive Download and Extraction +""""""""""""""""""""""""""""""" +The source can be downloaded as `.zip `_ or `.tar.gz `_ archive. + +In Linux, the download and extraction of the files can usually also be achieved using the utilities ``wget`` and ``tar``: + +.. code-block:: sh + + $ wget https://github.com/ducktec/pydtnsim/archive/master.tar.gz + $ tar -xzf master.tar.gz + $ cd pydtnsim-master/ + +Git Clone +""""""""" +If the version-control system ``git`` is installed, the project can also be cloned: + +.. code-block:: sh + + $ git clone https://github.com/ducktec/pydtnsim.git + $ cd pydtnsim/ + +Module Installation +""""""""""""""""""" +.. warning:: Please store the ``pydtnsim/`` source code folder in an appropriate (long-term) directory on your local device. As we are installing the module as editable, the Python environment will continuously reference the files directly instead of copying them to hidden internal folders. Moving the directory around after the installation will likely result in broken references and errors! + +As next step, the module can be made available in the Python environment: + +.. code-block:: sh + + $ pip install -e "." + +``pip3`` installs the module as editable (achieved with the parameter ``-e``) and tries to satisfy all core dependencies (see above :ref:`dependency table `). + +If all development dependencies [1]_ shall be installed, the ``[dev]`` specifier has to be added to the installation command: + +.. code-block:: sh + + $ pip install -e ".[dev]" + +Check if the module was installed correctly by invoking a Python shell and importing the module: + +.. code-block:: python + + > import pydtnsim + +If no error occurs, the installation was successful. Continue ith the section :ref:`getting_started`. + +.. tip:: + + A recommendation in general, but a must in the context of upstream development is the use of the environment wrappers `pyenv `_ (for the version of the Python interpreter) and `pipenv `_ (for the Pip package environment). The configuration files for *pipenv* are provided (``Pipfile`` and ``Pipfile.lock``) and contain also the requirements for *pyenv*. + + In combination, the wrappers ensure a sound and deterministic development environment for all developers by installing clearly specified versions and encapsulating them from the other python (package) installations on the systems. An article outlining the benefits of the wrappers can be found at [#]_. + +.. [#] https://hackernoon.com/reaching-python-development-nirvana-bb5692adf30c?gi=26b62f02bc0b diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..27f573b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/monitoring.rst b/docs/monitoring.rst new file mode 100644 index 0000000..f99db46 --- /dev/null +++ b/docs/monitoring.rst @@ -0,0 +1,2 @@ +Simulation Monitoring +===================== diff --git a/docs/references.bib b/docs/references.bib new file mode 100644 index 0000000..5c0d76f --- /dev/null +++ b/docs/references.bib @@ -0,0 +1,8 @@ +@article{Vahdat2000, +author = {Vahdat, Amin and Becker, David}, +journal = {Technical Report}, +number = {CS-200006}, +title = {{Epidemic routing for partially connected ad hoc networks}}, +url = {http://cseweb.ucsd.edu/~vahdat/papers/epidemic.pdf}, +year = {2000} +} diff --git a/docs/resources/data_format_ion.xml b/docs/resources/data_format_ion.xml new file mode 100644 index 0000000..efdde21 --- /dev/null +++ b/docs/resources/data_format_ion.xml @@ -0,0 +1 @@ +7Zldb5swFIZ/DZeV+EhIuCxpu07atG6ZtN1NLj4FawZHxmnS/fodggkfTpu1XSlIyUWEX5tj+zwvjnEsb5FuP0iySj4LCtxybbq1vAvLdSezKX4XwkMpuEFQCrFktJScWliyP6BFW6trRiFvNVRCcMVWbTESWQaRamlESrFpN7sTvN3risRgCMuIcFP9wahKSnXuzmr9GlicVD07vp5fSqrGeiZ5QqjYNCTv0vIWUghVXqXbBfAid1VeyvuuHqndD0xCpv7lBh7GP7efzhL7S5h+vVIk+vUxPnPcMsw94Ws9Yz1a9VClIJZivbK8MBX35HYn2liSkLM/zbJQRDXK6ANoloGyZlHzaih6ICAVbA+h1U3rhDan7uwTikYEkYKSD9ikCuTMy1u0CZ2JDrGpkTpzPfOkgbPqimgXxfvQdaLxQuf6OXk30k6MvGMecBhholIMfeHgZa6k+A0LwYVEJRMZtgzvGOcdiXAWZ1iMMD+AelhklaGpz3VFyigtugk3CVOwXJGo6HODT/CO5DqjQDWWO5GpKrzlev7u845uaFJ/wtKmF5qs+0RtPmE4W6xTJ+BvC3zbht3gP7V75O8dWGFDZxzwbTsIbHvE8NG5Xfhun/Anh+B7vm2Pg39Bf9T8A8fgP+mT/9Tg79i7lI4CfzFS3K+PF78zMRf/Xvk7pgEM9JDR8+JNpWDISZ6zqG2Ex6DkYi0juAHJcKwgC7Asi7HRFCsVkTGoA5X+Pt9AjVefoxvqIz+ilSaBE8Xu2+EPJVf3cCMYdlxj8+z2fj3o8NFTL+9qvvN0A007gfxOIJ2mbqAd6/20X4HfP+F/Af75/8IfvDP+2Qn/8/HvV+jX4ne7y0jf+Ocn/C/A331oX4y/u4z0jN9c+5fYYzHA78jFcMJAd4ADegE8csjnTzu+0eX32vuZiz/yRy6W6/OC9K3Eq7i4ugZCQZr6ODwyqBOiYwfB7rA8Yv5CXGbUNEK5YIzTHoM6Q3jaHm61YRuKPQLDHheYJNMJ34garT8GdchwxB+z7tbkzfyBxfqvwXJHUv+/6l3+BQ== \ No newline at end of file diff --git a/docs/resources/getting_started/dtn_simulation.py b/docs/resources/getting_started/dtn_simulation.py new file mode 100644 index 0000000..d265302 --- /dev/null +++ b/docs/resources/getting_started/dtn_simulation.py @@ -0,0 +1,20 @@ +"""Minimal Simulation Example.""" + +from pydtnsim import Simulator, ContactPlan, ContactGraph, Contact +from pydtnsim.nodes import SimpleCGRNode +from pydtnsim.packet_generators import BatchPacketGenerator + +from pydtnsim.routing import cgr_basic + + +def main(): + """Simulate basic scenario.""" + # Create simulation environment + simulator = Simulator() + + # Run the simulation for 1000 seconds (1000000 ms) + simulator.run_simulation(1000000) + + +if __name__ == "__main__": + main() diff --git a/docs/resources/getting_started/dtn_simulation_elements.py b/docs/resources/getting_started/dtn_simulation_elements.py new file mode 100644 index 0000000..3a400db --- /dev/null +++ b/docs/resources/getting_started/dtn_simulation_elements.py @@ -0,0 +1,74 @@ +from pydtnsim import Simulator +from pydtnsim import ContactPlan, ContactGraph, Contact +from pydtnsim.nodes import SimpleCGRNode +from pydtnsim.routing import cgr_basic +from pydtnsim.packet_generators import ContinuousPacketGenerator + +def main(): + """Simulate basic scenario.""" + # Create simulation environment + simulator = Simulator() + + # Generate empty contact plan + contact_plan = ContactPlan(10, 50) + + # Add the contacts + contact_plan.add_contact('node_a', 'node_b', 0, 100000) + contact_plan.add_contact('node_a', 'node_b', 500000, 750000) + contact_plan.add_contact('node_b', 'node_c', 0, 200000) + contact_plan.add_contact('node_b', 'node_c', 350000, 400000) + contact_plan.add_contact('node_b', 'node_c', 950000, 990000) + + # Convert contact plan to contact graph + contact_graph = ContactGraph(contact_plan) + + # Generate contact objects and register them + for planned_contact in contact_plan.get_contacts(): + # Create a Contact simulation object based on the ContactPlan + # information + contact = Contact(planned_contact.from_time, planned_contact.to_time, + planned_contact.datarate, planned_contact.from_node, + planned_contact.to_node, planned_contact.delay) + # Register the contact as a generator object in the simulation + # environment + simulator.register_contact(contact) + + # Generate network node objects and register them + for planned_node in contact_plan.get_nodes(): + # Generate contact list of node + contact_list = contact_plan.get_outbound_contacts_of_node(planned_node) + # Create a dict that maps the contact identifiers to Contact simulation + # objects + contact_dict = simulator.get_contact_dict(contact_list) + # Create a node simulation object + SimpleCGRNode(planned_node, contact_dict, cgr_basic.cgr, contact_graph, + simulator, []) + + # Generate packet generator 1 and register them + generator1 = ContinuousPacketGenerator( + 10, # Data Generation Rate: 10 Bytes per ms + 100000, # Packet Size: 100 KB + ['node_a'], # From 'node_a' + ['node_c'], # To 'node_c' + 0, # Start injection at simulation time 0s + 1000000) # End injection at simulation end (1000s) + + # Generate packet generator 2 and register them + generator2 = ContinuousPacketGenerator( + 10, # Data Generation Rate: 10 Bytes per ms + 100000, # Packet Size: 100 KB + ['node_c'], # From 'node_c' + ['node_a'], # To 'node_a' + 0, # Start injection at simulation time 0s + 1000000) # End injection at simulation end (1000s) + + # Register the generators as a generator objects in the simulation + # environment + simulator.register_generator(generator1) + simulator.register_generator(generator2) + + # Run the simulation for 1000 seconds (1000000 ms) + simulator.run_simulation(1000000) + +if __name__ == "__main__": + main() diff --git a/docs/resources/getting_started/injection_methods.svg b/docs/resources/getting_started/injection_methods.svg new file mode 100644 index 0000000..7020591 --- /dev/null +++ b/docs/resources/getting_started/injection_methods.svg @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + t + + + + + + + + + + Injected + + + Packets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + t + + + + + + + + + + Injected + + + Packets + + + + + + + + + + + + + + + + + + Batch + Continuous + + + diff --git a/docs/resources/getting_started/packet_injection_scheme.svg b/docs/resources/getting_started/packet_injection_scheme.svg new file mode 100644 index 0000000..8387021 --- /dev/null +++ b/docs/resources/getting_started/packet_injection_scheme.svg @@ -0,0 +1,2 @@ + +
Dest D
Dest D
Dest E
Dest E
Dest F
Dest F
Source A
Source A
Source B
Source B
Source C
Source C
List of
Source Nodes
List of<br>Source Nodes<br>
List of
Destination Nodes
List of<br>Destination Nodes<br>
An arrow signals injection of packets for that node pair
An arrow signals injection of packets for that node pair
(
(
)
)
\ No newline at end of file diff --git a/docs/resources/getting_started/packet_injection_scheme.xml b/docs/resources/getting_started/packet_injection_scheme.xml new file mode 100644 index 0000000..b506494 --- /dev/null +++ b/docs/resources/getting_started/packet_injection_scheme.xml @@ -0,0 +1 @@ +7Vtdb6M4FP01kWYfdgU2X3lsknbmobMaKdKutG8OGHBLcOQ4TTK/fu1gCOCQZBQ+lE6KVOFrDL7nnGtfYzKC0+XuK0Or+DsNcDICRrAbwdkIAMcdi//SsM8MFnAzQ8RIkJnMo2FOfmJlNJR1QwK8rlzIKU04WVWNPk1T7POKDTFGt9XLQppUn7pCEdYMcx8luvVfEvA4s3q5F9L+DZMozp9sOsrhJcovVp6sYxTQbckEn0dwyijl2dlyN8WJxC7HJWv30lBbdIzhlF/T4Bty57MP/+31ffLf01fjn02wn/wJsrt8oGSjHFad5fscAXEXAbYoTLYx4Xi+Qr6s2Qq6hS3my0SUTHHKKEec0FQUx4YoL+kHWhzucqjFa/KzXJZXl8pCN7hcxgEpFxW/5QZoHeNAFUKSJFOaUHboM3wx5CHsyj3MON414mYWbAgVY7rEnO3FJaqBrSBRAjYBzMrboxxM18pscVkKOZZISTAqbn1kSZwoon6BNBM+WLvEGsxBKmizhqYNtBlsaL3KhruQ7CSedSztZ3m0hKVr/WVfRtM4AabRFZZ6CMzwmgvLTMNUOM6r4K05o+84RyulKa4BqEwoIZEMjASH8g4SRCKmhidlXpIgSJq4YnSTBgelt6Voz66zYI41FtwTLICuWDCdz6NoV8eyV0WbbpOin38jRbv6uNKvosefRtEADj1GG02Kfvl9FA3AwGM0cDSwq26XMH/DnO/VGgxtOBUmynhMI5qi5JXSlbqOIxZh/gMzIvqImUSVpJGohJI4umE+bqoUTbl6giPzxTQolWrxESDshb6mBVHj+B5ehAVnONAWcTXGhP+Hbp0BSmUUmW8X0zhdAgwnIpH+qHakfTo9fTwS3s9VUQVFI8N1/M+SVSXnLOnXKucuGM7SmhsYVk1/UJLy4+BgOrXJzqrFvCIja1XTSdGNG6Qzfkinc+mM+5EOhL1Kp80XDpeyojPETr3nyUs7M7VpO1VEh17RWhrE80yUwHjqIF1imUu35EshTXlH7HhWlZyhF7rQ0Ci446Ez9Hzsn4ywhWdbttHu0Gn3lVddOXS6/c660HxIp2vpdJawVecIYPQsnROz7EM6LUunn4Stb+nYPSZszcROqsS2m7AN/cJWf/ddJGyTu0jY2mSnnrAN/R43Xx99jqEzsLEXWKcizAML6DjtDp3joRM2szp0wp5nXeshna6l01HCBj3j/KyrEO5MOvZDOp1L59aE7aZ5pc/twXP4T8r4t5pXDb5taOrbhkViNb2LxKpNemqJ1eDbidDT2Hklh01dGo6Ak0gkF0ycRfKsIO5vKr/i1Oo7oNMXwGJ2G5/Vj9Sq5BqHv3bIHXsVcvM147b8oWmf3Oqj2xlu5V4+SbNvBx8EN3wPYBmXGDZBn+FrXfFiIBJYrRqdr37SOSq6+gszjlvL0ixPQ6XI3CqogK5Q0aecJynqwwfkEhwhMJSs5W3SN+F8JnkZFMJt/x1zWRUKAYn8JUYyYFIRDodawu4wBFxPHsquEsfxtRFxRneNkgA1RehR4vQaJaamhy/3QqOiC0Cd1pkpj054LFFl9cqUvm36x4OpKyKuCKj2mRPF469asqX18adB8Pl/ \ No newline at end of file diff --git a/docs/resources/getting_started/topology.svg b/docs/resources/getting_started/topology.svg new file mode 100644 index 0000000..9c042f0 --- /dev/null +++ b/docs/resources/getting_started/topology.svg @@ -0,0 +1,2 @@ + +
Node
A
[Not supported by viewer]
Node
B
[Not supported by viewer]
Node
C
[Not supported by viewer]
[0,100)
[500,750)
[Not supported by viewer]
[0,200)
[350,400)
[950,990)
[Not supported by viewer]
\ No newline at end of file diff --git a/docs/resources/getting_started/topology.xml b/docs/resources/getting_started/topology.xml new file mode 100644 index 0000000..eb49a80 --- /dev/null +++ b/docs/resources/getting_started/topology.xml @@ -0,0 +1 @@ +5VfbjpswEP0aHvrQCuyQy2Ngk66222qlPHT3qfKCA24Npsa59es7DiaEW0qrtNpVFSnynLHHnjNzDFjYT/bvJcnijyKk3EJ2uLfwjYXQ1HHhXwOHAnAdXACRZGEBORWwYj+oAW2DblhI89pEJQRXLKuDgUhTGqgaRqQUu/q0teD1XTMS0RawCghvo59ZqGKTFppU+C1lUVzu7IxnhSch5WSTSR6TUOzOILywsC+FUMUo2fuUa+5KXop1yx7v6WCSpmrIgntyp5bf7z5sb/1x9uUZJTl7eGuibAnfmIQ/QQUtNOYQ03uWMIr0aN6GTFbqUFIF20FVwPB2MVN0lZFAe3bQF4DFKuFgOTAkeVaUas32FE7nrRnnvuBCHgPhJdK/0xZbKhXd92btnLiEHqQioUoeYEq5YGToN/03NuauKqZroPisjiVGTPtEp8AVwzAwJP8G4eM2bSE0nDGFVLGIREr4okI9KTZpqIm6setE0j1Tj2fjJz3lnautFA77aFYcjcqXKyLVXGsDoICTPGdBCS8ZL4N/pUodjCDJRgmAquPdC5GZeUVCOovLJYKkxUYG9AI5yAicyIiqC/Nwd8kl5USxbf0cV68gGigZ77VKBqOXJRk8kHD/tRLu2i+L8FGL8DaPadi+Qc7oG3jHXPHuKF8OfnV3oO5SDOR68BVjdngQDBLpfRo500YNizTNqvOHeTPQrBEINwIVPLQCHfvhlPaft8ik3SKuB0fwHdt+06FD1zs2uT9xO93N9gItqWZDSfGNlgJMRUobmjQQ4SxKdc9BA1HAPa1MBu9zc+NQ+sHVqf76Y/YKukYNXU/dlq4dp6vZ3L8k7Glf1VBf1bBufH/U554d3bPZf1RUPP1nRQWz+jwolFt9Y+HFTw== \ No newline at end of file diff --git a/docs/routing/cgr.rst b/docs/routing/cgr.rst new file mode 100644 index 0000000..8fcede5 --- /dev/null +++ b/docs/routing/cgr.rst @@ -0,0 +1,2 @@ +Contact Graph Routing +===================== diff --git a/docs/routing/index.rst b/docs/routing/index.rst new file mode 100644 index 0000000..f2fe493 --- /dev/null +++ b/docs/routing/index.rst @@ -0,0 +1,11 @@ +.. _routing_mechanisms: + +Routing Mechanisms +================== + +With ``pyDTNsim``, the behavior of various routing mechanisms can be simulated. The currently implemented mechanisms are outlined in the next chapters: + +.. toctree:: + :maxdepth: 2 + + cgr diff --git a/docs/scenario_setup.rst b/docs/scenario_setup.rst new file mode 100644 index 0000000..1e44675 --- /dev/null +++ b/docs/scenario_setup.rst @@ -0,0 +1,2 @@ +Simulation Scenario Setup +========================= diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 0000000..0b0f9ed --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,7 @@ +pydtnsim +======== + +.. toctree:: + :maxdepth: 4 + + pydtnsim diff --git a/docs/source/pydtnsim.backend.rst b/docs/source/pydtnsim.backend.rst new file mode 100644 index 0000000..f0d7da8 --- /dev/null +++ b/docs/source/pydtnsim.backend.rst @@ -0,0 +1,22 @@ +pydtnsim.backend package +======================== + +Submodules +---------- + +pydtnsim.backend.qsim module +---------------------------- + +.. automodule:: pydtnsim.backend.qsim + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim.backend + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pydtnsim.monitors.rst b/docs/source/pydtnsim.monitors.rst new file mode 100644 index 0000000..a0d8764 --- /dev/null +++ b/docs/source/pydtnsim.monitors.rst @@ -0,0 +1,30 @@ +pydtnsim.monitors package +========================= + +Submodules +---------- + +pydtnsim.monitors.base\_monitor module +-------------------------------------- + +.. automodule:: pydtnsim.monitors.base_monitor + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.monitors.monitor\_notifier module +------------------------------------------ + +.. automodule:: pydtnsim.monitors.monitor_notifier + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim.monitors + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pydtnsim.nodes.rst b/docs/source/pydtnsim.nodes.rst new file mode 100644 index 0000000..477d35d --- /dev/null +++ b/docs/source/pydtnsim.nodes.rst @@ -0,0 +1,22 @@ +pydtnsim.nodes package +====================== + +Submodules +---------- + +pydtnsim.nodes.simple\_cgr\_node module +--------------------------------------- + +.. automodule:: pydtnsim.nodes.simple_cgr_node + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim.nodes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pydtnsim.packet_generators.rst b/docs/source/pydtnsim.packet_generators.rst new file mode 100644 index 0000000..a442564 --- /dev/null +++ b/docs/source/pydtnsim.packet_generators.rst @@ -0,0 +1,38 @@ +pydtnsim.packet\_generators package +=================================== + +Submodules +---------- + +pydtnsim.packet\_generators.base\_packet\_generator module +---------------------------------------------------------- + +.. automodule:: pydtnsim.packet_generators.base_packet_generator + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.packet\_generators.batch\_packet\_generator module +----------------------------------------------------------- + +.. automodule:: pydtnsim.packet_generators.batch_packet_generator + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.packet\_generators.continuous\_packet\_generator module +---------------------------------------------------------------- + +.. automodule:: pydtnsim.packet_generators.continuous_packet_generator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim.packet_generators + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pydtnsim.routing.rst b/docs/source/pydtnsim.routing.rst new file mode 100644 index 0000000..b61cd02 --- /dev/null +++ b/docs/source/pydtnsim.routing.rst @@ -0,0 +1,54 @@ +pydtnsim.routing package +======================== + +Submodules +---------- + +pydtnsim.routing.cgr\_anchor module +----------------------------------- + +.. automodule:: pydtnsim.routing.cgr_anchor + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.routing.cgr\_basic module +---------------------------------- + +.. automodule:: pydtnsim.routing.cgr_basic + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.routing.cgr\_utils module +---------------------------------- + +.. automodule:: pydtnsim.routing.cgr_utils + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.routing.dijkstra module +-------------------------------- + +.. automodule:: pydtnsim.routing.dijkstra + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.routing.scgr module +---------------------------- + +.. automodule:: pydtnsim.routing.scgr + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim.routing + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/pydtnsim.rst b/docs/source/pydtnsim.rst new file mode 100644 index 0000000..cf7ec11 --- /dev/null +++ b/docs/source/pydtnsim.rst @@ -0,0 +1,65 @@ +pydtnsim package +================ + +Subpackages +----------- + +.. toctree:: + + pydtnsim.backend + pydtnsim.monitors + pydtnsim.nodes + pydtnsim.packet_generators + pydtnsim.routing + +Submodules +---------- + +pydtnsim.contact module +----------------------- + +.. automodule:: pydtnsim.contact + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.contact\_graph module +------------------------------ + +.. automodule:: pydtnsim.contact_graph + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.contact\_plan module +----------------------------- + +.. automodule:: pydtnsim.contact_plan + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.packet module +---------------------- + +.. automodule:: pydtnsim.packet + :members: + :undoc-members: + :show-inheritance: + +pydtnsim.simulator module +------------------------- + +.. automodule:: pydtnsim.simulator + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pydtnsim + :members: + :undoc-members: + :show-inheritance: diff --git a/pydtnsim/__init__.py b/pydtnsim/__init__.py index f3e772a..6632a28 100644 --- a/pydtnsim/__init__.py +++ b/pydtnsim/__init__.py @@ -1,6 +1,6 @@ """Discrete event simulation library for DTN.""" -from .simulator import Simulator +from .simulator import Simulator, Output from .contact_graph import ContactGraph from .contact_plan import ContactPlan, ContactIdentifier from .contact import Contact diff --git a/pydtnsim/simulator.py b/pydtnsim/simulator.py index 7b99c97..3582782 100644 --- a/pydtnsim/simulator.py +++ b/pydtnsim/simulator.py @@ -126,6 +126,7 @@ def run_simulation(self, # Signal to monitors that simulation ended self.notifier.simulation_ended() + print("Simulation completed!") self.__print_stats() def register_node(self, node): @@ -216,12 +217,6 @@ def __print_stats(self): 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):