From bd01f4e0c5669287ceacd7951e546c76ea9537a6 Mon Sep 17 00:00:00 2001 From: John Harwell Date: Mon, 25 Jul 2022 11:47:24 -0500 Subject: [PATCH] refactor(#304): XML experiment definition --- docs/index.rst | 1 + docs/src/roadmap.rst | 10 +- docs/src/tutorials/plugin/platform_plugin.rst | 13 +- docs/src/tutorials/project/new_bc.rst | 10 +- docs/src/usage/environment.rst | 104 ++++++ scripts/ros1gazebo-integration-tests.sh | 4 + .../core/{xml.py => experiment/definition.py} | 323 +----------------- sierra/core/experiment/xml.py | 323 ++++++++++++++++++ sierra/core/generators/exp_creator.py | 15 +- sierra/core/generators/exp_generators.py | 17 +- sierra/core/generators/generator_factory.py | 43 +-- sierra/core/ros1/callbacks.py | 9 +- sierra/core/ros1/generators.py | 26 +- sierra/core/ros1/variables/exp_setup.py | 140 ++++---- sierra/core/utils.py | 26 +- sierra/core/variables/base_variable.py | 26 +- sierra/core/variables/batch_criteria.py | 47 +-- sierra/core/variables/variable_density.py | 4 +- .../argos/generators/platform_generators.py | 47 ++- sierra/plugins/platform/argos/plugin.py | 12 +- .../platform/argos/variables/arena_shape.py | 111 +++--- .../platform/argos/variables/cameras.py | 132 +++---- .../platform/argos/variables/exp_setup.py | 26 +- .../argos/variables/physics_engines.py | 132 +++---- .../variables/population_constant_density.py | 10 +- .../argos/variables/population_size.py | 10 +- .../variables/population_variable_density.py | 10 +- .../platform/argos/variables/rendering.py | 60 ++-- .../generators/platform_generators.py | 15 +- sierra/plugins/platform/ros1gazebo/plugin.py | 12 +- .../ros1gazebo/variables/population_size.py | 104 +++--- .../generators/platform_generators.py | 19 +- sierra/plugins/platform/ros1robot/plugin.py | 10 +- .../ros1robot/variables/population_size.py | 70 ++-- sierra/version.py | 2 +- 35 files changed, 1034 insertions(+), 889 deletions(-) create mode 100755 docs/src/usage/environment.rst rename sierra/core/{xml.py => experiment/definition.py} (56%) create mode 100644 sierra/core/experiment/xml.py diff --git a/docs/index.rst b/docs/index.rst index fe2f7fcc..b8a012a3 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -39,6 +39,7 @@ SIERRA: Automation for the Scientific Method and Agent-Based Research src/philosophy.rst src/faq.rst src/contributing.rst + src/roadmap.rst src/glossary.rst src/api.rst diff --git a/docs/src/roadmap.rst b/docs/src/roadmap.rst index e2a5fc26..3c052b25 100644 --- a/docs/src/roadmap.rst +++ b/docs/src/roadmap.rst @@ -1,13 +1,11 @@ .. _ln-sierra-roadmap: -============== -SIERRA Roadmap -============== +=================== +Development Roadmap +=================== This page shows a brief overview of some of the ways I think SIERRA could be -improved. Big picture stuff, not "add more unit tests". Basically a place to -put stuff I want to add someday so I don't forget. - +improved. Big picture stuff, not "add more unit tests". Supporting ROS2 =============== diff --git a/docs/src/tutorials/plugin/platform_plugin.rst b/docs/src/tutorials/plugin/platform_plugin.rst index a8388923..6cbdeb34 100644 --- a/docs/src/tutorials/plugin/platform_plugin.rst +++ b/docs/src/tutorials/plugin/platform_plugin.rst @@ -38,8 +38,7 @@ additional files can be included. import implements - from sierra.core import xml - from sierra.core.experiment import bindings + from sierra.core.experiment import bindings, xml, definition @implements.implements(bindings.IParsedCmdlineConfigurer) class CmdlineParserGenerator(): @@ -91,8 +90,8 @@ additional files can be included. :class:`~sierra.core.experiment.bindings.IExpRunConfigurer`. """ - def population_size_from_pickle(def: tp.Union[xml.XMLAttrChangeSet, - xml.XMLTagAddList]) -> int: + def population_size_from_pickle(def: tp.Union[xml.AttrChangeSet, + xml.TagAddList]) -> int: """ During stage 5, there is no way for SIERRA to know how many robots were used in a cross-platform way, because different platforms can @@ -107,7 +106,7 @@ additional files can be included. if path == ".//system" and attr == "size": return int(value) - def population_size_from_def(exp_def: xml.XMLLuigi) -> int: + def population_size_from_def(exp_def: definition.XMLExpDef) -> int: """ During stage 2, on some platforms (e.g., ROS) you need to be able to extract the # of robots that will be used for a given @@ -221,6 +220,8 @@ additional files can be included. .. code-block:: python + from sierra.core.experiment import definition + class PlatformExpDefGenerator(): """ Create an experiment definition from the @@ -244,7 +245,7 @@ additional files can be included. **kwargs) -> None: pass - def generate(self) -> XMLLuigi: + def generate(self) -> definition.XMLExpDef: pass class PlatformExpRunDefUniqueGenerator: diff --git a/docs/src/tutorials/project/new_bc.rst b/docs/src/tutorials/project/new_bc.rst index 798511d5..09e38b68 100755 --- a/docs/src/tutorials/project/new_bc.rst +++ b/docs/src/tutorials/project/new_bc.rst @@ -33,7 +33,7 @@ following to get it to work with SIERRA as a :term:`Batch Criteria`: it within), produce a list of sets, where each set is all changes that need to be made to the ``.xml`` template file in order to set the value of your variable to something. Each change is a - :class:`~sierra.core.xml.XMLAttrChange` object, that takes the + :class:`~sierra.core.experiment.xml.AttrChange` object, that takes the following arguments in its constructor: #. XPath search path for the **parent** of the attribute that you want to @@ -48,8 +48,8 @@ following to get it to work with SIERRA as a :term:`Batch Criteria`: tags that need to be removed from the ``.xml`` template file in order to set the value of your variable to something. - Each change is a :class:`~sierra.core.xml.XMLTagRm` object that takes - the following arguments in its constructor: + Each change is a :class:`~sierra.core.experiment.xml.TagRm` object that + takes the following arguments in its constructor: #. XPath search path for the **parent** of the tag that you want to remove. @@ -60,8 +60,8 @@ following to get it to work with SIERRA as a :term:`Batch Criteria`: passed during initialization, generate a list of sets, where each set is all tags that need to be added to the ``.xml`` template file. - Each change is a :class:`~sierra.core.xml.XMLTagAdd` object that takes - the following arguments in its constructor: + Each change is a :class:`~sierra.core.experiment.xml.TagAdd` object that + takes the following arguments in its constructor: #. XPath search path for the **parent** of the tag that you want to add. diff --git a/docs/src/usage/environment.rst b/docs/src/usage/environment.rst new file mode 100755 index 00000000..5cf60b0a --- /dev/null +++ b/docs/src/usage/environment.rst @@ -0,0 +1,104 @@ +.. _ln-usage-env-vars: + +Environment Variables +===================== + +.. envvar:: SIERRA_PLUGIN_PATH + + Used for locating :term:`plugins `. The directory `containing` a + plugin directory outside the SIERRA source tree must be on + ``SIERRA_PLUGIN_PATH``. Paths are added to ``PYTHONPATH`` as needed to load + plugins correctly. For example, if you have a different version of the + ``--storage-medium`` plugin you'd like to use, and you have but the directory + containing the plugin in ``$HOME/plugins``, then you need to add + ``$HOME/plugins`` to your ``SIERRA_PLUGIN_PATH`` to so that SIERRA will find + it. This variable is used in stages 1-5. + + Used for locating :term:`projects `; all projects specifiable with + ``--project`` are directories found within the directories on this path. For + example, if you have a project ``$HOME/git/projects/myproject``, then + ``$HOME/git`` must be on ``SIERRA_PLUGIN_PATH`` in order for you to be able + to specify ``--project=myproject``. This variable is used in stages 1-5. + + You *cannot* just put the parent directory of your project on + :envvar:`PYTHONPATH` because SIERRA uses this path for other things + internally (e.g., computing the paths to YAML config files). + +.. envvar:: PYTHONPATH + + Used for locating projects per the usual python mechanisms. + +.. envvar:: ARGOS_PLUGIN_PATH + + Must be set to contain the library directory where you installed/built ARGoS, + as well as the library directory for your project ``.so``. Checked to be + non-empty before running stage 2 for all ``--exec-env`` plugins. SIERRA does + `not` modify this variable, so it needs to be setup properly prior to + invoking SIERRA (i.e., the directory containing the :term:`Project` ``.so`` + file needs to be on it). SIERRA can't know, in general, where the location of + the C++ code corresponding to the loaded :term:`Project` is. + +.. envvar:: SIERRA_ARCH + + Used to determine the names of ARGoS executables via ``argos3-$SIERRA_ARCH``, + so that in HPC environments with multiple queues/sub-clusters with different + architectures ARGoS can be compiled natively for each for maximum + performance. Can be any string. Used when generating ARGoS cmds in stage 1, + and only if SIERRA is run on a cluster. + +.. envvar:: SIERRA_NODEFILE + + Points to a file suitable for passing to :program:`parallel` via + ``--sshloginfile``. See :program:`parallel` docs for content/formatting + requirements. + + Used by SIERRA to configure experiments during stage 1,2; if it is not + defined and ``--nodefile`` is not passed SIERRA will throw an error. + +.. envvar:: PARALLEL + + Any and all environment variables needed by your :term:`Project` must be + exported via the ``PARALLEL`` environment variable before invoking SIERRA, + because GNU parallel does not export the environment of the node it is + launched from to slave nodes (or even on the local machine). Something like:: + + export PARALLEL="--workdir . \ + --env PATH \ + --env LD_LIBRARY_PATH \ + --env LOADEDMODULES \ + --env _LMFILES_ \ + --env MODULE_VERSION \ + --env MODULEPATH \ + --env MODULEVERSION_STACK + --env MODULESHOME \ + --env OMP_DYNAMICS \ + --env OMP_MAX_ACTIVE_LEVELS \ + --env OMP_NESTED \ + --env OMP_NUM_THREADS \ + --env OMP_SCHEDULE \ + --env OMP_STACKSIZE \ + --env OMP_THREAD_LIMIT \ + --env OMP_WAIT_POLICY \ + --env SIERRA_ARCH \ + --env SIERRA_PLUGIN_PATH" + + Should be a good starting point. Only used if SIERRA is run on a cluster with + ``exec_env=hpc.slurm|hpc.pbs``. Don't forget to include + :envvar:`ARGOS_PLUGIN_PATH`, :envvar:`ROS_PACKAGE_PATH`, etc., depending on + your chosen :term:`Platform`. + +.. envvar:: PARALLEL_SHELL + + SIERRA sets up the :term:`Experiment` execution environments by running one + or more shell commands in a subprocess (treated as a ``shell``, which means + that :program:`parallel` can't determine ``SHELL``, and therefore defaults to + ``/bin/sh``, which is not what users expect. SIERRA explicitly sets + ``PARALLEL_SHELL`` to the result of ``shutil.which('bash')`` in keeping with + the Principle Of Least Surprise. + +.. envvar:: ROS_PACKAGE_PATH + + The list of directories which defines where ROS will search for + packages. SIERRA does `not` modify this variable, so it needs to be setup + properly prior to invoking SIERRA (i.e., sourcing the proper ``setup.bash`` + script). diff --git a/scripts/ros1gazebo-integration-tests.sh b/scripts/ros1gazebo-integration-tests.sh index d6c8ab29..84bfc0f9 100755 --- a/scripts/ros1gazebo-integration-tests.sh +++ b/scripts/ros1gazebo-integration-tests.sh @@ -69,4 +69,8 @@ set -x rospack find sierra_rosbridge +cd $SAMPLE_ROOT +ls -alh +python3 -m projects.ros1gazebo_project.generators.scenario_generators + batch_criteria_test diff --git a/sierra/core/xml.py b/sierra/core/experiment/definition.py similarity index 56% rename from sierra/core/xml.py rename to sierra/core/experiment/definition.py index dd111bae..9229001e 100755 --- a/sierra/core/xml.py +++ b/sierra/core/experiment/definition.py @@ -1,4 +1,4 @@ -# Copyright 2018 London Lowmanstone, John Harwell, All rights reserved. +# Copyright 2022 John Harwell, All rights reserved. # # This file is part of SIERRA. # @@ -30,294 +30,11 @@ # Project packages from sierra.core import types +from sierra.core.experiment import xml -class XMLAttrChange(): - """ - Specification for a change to an existing XML attribute. - """ - - def __init__(self, - path: str, - attr: str, - value: tp.Union[str, int, float]) -> None: - self.path = path - self.attr = attr - self.value = str(value) - - def __iter__(self): - yield from [self.path, self.attr, self.value] - - def __repr__(self) -> str: - return self.path + '/' + self.attr + ': ' + str(self.value) - - -class XMLTagRm(): - """ - Specification for removal of an existing XML tag. - """ - - def __init__(self, path: str, tag: str): - """ - Arguments: - path: The path to the **parent** of the tag you want to remove, in - XPath syntax. - - tag: The name of the tag to remove. - """ - self.path = path - self.tag = tag - - def __iter__(self): - yield from [self.path, self.tag] - - def __repr__(self) -> str: - return self.path + '/' + self.tag - - -class XMLTagAdd(): - """ - Specification for adding a new XML tag. - - The tag may be added idempotently, or duplicates can be allowed. - """ - - def __init__(self, - path: tp.Optional[str], - tag: str, - attr: dict, - allow_dup: bool): - """ - Arguments: - path: The path to the **parent** tag you want to add a new tag - under, in XPath syntax. If None, then the tag will be added as - the root XML tag. - - tag: The name of the tag to add. - - attr: A dictionary of (attribute, value) pairs to also create as - children of the new tag when creating the new tag. - """ - - self.path = path - self.tag = tag - self.attr = attr - self.allow_dup = allow_dup - - def __iter__(self): - yield from [self.path, self.tag, self.attr] - - def __repr__(self) -> str: - if self.path is not None: - return self.path + '/' + self.tag + ': ' + str(self.attr) - else: - return '/' + self.tag + ': ' + str(self.attr) - - -class XMLAttrChangeSet(): - """ - Data structure for :class:`XMLAttrChange` objects. - - The order in which attributes are changed doesn't matter from the standpoint - of correctness (i.e., different orders won't cause crashes). - - """ - @staticmethod - def unpickle(fpath: str) -> 'XMLAttrChangeSet': - """ - Read in all the different sets of parameter changes that were pickled to - make crucial parts of the experiment definition easily accessible. You - don't know how many there are, so go until you get an exception. - - """ - exp_def = XMLAttrChangeSet() - - try: - with open(fpath, 'rb') as f: - while True: - exp_def |= XMLAttrChangeSet(*pickle.load(f)) - except EOFError: - pass - return exp_def - - def __init__(self, *args: XMLAttrChange) -> None: - self.changes = set(args) - self.logger = logging.getLogger(__name__) - - def __len__(self) -> int: - return len(self.changes) - - def __iter__(self) -> tp.Iterator[XMLAttrChange]: - return iter(self.changes) - - def __ior__(self, other: 'XMLAttrChangeSet') -> 'XMLAttrChangeSet': - self.changes |= other.changes - return self - - def __or__(self, other: 'XMLAttrChangeSet') -> 'XMLAttrChangeSet': - new = XMLAttrChangeSet(*self.changes) - new |= other - return new - - def __repr__(self) -> str: - return str(self.changes) - - def add(self, chg: XMLAttrChange) -> None: - self.changes.add(chg) - - def pickle(self, fpath: str, delete: bool = False) -> None: - from sierra.core import utils - - if delete and utils.path_exists(fpath): - os.remove(fpath) - - with open(fpath, 'ab') as f: - utils.pickle_dump(self.changes, f) - - -class XMLTagRmList(): - """ - Data structure for :class:`XMLTagRm` objects. - - The order in which tags are removed matters (i.e., if you remove dependent - tags in the wrong order you will get an exception), hence the list - representation. - - """ - - def __init__(self, *args: XMLTagRm) -> None: - self.rms = list(args) - - def __len__(self) -> int: - return len(self.rms) - - def __iter__(self) -> tp.Iterator[XMLTagRm]: - return iter(self.rms) - - def __repr__(self) -> str: - return str(self.rms) - - def extend(self, other: 'XMLTagRmList') -> None: - self.rms.extend(other.rms) - - def append(self, other: XMLTagRm) -> None: - self.rms.append(other) - - def pickle(self, fpath: str, delete: bool = False) -> None: - from sierra.core import utils - - if delete and utils.path_exists(fpath): - os.remove(fpath) - - with open(fpath, 'ab') as f: - utils.pickle_dump(self.rms, f) - - -class XMLTagAddList(): - """ - Data structure for :class:`XMLTagAdd` objects. - - The order in which tags are added matters (i.e., if you add dependent tags - in the wrong order you will get an exception), hence the list - representation. - """ - - @staticmethod - def unpickle(fpath: str) -> tp.Optional['XMLTagAddList']: - """ - Read in all the different sets of parameter changes that were pickled to - make crucial parts of the experiment definition easily accessible. You - don't know how many there are, so go until you get an exception. - - """ - exp_def = XMLTagAddList() - - try: - with open(fpath, 'rb') as f: - while True: - exp_def.append(*pickle.load(f)) - except EOFError: - pass - return exp_def - - def __init__(self, *args: XMLTagAdd) -> None: - self.adds = list(args) - - def __len__(self) -> int: - return len(self.adds) - - def __iter__(self) -> tp.Iterator[XMLTagAdd]: - return iter(self.adds) - - def __repr__(self) -> str: - return str(self.adds) - - def extend(self, other: 'XMLTagAddList') -> None: - self.adds.extend(other.adds) - - def append(self, other: XMLTagAdd) -> None: - self.adds.append(other) - - def prepend(self, other: XMLTagAdd) -> None: - self.adds.insert(0, other) - - def pickle(self, fpath: str, delete: bool = False) -> None: - from sierra.core import utils - - if delete and utils.path_exists(fpath): - os.remove(fpath) - - with open(fpath, 'ab') as f: - utils.pickle_dump(self.adds, f) - - -class InvalidElementError(RuntimeError): - """Error class for when an element cannot be found or used.""" - - -class XMLWriterConfig(): - """Config for writing the XML content managed by :class:`XMLLuigi`. - - Different parts of the XML tree can be written to multiple XML files. - - Attributes: - - values: Dict with the following possible key, value pairs: - - ``src_parent`` - The parent of the root of the XML tree - specifying a sub-tree to write out as a child - of ``dest_root``. This key is required. - - ``src_tag`` - The name of the tag within ``src_parent`` to write - out.This key is required. - - ``dest_root`` - The new name of ``src_root`` when writing out - the partial XML tree to a new file. This key is - optional. - - ``opath_leaf`` - Additional bits added to whatever the opath - file stem that is set for the :class:`XMLLuigi` - instance. This key is optional. - - ``child_grafts`` - Additional bits of the XML tree to add under - the new ``dest_root/src_tag``, specified as a - list of XPath strings. You can't just have - multiple src_roots because that makes - unambiguous renaming of ``src_root`` -> - ``dest_root`` impossible. This key is - optional. - - """ - - def __init__(self, values: tp.List[dict]) -> None: - self.values = values - - def add(self, value: dict) -> None: - self.values.append(value) - - -class XMLLuigi: - """A class to help edit and write xml files. +class XMLExpDef: + """Read, write, and modify parsed XML files into experiment definitions. Functionality includes single tag removal/addition, single attribute change/add/remove. @@ -331,18 +48,18 @@ class XMLLuigi: def __init__(self, input_fpath: str, - write_config: tp.Optional[XMLWriterConfig] = None) -> None: + write_config: tp.Optional[xml.WriterConfig] = None) -> None: self.write_config = write_config self.input_fpath = input_fpath self.tree = ET.parse(self.input_fpath) self.root = self.tree.getroot() - self.tag_adds = XMLTagAddList() - self.attr_chgs = XMLAttrChangeSet() + self.tag_adds = xml.TagAddList() + self.attr_chgs = xml.AttrChangeSet() self.logger = logging.getLogger(__name__) - def write_config_set(self, config: XMLWriterConfig) -> None: + def write_config_set(self, config: xml.WriterConfig) -> None: """Set the write config for the object; provided for cases in which the configuration is dependent on whether or not certain tags are present in the input file. @@ -468,7 +185,7 @@ def attr_change(self, path, attr, value) - self.attr_chgs.add(XMLAttrChange(path, attr, value)) + self.attr_chgs.add(xml.AttrChange(path, attr, value)) def attr_add(self, path: str, @@ -508,7 +225,7 @@ def attr_add(self, path, attr, value) - self.attr_chgs.add(XMLAttrChange(path, attr, value)) + self.attr_chgs.add(xml.AttrChange(path, attr, value)) def has_tag(self, path: str) -> bool: return self.root.find(path) is not None @@ -652,23 +369,23 @@ def tag_add(self, path, tag, str(attr)) - self.tag_adds.append(XMLTagAdd(path, tag, attr, allow_dup)) + self.tag_adds.append(xml.TagAdd(path, tag, attr, allow_dup)) -def unpickle(fpath: str) -> tp.Optional[tp.Union[XMLAttrChangeSet, - XMLTagAddList]]: +def unpickle(fpath: str) -> tp.Optional[tp.Union[xml.AttrChangeSet, + xml.TagAddList]]: """ Read in all the different sets of parameter changes that were pickled to make crucial parts of the experiment definition easily accessible. You don't know how many there are, so go until you get an exception. """ try: - return XMLAttrChangeSet.unpickle(fpath) + return xml.AttrChangeSet.unpickle(fpath) except EOFError: pass try: - return XMLTagAddList.unpickle(fpath) + return xml.TagAddList.unpickle(fpath) except EOFError: pass @@ -676,13 +393,5 @@ def unpickle(fpath: str) -> tp.Optional[tp.Union[XMLAttrChangeSet, __api__ = [ - 'InvalidElementError', - 'XMLLuigi', - 'XMLAttrChange', - 'XMLAttrChangeSet', - 'XMLTagAdd', - 'XMLTagAddList', - 'XMLTagRm', - 'XMLTagRmList', - 'XMLWriterConfig' + 'XMLExpDef', ] diff --git a/sierra/core/experiment/xml.py b/sierra/core/experiment/xml.py new file mode 100644 index 00000000..c6fced49 --- /dev/null +++ b/sierra/core/experiment/xml.py @@ -0,0 +1,323 @@ +# Copyright 2022 John Harwell, All rights reserved. +# +# This file is part of SIERRA. +# +# SIERRA is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# SIERRA is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# SIERRA. If not, see None: + self.path = path + self.attr = attr + self.value = str(value) + + def __iter__(self): + yield from [self.path, self.attr, self.value] + + def __repr__(self) -> str: + return self.path + '/' + self.attr + ': ' + str(self.value) + + +class TagRm(): + """ + Specification for removal of an existing XML tag. + """ + + def __init__(self, path: str, tag: str): + """ + Arguments: + path: The path to the **parent** of the tag you want to remove, in + XPath syntax. + + tag: The name of the tag to remove. + """ + self.path = path + self.tag = tag + + def __iter__(self): + yield from [self.path, self.tag] + + def __repr__(self) -> str: + return self.path + '/' + self.tag + + +class TagAdd(): + """ + Specification for adding a new XML tag. + + The tag may be added idempotently, or duplicates can be allowed. + """ + + def __init__(self, + path: tp.Optional[str], + tag: str, + attr: dict, + allow_dup: bool): + """ + Arguments: + path: The path to the **parent** tag you want to add a new tag + under, in XPath syntax. If None, then the tag will be added as + the root XML tag. + + tag: The name of the tag to add. + + attr: A dictionary of (attribute, value) pairs to also create as + children of the new tag when creating the new tag. + """ + + self.path = path + self.tag = tag + self.attr = attr + self.allow_dup = allow_dup + + def __iter__(self): + yield from [self.path, self.tag, self.attr] + + def __repr__(self) -> str: + if self.path is not None: + return self.path + '/' + self.tag + ': ' + str(self.attr) + else: + return '/' + self.tag + ': ' + str(self.attr) + + +class AttrChangeSet(): + """ + Data structure for :class:`AttrChange` objects. + + The order in which attributes are changed doesn't matter from the standpoint + of correctness (i.e., different orders won't cause crashes). + + """ + @staticmethod + def unpickle(fpath: str) -> 'AttrChangeSet': + """ + Read in all the different sets of parameter changes that were pickled to + make crucial parts of the experiment definition easily accessible. You + don't know how many there are, so go until you get an exception. + + """ + exp_def = AttrChangeSet() + + try: + with open(fpath, 'rb') as f: + while True: + exp_def |= AttrChangeSet(*pickle.load(f)) + except EOFError: + pass + return exp_def + + def __init__(self, *args: AttrChange) -> None: + self.changes = set(args) + self.logger = logging.getLogger(__name__) + + def __len__(self) -> int: + return len(self.changes) + + def __iter__(self) -> tp.Iterator[AttrChange]: + return iter(self.changes) + + def __ior__(self, other: 'AttrChangeSet') -> 'AttrChangeSet': + self.changes |= other.changes + return self + + def __or__(self, other: 'AttrChangeSet') -> 'AttrChangeSet': + new = AttrChangeSet(*self.changes) + new |= other + return new + + def __repr__(self) -> str: + return str(self.changes) + + def add(self, chg: AttrChange) -> None: + self.changes.add(chg) + + def pickle(self, fpath: str, delete: bool = False) -> None: + from sierra.core import utils + + if delete and utils.path_exists(fpath): + os.remove(fpath) + + with open(fpath, 'ab') as f: + utils.pickle_dump(self.changes, f) + + +class TagRmList(): + """ + Data structure for :class:`TagRm` objects. + + The order in which tags are removed matters (i.e., if you remove dependent + tags in the wrong order you will get an exception), hence the list + representation. + + """ + + def __init__(self, *args: TagRm) -> None: + self.rms = list(args) + + def __len__(self) -> int: + return len(self.rms) + + def __iter__(self) -> tp.Iterator[TagRm]: + return iter(self.rms) + + def __repr__(self) -> str: + return str(self.rms) + + def extend(self, other: 'TagRmList') -> None: + self.rms.extend(other.rms) + + def append(self, other: TagRm) -> None: + self.rms.append(other) + + def pickle(self, fpath: str, delete: bool = False) -> None: + from sierra.core import utils + + if delete and utils.path_exists(fpath): + os.remove(fpath) + + with open(fpath, 'ab') as f: + utils.pickle_dump(self.rms, f) + + +class TagAddList(): + """ + Data structure for :class:`TagAdd` objects. + + The order in which tags are added matters (i.e., if you add dependent tags + in the wrong order you will get an exception), hence the list + representation. + """ + + @staticmethod + def unpickle(fpath: str) -> tp.Optional['TagAddList']: + """ + Read in all the different sets of parameter changes that were pickled to + make crucial parts of the experiment definition easily accessible. You + don't know how many there are, so go until you get an exception. + + """ + exp_def = TagAddList() + + try: + with open(fpath, 'rb') as f: + while True: + exp_def.append(*pickle.load(f)) + except EOFError: + pass + return exp_def + + def __init__(self, *args: TagAdd) -> None: + self.adds = list(args) + + def __len__(self) -> int: + return len(self.adds) + + def __iter__(self) -> tp.Iterator[TagAdd]: + return iter(self.adds) + + def __repr__(self) -> str: + return str(self.adds) + + def extend(self, other: 'TagAddList') -> None: + self.adds.extend(other.adds) + + def append(self, other: TagAdd) -> None: + self.adds.append(other) + + def prepend(self, other: TagAdd) -> None: + self.adds.insert(0, other) + + def pickle(self, fpath: str, delete: bool = False) -> None: + from sierra.core import utils + + if delete and utils.path_exists(fpath): + os.remove(fpath) + + with open(fpath, 'ab') as f: + utils.pickle_dump(self.adds, f) + + +class WriterConfig(): + """Config for writing the XML content managed by + :class:`~sierra.core.experiment.definition.XMLExpDef`. + + Different parts of the XML tree can be written to multiple XML files. + + Attributes: + + values: Dict with the following possible key, value pairs: + + ``src_parent`` - The parent of the root of the XML tree + specifying a sub-tree to write out as a child + of ``dest_root``. This key is required. + + ``src_tag`` - The name of the tag within ``src_parent`` to write + out.This key is required. + + ``dest_root`` - The new name of ``src_root`` when writing out + the partial XML tree to a new file. This key is + optional. + + ``opath_leaf`` - Additional bits added to whatever the opath + file stem that is set for the + :class:`~sierra.core.experiment.definition.XMLExpDef` + instance. This key is optional. + + ``child_grafts`` - Additional bits of the XML tree to add under + the new ``dest_root/src_tag``, specified as a + list of XPath strings. You can't just have + multiple src_roots because that makes + unambiguous renaming of ``src_root`` -> + ``dest_root`` impossible. This key is + optional. + + """ + + def __init__(self, values: tp.List[dict]) -> None: + self.values = values + + def add(self, value: dict) -> None: + self.values.append(value) + + +__api__ = [ + 'AttrChange', + 'AttrChangeSet', + 'TagAdd', + 'TagAddList', + 'TagRm', + 'TagRmList', + 'WriterConfig' +] diff --git a/sierra/core/generators/exp_creator.py b/sierra/core/generators/exp_creator.py index 66548fc5..03e5fcf4 100755 --- a/sierra/core/generators/exp_creator.py +++ b/sierra/core/generators/exp_creator.py @@ -22,7 +22,6 @@ # Core packages import os import random -import typing as tp import copy import logging import time @@ -32,10 +31,10 @@ # Project packages from sierra.core.variables import batch_criteria as bc -from sierra.core import config, utils, types, platform, xml +from sierra.core import config, utils, types, platform import sierra.core.plugin_manager as pm from sierra.core.generators.exp_generators import BatchExpDefGenerator -from sierra.core.experiment import bindings +from sierra.core.experiment import bindings, definition, xml class ExpCreator: @@ -114,9 +113,9 @@ def __init__(self, self.commands_fpath = os.path.join(self.exp_input_root, config.kGNUParallel['cmdfile_stem']) - def from_def(self, exp_def: xml.XMLLuigi): + def from_def(self, exp_def: definition.XMLExpDef): """ - Given a :class:`~sierra.core.xml.XMLLuigi` object containing all changes + Given a :class:`~sierra.core.definition.XMLExpDef` object containing all changes that should be made to all runs in the experiment, create additional changes to create a set of unique runs from which distributions of swarm behavior can be meaningfully computed post-hoc. @@ -159,7 +158,7 @@ def from_def(self, exp_def: xml.XMLLuigi): utils.pickle_dump(self.random_seeds, f) def _create_exp_run(self, - run_exp_def: xml.XMLLuigi, + run_exp_def: definition.XMLExpDef, cmds_generator: bindings.IExpShellCmdsGenerator, run_num: int) -> None: run_output_dir = "{0}_{1}_output".format(self.main_input_name, @@ -336,8 +335,8 @@ def create(self, generator: BatchExpDefGenerator) -> None: # Scaffold the batch experiment, creating experiment directories and # writing template XML input files for each experiment in the batch with # changes from the batch criteria added. - exp_def = xml.XMLLuigi(input_fpath=self.batch_config_template, - write_config=xml.XMLWriterConfig([{'.': ''}])) + exp_def = definition.XMLExpDef(input_fpath=self.batch_config_template, + write_config=xml.WriterConfig([{'.': ''}])) self.criteria.scaffold_exps(exp_def, self.cmdopts) diff --git a/sierra/core/generators/exp_generators.py b/sierra/core/generators/exp_generators.py index 417dc64e..04fc6507 100755 --- a/sierra/core/generators/exp_generators.py +++ b/sierra/core/generators/exp_generators.py @@ -29,8 +29,7 @@ # Project packages import sierra.core.generators.generator_factory as gf -import sierra.core.xml -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import spec, definition from sierra.core import types import sierra.core.variables.batch_criteria as bc @@ -90,7 +89,7 @@ def __init__(self, self.cmdopts = cmdopts self.logger = logging.getLogger(__name__) - def generate_defs(self) -> tp.List[sierra.core.xml.XMLLuigi]: + def generate_defs(self) -> tp.List[definition.XMLExpDef]: """ Generates and returns a list of experiment definitions (one for each experiment in the batch), which can used to create the batch @@ -128,18 +127,18 @@ def _create_exp_generator(self, exp_num: int): exp_num: Experiment number in the batch """ - spec = ExperimentSpec(self.criteria, exp_num, self.cmdopts) - + exp_spec = spec.ExperimentSpec(self.criteria, exp_num, self.cmdopts) + template_fpath = os.path.join(exp_spec.exp_input_root, + self.batch_config_leaf) scenario = gf.scenario_generator_create(controller=self.controller_name, - spec=spec, - template_input_file=os.path.join(spec.exp_input_root, - self.batch_config_leaf), + exp_spec=exp_spec, + template_input_file=template_fpath, cmdopts=self.cmdopts) controller = gf.controller_generator_create(controller=self.controller_name, config_root=self.cmdopts['project_config_root'], cmdopts=self.cmdopts, - spec=spec) + exp_spec=exp_spec) generator = gf.joint_generator_create(scenario=scenario, controller=controller) diff --git a/sierra/core/generators/generator_factory.py b/sierra/core/generators/generator_factory.py index 4e4ced97..67bef35c 100755 --- a/sierra/core/generators/generator_factory.py +++ b/sierra/core/generators/generator_factory.py @@ -28,8 +28,7 @@ import yaml # Project packages -from sierra.core.xml import XMLLuigi, XMLTagAdd -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import spec, xml, definition import sierra.core.plugin_manager as pm from sierra.core import types, config, utils @@ -45,7 +44,7 @@ def __init__(self, controller: str, config_root: str, cmdopts: types.Cmdopts, - spec: ExperimentSpec) -> None: + exp_spec: spec.ExperimentSpec) -> None: controllers_yaml = os.path.join(config_root, config.kYAML['controllers']) with utils.utf8open(controllers_yaml) as f: @@ -58,9 +57,9 @@ def __init__(self, self.category, self.name = controller.split('.') self.cmdopts = cmdopts self.logger = logging.getLogger(__name__) - self.spec = spec + self.spec = exp_spec - def generate(self, exp_def: XMLLuigi) -> XMLLuigi: + def generate(self, exp_def: definition.XMLExpDef) -> definition.XMLExpDef: """ Generates all changes to the input file for the :term:`Experimental Run` (does not save). @@ -71,8 +70,8 @@ def generate(self, exp_def: XMLLuigi) -> XMLLuigi: return exp_def def _pp_for_tag_add(self, - add: XMLTagAdd, - robot_id: tp.Optional[int] = None) -> XMLTagAdd: + add: xml.TagAdd, + robot_id: tp.Optional[int] = None) -> xml.TagAdd: module = pm.pipeline.get_plugin_module(self.cmdopts['platform']) if '__UUID__' in add.path: prefix = module.robot_prefix_extract(self.main_config, self.cmdopts) @@ -81,7 +80,9 @@ def _pp_for_tag_add(self, add.attr = eval(add.attr) return add - def _do_tag_add(self, exp_def: XMLLuigi, add: XMLTagAdd) -> None: + def _do_tag_add(self, + exp_def: definition.XMLExpDef, + add: xml.TagAdd) -> None: # If the user is applying tags for each robot, then they might be added # multiple tags with the same name, but different attributes, so we @@ -116,7 +117,8 @@ def _do_tag_add(self, exp_def: XMLLuigi, add: XMLTagAdd) -> None: pp_add.attr, False) - def _generate_controller_support(self, exp_def: XMLLuigi) -> None: + def _generate_controller_support(self, + exp_def: definition.XMLExpDef) -> None: # Setup controller support code (if any) chgs = self.controller_config.get(self.category, {}).get('xml', @@ -137,7 +139,7 @@ def _generate_controller_support(self, exp_def: XMLLuigi) -> None: for t in adds: self._do_tag_add(exp_def, t) - def _generate_controller(self, exp_def: XMLLuigi) -> None: + def _generate_controller(self, exp_def: definition.XMLExpDef) -> None: if self.category not in self.controller_config: self.logger.fatal("Controller category '%s' not found in YAML configuration", self.category) @@ -164,10 +166,10 @@ def _generate_controller(self, exp_def: XMLLuigi) -> None: adds = controller.get('xml', {}).get('tag_add', {}) for t in adds: - self._do_tag_add(exp_def, XMLTagAdd(t[0], - t[1], - t[2], - False)) + self._do_tag_add(exp_def, xml.TagAdd(t[0], + t[1], + t[2], + False)) def joint_generator_create(controller, scenario): @@ -191,7 +193,7 @@ def generate(self): generate})() -def scenario_generator_create(spec: ExperimentSpec, +def scenario_generator_create(exp_spec: spec.ExperimentSpec, controller, **kwargs): """ @@ -203,15 +205,15 @@ def __init__(self, **kwargs) -> None: self.logger = logging.getLogger(__name__) module = pm.module_load_tiered(project=cmdopts['project'], path='generators.scenario_generators') - generator_name = module.gen_generator_name(spec.scenario_name) + generator_name = module.gen_generator_name(exp_spec.scenario_name) self.scenario_generator = getattr(module, generator_name)(controller=controller, - spec=spec, + exp_spec=exp_spec, **kwargs) def generate(self): return self.scenario_generator.generate() - return type(spec.scenario_name, + return type(exp_spec.scenario_name, (object,), {"__init__": __init__, "generate": generate })(**kwargs) @@ -220,7 +222,7 @@ def generate(self): def controller_generator_create(controller: str, config_root: str, cmdopts: types.Cmdopts, - spec: ExperimentSpec): + exp_spec: spec.ExperimentSpec): """ Creates a controller generator from the cmdline specification. """ @@ -229,12 +231,11 @@ def controller_generator_create(controller: str, (ControllerGenerator,), {})(controller, config_root, cmdopts, - spec) + exp_spec) __api__ = [ 'ControllerGenerator', - 'joint_generator_create', 'scenario_generator_create', 'controller_generator_create', diff --git a/sierra/core/ros1/callbacks.py b/sierra/core/ros1/callbacks.py index 469fe437..10102b71 100644 --- a/sierra/core/ros1/callbacks.py +++ b/sierra/core/ros1/callbacks.py @@ -24,11 +24,12 @@ # 3rd party packages # Project packages -from sierra.core import xml, types +from sierra.core import types +from sierra.core.experiment import xml, definition -def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, - xml.XMLTagAddList], +def population_size_from_pickle(adds_def: tp.Union[xml.AttrChangeSet, + xml.TagAddList], main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: for add in adds_def: @@ -38,7 +39,7 @@ def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, return 0 -def population_size_from_def(exp_def: xml.XMLLuigi, +def population_size_from_def(exp_def: definition.XMLExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return population_size_from_pickle(exp_def.tag_adds, main_config, cmdopts) diff --git a/sierra/core/ros1/generators.py b/sierra/core/ros1/generators.py index 1a5f96eb..025fbf29 100644 --- a/sierra/core/ros1/generators.py +++ b/sierra/core/ros1/generators.py @@ -24,8 +24,7 @@ # 3rd party packages # Project packages -from sierra.core.xml import XMLLuigi, XMLWriterConfig -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import definition, spec, xml import sierra.core.utils as scutils from sierra.core import types, config import sierra.core.ros1.variables.exp_setup as exp @@ -53,21 +52,21 @@ class ROSExpDefGenerator(): """ def __init__(self, - spec: ExperimentSpec, + exp_spec: spec.ExperimentSpec, controller: str, cmdopts: types.Cmdopts, **kwargs) -> None: self.controller = controller - self.spec = spec + self.spec = exp_spec self.cmdopts = cmdopts self.template_input_file = kwargs['template_input_file'] self.kwargs = kwargs self.ros_param_server = False self.logger = logging.getLogger(__name__) - def generate(self) -> XMLLuigi: - exp_def = XMLLuigi(input_fpath=self.template_input_file) - wr_config = XMLWriterConfig([]) + def generate(self) -> definition.XMLExpDef: + exp_def = definition.XMLExpDef(input_fpath=self.template_input_file) + wr_config = xml.WriterConfig([]) if exp_def.has_tag('./params'): self.logger.debug("Using shared XML parameter file") @@ -113,7 +112,7 @@ def generate(self) -> XMLLuigi: return exp_def - def _generate_experiment(self, exp_def: XMLLuigi) -> None: + def _generate_experiment(self, exp_def: definition.XMLExpDef) -> None: """ Generate XML tag changes to setup basic experiment parameters. @@ -160,12 +159,13 @@ def __init__(self, self.run_num = run_num self.logger = logging.getLogger(__name__) - def generate(self, exp_def: XMLLuigi): + def generate(self, exp_def: definition.XMLExpDef): return exp_def - def generate_random(self, exp_def: XMLLuigi) -> None: - """Generate XML changes for random seeding for a specific: term: `Experimental - Run` in an: term: `Experiment` during the input generation process. + def generate_random(self, exp_def: definition.XMLExpDef) -> None: + """Generate XML changes for random seeding for a specific: term: + `Experimental Run` in an: term: `Experiment` during the input generation + process. """ self.logger.trace("Generating random seed changes for run%s", # type: ignore @@ -187,7 +187,7 @@ def generate_random(self, exp_def: XMLLuigi) -> None: "value": str(self.random_seed) }) - def generate_paramfile(self, exp_def: XMLLuigi) -> None: + def generate_paramfile(self, exp_def: definition.XMLExpDef) -> None: """Generate XML changes for the parameter for for a specific : term: `Experimental Run` in an: term: `Experiment` during the input generation process. diff --git a/sierra/core/ros1/variables/exp_setup.py b/sierra/core/ros1/variables/exp_setup.py index f9b68e96..a1f30a8c 100644 --- a/sierra/core/ros1/variables/exp_setup.py +++ b/sierra/core/ros1/variables/exp_setup.py @@ -28,7 +28,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable -from sierra.core.xml import XMLAttrChangeSet, XMLTagAdd, XMLTagRmList, XMLTagAddList +from sierra.core.experiment import xml from sierra.core import config from sierra.core.variables.exp_setup import Parser @@ -65,69 +65,69 @@ def __init__(self, self.tag_adds = None - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: return [] - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: return [] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: if not self.tag_adds: - adds = XMLTagAddList( - XMLTagAdd("./master/group/[@ns='sierra']", - "param", - { - "name": "experiment/length", - "value": str(self.n_secs_per_run), - }, - True), - XMLTagAdd("./master/group/[@ns='sierra']", - "param", - { - "name": "experiment/ticks_per_sec", - "value": str(self.n_ticks_per_sec), - }, - True), - XMLTagAdd("./master/group/[@ns='sierra']", - "param", - { - "name": "experiment/barrier_start", - "value": str(self.barrier_start).lower(), - }, - True), - XMLTagAdd("./master/group/[@ns='sierra']", - "node", - { - "name": "sierra_timekeeper", - "pkg": "sierra_rosbridge", - "type": "sierra_timekeeper.py", - "required": "true", - # Otherwise rospy prints nothing - "output": "screen" - }, - True), - - XMLTagAdd("./robot/group/[@ns='sierra']", - "param", - { - "name": "experiment/length", - "value": str(self.n_secs_per_run), - }, - True), - XMLTagAdd("./robot/group/[@ns='sierra']", - "param", - { - "name": "experiment/ticks_per_sec", - "value": str(self.n_ticks_per_sec), - }, - True), - XMLTagAdd("./robot/group/[@ns='sierra']", - "param", - { - "name": "experiment/barrier_start", - "value": str(self.barrier_start).lower() - }, - True) + adds = xml.TagAddList( + xml.TagAdd("./master/group/[@ns='sierra']", + "param", + { + "name": "experiment/length", + "value": str(self.n_secs_per_run), + }, + True), + xml.TagAdd("./master/group/[@ns='sierra']", + "param", + { + "name": "experiment/ticks_per_sec", + "value": str(self.n_ticks_per_sec), + }, + True), + xml.TagAdd("./master/group/[@ns='sierra']", + "param", + { + "name": "experiment/barrier_start", + "value": str(self.barrier_start).lower(), + }, + True), + xml.TagAdd("./master/group/[@ns='sierra']", + "node", + { + "name": "sierra_timekeeper", + "pkg": "sierra_rosbridge", + "type": "sierra_timekeeper.py", + "required": "true", + # Otherwise rospy prints nothing + "output": "screen" + }, + True), + + xml.TagAdd("./robot/group/[@ns='sierra']", + "param", + { + "name": "experiment/length", + "value": str(self.n_secs_per_run), + }, + True), + xml.TagAdd("./robot/group/[@ns='sierra']", + "param", + { + "name": "experiment/ticks_per_sec", + "value": str(self.n_ticks_per_sec), + }, + True), + xml.TagAdd("./robot/group/[@ns='sierra']", + "param", + { + "name": "experiment/barrier_start", + "value": str(self.barrier_start).lower() + }, + True) ) if self.robots_need_timekeeper: # Robots also need the timekeeper when they are real and not @@ -145,17 +145,17 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: # most 1 dependent node will be active at a given time. Plus, # it's just sloppy to leave that sort of thing hanging around # after a run exits. - adds.append(XMLTagAdd("./robot/group/[@ns='sierra']", - "node", - { - "name": "sierra_timekeeper", - "pkg": "sierra_rosbridge", - "type": "sierra_timekeeper.py", - "required": "true", - # Otherwise rospy prints nothing - "output": "screen" - }, - True) + adds.append(xml.TagAdd("./robot/group/[@ns='sierra']", + "node", + { + "name": "sierra_timekeeper", + "pkg": "sierra_rosbridge", + "type": "sierra_timekeeper.py", + "required": "true", + # Otherwise rospy prints nothing + "output": "screen" + }, + True) ) self.tag_adds = adds diff --git a/sierra/core/utils.py b/sierra/core/utils.py index c752939c..56450860 100755 --- a/sierra/core/utils.py +++ b/sierra/core/utils.py @@ -34,8 +34,8 @@ # Project packages from sierra.core.vector import Vector3D -from sierra.core.xml import XMLLuigi, XMLAttrChangeSet, XMLTagAddList, XMLTagRmList -from sierra.core import types, xml, config +from sierra.core.experiment import xml, definition +from sierra.core import types, config from sierra.core import plugin_manager as pm @@ -255,16 +255,16 @@ def bivar_exp_labels_calc(exp_dirs: tp.List[str]) -> tp.Tuple[tp.List[str], def apply_to_expdef(var, - exp_def: XMLLuigi) -> tp.Tuple[tp.Optional[XMLTagRmList], - tp.Optional[XMLTagAddList], - tp.Optional[XMLAttrChangeSet]]: + exp_def: definition.XMLExpDef) -> tp.Tuple[tp.Optional[xml.TagRmList], + tp.Optional[xml.TagAddList], + tp.Optional[xml.AttrChangeSet]]: """ Remove existing XML tags, add new XML tags, and change existing XML attributes (in that order) for the specified variable. """ - rmsl = var.gen_tag_rmlist() # type: tp.List[XMLTagRmList] - addsl = var.gen_tag_addlist() # type: tp.List[XMLTagAddList] - chgsl = var.gen_attr_changelist() # type: tp.List[XMLAttrChangeSet] + rmsl = var.gen_tag_rmlist() # type: tp.List[xml.TagRmList] + addsl = var.gen_tag_addlist() # type: tp.List[xml.TagAddList] + chgsl = var.gen_attr_changelist() # type: tp.List[xml.AttrChangeSet] if rmsl: rms = rmsl[0] @@ -290,8 +290,8 @@ def apply_to_expdef(var, return rms, adds, chgs -def pickle_modifications(adds: tp.Optional[XMLTagAddList], - chgs: tp.Optional[XMLAttrChangeSet], +def pickle_modifications(adds: tp.Optional[xml.TagAddList], + chgs: tp.Optional[xml.AttrChangeSet], path: str) -> None: """ After applying XML attribute changes and/or adding new XML tags, pickle saxd @@ -320,7 +320,7 @@ def batch_template_path(cmdopts: types.Cmdopts, def get_n_robots(main_config: types.YAMLDict, cmdopts: types.Cmdopts, exp_input_root: str, - exp_def: xml.XMLLuigi) -> int: + exp_def: definition.XMLExpDef) -> int: """ Get the # robots used for a specific :term:`Experiment`. """ @@ -338,8 +338,8 @@ def get_n_robots(main_config: types.YAMLDict, main_config, cmdopts) if n_robots <= 0: - pkl_def = xml.unpickle(os.path.join(exp_input_root, - config.kPickleLeaf)) + pkl_def = definition.unpickle(os.path.join(exp_input_root, + config.kPickleLeaf)) n_robots = module.population_size_from_pickle(pkl_def, main_config, cmdopts) diff --git a/sierra/core/variables/base_variable.py b/sierra/core/variables/base_variable.py index def85581..39c965da 100755 --- a/sierra/core/variables/base_variable.py +++ b/sierra/core/variables/base_variable.py @@ -21,7 +21,7 @@ import implements # Project packages -from sierra.core.xml import XMLAttrChangeSet, XMLTagRmList, XMLTagAddList +from sierra.core.experiment import xml class IBaseVariable(implements.Interface): @@ -29,26 +29,28 @@ class IBaseVariable(implements.Interface): """ - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: - """Generate a list of sets of XML attributes to change in the template input XML -file.""" + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: + """Generate a list of sets of XML attributes to change in the template + input XML file. + + """ raise NotImplementedError - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: - """Generate a list of lists of XML tags to remove from the template input XML -file.""" + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: + """Generate a list of lists of XML tags to remove from the template + input XML file.""" raise NotImplementedError - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: - """Generate a list of lists of XML tags (and possibly child attributes) to add - to the template input XML file. + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: + """Generate a list of lists of XML tags (and possibly child attributes) + to add to the template input XML file. """ raise NotImplementedError def gen_files(self) -> None: - """Generate one or more new files which will (presumably) be referenced in the - template input file by path. + """Generate one or more new files which will (presumably) be referenced + in the template input file by path. """ diff --git a/sierra/core/variables/batch_criteria.py b/sierra/core/variables/batch_criteria.py index 40f870b5..c0b3f5ff 100755 --- a/sierra/core/variables/batch_criteria.py +++ b/sierra/core/variables/batch_criteria.py @@ -29,7 +29,8 @@ from sierra.core.variables import base_variable from sierra.core.vector import Vector3D -from sierra.core import xml, utils +from sierra.core import utils +from sierra.core.experiment import definition, xml import sierra.core.config import sierra.core.plugin_manager as pm @@ -206,13 +207,13 @@ def __init__(self, # Stub out IBaseVariable because all concrete batch criteria only implement # a subset of them. - def gen_attr_changelist(self) -> tp.List[xml.XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: return [] - def gen_tag_rmlist(self) -> tp.List[xml.XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: return [] - def gen_tag_addlist(self) -> tp.List[xml.XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: return [] def gen_files(self) -> None: @@ -292,7 +293,7 @@ def pickle_exp_defs(self, cmdopts: types.Cmdopts) -> None: exp_defj.pickle(pkl_path, delete=True) def scaffold_exps(self, - batch_def: xml.XMLLuigi, + batch_def: definition.XMLExpDef, cmdopts: types.Cmdopts) -> None: """ Scaffold a batch experiment by taking the raw template input file and @@ -341,8 +342,8 @@ def scaffold_exps(self, assert False, "Batch experiment size/# exp dir mismatch" def _scaffold_expi(self, - expi_def: xml.XMLLuigi, - modsi: tp.Union[xml.XMLAttrChangeSet, xml.XMLTagAddList], + expi_def: definition.XMLExpDef, + modsi: tp.Union[xml.AttrChangeSet, xml.TagAddList], i: int, cmdopts: types.Cmdopts) -> None: exp_dirname = self.gen_exp_dirnames(cmdopts)[i] @@ -359,9 +360,9 @@ def _scaffold_expi(self, exist_ok=cmdopts['exp_overwrite']) for mod in modsi: - if isinstance(mod, xml.XMLAttrChange): + if isinstance(mod, xml.AttrChange): expi_def.attr_change(mod.path, mod.attr, mod.value) - elif isinstance(mod, xml.XMLTagAdd): + elif isinstance(mod, xml.TagAdd): expi_def.tag_add(mod.path, mod.tag, mod.attr, mod.allow_dup) else: assert False,\ @@ -369,12 +370,12 @@ def _scaffold_expi(self, # This will be the "template" input file used to generate the input # files for each experimental run in the experiment - wr_config = xml.XMLWriterConfig([{'src_parent': None, - 'src_tag': '.', - 'opath_leaf': None, - 'create_tags': None, - 'dest_parent': None - }]) + wr_config = xml.WriterConfig([{'src_parent': None, + 'src_tag': '.', + 'opath_leaf': None, + 'create_tags': None, + 'dest_parent': None + }]) expi_def.write_config_set(wr_config) opath = utils.batch_template_path(cmdopts, self.batch_input_root, @@ -428,9 +429,9 @@ def populations(self, module = pm.pipeline.get_plugin_module(cmdopts['platform']) for d in dirs: - exp_def = xml.unpickle(os.path.join(self.batch_input_root, - d, - sierra.core.config.kPickleLeaf)) + exp_def = definition.unpickle(os.path.join(self.batch_input_root, + d, + sierra.core.config.kPickleLeaf)) sizes.append(module.population_size_from_pickle(exp_def, self.main_config, @@ -464,7 +465,7 @@ def is_bivar(self) -> bool: def is_univar(self) -> bool: return False - def gen_attr_changelist(self) -> tp.List[xml.XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: list1 = self.criteria1.gen_attr_changelist() list2 = self.criteria2.gen_attr_changelist() ret = [] @@ -475,7 +476,7 @@ def gen_attr_changelist(self) -> tp.List[xml.XMLAttrChangeSet]: return ret - def gen_tag_rmlist(self) -> tp.List[xml.XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: ret = self.criteria1.gen_tag_rmlist() ret.extend(self.criteria2.gen_tag_rmlist()) return ret @@ -516,9 +517,9 @@ def populations(self, cmdopts: types.Cmdopts) -> tp.List[tp.List[int]]: module = pm.pipeline.get_plugin_module(cmdopts['platform']) for d in dirs: - exp_def = xml.unpickle(os.path.join(self.batch_input_root, - d, - sierra.core.config.kPickleLeaf)) + exp_def = definition.unpickle(os.path.join(self.batch_input_root, + d, + sierra.core.config.kPickleLeaf)) index = dirs.index(d) i = int(index / (n_chgs2 + n_adds2)) j = index % (n_chgs2 + n_adds2) diff --git a/sierra/core/variables/variable_density.py b/sierra/core/variables/variable_density.py index 274ffeb0..9895f816 100755 --- a/sierra/core/variables/variable_density.py +++ b/sierra/core/variables/variable_density.py @@ -25,7 +25,7 @@ from sierra.core.variables.batch_criteria import UnivarBatchCriteria from sierra.core.utils import ArenaExtent from sierra.core import types -from sierra.core.xml import XMLAttrChangeSet +from sierra.core.experiment import xml class VariableDensity(UnivarBatchCriteria): @@ -54,7 +54,7 @@ def __init__(self, self, cli_arg, main_config, batch_input_root) self.densities = densities self.extent = extent - self.attr_changes = [] # type: tp.List[XMLAttrChangeSet] + self.attr_changes = [] # type: tp.List[xml.AttrChangeSet] class Parser(): diff --git a/sierra/plugins/platform/argos/generators/platform_generators.py b/sierra/plugins/platform/argos/generators/platform_generators.py index e2e99433..7dc37d3c 100644 --- a/sierra/plugins/platform/argos/generators/platform_generators.py +++ b/sierra/plugins/platform/argos/generators/platform_generators.py @@ -27,9 +27,8 @@ # 3rd party packages # Project packages -from sierra.core.xml import XMLLuigi, XMLWriterConfig from sierra.core.utils import ArenaExtent -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import spec, definition, xml from sierra.core import types, config, utils import sierra.core.plugin_manager as pm @@ -49,32 +48,32 @@ class PlatformExpDefGenerator(): """ def __init__(self, - spec: ExperimentSpec, + exp_spec: spec.ExperimentSpec, controller: str, cmdopts: types.Cmdopts, **kwargs) -> None: self.controller = controller - self.spec = spec + self.spec = exp_spec self.cmdopts = cmdopts self.template_input_file = kwargs['template_input_file'] self.kwargs = kwargs self.logger = logging.getLogger(__name__) - def generate(self) -> XMLLuigi: + def generate(self) -> definition.XMLExpDef: """ Generates XML changes to simulation input files that are common to all experiments. """ # ARGoS uses a single input file - wr_config = XMLWriterConfig([{'src_parent': None, - 'src_tag': '.', - 'opath_leaf': config.kARGoS['launch_file_ext'], - 'create_tags': None, - 'dest_parent': None, - 'rename_to': None - }]) - exp_def = XMLLuigi(input_fpath=self.template_input_file, - write_config=wr_config) + wr_config = xml.WriterConfig([{'src_parent': None, + 'src_tag': '.', + 'opath_leaf': config.kARGoS['launch_file_ext'], + 'create_tags': None, + 'dest_parent': None, + 'rename_to': None + }]) + exp_def = definition.XMLExpDef(input_fpath=self.template_input_file, + write_config=wr_config) # Generate # robots self._generate_n_robots(exp_def) @@ -97,7 +96,7 @@ def generate(self) -> XMLLuigi: return exp_def def generate_physics(self, - exp_def: XMLLuigi, + exp_def: definition.XMLExpDef, cmdopts: types.Cmdopts, engine_type: str, n_engines: int, @@ -146,7 +145,7 @@ def generate_physics(self, utils.apply_to_expdef(pe, exp_def) def generate_arena_shape(self, - exp_def: XMLLuigi, + exp_def: definition.XMLExpDef, shape: arena_shape.ArenaShape) -> None: """ Generate XML changes for the specified arena shape. @@ -159,7 +158,7 @@ def generate_arena_shape(self, utils.pickle_modifications(adds, chgs, self.spec.exp_def_fpath) - def _generate_n_robots(self, xml: XMLLuigi) -> None: + def _generate_n_robots(self, xml: definition.XMLExpDef) -> None: """ Generate XML changes to setup # robots if it was specified on the cmdline. @@ -179,7 +178,7 @@ def _generate_n_robots(self, xml: XMLLuigi) -> None: # Write # robots info to file for later retrieval chgs[0].pickle(self.spec.exp_def_fpath) - def _generate_saa(self, exp_def: XMLLuigi) -> None: + def _generate_saa(self, exp_def: definition.XMLExpDef) -> None: """ Generates XML changes to disable selected sensors/actuators, which are computationally expensive in large swarms, but not that costly if the @@ -208,7 +207,7 @@ def _generate_saa(self, exp_def: XMLLuigi) -> None: exp_def.tag_remove(".//sensors", "battery", noprint=True) exp_def.tag_remove(".//entity/*", "battery", noprint=True) - def _generate_time(self, exp_def: XMLLuigi) -> None: + def _generate_time(self, exp_def: definition.XMLExpDef) -> None: """ Generate XML changes to setup simulation time parameters. @@ -222,7 +221,7 @@ def _generate_time(self, exp_def: XMLLuigi) -> None: # Write time setup info to file for later retrieval utils.pickle_modifications(adds, chgs, self.spec.exp_def_fpath) - def _generate_threading(self, exp_def: XMLLuigi) -> None: + def _generate_threading(self, exp_def: definition.XMLExpDef) -> None: """ Generates XML changes to set the # of cores for a simulation to use, which may be less than the total # available on the system, depending on @@ -248,7 +247,7 @@ def _generate_threading(self, exp_def: XMLLuigi) -> None: "valid on linux in ARGoS--configuration " "error?")) - def _generate_library(self, exp_def: XMLLuigi) -> None: + def _generate_library(self, exp_def: definition.XMLExpDef) -> None: """ Generates XML changes to set the library that controllers and loop functions are sourced from to the name of the plugin passed on the @@ -273,7 +272,7 @@ def _generate_library(self, exp_def: XMLLuigi) -> None: "library", lib_name) - def _generate_visualization(self, exp_def: XMLLuigi) -> None: + def _generate_visualization(self, exp_def: definition.XMLExpDef) -> None: """ Generates XML changes to remove visualization elements from input file, @@ -347,14 +346,14 @@ def __generate_random(self, exp_def) -> None: "random_seed", str(self.random_seed)) - def generate(self, exp_def: XMLLuigi): + def generate(self, exp_def: definition.XMLExpDef): # Setup simulation random seed self.__generate_random(exp_def) # Setup simulation visualization output self.__generate_visualization(exp_def) - def __generate_visualization(self, exp_def: XMLLuigi): + def __generate_visualization(self, exp_def: definition.XMLExpDef): """ Generates XML changes for setting up rendering for a specific simulation """ diff --git a/sierra/plugins/platform/argos/plugin.py b/sierra/plugins/platform/argos/plugin.py index 7c50383e..019b785a 100644 --- a/sierra/plugins/platform/argos/plugin.py +++ b/sierra/plugins/platform/argos/plugin.py @@ -30,8 +30,8 @@ # Project packages from sierra.plugins.platform.argos import cmdline -from sierra.core import hpc, xml, config, types, utils, platform -from sierra.core.experiment import bindings +from sierra.core import hpc, config, types, utils, platform +from sierra.core.experiment import bindings, definition, xml import sierra.core.variables.batch_criteria as bc @@ -300,8 +300,8 @@ def __call__(self) -> None: assert shutil.which('Xvfb') is not None, "Xvfb not found" -def population_size_from_pickle(chgs: tp.Union[xml.XMLAttrChangeSet, - xml.XMLTagAddList], +def population_size_from_pickle(chgs: tp.Union[xml.AttrChangeSet, + xml.TagAddList], main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: for path, attr, value in chgs: @@ -311,7 +311,7 @@ def population_size_from_pickle(chgs: tp.Union[xml.XMLAttrChangeSet, return -1 -def robot_type_from_def(exp_def: xml.XMLLuigi) -> tp.Optional[str]: +def robot_type_from_def(exp_def: definition.XMLExpDef) -> tp.Optional[str]: """ Get the entity type of the robots managed by ARGoS. @@ -324,7 +324,7 @@ def robot_type_from_def(exp_def: xml.XMLLuigi) -> tp.Optional[str]: return None -def population_size_from_def(exp_def: xml.XMLLuigi, +def population_size_from_def(exp_def: definition.XMLExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return population_size_from_pickle(exp_def.attr_chgs, main_config, cmdopts) diff --git a/sierra/plugins/platform/argos/variables/arena_shape.py b/sierra/plugins/platform/argos/variables/arena_shape.py index ecb1c592..d542292e 100755 --- a/sierra/plugins/platform/argos/variables/arena_shape.py +++ b/sierra/plugins/platform/argos/variables/arena_shape.py @@ -23,7 +23,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable from sierra.core.utils import ArenaExtent -from sierra.core.xml import XMLAttrChange, XMLAttrChangeSet, XMLTagRmList, XMLTagAddList +from sierra.core.experiment import xml kWALL_WIDTH = 0.4 @@ -43,9 +43,9 @@ class ArenaShape(): def __init__(self, extents: tp.List[ArenaExtent]) -> None: self.extents = extents - self.attr_changes = [] # type: tp.List[XMLAttrChangeSet] + self.attr_changes = [] # type: tp.List[xml.AttrChangeSet] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """Generate list of sets of changes necessary to make to the input file to correctly set up the simulation with the specified arena. @@ -56,20 +56,20 @@ def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: return self.attr_changes - def _gen_chgs_for_extent(self, extent: ArenaExtent) -> XMLAttrChangeSet: + def _gen_chgs_for_extent(self, extent: ArenaExtent) -> xml.AttrChangeSet: xsize = extent.xsize() ysize = extent.ysize() zsize = extent.zsize() - chgs = XMLAttrChangeSet(XMLAttrChange(".//arena", - "size", - f"{xsize},{ysize},{zsize}"), - XMLAttrChange(".//arena", - "center", - "{0:.9f},{1:.9f},{2}".format(xsize / 2.0, - ysize / 2.0, - zsize / 2.0))) + chgs = xml.AttrChangeSet(xml.AttrChange(".//arena", + "size", + f"{xsize},{ysize},{zsize}"), + xml.AttrChange(".//arena", + "center", + "{0:.9f},{1:.9f},{2}".format(xsize / 2.0, + ysize / 2.0, + zsize / 2.0))) # We restrict the places robots can spawn within the arena as follows: # @@ -80,27 +80,34 @@ def _gen_chgs_for_extent(self, extent: ArenaExtent) -> XMLAttrChangeSet: # being near arena boundaries on the first timestep. # # - All robots start on the ground with Z=0. - chgs.add(XMLAttrChange(".//arena/distribute/position", - "max", - "{0:.9f}, {1:.9f}, 0".format(xsize - 2.0 * kWALL_WIDTH - 2.0, - ysize - 2.0 * kWALL_WIDTH - 2.0))) - chgs.add(XMLAttrChange(".//arena/distribute/position", - "min", - "{0:.9f}, {1:.9f}, 0".format(2.0 * kWALL_WIDTH + 2.0, 2.0 * kWALL_WIDTH + 2.0))) - - chgs.add(XMLAttrChange(".//arena/*[@id='wall_north']", - "size", - "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH))) - - chgs.add(XMLAttrChange(".//arena/*[@id='wall_north']/body", - "position", - "{0:.9f}, {1:.9f}, 0".format(xsize / 2.0, ysize))) - chgs.add(XMLAttrChange(".//arena/*[@id='wall_south']", - "size", - "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH))) - XMLAttrChange(".//arena/*[@id='wall_south']/body", - "position", - "{0:.9f}, 0, 0 ".format(xsize / 2.0)), + chgs.add(xml.AttrChange(".//arena/distribute/position", + "max", + "{0:.9f}, {1:.9f}, 0".format(xsize - 2.0 * kWALL_WIDTH - 2.0, + ysize - 2.0 * kWALL_WIDTH - 2.0))) + chgs.add(xml.AttrChange(".//arena/distribute/position", + "min", + "{0:.9f}, {1:.9f}, 0".format(2.0 * kWALL_WIDTH + 2.0, 2.0 * kWALL_WIDTH + 2.0))) + + chgs.add(xml.AttrChange(".//arena/*[@id='wall_north']", + "size", + "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH))) + + chgs.add(xml.AttrChange(".//arena/*[@id='wall_north']/body", + "position", + "{0:.9f}, {1:.9f}, 0".format(xsize / 2.0, ysize))) + chgs.add(xml.AttrChange(".//arena/*[@id='wall_south']", + "size", + "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH))) + + chgs.add(xml.AttrChange(".//arena/*[@id='wall_north']/body", + "position", + "{0:.9f}, {1:.9f}, 0".format(xsize / 2.0, ysize))) + chgs.add(xml.AttrChange(".//arena/*[@id='wall_south']", + "size", + "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH))) + xml.AttrChange(".//arena/*[@id='wall_south']/body", + "position", + "{0:.9f}, 0, 0 ".format(xsize / 2.0)), # East wall needs to have its X coordinate offset by the width of the # wall / 2 in order to be centered on the boundary for the arena. This @@ -109,29 +116,29 @@ def _gen_chgs_for_extent(self, extent: ArenaExtent) -> XMLAttrChangeSet: # along the east wall. # # I think this is a bug in ARGoS. - chgs.add(XMLAttrChange(".//arena/*[@id='wall_east']", - "size", - "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, - ysize + kWALL_WIDTH))) - chgs.add(XMLAttrChange(".//arena/*[@id='wall_east']/body", - "position", - "{0:.9f}, {1:.9f}, 0".format(xsize - kWALL_WIDTH / 2.0, - ysize / 2.0))) - - chgs.add(XMLAttrChange(".//arena/*[@id='wall_west']", - "size", - "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, - ysize + kWALL_WIDTH))) - chgs.add(XMLAttrChange(".//arena/*[@id='wall_west']/body", - "position", - "0, {0:.9f}, 0".format(ysize / 2.0))) + chgs.add(xml.AttrChange(".//arena/*[@id='wall_east']", + "size", + "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, + ysize + kWALL_WIDTH))) + chgs.add(xml.AttrChange(".//arena/*[@id='wall_east']/body", + "position", + "{0:.9f}, {1:.9f}, 0".format(xsize - kWALL_WIDTH / 2.0, + ysize / 2.0))) + + chgs.add(xml.AttrChange(".//arena/*[@id='wall_west']", + "size", + "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, + ysize + kWALL_WIDTH))) + chgs.add(xml.AttrChange(".//arena/*[@id='wall_west']/body", + "position", + "0, {0:.9f}, 0".format(ysize / 2.0))) return chgs - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: return [] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: return [] def gen_files(self) -> None: @@ -141,6 +148,4 @@ def gen_files(self) -> None: __api__ = [ 'kWALL_WIDTH', 'ArenaShape', - - ] diff --git a/sierra/plugins/platform/argos/variables/cameras.py b/sierra/plugins/platform/argos/variables/cameras.py index 37122233..7b54af07 100755 --- a/sierra/plugins/platform/argos/variables/cameras.py +++ b/sierra/plugins/platform/argos/variables/cameras.py @@ -29,7 +29,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable from sierra.core.utils import ArenaExtent -from sierra.core.xml import XMLAttrChangeSet, XMLTagRmList, XMLTagAddList, XMLTagRm, XMLTagAdd +from sierra.core.experiment import xml from sierra.core import types, config from sierra.core.vector import Vector3D import sierra.plugins.platform.argos.variables.exp_setup as exp @@ -64,42 +64,42 @@ def __init__(self, self.cmdline = cmdline self.extents = extents self.setup = setup - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Does nothing because all tags/attributes are either deleted or added. """ return [] - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: """ Removing the ```` tag if it exists may be desirable so an option is provided to do so. Obviously you *must* call this function BEFORE adding new definitions. """ - return [XMLTagRmList(XMLTagRm("./visualization/qt-opengl", "camera"))] + return [xml.TagRmList(xml.TagRm("./visualization/qt-opengl", "camera"))] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: if not self.tag_adds: - adds = XMLTagAddList(XMLTagAdd('./visualization/qt-opengl', - 'camera', - {}, - False), - XMLTagAdd("./visualization/qt-opengl/camera", - "placements", - {}, - False)) + adds = xml.TagAddList(xml.TagAdd('./visualization/qt-opengl', + 'camera', + {}, + False), + xml.TagAdd("./visualization/qt-opengl/camera", + "placements", + {}, + False)) in_ticks = self.setup.n_secs_per_run * \ config.kARGoS['n_ticks_per_sec'] - adds.append(XMLTagAdd('.//qt-opengl/camera', - 'timeline', - { - 'loop': str(in_ticks) - }, - False)) + adds.append(xml.TagAdd('.//qt-opengl/camera', + 'timeline', + { + 'loop': str(in_ticks) + }, + False)) if self.cmdline in ['sierra.sw', 'sierra.sw+interp']: n_cameras = self.kARGOS_N_CAMERAS @@ -117,15 +117,15 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: n_cameras)) for index, up, look_at, pos in info: - camera = XMLTagAdd('.//camera/placements', - 'placement', - { - 'index': f"{index}", - 'up': f"{up.x},{up.y},{up.z}", - 'position': f"{pos.x},{pos.y},{pos.z}", - 'look_at': f"{look_at.x},{look_at.y},{look_at.z}", - }, - True) + camera = xml.TagAdd('.//camera/placements', + 'placement', + { + 'index': f"{index}", + 'up': f"{up.x},{up.y},{up.z}", + 'position': f"{pos.x},{pos.y},{pos.z}", + 'look_at': f"{look_at.x},{look_at.y},{look_at.z}", + }, + True) adds.append(camera) self.tag_adds = [adds] @@ -136,24 +136,24 @@ def gen_files(self) -> None: pass def _gen_keyframes(self, - adds: XMLTagAddList, + adds: xml.TagAddList, n_cameras: int, cycle_length: int) -> None: for c in range(0, n_cameras): index = c % n_cameras - adds.append(XMLTagAdd('.//qt-opengl/camera/timeline', - 'keyframe', - { - 'placement': str(index), - 'step': str(int(cycle_length / n_cameras * c)) - }, - True - )) + adds.append(xml.TagAdd('.//qt-opengl/camera/timeline', + 'keyframe', + { + 'placement': str(index), + 'step': str(int(cycle_length / n_cameras * c)) + }, + True + )) if self.interpolate and c < n_cameras: - adds.append(XMLTagAdd('.//qt-opengl/camera/timeline', - 'interpolate', - {}, - True)) + adds.append(xml.TagAdd('.//qt-opengl/camera/timeline', + 'interpolate', + {}, + True)) def _gen_camera_config(self, ext: ArenaExtent, @@ -197,47 +197,47 @@ class QTCameraOverhead(): def __init__(self, extents: tp.List[ArenaExtent]) -> None: self.extents = extents - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Does nothing because all tags/attributes are either deleted or added. """ return [] - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: """ Removing the ```` tag if it exists may be desirable so an option is provided to do so. Obviously you *must* call this function BEFORE adding new definitions. """ - return [XMLTagRmList(XMLTagRm("./visualization/qt-opengl", "camera"))] + return [xml.TagRmList(xml.TagRm("./visualization/qt-opengl", "camera"))] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: if not self.tag_adds: - adds = XMLTagAddList(XMLTagAdd('./visualization/qt-opengl', - 'camera', - {}, - False), - XMLTagAdd("./visualization/qt-opengl/camera", - "placements", - {}, - False)) + adds = xml.TagAddList(xml.TagAdd('./visualization/qt-opengl', + 'camera', + {}, + False), + xml.TagAdd("./visualization/qt-opengl/camera", + "placements", + {}, + False)) for ext in self.extents: height = max(ext.xsize(), ext.ysize()) * 0.75 - camera = XMLTagAdd('.//camera/placements', - 'placement', - { - 'index': '0', - 'position': "{0}, {1}, {2}".format(ext.xsize() / 2.0, - ext.ysize() / 2.0, - height), - 'look_at': "{0}, {1}, 0".format(ext.xsize() / 2.0, - ext.ysize() / 2.0), - }, - True) + camera = xml.TagAdd('.//camera/placements', + 'placement', + { + 'index': '0', + 'position': "{0}, {1}, {2}".format(ext.xsize() / 2.0, + ext.ysize() / 2.0, + height), + 'look_at': "{0}, {1}, 0".format(ext.xsize() / 2.0, + ext.ysize() / 2.0), + }, + True) adds.append(camera) self.tag_adds = [adds] diff --git a/sierra/plugins/platform/argos/variables/exp_setup.py b/sierra/plugins/platform/argos/variables/exp_setup.py index a75d2bcb..ad7ea464 100644 --- a/sierra/plugins/platform/argos/variables/exp_setup.py +++ b/sierra/plugins/platform/argos/variables/exp_setup.py @@ -27,7 +27,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable -from sierra.core.xml import XMLAttrChangeSet, XMLAttrChange, XMLTagRmList, XMLTagAddList +from sierra.core.experiment import xml from sierra.core import config, types from sierra.core.variables.exp_setup import Parser @@ -41,7 +41,7 @@ class ExpSetup(): duration: The simulation duration in seconds, NOT timesteps. """ @staticmethod - def extract_time_params(exp_def: XMLAttrChangeSet) -> types.SimpleDict: + def extract_time_params(exp_def: xml.AttrChangeSet) -> types.SimpleDict: """ Extract and return the length (in seconds), ticks_per_second for the specified experiment. @@ -67,24 +67,24 @@ def __init__(self, self.n_secs_per_run = n_secs_per_run self.n_datapoints = n_datapoints self.n_ticks_per_sec = n_ticks_per_sec - self.attr_changes = [] # type: tp.List[XMLAttrChangeSet] + self.attr_changes = [] # type: tp.List[xml.AttrChangeSet] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: if not self.attr_changes: - chgs = XMLAttrChangeSet(XMLAttrChange(".//experiment", - "length", - "{0}".format(self.n_secs_per_run)), - XMLAttrChange(".//experiment", - "ticks_per_second", - "{0}".format(self.n_ticks_per_sec)), - ) + chgs = xml.AttrChangeSet(xml.AttrChange(".//experiment", + "length", + "{0}".format(self.n_secs_per_run)), + xml.AttrChange(".//experiment", + "ticks_per_second", + "{0}".format(self.n_ticks_per_sec)), + ) self.attr_changes = [chgs] return self.attr_changes - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: return [] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: return [] def gen_files(self) -> None: diff --git a/sierra/plugins/platform/argos/variables/physics_engines.py b/sierra/plugins/platform/argos/variables/physics_engines.py index 61d726e2..e18a0da5 100755 --- a/sierra/plugins/platform/argos/variables/physics_engines.py +++ b/sierra/plugins/platform/argos/variables/physics_engines.py @@ -31,7 +31,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable from sierra.core.utils import ArenaExtent -from sierra.core.xml import XMLAttrChangeSet, XMLTagRmList, XMLTagAddList, XMLTagRm, XMLTagAdd +from sierra.core.experiment import xml from sierra.core import types, config @@ -69,7 +69,7 @@ def __init__(self, self.iter_per_tick = iter_per_tick self.layout = layout self.extents = extents - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] # If we are given multiple extents to map, we need to divide the # specified # of engines among them. @@ -79,22 +79,22 @@ def __init__(self, self.logger = logging.getLogger(__name__) - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Does nothing because all tags/attributes are either deleted or added. """ return [] - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: """ Removing the ```` tag if it exists may be desirable so an option is provided to do so. Obviously you *must* call this function BEFORE adding new definitions. """ - return [XMLTagRmList(XMLTagRm(".", "./physics_engines"))] + return [xml.TagRmList(xml.TagRm(".", "./physics_engines"))] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: self.logger.debug("Mapping %s physics engines of type %s to extents=%s", self.n_engines, self.engine_type, @@ -129,12 +129,12 @@ def _gen_all_engines(self, extent: ArenaExtent, n_engines_x: int, n_engines_y: int, - forward_engines: tp.List[int]) -> XMLTagAddList: + forward_engines: tp.List[int]) -> xml.TagAddList: """ Generate definitions for the specified # of 2D/3D physics engines for the specified arena extent. """ - adds = XMLTagAddList(XMLTagAdd('.', 'physics_engines', {}, False)) + adds = xml.TagAddList(xml.TagAdd('.', 'physics_engines', {}, False)) for i in range(0, self.n_engines): adds.extend(self.gen_single_engine(i, @@ -150,7 +150,7 @@ def gen_single_engine(self, extent: ArenaExtent, n_engines_x: int, n_engines_y: int, - forward_engines: tp.List[int]) -> XMLTagAddList: + forward_engines: tp.List[int]) -> xml.TagAddList: """ Generate definitions for a specific 2D/3D engine as a member of the mapping of the specified arena extent to one or more engines. @@ -178,7 +178,7 @@ def gen_single_engine(self, """ - adds = XMLTagAddList() + adds = xml.TagAddList() size_x = extent.xsize() / n_engines_x size_y = extent.ysize() / n_engines_y @@ -186,33 +186,33 @@ def gen_single_engine(self, name = self._gen_engine_name(engine_id) - adds.append(XMLTagAdd('.//physics_engines', - self.engine_type, - { - 'id': name, - 'iterations': str(self.iter_per_tick) - }, - True)) - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']", - "boundaries", - {}, - True)) - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']/boundaries", - "top", - { - 'height': str(size_z) - }, - True)) - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']/boundaries", - "bottom", - { - 'height': '0.0' - }, - True)) - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']/boundaries", - "sides", - {}, - True)) + adds.append(xml.TagAdd('.//physics_engines', + self.engine_type, + { + 'id': name, + 'iterations': str(self.iter_per_tick) + }, + True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']", + "boundaries", + {}, + True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']/boundaries", + "top", + { + 'height': str(size_z) + }, + True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']/boundaries", + "bottom", + { + 'height': '0.0' + }, + True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']/boundaries", + "sides", + {}, + True)) # Engine lower X coord increasing as engine id increases if engine_id in forward_engines: @@ -243,15 +243,15 @@ def gen_single_engine(self, vertices = [(ll_x, ll_y), (lr_x, lr_y), (ur_x, ur_y), (ul_x, ul_y)] for v in vertices: - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']/boundaries/sides", - "vertex", - { - "point": "{0}, {1}".format(v[0], v[1]) - }, - True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']/boundaries/sides", + "vertex", + { + "point": "{0}, {1}".format(v[0], v[1]) + }, + True)) return adds - def _gen1_engines(self) -> XMLTagAddList: + def _gen1_engines(self) -> xml.TagAddList: """ Generate definitions for 1 2D or 3D physics engine for the specified extents. @@ -260,15 +260,15 @@ def _gen1_engines(self) -> XMLTagAddList: name = self._gen_engine_name(0) - return XMLTagAddList(XMLTagAdd('.', 'physics_engines', {}, False), - XMLTagAdd(".//physics_engines", - self.engine_type, - { - 'id': name - }, - True)) + return xml.TagAddList(xml.TagAdd('.', 'physics_engines', {}, False), + xml.TagAdd(".//physics_engines", + self.engine_type, + { + 'id': name + }, + True)) - def _gen2_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen2_engines(self, extent: ArenaExtent) -> xml.TagAddList: """Generate definitions for 2 2D or 3D physics engines for the specified extents. @@ -287,7 +287,7 @@ def _gen2_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=1, forward_engines=[]) - def _gen4_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen4_engines(self, extent: ArenaExtent) -> xml.TagAddList: """Generate definitions for 4 2D or 3D physics engines for the specified extent. @@ -307,7 +307,7 @@ def _gen4_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=2, forward_engines=[0, 1]) - def _gen6_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen6_engines(self, extent: ArenaExtent) -> xml.TagAddList: """Generate definitions for 6 2D or 3D physics engines for the specified extent. @@ -327,7 +327,7 @@ def _gen6_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=2, forward_engines=[0, 1, 2]) - def _gen8_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen8_engines(self, extent: ArenaExtent) -> xml.TagAddList: """ Generate definitions for 8 2D or 3D physics engines for the specified pair of (X,Y) arena extents with a uniform grid layout. @@ -347,7 +347,7 @@ def _gen8_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=2, forward_engines=[0, 1, 2, 3]) - def _gen12_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen12_engines(self, extent: ArenaExtent) -> xml.TagAddList: """ Generate definitions for 12 2D or 3D physics engines for the specified pair of (X,Y) arena extents with a uniform grid layout. @@ -368,7 +368,7 @@ def _gen12_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=3, forward_engines=[0, 1, 2, 3, 8, 9, 10, 11]) - def _gen16_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen16_engines(self, extent: ArenaExtent) -> xml.TagAddList: """Generate definitions for 16 2D or 3D physics engines for the specified pair of (X,Y) arena extents with a uniform grid layout. @@ -389,7 +389,7 @@ def _gen16_engines(self, extent: ArenaExtent) -> XMLTagAddList: n_engines_y=4, forward_engines=[0, 1, 2, 3, 8, 9, 10, 11]) - def _gen24_engines(self, extent: ArenaExtent) -> XMLTagAddList: + def _gen24_engines(self, extent: ArenaExtent) -> xml.TagAddList: """Generate definitions for 16 2D or 3D physics engines for the specified pair of (X,Y) arena extents with a uniform grid layout. @@ -459,7 +459,7 @@ def gen_single_engine(self, extent: ArenaExtent, n_engines_x: int, n_engines_y: int, - forward_engines: tp.List[int]) -> XMLTagAddList: + forward_engines: tp.List[int]) -> xml.TagAddList: adds = super().gen_single_engine(engine_id, extent, n_engines_x, @@ -467,13 +467,13 @@ def gen_single_engine(self, forward_engines) if self.engine_type == 'dynamics2d' and self.spatial_hash_info is not None: name = self._gen_engine_name(engine_id) - adds.append(XMLTagAdd(f".//physics_engines/*[@id='{name}']", - "spatial_hash", - { - 'cell_size': str(self.spatial_hash_info['cell_size']), - 'cell_num': str(self.spatial_hash_info['cell_num']) - }, - True)) + adds.append(xml.TagAdd(f".//physics_engines/*[@id='{name}']", + "spatial_hash", + { + 'cell_size': str(self.spatial_hash_info['cell_size']), + 'cell_num': str(self.spatial_hash_info['cell_num']) + }, + True)) return adds diff --git a/sierra/plugins/platform/argos/variables/population_constant_density.py b/sierra/plugins/platform/argos/variables/population_constant_density.py index 70103cd7..1b512d34 100755 --- a/sierra/plugins/platform/argos/variables/population_constant_density.py +++ b/sierra/plugins/platform/argos/variables/population_constant_density.py @@ -34,7 +34,7 @@ from sierra.core import utils, types import sierra.core.variables.batch_criteria as bc from sierra.core.vector import Vector3D -from sierra.core.xml import XMLAttrChange, XMLAttrChangeSet +from sierra.core.experiment import xml @implements.implements(bc.IConcreteBatchCriteria) @@ -54,7 +54,7 @@ def __init__(self, *args, **kwargs) -> None: self.already_added = False self.logger = logging.getLogger(__name__) - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Generate list of sets of changes to input file to set the # robots for a set of arena sizes such that the swarm density is constant. Robots are @@ -81,9 +81,9 @@ def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: str(extent.area()), self.target_density / 100.0) - changeset.add(XMLAttrChange(".//arena/distribute/entity", - "quantity", - str(n_robots))) + changeset.add(xml.AttrChange(".//arena/distribute/entity", + "quantity", + str(n_robots))) self.logger.debug("Calculated swarm size=%d for extent=%s,density=%s", n_robots, str(extent), self.target_density) diff --git a/sierra/plugins/platform/argos/variables/population_size.py b/sierra/plugins/platform/argos/variables/population_size.py index 4e023da8..56c7a000 100755 --- a/sierra/plugins/platform/argos/variables/population_size.py +++ b/sierra/plugins/platform/argos/variables/population_size.py @@ -26,7 +26,7 @@ # Project packages from sierra.core.variables import batch_criteria as bc -from sierra.core.xml import XMLAttrChange, XMLAttrChangeSet +from sierra.core.experiment import xml from sierra.core import types from sierra.core.variables import population_size @@ -48,8 +48,8 @@ class PopulationSize(population_size.BasePopulationSize): """ @staticmethod - def gen_attr_changelist_from_list(sizes: tp.List[int]) -> tp.List[XMLAttrChangeSet]: - return [XMLAttrChangeSet(XMLAttrChange(".//arena/distribute/entity", "quantity", str(s))) + def gen_attr_changelist_from_list(sizes: tp.List[int]) -> tp.List[xml.AttrChangeSet]: + return [xml.AttrChangeSet(xml.AttrChange(".//arena/distribute/entity", "quantity", str(s))) for s in sizes] def __init__(self, @@ -62,9 +62,9 @@ def __init__(self, main_config, batch_input_root) self.size_list = size_list - self.attr_changes = [] # type: tp.List[XMLAttrChangeSet] + self.attr_changes = [] # type: tp.List[xml.AttrChangeSet] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Generate list of sets of changes for swarm sizes to define a batch experiment. """ diff --git a/sierra/plugins/platform/argos/variables/population_variable_density.py b/sierra/plugins/platform/argos/variables/population_variable_density.py index f60439a3..0621e6bb 100755 --- a/sierra/plugins/platform/argos/variables/population_variable_density.py +++ b/sierra/plugins/platform/argos/variables/population_variable_density.py @@ -32,7 +32,7 @@ from sierra.core.variables import variable_density as vd import sierra.core.variables.batch_criteria as bc from sierra.core.vector import Vector3D -from sierra.core.xml import XMLAttrChange, XMLAttrChangeSet +from sierra.core.experiment import xml from sierra.core import types, utils @@ -51,7 +51,7 @@ def __init__(self, *args, **kwargs) -> None: self.already_added = False self.logger = logging.getLogger(__name__) - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Generate list of sets of changes to input file to set the # robots for a set of swarm densities. Robots are approximated as point masses. @@ -67,9 +67,9 @@ def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: calculated as 0 for area=%d,density=%s", self.extent.area(), density) - changeset = XMLAttrChangeSet(XMLAttrChange(".//arena/distribute/entity", - "quantity", - str(n_robots))) + changeset = xml.AttrChangeSet(xml.AttrChange(".//arena/distribute/entity", + "quantity", + str(n_robots))) self.attr_changes.append(changeset) self.logger.debug("Calculated swarm size=%d for extent=%s,density=%s", n_robots, diff --git a/sierra/plugins/platform/argos/variables/rendering.py b/sierra/plugins/platform/argos/variables/rendering.py index a7690f0a..da00f645 100755 --- a/sierra/plugins/platform/argos/variables/rendering.py +++ b/sierra/plugins/platform/argos/variables/rendering.py @@ -26,7 +26,7 @@ # Project packages from sierra.core.variables.base_variable import IBaseVariable -from sierra.core.xml import XMLAttrChangeSet, XMLTagRmList, XMLTagAddList, XMLTagRm, XMLTagAdd +from sierra.core.experiment import xml import sierra.core.config from sierra.core import types @@ -51,49 +51,49 @@ class ARGoSQTHeadlessRendering(): def __init__(self, setup: exp.ExpSetup) -> None: self.setup = setup - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] - def gen_attr_changelist(self) -> tp.List[XMLAttrChangeSet]: + def gen_attr_changelist(self) -> tp.List[xml.AttrChangeSet]: """ Does nothing because all tags/attributes are either deleted or added. """ return [] - def gen_tag_rmlist(self) -> tp.List[XMLTagRmList]: + def gen_tag_rmlist(self) -> tp.List[xml.TagRmList]: """ Removing the ```` tag if it exists may be desirable so an option is provided to do so. Obviously you *must* call this function BEFORE adding new definitions. """ - return [XMLTagRmList(XMLTagRm("./visualization", "qt-opengl"))] + return [xml.TagRmList(xml.TagRm("./visualization", "qt-opengl"))] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: if not self.tag_adds: - self.tag_adds = [XMLTagAddList(XMLTagAdd('.', - 'visualization', - {}, - False), - XMLTagAdd('./visualization', - 'qt-opengl', - {'autoplay': "true"}, - False - ), - XMLTagAdd('./visualization/qt-opengl', - 'frame_grabbing', - { - 'directory': 'frames', - 'base_name': 'frame_', - 'format': sierra.core.config.kImageExt[1:], - 'headless_grabbing': "true", - 'headless_frame_size': "{0}".format(self.kFrameSize), - 'headless_frame_rate': "{0}".format(self.kFRAME_RATE), - }, - False), - XMLTagAdd('visualization/qt-opengl', - 'user_functions', - {'label': '__EMPTY__'}, - False))] + self.tag_adds = [xml.TagAddList(xml.TagAdd('.', + 'visualization', + {}, + False), + xml.TagAdd('./visualization', + 'qt-opengl', + {'autoplay': "true"}, + False + ), + xml.TagAdd('./visualization/qt-opengl', + 'frame_grabbing', + { + 'directory': 'frames', + 'base_name': 'frame_', + 'format': sierra.core.config.kImageExt[1:], + 'headless_grabbing': "true", + 'headless_frame_size': "{0}".format(self.kFrameSize), + 'headless_frame_rate': "{0}".format(self.kFRAME_RATE), + }, + False), + xml.TagAdd('visualization/qt-opengl', + 'user_functions', + {'label': '__EMPTY__'}, + False))] return self.tag_adds diff --git a/sierra/plugins/platform/ros1gazebo/generators/platform_generators.py b/sierra/plugins/platform/ros1gazebo/generators/platform_generators.py index 8c9d2b80..9699fb03 100644 --- a/sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +++ b/sierra/plugins/platform/ros1gazebo/generators/platform_generators.py @@ -24,8 +24,7 @@ # 3rd party packages # Project packages -from sierra.core.xml import XMLLuigi -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import spec, xml, definition from sierra.core import types, ros1, config @@ -38,14 +37,14 @@ class PlatformExpDefGenerator(ros1.generators.ROSExpDefGenerator): """ def __init__(self, - spec: ExperimentSpec, + exp_spec: spec.ExperimentSpec, controller: str, cmdopts: types.Cmdopts, **kwargs) -> None: - super().__init__(spec, controller, cmdopts, **kwargs) + super().__init__(exp_spec, controller, cmdopts, **kwargs) self.logger = logging.getLogger(__name__) - def generate(self) -> XMLLuigi: + def generate(self) -> definition.XMLExpDef: exp_def = super().generate() exp_def.write_config.add({ @@ -74,7 +73,7 @@ def generate(self) -> XMLLuigi: return exp_def - def _generate_gazebo_core(self, exp_def: XMLLuigi) -> None: + def _generate_gazebo_core(self, exp_def: definition.XMLExpDef) -> None: """ Generate XML tag changes to setup Gazebo core experiment parameters. @@ -110,7 +109,7 @@ def _generate_gazebo_core(self, exp_def: XMLLuigi) -> None: # Don't start gazebo under gdb exp_def.tag_remove("./master/include", "arg/[@name='debug']") - def _generate_gazebo_vis(self, exp_def: XMLLuigi) -> None: + def _generate_gazebo_vis(self, exp_def: definition.XMLExpDef) -> None: """ Generate XML changes to configure Gazebo according to visualization configuration. @@ -134,7 +133,7 @@ def __init__(self, ros1.generators.ROSExpRunDefUniqueGenerator.__init__( self, *args, **kwargs) - def generate(self, exp_def: XMLLuigi): + def generate(self, exp_def: definition.XMLExpDef): exp_def = super().generate(exp_def) self.generate_random(exp_def) diff --git a/sierra/plugins/platform/ros1gazebo/plugin.py b/sierra/plugins/platform/ros1gazebo/plugin.py index f5c1e407..4b2a296a 100644 --- a/sierra/plugins/platform/ros1gazebo/plugin.py +++ b/sierra/plugins/platform/ros1gazebo/plugin.py @@ -30,8 +30,8 @@ # Project packages from sierra.plugins.platform.ros1gazebo import cmdline -from sierra.core import hpc, xml, platform, config, ros1, types, utils -from sierra.core.experiment import bindings +from sierra.core import hpc, platform, config, ros1, types +from sierra.core.experiment import bindings, definition, xml import sierra.core.variables.batch_criteria as bc @@ -88,7 +88,7 @@ def _hpc_slurm(self, args: argparse.Namespace) -> None: args.exec_jobs_per_node) def _hpc_adhoc(self, args: argparse.Namespace) -> None: - with utils.utf8open(args.nodefile, 'r') as f: + with open(args.nodefile, 'r') as f: lines = f.readlines() n_nodes = len(lines) @@ -324,8 +324,8 @@ def __call__(self) -> None: f"Gazebo version {version} < min required {min_version}" -def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, - xml.XMLTagAddList], +def population_size_from_pickle(adds_def: tp.Union[xml.AttrChangeSet, + xml.TagAddList], main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return ros1.callbacks.population_size_from_pickle(adds_def, @@ -333,7 +333,7 @@ def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, cmdopts) -def population_size_from_def(exp_def: xml.XMLLuigi, +def population_size_from_def(exp_def: definition.XMLExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return ros1.callbacks.population_size_from_def(exp_def, diff --git a/sierra/plugins/platform/ros1gazebo/variables/population_size.py b/sierra/plugins/platform/ros1gazebo/variables/population_size.py index fa951526..8ca94735 100755 --- a/sierra/plugins/platform/ros1gazebo/variables/population_size.py +++ b/sierra/plugins/platform/ros1gazebo/variables/population_size.py @@ -28,7 +28,7 @@ # Project packages from sierra.core.variables import batch_criteria as bc -from sierra.core.xml import XMLTagAdd, XMLTagAddList +from sierra.core.experiment import xml from sierra.core import types, utils from sierra.core.vector import Vector3D from sierra.core.variables import population_size @@ -70,9 +70,9 @@ def __init__(self, self.logger.warning("# possible positions < # robots: %s < %s", len(positions), self.sizes[-1]) - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: """ Generate list of sets of changes for system sizes to define a batch experiment. @@ -90,26 +90,26 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: desc_cmd = f"$(find xacro)/xacro $(find {model_base}_description)/urdf/{model}.urdf.xacro" for s in self.sizes: - exp_adds = XMLTagAddList() + exp_adds = xml.TagAddList() pos_i = random.randint(0, len(self.positions) - 1) - exp_adds.append(XMLTagAdd(".", - "master", - {}, - True)) - exp_adds.append(XMLTagAdd("./master", - "group", - { - 'ns': 'sierra' - }, - False)) - exp_adds.append(XMLTagAdd("./master/group/[@ns='sierra']", - "param", - { - 'name': 'experiment/n_robots', - 'value': str(s) - }, - False)) + exp_adds.append(xml.TagAdd(".", + "master", + {}, + True)) + exp_adds.append(xml.TagAdd("./master", + "group", + { + 'ns': 'sierra' + }, + False)) + exp_adds.append(xml.TagAdd("./master/group/[@ns='sierra']", + "param", + { + 'name': 'experiment/n_robots', + 'value': str(s) + }, + False)) for i in range(0, s): @@ -118,20 +118,20 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: pos_i = (pos_i + 1) % len(self.positions) spawn_cmd_args = f"-urdf -model {model}_{ns} -x {pos.x} -y {pos.y} -z {pos.z} -param robot_description" - exp_adds.append(XMLTagAdd("./robot", - "group", - { - 'ns': ns - }, - True)) - - exp_adds.append(XMLTagAdd(f"./robot/group/[@ns='{ns}']", - "param", - { - "name": "tf_prefix", - "value": ns - }, - True)) + exp_adds.append(xml.TagAdd("./robot", + "group", + { + 'ns': ns + }, + True)) + + exp_adds.append(xml.TagAdd(f"./robot/group/[@ns='{ns}']", + "param", + { + "name": "tf_prefix", + "value": ns + }, + True)) # These two tag adds are OK to use because: # @@ -140,23 +140,23 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: # # - All robots in Gazebo will provide a robot description # .urdf.xacro per ROS naming conventions - exp_adds.append(XMLTagAdd(f"./robot/group/[@ns='{ns}']", - "param", - { - "name": "robot_description", - "command": desc_cmd - }, - True)) - - exp_adds.append(XMLTagAdd(f"./robot/group/[@ns='{ns}']", - "node", - { - "name": "spawn_urdf", - "pkg": "gazebo_ros", - "type": "spawn_model", - "args": spawn_cmd_args - }, - True)) + exp_adds.append(xml.TagAdd(f"./robot/group/[@ns='{ns}']", + "param", + { + "name": "robot_description", + "command": desc_cmd + }, + True)) + + exp_adds.append(xml.TagAdd(f"./robot/group/[@ns='{ns}']", + "node", + { + "name": "spawn_urdf", + "pkg": "gazebo_ros", + "type": "spawn_model", + "args": spawn_cmd_args + }, + True)) self.tag_adds.append(exp_adds) diff --git a/sierra/plugins/platform/ros1robot/generators/platform_generators.py b/sierra/plugins/platform/ros1robot/generators/platform_generators.py index eb24c14d..0cc4616a 100644 --- a/sierra/plugins/platform/ros1robot/generators/platform_generators.py +++ b/sierra/plugins/platform/ros1robot/generators/platform_generators.py @@ -27,8 +27,7 @@ import yaml # Project packages -from sierra.core.xml import XMLLuigi, XMLTagAdd -from sierra.core.experiment.spec import ExperimentSpec +from sierra.core.experiment import spec, xml, definition from sierra.core import types, ros1, config, utils @@ -40,15 +39,15 @@ class PlatformExpDefGenerator(ros1.generators.ROSExpDefGenerator): """ def __init__(self, - spec: ExperimentSpec, + exp_spec: spec.ExperimentSpec, controller: str, cmdopts: types.Cmdopts, **kwargs) -> None: - super().__init__(spec, controller, cmdopts, **kwargs) + super().__init__(exp_spec, controller, cmdopts, **kwargs) self.logger = logging.getLogger(__name__) - def generate(self) -> XMLLuigi: + def generate(self) -> definition.XMLExpDef: exp_def = super().generate() self.logger.debug("Writing separate launch file") @@ -83,7 +82,7 @@ def __init__(self, ros1.generators.ROSExpRunDefUniqueGenerator.__init__( self, *args, **kwargs) - def generate(self, exp_def: XMLLuigi): + def generate(self, exp_def: definition.XMLExpDef): exp_def = super().generate(exp_def) main_path = os.path.join(self.cmdopts['project_config_root'], config.kYAML['main']) @@ -102,10 +101,10 @@ def generate(self, exp_def: XMLLuigi): 'src_parent': "./robot", 'src_tag': f"group/[@ns='{prefix}{i}']", 'opath_leaf': f'_robot{i}' + config.kROS['launch_file_ext'], - 'create_tags': [XMLTagAdd(None, - 'launch', - {}, - False)], + 'create_tags': [xml.TagAdd(None, + 'launch', + {}, + False)], 'dest_parent': ".", 'rename_to': None, 'child_grafts': ["./robot/group/[@ns='sierra']"] diff --git a/sierra/plugins/platform/ros1robot/plugin.py b/sierra/plugins/platform/ros1robot/plugin.py index 3ec27175..2d5a9fe9 100644 --- a/sierra/plugins/platform/ros1robot/plugin.py +++ b/sierra/plugins/platform/ros1robot/plugin.py @@ -28,8 +28,8 @@ # Project packages from sierra.plugins.platform.ros1robot import cmdline -from sierra.core import xml, platform, config, ros1, types, utils -from sierra.core.experiment import bindings +from sierra.core import platform, config, ros1, types, utils +from sierra.core.experiment import bindings, definition, xml import sierra.core.variables.batch_criteria as bc @@ -359,8 +359,8 @@ def __call__(self) -> None: "Wrong ROS version: This plugin is for ROS1" -def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, - xml.XMLTagAddList], +def population_size_from_pickle(adds_def: tp.Union[xml.AttrChangeSet, + xml.TagAddList], main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return ros1.callbacks.population_size_from_pickle(adds_def, @@ -368,7 +368,7 @@ def population_size_from_pickle(adds_def: tp.Union[xml.XMLAttrChangeSet, cmdopts) -def population_size_from_def(exp_def: xml.XMLLuigi, +def population_size_from_def(exp_def: definition.XMLExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> int: return ros1.callbacks.population_size_from_def(exp_def, diff --git a/sierra/plugins/platform/ros1robot/variables/population_size.py b/sierra/plugins/platform/ros1robot/variables/population_size.py index c355f4c5..a28ecc1d 100755 --- a/sierra/plugins/platform/ros1robot/variables/population_size.py +++ b/sierra/plugins/platform/ros1robot/variables/population_size.py @@ -27,9 +27,9 @@ # Project packages from sierra.core.variables import batch_criteria as bc -from sierra.core.xml import XMLTagAdd, XMLTagAddList from sierra.core import types from sierra.core.variables import population_size +from sierra.core.experiment import xml @implements.implements(bc.IConcreteBatchCriteria) @@ -62,9 +62,9 @@ def __init__(self, self.sizes = sizes self.robot = robot self.logger = logging.getLogger(__name__) - self.tag_adds = [] # type: tp.List[XMLTagAddList] + self.tag_adds = [] # type: tp.List[xml.TagAddList] - def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: + def gen_tag_addlist(self) -> tp.List[xml.TagAddList]: """ Generate list of sets of changes for system sizes to define a batch experiment. @@ -74,24 +74,24 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: prefix = robot_config['prefix'] for s in self.sizes: - per_robot = XMLTagAddList() - per_robot.append(XMLTagAdd(".", - "master", - {}, - True)) - per_robot.append(XMLTagAdd("./master", - "group", - { - 'ns': 'sierra' - }, - False)) - per_robot.append(XMLTagAdd("./master/group/[@ns='sierra']", - "param", - { - 'name': 'experiment/n_robots', - 'value': str(s) - }, - False)) + per_robot = xml.TagAddList() + per_robot.append(xml.TagAdd(".", + "master", + {}, + True)) + per_robot.append(xml.TagAdd("./master", + "group", + { + 'ns': 'sierra' + }, + False)) + per_robot.append(xml.TagAdd("./master/group/[@ns='sierra']", + "param", + { + 'name': 'experiment/n_robots', + 'value': str(s) + }, + False)) for i in range(0, s): @@ -99,20 +99,20 @@ def gen_tag_addlist(self) -> tp.List[XMLTagAddList]: # here--we can't know the exact node/package names without # using a lot of (brittle) config. ns = f'{prefix}{i}' - per_robot.append(XMLTagAdd("./robot", - "group", - { - 'ns': ns - }, - True)) - - per_robot.append(XMLTagAdd(f"./robot/group/[@ns='{ns}']", - "param", - { - "name": "tf_prefix", - "value": ns - }, - True)) + per_robot.append(xml.TagAdd("./robot", + "group", + { + 'ns': ns + }, + True)) + + per_robot.append(xml.TagAdd(f"./robot/group/[@ns='{ns}']", + "param", + { + "name": "tf_prefix", + "value": ns + }, + True)) self.tag_adds.append(per_robot) diff --git a/sierra/version.py b/sierra/version.py index 9c5f91e4..d15c2d4b 100644 --- a/sierra/version.py +++ b/sierra/version.py @@ -22,4 +22,4 @@ # Project packages -__version__ = "1.2.8" +__version__ = "1.2.9"