11.3.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 974b435a authored by Daniel Lehmberg's avatar Daniel Lehmberg

Squashed 'Tools/SUQController/' changes from f75af9422..2bcc6f3ee

2bcc6f3ee Merge branch 'omnet_add_on_final' into 'master'
ca96ef284 Merge branch 'master' into omnet_add_on_final
34d78229e minor changes
42f00a252 minor changes (pyDOE not global dependency)
980041184 minor changes
2ef30133c corrected vadere server name
5666a686b add vadere server id
db95e7a4e moved file to repo Forschung
1781dbeb3 social dist calibration
99a919b35 refactored
83d944bd7 moved util function into rover class CoupledDictVariation
66bac6af3 read data for succesfull sim runs
3ff758a1a refactored
45d5b59d0 use vadere default seed instead of seed "42"
17dd13cfe get enviromenment_manager info
933181b19 create subset of simulations
108747469 set seeds with omnet ini file
b1c5bee19 only copy folder structure and xml files
ef848d982 use nlevels
08df62298 added some explanations
c3b4d6bc3 Merge branch 'onnet_add_on3' into omnet_add_on_final
639822bc8 Auto stash before merge of "omnet_add_on_final" and "origin/omnet_add_on_final"
c044e1bc3 Apply suggestion to suqc/parameter/sampling.py
733769944 further refactoring
51123ef2d applied some suggestions
6eecb3e8c do not copy cache results
6d70e73a4 Apply suggestion to suqc/environment.py
7629d24b6 Merge branch 'omnet_add_on_final0' into omnet_add_on_final
c2468db5c update
dd8afe40c Update README.md
b6c68b8f2 Update README.md
c852a6d74 Update README.md
1fae57c3d Update README.md
d4d1944c4 Update README.md
4605c5942 Apply suggestion to requirements.txt
ce488ff72 remove output after each simulation run in rover
c4d3c688f implemented AbstractScenarioCreation
8c7f67c1d abstract 2
f14585306 VaderQoI s parent class is Qoi
a7b990113 use scenario file defined in config
a6b02378f moved classed into sampling.py
41776cf94 set runscript to class attribute
4b54ba0fb give qoi to external python script
5039ddf2d added GenerealOutputFile
6a1c75540 use general QoI
34d88a1fc removed waiting
1176810db format code
664225e14 allow multiple runs
101905a4b wrong value
fceb0dbbc final setup of parameter studies
d46f84f2c removed figures
95d0bede4 removed seed
83fd95dca added shadowing study
94300edbd fixed bugs and refactored
b488aae21 extended sampling methods
85086f7ab before introducing new sampling feature
c68f3abb7 repition test
0516249ab some parameterstudies to compare with LTE
872dc90ce use different numbr of repititions
98b8d22e8 refactored for rover sim
015c13f10 adapted postprocessing for Python 3.8
f6da2f347 fixed bug
af30aa71b prepared for FP
55cd34485 added postprocessing
12012a827 added postprocessing
6e9565929 added utility for vector parameters
419bd6d74 added dependent parameters
ff94bcd59 read qoi
606324287 changed scenario
5951e9187 no parralel runs
e066af5e9 produce error in deep_look_up
8f9822a69 extended framework with abstract consolewrapper
97c6bc77d moved methods in abstract class
5f50ddecc sorted scripts
f588d5ed1 also parse inifiles
4b34227b4 create rover structure in output folder
577133bac minor: add TODO
d5114d6a7 Merge branch 'delete_me' into test
c4d7b7cbf added classes and tried to access data
216dc10b6 Merge branch 'CM' into 'master'
9fa54dc33 added forgotten if query for reading data
824d6f9cb adapt read from existing output
791e3e13b apply black and isort
9ff248e3d Merge branch 'master' into omnet_add_on (apply black isort)
ea9e16349 apply black and isort
64d7b4afc Merge remote-tracking branch 'origin/omnet_add_on' into omnet_add_on
1623c7f3e created sampling with units
c4f62c728 add ConfigParser for OMNeT++ ini files.
b9b446001 Merge remote-tracking branch 'origin/master'
f62bf74b3 scenario runs for FolderExistScenarios

git-subtree-dir: Tools/SUQController
git-subtree-split: 2bcc6f3eeb520df2c455a112016b86fda95cc607
parent 7a9937ed
......@@ -45,3 +45,27 @@ not installed successfully.
### Introduction
See [SRC_PATH]/tutorial
#### Using SUQC and Vadere
Here a few hints for your .scenario file for Vadere:
1. ScenarioChecker
Before running your scenario automatically on suqc, activate the ``ScenarioChecker`` (Project > Activate ScenarioChecker) and run it in the ``VadereGui``.
The ScenarioChecker will point out potential problems with your scenario file.
2. Default parameters
Make sure to set ``realTimeSimTimeRatio`` to 0.0. (Values > 0.0 slow down the simulation for the visualisation)
Another point that may cost a lot of computation time is the ``optimizationType``, consider using ``DISCRETE`` (discrete optimization) instead of ``NELDER_MEAD``. Please note, that ``varyStepDirection`` should always be activated with discrete optimization.
Remove ``attributesCar`` from the .scenario file if you are not using any vehicles to avoid confusion of attributes.
3. Visual check
Visually check the results of your simulation, maybe check upper and lower parameter bounds.
4. Clean topography
Remove elements in your topography that are not used. Sometimes through the interaction with the mouse, tiny obstacles or targets are created unintentionally.
Check the elements in your topography, you can take a look at the ``ElementTree`` in the Topography creator tab. Remove all elements that are unused, especially focusing on targets.
5. Data processors
Remove all data processors and output files that you don't use. In particular, remove the overlap processors, they are intended for testing purposes.
6. Reproducibility
Make sure that your runs are reproducible - work with a ``fixedSeed`` by activating ``useFixedSeed`` or save all the ``simulationSeed``s that have been used.
(Another way is to provide a ``fixedSeed`` for each runs with suqc, in this case make sure that ``useFixedSeed`` is true.)
......@@ -2,15 +2,15 @@
import os
from setuptools import setup, find_packages
from setuptools import find_packages, setup
from suqc.configuration import SuqcConfig
from suqc import __version__
from suqc.configuration import SuqcConfig
# To generate a new requirements.txt file run in console (install vis 'pip3 install pipreqs'):
# pipreqs --use-local --force /home/daniel/REPOS/suq-controller
with open('requirements.txt', "r") as f:
with open("requirements.txt", "r") as f:
requirements = f.read().splitlines()
# Writes a file that gives information about the version such that "suqc.__version__" provides the current version,
......@@ -27,7 +27,7 @@ setup(
data_files=[('suqc', ["suqc/PACKAGE.txt"])]
data_files=[("suqc", ["suqc/PACKAGE.txt"])],
......@@ -5,4 +5,4 @@ from suqc.parameter.postchanges import PostScenarioChangesBase
from suqc.qoi import *
from suqc.request import *
__version__ = "2.0"
__version__ = "2.1"
#!/usr/bin/env python3
import os
import json
import os
import os.path as p
import pathlib
# configuration of the suq-controller
DEFAULT_SUQC_CONFIG = {"default_vadere_src_path": "TODO", # TODO Feature: #25
"server": {
"host": "",
"user": "",
"port": -1}}
"default_vadere_src_path": "TODO", # TODO Feature: #25
"server": {"host": "", "user": "", "port": -1},
def check_setup(_paths_class):
if not os.path.exists(_paths_class.path_cfg_folder()) and _paths_class.is_package_paths():
if (
not os.path.exists(_paths_class.path_cfg_folder())
and _paths_class.is_package_paths()
print(f"INFO: Setting up configuration folder {_paths_class.path_cfg_folder()}")
# the next two checks will fail automatically too, because the folder is empty
if not os.path.exists(_paths_class.path_suq_config_file()):
print(f"INFO: Setting up default configuration file located at {_paths_class.path_suq_config_file()}")
f"INFO: Setting up default configuration file located at "
if not os.path.exists(_paths_class.path_container_folder()):
print(f"INFO: Setting up the default container path (which will store output of simulation runs). "
f"Location {_paths_class.path_container_folder()}")
f"INFO: Setting up the default container path "
f"(which will store output of simulation runs). "
f"Location {_paths_class.path_container_folder()}"
return _paths_class
......@@ -128,4 +135,4 @@ class SuqcConfig(object):
if __name__ == "__main__":
\ No newline at end of file
This diff is collapsed.
import enum
from collections.abc import MutableMapping
from configparser import ConfigParser, NoOptionError
class OppParser(ConfigParser):
def optionxform(self, optionstr):
return optionstr
class OppConfigType(enum.Enum):
Set type on OppConfigFileBase to create read-only configurations if needed.
def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
elif type(other) is int:
return self.value < other
return NotImplemented
def __gt__(self, other):
return self != other and other < self
def __eq__(self, other):
if self.__class__ is other.__class__:
return self.value == other.value
elif type(other) is int:
return self.value == other
return NotImplemented
def __le__(self, other):
return self < other or self == other
def __ge__(self, other):
return self > other or self == other
class OppConfigFileBase(MutableMapping):
Represents an omnetpp.ini file. The extends logic is defined in SimulationManual.pdf p.282 ff.
Each OppConfigFileBase object has a reference to complete omnetpp.ini configuration file but
only access's its own options, as well as all options reachable by the search path build
using the 'extends' option.
Example(taken form [1]):
The search path for options for the configuration `SlottedAloha2b` is:
[Config SlottedAlohaBase]
[Config LowTrafficSettings]
[Config HighTrafficSettings]
[Config SlottedAloha1]
extends = SlottedAlohaBase, LowTrafficSettings
[Config SlottedAloha2]
extends = SlottedAlohaBase, HighTrafficSettings
[Config SlottedAloha2a]
extends = SlottedAloha2
[Config SlottedAloha2b]
extends = SlottedAloha2
[1]: https://doc.omnetpp.org/omnetpp/manual/#sec:config-sim:section-inheritance
def from_path(
cls, ini_path, config, cfg_type=OppConfigType.EDIT_LOCAL, is_parent=False
_root = OppParser(inline_comment_prefixes="#")
return cls(_root, config, cfg_type, is_parent)
def __init__(
root_cfg: OppParser,
config_name: str,
self._root: OppParser = root_cfg
self._cfg_type = cfg_type
self._sec = self._ensure_config_prefix(config_name)
if not self._has_section_(self._sec):
raise ValueError(f"no section found with name {self._sec}")
self._parent_cfg = []
self.section_hierarchy = [self._ensure_config_prefix(self._sec)]
self._is_parent = is_parent
if not self._is_parent:
stack = [iter(self.parents)]
while stack:
for p in stack[0]:
if p == "":
_pp = OppConfigFileBase(self._root, p, is_parent=True)
if len(_pp.parents) > 0:
if config_name != "General" and self._has_section_("General"):
OppConfigFileBase(self._root, "General", is_parent=True)
def writer(self, fp):
""" write the current state to the given file descriptor. Caller must close file."""
def _ensure_config_prefix(val):
""" All omnetpp configurations start with 'Config'. Add 'Config' if it is missing. """
if not val.startswith("Config") and val != "General":
return f"Config {val.strip()}"
return val
def section(self):
""" Section managed by this OppConfigFileBase object (read-only) """
return self._sec
def parents(self):
""" local parents i.e all configurations listed in the 'extends' option (read-only) """
return [
for s in self._getitem_local_("extends", default="").strip().split(",")
def type(self):
return self._cfg_type
def is_local(self, option):
Returns True if the given object belongs directly to the current section and False if
options is contained higher up the hierarchy OR does not exist.
return self._contains_local_(option)
def get_config_for_option(self, option):
Returns the name of the section the option first occurs search order: local --> general
or None if option does not exist
if self._contains_local_(option):
return self.section
for p in self._parent_cfg:
if p._contains_local_(option):
return p.get_config_for_option(option)
return None
def _has_section_(self, sec):
True if section exist in the configuration. Note: Returns also True even if given section is not
in the section_hierarchy if the current section.
return self._root.has_section(sec)
def _getitem_local_(self, k, default=None):
Search for key in local configuration
return self._root.get(self._sec, k)
except NoOptionError:
if default is not None:
return default
raise KeyError(f"key not found. Key: {k}")
def _set_local(self, k, v):
Set new value for key. OppConfigType checks already done
self._root.set(self._sec, k, v)
def _contains_local_(self, k):
True if key exist in current section (parents are not searched) otherwise False
return self._root.has_option(self._sec, k)
def _contained_by_parent(self, k):
True if key exists in any parent. Note key my exist multiple time but only first occurrence of key
will be returned. See search path.
return any([k in parent for parent in self._parent_cfg])
def _delitem_local(self, k):
Delete local key.
self._root.remove_option(self._sec, k)
def __setitem__(self, k, v):
if self._cfg_type is OppConfigType.READ_ONLY:
raise NotImplementedError("Cannot set value on read only config")
if self._contains_local_(k):
self._set_local(k, v)
elif self._contained_by_parent(k):
if self._cfg_type <= OppConfigType.EDIT_LOCAL:
raise NotImplementedError("Cannot edit value of parent config")
for p in self._parent_cfg:
if p._contains_local_(k):
p._set_local(k, v)
raise KeyError(f"key not found. Key: {k}")
def __delitem__(self, k):
if self._cfg_type.value < OppConfigType.EXT_DEL_LOCAL:
raise ValueError(
f"current object does not allow deletion. cfg_type={self._cfg_type}"
if k not in self:
raise KeyError(f"key not found. Key: {k}")
if self._contains_local_(k):
self._root.remove_option(self._sec, k)
raise NotImplementedError(
f"deletion of parent config option not implemented"
def __getitem__(self, k):
if k not in self:
raise KeyError(f"key not found. Key: {k}")
if self._contains_local_(k):
return self._getitem_local_(k)
for parent in self._parent_cfg:
return parent._getitem_local_(k)
except KeyError:
raise KeyError(f"key not found. Key: {k}")
def __contains__(self, k) -> bool:
if self._contains_local_(k):
return True
elif any([k in parent for parent in self._parent_cfg]):
return True
return False
def __len__(self) -> int:
_len = 0
for s in self.section_hierarchy:
_len += len(self._root.items(s))
return _len
def __iter__(self):
for s in self.section_hierarchy:
for item in self._root.items(s):
yield item
def items(self):
return list(self.__iter__())
def keys(self):
return [k for k, _ in self.__iter__()]
def values(self):
return [v for _, v in self.__iter__()]
def get(self, k):
return self[k]
def setdefault(self, k, default=...):
if k in self:
return self[k]
if self._cfg_type <= OppConfigType.EDIT_LOCAL:
raise NotImplementedError(
"Cannot set value on READ_ONLY or EDIT_LOCAL config. Use EXT_DEL_LOCAL "
self._set_local(k, default)
return default
class OppConfigFile(OppConfigFileBase):
Helpers to manage OMNeT++ specifics not part of the standard ini-Configuration
* Read/Write int and doubles
* specify units (i.e. s, dBm, m)
* Handle string quotes (are part of the value)
todo: implement
def __init__(self, root_cfg: OppParser, config_name: str):
super().__init__(root_cfg, config_name)
import os
import unittest
from suqc.opp.config_parser import OppConfigFileBase, OppConfigType
class OppConfigFileBaseTest(unittest.TestCase):
NEW_FILE = "omnetpp_2.ini"
NEW_FILE_COMP = "omnetpp_compare.ini"
NEW_FILE_DEL = "omnetpp_del.ini"
def get_object(
config, cfg_type=OppConfigType.EDIT_LOCAL, is_parent=False, path="omnetpp.ini"
return OppConfigFileBase.from_path(
os.path.join(os.path.split(__file__)[0], path), config, cfg_type, is_parent
def save_object(obj: OppConfigFileBase, path):
with open(os.path.join(os.path.split(__file__)[0], path), "w") as f:
def get_lines(path):
with open(os.path.join(os.path.split(__file__)[0], path), "r") as f:
return f.readlines()
def tearDown(self) -> None:
f = os.path.join(os.path.split(__file__)[0], self.NEW_FILE)
if os.path.exists(f):
def test_set_default_exits(self):
opp = self.get_object("HighTrafficSettings", OppConfigType.READ_ONLY)
# set default on exiting must work
self.assertEqual(opp.setdefault("opt_3", '"val_3"'), '"val_3"')
# set new will ignore default on existing
self.assertEqual(opp.setdefault("opt_3", '"new"'), '"val_3"')
def test_set_default_not_exits(self):
opp = self.get_object("HighTrafficSettings", OppConfigType.READ_ONLY)
# must raise error on OppConfigType.READ_ONLY
self.assertRaises(NotImplementedError, opp.setdefault, "new_key", "42")
opp = self.get_object("HighTrafficSettings", OppConfigType.EDIT_LOCAL)
# must raise error on OppConfigType.EDIT_LOCAL
self.assertRaises(NotImplementedError, opp.setdefault, "new_key", "42")
opp = self.get_object("HighTrafficSettings", OppConfigType.EXT_DEL_LOCAL)
# must work on OppConfigType.EXT_DEL_LOCAL
ret = opp.setdefault("new_key", "42")
self.assertEqual(ret, "42")
self.assertEqual(opp["new_key"], "42")
# new key must be local
def test_read_only(self):
opp = self.get_object("HighTrafficSettings", OppConfigType.READ_ONLY)
# reading must work
self.assertEqual(opp["opt_3"], '"val_3"')
self.assertEqual(opp["general_option"], '"VAL1"')
# setting new values must not work for (local and parent options)
self.assertRaises(NotImplementedError, opp.__setitem__, "opt_3", '"new_val"')
NotImplementedError, opp.__setitem__, "general_option", '"new_val"'
def test_edit_local(self):
opp = self.get_object("HighTrafficSettings", OppConfigType.EDIT_LOCAL)
# reading must work
self.assertEqual(opp["opt_3"], '"val_3"')
self.assertEqual(opp["general_option"], '"VAL1"')
# setting new values must work for local options only
opp["opt_3"] = '"new_val"'
self.assertEqual(opp["opt_3"], '"new_val"')
# general_option belongs to parent config 'General'
NotImplementedError, opp.__setitem__, "general_option", '"new_val"'
def test_hierarchy(self):
""" Ensure correct lookup order for extended configurations"""
opp = self.get_object("SlottedAloha2b", OppConfigType.EDIT_LOCAL)
"Config SlottedAloha2b",
"Config SlottedAloha2",
"Config SlottedAlohaBase",
"Config HighTrafficSettings",
opp = self.get_object("SlottedAloha1", OppConfigType.EDIT_LOCAL)
"Config SlottedAloha1",
"Config SlottedAlohaBase",
"Config LowTrafficSettings",
opp = self.get_object("General", OppConfigType.EDIT_LOCAL)
self.assertListEqual(opp.section_hierarchy, ["General"])
opp = self.get_object("SlottedAlohaBase", OppConfigType.EDIT_LOCAL)
opp.section_hierarchy, ["Config SlottedAlohaBase", "General"]
def test_override(self):
opp = self.get_object("SlottedAloha2", OppConfigType.EXT_DEL_LOCAL)
opp["opt_5"] = '"val_55"'
self.save_object(opp, self.NEW_FILE)
opp2 = opp = self.get_object(
"SlottedAloha2", OppConfigType.EXT_DEL_LOCAL, path=self.NEW_FILE
self.assertEqual(opp2["opt_5"], '"val_55"')
lines_new = [
line for line in self.get_lines(self.NEW_FILE) if not line.startswith("\n")
lines_comp = [
for line in self.get_lines(self.NEW_FILE_COMP)
if not line.startswith("\n")
self.assertListEqual(lines_new, lines_comp)
def test_safe_to_file(self):
sa_2 = self.get_object("SlottedAloha2", OppConfigType.EXT_DEL_LOCAL)
hts = self.get_object("HighTrafficSettings", OppConfigType.EXT_DEL_LOCAL)
self.assertEqual(sa_2["opt_HT"], '"overwritten_val_HT"')