Repository: pylhc/PyLHC (language: python)

Issue:
remove auto_six and job_submitter from repo
Both scripts were moved to the new `submitter` repository.


Discussion / hints:

Fix patch:
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 071cbcb..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,1 +0,0 @@
-include pylhc/sixdesk_tools/mask_*
\ No newline at end of file
diff --git a/README.md b/README.md
index 1283964..5f3915d 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ pip install git+https://github.com/pylhc/PyLHC.git#egg=pylhc
 
 After installing, scripts can be run with either `python -m pylhc.SCRIPT --FLAG ARGUMENT` or by calling the `.py` files directly.
 
-Note: some of the scripts access functionality only available on the CERN Technical Network.
+Note: some scripts access functionality only available on the CERN Technical Network.
 To use those, you should make sure to install the relevant extra dependencies with `pip install path/to/Pylhc[tech]`.
 
 ## Description
@@ -42,8 +42,6 @@ This package provides tools for particle accelerator data analysis, simulations
 
 ## Functionality
 
-- `HTCondor Job Submitter` - Allows to generate jobs based on a templates and submit them to HTCondor. ([**job_submitter.py**](pylhc/job_submitter.py))
-- `AutoSix` - Allows to generate and submit parametric SixDesk studies easily. ([**autosix.py**](pylhc/autosix.py))
 - `Forced DA Analysis` - Script to analyse forced DA. ([**forced_da_analysis.py**](pylhc/forced_da_analysis.py))
 - `Machine Settings Info` - Prints an overview over the machine settings at a given time. ([**machine_settings_info.py**](pylhc/machine_settings_info.py))
 - `BSRT Logger` and `BSRT Analysis` - Saves data coming straight from LHC BSRT FESA class and allows subsequent analysis. ([**bsrt_logger.py**](pylhc/bsrt_logger.py) & [**bsrt_analysis.py**](pylhc/bsrt_analysis.py) )
diff --git a/doc/entrypoints/submitter.rst b/doc/entrypoints/submitter.rst
deleted file mode 100644
index 2a05570..0000000
--- a/doc/entrypoints/submitter.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-HTCondor Job Submitter
-**************************
-
-.. automodule:: pylhc.job_submitter
-    :members:
-
-
-.. automodule:: pylhc.autosix
-    :members:
diff --git a/doc/modules/htc.rst b/doc/modules/htc.rst
deleted file mode 100644
index ec1aadd..0000000
--- a/doc/modules/htc.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-HTCondor Tools
-**************************
-
-.. automodule:: pylhc.htc.utils
-    :members:
-
-
-.. automodule:: pylhc.htc.mask
-    :members:
diff --git a/doc/modules/sixdesk_tools.rst b/doc/modules/sixdesk_tools.rst
deleted file mode 100644
index fa6e48d..0000000
--- a/doc/modules/sixdesk_tools.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-Sixdesk Tools
-**************************
-
-.. automodule:: pylhc.sixdesk_tools.create_workspace
-    :members:
-
-.. automodule:: pylhc.sixdesk_tools.submit
-    :members:
-
-.. automodule:: pylhc.sixdesk_tools.post_process_da
-    :members:
-
-.. automodule:: pylhc.sixdesk_tools.utils
-    :members:
-
-.. automodule:: pylhc.sixdesk_tools.troubleshooting
-    :members:
diff --git a/pylhc/autosix.py b/pylhc/autosix.py
deleted file mode 100644
index 6e20768..0000000
--- a/pylhc/autosix.py
+++ /dev/null
@@ -1,642 +0,0 @@
-"""
-AutoSix
--------
-
-A wrapper for SixDesk to perform the setup and steps needed automatically.
-
-The idea is, to call this script with the same parameters and it runs through
-all the steps automatically.
-
-The functionality is similar to the :mod:`pylhc.job_submitter` in that
-the inner product of a ``replace_dict`` is used to automatically create a set of
-job-directories to gather the data.
-To avoid conflicts each of these job-directories is a SixDesk workspace,
-meaning there will be only one "study" per directory, .
-
-The ``replace_dict`` contains variables for your mask as well as variables
-for the SixDesk environment. See the description of ``replace_dict`` below.
-In any other way, these *special* variables behave like normal variables and
-can also be inserted in your mask. They are also looped over in the same manner
-as any other variable (if given as a list).
-
-.. important::
-    As the loop over Seeds is handled by SixDesk you need to set
-    `FIRSTSEED` and `LASTSEED` to ``None`` or ``0`` to deactivate this loop.
-    Otherwise a ``%SEEDRAN`` placeholder is required in your mask,
-    which needs to be present **after** filling in the variables (see example below).
-
-
-.. note::
-    Unlike in the :mod:`pylhc.job_submitter`, the output directory of the
-    HTCondor job (the 'mask-job') is not automatically transferred to the
-    workspace. To have access to this data, you will need to specify different
-    output-directories in your mask manually, e.g. using strings containing
-    the variable placeholders.
-
-
-.. code-block:: python
-
-    from pathlib import Path
-    from omc3.utils import logging_tools
-    from pylhc import autosix
-
-    LOG = logging_tools.get_logger(__name__)
-
-    if __name__ == '__main__':
-        autosix.main(
-            working_directory=Path('/afs/cern.ch/work/u/user/sixdeskbase'),
-            mask=Path('my_madx.mask'), # can contain any of the parameters used in replace_dict
-            python=Path('/afs/cern.ch/work/u/user/my_venv/bin/python'),
-            ignore_twissfail_check=False,  # if script prints 'check if twiss failed' or similar
-            replace_dict=dict(
-                # Part of the sixdesk-environment:
-                TURNS=100000,
-                AMPMIN=4, AMPMAX=30, AMPSTEP=2,
-                ANGLES=11,
-                # Examples for mask:
-                BEAM=[1, 4],
-                TUNE=[62.29, 62.30, 62.31, 62.31]
-                OUTPUT='/afs/cern.ch/work/u/user/study_output/',
-                SEED='%SEEDRAN',  # puts '%SEEDRAN' in the mask and lets sixdesk handle this loop
-            ),
-            jobid_mask="B%(BEAM)d-QX%(TUNE)s",
-            # unlock=True,
-            # resubmit=True,
-            # ssh='lxplus.cern.ch',
-        )
-
-
-Upon running the script the job-matrix is created
-(see *Jobs.tfs* in working directory) and the following stages are run per job:
-
-- ``create_jobs``: create workspace; fill sysenv, sixdeskenv, mask.
-- ``initialize_workspace``: initialize workspace from the env-files.
-- ``submit_mask``: submit mask-job to HTCondor. (*interrupt*)
-- ``check_input``: check if sixdesk input is complete.
-- ``submit_sixtrack``: submit sixdesk-jobs to HTCondor. (*interrupt*)
-- ``check_sixtrack_output``: check if all sixdesk jobs are completed.
-- ``sixdb_load``: create database and load jobs output.
-- ``sixdb_cmd``: calculated DA from database data.
-- ``post_process``: extract data from database, write into *.tfs* and plot.
-- ``final``: announce everything has finished
-
-
-To keep track of the stages, they are written into the *stages\_completed.txt*
-in the *autosix\_output* directory in the workspaces.
-Stages that are written in this file are assumed to be done and will be skipped.
-To rerun a stage, delete the stage and all following stages in that file and
-start your script anew.
-
-The stages are run independently of each job, meaning different jobs can be
-at different stages. E.g if one job has all data for the ``six_db`` analysis
-already, but the others are still running on sixdesk the
-``check_sixtrack_output`` stage will fail for these jobs but the other one will
-just continue.
-
-Because the stages after ``submit_mask`` and ``submit_sixtrack`` need only be
-run after the jobs on HTCondor are completed, these two stages interrupt the
-execution of stages if they have successfully finished. Check your scheduler
-via ``condor_q`` and run your script again after everything is done, to
-have autosix continue its work.
-
-.. note::
-    While most studies should be fine with the input options given, there is the
-    possibility to manually adapt the *sixdeskenv* and *sysenv* file before
-    workspace initialization but adding the switch ``stop_workspace_init``.
-    This will not reset automatically and one will have to remove the switch
-    again to continue.
-    As this is a bit of a workaround, it might be easier to define a new
-    variable in the **pylhc.sixdesk_tools.mask_sixdeskenv** file and put its
-    current default into **pylhc.constants.autosix.SIXENV_DEFAULT**.
-    One can then use the ``replace_dict`` to change its value.
-    This is left open as a task for the inspired user to implement, as only he
-    knows which variable he or she needs to change.
-
-
-AutoSix is not only able to run MAD-X masks, but also **cpymad** masks.
-Requirement for the latter is to provide the ``executable`` path to a
-python binary with **cpymad**, and all other packages used, installed.
-
-To create the files needed for Sixtrack input, MAD-X masks need to contain
-
-.. code-block:: bash
-
-    if (NRJ<5000.0000) {VRF400:=8.;} else {VRF400:=16.;};
-    LAGRF400.B1=0.5;
-    LAGRF400.B2=0.;
-    twiss;
-    sixtrack, cavall, radius=0.017;
-
-
-while **cpymad** masks can do the same task with
-
-.. code-block:: python
-
-    madx.globals["VRF400"] = 8 if madx.globals['NRJ'] < 5000 else 16
-    madx.globals["LAGRF400.B1"] = 0.5
-    madx.globals["LAGRF400.B2"] = 0.
-    madx.twiss()  # used by sixtrack
-    madx.sixtrack(cavall=True, radius=0.017)
-
-
-In theory, any kind of mask is possible, given the correct ``executable``
-is provided and the Sixtrack outputfiles created.
-
-.. note::
-    For the creation of polar plots, the function
-    :func:`pylhc.sixdesk_tools.post_process_da.plot_polar` is available,
-    which is used for the basic polar plotting in the ``post_process`` stage,
-    but provides more customization features if called manually.
-
-
-Arguments:
-
-*--Required--*
-
-- **mask** *(PathOrStr)*:
-
-    Program mask to use
-
-
-- **replace_dict** *(DictAsString)*:
-
-    Dict with keys of the strings to be replaced in the mask (required) as
-    well as the mask_sixdeskenv and mask_sysenv files in the sixdesk_tools
-    module. Required fields are TURNS, AMPMIN, AMPMAX, AMPSTEP,
-    ANGLES. Optional fields are RESUBMISSION, PLATFORM, LOGLEVEL,
-    FIRSTSEED, LASTSEED, ENERGY, NPAIRS, EMITTANCE, DIMENSIONS, WRITEBINS.
-    These keys can also be used in the mask if needed. The values of this
-    dict are lists of values to replace these or single entries.
-
-
-- **working_directory** *(PathOrStr)*:
-
-    Directory where data should be put
-
-
-*--Optional--*
-
-- **da_turnstep** *(int)*:
-
-    Step between turns used in DA-vs-Turns plot.
-
-    default: ``100``
-
-
-- **executable** *(PathOrStr)*:
-
-    Path to executable.
-
-    default: ``/afs/cern.ch/user/m/mad/bin/madx``
-
-
-- **apply_mad6t_hacks**:
-
-    Apply two hacks: Removes '<' in binary call and
-    ignore the check for 'Twiss fail' in the submission file.
-    This hack is needed in case this check greps the wrong lines,
-    e.g. in madx- comments. USE WITH CARE!!
-
-    action: ``store_true``
-
-
-- **jobid_mask** *(str)*:
-
-    Mask to name jobs from replace_dict
-
-
-- **python3** *(PathOrStr)*:
-
-    Path to python to use with sixdb (python3 with requirements
-    installed).
-
-    default: ``python3``
-
-
-- **python2** *(PathOrStr)*:
-
-    Path to python to use with run_six.sh (python2 with requirements installed).
-    ONLY THE PATH TO THE DIRECTORY OF THE python BINARY IS NEEDED!
-    And it can't be an Anaconda Distribution.
-
-    default: None (uses the first `python` in path)
-
-
-- **resubmit**:
-
-    Resubmits if needed.
-
-    action: ``store_true``
-
-
-- **ssh** *(str)*:
-
-    Run htcondor from this machine via ssh (needs access to the
-    `working_directory`)
-
-
-- **stop_workspace_init**:
-
-    Stops the workspace creation before initialization, so one can make
-    manual changes.
-
-    action: ``store_true``
-
-
-- **unlock**:
-
-    Forces unlocking of folders.
-
-    action: ``store_true``
-
-
-
-:author: jdilly
-
-"""
-import itertools
-from pathlib import Path
-from typing import Union
-
-import numpy as np
-import tfs
-from generic_parser import EntryPointParameters, entrypoint
-from generic_parser.entry_datatypes import DictAsString
-from omc3.utils import logging_tools
-from omc3.utils.iotools import PathOrStr, save_config
-
-from pylhc.constants.autosix import (
-    Stage,
-    HEADER_BASEDIR,
-    get_stagefile_path,
-    DEFAULTS,
-    SIXENV_REQUIRED,
-    SIXENV_DEFAULT,
-)
-from pylhc.htc.mask import generate_jobdf_index
-from pylhc.job_submitter import (
-    JOBSUMMARY_FILE,
-    COLUMN_JOBID,
-    check_replace_dict,
-    keys_to_path,
-)
-from pylhc.sixdesk_tools.create_workspace import (
-    create_job,
-    remove_twiss_fail_check,
-    init_workspace,
-    fix_pythonfile_call
-)
-from pylhc.sixdesk_tools.post_process_da import post_process_da
-from pylhc.sixdesk_tools.submit import (
-    submit_mask,
-    submit_sixtrack,
-    check_sixtrack_input,
-    check_sixtrack_output,
-    sixdb_cmd,
-    sixdb_load,
-)
-from pylhc.sixdesk_tools.utils import is_locked, check_mask, check_stage, StageSkip
-
-LOG = logging_tools.get_logger(__name__)
-
-
-def get_params():
-    params = EntryPointParameters()
-    params.add_parameter(
-        name="mask",
-        type=PathOrStr,
-        required=True,
-        help="Program mask to use",
-    )
-    params.add_parameter(
-        name="working_directory",
-        type=PathOrStr,
-        required=True,
-        help="Directory where data should be put",
-    )
-    params.add_parameter(
-        name="replace_dict",
-        help=(
-            "Dict with keys of the strings to be replaced in the mask (required) "
-            "as well as the mask_sixdeskenv and mask_sysenv files "
-            "in the sixdesk_tools module. "
-            f"Required fields are {', '.join(SIXENV_REQUIRED)}. "
-            f"Optional fields are {', '.join(SIXENV_DEFAULT.keys())}. "
-            "These keys can also be used in the mask if needed. "
-            "The values of this dict are lists of values to replace "
-            "these or single entries."
-        ),
-        type=DictAsString,
-        required=True,
-    )
-    params.add_parameter(
-        name="executable",
-        default=DEFAULTS["executable"],
-        type=PathOrStr,
-        help="Path to executable.",
-    )
-    params.add_parameter(
-        name="python2",
-        default=DEFAULTS["python2"],
-        type=PathOrStr,
-        help=("Path to python to use with run_six.sh (python2 with requirements installed)."
-              " ONLY THE PATH TO THE DIRECTORY OF THE python BINARY IS NEEDED!"
-              " And it can't be an Anaconda Distribution."),
-    )
-    params.add_parameter(
-        name="python3",
-        default=DEFAULTS["python3"],
-        type=PathOrStr,
-        help="Path to python to use with sixdb (python3 with requirements installed).",
-    )
-    params.add_parameter(
-        name="jobid_mask",
-        help="Mask to name jobs from replace_dict",
-        type=str,
-    )
-    params.add_parameter(
-        name="ssh",
-        help="Run htcondor from this machine via ssh (needs access to the `working_directory`)",
-        type=str,
-    )
-    params.add_parameter(
-        name="unlock",
-        help="Forces unlocking of folders.",
-        action="store_true",
-    )
-    params.add_parameter(
-        name="apply_mad6t_hacks",
-        help=(
-            "Apply two hacks: Removes '<' in binary call and"
-            "ignore the check for 'Twiss fail' in the submission file. "
-            "This is hack needed in case this check greps the wrong lines, "
-            "e.g. in madx-comments. USE WITH CARE!!"
-        ),
-        action="store_true",
-    )
-    params.add_parameter(
-        name="stop_workspace_init",
-        help=(
-            "Stops the workspace creation before initialization,"
-            " so one can make manual changes."
-        ),
-        action="store_true",
-    )
-    params.add_parameter(
-        name="resubmit",
-        help="Resubmits if needed.",
-        action="store_true",
-    )
-    params.add_parameter(
-        name="da_turnstep",
-        type=int,
-        help="Step between turns used in DA-vs-Turns plot.",
-        default=DEFAULTS["da_turnstep"],
-    )
-    params.add_parameter(
-        name="max_stage",
-        type=str,
-        help="Last stage to be run. All following stages are skipped.",
-    )
-    return params
-
-
-@entrypoint(get_params(), strict=True)
-def main(opt):
-    """ Loop to create jobs from replace dict product matrix. """
-    LOG.info("Starting autosix.")
-    with open(opt.mask, "r") as mask_f:
-        mask = mask_f.read()
-    opt = _check_opts(mask, opt)
-    save_config(opt.working_directory, opt, __file__)
-
-    jobdf = _generate_jobs(opt.working_directory, opt.jobid_mask, **opt.replace_dict)
-    for job_args in jobdf.iterrows():
-        setup_and_run(
-            jobname=job_args[0],
-            basedir=opt.working_directory,
-            # kwargs:
-            ssh=opt.ssh,
-            python2=opt.python2,
-            python3=opt.python3,
-            unlock=opt.unlock,
-            resubmit=opt.resubmit,
-            da_turnstep=opt.da_turnstep,
-            apply_mad6t_hacks=opt.apply_mad6t_hacks,
-            max_stage=opt.max_stage,
-            # kwargs passed only to create_jobs:
-            mask_text=mask,
-            binary_path=opt.executable,
-            stop_workspace_init=opt.stop_workspace_init,
-            **job_args[1],
-        )
-
-
-def setup_and_run(jobname: str, basedir: Path, **kwargs):
-    """Main submitting procedure for single job.
-
-    Args:
-        jobname (str): Name of the job/study
-        basedir (Path): Working directory
-
-    Keyword Args (optional):
-        unlock (bool): unlock folder
-        ssh (str): ssh-server to use
-        python (str): python binary to use for sixDB
-        resubmit(bool): Resubmit jobs if checks fail
-        da_turnstep (int): Step in turns for DA
-        ignore_twissfail_check (bool): Hack to ignore check for 'Twiss fail' after run
-        max_stage (str): Last stage to run
-
-    Keyword Args (needed for create jobs):
-        mask_text (str): Content of the mask to use.
-        binary_path (Path): path to binary to use in jobs
-        All Key=Values needed to fill the mask!
-        All Key=Values needed to fill the mask!
-
-    """
-    LOG.info(f"vv---------------- Job {jobname} -------------------vv")
-    unlock: bool = kwargs.pop("unlock", False)
-    ssh: str = kwargs.pop("ssh", None)
-    python2: Union[Path, str] = kwargs.pop("python2", DEFAULTS["python2"])
-    python3: Union[Path, str] = kwargs.pop("python3", DEFAULTS["python3"])
-    resubmit: bool = kwargs.pop("resubmit", False)
-    da_turnstep: int = kwargs.pop("da_turnstep", DEFAULTS["da_turnstep"])
-    apply_mad6t_hacks: bool = kwargs.pop("apply_mad6t_hacks", False)
-    stop_workspace_init: bool = kwargs.pop("stop_workspace_init", False)
-    max_stage: str = kwargs.pop("max_stage", None)
-    if max_stage is not None:
-        max_stage = Stage[max_stage]
-
-    if is_locked(jobname, basedir, unlock=unlock):
-        LOG.info(f"{jobname} is locked. Try 'unlock' flag if this causes errors.")
-
-    with check_stage(Stage.create_job, jobname, basedir, max_stage) as check_ok:
-        """
-        create workspace
-        > cd $basedir
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/set_env.sh -N workspace-$jobname
-
-        write sixdeskenv, sysenv, filled mask (manual)
-
-        """
-        if check_ok:
-            create_job(jobname, basedir, ssh=ssh, **kwargs)
-
-    with check_stage(Stage.initialize_workspace, jobname, basedir, max_stage) as check_ok:
-        """
-        initialize workspace
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/set_env.sh -s
-
-        remove the twiss-fail check in sixtrack_input
-        (manual)
-        """
-        if check_ok:
-            if stop_workspace_init:
-                LOG.info(
-                    f"Workspace creation for job {jobname} interrupted."
-                    " Check directory to manually adapt `sixdeskenv`"
-                    " and `sysenv`. Remove 'stop_workspace_init' from input"
-                    " parameters or set to 'False' to continue run."
-                )
-                raise StageSkip()
-
-            init_workspace(jobname, basedir, ssh=ssh)
-            if apply_mad6t_hacks:
-                fix_pythonfile_call(jobname, basedir)  # removes "<" in call
-                remove_twiss_fail_check(jobname, basedir)  # removes 'grep twiss fail'
-
-    with check_stage(Stage.submit_mask, jobname, basedir, max_stage) as check_ok:
-        """
-        submit for input generation
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/mad6t.sh -s
-        """
-        if check_ok:
-            submit_mask(jobname, basedir, ssh=ssh)
-            return  # takes a while, so we interrupt here
-
-    with check_stage(Stage.check_input, jobname, basedir, max_stage) as check_ok:
-        """
-        Check if input files have been generated properly
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/mad6t.sh -c
-
-        If not, and resubmit is active
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/mad6t.sh -w
-        """
-        if check_ok:
-            check_sixtrack_input(jobname, basedir, ssh=ssh, resubmit=resubmit)
-
-    with check_stage(Stage.submit_sixtrack, jobname, basedir, max_stage) as check_ok:
-        """
-        Generate simulation files (-g) and check if runnable (-c) and submit (-s) (-g -c -s == -a).
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/run_six.sh -a
-        """
-        if check_ok:
-            submit_sixtrack(jobname, basedir, python=python2, ssh=ssh)
-            return  # takes even longer
-
-    with check_stage(Stage.check_sixtrack_output, jobname, basedir, max_stage) as check_ok:
-        """
-        Checks sixtrack output via run_status. If this fails even though all
-        jobs have finished on the scheduler, check the log-output (run_status
-        messages are logged to debug).
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/run_status
-        
-        If not, and resubmit is active
-        > cd $basedir/workspace-$jobname/sixjobs
-        > /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/bash/run_six.sh -i
-        """
-        if check_ok:
-            check_sixtrack_output(jobname, basedir, python=python2, ssh=ssh, resubmit=resubmit)
-
-    with check_stage(Stage.sixdb_load, jobname, basedir, max_stage) as check_ok:
-        """
-        Gather results into database via sixdb.
-        > cd $basedir/workspace-$jobname/sixjobs
-        > python3 /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/externals/SixDeskDB/sixdb . load_dir
-        """
-        if check_ok:
-            sixdb_load(jobname, basedir, python=python3, ssh=ssh)
-
-    with check_stage(Stage.sixdb_cmd, jobname, basedir, max_stage) as check_ok:
-        """
-        Analysise results in database via sixdb.
-        > cd $basedir/workspace-$jobname/sixjobs
-        > python3 /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/externals/SixDeskDB/sixdb $jobname da
-
-        when fixed:
-        > python3 /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/externals/SixDeskDB/sixdb $jobname da_vs_turns -turnstep 100 -outfile
-        > python3 /afs/cern.ch/project/sixtrack/SixDesk_utilities/pro/utilities/externals/SixDeskDB/sixdb $jobname plot_da_vs_turns
-        """
-        if check_ok:
-            sixdb_cmd(jobname, basedir, cmd=["da"], python=python3, ssh=ssh)
-
-            # da_vs_turns is broken at the moment (jdilly, 19.10.2020)
-            # sixdb_cmd(jobname, basedir, cmd=['da_vs_turns', '-turnstep', str(da_turnstep), '-outfile'],
-            #           python=python, ssh=ssh)
-            # sixdb_cmd(jobname, basedir, cmd=['plot_da_vs_turns'], python=python, ssh=ssh)
-
-    with check_stage(Stage.post_process, jobname, basedir, max_stage) as check_ok:
-        """
-        Extracts the analysed data in the database and writes them to three tfs files:
-
-        - All DA values
-        - Statistics over angles, listed per seed (+ Seed 0 as over seeds and angles)
-        - Statistics over seeds, listed per angle
-
-        The statistics over the seeds are then plotted in a polar plot.
-        All files are outputted to the ``sixjobs/autosix_output`` folder in the job directory.
-        """
-        if check_ok:
-            post_process_da(jobname, basedir)
-
-    with check_stage(Stage.final, jobname, basedir, max_stage) as check_ok:
-        """ Just info about finishing this script and where to check the stagefile. """
-        if check_ok:
-            stage_file = get_stagefile_path(jobname, basedir)
-            LOG.info(
-                f"All stages run. Check stagefile {str(stage_file)} "
-                "in case you want to rerun some stages."
-            )
-            raise StageSkip()
-
-    LOG.info(f"^^---------------- Job {jobname} -------------------^^")
-
-
-# Helper for main --------------------------------------------------------------
-
-
-def _check_opts(mask_text, opt):
-    opt = keys_to_path(opt, "mask", "working_directory", "executable")
-    check_mask(mask_text, opt.replace_dict)
-    opt.replace_dict = check_replace_dict(opt.replace_dict)
-    return opt
-
-
-def get_jobs_and_values(jobid_mask, **kwargs):
-    values_grid = np.array(list(itertools.product(*kwargs.values())), dtype=object)
-    job_names = generate_jobdf_index(None, jobid_mask, kwargs.keys(), values_grid)
-    return job_names, values_grid
-
-
-def _generate_jobs(basedir, jobid_mask, **kwargs) -> tfs.TfsDataFrame:
-    """ Generates product matrix for job-values and stores it as TfsDataFrame. """
-    LOG.debug("Creating Jobs")
-    job_names, values_grid = get_jobs_and_values(jobid_mask, **kwargs)
-    job_df = tfs.TfsDataFrame(
-        headers={HEADER_BASEDIR: basedir},
-        index=job_names,
-        columns=list(kwargs.keys()),
-        data=values_grid,
-    )
-    tfs.write(basedir / JOBSUMMARY_FILE, job_df, save_index=COLUMN_JOBID)
-    return job_df
-
-
-if __name__ == "__main__":
-    main()
diff --git a/pylhc/constants/autosix.py b/pylhc/constants/autosix.py
deleted file mode 100644
index eaa3d64..0000000
--- a/pylhc/constants/autosix.py
+++ /dev/null
@@ -1,148 +0,0 @@
-"""
-Constants: Autosix
-----------------------------------
-
-Collections of constants and paths used in autosix.
-
-:module: constants.autosix
-:author: jdilly
-
-"""
-from pathlib import Path
-
-from pylhc.constants.external_paths import SIXDESK_UTILS, MADX_BIN
-from enum import IntEnum
-
-# Program Paths ----------------------------------------------------------------
-SETENV_SH = SIXDESK_UTILS / "set_env.sh"
-MAD_TO_SIXTRACK_SH = SIXDESK_UTILS / "mad6t.sh"
-RUNSIX_SH = SIXDESK_UTILS / "run_six.sh"
-RUNSTATUS_SH = SIXDESK_UTILS / "run_status"
-DOT_PROFILE = SIXDESK_UTILS / "dot_profile"
-SIXDB = SIXDESK_UTILS.parent / "externals" / "SixDeskDB" / "sixdb"
-SIXDESKLOCKFILE = "sixdesklock"
-
-# Constants and Requirements ---------------------------------------------------
-
-HEADER_BASEDIR = "BASEDIR"
-
-# Defaults ---
-
-DEFAULTS = dict(
-    python2=None,
-    python3="python3",
-    da_turnstep=100,
-    executable=MADX_BIN,
-)
-
-# Stages ---
-Stage = IntEnum('Stage',
-                names=[
-                    "create_job",
-                    "initialize_workspace",
-                    "submit_mask",
-                    "check_input",
-                    "submit_sixtrack",
-                    "check_sixtrack_output",
-                    "sixdb_load",
-                    "sixdb_cmd",
-                    "post_process",
-                    "final",
-                ],
-                start=0)
-
-# Sixenv ---
-SIXENV_REQUIRED = ["TURNS", "AMPMIN", "AMPMAX", "AMPSTEP", "ANGLES"]
-SIXENV_DEFAULT = dict(
-    RESUBMISSION=0,  # 0: never, 1: if fort.10, 2: always
-    PLATFORM="HTCondor",
-    LOGLEVEL=0,  # 0: basic + errors , 1: + info, >=2: + debug
-    FIRSTSEED=1,
-    LASTSEED=60,
-    ENERGY="col",  # 'col' or 'inj'
-    NPAIRS=30,  # 1-32 particle pairs
-    EMITTANCE=3.75,  # normalized emittance
-    DIMENSIONS=6,  # Phase-Space dimensions
-    WRITEBINS=500,
-)
-SEED_KEYS = ["FIRSTSEED", "LASTSEED"]
-
-
-# SixDB and Postprocess ---
-
-SIXTRACK_OUTPUT_FILES = "fort.10.gz", "Sixout.zip"
-SIXTRACK_INPUT_CHECK_FILES = "JOB_NOT_YET_STARTED", "JOB_NOT_YET_COMPLETED"
-
-HEADER_NTOTAL, HEADER_INFO, HEADER_HINT = "NTOTAL", "INFO", "HINT"
-MEAN, STD, MIN, MAX, N = "MEAN", "STD", "MIN", "MAX", "N"
-SEED, ANGLE, ALOST1, ALOST2, AMP = "SEED", "ANGLE", "ALOST1", "ALOST2", "A"
-
-
-# Workspace Paths --------------------------------------------------------------
-
-# Input ---
-def get_workspace_path(jobname: str, basedir: Path) -> Path:
-    return basedir / f"workspace-{jobname}"
-
-
-def get_scratch_path(basedir: Path) -> Path:
-    return basedir / f"scratch-0"
-
-
-def get_sixjobs_path(jobname: str, basedir: Path) -> Path:
-    return get_workspace_path(jobname, basedir) / "sixjobs"
-
-
-def get_sixdeskenv_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "sixdeskenv"
-
-
-def get_sysenv_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "sysenv"
-
-
-def get_masks_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "mask"
-
-
-def get_track_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "track"
-
-
-def get_database_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / f"{jobname}.db"
-
-
-def get_sixtrack_input_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "sixtrack_input"
-
-
-def get_mad6t_mask_path(jobname: str, basedir: Path) -> Path:
-    return get_sixtrack_input_path(jobname, basedir) / "mad6t.sh"
-
-
-def get_mad6t1_mask_path(jobname: str, basedir: Path) -> Path:
-    return get_sixtrack_input_path(jobname, basedir) / "mad6t1.sh"
-
-
-# Output ---
-
-
-def get_autosix_results_path(jobname: str, basedir: Path) -> Path:
-    return get_sixjobs_path(jobname, basedir) / "autosix_output"
-
-
-def get_stagefile_path(jobname: str, basedir: Path) -> Path:
-    return get_autosix_results_path(jobname, basedir) / "stages_completed.txt"
-
-
-def get_tfs_da_path(jobname: str, basedir: Path) -> Path:
-    return get_autosix_results_path(jobname, basedir) / f"{jobname}_da.tfs"
-
-
-def get_tfs_da_seed_stats_path(jobname: str, basedir: Path) -> Path:
-    return get_autosix_results_path(jobname, basedir) / f"{jobname}_da_per_seed.tfs"
-
-
-def get_tfs_da_angle_stats_path(jobname: str, basedir: Path) -> Path:
-    return get_autosix_results_path(jobname, basedir) / f"{jobname}_da_per_angle.tfs"
diff --git a/pylhc/constants/external_paths.py b/pylhc/constants/external_paths.py
deleted file mode 100644
index ca6bdc1..0000000
--- a/pylhc/constants/external_paths.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-Constants: External Paths
--------------------------
-
-Specific constants relating to external paths to be used in ``PyLHC``,
-to help with consistency.
-"""
-from pathlib import Path
-
-AFS_CERN = Path("/", "afs", "cern.ch")
-LINTRACK = AFS_CERN / "eng" / "sl" / "lintrack"
-
-# Binary Files -----------------------------------------------------------------
-MADX_BIN = AFS_CERN / "user" / "m" / "mad" / "bin" / "madx"
-PYTHON3_BIN = LINTRACK / "anaconda3" / "bin" / "python"
-PYTHON2_BIN = LINTRACK / "miniconda2" / "bin" / "python"
-SIXDESK_UTILS = (
-        AFS_CERN / "project" / "sixtrack" / "SixDesk_utilities" / "pro" / "utilities" / "bash"
-)
-
-
-# Repositories -----------------------------------------------------------------
-SIXDESK_GITHUB = "https://github.com/SixTrack/SixDesk.git"
diff --git a/pylhc/htc/__init__.py b/pylhc/htc/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/pylhc/htc/mask.py b/pylhc/htc/mask.py
deleted file mode 100644
index 1458e00..0000000
--- a/pylhc/htc/mask.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""
-Mask Resolver
--------------
-
-This module provides functionality to resolve and write script masks for ``HTCondor`` jobs
-submission.
-"""
-import logging
-import re
-from pathlib import Path
-
-import pandas as pd
-
-from pylhc.htc.utils import COLUMN_JOB_DIRECTORY, COLUMN_JOB_FILE
-
-LOG = logging.getLogger(__name__)
-
-
-def create_jobs_from_mask(
-    job_df: pd.DataFrame, maskfile: Path, replace_keys: dict, file_ext: str
-) -> pd.DataFrame:
-    """
-    Takes path to mask file, list of parameter to be replaced and pandas dataframe containg per job
-    the job directory where processed mask is to be put, and columns containing the parameter values
-    with column named like replace parameters. Job directories have to be created beforehand.
-    Processed (madx) mask has the same filename as mask but with the given file extension.
-    Input Dataframe is returned with additional column containing path to the processed script
-    files.
-
-    Args:
-        job_df (pd.DataFrame): Job parameters as defined in description.
-        maskfile: `Path` object to the mask file.
-        replace_keys: keys to be replaced (must correspond to columns in ``job_df``).
-        file_ext: file extention to use (defaults to **madx**).
-
-    Returns:
-        The provided ``job_df`` but with added path to the scripts.
-    """
-    with maskfile.open("r") as mfile:
-        template = mfile.read()
-
-    jobname = maskfile.with_suffix("").name
-    jobs = [None] * len(job_df)
-    for idx, (jobid, values) in enumerate(job_df.iterrows()):
-        jobfile_fullpath = (Path(values[COLUMN_JOB_DIRECTORY]) / jobname).with_suffix(file_ext)
-
-        with jobfile_fullpath.open("w") as madxjob:
-            madxjob.write(template % dict(zip(replace_keys, values[list(replace_keys)])))
-        jobs[idx] = jobfile_fullpath.name
-    job_df[COLUMN_JOB_FILE] = jobs
-    return job_df
-
-
-def find_named_variables_in_mask(mask: str):
-    return set(re.findall(r"%\((\w+)\)", mask))
-
-
-def check_percentage_signs_in_mask(mask: str):
-    """ Checks for '%' in the mask, that are not replacement variables. """
-    cleaned_mask = re.sub(r"%\((\w+)\)", "", mask)
-    n_signs = cleaned_mask.count("%")
-    if n_signs == 0:
-        return
-
-    # Help the user find the %
-    for idx, line in enumerate(cleaned_mask.split("\n")):
-        if "%" in line:
-            positions = [str(i) for i, char in enumerate(line) if char == "%"]
-            LOG.error(f"Problematic '%' sign(s) in line {idx}, pos {' ,'.join(positions)}.")
-    raise KeyError(f"{n_signs} problematic '%' signs found in template. Please remove.")
-
-
-def generate_jobdf_index(old_df, jobid_mask, keys, values):
-    """ Generates index for jobdf from mask for job_id naming. """
-    if not jobid_mask:
-        nold = len(old_df.index) if old_df is not None else 0
-        start = nold-1 if nold > 0 else 0
-        return range(start, start + values.shape[0])
-    return [jobid_mask % dict(zip(keys, v)) for v in values]
-
-
-if __name__ == "__main__":
-    raise EnvironmentError(f"{__file__} is not supposed to run as main.")
diff --git a/pylhc/htc/utils.py b/pylhc/htc/utils.py
deleted file mode 100644
index c9f918d..0000000
--- a/pylhc/htc/utils.py
+++ /dev/null
@@ -1,235 +0,0 @@
-"""
-HTCondor Utilities
-------------------
-
-This module provides functionality to create HTCondor jobs and submit them to ``HTCondor``.
-
-``write_bash`` creates bash scripts executing either a python or madx script.
-Takes as input `Dataframe`, job type, and optional additional commandline arguments for the script.
-A shell script is created in each job directory in the dataframe.
-
-``make_subfile`` takes the job dataframe and creates the **.sub** files required for submissions to
-``HTCondor``. The **.sub** file will be put in the working directory. The maximum runtime of one
-job can be specified, standard is 8h.
-"""
-import logging
-import subprocess
-from pathlib import Path
-
-from pandas import DataFrame
-
-try:
-    import htcondor
-except ImportError:  # will be handled by job_submitter
-    pass
-
-from pylhc.constants.external_paths import MADX_BIN, PYTHON2_BIN, PYTHON3_BIN
-
-LOG = logging.getLogger(__name__)
-
-
-SHEBANG = "#!/bin/bash"
-SUBFILE = "queuehtc.sub"
-BASH_FILENAME = "Job"
-
-HTCONDOR_JOBLIMIT = 100000
-
-EXECUTEABLEPATH = {
-    "madx": MADX_BIN,
-    "python3": PYTHON3_BIN,
-    "python2": PYTHON2_BIN,
-}
-
-
-CMD_SUBMIT = "condor_submit"
-JOBFLAVOURS = (
-    "espresso",  # 20 min
-    "microcentury",  # 1 h
-    "longlunch",  # 2 h
-    "workday",  # 8 h
-    "tomorrow",  # 1 d
-    "testmatch",  # 3 d
-    "nextweek",  # 1 w
-)
-
-NOTIFICATIONS = ("always", "complete", "error", "never")
-
-
-COLUMN_SHELL_SCRIPT = "ShellScript"
-COLUMN_JOB_DIRECTORY = "JobDirectory"
-COLUMN_JOB_FILE = "JobFile"
-
-
-# Subprocess Methods ###########################################################
-
-
-def create_subfile_from_job(cwd: Path, job: str):
-    """Write file to submit to ``HTCondor``."""
-    subfile = cwd / SUBFILE
-    LOG.debug(f"Writing sub-file '{str(subfile)}'.")
-    with subfile.open("w") as f:
-        f.write(str(job))
-    return subfile
-
-
-def submit_jobfile(jobfile: Path, ssh: str):
-    """Submit subfile to ``HTCondor`` via subprocess."""
-    proc_args = [CMD_SUBMIT, jobfile]
-    if ssh:
-        proc_args = ["ssh", ssh] + proc_args
-    status = _start_subprocess(proc_args)
-    if status:
-        raise RuntimeError("Submit to HTCondor was not successful!")
-    else:
-        LOG.info("Jobs successfully submitted.")
-
-
-def _start_subprocess(command):
-    LOG.debug(f"Executing command '{command}'")
-    process = subprocess.Popen(
-        command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-    )
-    for line in process.stdout:
-        htc_line = line.decode("utf-8").strip()
-        if htc_line:
-            LOG.debug(f"{htc_line} (from HTCondor)")
-    return process.wait()
-
-
-# Job Creation #################################################################
-
-
-def create_multijob_for_bashfiles(job_df: DataFrame, **kwargs):
-    """
-    Function to create an ``HTCondor`` job assuming n_files bash-files.
-
-    Keyword Args:
-        output_dir (str): output directory that will be transferred. Defaults to ``None``.
-        duration (str): max duration of the job. Needs to be one of the ``HTCondor`` Jobflavours.
-            Defaults to ``workday``.
-        group (str): force use of accounting group. Defaults to ``None``.
-        retries (int): maximum amount of retries. Default to ``3``.
-        notification (str): Notify under certain conditions. Defaults to ``error``.
-        priority (int): Priority to order your jobs. Defaults to ``None``.
-    """
-    submit_dict = {
-        "MyId": "htcondor",
-        "universe": "vanilla",
-        "arguments": "$(ClusterId) $(ProcId)",
-        "output": Path("$(initialdir)", "$(MyId).$(ClusterId).$(ProcId).out"),
-        "error": Path("$(initialdir)", "$(MyId).$(ClusterId).$(ProcId).err"),
-        "log": Path("$(initialdir)", "$(MyId).$(ClusterId).$(ProcId).log"),
-        "on_exit_remove": "(ExitBySignal == False) && (ExitCode == 0)",
-        "requirements": "Machine =!= LastRemoteHost",
-    }
-    submit_dict.update(_map_kwargs(kwargs))
-
-    job = htcondor.Submit(submit_dict)
-
-    # add the multiple bash files
-    scripts = [
-        str(Path(*parts))
-        for parts in zip(job_df[COLUMN_JOB_DIRECTORY], job_df[COLUMN_SHELL_SCRIPT])
-    ]
-    args = [",".join(parts) for parts in zip(scripts, job_df[COLUMN_JOB_DIRECTORY])]
-    queueArgs = ["queue executable, initialdir from (", *args, ")"]
-
-    # ugly but job.setQArgs doesn't take string containing \n
-    # job.setQArgs("\n".join(queueArgs))
-    job = str(job) + "\n".join(queueArgs)
-    LOG.debug(f"Created HTCondor subfile with content: \n{job}")
-    return job
-
-
-# Main functions ###############################################################
-
-
-def make_subfile(cwd: Path, job_df: DataFrame, **kwargs):
-    """
-    Creates submit-file for ``HTCondor``.
-    For kwargs, see ``create_multijob_for_bashfiles``.
-    """
-    job = create_multijob_for_bashfiles(job_df, **kwargs)
-    return create_subfile_from_job(cwd, job)
-
-
-def write_bash(
-    job_df: DataFrame,
-    output_dir: Path = None,
-    executable: str = "madx",
-    cmdline_arguments: dict = None,
-) -> DataFrame:
-    """Write the bash-files to be called by ``HTCondor``."""
-    if len(job_df.index) > HTCONDOR_JOBLIMIT:
-        raise AttributeError("Submitting too many jobs for HTCONDOR")
-
-    cmds = ""
-    if cmdline_arguments is not None:
-        cmds = " ".join([f"{param} {val}" for param, val in cmdline_arguments.items()])
-
-    exec_path = EXECUTEABLEPATH.get(executable, executable)
-    shell_scripts = [None] * len(job_df.index)
-    for idx, (jobid, job) in enumerate(job_df.iterrows()):
-        job_dir = Path(job[COLUMN_JOB_DIRECTORY])
-        bash_file_name = f"{BASH_FILENAME}.{jobid}.sh"
-        jobfile = job_dir / bash_file_name
-        LOG.debug(f"Writing bash-file {idx:d} '{jobfile}'.")
-        with open(jobfile, "w") as f:
-            f.write(f"{SHEBANG}\n")
-            if output_dir is not None:
-                f.write(f"mkdir {str(output_dir)}\n")
-            f.write(f"{str(exec_path)} {str(job_dir / job[COLUMN_JOB_FILE])} {cmds}\n")
-        shell_scripts[idx] = bash_file_name
-    job_df[COLUMN_SHELL_SCRIPT] = shell_scripts
-    return job_df
-
-
-# Helper #######################################################################
-
-
-def _map_kwargs(add_dict):
-    """
-    Maps the kwargs for the job-file. Some arguments have pre-defined choices and defaults,
-    the remaining ones are just passed on.
-    """
-    new = {}
-
-    # Predefined ones
-    htc_map = {
-        "duration": ("+JobFlavour", JOBFLAVOURS, "workday"),
-        "output_dir": ("transfer_output_files", None, None),
-        "accounting_group": ("+AccountingGroup", None, None),
-        "max_retries": ("max_retries", None, 3),
-        "notification": ("notification", NOTIFICATIONS, "error"),
-    }
-    for key, (mapped, choices, default) in htc_map.items():
-        try:
-            value = add_dict.pop(key)
-        except KeyError:
-            if default is not None:
-                new[mapped] = default
-        else:
-            if choices is not None and value not in choices:
-                raise TypeError(
-                    f"{key} needs to be one of '{str(choices).strip('[]')}' but "
-                    f"instead was '{value}'"
-                )
-            new[mapped] = _maybe_put_in_quotes(mapped, value)
-
-    # Pass-Through Arguments
-    LOG.debug(f"Remaining arguments to be added: '{str(add_dict).strip('{}'):s}'")
-    new.update(add_dict)
-    return new
-
-
-def _maybe_put_in_quotes(key, value):
-    if key.startswith("+"):
-        return f'"{value}"'
-    return value
-
-
-# Script Mode ##################################################################
-
-
-if __name__ == "__main__":
-    raise EnvironmentError(f"{__file__} is not supposed to run as main.")
diff --git a/pylhc/job_submitter.py b/pylhc/job_submitter.py
deleted file mode 100644
index 30a9bcd..0000000
--- a/pylhc/job_submitter.py
+++ /dev/null
@@ -1,535 +0,0 @@
-"""
-Job Submitter
--------------
-
-Allows to execute a parametric study using a script-mask and a `dictionary` with parameters to
-replace, from the command line. The parameters to be replaced must be present in the given mask as
-``%(PARAMETER)s`` (other types apart from string also allowed).
-
-The type of script and executable is freely choosable, but defaults to ``madx`` - for which this
-submitter was originally written.
-
-When submitting to ``HTCondor``, data to be transferred back to the working directory must be
-written in a sub-folder defined by ``job_output_directory`` which defaults to **Outputdata**.
-
-This script also allows to check if all ``HTCondor`` jobs finished successfully, for resubmissions
-with a different parameter grid, and for local execution.
-
-A **Jobs.tfs** file is created in the working directory containing the Job Id, parameter per job
-and job directory for further post processing.
-
-*--Required--*
-
-- **mask** *(str)*: Script Mask to use
-
-- **replace_dict** *(DictAsString)*: Dict containing the str to replace as
-  keys and values a list of parameters to replace
-
-- **working_directory** *(str)*: Directory where data should be put
-
-
-*--Optional--*
-
-- **append_jobs**: Flag to rerun job with finer/wider grid,
-  already existing points will not be reexecuted.
-
-  Action: ``store_true``
-- **check_files** *(str)*: List of files/file-name-masks expected to be in the
-  'job_output_dir' after a successful job (for appending/resuming). Uses the 'glob'
-  function, so unix-wildcards (*) are allowed. If not given, only the presence of the folder itself is checked.
-- **dryrun**: Flag to only prepare folders and scripts,
-  but does not start madx/submit jobs.
-  Together with `resume_jobs` this can be use to check which jobs succeeded and which failed.
-
-  Action: ``store_true``
-- **executable** *(str)*: Path to executable or job-type (of ['madx', 'python3', 'python2']) to use.
-
-- **htc_arguments** *(DictAsString)*: Additional arguments for htcondor, as Dict-String.
-  For AccountingGroup please use 'accounting_group'. 'max_retries' and 'notification' have defaults (if not given).
-  Others are just passed on.
-
-  Default: ``{}``
-- **job_output_dir** *(str)*: The name of the output dir of the job. (Make sure your script puts its data there!)
-
-  Default: ``Outputdata``
-- **jobflavour** *(str)*: Jobflavour to give rough estimate of runtime of one job
-
-  Choices: ``('espresso', 'microcentury', 'longlunch', 'workday', 'tomorrow', 'testmatch', 'nextweek')``
-  Default: ``workday``
-- **jobid_mask** *(str)*: Mask to name jobs from replace_dict
-
-- **num_processes** *(int)*: Number of processes to be used if run locally
-
-  Default: ``4``
-- **resume_jobs**: Only do jobs that did not work.
-
-  Action: ``store_true``
-- **run_local**: Flag to run the jobs on the local machine. Not suggested.
-
-  Action: ``store_true``
-- **script_arguments** *(DictAsString)*: Additional arguments to pass to the script,
-  as dict in key-value pairs ('--' need to be included in the keys).
-
-  Default: ``{}``
-- **script_extension** *(str)*: New extension for the scripts created from the masks.
-  This is inferred automatically for ['madx', 'python3', 'python2']. Otherwise not changed.
-
-- **ssh** *(str)*: Run htcondor from this machine via ssh (needs access to the `working_directory`)
-
-
-:author: mihofer, jdilly
-"""
-import itertools
-import multiprocessing
-import subprocess
-import sys
-from collections import OrderedDict
-from collections.abc import Iterable
-from functools import partial
-from pathlib import Path
-
-import numpy as np
-import pandas as pd
-import tfs
-from generic_parser import EntryPointParameters, entrypoint
-from generic_parser.entry_datatypes import DictAsString
-from generic_parser.tools import print_dict_tree
-from omc3.utils import logging_tools
-from omc3.utils.iotools import PathOrStr, save_config
-
-import pylhc.htc.utils as htcutils
-from pylhc.htc.mask import (
-    create_jobs_from_mask,
-    generate_jobdf_index,
-    find_named_variables_in_mask,
-    check_percentage_signs_in_mask
-)
-from pylhc.htc.utils import (
-    COLUMN_JOB_DIRECTORY,
-    COLUMN_SHELL_SCRIPT,
-    EXECUTEABLEPATH,
-    HTCONDOR_JOBLIMIT,
-    JOBFLAVOURS,
-)
-
-JOBSUMMARY_FILE = "Jobs.tfs"
-JOBDIRECTORY_PREFIX = "Job"
-COLUMN_JOBID = "JobId"
-CONFIG_FILE = "config.ini"
-
-SCRIPT_EXTENSIONS = {
-    "madx": ".madx",
-    "python3": ".py",
-    "python2": ".py",
-}
-
-LOG = logging_tools.get_logger(__name__)
-
-try:
-    import htcondor
-    HAS_HTCONDOR = True
-except ImportError:
-    platform = "macOS" if sys.platform == "darwin" else "windows"
-    LOG.error(f"htcondor python bindings are linux-only, this module is not callable on {platform}")
-    HAS_HTCONDOR = False
-
-
-def get_params():
-    params = EntryPointParameters()
-    params.add_parameter(
-        name="mask",
-        type=PathOrStr,
-        required=True,
-        help="Program mask to use",
-    )
-    params.add_parameter(
-        name="working_directory",
-        type=PathOrStr,
-        required=True,
-        help="Directory where data should be put",
-    )
-    params.add_parameter(
-        name="executable",
-        default="madx",
-        type=PathOrStr,
-        help=("Path to executable or job-type "
-              f"(of {str(list(EXECUTEABLEPATH.keys()))}) to use."),
-    )
-    params.add_parameter(
-        name="jobflavour",
-        type=str,
-        choices=JOBFLAVOURS,
-        default="workday",
-        help="Jobflavour to give rough estimate of runtime of one job ",
-    )
-    params.add_parameter(
-        name="run_local",
-        action="store_true",
-        help="Flag to run the jobs on the local machine. Not suggested.",
-    )
-    params.add_parameter(
-        name="resume_jobs", action="store_true", help="Only do jobs that did not work.",
-    )
-    params.add_parameter(
-        name="append_jobs",
-        action="store_true",
-        help=(
-            "Flag to rerun job with finer/wider grid, already existing points will not be "
-            "reexecuted."
-        ),
-    )
-    params.add_parameter(
-        name="dryrun",
-        action="store_true",
-        help="Flag to only prepare folders and scripts, but does not start madx/submit jobs. "
-        "Together with `resume_jobs` this can be use to check which jobs "
-        "succeeded and which failed.",
-    )
-    params.add_parameter(
-        name="replace_dict",
-        help=(
-            "Dict containing the str to replace as keys and values a list of parameters to "
-            "replace"
-        ),
-        type=DictAsString,
-        required=True,
-    )
-    params.add_parameter(
-        name="script_arguments",
-        help="Additional arguments to pass to the script, as dict in key-value pairs "
-        "('--' need to be included in the keys).",
-        type=DictAsString,
-        default={},
-    )
-    params.add_parameter(
-        name="script_extension",
-        help="New extension for the scripts created from the masks. This is inferred "
-        f"automatically for {str(list(SCRIPT_EXTENSIONS.keys()))}. Otherwise not changed.",
-        type=str,
-    )
-    params.add_parameter(
-        name="num_processes",
-        help="Number of processes to be used if run locally",
-        type=int,
-        default=4,
-    )
-    params.add_parameter(
-        name="check_files",
-        help=(
-            "List of files/file-name-masks expected to be in the "
-            "'job_output_dir' after a successful job "
-            "(for appending/resuming). Uses the 'glob' function, so "
-            "unix-wildcards (*) are allowed. If not given, only the "
-            "presence of the folder itself is checked."
-        ),
-        type=str,
-        nargs="+",
-    )
-    params.add_parameter(
-        name="jobid_mask", help="Mask to name jobs from replace_dict", type=str,
-    )
-    params.add_parameter(
-        name="job_output_dir",
-        help="The name of the output dir of the job. (Make sure your script puts its data there!)",
-        type=str,
-        default="Outputdata",
-    )
-    params.add_parameter(
-        name="htc_arguments",
-        help="Additional arguments for htcondor, as Dict-String. "
-        "For AccountingGroup please use 'accounting_group'. "
-        "'max_retries' and 'notification' have defaults (if not given). "
-        "Others are just passed on. ",
-        type=DictAsString,
-        default={},
-    )
-    params.add_parameter(
-        name="ssh",
-        help="Run htcondor from this machine via ssh (needs access to the `working_directory`)",
-        type=str,
-    )
-
-    return params
-
-
-@entrypoint(get_params(), strict=True)
-def main(opt):
-    if not opt.run_local:
-        LOG.info("Starting HTCondor Job-submitter.")
-        _check_htcondor_presence()
-    else:
-        LOG.info("Starting Job-submitter.")
-
-    opt = _check_opts(opt)
-    save_config(opt.working_directory, opt, __file__)
-
-    job_df = _create_jobs(
-        opt.working_directory,
-        opt.mask,
-        opt.jobid_mask,
-        opt.replace_dict,
-        opt.job_output_dir,
-        opt.append_jobs,
-        opt.executable,
-        opt.script_arguments,
-        opt.script_extension,
-    )
-    job_df, dropped_jobs = _drop_already_run_jobs(
-        job_df, opt.resume_jobs or opt.append_jobs, opt.job_output_dir, opt.check_files
-    )
-
-    if opt.dryrun:
-        _print_stats(job_df.index, dropped_jobs)
-    elif opt.run_local:
-        _run_local(job_df, opt.num_processes)
-    else:
-        _run_htc(
-            job_df,
-            opt.working_directory,
-            opt.job_output_dir,
-            opt.jobflavour,
-            opt.ssh,
-            opt.htc_arguments,
-        )
-
-
-# Main Functions ---------------------------------------------------------------
-
-
-def _create_jobs(
-    cwd,
-    maskfile,
-    jobid_mask,
-    replace_dict,
-    output_dir,
-    append_jobs,
-    executable,
-    script_args,
-    script_extension,
-):
-    LOG.debug("Creating Jobs")
-    values_grid = np.array(list(itertools.product(*replace_dict.values())), dtype=object)
-
-    if append_jobs:
-        jobfile_path = cwd / JOBSUMMARY_FILE
-        try:
-            job_df = tfs.read(str(jobfile_path.absolute()), index=COLUMN_JOBID)
-        except FileNotFoundError:
-            raise FileNotFoundError(
-                "Cannot append jobs, as no previous jobfile was found at " f"'{jobfile_path}'"
-            )
-        mask = [elem not in job_df[replace_dict.keys()].values for elem in values_grid]
-        njobs = mask.count(True)
-        values_grid = values_grid[mask]
-
-    else:
-        njobs = len(values_grid)
-        job_df = tfs.TfsDataFrame()
-
-    if njobs == 0:
-        raise ValueError(f"No (new) jobs found!")
-    if njobs > HTCONDOR_JOBLIMIT:
-        raise ValueError(f"Too many jobs! Allowed {HTCONDOR_JOBLIMIT}, given {njobs}.")
-
-    LOG.debug(f"Initial number of jobs: {njobs:d}")
-
-    data_df = pd.DataFrame(
-        index=generate_jobdf_index(job_df, jobid_mask, replace_dict.keys(), values_grid),
-        columns=list(replace_dict.keys()),
-        data=values_grid,
-    )
-    job_df = job_df.append(data_df, sort=False)
-
-    job_df = _setup_folders(job_df, cwd)
-
-    # creating all madx jobs
-    script_extension = _get_script_extension(script_extension, executable, maskfile)
-    job_df = create_jobs_from_mask(
-        job_df, maskfile, replace_dict.keys(), script_extension
-    )
-
-    # creating all shell scripts
-    job_df = htcutils.write_bash(
-        job_df, output_dir, executable=executable, cmdline_arguments=script_args
-    )
-
-    job_df[COLUMN_JOB_DIRECTORY] = job_df[COLUMN_JOB_DIRECTORY].apply(str)
-    job_df = _set_auto_tfs_column_types(job_df)
-    tfs.write(str(cwd / JOBSUMMARY_FILE), job_df, save_index=COLUMN_JOBID)
-    return job_df
-
-
-def _drop_already_run_jobs(job_df, drop_jobs, output_dir, check_files):
-    LOG.debug("Dropping already finished jobs, if necessary.")
-    finished_jobs = []
-    if drop_jobs:
-        finished_jobs = [
-            idx
-            for idx, row in job_df.iterrows()
-            if _job_was_successful(row, output_dir, check_files)
-        ]
-        LOG.info(
-            f"{len(finished_jobs):d} of {len(job_df.index):d}"
-            " Jobs have already finished and will be skipped."
-        )
-        job_df = job_df.drop(index=finished_jobs)
-    return job_df, finished_jobs
-
-
-def _run_local(job_df, num_processes):
-    LOG.info(f"Running {len(job_df.index)} jobs locally in {num_processes:d} processes.")
-    pool = multiprocessing.Pool(processes=num_processes)
-    pool.map(_execute_shell, job_df.iterrows())
-
-
-def _run_htc(job_df, cwd, output_dir, flavour, ssh, additional_htc_arguments):
-    LOG.info(f"Submitting {len(job_df.index)} jobs on htcondor, flavour '{flavour}'.")
-    # create submission file
-    subfile = htcutils.make_subfile(
-        cwd, job_df, output_dir=output_dir, duration=flavour, **additional_htc_arguments
-    )
-    # submit to htcondor
-    htcutils.submit_jobfile(subfile, ssh)
-
-
-def _get_script_extension(script_extension, executable, mask):
-    if script_extension is not None:
-        return script_extension
-    return SCRIPT_EXTENSIONS.get(executable, mask.suffix)
-
-
-# Sub Functions ----------------------------------------------------------------
-
-
-def _check_htcondor_presence() -> None:
-    """Checks the ``HAS_HTCONDOR`` variable and raises EnvironmentError if it is ``False``."""
-    if not HAS_HTCONDOR:
-        raise EnvironmentError("htcondor bindings are necessary to run this module.")
-
-
-def _setup_folders(job_df, working_directory):
-    def _return_job_dir(job_id):
-        return working_directory / f"{JOBDIRECTORY_PREFIX}.{job_id}"
-
-    LOG.debug("Setting up folders: ")
-    job_df[COLUMN_JOB_DIRECTORY] = [_return_job_dir(id_) for id_ in job_df.index]
-
-    for job_dir in job_df[COLUMN_JOB_DIRECTORY]:
-        try:
-            job_dir.mkdir()
-        except IOError:
-            LOG.debug(f"   failed '{job_dir}' (might already exist).")
-        else:
-            LOG.debug(f"   created '{job_dir}'.")
-    return job_df
-
-
-def _job_was_successful(job_row, output_dir, files):
-    output_dir = Path(job_row[COLUMN_JOB_DIRECTORY], output_dir)
-    success = output_dir.is_dir()
-    if success and files is not None and len(files):
-        for f in files:
-            success &= len(list(output_dir.glob(f))) > 0
-    return success
-
-
-def _execute_shell(df_row):
-    idx, column = df_row
-    with Path(column[COLUMN_JOB_DIRECTORY], "log.tmp").open("w") as logfile:
-        process = subprocess.Popen(
-            ["sh", column[COLUMN_SHELL_SCRIPT]],
-            shell=False,
-            stdout=logfile,
-            stderr=subprocess.STDOUT,
-            cwd=column[COLUMN_JOB_DIRECTORY],
-        )
-
-    status = process.wait()
-    return status
-
-
-def _check_opts(opt):
-    LOG.debug("Checking options")
-    if opt.resume_jobs and opt.append_jobs:
-        raise ValueError("Select either Resume jobs or Append jobs")
-
-    # Paths ---
-    opt = keys_to_path(opt, 'mask', 'working_directory', 'executable')
-
-    if str(opt.executable) in EXECUTEABLEPATH.keys():
-        opt.executable = str(opt.executable)
-
-    with open(opt.mask, "r") as inputmask:  # checks that mask and dir are there
-        mask = inputmask.read()
-
-    # Replace dict ---
-    dict_keys = set(opt.replace_dict.keys())
-    mask_keys = find_named_variables_in_mask(mask)
-    not_in_mask = dict_keys - mask_keys
-    not_in_dict = mask_keys - dict_keys
-
-    if len(not_in_dict):
-        raise KeyError(
-            "The following keys in the mask were not found in the given replace_dict: "
-            f"{str(not_in_dict).strip('{}')}"
-        )
-
-    if len(not_in_mask):
-        LOG.warning(
-            "The following replace_dict keys were not found in the given mask: "
-            f"{str(not_in_mask).strip('{}')}"
-        )
-
-        # remove all keys which are not present in mask (otherwise unnecessary jobs)
-        [opt.replace_dict.pop(key) for key in not_in_mask]
-        if len(opt.replace_dict) == 0:
-            raise KeyError("Empty replace-dictionary")
-    check_percentage_signs_in_mask(mask)
-
-    print_dict_tree(opt, name="Input parameter", print_fun=LOG.debug)
-    opt.replace_dict = check_replace_dict(opt.replace_dict)
-
-    return opt
-
-
-def _print_stats(new_jobs, finished_jobs):
-    """Print some quick statistics."""
-    LOG.info("------------- QUICK STATS ----------------")
-    LOG.info(f"Jobs total:{len(new_jobs) + len(finished_jobs):d}")
-    LOG.info(f"Jobs to run: {len(new_jobs):d}")
-    LOG.info(f"Jobs already finished: {len(finished_jobs):d}")
-    LOG.info("---------- JOBS TO RUN NAMES -------------")
-    for job_name in new_jobs:
-        LOG.info(job_name)
-    LOG.info("--------- JOBS FINISHED NAMES ------------")
-    for job_name in finished_jobs:
-        LOG.info(job_name)
-
-
-def _set_auto_tfs_column_types(df):
-    return df.apply(partial(pd.to_numeric, errors="ignore"))
-
-
-# Other ------------------------------------------------------------------------
-
-
-def check_replace_dict(replace_dict: dict) -> OrderedDict:
-    """ Makes all entries in replace-dict iterable. """
-    for key, value in replace_dict.items():
-        if isinstance(value, str) or not isinstance(value, Iterable):
-            replace_dict[key] = [value]
-    return OrderedDict(replace_dict)  # for python 3.6
-
-
-def keys_to_path(dict_, *keys):
-    """ Convert all keys to Path """
-    for key in keys:
-        dict_[key] = Path(dict_[key])
-    return dict_
-
-
-# Script Mode ------------------------------------------------------------------
-
-
-if __name__ == "__main__":
-    main()
diff --git a/pylhc/sixdesk_tools/__init__.py b/pylhc/sixdesk_tools/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/pylhc/sixdesk_tools/create_workspace.py b/pylhc/sixdesk_tools/create_workspace.py
deleted file mode 100644
index f682483..0000000
--- a/pylhc/sixdesk_tools/create_workspace.py
+++ /dev/null
@@ -1,214 +0,0 @@
-"""
-Create SixDesk Workspace
------------------------------------
-
-Tools to setup the workspace for sixdesk.
-"""
-import shutil
-from pathlib import Path
-
-import numpy as np
-from omc3.utils import logging_tools
-
-from pylhc.constants.autosix import (
-    SETENV_SH,
-    SIXENV_DEFAULT,
-    SIXENV_REQUIRED,
-    SEED_KEYS,
-    get_workspace_path,
-    get_scratch_path,
-    get_sixjobs_path,
-    get_masks_path,
-    get_mad6t_mask_path,
-    get_mad6t1_mask_path,
-    get_autosix_results_path,
-    get_sysenv_path,
-    get_sixdeskenv_path,
-)
-from pylhc.sixdesk_tools.utils import start_subprocess
-
-SYSENV_MASK = Path(__file__).parent / "mask_sysenv"
-SIXDESKENV_MASK = Path(__file__).parent / "mask_sixdeskenv"
-
-LOG = logging_tools.get_logger(__name__)
-
-
-# Main -------------------------------------------------------------------------
-
-
-def create_job(jobname: str, basedir: Path, mask_text: str, binary_path: Path, ssh: str = None, **kwargs):
-    """ Create environment and individual jobs/masks for SixDesk to send to HTC. """
-    _create_workspace(jobname, basedir, ssh=ssh)
-    _create_sysenv(jobname, basedir, binary_path=binary_path)
-    _create_sixdeskenv(jobname, basedir, **kwargs)
-    _write_mask(jobname, basedir, mask_text, **kwargs)
-    LOG.info("Workspace prepared.")
-
-
-def init_workspace(jobname: str, basedir: Path, ssh: str = None):
-    """ Initializes the workspace with sixdeskenv and sysenv. """
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    start_subprocess([SETENV_SH, "-s"], cwd=sixjobs_path, ssh=ssh)
-    LOG.info("Workspace initialized.")
-
-
-def remove_twiss_fail_check(jobname: str, basedir: Path):
-    """ Comments out the "Twiss fail" check from mad6t.sh """
-    LOG.info("Applying twiss-fail hack.")
-    for mad6t_path in (
-        get_mad6t_mask_path(jobname, basedir),
-        get_mad6t1_mask_path(jobname, basedir),
-    ):
-        with open(mad6t_path, "r") as f:
-            lines = f.readlines()
-
-        check_started = False
-        for idx, line in enumerate(lines):
-            if line.startswith('grep -i "TWISS fail"'):
-                check_started = True
-
-            if check_started:
-                lines[idx] = f"# {line}"
-                if line.startswith("fi"):
-                    break
-        else:
-            LOG.info(f"'TWISS fail' not found in {mad6t_path.name}")
-            continue
-
-        with open(mad6t_path, "w") as f:
-            f.writelines(lines)
-
-
-def fix_pythonfile_call(jobname: str, basedir: Path):
-    """ Removes '<' in the `binary file` line in mad6t.sh so __file__ works. """
-    LOG.info("Applying python-file call fix.")
-    for mad6t_path in (
-            get_mad6t_mask_path(jobname, basedir),
-            get_mad6t1_mask_path(jobname, basedir),
-    ):
-        with open(mad6t_path, "r") as f:
-            lines = f.readlines()
-
-        for idx, line in enumerate(lines):
-            if line.startswith('$MADX_PATH/$MADX'):
-                lines[idx] = f'$MADX_PATH/$MADX $junktmp/$filejob."$i" > $filejob.out."$i"\n'
-                break
-        else:
-            raise IOError(f"'$MADX_PATH/$MADX' line not found in {mad6t_path.name}")
-
-        with open(mad6t_path, "w") as f:
-            f.writelines(lines)
-
-# Helper -----------------------------------------------------------------------
-
-
-def _create_workspace(jobname: str, basedir: Path, ssh: str = None):
-    """ Create workspace structure (with default files). """
-    workspace_path = get_workspace_path(jobname, basedir)
-    scratch_path = get_scratch_path(basedir)
-    LOG.info(f'Creating new workspace in "{str(workspace_path)}"')
-
-    if workspace_path.exists():
-        LOG.warning(f'Workspace in "{str(workspace_path)}" already exists. ')
-        LOG.info("Do you want to delete the old workspace? [y/N]")
-        user_answer = input()
-        if user_answer.lower().startswith("y"):
-            shutil.rmtree(workspace_path)
-            try:
-                shutil.rmtree(scratch_path)
-            except FileNotFoundError:
-                pass
-        else:
-            LOG.warning("Keeping Workspace as-is.")
-            return
-
-    scratch_path.mkdir(parents=True, exist_ok=True)
-
-    # create environment with all necessary files
-    # _start_subprocess(['git', 'clone', GIT_REPO, basedir])
-    start_subprocess([SETENV_SH, "-N", workspace_path.name], cwd=basedir, ssh=ssh)
-
-    # create autosix results folder.
-    # Needs to be done after above command (as it crashes if folder exists)
-    # but before end of this stage (as it needs to write the stagefile)
-    get_autosix_results_path(jobname, basedir).mkdir(exist_ok=True, parents=True)
-
-
-def _create_sixdeskenv(jobname: str, basedir: Path, **kwargs):
-    """ Fills sixdeskenv mask and copies it to workspace """
-    workspace_path = get_workspace_path(jobname, basedir)
-    scratch_path = get_scratch_path(basedir)
-    sixdeskenv_path = get_sixdeskenv_path(jobname, basedir)
-
-    missing = [key for key in SIXENV_REQUIRED if key not in kwargs.keys()]
-    if len(missing):
-        raise ValueError(f"The following keys are required but missing {missing}.")
-
-    sixenv_replace = SIXENV_DEFAULT.copy()
-    sixenv_replace.update(kwargs)
-    sixenv_replace.update(
-        dict(
-            JOBNAME=jobname,
-            WORKSPACE=workspace_path.name,
-            BASEDIR=str(basedir),
-            SCRATCHDIR=str(scratch_path),
-            TURNSPOWER=np.log10(sixenv_replace["TURNS"]),
-        )
-    )
-
-    if any(sixenv_replace[key] is None for key in SEED_KEYS):
-        for key in SEED_KEYS:
-            sixenv_replace[key] = 0
-
-    # the following checks are limits of SixDesk in 2020
-    # and might be fixed upstream in the future
-    if sixenv_replace["AMPMAX"] < sixenv_replace["AMPMIN"]:
-        raise ValueError("Given AMPMAX is smaller than AMPMIN.")
-
-    if (sixenv_replace["AMPMAX"] - sixenv_replace["AMPMIN"]) % sixenv_replace["AMPSTEP"]:
-        raise ValueError("The amplitude range need to be dividable by the amplitude steps!")
-
-    if not sixenv_replace["ANGLES"] % 2:
-        raise ValueError("The number of angles needs to be an uneven one.")
-
-    sixenv_text = SIXDESKENV_MASK.read_text()
-    sixdeskenv_path.write_text(sixenv_text % sixenv_replace)
-    LOG.debug("sixdeskenv written.")
-
-
-def _create_sysenv(jobname: str, basedir: Path, binary_path: Path):
-    """ Fills sysenv mask and copies it to workspace """
-    LOG.info(f"Chosen binary for mask '{str(binary_path)}'")
-    sysenv_path = get_sysenv_path(jobname, basedir)
-    sysenv_replace = dict(
-        MADXPATH=str(binary_path.parent),
-        MADXBIN=binary_path.name,
-    )
-    sysenv_text = SYSENV_MASK.read_text()
-    sysenv_path.write_text(sysenv_text % sysenv_replace)
-    LOG.debug("sysenv written.")
-
-
-def _write_mask(jobname: str, basedir: Path, mask_text: str, **kwargs):
-    """ Fills mask with arguments and writes it out. """
-    masks_path = get_masks_path(jobname, basedir)
-    seed_range = [kwargs.get(key, SIXENV_DEFAULT[key]) for key in SEED_KEYS]
-
-    if seed_range.count(None) == 1:
-        raise ValueError(
-            "First- or Lastseed is set, but the other one is deactivated. " "Set or unset both."
-        )
-
-    if ("%SEEDRAN" not in mask_text) and ("%SEEDRAN" not in kwargs.values()) and any(seed_range):
-        raise ValueError(
-            "First- and Lastseed are set, but no seed-variable '%SEEDRAN' found in mask."
-        )
-
-    mask_text = mask_text.replace("%SEEDRAN", "#!#SEEDRAN")  # otherwise next line will complain
-    mask_filled = mask_text % kwargs
-    mask_filled = mask_filled.replace(
-        "#!#SEEDRAN", "%SEEDRAN"
-    )  # bring seedran back for sixdesk seed-loop
-
-    with open(masks_path / f"{jobname}.mask", "w") as mask_out:
-        mask_out.write(mask_filled)
diff --git a/pylhc/sixdesk_tools/mask_sixdeskenv b/pylhc/sixdesk_tools/mask_sixdeskenv
deleted file mode 100644
index 35a8802..0000000
--- a/pylhc/sixdesk_tools/mask_sixdeskenv
+++ /dev/null
@@ -1,311 +0,0 @@
-#!/bin/bash
-# July 1st, 2012.
-# Better message handling, fewer locks on the database by
-# relying on the study lock, faster run_post???
-# February 29, 2012 using new defaults
-# Tested with job_tracking collision
-# NOTA BENE: there is a new option for a more precise proton mass
-# and also a new flag to ignore tunes (tune=0)
-# and a new bunch_charge option for both collision and injection
-# March 25th, 2017
-# synchronising with new scripts
-
-export pmass=938.272013
-# or you can use the older value
-# by uncommenting the next line
-# export pmass=938.271998
-
-# New bunch_charge variable for fort.3.mother1_[col/inj]
-export bunch_charge=1.1500e+11
-
-# The name of the "study" .le. 16 characters ([a-z A-Z 0-9 + - _ . ,]
-# It must NOT contain a "percent-sign" (replacing "#") nor "_""_"
-# It now includes the Version info e.g. v64lhc
-# (If running mad6t you must have a $LHCDescrip.mask file in the subdirectory mask)
-export LHCDescrip=%(JOBNAME)s
-
-# The workspace for the scripts, sixdesk.log and links to sixtrack_input, track and work, 
-# It must NOT contain a "percent-sign" (replacing "#") nor "__" (two consecutive underscores)
-export workspace=%(WORKSPACE)s
-
-# The directory for the workspace normally $HOME
-initial=`echo $LOGNAME | cut -c 1`
-export basedir=%(BASEDIR)s
-
-# The scratch directory for temporary input files, jobs, sixdesk databases etc (not normally backed up)
-export scratchdir=%(SCRATCHDIR)s
-
-# The root track directory for all the tracking input and output
-# This directory can be used by multiple workspaces for scalability
-# but the default now includes the workspace name (track is added
-# by sysenv to make $sixdesktrackdir and the LHCDescrip is added
-# as necessary by run_six etc etc).
-export trackdir=$scratchdir/$workspace
-
-# The backed up or scratch directory for the mad6t input
-# It may be set to an existing sixtrack_input if you do not need to run mad6t.
-export sixtrack_input=$scratchdir/sixtrack_input/$workspace/$LHCDescrip
-
-# Flag for run_six for re-running cases
-# 0 => Jobs will not be re-submitted, 
-# 1 => Jobs will not be re-submitted if fort.10.gz exists
-# 2 => Jobs will be re-submitted anyway using existing input files
-export sixdeskforce=%(RESUBMISSION)d
-
-# One and one only of the following options must be selected
-# BOINC for LHC@home, LSF for LSF batch, CPSS for Windows desktops at CERN, GRID or HTCondor
-export platform=%(PLATFORM)s
-
-# The message logging level: 0 => basic and error messages, 1 => plus info,
-# >= 2 => + plus info and debug
-export sixdesklevel=%(LOGLEVEL)s
-
-# sixdeskecho = "" => only minimum information is echoed to stdout
-export sixdeskecho="yes please"
-
-# Options for run_mad6t (but sixtrack_inputdir defined above)
-# If CORR_TEST = 1, check_mad6t will copy all the corrector strengths
-# for each seed into one file in sixtrack_inputdir
-export CORR_TEST=0
-
-#If fort_34 is null, the fort.34 files will not be copied to sixtrack_inputdir
-export fort_34=""
-
-# Start and end seed for mad6t
-export istamad=%(FIRSTSEED)d
-export iendmad=%(LASTSEED)d
-
-# Note that all mad6t runs are with the local LSF batch system,
-# even if tracking is being performed on BOINC, CPSS or the GRID,
-# BUT they can now be done interactively with run_mad6t -i !!!
-
-# And set BIGNBLZ to be non-null to use the special bignblz SixTrack
-# available only for LSF and NOT BOINC.
-export BIGNBLZ=""
-
-# LSF batch queue for mad6t jobs. Normally 8nm is enough, but for
-# lhc.D1-D2-MQonly-inj-no-skew study 1nh was necessary.
-export madlsfq=8nh
-export shortlsfq=8nh
-export longlsfq=1nd
-export dalsfq=1nd
-# equivalent queues for htcondor
-export madHTCq=tomorrow
-export shortHTCq=workday
-export longHTCq=testmatch
-export daHTCq=testmatch
-
-# Format: "col" or "inj" ( also for run_six)
-export runtype="%(ENERGY)s"
-# and the beam can be set to "" or b1 or B1 for beam1, or to b2 or B2 for beam2
-# and "_b1" or "_b2" is appended to the mask filename
-export beam=""
-
-# Options for run_six
-# idfor = 0 => closed orbit added, = 1 => initial co-ordinates unchanged
-export idfor=0
-
-#The algorithm for beam-beam interactions 
-# 0 is the "old" way, "1" is the new Erskine/McIntosh algorithm
-export ibtype=0
-
-#general parameters
-# No of particle pairs, normally 30 (other values ARE NOW SUPPORTED
-# in the range 1 to 32
-export sixdeskpairs=%(NPAIRS)d
-
-# seeds for everything except mad6t
-export ista=$istamad
-export iend=$iendmad
-
-# angle step
-export kstep=1
-
-#normalized emittance
-export emit=%(EMITTANCE)f
-export emit_beam=$emit
-
-# Crossing angle for substitution in mask and mother file
-# uncomment it, to make it operational
-# export xing=185
-
-# e0 gamma
-if test $runtype = "inj"
-then
-  export e0=450000.
-  export gamma=479.6
-elif test $runtype = "col"
-then
-  export e0=6500000.
-  export gamma=6927.6
-fi
-
-#phase space dimension
-export dimen=%(DIMENSIONS)d
-
-#switch for chromaticity correction
-# If chrom=0 no correction is applied but two one turn runs are made
-# using chrom_eps to generate sensible values (for info only).
-# If chrom=1 then chromx and chromy are used
-export chrom=0
-export chromx=2.0
-export chromy=2.0
-export chrom_eps=0.0000001
-
-#initial relative momentum deviation
-if test $runtype = "inj"
-then
-  export dpini=0.00075
-elif test $runtype = "col"
-then
-  export dpini=0.00027
-fi
-export dpmax=0.002
-
-#tunes
-# If tune=0, the tunes are ignored.
-export tune=0
-
-# Multiple tunescans can be specified 
-# tunescans will be computed on a straight line from 
-# (tunex,tuney) with gradient deltay/deltax until and including (tunex1,tuney1)
-# The tunes must be 10 <= tune < 100 in format dd.dd[d][d]
-if test $runtype = "inj"
-then
-  #tunes (injection)
-  export tunex=64.282
-  export tuney=59.312
-  export deltax=0.001
-  export deltay=0.001
-  export tunex1=64.282
-  export tuney1=59.312
-elif test $runtype = "col"
-then
-  #tunes (collision)
-  export tunex=62.31
-  export tuney=60.32
-  export deltax=0.001
-  export deltay=0.001
-  export tunex1=62.31
-  export tuney1=60.32
-fi
-# switch for tune scans on a squared domain
-# uncomment it, to make it operational
-# export squaredTuneScan=yes
-
-#switch for Guignard resonance calculation
-export reson=0
-
-#switch for precise tune determination
-export sussix=0
-# Note if sussix = 1, short must be 1 (long/da 0)
-
-# Now we have short or long term parameters
-# only one of short and long may be 1
-#short term parameters
-export short=0
-if test $short -eq 1
-then
-  export ns1s=1
-  export ns2s=10
-  export nss=10
-  #
-  export turnss=1000
-  export turnsse=3
-  export writebins=1
-  # kini=0 is the momemtum detuning and then set to 1
-  export kini=0
-  export kend=5
-  export kmax=5
-  # and set up the LSF job type and queue
-  export lsfq=$shortlsfq
-  export HTCq=$shortHTCq
-  export lsfjobtype=sixmedium
-fi
- 
-#long term parameters
-export long=1
-if test $long -eq 1
-then
-# amplitudes which must be 0 <= amplitude < 100 in format [d][d][.][d][d][d]
-  export ns1l=%(AMPMIN).3f
-  export ns2l=%(AMPMAX).3f
-  export nsincl=%(AMPSTEP).3f
-  #
-  export turnsl=%(TURNS)d
-  export turnsle=%(TURNSPOWER)d
-  export writebinl=%(WRITEBINS)d
-  export kinil=1
-  export kendl=%(ANGLES)d
-  export kmaxl=%(ANGLES)d
-          # and set up the LSF job type and queue
-  export lsfq=$longlsfq
-  export HTCq=$longHTCq
-  export lsfjobtype=sixtracking
-
-  # reduce angle steps at small angles, achieving a constant density painting of the phase space
-  # export reduce_angs_with_amplitude=10
-fi  
-
-#da parameters 
-
-export da=0
-if test $da -eq 1
-then
-  export sixdeskM="-M 1000000"
-  export lsfq=$dalsfq
-  export HTCq=$daHTCq
-  export lsfjobtype=sixda
-# some physics needed here
-# dimda = 4 or 6 but MUST be set to NOT null for short/long
-  export dimda=4
-  export NO=4
-  ((NO1=NO+1))
-  export NO1
-  export NV=5
-  export turnss=1
-else
-  export dimda=0 
-fi
-
-# Parameters for run_join10
-# Range of tracked turns
-if test $short = 1
-then
-  export turnsemax=$turnsse
-fi
-if test $long = 1
-then
-  export turnsemax=$turnsle
-fi
-
-# For run_post
-if test $long = 1
-then
-  export turnse=$turnsle
-fi
-if test $short = 1
-then
-  export turnse=$turnsse
-fi
-
-# flag for short and long plotting
-# iplot=1 produces plots for each seed 
-# iplot=2 prints as well using $PRINT_CMD
-export iplot=0
-
-# kvar=0 => kend=$kendl, kvar=1 => kend=$kinil
-# kvar should be set to 1 to obtain the DA
-# as a function of the angles (when long=1)
-# The DA over ALL seeds and angles is plotted for each angle
-# even if iplot=0
-if test "$long" -eq 1
-then
-  export kvar=1
-else
-  export kvar=0
-fi
-# BNL variables for bnlelens 
-# Later I could separate out elens and bnl dependencies in sixtrack.s
-# as we may wish to run LHC elens studies
-export BNL=""
diff --git a/pylhc/sixdesk_tools/mask_sysenv b/pylhc/sixdesk_tools/mask_sysenv
deleted file mode 100644
index 7a375b9..0000000
--- a/pylhc/sixdesk_tools/mask_sysenv
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/bin/bash
-# February 29, 2012
-# All the variables the user will not normally want to see!
-# March 25th, 2017
-# synchronising with new scripts + appname
-#
-# app name, used by any platform
-export appName=sixtrack
-# 
-
-# # The path to all scripts etc bin,Bin,scripts, exes, dots
-# export sixdeskpath=/afs/cern.ch/group/si/slap/bin/sixdesk
-# # The following SixTrack version is used for the one-turn
-# # SixTrack run to get the Beta values and for all LSF tasks (except DA)
-# # and the BNL EXE which is the same I hope
-# export SIXTRACKEXE=$sixdeskpath/exes/$appName
-# if test "$BIGNBLZ" != ""
-# then
-#   export SIXTRACKEXE=$sixdeskpath/exes/SixTrack_bignblz_pro
-# fi
-# export SIXTRACKBNLEXE=$sixdeskpath/exes/SixTrack_bnl_pro
-# # Latest DA version from
-# export SIXTRACKDAEXE=$sixdeskpath/exes/SixTrack_crlibm_da_lf95v4200
-
-# The following version of mad-X is used by the mad6t jobs.
-# All now call a madx executable so -X is no longer required.
-export MADX_PATH="%(MADXPATH)s"
-# Doesn't seem to work!
-#export MADX="madx_pro"
-# and the MUST? use for Massimo
-#export MADX="madx_dev"
-# and the new default
-export MADX="%(MADXBIN)s"
-
-export sixdeskplatform=`echo "$platform" | tr '[A-Z]' '[a-z]'`
-
-# Turn ON/OFF CASTOR........... true or false 
-export sixdeskcastor="true"
-#
-if test "$BNL" != ""
-then
-  export sixdeskbnlin="fort.54"
-  export bnlfilenames="beambeam-output.dat beambeamlostID.dat SixTwiss.dat checkdist.dat"
-  export bnlfortnames="fort.52 fort.53 fort.51 fort.97"
-  if test "$sixdeskplatform" = "boinc"
-  then
-    export sixdeskbnlout="fort.10"
-  elif test "$sixdeskplatform" = "cpss"
-  then
-    export sixdeskbnlout=$bnlfortnames
-  elif test "$sixdeskplatform" = "lsf"
-  then
-    export sixdeskbnlout=$bnlfilenames
-  else
-    echo "UNKNOWN sixdeskplatform $sixdeskplatform"
-    exit 1
-  fi
-fi
-
-# Not really needed anymore but must be non-zero!
-export sixdeskcr=1 
-
-export LHCDesName=$LHCDescrip
-export LHCDesHome=$LHCDescrip
-
-export sixdeskhome=$basedir/$workspace/sixjobs
-export sixdesklogs=$scratchdir/sixdesklogs/$workspace
-export sixdesklogdir=$sixdesklogs/$LHCDescrip
-export cronlogs=$scratchdir/cronlogs/$workspace
-export cronlogdir=$cronlogs/$LHCDescrip
-
-export sixdesktrack=$trackdir/track
-
-export sixdeskwork=$scratchdir/work/$workspace/$LHCDescrip
-
-export sixdeskjobs=$sixdeskwork/$sixdeskplatform"jobs"
-export sixdeskjobs_logs=$sixdeskjobs/jobs_logs
-
-export sixdeskstudy=$sixdeskhome/studies/$LHCDescrip
-
-# For BOINC 
-# The SixTrack executable is now ????.
-# export sixdeskpts=boinc:users
-# export boincdir=/afs/cern.ch/user/b/boinc/scratch0
-# export sixdeskboincdirname=$workspace"_"$LHCDescrip
-# # and use boinctest (for Igor and new BOINC release)
-# export sixdeskboinctest=false
-# sixdeskboincdir=$boincdir/boinc/$sixdeskboincdirname
-# if ${sixdeskboinctest} ; then
-#   sixdeskboincdir=$boincdir/boinctest/$sixdeskboincdirname
-# fi
-# export sixdeskboincdir
-export sixdeskparts=`expr $sixdeskpairs \* 2`
-if test "$short" -eq 1 -o "$da" -eq 1
-then
-  sixdeskturns=$turnss
-fi
-if test "$long" -eq 1
-then
-  sixdeskturns=$turnsl
-fi
-if test "$BNL" != ""
-then
-  sixdeskturns=$bnlturns
-fi
-export sixdeskturns
-sixdeskfpopse=`expr $sixdeskturns \* $sixdeskparts`
-#sixdeskfpopse=`expr $sixdeskfpopse \* 2`
-#sixdeskfpopse=`expr $sixdeskfpopse / 3`
-sixdeskfpopse=`expr $sixdeskfpopse / 2`
-#sixdeskfpopse=`expr $sixdeskfpopse \* 3`
-export sixdeskfpopse=$sixdeskfpopse"000000"
-# For CPSS
-# sixdeskprog/uploadProgram Variables
-# sixdeskProgramName, sixdeskFileName, sixdeskTargetFileName
-# sixdeskVersion, sixdeskAuthor, sixdeskDescription
-export sixdeskexec="$sixdeskpath/exes/SixTrack_4411_crlibm_bnl_ifort_icpss.exe"
-export sixdeskOsMin="5.0"
-export sixdeskOsMax="9.9"
-export sixdeskCpuSpeedMin="100"
-export sixdeskclientv=2.5
-export sixdeskProgramName="Sixtrack V4211 Tilt Lost CRLIBM CR BNL"
-export sixdeskFileName="$sixdeskexec"
-export sixdeskTargetFileName="sixtrack.exe"
-export sixdeskVersion="4.2.11 BNL"
-export sixdeskAuthor="Frank Schmidt & Eric McIntosh"
-export sixdeskProgramDescription="Lahey 7.1 Sixtrack[CR] with crlibm made fom .s"
-# sixdeskgroup/createTaskGroup Variables
-# sixdeskTaskGroupName, sixdeskTaskGroupDescription,
-# sixdeskStatus, sixdeskPriority, sixdeskComments
-export sixdeskTaskGroupName=$LOGNAME"_"$workspace"_"$LHCDescrip
-export sixdeskTaskGroupDescription=$workspace"_"$LHCDescrip
-export sixdeskStatus="Active"
-export sixdeskPriority="Normal"
-export sixdeskComments="$LHCDescrip"
diff --git a/pylhc/sixdesk_tools/post_process_da.py b/pylhc/sixdesk_tools/post_process_da.py
deleted file mode 100644
index edffc2b..0000000
--- a/pylhc/sixdesk_tools/post_process_da.py
+++ /dev/null
@@ -1,349 +0,0 @@
-"""
-Post Process DA
-----------------------------------
-
-Tools to process data after sixdb has calculated the
-da. Includes functions for extracting data from database
-as well as plotting of DA polar plots.
-"""
-import sqlite3 as sql
-from pathlib import Path
-from typing import Any, Tuple, Iterable, Union
-
-import numpy as np
-import pandas as pd
-from generic_parser import DotDict
-from matplotlib import pyplot as plt
-from matplotlib import rcParams, lines as mlines
-from omc3.plotting.utils import style as pstyle
-from omc3.utils import logging_tools
-from pylhc.constants.autosix import (
-    get_database_path,
-    get_tfs_da_path,
-    get_tfs_da_seed_stats_path,
-    get_tfs_da_angle_stats_path,
-    get_autosix_results_path,
-    HEADER_NTOTAL,
-    HEADER_INFO,
-    HEADER_HINT,
-    MEAN,
-    STD,
-    MIN,
-    MAX,
-    N,
-    SEED,
-    ANGLE,
-    ALOST1,
-    ALOST2,
-    AMP,
-)
-from scipy.interpolate import interp1d
-from tfs import TfsDataFrame, write_tfs
-
-from pylhc.sixdesk_tools.utils import StageSkip
-
-LOG = logging_tools.get_logger(__name__)
-
-DA_COLUMNS = (ALOST1, ALOST2)
-INFO = (
-    "Statistics over the N={n:d} {over:s} per {per:s}. "
-    "The N-Columns indicate how many non-zero DA values were used."
-)
-HINT = "{param:s} {val:} is the respective value calculated over all other {param:s}s."
-OVER_WHICH = {SEED: "angles", ANGLE: "seeds"}
-
-# Fixed plot styles ---
-COLOR_MEAN = "red"
-COLOR_SEED = "grey"
-COLOR_LIM = "black"
-COLOR_FILL = "blue"
-ALPHA_SEED = 0.5
-ALPHA_FILL = 0.2
-ALPHA_FILL_STD = 0.2
-
-
-def post_process_da(jobname: str, basedir: Path):
-    """ Post process the DA results into dataframes and DA plots. """
-    LOG.info("Post-Processing Sixdesk Results.")
-    try:
-        df_da, df_angle, df_seed = create_da_tfs(jobname, basedir)
-        create_polar_plots(jobname, basedir, df_da, df_angle)
-    except Exception as e:
-        LOG.exception("Post Processing Failed.")
-        raise StageSkip("Post Processing failed!") from e
-    LOG.info("Post-Processing finished.")
-
-
-# Data Analysis ----------------------------------------------------------------
-
-
-def create_da_tfs(jobname: str, basedir: Path) -> Tuple[TfsDataFrame, TfsDataFrame, TfsDataFrame]:
-    """ Extracts data from db into dataframes, and writes and returns them."""
-    LOG.info("Gathering DA data into tfs-files.")
-    df_da = extract_da_data_from_db(jobname, basedir)
-
-    df_angle = _create_stats_df(df_da, ANGLE)
-    df_seed = _create_stats_df(df_da, SEED, global_index=0)
-
-    try:
-        write_tfs(get_tfs_da_path(jobname, basedir), df_da)
-        write_tfs(get_tfs_da_angle_stats_path(jobname, basedir), df_angle, save_index=ANGLE)
-        write_tfs(get_tfs_da_seed_stats_path(jobname, basedir), df_seed, save_index=SEED)
-    except OSError:  # TODO remove
-        da_path = get_tfs_da_path(jobname, basedir)
-        angle_path = get_tfs_da_angle_stats_path(jobname, basedir)
-        seed_path = get_tfs_da_seed_stats_path(jobname, basedir)
-        write_tfs(da_path.with_name(da_path.name.replace("-by-", "-")), df_da)
-        write_tfs(angle_path.with_name(angle_path.name.replace("-by-", "-")), df_angle, save_index=ANGLE)
-        write_tfs(seed_path.with_name(seed_path.name.replace("-by-", "-")), df_seed, save_index=SEED)
-
-    return df_da, df_angle, df_seed
-
-
-def extract_da_data_from_db(jobname: str, basedir: Path) -> TfsDataFrame:
-    """ Extract data directly from the database. """
-    db_path = get_database_path(jobname, basedir)
-    db = sql.connect(db_path)
-    df_da = pd.read_sql(
-        "SELECT seed, angle, alost1, alost2, Amin, Amax FROM da_post ORDER BY seed, angle", db
-    )
-    df_da = df_da.rename(
-        columns={
-            "seed": SEED,
-            "angle": ANGLE,
-            "alost1": ALOST1,
-            "alost2": ALOST2,
-            "Amin": f"{MIN}{AMP}",
-            "Amax": f"{MAX}{AMP}",
-        }
-    )
-    return TfsDataFrame(df_da)
-
-
-def _create_stats_df(df: TfsDataFrame, parameter: str, global_index: Any = None):
-    """ Calculates the stats over a given parameter """
-    operation_map = DotDict({MEAN: np.mean, STD: np.std, MIN: np.min, MAX: np.max})
-
-    pre_index = [] if global_index is None else [global_index]
-    index = sorted(set(df[parameter]))
-    n_total = sum(df[parameter] == index[0])
-
-    df_stats = TfsDataFrame(
-        index=pre_index + index,
-        columns=[f"{fun}{al}" for al in DA_COLUMNS for fun in list(operation_map.keys()) + [N]],
-    )
-    df_stats.headers[HEADER_INFO] = INFO.format(
-        over=OVER_WHICH[parameter], per=parameter.lower(), n=n_total
-    )
-    df_stats.headers[HEADER_NTOTAL] = n_total
-
-    for col_da in DA_COLUMNS:
-        for idx in index:
-            mask = (df[parameter] == idx) & (df[col_da] != 0)
-            df_stats.loc[idx, f"{N}{col_da}"] = sum(mask)
-            for name, operation in operation_map.items():
-                df_stats.loc[idx, f"{name}{col_da}"] = operation(df.loc[mask, col_da])
-            for name, operation in operation_map.get_subdict([MIN, MAX]).items():
-                df_stats.loc[idx, f"{name}{AMP}"] = operation(df.loc[mask, f"{name}{AMP}"])
-
-        if global_index is not None:
-            df_stats.loc[global_index, f"{N}{col_da}"] = sum(df_stats.loc[index, f"{N}{col_da}"])
-            for name, operation in operation_map.items():
-                df_stats.loc[global_index, f"{name}{col_da}"] = operation(
-                    df_stats.loc[index, f"{name}{col_da}"]
-                )
-            for name, operation in operation_map.get_subdict([MIN, MAX]).items():
-                df_stats.loc[global_index, f"{name}{AMP}"] = operation(
-                    df_stats.loc[index, f"{name}{AMP}"]
-                )
-            df_stats.headers[HEADER_HINT] = HINT.format(param=parameter, val=global_index)
-
-    return df_stats
-
-
-# Single Plots -----------------------------------------------------------------
-
-
-def create_polar_plots(jobname: str, basedir: Path, df_da: TfsDataFrame, df_angles: TfsDataFrame):
-    """ Plotting loop over da-methods and wrapper so save plots. """
-    LOG.info("Creating Polar Plots.")
-    outdir_path = get_autosix_results_path(jobname, basedir)
-    for da_col in DA_COLUMNS:
-        fig = plot_polar(df_angles, da_col, jobname, df_da)
-        fig.tight_layout(), fig.tight_layout()
-        try:  # TODO  remove
-            fig.savefig(outdir_path / fig.canvas.get_default_filename())
-        except OSError:
-            fig.savefig(outdir_path / fig.canvas.get_default_filename().replace("-by-", "-"))
-
-    # plt.show()
-
-
-def plot_polar(
-    df_angles: TfsDataFrame,
-    da_col: str = ALOST2,
-    jobname: str = "",
-    df_da: TfsDataFrame = None,
-    **kwargs,
-) -> plt.Figure:
-    """Create Polar Plot for DA analysis data.
-
-    Keyword arguments are all optional.
-
-    Args:
-        df_angles (TfsDataFrame): Dataframe with the statistics (min, max, mean) per angle
-        da_col (str): DA-Column name from sixdesk analysis to be used , e.g. ``ALOST2``.
-                      (optional, default: ``ALOST2``)
-        jobname (str): Name of the job. Used in window title only (optional).
-        df_da (TfsDataFrame): Full DA analysis result. If given, plots
-                              the individual DA results per seed. (optional)
-
-    Keyword Arguments:
-        plot_styles (Iterable[str]): Iterable over plots styles to be applied, default: 'standard'
-        interpolated (bool): If true, uses interpolation to plot the lines curved
-        fill (bool): If true, fills the area between min and max with light blue
-        angle_ticks (Iterable[numeric]): Positions in degree of the angle ticks (and lines)
-        amplitude ticks (Iterable[numeric]): Positions of the amplitude ticks.
-        remaining args: any rcParams to be set.
-
-    Returns:
-        Figure of the polar plot.
-    """
-    interpolated: bool = kwargs.pop("interpolated", True)
-    fill: bool = kwargs.pop("fill", df_da is None)
-    angle_ticks: Iterable[np.numeric] = kwargs.pop("angle_ticks", None)
-    amplitude_ticks: Iterable[np.numeric] = kwargs.pop("amplitude_ticks", None)
-    plot_styles: Iterable[Union[Path, str]] = kwargs.pop("plot_styles", "standard")
-
-    if "lines.marker" not in kwargs:
-        kwargs["lines.marker"] = "None"
-    pstyle.set_style(plot_styles, kwargs)
-    fig, ax = plt.subplots(nrows=1, ncols=1, subplot_kw={"projection": "polar"})
-    fig.canvas.set_window_title(f"{jobname} polar plot for {da_col}")
-
-    angles = np.deg2rad(df_angles.index)
-    da_min, da_mean, da_max, da_std = (
-        df_angles[f"{name}{da_col}"] for name in (MIN, MEAN, MAX, STD)
-    )
-
-    seed_h, seed_l = _plot_seeds(ax, df_da, da_col, interpolated)
-    if interpolated:
-        mean_h, max_h = _plot_interpolated(ax, angles, da_min, da_mean, da_max, da_std, fill)
-    else:
-        mean_h, max_h = _plot_straight(ax, angles, da_min, da_mean, da_max, da_std, fill)
-
-    ax.set_thetamin(0)
-    ax.set_thetamax(90)
-    ax.set_rlim([0, None])
-    ax.set_xlabel(r"$\sigma_{x}~[\sigma_{nominal}]$", labelpad=15)
-    ax.set_ylabel(r"$\sigma_{y}~[\sigma_{nominal}]$", labelpad=20)
-
-    if angle_ticks is not None:
-        ax.set_xticks(np.deg2rad(angle_ticks))
-
-    if amplitude_ticks is not None:
-        ax.set_yticks(amplitude_ticks)
-    ax.tick_params(labelright=True, labelleft=True)
-
-    ax.legend(
-        loc="upper right",
-        bbox_to_anchor=(0.9, 0.95),
-        bbox_transform=fig.transFigure,
-        # frameon=False,
-        handles=seed_h + [mean_h, max_h],
-        labels=seed_l + ["Mean DA", "Limits"],
-        ncol=1,
-    )
-
-    return fig
-
-
-def _plot_seeds(ax, df_da, da_col, interpolated):
-    """Add the Seed lines to the polar plots, if df_da is given."""
-    if df_da is not None:
-        seed_h = None
-        for seed in sorted(set(df_da[SEED])):
-            seed_mask = df_da[SEED] == seed
-            angles = np.deg2rad(df_da.loc[seed_mask, ANGLE])
-            da_data = df_da.loc[seed_mask, da_col]
-            da_data.loc[da_data == 0] = np.NaN
-            if interpolated:
-                seed_h, _, _ = _interpolated_line(
-                    ax,
-                    angles,
-                    da_data,
-                    c=COLOR_SEED,
-                    ls="-",
-                    label=f"Seed {seed:d}",
-                    alpha=ALPHA_SEED,
-                )
-            else:
-                (seed_h,) = ax.plot(
-                    angles, da_data, c=COLOR_SEED, ls="-", label=f"Seed {seed:d}", alpha=ALPHA_SEED
-                )
-        return [seed_h], ["DA per Seed"]
-    return [], []
-
-
-def _plot_interpolated(ax, angles, da_min, da_mean, da_max, da_std, fill):
-    """Plot interpolated DA lines and areas."""
-    _, _, ip_min = _interpolated_line(ax, angles, da_min, c=COLOR_LIM, ls="--", label="Minimum DA")
-    max_h, ip_x, ip_max = _interpolated_line(
-        ax, angles, da_max, c=COLOR_LIM, ls="--", label="Maximum DA"
-    )
-    if fill:
-        ax.fill_between(ip_x, ip_min, ip_max, color=COLOR_FILL, alpha=ALPHA_FILL)
-        _, ip_std_min = _interpolated_coords(angles, da_mean - da_std)
-        _, ip_std_max = _interpolated_coords(angles, da_mean + da_std)
-        ax.fill_between(ip_x, ip_std_min, ip_std_max, color=COLOR_FILL, alpha=ALPHA_FILL_STD)
-
-    mean_h, _, _ = _interpolated_line(ax, angles, da_mean, c=COLOR_MEAN, ls="-", label="Mean DA")
-    return mean_h, max_h
-
-
-def _plot_straight(ax, angles, da_min, da_mean, da_max, da_std, fill):
-    """Plot straight DA lines and areas."""
-    (_,) = ax.plot(angles, da_min, c=COLOR_LIM, ls="--", label="Minimum DA")
-    (max_h,) = ax.plot(angles, da_max, c=COLOR_LIM, ls="--", label="Maximum DA")
-    if fill:
-        ax.fill_between(
-            angles,
-            da_min.astype(float),
-            da_max.astype(float),  # weird conversion to obj otherwise
-            color=COLOR_FILL,
-            alpha=ALPHA_FILL,
-        )
-        ax.fill_between(
-            angles,
-            (da_mean - da_std).astype(float),
-            (da_mean + da_std).astype(float),
-            color=COLOR_FILL,
-            alpha=ALPHA_FILL_STD,
-        )
-    (mean_h,) = ax.plot(angles, da_mean, c=COLOR_MEAN, ls="-", label="Mean DA")
-    return mean_h, max_h
-
-
-def _interpolated_line(ax, x, y, npoints: int = 100, **kwargs):
-    """Plot a line that interpolates linearly between points.
-    Useful for polar plots with sparse points."""
-    ls = kwargs.pop("linestyle", kwargs.pop("ls", rcParams["lines.linestyle"]))
-    marker = kwargs.pop("marker", rcParams["lines.marker"])
-    label = kwargs.pop("label")
-
-    ip_x, ip_y = _interpolated_coords(x, y, npoints)
-    (line_h,) = ax.plot(ip_x, ip_y, marker="None", ls=ls, label=f"_{label}_line", **kwargs)
-
-    if marker.lower() not in ["none", ""]:
-        ax.plot(x, y, ls="None", marker=marker, label=f"_{label}_markers", **kwargs)
-
-    # fake handle for legend
-    handle = mlines.Line2D([], [], color=line_h.get_color(), ls=ls, marker=marker, label=label)
-    return handle, ip_x, ip_y
-
-
-def _interpolated_coords(x, y, npoints: int = 100):
-    """ Do linear interpolation between points. """
-    ip_x = np.linspace(min(x), max(x), npoints)
-    ip_y = interp1d(x, y)(ip_x)
-    return ip_x, ip_y
diff --git a/pylhc/sixdesk_tools/submit.py b/pylhc/sixdesk_tools/submit.py
deleted file mode 100644
index 4a03cb8..0000000
--- a/pylhc/sixdesk_tools/submit.py
+++ /dev/null
@@ -1,119 +0,0 @@
-"""
-SixDesk Submission Utils
----------------------------
-
-Individual functions to call SixDesk functionality.
-"""
-from pathlib import Path
-from typing import Union
-
-from omc3.utils import logging_tools
-
-from pylhc.sixdesk_tools.utils import start_subprocess, StageSkip
-from pylhc.constants.autosix import (
-    MAD_TO_SIXTRACK_SH,
-    RUNSIX_SH,
-    RUNSTATUS_SH,
-    SIXDB,
-    get_sixjobs_path,
-)
-
-LOG = logging_tools.get_logger(__name__)
-
-
-def submit_mask(jobname: str, basedir: Path, ssh: str = None):
-    """ Run the mask (probably Madx) and generate sixtrack input files. """
-    LOG.info("Submitting mask to run for sixtrack input generation.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    start_subprocess([MAD_TO_SIXTRACK_SH, "-s"], cwd=sixjobs_path, ssh=ssh)
-    LOG.info("Submitted mask-jobs.")
-
-
-def check_sixtrack_input(jobname: str, basedir: Path, ssh: str = None, resubmit: bool = False):
-    """ Checks the generated input files needed by sixtrack and resubmits, if requested. """
-    LOG.info("Checking if input files are present.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    try:
-        start_subprocess([MAD_TO_SIXTRACK_SH, "-c"], cwd=sixjobs_path, ssh=ssh)
-    except OSError as e:
-        if resubmit:
-            LOG.info("Resubmitting mask to run wrong seeds for sixtrack input generation.")
-            start_subprocess([MAD_TO_SIXTRACK_SH, "-w"], cwd=sixjobs_path, ssh=ssh)
-            raise StageSkip("Resubmitted input generation jobs "
-                            "(Not really an error, but the run is now interrupted).")
-        else:
-            raise StageSkip(
-                "Checking input files failed. Check (debug-) logs. "
-                "Maybe restart with 'resubmit' flag."
-            ) from e
-    else:
-        LOG.info("Check for input files was successful.")
-
-
-def submit_sixtrack(jobname: str, basedir: Path, python: Path = None, ssh: str = None, resubmit: bool = False):
-    """ Generate simulation files and check if runnable and submit. """
-    re_str = "Re-" if resubmit else ""
-    LOG.info(f"{re_str}Submitting to sixtrack.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    args = ["-i"] if resubmit else ["-a"]
-    if python is not None:
-        if not python.is_dir():
-            python = python.parent
-        args += ["-P", str(python)]
-    try:
-        start_subprocess([RUNSIX_SH] + args, cwd=sixjobs_path, ssh=ssh, check_log='exit status: 1')
-    except OSError as e:
-        raise StageSkip(
-            f"{re_str}Submit to sixtrack for {jobname} ended in error."
-            f" Input generation possibly not finished. Check your Scheduler."
-        ) from e
-    else:
-        LOG.info(f"{re_str}Submitted jobs to Sixtrack")
-
-
-def check_sixtrack_output(jobname: str, basedir: Path, python: Union[Path, str], ssh: str = None, resubmit: bool = False):
-    """ Checks if the sixtrack output is all there. """
-    LOG.info("Checking if sixtrack has finished.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    try:
-        start_subprocess([RUNSTATUS_SH], cwd=sixjobs_path, ssh=ssh)
-    except OSError as e:
-        if resubmit:
-            submit_sixtrack(jobname, basedir, python=python, ssh=ssh, resubmit=True)
-            raise StageSkip(
-                f"Sixtrack for {jobname} seems to be incomplete."
-                " Resubmitted incomplete sixtrack jobs."
-                " Wait until they have finished and run again."
-            )
-        else:
-            raise StageSkip(
-                f"Sixtrack for {jobname} seems to be incomplete."
-                f" Run possibly not finished. Check (debug-) log or your Scheduler."
-            ) from e
-    else:
-        LOG.info("Sixtrack results are all present.")
-
-
-def sixdb_load(jobname: str, basedir: Path, python: Union[Path, str], ssh: str = None):
-    """ Creates sixdb database and loads the study results into it. """
-    LOG.info("Loading study into database.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    try:
-        start_subprocess([python, SIXDB, ".", "load_dir"], cwd=sixjobs_path, ssh=ssh)
-    except OSError as e:
-        raise StageSkip(f"Sixdb loading for {jobname} failed. Check (debug-) log.") from e
-    else:
-        LOG.info("Created database for study.")
-
-
-def sixdb_cmd(jobname: str, basedir: Path, python: Union[Path, str], cmd: list, ssh: str = None):
-    """ Performs analysis on the sixdb database. """
-    cmd_str = " ".join(cmd)
-    LOG.info(f"Performing sixdb command `{cmd_str}`.")
-    sixjobs_path = get_sixjobs_path(jobname, basedir)
-    try:
-        start_subprocess([python, SIXDB, jobname] + cmd, cwd=sixjobs_path, ssh=ssh)
-    except OSError as e:
-        raise StageSkip(f"SixBD command {cmd_str} for {jobname} failed. Check (debug-) log.") from e
-    else:
-        LOG.info(f"SixDB command '{cmd_str}' successfully run.")
diff --git a/pylhc/sixdesk_tools/troubleshooting.py b/pylhc/sixdesk_tools/troubleshooting.py
deleted file mode 100644
index 0960c59..0000000
--- a/pylhc/sixdesk_tools/troubleshooting.py
+++ /dev/null
@@ -1,232 +0,0 @@
-"""
-SixDesk Troubleshooting tools
------------------------------
-
-Some useful functions to troubleshoot the SixDesk output.
-"""
-from pathlib import Path
-
-from omc3.utils import logging_tools
-
-from pylhc.autosix import get_jobs_and_values
-from pylhc.constants.autosix import (get_stagefile_path, Stage, get_track_path,
-                                     get_workspace_path, SIXTRACK_INPUT_CHECK_FILES,
-                                     SIXTRACK_OUTPUT_FILES, get_database_path)
-
-LOG = logging_tools.get_logger(__name__)
-
-
-# Stages -----------------------------------------------------------------------
-
-def get_last_stage(jobname, basedir):
-    """ Get the last run stage of job `jobname`. """
-    stage_file = get_stagefile_path(jobname, basedir)
-    last_stage = Stage[stage_file.read_text().strip('\n').split('\n')[-1]]
-    return last_stage
-
-
-# Set Stages ---
-
-def set_stages_for_setup(basedir: Path, stage_name: str, jobid_mask: str, replace_dict: dict):
-    """ Sets the last run stage for all jobs from given job-setups. """
-    jobs, _ = get_jobs_and_values(jobid_mask, **replace_dict)
-    for job in jobs:
-        LOG.info(f"Setting stage to {stage_name} in {jobname}")
-        set_stages(job, basedir, stage_name)
-
-
-def set_stages(jobname: str, basedir: Path, stage_name: str):
-    """ Sets the last run stage of all given jobs to `stage_name`. """
-    if stage_name not in Stage.__members__:
-        raise ValueError(f"Unknown stage '{stage_name}'")
-
-    stage_file = get_stagefile_path(jobname, basedir)
-    if stage_file.exists():
-        stage_file.unlink()
-    for stage in Stage:
-        with open(stage_file, "a+") as f:
-            f.write(f"{stage.name}\n")
-
-        if stage.name == stage_name:
-            break
-
-
-def skip_stages(jobname: str, basedir: Path, stage_name: str):
-    """ Skip stages until `stagename`, i.e. similar to `set_stages` but only if
-    the stage hasn't been reached yet. Inverse to `reset_stages`"""
-    if stage_name not in Stage.__members__:
-        raise ValueError(f"Unknown stage '{stage_name}'")
-
-    new_stage = Stage[stage_name]
-    last_stage = get_last_stage(jobname, basedir)
-    if last_stage < new_stage:
-        LOG.info(f"Skipping stage form {last_stage.name} to {new_stage.name} in {jobname}")
-        set_stages(jobname, basedir, stage_name)
-    else:
-        LOG.debug(f"Stage {last_stage.name} unchanged in {jobname}")
-
-
-def reset_stages(jobname: str, basedir: Path, stagename: str):
-    """ Reset stages until `stagename`, i.e. similar to `set_stages` but only if
-    the stage has already been run. Inverse to `skip_stages`"""
-    if stage_name not in Stage.__members__:
-        raise ValueError(f"Unknown stage '{stage_name}'")
-
-    new_stage = Stage[stage_name]
-    last_stage = get_last_stage(jobname, basedir)
-    if last_stage > new_stage:
-        LOG.info(f"Resetting stage from {last_stage.name} to {new_stage.name} in {jobname}")
-        set_stages(jobname, basedir, stage_name)
-    else:
-        LOG.debug(f"Stage {last_stage.name} unchanged in {jobname}")
-
-
-# Check Stages ---
-
-def check_stages_for_setup(basedir: Path, stage_name: str, jobid_mask: str, replace_dict: dict):
-    """ Check the last run stage for all jobs from given job-setups. """
-    jobs, _ = get_jobs_and_values(jobid_mask, **replace_dict)
-    for job in jobs:
-        check_last_stage(job, basedir)
-
-
-def check_last_stage(jobname: str, basedir: Path):
-    """ Logs names of all last run stages for given jobs. """
-    last_stage = get_last_stage(jobname, basedir)
-    LOG.info(f"'{jobname}' at stage '{last_stage.name}'")
-
-
-# Complete check for failure ---------------------------------------------------
-
-def find_obviously_failed_sixtrack_submissions(basedir: Path):
-    """ Checks in jobs in `track` whether the directory structure seems to be created
-    and if there is output data. This checks only the first directories found,
-    to speed up this process. For a more precise scan see check_sixtrack_output_data.
-    """
-    jobs = []
-    for job in get_all_jobs_in_base(basedir):
-        try:
-            LOG.debug(str(job))
-            track = get_track_path(jobname=job, basedir=basedir)
-            first_seed = get_first_dir(track) / 'simul'
-            tunes = get_first_dir(first_seed)
-            amp = get_first_dir(tunes, '*_*')
-            turns = get_first_dir(amp, 'e*')
-            angle = get_first_dir(turns, ".*")
-
-            file_names = [f.name for f in angle.glob("*")]
-            out_files_present = [f for f in SIXTRACK_OUTPUT_FILES if f in file_names]
-            if not len(out_files_present):
-                raise OSError(str(get_workspace_path(jobname=job, basedir=basedir)))
-        except OSError as e:
-            LOG.error(f"{e.args[0]} (stage: {get_last_stage(jobname=job, basedir=basedir).name})")
-            jobs.append(str(job))
-    return jobs
-
-
-def check_sixtrack_output_data(jobname: str, basedir: Path):
-    """ Presence checks for SixDesk tracking output data.
-
-    This checks recursively all directories in `track`.
-    Will be busy for a while.
-    """
-    track_path = get_track_path(jobname, basedir)
-    seed_dirs = list(track_path.glob("[0-9]")) + list(track_path.glob("[0-9][0-9]"))
-    if not len(seed_dirs):
-        raise OSError(f"No seed-dirs present in {str(track_path)}.")
-
-    for seed_dir in seed_dirs:
-        if not seed_dir.is_dir():
-            continue
-
-        simul_path = seed_dir / 'simul'
-        tunes_dirs = list(simul_path.glob("*"))
-        if not len(tunes_dirs):
-            raise OSError(f"No tunes-dirs present in {str(seed_dir)}.")
-
-        for tunes_dir in tunes_dirs:
-            if not tunes_dir.is_dir():
-                continue
-
-            amp_dirs = list(tunes_dir.glob("*_*"))
-            if not len(amp_dirs):
-                raise OSError(f"No amplitude-dirs present in {str(tunes_dir)}.")
-
-            for amp_dir in amp_dirs:
-                if not amp_dir.is_dir():
-                    continue
-
-                turns_dirs = list(amp_dir.glob('*'))
-                if not len(turns_dirs):
-                    raise OSError(f"No turns-dirs present in {str(amp_dir)}.")
-
-                for turn_dir in turns_dirs:
-                    if not turn_dir.is_dir():
-                        continue
-
-                    angle_dirs = list(turn_dir.glob('.*'))
-                    if not len(angle_dirs):
-                        raise OSError(f"No angle-dirs present in {str(turn_dir)}.")
-
-                    for angle_dir in angle_dirs:
-                        if not angle_dir.is_dir():
-                            continue
-
-                        htcondor_files = list(angle_dir.glob("htcondor.*"))
-                        if len(htcondor_files) != 3:
-                            raise OSError(f"Not all htcondor files present in {str(angle_dir)}.")
-
-                        file_names = [f.name for f in angle_dir.glob("*")]
-                        in_files_present = [f for f in SIXTRACK_INPUT_CHECK_FILES if f in file_names]
-                        if len(in_files_present):
-                            raise OSError(f"The files '{in_files_present}' are found in {str(angle_dir)},"
-                                          "yet they should have been deleted after tracking.")
-
-                        out_files_present = [f for f in SIXTRACK_OUTPUT_FILES if f in file_names]
-                        if not len(out_files_present):
-                            raise OSError(f"None of the expected output files '{SIXTRACK_OUTPUT_FILES}' "
-                                          f"are present in {str(angle_dir)}")
-
-# Long Database Names Hack -----------------------------------------------------
-
-
-def create_database_symlink(jobname: str, basedir: Path):
-    db_path = get_database_path(jobname, basedir)
-    if db_path.exists():
-        LOG.debug(f"Database already exists in {jobname}.")
-        return
-
-    real_db_path = db_path.parent / "my.db"
-    real_db_path.touch()
-
-    db_path.symlink_to(real_db_path)
-    LOG.info(f"Crated database link in {jobname}.")
-
-
-def move_database_symlink(jobname: str, basedir: Path):
-    db_path = get_database_path(jobname, basedir)
-    real_db_path = db_path.parent / "my.db"
-    if real_db_path.exists():
-        real_db_path.rename(db_path)
-        LOG.info(f"Renamed database to its proper name in {jobname}.")
-
-
-# Helper -----------------------------------------------------------------------
-
-def for_all_jobs(func: callable, basedir: Path, *args, **kwargs):
-    """ Do function for all jobs in basedir. """
-    for job in get_all_jobs_in_base(basedir):
-        func(job, basedir, *args, **kwargs)
-
-
-def get_all_jobs_in_base(basedir):
-    """ Returns all job-names in the sixdeskbase dir. """
-    return [f.name.replace('workspace-', '') for f in basedir.glob("workspace-*")]
-
-
-def get_first_dir(cwd: Path, glob: str = "*"):
-    """ Return first directory of pattern `glob`. """
-    for d in cwd.glob(glob):
-        if d.is_dir():
-            return d
-    raise OSError(str(cwd))
diff --git a/pylhc/sixdesk_tools/utils.py b/pylhc/sixdesk_tools/utils.py
deleted file mode 100644
index 725bd88..0000000
--- a/pylhc/sixdesk_tools/utils.py
+++ /dev/null
@@ -1,173 +0,0 @@
-"""
-SixDesk Utilities
---------------------
-
-Helper Utilities for Autosix.
-"""
-import subprocess
-from contextlib import contextmanager
-from pathlib import Path
-
-from omc3.utils import logging_tools
-
-from pylhc.constants.autosix import (
-    SIXDESKLOCKFILE,
-    Stage,
-    get_workspace_path,
-    get_stagefile_path,
-)
-from pylhc.constants.external_paths import SIXDESK_UTILS
-from pylhc.htc.mask import find_named_variables_in_mask
-
-LOG = logging_tools.get_logger(__name__)
-
-
-# Checks  ----------------------------------------------------------------------
-
-
-def check_mask(mask_text: str, replace_args: dict):
-    """ Checks validity/compatibility of the mask and replacement dict. """
-    dict_keys = set(replace_args.keys())
-    mask_keys = find_named_variables_in_mask(mask_text)
-    not_in_dict = mask_keys - dict_keys
-
-    if len(not_in_dict):
-        raise KeyError(
-            "The following keys in the mask were not found for replacement: "
-            f"{str(not_in_dict).strip('{}')}"
-        )
-
-
-# Stages -----------------------------------------------------------------------
-
-
-class StageSkip(Exception):
-    pass
-
-
-@contextmanager
-def check_stage(stage: Stage, jobname: str, basedir: Path, max_stage: Stage = None):
-    """ Wrapper for stage functions to add stage to stagefile. """
-    if not should_run_stage(stage, jobname, basedir, max_stage):
-        yield False
-    else:
-        try:
-            yield True
-        except StageSkip as e:
-            if str(e):
-                LOG.error(str(e))
-        else:
-            stage_done(stage, jobname, basedir)
-
-
-def stage_done(stage: Stage, jobname: str, basedir: Path):
-    """ Append current stage name to stagefile. """
-    stage_file = get_stagefile_path(jobname, basedir)
-    with open(stage_file, "a+") as f:
-        f.write(f"{stage.name}\n")
-
-
-def should_run_stage(stage: Stage, jobname: str, basedir: Path, max_stage: Stage = None):
-    """ Checks if the stage should be run. """
-    stage_file = get_stagefile_path(jobname, basedir)
-    if not stage_file.exists():
-        if stage.value == 0:
-            return True
-        else:
-            LOG.debug(f"Stage {stage} not run because previous stage(s) missing.")
-            return False
-
-    with open(stage_file, "r") as f:
-        stage_file_txt = f.read().split("\n")
-    run_stages = [line.strip() for line in stage_file_txt if line.strip()]
-
-    if stage.name in run_stages:
-        LOG.info(f"Stage {stage.name} has already been run. Skipping.")
-        return False
-
-    if stage.value == 0:
-        return True
-
-    # check if user requested a stop at a certain stage
-    if (max_stage is not None) and (stage > max_stage):
-        LOG.info(f"Stage {stage.name} would run after requested "
-                 f"maximum stage {max_stage.name}. Skipping.")
-        return False
-
-    # check if last run stage is also the stage before current stage in stage order
-    if run_stages[-1] == Stage(stage-1).name:
-        return True
-
-    LOG.debug(f"Stage {stage.name} not run because previous stage(s) missing.")
-    return False
-
-
-# Locks ------------------------------------------------------------------------
-
-
-def is_locked(jobname: str, basedir: Path, unlock: bool = False):
-    """ Checks for sixdesklock-files """
-    workspace_path = get_workspace_path(jobname, basedir)
-    locks = list(workspace_path.glob(f"**/{SIXDESKLOCKFILE}"))  # list() for repeated usage
-
-    if locks:
-        LOG.info("The following folders are locked:")
-        for lock in locks:
-            LOG.info(f"{str(lock.parent)}")
-
-            with open(lock, "r") as f:
-                txt = f.read()
-            txt = txt.replace(str(SIXDESK_UTILS), "$SIXUTILS").strip("\n")
-            if txt:
-                LOG.debug(f" -> locked by: {txt}")
-
-        if unlock:
-            for lock in locks:
-                LOG.debug(f"Removing lock {str(lock)}")
-                lock.unlink()
-            return False
-        return True
-    return False
-
-
-# Commandline ------------------------------------------------------------------
-
-
-def start_subprocess(command, cwd=None, ssh: str = None, check_log: str = None):
-    if isinstance(command, str):
-        command = [command]
-
-    # convert Paths
-    command = [str(c) if isinstance(c, Path) else c for c in command]
-
-    if ssh:
-        # Send command to remote machine
-        command = " ".join(command)
-        if cwd:
-            command = f'cd "{cwd}" && {command}'
-        LOG.debug(f"Executing command '{command}' on {ssh}")
-        process = subprocess.Popen(
-            ["ssh", ssh, command], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd,
-        )
-
-    else:
-        # Execute command locally
-        LOG.debug(f"Executing command '{' '.join(command)}'")
-        process = subprocess.Popen(
-            command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd
-        )
-
-    # Log output
-    for line in process.stdout:
-        decoded = line.decode("utf-8").strip()
-        if decoded:
-            LOG.debug(decoded)
-            if check_log is not None and check_log in decoded:
-                raise OSError(
-                    f"'{check_log}' found in last logging message. "
-                    "Something went wrong with the last command. Check (debug-)log."
-                )
-
-    # Wait for finish and check result
-    if process.wait() != 0:
-        raise OSError("Something went wrong with the last command. Check (debug-)log.")
diff --git a/setup.py b/setup.py
index 8fc5dbb..fc5dc7d 100644
--- a/setup.py
+++ b/setup.py
@@ -35,7 +35,6 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
     "matplotlib>=3.2.0",
     "pjlsa>=0.0.14",
     "pytimber>=2.8.0",
-    "htcondor>=8.9.2 ; sys_platform=='linux'",  # no bindings for macOS or windows on PyPI
     "tfs-pandas>=2.0",
     "generic-parser>=1.0.8",
     "parse>=1.15.0",
@@ -53,8 +52,6 @@ def about_package(init_posixpath: pathlib.Path) -> dict:
         "pytest-cov>=2.7",
         "pytest-regressions>=2.0.0",
         "pytest-mpl>=0.11",
-        "hypothesis>=5.0.0",
-        "attrs>=19.2.0",
     ],
     "doc": ["sphinx", "sphinx_rtd_theme"],
 }


Test patch:
diff --git a/tests/unit/test_autosix.py b/tests/unit/test_autosix.py
deleted file mode 100644
index 160d44e..0000000
--- a/tests/unit/test_autosix.py
+++ /dev/null
@@ -1,206 +0,0 @@
-import logging
-from pathlib import Path
-from unittest.mock import patch
-
-import tfs
-
-from pylhc.sixdesk_tools.create_workspace import remove_twiss_fail_check
-from pylhc.sixdesk_tools.post_process_da import plot_polar, plt
-from pylhc.autosix import _generate_jobs, setup_and_run
-from pylhc.constants.autosix import (
-    get_masks_path, get_autosix_results_path, get_sixdeskenv_path,
-    get_sysenv_path, get_stagefile_path, ANGLE, Stage, get_mad6t_mask_path, get_mad6t1_mask_path
-)
-
-STAGE_NAMES = [s.name for s in Stage]
-
-INPUTS = Path(__file__).parent.parent / 'inputs'
-DA_RESULTS_DIR = INPUTS / 'sixdesk_da_results'
-
-# log-texts to be changed if they change in `should_run_stage`
-ALREADY_RUN_LOG = "Stage {} has already been run."
-PREVIOUS_MISSING_LOG = "Stage {} not run because previous stage(s) missing."
-AFTER_MAXIMUM_LOG = "Stage {} would run after requested maximum stage {}."
-
-
-def test_create_job_matrix(tmp_path):
-    jobs_df = _generate_jobs(tmp_path, jobid_mask=None, 
-                             param0=[1, 2., 3],
-                             param1=[4],
-                             param2=["test", "some", "more"]
-                             )
-    
-    assert tmp_path in jobs_df.headers.values()
-    assert len(jobs_df.index) == 9
-    assert all(f"param{i}" in jobs_df.columns for i in range(3))
-    assert len(list(tmp_path.glob("*.tfs"))) == 1
-
-
-def test_create_workspace(tmp_path):
-    jobname="test_job"
-
-    mock_create, mock_submit = _create_subprocess_mocks(jobname, tmp_path)
-    with mock_create, mock_submit:
-        setup_and_run(jobname=jobname,
-                      basedir=tmp_path,
-                      mask_text="Just a mask %(PARAM1)s %(PARAM2)s %(BEAM)s",
-                      binary_path=Path('somethingcomplicated/pathomatic'),
-                      PARAM1=4,
-                      PARAM2="%SEEDRAN",
-                      BEAM=1,
-                      TURNS=10101,
-                      AMPMIN=2, AMPMAX=20, AMPSTEP=2,
-                      ANGLES=5,
-                      )
-
-        mask = next(get_masks_path(jobname, tmp_path).glob("*"))
-        assert mask.exists()
-
-        mask_text = mask.read_text()
-        assert "%SEEDRAN" in mask_text
-        assert "4" in mask_text
-        assert "1" in mask_text
-        assert "mask" in mask_text
-
-        sixdeskenv = get_sixdeskenv_path(jobname, tmp_path)
-        assert sixdeskenv.exists()
-
-        sixdeskenv_text = sixdeskenv.read_text()
-        assert "10101" in sixdeskenv_text
-
-        sysenv = get_sysenv_path(jobname, tmp_path)
-        assert sysenv.exists()
-
-        sysenv_text = sysenv.read_text()
-        assert "somethingcomplicated" in sysenv_text
-        assert "pathomatic" in sysenv_text
-
-        autosix_result = get_autosix_results_path(jobname, tmp_path)
-        assert autosix_result.exists()
-
-        stagefile = get_stagefile_path(jobname, tmp_path)
-        assert stagefile.exists()
-
-        stagefile_text = stagefile.read_text()
-        assert all(s in stagefile_text for s in STAGE_NAMES[:3])
-
-
-def test_create_workspace_stop_init(tmp_path):
-    jobname="test_job"
-
-    mock_create, mock_submit = _create_subprocess_mocks(jobname, tmp_path)
-    with mock_create, mock_submit:
-        setup_and_run(jobname=jobname,
-                      basedir=tmp_path,
-                      binary_path=Path('somethingcomplicated/pathomatic'),
-                      stop_workspace_init=True,
-                      mask_text="",
-                      TURNS=10101,
-                      AMPMIN=2, AMPMAX=20, AMPSTEP=2,
-                      ANGLES=5,
-                      FIRSTSEED=None, LASTSEED=None,
-                      )
-
-        stagefile = get_stagefile_path(jobname, tmp_path)
-        assert stagefile.exists()
-
-        stagefile_text = stagefile.read_text()
-        assert Stage.create_job.name in stagefile_text
-        assert Stage.initialize_workspace.name not in stagefile_text
-
-
-def test_skip_all_stages(tmp_path, caplog):
-    """ Skips all stages but the last one, which prints "All stages run". """
-    jobname = "test_job"
-
-    stagefile = get_stagefile_path(jobname, tmp_path)
-    stagefile.parent.mkdir(parents=True)
-    stagefile.write_text("\n".join(STAGE_NAMES[:-1]))
-    with caplog.at_level(logging.INFO):
-        setup_and_run(jobname, tmp_path)
-
-    assert all(ALREADY_RUN_LOG.format(s) in caplog.text for s in STAGE_NAMES[:-1])
-    assert "All stages run." in caplog.text
-
-
-def test_max_stage(tmp_path, caplog):
-    """ Skips all stages, first because they had already 'run',
-    the others because they come after `max_stage`. """
-    jobname = "test_job"
-    run_stages = STAGE_NAMES[:-2]  # ends at `-3`
-    max_stage = STAGE_NAMES[-3]
-    after_max_stages = STAGE_NAMES[-2:]
-
-    stagefile = get_stagefile_path(jobname, tmp_path)
-    stagefile.parent.mkdir(parents=True)
-    stagefile.write_text("\n".join(run_stages))
-    with caplog.at_level(logging.INFO):
-        setup_and_run(jobname, tmp_path, max_stage=max_stage)
-
-    assert all(ALREADY_RUN_LOG.format(s) in caplog.text for s in run_stages)
-    assert all(AFTER_MAXIMUM_LOG.format(s, max_stage) in caplog.text for s in after_max_stages)
-    assert not any(PREVIOUS_MISSING_LOG.format(s) in caplog.text for s in STAGE_NAMES)
-
-
-def test_polar_plot(tmp_path):
-    df_angles = tfs.read(DA_RESULTS_DIR / 'da_per_angle.tfs', index=ANGLE)
-    df_da = tfs.read(DA_RESULTS_DIR / 'da.tfs')
-    fig = plot_polar(df_angles=df_angles, df_da=df_da, interpolated=False, fill=True)
-    assert len(fig.axes) == 1
-    assert len(fig.axes[0].lines) == 63  # 60 Seeds, MEAN, MIN, MAX
-    # plt.show()
-
-
-def test_polar_plot_interpolated(tmp_path):
-    df_angles = tfs.read(DA_RESULTS_DIR / 'da_per_angle.tfs', index=ANGLE)
-    df_da = tfs.read(DA_RESULTS_DIR / 'da.tfs')
-    fig = plot_polar(df_angles=df_angles, df_da=df_da, interpolated=True, fill=False)
-    assert len(fig.axes) == 1
-    assert len(fig.axes[0].lines) == 63  # 60 Seeds, MEAN, MIN, MAX
-    # plt.show()
-
-
-def test_twissfail_removal(tmp_path):
-    jobname = "test_job"
-    mad6t, mad6t1 = _create_mad6t_files(jobname, tmp_path)
-    remove_twiss_fail_check(jobname, tmp_path)
-
-    for f in (mad6t, mad6t1):
-        mad6t_lines = f.read_text().split("\n")
-
-        assert all(l.startswith("#") for l in mad6t_lines[:-1])
-        assert mad6t_lines[-1].startswith("if")
-
-
-# Helper -----------------------------------------------------------------------
-
-
-def _create_subprocess_mocks(jobname, dirpath):
-    def subprocess_mock(*args, **kwargs):
-        dirpath.mkdir(exist_ok=True, parents=True)
-        get_masks_path(jobname, dirpath).mkdir(exist_ok=True, parents=True)
-
-    mock_crate = patch('pylhc.sixdesk_tools.create_workspace.start_subprocess', new=subprocess_mock)
-    mock_submit = patch('pylhc.sixdesk_tools.submit.start_subprocess', new=subprocess_mock)
-    return mock_crate, mock_submit
-
-
-def _create_mad6t_files(jobname, tmppath):
-    mad6t = get_mad6t_mask_path(jobname, tmppath)
-    mad6t1 = get_mad6t1_mask_path(jobname, tmppath)
-    mad6t.parent.mkdir(parents=True)
-    mad6t.write_text(_mad6t_text())
-    mad6t1.write_text(_mad6t_text())
-    return mad6t, mad6t1
-
-
-def _mad6t_text():
-    return """grep -i "TWISS fail" $filejob.out."$i" > /dev/null
-if test $? -eq 0
-then
-  touch $sixtrack_input/ERRORS
-  echo "MADX TWISS appears to have failed!"
-  echo "$filejob.out.${i} MADX TWISS appears to have failed!" >> $sixtrack_input/ERRORS
-  exit 2
-fi
-if test ! -s fc.2"""
diff --git a/tests/unit/test_job_submitter.py b/tests/unit/test_job_submitter.py
deleted file mode 100644
index de3b326..0000000
--- a/tests/unit/test_job_submitter.py
+++ /dev/null
@@ -1,129 +0,0 @@
-import sys
-from pathlib import Path
-
-import pytest
-from generic_parser import DotDict
-
-from pylhc.job_submitter import main as job_submit
-
-skip_not_linux = pytest.mark.skipif(
-    sys.platform != "linux", reason="htcondor python bindings from PyPI are only on linux"
-)
-
-skip_on_linux = pytest.mark.skipif(
-    sys.platform == "linux", reason="htcondor python bindings are present"
-)
-
-
-@skip_not_linux
-def test_job_creation_and_localrun(tmp_path):
-    args, setup = _create_setup(tmp_path)
-    setup.update(run_local=True)
-    job_submit(**setup)
-    _test_output(args)
-
-
-@skip_not_linux
-def test_find_errornous_percentage_signs(tmp_path):
-    mask = "%(PARAM1)s.%(PARAM2)d\nsome stuff # should be 5%\nsome % more % stuff."
-    args, setup = _create_setup(tmp_path, mask_content=mask)
-    with pytest.raises(KeyError) as e:
-        job_submit(**setup)
-    assert "problematic '%'" in e.value.args[0]
-
-
-@skip_not_linux
-def test_missing_keys(tmp_path):
-    mask = "%(PARAM1)s.%(PARAM2)s.%(PARAM3)s"
-    args, setup = _create_setup(tmp_path, mask_content=mask)
-    with pytest.raises(KeyError) as e:
-        job_submit(**setup)
-    assert "PARAM3" in e.value.args[0]
-
-
-@skip_on_linux
-def test_not_on_linux(tmp_path):
-    args, setup = _create_setup(tmp_path)
-    with pytest.raises(EnvironmentError) as e:
-        job_submit(**setup)
-    assert "htcondor bindings" in e.value.args[0]
-
-
-@skip_not_linux
-@pytest.mark.cern_network
-def test_htc_submit():
-    """ This test is here for local testing only. You need to adapt the path
-    and delete the results afterwards manually (so you can check them before."""
-    user = "jdilly"
-    path = Path("/", "afs", "cern.ch", "user", user[0], user, "htc_temp")
-    path.mkdir(exist_ok=True)
-    args, setup = _create_setup(path)
-
-    job_submit(**setup)
-    _test_output(args, post_run=False)
-    # _test_output(args, post_run=True)  # you can use this if you like after htcondor is done
-
-
-# Helper -----------------------------------------------------------------------
-
-
-def _create_setup(cwd_path: Path, mask_content: str = None):
-    """ Create a quick setup for Parameters PARAM1 and PARAM2. """
-    out_name = "out.txt"
-    out_dir = "Outputdir"
-
-    args = DotDict(
-        cwd=cwd_path,
-        out_name=out_name,
-        out_dir=out_dir,
-        id="%(PARAM1)s.%(PARAM2)d",
-        mask_name="test_script.mask",
-        ext=".sh",
-        out_file=Path(out_dir, out_name),
-        p1_list=["a", "b"],
-        p2_list=[1, 2, 3],
-    )
-
-    mask_path = cwd_path / args.mask_name
-    if mask_content is None:
-        mask_content = args.id
-
-    with mask_path.open("w") as f:
-        f.write(f'echo "{mask_content}" > "{args.out_file}"\n')
-
-    setup = dict(
-        executable="/bin/bash",
-        script_extension=args.ext,
-        job_output_dir=out_dir,
-        mask=str(mask_path),
-        replace_dict=dict(PARAM1=args.p1_list, PARAM2=args.p2_list,),
-        jobid_mask=args.id,
-        jobflavour="workday",
-        resume_jobs=True,
-        check_files=[args.out_name],
-        working_directory=str(args.cwd),
-        dryrun=False,
-    )
-    return args, setup
-
-
-def _test_output(args, post_run=True):
-    for p1 in args.p1_list:
-        for p2 in args.p2_list:
-            current_id = args.id % dict(PARAM1=p1, PARAM2=p2)
-            job_name = f"Job.{current_id}"
-            job_dir_path = args.cwd / job_name
-            out_dir_path = job_dir_path / args.out_dir
-            out_file_path = out_dir_path / args.out_name
-
-            assert job_dir_path.exists()
-            assert job_dir_path.is_dir()
-            assert (job_dir_path / args.mask_name).with_suffix(args.ext).exists()
-            # assert out_dir_path.exists()  # does not seem to be pre-created anymore (jdilly 2021-05-04)
-            if post_run:
-                assert out_dir_path.is_dir()
-                assert out_file_path.exists()
-                assert out_file_path.is_file()
-
-                with out_file_path.open("r") as f:
-                    assert f.read().strip("\n") == current_id