From 30a61c99a2f90ce345f5d679936d8a90a1c9ab80 Mon Sep 17 00:00:00 2001
From: James Robinson <james.em.robinson@gmail.com>
Date: Thu, 8 Mar 2018 17:51:08 +0100
Subject: [PATCH] Added Wy, bbH, HWj_EW and HZj_EW processes. 2018-03-07.
 (PowhegControl-00-03-10)

Former-commit-id: 878118b1ecc7ca3d8ee4023882b31db0478706af
---
 ...Pythia8EvtGen_A14NNPDF23_HWj_EW_example.py |  24 ++
 ...Pythia8EvtGen_A14NNPDF23_HZj_EW_example.py |  24 ++
 ...hegPythia8EvtGen_A14NNPDF23_bbH_example.py |  24 ++
 .../python/algorithms/generators/__init__.py  |   2 +-
 .../algorithms/generators/merge_output.py     |   2 +-
 .../python/algorithms/generators/multicore.py | 105 ++++++---
 .../algorithms/generators/singlecore.py       |   8 +-
 .../algorithms/postprocessors/__init__.py     |   2 +
 .../postprocessors/directory_cleaner.py       |  28 +++
 .../postprocessors/integration_grid_tester.py |  76 +++---
 .../integration_gridpack_creator.py           |  32 +++
 .../algorithms/postprocessors/madspin.py      |  16 +-
 .../algorithms/postprocessors/reweighter.py   |  37 ++-
 .../preprocessors/directory_cleaner.py        |   2 +-
 .../algorithms/preprocessors/reweighter.py    |   1 +
 .../python/algorithms/scheduler.py            |   6 +-
 .../python/parameters/registry.py             | 222 ++++++++++--------
 .../PowhegControl/python/powheg_control.py    |  92 ++++----
 .../python/processes/powheg/HWj_EW.py         | 189 +++++++++++++++
 .../python/processes/powheg/HZj_EW.py         | 192 +++++++++++++++
 .../python/processes/powheg/Wy.py             |  12 +-
 .../python/processes/powheg/__init__.py       |   3 +
 .../python/processes/powheg/bbH.py            | 133 +++++++++++
 .../python/processes/powheg/jj.py             |   1 +
 .../python/processes/powheg_RES.py            |  48 ++++
 .../python/processes/powheg_V1.py             |  25 ++
 .../python/processes/powheg_V2.py             |  53 ++++-
 .../python/processes/powheg_base.py           |  20 +-
 .../share/PowhegControl_HWj_EW_Common.py      |   4 +
 .../share/PowhegControl_HZj_EW_Common.py      |   4 +
 .../share/PowhegControl_Wy_Common.py          |   3 +-
 31 files changed, 1144 insertions(+), 246 deletions(-)
 create mode 100644 Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HWj_EW_example.py
 create mode 100644 Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HZj_EW_example.py
 create mode 100755 Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_bbH_example.py
 create mode 100644 Generators/PowhegControl/python/algorithms/postprocessors/directory_cleaner.py
 create mode 100644 Generators/PowhegControl/python/algorithms/postprocessors/integration_gridpack_creator.py
 create mode 100644 Generators/PowhegControl/python/processes/powheg/HWj_EW.py
 create mode 100644 Generators/PowhegControl/python/processes/powheg/HZj_EW.py
 create mode 100644 Generators/PowhegControl/python/processes/powheg/bbH.py
 create mode 100644 Generators/PowhegControl/share/PowhegControl_HWj_EW_Common.py
 create mode 100644 Generators/PowhegControl/share/PowhegControl_HZj_EW_Common.py

diff --git a/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HWj_EW_example.py b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HWj_EW_example.py
new file mode 100644
index 0000000000000..0c5d4fb61de91
--- /dev/null
+++ b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HWj_EW_example.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+#--------------------------------------------------------------
+# EVGEN configuration
+#--------------------------------------------------------------
+evgenConfig.description = "POWHEG+Pythia8 Higgs+W+jet production with electroweak effects using the A14 NNPDF2.3 tune."
+evgenConfig.keywords = ["Higgs", "SMHiggs", "W", "WHiggs", "1jet"]
+evgenConfig.contact = ["james.robinson@cern.ch"]
+
+# --------------------------------------------------------------
+# Load ATLAS defaults for the Powheg HWj_EW process
+# --------------------------------------------------------------
+include("PowhegControl/PowhegControl_HWj_EW_Common.py")
+
+# --------------------------------------------------------------
+# Generate events
+# --------------------------------------------------------------
+PowhegConfig.generate()
+
+#--------------------------------------------------------------
+# Pythia8 showering with the A14 NNPDF2.3 tune
+#--------------------------------------------------------------
+include("MC15JobOptions/Pythia8_A14_NNPDF23LO_EvtGen_Common.py")
+include("MC15JobOptions/Pythia8_Powheg.py")
diff --git a/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HZj_EW_example.py b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HZj_EW_example.py
new file mode 100644
index 0000000000000..4e82296130b73
--- /dev/null
+++ b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_HZj_EW_example.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+#--------------------------------------------------------------
+# EVGEN configuration
+#--------------------------------------------------------------
+evgenConfig.description = "POWHEG+Pythia8 H+Z+jet production with electroweak effects using the A14 NNPDF2.3 tune."
+evgenConfig.keywords = ["Higgs", "SMHiggs", "Z", "ZHiggs", "1jet"]
+evgenConfig.contact = ["james.robinson@cern.ch"]
+
+# --------------------------------------------------------------
+# Load ATLAS defaults for the Powheg HZj_EW process
+# --------------------------------------------------------------
+include("PowhegControl/PowhegControl_HZj_EW_Common.py")
+
+# --------------------------------------------------------------
+# Generate events
+# --------------------------------------------------------------
+PowhegConfig.generate()
+
+#--------------------------------------------------------------
+# Pythia8 showering with the A14 NNPDF2.3 tune
+#--------------------------------------------------------------
+include("MC15JobOptions/Pythia8_A14_NNPDF23LO_EvtGen_Common.py")
+include("MC15JobOptions/Pythia8_Powheg.py")
diff --git a/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_bbH_example.py b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_bbH_example.py
new file mode 100755
index 0000000000000..8bec1834c2121
--- /dev/null
+++ b/Generators/PowhegControl/examples/processes/MC15.101010.PowhegPythia8EvtGen_A14NNPDF23_bbH_example.py
@@ -0,0 +1,24 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+#--------------------------------------------------------------
+# EVGEN configuration
+#--------------------------------------------------------------
+evgenConfig.description = "POWHEG+Pythia8 bbH production with A14 NNPDF2.3 tune."
+evgenConfig.keywords = ["SM", "bottom", "Higgs"]
+evgenConfig.contact = ["james.robinson@cern.ch", "riccardo.di.sipio@cern.ch" ]
+
+# --------------------------------------------------------------
+# Load ATLAS defaults for the Powheg bbH process
+# --------------------------------------------------------------
+include("PowhegControl/PowhegControl_bbH_Common.py")
+
+# --------------------------------------------------------------
+# Generate events
+# --------------------------------------------------------------
+PowhegConfig.generate()
+
+#--------------------------------------------------------------
+# Pythia8 showering with the A14 NNPDF2.3 tune
+#--------------------------------------------------------------
+include("MC15JobOptions/Pythia8_A14_NNPDF23LO_EvtGen_Common.py")
+include("MC15JobOptions/Pythia8_Powheg.py")
diff --git a/Generators/PowhegControl/python/algorithms/generators/__init__.py b/Generators/PowhegControl/python/algorithms/generators/__init__.py
index 4828de0345d6a..073334e089bab 100644
--- a/Generators/PowhegControl/python/algorithms/generators/__init__.py
+++ b/Generators/PowhegControl/python/algorithms/generators/__init__.py
@@ -1,6 +1,6 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from merge_output import merge_output
-from multicore import multicore
+from multicore import multicore, multicore_untimed
 from output_validator import output_validator
 from singlecore import singlecore, singlecore_untimed
diff --git a/Generators/PowhegControl/python/algorithms/generators/merge_output.py b/Generators/PowhegControl/python/algorithms/generators/merge_output.py
index 93759807fbb8a..c56dc911faf72 100644
--- a/Generators/PowhegControl/python/algorithms/generators/merge_output.py
+++ b/Generators/PowhegControl/python/algorithms/generators/merge_output.py
@@ -14,7 +14,7 @@ logger = Logging.logging.getLogger("PowhegControl")
 def merge_output(cores, n_events_unscaled, powheg_LHE_output):
     """! Merge output events if running in multicore mode.
 
-    @param cores              Number of cores in use
+    @param cores              Number of cores in use.
     @param n_events_unscaled  Total number of events generated.
     @param powheg_LHE_output  Name of LHE file produced by PowhegBox.
 
diff --git a/Generators/PowhegControl/python/algorithms/generators/multicore.py b/Generators/PowhegControl/python/algorithms/generators/multicore.py
index af4ad357e73fc..45595fd9a17d6 100644
--- a/Generators/PowhegControl/python/algorithms/generators/multicore.py
+++ b/Generators/PowhegControl/python/algorithms/generators/multicore.py
@@ -6,22 +6,21 @@ from ...utility import FileParser, ProcessManager, SingleProcessThread
 from functools import partial
 import os
 
-## Get handle to Athena logging
+# Get handle to Athena logging
 logger = Logging.logging.getLogger("PowhegControl")
 
 
-def multicore(process, cores):
+def multicore(process):
     """! Run multiple Powheg processes, each in its own thread.
 
-    @param process PowhegBox process.
-    @param cores   Number of cores in use.
+    @param process  PowhegBox process.
 
     @author James Robinson  <james.robinson@cern.ch>
     """
     # Construct random seeds - increment by 1e6 each time
-    logger.info("Running in multicore mode with {} subjobs".format(cores))
+    logger.info("Running in multicore mode with {} subjobs".format(process.cores))
     with open("pwgseeds.dat", "wb") as random_seed_list:
-        for idx in range(cores):
+        for idx in range(process.cores):
             random_seed_list.write(str(process.random_seed + int(idx * 1e6)) + "\n")
 
     # Remove iseed when providing seeds from pwgseeds.dat
@@ -29,70 +28,106 @@ def multicore(process, cores):
     logger.debug("Disabling iseed variable when multiple seeds are used")
 
     # Construct generation function
-    generation_fn = partial(__run_threaded_multicore, process.executable, cores)
+    generation_fn = partial(multicore_untimed, process)
 
     if process.powheg_version == "V1":
         __multicore_v1(generation_fn)
     elif process.powheg_version == "V2" or process.powheg_version == "RES":
-        __multicore_v2(generation_fn, process.itmx1)
+        __multicore_multistage(process, generation_fn)
     else:
         raise ValueError("Powheg version {} is not supported for multicore running!".format(process.powheg_version))
 
-
 @timed("multi-core generation (V1)")
 def __multicore_v1(generation_fn):
-    """! Run Powheg V1 generation in multicore mode."""
+    """! Run Powheg V1 generation in multi-core mode.
+
+    @param generation_fn  Function that can be called without argument to generate events.
+
+    @author James Robinson  <james.robinson@cern.ch>
+    """
     generation_fn()
 
+@timed("multi-core generation (V2/RES)")
+def __multicore_multistage(process, generation_fn):
+    """! Run Powheg V2/RES generation in multi-core mode.
 
-@timed("multi-core generation (V2)")
-def __multicore_v2(generation_fn, n_xgrid_iterations):
-    """! Run Powheg V2 generation in multicore mode."""
-    __multicore_v2_stage_1(generation_fn, n_xgrid_iterations)
-    __multicore_v2_stage_2(generation_fn)
-    __multicore_v2_stage_3(generation_fn)
-    __multicore_v2_stage_4(generation_fn)
+    @param process        PowhegBox process.
+    @param generation_fn  Function that can be called without argument to generate events.
 
+    @author James Robinson  <james.robinson@cern.ch>
+    """
+    if process.stage_is_completed(1):
+        logger.info("=> Skipping multi-core generation (V2/RES): stage 1 <=")
+    else:
+        __multicore_multistage_stage_1(generation_fn, process.itmx1)
+    if process.stage_is_completed(2):
+        logger.info("=> Skipping multi-core generation (V2/RES): stage 2 <=")
+    else:
+        __multicore_multistage_stage_2(generation_fn)
+    if process.stage_is_completed(3):
+        logger.info("=> Skipping multi-core generation (V2/RES): stage 3 <=")
+    else:
+        __multicore_multistage_stage_3(generation_fn)
+    __multicore_multistage_stage_4(generation_fn)
 
-@timed("multi-core generation (V2: stage 1)")
-def __multicore_v2_stage_1(generation_fn, n_xgrid_iterations):
-    """! Run Powheg V2 (stage 1) generation in multicore mode."""
+@timed("multi-core generation (V2/RES): stage 1)")
+def __multicore_multistage_stage_1(generation_fn, n_xgrid_iterations):
+    """! Run Powheg V2/RES (stage 1) generation in multi-core mode.
+
+    @param generation_fn       Function that can be called without argument to generate events.
+    @param n_xgrid_iterations  Number of xgrid iterations to perform.
+
+    @author James Robinson  <james.robinson@cern.ch>
+    """
     FileParser("powheg.input").text_replace("parallelstage.*", "parallelstage 1")
     # For stage 1, we need n_xgrid_iterations iterations
     for xgrid_iteration in range(1, n_xgrid_iterations + 1):
         FileParser("powheg.input").text_replace("xgriditeration.*", "xgriditeration {}".format(xgrid_iteration))
         generation_fn()
 
+@timed("multi-core generation (V2/RES): stage 2)")
+def __multicore_multistage_stage_2(generation_fn):
+    """! Run Powheg V2/RES (stage 2) generation in multi-core mode.
+
+    @param generation_fn  Function that can be called without argument to generate events.
 
-@timed("multi-core generation (V2: stage 2)")
-def __multicore_v2_stage_2(generation_fn):
-    """! Run Powheg V2 (stage 2) generation in multicore mode."""
+    @author James Robinson  <james.robinson@cern.ch>
+    """
     FileParser("powheg.input").text_replace("parallelstage.*", "parallelstage 2")
     generation_fn()
 
+@timed("multi-core generation (V2/RES): stage 3)")
+def __multicore_multistage_stage_3(generation_fn):
+    """! Run Powheg V2/RES (stage 3) generation in multi-core mode.
+
+    @param generation_fn  Function that can be called without argument to generate events.
 
-@timed("multi-core generation (V2: stage 3)")
-def __multicore_v2_stage_3(generation_fn):
-    """! Run Powheg V2 (stage 3) generation in multicore mode."""
+    @author James Robinson  <james.robinson@cern.ch>
+    """
     FileParser("powheg.input").text_replace("parallelstage.*", "parallelstage 3")
     generation_fn()
 
+@timed("multi-core generation (V2/RES): stage 4)")
+def __multicore_multistage_stage_4(generation_fn):
+    """! Run Powheg V2/RES (stage 4) generation in multi-core mode.
+
+    @param generation_fn  Function that can be called without argument to generate events.
 
-@timed("multi-core generation (V2: stage 4)")
-def __multicore_v2_stage_4(generation_fn):
-    """! Run Powheg V2 (stage 4) generation in multicore mode."""
+    @author James Robinson  <james.robinson@cern.ch>
+    """
     FileParser("powheg.input").text_replace("parallelstage.*", "parallelstage 4")
     generation_fn()
 
-
-def __run_threaded_multicore(powheg_executable, cores):
+def multicore_untimed(process):
     """! Run multiple Powheg processes, each in its own thread.
 
+    @param process  PowhegBox process.
+
     @author James Robinson  <james.robinson@cern.ch>
     """
-    if not os.path.isfile(powheg_executable):
-        raise OSError("Powheg executable {} not found!".format(powheg_executable))
-    processes = [SingleProcessThread(powheg_executable, seed_index=idx) for idx in range(1, cores + 1)]
-    manager = ProcessManager(processes)
+    if not os.path.isfile(process.executable):
+        raise OSError("Powheg executable {} not found!".format(process.executable))
+    threads = [SingleProcessThread(process.executable, seed_index=idx) for idx in range(1, process.cores + 1)]
+    manager = ProcessManager(threads)
     while manager.monitor():
         pass
diff --git a/Generators/PowhegControl/python/algorithms/generators/singlecore.py b/Generators/PowhegControl/python/algorithms/generators/singlecore.py
index e4b5cf5d9e955..a7394e1b85b49 100644
--- a/Generators/PowhegControl/python/algorithms/generators/singlecore.py
+++ b/Generators/PowhegControl/python/algorithms/generators/singlecore.py
@@ -1,7 +1,7 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from ...decorators import timed
-from ...utility import ProcessManager, SingleProcessThread
+from ...utility import FileParser, ProcessManager, SingleProcessThread
 import os
 
 
@@ -9,7 +9,7 @@ import os
 def singlecore(process):
     """! Run a single Powheg process in its own timed thread.
 
-    @param process PowhegBox process.
+    @param process  PowhegBox process.
 
     @author James Robinson  <james.robinson@cern.ch>
     """
@@ -19,7 +19,7 @@ def singlecore(process):
 def singlecore_untimed(process):
     """! Run a single Powheg process in its own thread.
 
-    @param process PowhegBox process.
+    @param process  PowhegBox process.
 
     @author James Robinson  <james.robinson@cern.ch>
     """
@@ -28,4 +28,4 @@ def singlecore_untimed(process):
     threads = [SingleProcessThread(process.executable)]
     manager = ProcessManager(threads)
     while manager.monitor():
-        pass
+        pass
\ No newline at end of file
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/__init__.py b/Generators/PowhegControl/python/algorithms/postprocessors/__init__.py
index c947eb59202f5..65f620e7bc190 100644
--- a/Generators/PowhegControl/python/algorithms/postprocessors/__init__.py
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/__init__.py
@@ -1,6 +1,8 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from cross_section_calculator import cross_section_calculator
+from directory_cleaner import directory_cleaner
+from integration_gridpack_creator import integration_gridpack_creator
 from integration_grid_tester import integration_grid_tester
 from madspin import MadSpin
 from nnlo_reweighter import NNLO_reweighter
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/directory_cleaner.py b/Generators/PowhegControl/python/algorithms/postprocessors/directory_cleaner.py
new file mode 100644
index 0000000000000..65d81084c98c1
--- /dev/null
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/directory_cleaner.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import Logging
+from ...decorators import timed
+import glob
+import os
+
+## Get handle to Athena logging
+logger = Logging.logging.getLogger("PowhegControl")
+
+
+@timed("directory cleaner")
+def directory_cleaner(process):
+    """! Clean up the directory after running.
+
+    Remove any leftover files to avoid clutter.
+
+    @author James Robinson <james.robinson@cern.ch>
+    """
+    nRemoved = 0
+    for file_name in sum([glob.glob(_f) for _f in process.files_for_cleanup], []):
+        logger.debug("... removing unneeded file: {}".format(file_name))
+        try:
+            os.remove(file_name)
+        except OSError:
+            logger.warning("... could not remove {}".format(file_name))
+        nRemoved += 1
+    logger.info("... removed {} unneeded files".format(nRemoved))
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/integration_grid_tester.py b/Generators/PowhegControl/python/algorithms/postprocessors/integration_grid_tester.py
index 5ff2aaf443791..b92cab29419f9 100644
--- a/Generators/PowhegControl/python/algorithms/postprocessors/integration_grid_tester.py
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/integration_grid_tester.py
@@ -34,42 +34,46 @@ def integration_grid_tester():
     @author James Robinson <james.robinson@cern.ch>
     """
     inclusive_xs, inclusive_xs_error, negative_weights, positive_weights, n_events, n_upper_bound_failures_xs, n_upper_bound_failures_radiation = 0, 0, 0, 0, 0, 0, 0
-    for file_name in glob.glob("pwg*stat*.dat"):
-        if os.path.isfile(file_name):
-            # Inclusive cross-section uncertainty [relative error on (total pos + |total neg|)]
-            with open(file_name, "rb") as data_file:
-                try:
-                    matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde(.*)weights)(.*)[0-9](.*)\+\-(.*)[0-9](.*)", line)]
-                    if len(matched_lines) > 0:
-                        positive_weight_xs = sum([map(float, re.findall(regex_match_floats, line)) for line in matched_lines if "pos." in line], [])
-                        negative_weight_xs = sum([map(float, re.findall(regex_match_floats, line)) for line in matched_lines if "|neg.|" in line], [])
-                        inclusive_xs += positive_weight_xs[0] + negative_weight_xs[0]
-                        inclusive_xs_error += math.sqrt(positive_weight_xs[1]**2 + negative_weight_xs[1]**2)
-                except:  # catch all exceptions
-                    pass
-            # Negative weight test
-            with open(file_name, "rb") as data_file:
-                try:
-                    matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde(.*)weights|Remnant cross section)(.*)[0-9](.*)\+\-(.*)[0-9](.*)", line)]
-                    if len(matched_lines) > 0:
-                        negative_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "btilde |neg.|" in line][0]))[0]
-                        positive_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "btilde pos." in line][0]))[0]
-                        positive_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "Remnant cross section" in line][0]))[0]
-                except:  # catch all exceptions
-                    pass
-
-    for file_name in [x for x in glob.glob("pwgcounters*.dat") if "st3" not in x]:
-        if os.path.isfile(file_name):
-            # Upper bound violations [in inclusive cross-section and generation of radiation]
-            with open(file_name, "rb") as data_file:
-                try:
-                    matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde event|remnant event|upper bound failure)(.*)[0-9](.*)", line)]
-                    if len(matched_lines) > 0:
-                        n_events += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "event" in line]))
-                        n_upper_bound_failures_xs += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "upper bound failure in inclusive" in line]))
-                        n_upper_bound_failures_radiation += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "upper bound failure in generation" in line]))
-                except:  # catch all exceptions
-                    pass
+    # Open stat files
+    for file_name in sum([glob.glob(_f) for _f in ["pwgstat.dat", "pwgstat-0001.dat", "pwg-stat.dat", "pwg-st3-0001-stat.dat", "pwg-0001-st3-stat.dat"]], []):
+        # Inclusive cross-section uncertainty [relative error on (total pos + |total neg|)]
+        with open(file_name, "rb") as data_file:
+            try:
+                matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde(.*)weights)(.*)[0-9](.*)\+\-(.*)[0-9](.*)", line)]
+                matched_lines = [re.sub(" +", " ", _l) for _l in matched_lines] # strip multiple whitespace
+                if len(matched_lines) > 0:
+                    positive_weight_xs = sum([map(float, re.findall(regex_match_floats, line)) for line in matched_lines if "pos." in line], [])
+                    negative_weight_xs = sum([map(float, re.findall(regex_match_floats, line)) for line in matched_lines if "|neg.|" in line], [])
+                    inclusive_xs += positive_weight_xs[0] + negative_weight_xs[0]
+                    inclusive_xs_error += math.sqrt(positive_weight_xs[1]**2 + negative_weight_xs[1]**2)
+            except:  # catch all exceptions
+                pass
+        # Negative weight test
+        with open(file_name, "rb") as data_file:
+            try:
+                matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde(.*)weights|Remnant cross section)(.*)[0-9](.*)\+\-(.*)[0-9](.*)", line)]
+                matched_lines = [re.sub(" +", " ", _l) for _l in matched_lines] # strip multiple whitespace
+                if len(matched_lines) > 0:
+                    negative_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "btilde |neg.|" in line][0]))[0]
+                    positive_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "btilde pos." in line][0]))[0]
+                    positive_weights += map(float, re.findall(regex_match_floats, [line for line in matched_lines if "Remnant cross section" in line][0]))[0]
+            except:  # catch all exceptions
+                pass
+    # Open counter files
+    file_names = sum([glob.glob(_f) for _f in ["pwgcounters-st4-*.dat", "pwgcounters0*.dat"]], [])
+    if not file_names: file_names = glob.glob("pwgcounters.dat")
+    for file_name in file_names:
+        # Upper bound violations [in inclusive cross-section and generation of radiation]
+        with open(file_name, "rb") as data_file:
+            try:
+                matched_lines = [line.replace("+-", "") for line in data_file if re.match(r"(.*)(btilde event|remnant event|upper bound failure)(.*)[0-9](.*)", line)]
+                matched_lines = [re.sub(" +", " ", _l) for _l in matched_lines] # strip multiple whitespace
+                if len(matched_lines) > 0:
+                    n_events += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "event" in line]))
+                    n_upper_bound_failures_xs += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "upper bound failure in inclusive" in line]))
+                    n_upper_bound_failures_radiation += sum(map(float, [re.findall(regex_match_floats, line)[0] for line in matched_lines if "upper bound failure in generation" in line]))
+            except:  # catch all exceptions
+                pass
 
     # Calculate test statistics
     inclusive_xs_test = safe_percentage(inclusive_xs_error, inclusive_xs)
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/integration_gridpack_creator.py b/Generators/PowhegControl/python/algorithms/postprocessors/integration_gridpack_creator.py
new file mode 100644
index 0000000000000..ae2aa220e137c
--- /dev/null
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/integration_gridpack_creator.py
@@ -0,0 +1,32 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import Logging
+from ...decorators import timed
+import glob
+import os
+import subprocess
+
+## Get handle to Athena logging
+logger = Logging.logging.getLogger("PowhegControl")
+
+
+@timed("integration gridpack creator")
+def integration_gridpack_creator(process):
+    """! Create tarball containing integration grids for future use.
+
+    Tar up integration grids
+
+    @author James Robinson <james.robinson@cern.ch>
+    """
+    output_tarball_name = "integration_grids.tar.gz"
+    file_names = sum([glob.glob(_f) for _f in process.integration_file_names], [])
+
+    if file_names:
+        logger.info("Tar-ing {} integration grids into {}".format(len(file_names), output_tarball_name))
+        for line in subprocess.check_output(["tar", "cvzf", output_tarball_name] + file_names, stderr=subprocess.STDOUT).splitlines():
+            logger.info(line)
+        for file_name in file_names:
+            try:
+                os.remove(file_name)
+            except OSError:
+                logger.warning("... could not clean up {}".format(file_name))
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/madspin.py b/Generators/PowhegControl/python/algorithms/postprocessors/madspin.py
index fc69a16b5e5b9..756eed44d8f07 100644
--- a/Generators/PowhegControl/python/algorithms/postprocessors/madspin.py
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/madspin.py
@@ -30,8 +30,10 @@ def MadSpin(process, powheg_LHE_output):
 def __construct_inputs(input_LHE_events, process):
     """! Construct MadSpin runcard.
 
-    @param input_LHE_events Input LHE file name.
-    @param process          MadSpin process.
+    @param input_LHE_events  Input LHE file name.
+    @param process           MadSpin process.
+
+    @author James Robinson <james.robinson@cern.ch>
     """
     # Find insertion point for MadSpin header
     logger.info("Constructing MadSpin runcard header")
@@ -244,7 +246,10 @@ def __construct_inputs(input_LHE_events, process):
 
 @timed("MadSpin executable")
 def __run_executable(executable):
-    """! Run MadSpin executable."""
+    """! Run MadSpin executable.
+
+    @author James Robinson <james.robinson@cern.ch>
+    """
     logger.info("MadSpin executable: {}".format(executable))
     with open("madspin_runcard.txt", "rb") as runcard_input:
         processes = [SingleProcessThread([executable], stdin=runcard_input, ignore_output=["INFO:", "MadSpin>"])]
@@ -254,7 +259,10 @@ def __run_executable(executable):
 
 
 def __prepare_outputs(input_LHE_events):
-    """! Prepare MadSpin output."""
+    """! Prepare MadSpin output.
+
+    @author James Robinson <james.robinson@cern.ch>
+    """
     logger.info("Preparing MadSpin output")
 
     # Unzip MadSpin events
diff --git a/Generators/PowhegControl/python/algorithms/postprocessors/reweighter.py b/Generators/PowhegControl/python/algorithms/postprocessors/reweighter.py
index 3cefa5d0cde22..63b2c679675fb 100644
--- a/Generators/PowhegControl/python/algorithms/postprocessors/reweighter.py
+++ b/Generators/PowhegControl/python/algorithms/postprocessors/reweighter.py
@@ -3,7 +3,7 @@
 from AthenaCommon import Logging
 from ...decorators import timed
 from ...utility import FileParser
-from ..generators import singlecore_untimed
+from ..generators import multicore_untimed, singlecore_untimed
 import collections
 import os
 import shutil
@@ -94,7 +94,7 @@ def reweighter(process, weight_groups, powheg_LHE_output):
             weight_list = [WeightTuple(ID=0, name="nominal", group="nominal", parallel_xml_compatible=True, parameter_settings=[], keywords=None, combine=None)] + weight_list
 
         # Construct xml output
-        xml_lines, serial_xml_weight_list, current_weightgroup = [], [], ""
+        xml_lines, serial_xml_weight_list, current_weightgroup = [], [], None
         for weight in weight_list:
             # Group elements
             if weight.parallel_xml_compatible and weight.group != current_weightgroup:
@@ -104,7 +104,6 @@ def reweighter(process, weight_groups, powheg_LHE_output):
             # Weight elements
             if weight.parallel_xml_compatible:
                 keyword_pairs_str = " ".join(["{}={}".format(k, v) for p, v in weight.parameter_settings for k in weight.keywords[p]])
-                if keyword_pairs_str == "": keyword_pairs_str = "nominal"
                 xml_lines.append("<weight id='{}'> {} </weight>".format(weight.ID, keyword_pairs_str))
             else:
                 serial_xml_weight_list.append(weight)
@@ -116,8 +115,7 @@ def reweighter(process, weight_groups, powheg_LHE_output):
             # Write xml output
             with open("reweighting_input.xml", "wb") as f_rwgt:
                 f_rwgt.write("<initrwgt>\n")
-                for xml_line in xml_lines:
-                    f_rwgt.write("{}\n".format(xml_line))
+                [f_rwgt.write("{}\n".format(xml_line)) for xml_line in xml_lines]
                 f_rwgt.write("</initrwgt>")
 
             # Add reweighting lines to runcard
@@ -126,12 +124,22 @@ def reweighter(process, weight_groups, powheg_LHE_output):
             FileParser("powheg.input").text_replace("clobberlhe .*", "clobberlhe 1")
 
             logger.info("Preparing simultaneous calculation of {} additional weights for generated events.".format(n_parallel_xml_weights))
-            singlecore_untimed(process)
+
+            # Allow RES processes to do their reweighting with manyseeds enabled, or they will look for the wrong files
+            if process.parameters_by_name("manyseeds")[0].value == 1:
+                if process.powheg_version == "RES":
+                    multicore_untimed(process)
+                else:
+                    FileParser("powheg.input").text_replace("manyseeds .*", "manyseeds 0")
+                    FileParser("powheg.input").text_replace("parallelstage .*", "parallelstage -1")
+                    singlecore_untimed(process)
+            else:
+                singlecore_untimed(process)
 
             # Move the reweighted file back
             rename_LHE_output(powheg_LHE_output)
 
-        # Iterate over any variations which require old-style reweighting
+        # Iterate over any variations which require non-simultaneous reweighting
         if len(serial_xml_weight_list) > 0:
             logger.info("Preparing individual calculation of {} additional weights for generated events.".format(len(serial_xml_weight_list)))
             shutil.move("reweighting_input.xml", "reweighting_input.nominal")
@@ -193,7 +201,7 @@ def add_single_weight(process, weight, idx_weight, n_total, use_XML):
         else:
             # As the nominal process has already been run, turn on compute_rwgt
             FileParser("powheg.input").text_replace("compute_rwgt 0", "compute_rwgt 1")
-            # Ensure that manyseeds is turned off,  as this would cause the reweighting to crash
+            # Ensure that manyseeds/parallelstage are turned off, as these cause the reweighting to crash
             FileParser("powheg.input").text_replace("manyseeds .*", "manyseeds 0")
             FileParser("powheg.input").text_replace("parallelstage .*", "parallelstage -1")
 
@@ -206,13 +214,12 @@ def add_single_weight(process, weight, idx_weight, n_total, use_XML):
             except KeyError:
                 logger.warning("Parameter '{}' not recognised. Cannot reweight!".format(parameter))
 
-
         if use_XML:
             # Create XML reweighting file
             with open("reweighting_input.xml", "wb") as f_rwgt:
                 f_rwgt.write("<initrwgt>\n")
                 f_rwgt.write("<weightgroup name='{}' combine='{}'>\n".format(weight.group, weight.combine))
-                f_rwgt.write("<weight id='{}'> {} </weight>\n".format(weight.ID, weight.name))
+                f_rwgt.write("<weight id='{}'> </weight>\n".format(weight.ID))
                 f_rwgt.write("</weightgroup>\n")
                 f_rwgt.write("</initrwgt>")
         else:
@@ -223,7 +230,15 @@ def add_single_weight(process, weight, idx_weight, n_total, use_XML):
             FileParser("powheg.input").text_replace("lhrwgt_group_name .*", "lhrwgt_group_name '{}'".format(weight.group))
 
         # Run the process until termination
-        singlecore_untimed(process)
+        if process.parameters_by_name("manyseeds")[0].value == 1:
+            if process.powheg_version == "RES":
+                multicore_untimed(process)
+            else:
+                FileParser("powheg.input").text_replace("manyseeds .*", "manyseeds 0")
+                FileParser("powheg.input").text_replace("parallelstage .*", "parallelstage -1")
+                singlecore_untimed(process)
+        else:
+            singlecore_untimed(process)
 
     # Run single weight variation
     __timed_inner_fn()
diff --git a/Generators/PowhegControl/python/algorithms/preprocessors/directory_cleaner.py b/Generators/PowhegControl/python/algorithms/preprocessors/directory_cleaner.py
index e594b25d05720..05e68cf1a844a 100644
--- a/Generators/PowhegControl/python/algorithms/preprocessors/directory_cleaner.py
+++ b/Generators/PowhegControl/python/algorithms/preprocessors/directory_cleaner.py
@@ -10,7 +10,7 @@ logger = Logging.logging.getLogger("PowhegControl")
 
 
 @timed("directory cleaner")
-def directory_cleaner():
+def directory_cleaner(*args):
     """! Clean up the directory before running.
 
     Remove any existing LHE files to avoid repeated events.
diff --git a/Generators/PowhegControl/python/algorithms/preprocessors/reweighter.py b/Generators/PowhegControl/python/algorithms/preprocessors/reweighter.py
index 8b22cc33a9d65..0111819a1a5ac 100644
--- a/Generators/PowhegControl/python/algorithms/preprocessors/reweighter.py
+++ b/Generators/PowhegControl/python/algorithms/preprocessors/reweighter.py
@@ -13,6 +13,7 @@ def reweighter(process, *args):
     """
     # Alter/remove runcard options depending on which weighting scheme is being used
     if process.use_XML_reweighting:
+        # FileParser("powheg.input").text_remove("compute_rwgt")
         FileParser("powheg.input").text_remove("lhrwgt_descr")
         FileParser("powheg.input").text_remove("lhrwgt_group_combine")
         FileParser("powheg.input").text_remove("lhrwgt_group_name")
diff --git a/Generators/PowhegControl/python/algorithms/scheduler.py b/Generators/PowhegControl/python/algorithms/scheduler.py
index 95bc063a891c9..df88b3a83e7cc 100644
--- a/Generators/PowhegControl/python/algorithms/scheduler.py
+++ b/Generators/PowhegControl/python/algorithms/scheduler.py
@@ -29,7 +29,7 @@ class Scheduler(object):
     ## Postprocessing evaluation order
     ordered_postprocessors = ["quark colour fixer", "reweighter", "NNLO reweighter", "MadSpin", "PHOTOS",
                               "integration grid tester", "cross section calculator", "output file renamer",
-                              "output tarball preparer"]
+                              "output tarball preparer", "integration gridpack creator", "directory cleaner"]
 
     ## Map preprocessing names to functions
     preprocessor_fn_dict = {
@@ -48,6 +48,8 @@ class Scheduler(object):
     ## Map postprocessing names to functions
     postprocessor_fn_dict = {
         "cross section calculator": partial(postprocessors.cross_section_calculator, powheg_LHE_output=powheg_LHE_output),
+        "directory cleaner": postprocessors.directory_cleaner,
+        "integration gridpack creator": postprocessors.integration_gridpack_creator,
         "integration grid tester": postprocessors.integration_grid_tester,
         "MadSpin": partial(postprocessors.MadSpin, powheg_LHE_output=powheg_LHE_output),
         "NNLO reweighter": partial(postprocessors.NNLO_reweighter, powheg_LHE_output=powheg_LHE_output),
@@ -64,7 +66,7 @@ class Scheduler(object):
         self.sequence = {"preprocessors": {}, "generators": {}, "postprocessors": {}}
 
         # Add universal components
-        self.add("directory cleaner")
+        self.add("output validator")
         self.add("integration grid tester")
 
     def add(self, name, *args):
diff --git a/Generators/PowhegControl/python/parameters/registry.py b/Generators/PowhegControl/python/parameters/registry.py
index b8b3de58ce58f..7deeaad9c4302 100644
--- a/Generators/PowhegControl/python/parameters/registry.py
+++ b/Generators/PowhegControl/python/parameters/registry.py
@@ -16,8 +16,8 @@ class Registry(object):
 
     def __init__(self):
         """! Constructor: initialise the registry."""
-        self.add_default("allrad", 0, description="turns on multiple shower scheme. [1:enabled]")
-        self.add_default("alpha", -1, description="")
+        self.add_default("allrad", 0, description="turns on multiple shower scheme. Keeps hardest radiation from production and all resonances. [1:enabled]")
+        self.add_default("alpha", -1, description="[-1:use Powheg default]")
         self.add_default("alphaem_inv", 1.0 / float(atlas_common.alphaem), description="EM coupling reciprocal")
         self.add_default("alphaem_z", atlas_common.alphaem, description="EM coupling at the Z-boson mass")
         self.add_default("alphaem", atlas_common.alphaem, description="EM coupling")
@@ -27,17 +27,17 @@ class Registry(object):
         self.add_default("alphaspdf", atlas_common.alphaqcd, description="strong coupling")
         self.add_default("altmap", 0, description="mapping that preserves the relative kinematics of the emitter where possible. [1:enabled]")
         self.add_default("arXiv:1207.5018", -1, frozen=True, description="compare to arXiv:1207.5018. [>0:enabled]")
-        self.add_default("atlas_scale", -1, description="(-1:Powheg default)")
-        self.add_default("bcut", -1, description="(-1:Powheg default)")
-        self.add_default("bmass_in_minlo", 0, description="(0:disabled; 1:enabled) use non-zero b-mass in MiNLO")
+        self.add_default("atlas_scale", -1, description="[-1:use Powheg default]")
+        self.add_default("bcut", -1, description="[-1:use Powheg default]")
+        self.add_default("bmass_in_minlo", 0, description="use non-zero b-mass in MiNLO. [0:disabled; 1:enabled]")
         self.add_default("bmass_lhe", atlas_common.mass.b, name="mass_b", description="b-quark mass in GeV (for momentum reshuffling)")
         self.add_default("bmass", atlas_common.mass.b, name="mass_b", description="b-quark mass in GeV")
         self.add_default("Bmass", atlas_common.mass.b, name="mass_b", description="b-quark mass in GeV")
         self.add_default("bornktmin", -1, description="generation cut: minimum kt in underlying Born. [<0:default to 0]")
         self.add_default("bornonly", 0, description="calculate only Born-level process. [1:enabled]")
         self.add_default("bornsuppfact", -1, description="mass parameter for Born suppression factor. [<0:disabled]")
-        self.add_default("bornsuppfactV", -1, description="(-1:Powheg default)")
-        self.add_default("bornsuppfactW", -1, description="(-1:Powheg default)")
+        self.add_default("bornsuppfactV", -1, description="[-1:use Powheg default]")
+        self.add_default("bornsuppfactW", -1, description="[-1:use Powheg default]")
         self.add_default("bornzerodamp", 1, description="use damping where the Born is strongly suppressed (or 0). [1:enabled]")
         self.add_default("bottommass", atlas_common.mass.b, name="mass_b", description="b-quark mass in GeV (loops disabled if <= 0)",)
         self.add_default("bottomthr", atlas_common.mass.b, description="minimum pT in GeV for generating emission off b-quarks. [<0:default to 5.0]")
@@ -47,8 +47,8 @@ class Registry(object):
         self.add_default("BR_t_to_Ws", atlas_common.branching_ratio.t_to_Ws, description="top branching ratio to s-quarks")
         self.add_default("BR_W_to_hadrons", atlas_common.branching_ratio.W_to_hadrons, description="total W branching ratio to hadrons")
         self.add_default("BR_W_to_leptons", atlas_common.branching_ratio.W_to_leptons, description="total W branching ratio to leptons")
-        self.add_default("brpar_diexp", -1, description="(-1:Powheg default)")
-        self.add_default("brpar_dijexp", -1, description="(-1:Powheg default)")
+        self.add_default("brpar_diexp", -1, description="[-1:use Powheg default]")
+        self.add_default("brpar_dijexp", -1, description="[-1:use Powheg default]")
         self.add_default("btildeborn", -1, description="Born contributions. [0:disabled]")
         self.add_default("btildecoll", -1, description="collinear contributions. [0:disabled]")
         self.add_default("btildereal", -1, description="for fixed order: distinguish real terms from Born/virtual/subtraction. [0:disabled]")
@@ -57,14 +57,15 @@ class Registry(object):
         self.add_default("btlscalereal", -1, description="compute scales that depend on the real kinematics. [1:enabled]")
         self.add_default("bwcutoff", 15, description="mass window is object_mass +/- bwcutoff * object_width")
         self.add_default("bwshape", 1, description="functional form of Breit-Wigner used to distribute Higgs virtuality. [1:running width; 2:hwidth]")
-        self.add_default("chainA", "''", frozen=True, description="weakino decay chain: UNUSED.")
-        self.add_default("chainB", "''", frozen=True, description="weakino decay chain: UNUSED.")
+        self.add_default("chainA", "''", frozen=True, description="UNUSED. weakino decay chain.")
+        self.add_default("chainB", "''", frozen=True, description="UNUSED. weakino decay chain.")
         self.add_default("charmmass", atlas_common.mass.c, name="mass_c", description="c-quark mass in GeV (loops enabled if <= 0)")
         self.add_default("charmthr", atlas_common.mass.c, description="minimum pT in GeV for generating emission off c-quarks. [<0:default to 1.5]")
         self.add_default("charmthrpdf", atlas_common.mass.c, description="threshold in GeV at which c-quark PDF becomes non-zero. [<0:default to 1.5]")
-        self.add_default("check_bad_st2", -1, description="check stage 2 output. [1:enabled]")
+        self.add_default("check_bad_st2", -1, description="check stage 2 output and discard bad grids. [1:enabled]")
         self.add_default("chklimseed", -1, description="check limit seed")
         self.add_default("ckkwscalup", 1, description="scalup scale for subsequent shower. [0:Powheg; 1:CKKW (use the smallest kt in the final state)]")
+        self.add_default("CKM_diagonal", 0, description="Set CKM matrix diagonal. [0:False; 1:True]")
         self.add_default("CKM_Vcb", atlas_common.CKM.Vcb, description="CKM element: Vcb")
         self.add_default("CKM_Vcd", atlas_common.CKM.Vcd, description="CKM element: Vcd")
         self.add_default("CKM_Vcs", atlas_common.CKM.Vcs, description="CKM element: Vcs")
@@ -77,17 +78,18 @@ class Registry(object):
         self.add_default("clobberlhe", -1, frozen=True, description="allow LHE files to be overwritten. [1:enabled]")
         self.add_default("cmass_lhe", atlas_common.mass.c, name="mass_c", description="c-quark mass in GeV (for momentum reshuffling)")
         self.add_default("Cmass", atlas_common.mass.c, name="mass_c", description="c-quark mass in GeV")
-        self.add_default("collremnsamp\"", -1, name="collremnsamp", description="(-1:Powheg default)")
+        self.add_default("collremnsamp\"", -1, name="collremnsamp", description="[-1:use Powheg default]")
         self.add_default("colltest", 1, description="check collinear limits. [0:disabled]")
+        self.add_default("comparison_paper", -1, frozen=True, description="compare to paper. [>0:enabled]")
         self.add_default("complexGFermi", 1, description="use complex G_F [0:disabled]")
         self.add_default("complexmass", -1, description="complex mass")
         self.add_default("complexpolescheme", 0, description="use complex pole scheme (Passarino et al.) [>0:enabled]")
         self.add_default("compress_lhe", -1, frozen=True, description="compress LHE output.")
-        self.add_default("compress_upb", -1, frozen=True, description="")
+        self.add_default("compress_upb", -1, frozen=True, description="[-1:use Powheg default]")
         self.add_default("compute_rwgt", 0, frozen=True, description="whether to compute a reweighting factor. [1:enabled]")
         self.add_default("corI", 1, description="particle pair to correlate - corI and corJ should be different and a number between 1 and 4.")
         self.add_default("corJ", 2, description="particle pair to correlate - corI and corJ should be different and a number between 1 and 4.")
-        self.add_default("cutallpairs", -1, description="(-1:Powheg-default)")
+        self.add_default("cutallpairs", -1, description="[-1:use Powheg default]")
         self.add_default("dec1", -1, hidden=True, description="Weakino decay 1. UNUSED")
         self.add_default("dec2", -1, hidden=True, description="Weakino decay 2. UNUSED")
         self.add_default("dec3", -1, hidden=True, description="Weakino decay 3. UNUSED")
@@ -97,9 +99,10 @@ class Registry(object):
         self.add_default("delg1_z", 0, description="Delta_g1(Z)")
         self.add_default("delk_g", 0, description="Delta_K(Gamma)")
         self.add_default("delk_z", 0, description="Delta_K(Z)")
+        self.add_default("delta_mbbmin", 0, description="if non-zero, use generation cut on m_bb")
         self.add_default("delta_mttmin", 0, description="if non-zero, use generation cut on m_tt")
         self.add_default("Deltak_gam", 0, description="Delta_K(Gamma)")
-        self.add_default("deltar", -1, description="")
+        self.add_default("deltar", -1, description="[-1:use Powheg default]")
         self.add_default("diagCKM", 0, description="which CKM matrix to use [0:normal CKM; 1:diagonal CKM]")
         self.add_default("Dmass", atlas_common.mass.d, name="mass_d", description="d-quark mass in GeV")
         self.add_default("DMgDM", 1.0, name="gDM", description="X-Xbar-med coupling")
@@ -120,25 +123,26 @@ class Registry(object):
         self.add_default("Elmass", atlas_common.mass.e, name="mass_e", description="mass of electron in GeV")
         self.add_default("enhancereg", -1, description="enhance reg")
         self.add_default("evenmaxrat", 1, description="speed up upper-bound calculation by taking maximum of identical processes. [1:enabled]")
+        self.add_default("ew_renorm_scheme", -1, description="[-1:use Powheg default]")
         self.add_default("ew", 1, description="EW corrections. (0:disabled; 1:enabled)")
         self.add_default("ewi", 0.01, description="regulator for on-shell divergences")
         self.add_default("ewscheme", 2, description="EW scheme. [1: MZ, MW, Gmu; 2:MZ, MW, alpha]")
-        self.add_default("expm2bb", -1, description="(-1:Powheg default)")
+        self.add_default("expm2bb", -1, description="[-1:use Powheg default]")
         self.add_default("facscfact", 1.0, name="mu_F", description="factorization scale factor: mu_fact = mu_ref * facscfact")
         self.add_default("factsc2min", 2.0, description="value at which the factorization scale is frozen (needed with MiNLO)")
         self.add_default("fakevirt", 0, description="set virtual amplitude proportional to Born amplitude when generating grids - DO NOT USE when generating events. [1:enabled]")
         self.add_default("fakevirtuals", 0, description="generate the grid with fake virtuals. [1:enabled]")
-        self.add_default("fastbtlbound", 1, description="(0:disabled; 1:enabled) use fast btilde bound.")
-        self.add_default("ffltest", -1, description="(-1:Powheg default)")
+        self.add_default("fastbtlbound", 1, description="use fast btilde bound. [0: disabled; 1: enabled]")
+        self.add_default("ffltest", -1, description="[-1:use Powheg default]")
         self.add_default("fin1", -1, description="PDG ID for final state weakinos. [neu10 = 1000022, neu20 = 1000023, neu30 = 1000025, neu40 = 1000035, cha1+ = 1000024, cha2+ = 1000037]")
         self.add_default("fin2", -1, description="PDG ID for final state weakinos. [neu10 = 1000022, neu20 = 1000023, neu30 = 1000025, neu40 = 1000035, cha1+ = 1000024, cha2+ = 1000037]")
-        self.add_default("fixedgrid", -1, description="(-1:use Powheg default)")
-        self.add_default("fixedscale", -1, description="use reference renormalisation and factorisation scales [>=0:enabled]")
-        self.add_default("flg_debug", 0, description="write extra information to LHEF. Breaks PYTHIA showering. [1:enabled]")
+        self.add_default("fixedgrid", -1, description="[-1:use Powheg default]")
+        self.add_default("fixedscale", -1, description="use reference renormalisation and factorisation scales [>=0: enabled]")
+        self.add_default("flg_debug", 0, description="write extra information to LHEF. Breaks PYTHIA showering. [1: enabled]")
         self.add_default("foldcsi", 1, description="number of folds on csi integration. [allowed: 1, 2, 5, 10, 25, 50]")
         self.add_default("foldphi", 1, description="number of folds on phi integration. [allowed: 1, 2, 5, 10, 25, 50]")
         self.add_default("foldy", 1, description="number of folds on y integration. [allowed: 1, 2, 5, 10, 25, 50]")
-        self.add_default("for_reweighting", 0, description="Modify subtraction to reduce reweighting factors (for adding virtual contribution during reweighing). [1:enabled]")
+        self.add_default("for_reweighting", 0, description="run the whole chain without virtual corrections and add these during reweighting. [1:enabled]")
         self.add_default("frensc2min", 2.0, description="value at which the renormalisation scale is frozen (needed with MiNLO)")
         self.add_default("fullphsp", -1, description="enable ISR/FSR phase space parametrization for process with >=2 jet in the ME. [1:enabled]")
         self.add_default("fullrwgt", -1, description="experimental! Must ONLY be used for processes with no Born-level parton radiation. [1:enabled]")
@@ -146,23 +150,23 @@ class Registry(object):
         self.add_default("G_F", atlas_common.G_F, description="Fermi coupling")
         self.add_default("G_mu", atlas_common.G_F, description="Fermi coupling")
         self.add_default("gfermi", atlas_common.G_F, name="G_F", description="Fermi constant")
-        self.add_default("ggproc", -1, description="(-1:Powheg default)")
+        self.add_default("ggproc", -1, description="[-1:use Powheg default]")
         self.add_default("gmu", atlas_common.G_F, name="G_F", description="Fermi constant")
-        self.add_default("gqbproc", -1, description="(-1:Powheg default)")
+        self.add_default("gqbproc", -1, description="[-1:use Powheg default]")
         self.add_default("hdamp", -1, description="apply damping factor (in GeV) for high-pT radiation: h**2/(pt2+h**2). [>0:enabled]")
-        self.add_default("hdecaymode", 0, frozen=True, description="DEPRECATED: this does nothing. It specifies decay mode in Powheg's PYTHIA/HERWIG which we do not use.")
+        self.add_default("hdecaymode", 0, frozen=True, description="UNUSED. This specifies decay mode in Powheg's PYTHIA/HERWIG which we do not use.")
         self.add_default("hdecaywidth", 0, description="Higgs width determination. [0:use hwidth; >0:read total decay width from HDECAY sm.br2 file]")
         self.add_default("hfact", -1, description="apply damping factor for high-pT radiation. [>0:enabled]")
-        self.add_default("higgsfixedwidth", 0, description="(0:running width; 1:fixed width in Breit-Wigner)")
-        self.add_default("Hmass", atlas_common.mass.H, name="mass_H", description="Higgs boson mass in GeV")
+        self.add_default("higgsfixedwidth", 0, description="[0:running width; 1:fixed width in Breit-Wigner]")
         self.add_default("hmass", atlas_common.mass.H, name="mass_H", description="Higgs boson mass in GeV")
-        self.add_default("Hwidth", atlas_common.width.H, name="width_H", description="Higgs boson width in GeV")
+        self.add_default("Hmass", atlas_common.mass.H, name="mass_H", description="Higgs boson mass in GeV")
         self.add_default("hwidth", atlas_common.width.H, name="width_H", description="Higgs boson width in GeV")
-        self.add_default("HWJsudakov", -1, description="(-1:Powheg default)")
+        self.add_default("Hwidth", atlas_common.width.H, name="width_H", description="Higgs boson width in GeV")
+        self.add_default("HWJsudakov", -1, description="[-1:use Powheg default]")
         self.add_default("icsimax", 1, description="number of intervals (<= 10) csi grid to compute upper bounds")
         self.add_default("idDM", 1000022, description="PDG ID of DM particles")
         self.add_default("idvecbos", 24, description="PDG ID for vector boson to be produced")
-        self.add_default("iftopinloop", -1, description="")
+        self.add_default("iftopinloop", -1, description="[-1:use Powheg default]")
         self.add_default("ih1", 1, name="beam_1_type", description="hadron content of beam 1. [(-)1:(anti)proton; (-)2:(anti)neutron; (-)3:(-)pion]")
         self.add_default("ih2", 1, name="beam_2_type", description="hadron content of beam 2. [(-)1:(anti)proton; (-)2:(anti)neutron; (-)3:(-)pion]")
         self.add_default("incomingflavors", 5, description="number of incoming flavours")
@@ -172,27 +176,30 @@ class Registry(object):
         self.add_default("itmx1btl", -1, description="number of iterations for btilde during grid generation")
         self.add_default("itmx1btlbrn", -1, description="number of iterations for Born-level btilde during grid generation")
         self.add_default("itmx1osres", -1, description="number of iterations for initializing the integration grid of on-shell resonances (only required for DSUB_II)")
+        self.add_default("itmx1reg", -1, description="[-1:use Powheg default]")
         self.add_default("itmx1rm", -1, description="number of iterations for initializing the integration grid for the remnant. [<0:use itmx1]")
         self.add_default("itmx2", 1, description="number of iterations for computing the integral and finding upper bound")
         self.add_default("itmx2btl", -1, description="number of iterations for btilde during integral/upper bound finding")
         self.add_default("itmx2btlbrn", -1, description="number of iterations for Born-level btilde during integral/upper bound finding")
         self.add_default("itmx2osres", -1, description="number of iterations for computing the integral of on-shell resonances (only required for DSUB_II)")
+        self.add_default("itmx2reg", -1, description="[-1:use Powheg default]")
         self.add_default("itmx2rm", -1, description="number of iterations for computing the integral and finding upper bound for the remnant. [<0:use itmx2]")
         self.add_default("iupperfsr", -1, description="choice of FSR upper bounding functional form. [<0:use default - usually 2]")
         self.add_default("iupperisr", -1, description="choice of ISR upper bounding functional form. [<0:use default - usually 1]")
         self.add_default("iymax", 1, description="number of intervals (<= 10) in y grid to compute upper bounds")
-        self.add_default("jacsing", -1, description="(-1:use Powheg default)")
+        self.add_default("jacsing", -1, description="[-1:use Powheg default]")
         self.add_default("kappa_ghb", 1.0, description="multiplicative kappa-factor of the Higgs-bottom coupling. ONLY USED FOR REWEIGHTING.")
         self.add_default("kappa_ght", 1.0, description="multiplicative kappa-factor of the Higgs-top coupling. ONLY USED FOR REWEIGHTING.")
         self.add_default("kappa_ghw", 1.0, description="multiplicative kappa-factor of the Higgs-W coupling. ONLY USED FOR REWEIGHTING.")
         self.add_default("kappa_ghz", 1.0, description="multiplicative kappa-factor of the Higgs-Z coupling. ONLY USED FOR REWEIGHTING.")
         self.add_default("kt2minqed", 0.8, description="kt2_rad_min for photon radiation from leptons. [<0: use 0.8]")
-        self.add_default("ktmerging", -1, description="(-1:Powheg default)")
+        self.add_default("ktmerging", -1, description="[-1:use Powheg default]")
         self.add_default("lambda_g", 0, description="Lambda(gamma)")
         self.add_default("Lambda_gam", 0, description="Lambda(gamma)")
         self.add_default("lambda_z", 0, description="Lambda(Z)")
-        self.add_default("largecorrfact", -1, description="(-1:Powheg default)")
-        self.add_default("lepaslight", -1, description="(-1:Powheg default)")
+        self.add_default("lambdaHHH", 1, description="coupling modifier for trilinear Higgs coupling. [SM: 1]")
+        self.add_default("largecorrfact", -1, description="[-1:use Powheg default]")
+        self.add_default("lepaslight", -1, description="[-1:use Powheg default]")
         self.add_default("lhans1", 10800, name="PDF", description="PDF set for hadron 1. [LHAGLUE numbering]")
         self.add_default("lhans2", 10800, name="PDF", description="PDF set for hadron 2. [LHAGLUE numbering]")
         self.add_default("lhapdf6maxsets", 200, description="Maximum number of PDF sets to keep in memory. [<0:default to 10]")
@@ -205,12 +212,12 @@ class Registry(object):
         self.add_default("lhrwgt_group_combine", "none", frozen=True, description="reweighting combination method.")
         self.add_default("lhrwgt_group_name", "nominal", frozen=True, description="group description.")
         self.add_default("lhrwgt_id", 0, frozen=True, description="weight ID.")
-        self.add_default("LOevents", 0, description="(0:disabled; 1:enabled) produce LOPS events (scalup=ptj); in this case bornonly should also be enabled.")
-        self.add_default("m2bb", -1, description="(-1:use Powheg default)")
+        self.add_default("LOevents", 0, description="produce LOPS events (scalup=ptj); in this case bornonly should also be enabled. [0:disabled; 1:enabled]")
+        self.add_default("m2bb", -1, description="[-1:use Powheg default]")
         self.add_default("MadSpin_decays", [], description="decays allowed by MadSpin")
         self.add_default("MadSpin_enabled", True, description="use MadSpin for top decays (only if decays are disabled in Powheg). [False:disabled; True:enabled]")
-        self.add_default("MadSpin_model", "loop_sm-ckm", description="which model to import in MadSpin.")
         self.add_default("MadSpin_mode", "full", description="which spin mode to use in MadSpin. ['full'; 'bridge'; 'none']")
+        self.add_default("MadSpin_model", "loop_sm-ckm", description="which model to import in MadSpin.")
         self.add_default("MadSpin_nFlavours", "4", description="which flavour scheme to use. [4; 5]")
         self.add_default("MadSpin_process", "", description="process that MadSpin is operating on")
         self.add_default("MadSpin_taus_are_leptons", True, description="whether lepton definitions should include taus. [False: do not include taus, True: include taus]")
@@ -220,8 +227,8 @@ class Registry(object):
         self.add_default("mass_d", atlas_common.mass.d, description="d-quark mass in GeV")
         self.add_default("mass_e", atlas_common.mass.e, description="mass of electron in GeV")
         self.add_default("mass_H", atlas_common.mass.H, description="Higgs boson mass in GeV")
-        self.add_default("mass_high", -1, description="(-1:use Powheg default) If set then require M_object < mass_high; otherwise allow internal Powheg computation.")
-        self.add_default("mass_low", -1, description="(-1:use Powheg default) If set then require M_object > mass_low; otherwise allow internal Powheg computation.")
+        self.add_default("mass_high", -1, description="If set then require M_object < mass_high; otherwise allow internal Powheg computation. [-1:use Powheg default]")
+        self.add_default("mass_low", -1, description="If set then require M_object > mass_low; otherwise allow internal Powheg computation. [-1:use Powheg default]")
         self.add_default("mass_mu", atlas_common.mass.mu, description="mass of muon in GeV")
         self.add_default("mass_s", atlas_common.mass.s, description="s-quark mass in GeV")
         self.add_default("mass_t", atlas_common.mass.t, description="top quark mass in GeV")
@@ -229,9 +236,9 @@ class Registry(object):
         self.add_default("mass_u", atlas_common.mass.u, description="u-quark mass in GeV")
         self.add_default("mass_W", atlas_common.mass.W, description="W boson mass in GeV")
         self.add_default("mass_Z", atlas_common.mass.Z, description="Z boson mass in GeV")
-        self.add_default("massivebottom", 1, name="use_massive_b", description="(0:disabled; 1:enabled) enable bottom quark loops")
-        self.add_default("massivetop", 1, name="use_massive_t", description="(0:disabled; 1:enabled) enable top quark loops")
-        self.add_default("massren", 0, description="(0 = OS, 1 = MSBAR, 2 = DRBAR)")
+        self.add_default("massivebottom", 1, name="use_massive_b", description="enable bottom quark loops. [0:disabled; 1:enabled]")
+        self.add_default("massivetop", 1, name="use_massive_t", description="enable top quark loops. [0:disabled; 1:enabled]")
+        self.add_default("massren", 0, description="[0:OS; 1:MSBAR; 2:DRBAR]")
         self.add_default("masswindow_high", -1, description="DEPRECATED: use mass_high instead")
         self.add_default("masswindow_low", -1, description="DEPRECATED: use mass_low instead")
         self.add_default("masswindow", 10.0, description="number of widths around hmass in the BW for an off-shell Higgs boson")
@@ -244,15 +251,15 @@ class Registry(object):
         self.add_default("maxseeds", -1, frozen=True, description="maximum number of seeds to use. [<0:default to 200]")
         self.add_default("mglowidth", -1, description="MG5 LO width")
         self.add_default("min_h_mass", 10., name="mass_H_low", description="Require Higgs boson mass > mass low")
-        self.add_default("min_w_mass", 1.0, name="mass_W_low", description="Require W boson mass > mass low")
         self.add_default("min_W_mass", 1.0, name="mass_W_low", description="Require W boson mass > mass low")
+        self.add_default("min_w_mass", 1.0, name="mass_W_low", description="Require W boson mass > mass low")
         self.add_default("min_z_mass", 1.0, name="mass_Z_low", description="Require Z boson mass > mass low")
         self.add_default("min_Z_mass", 1.0, name="mass_Z_low", description="Require Z boson mass > mass low")
-        self.add_default("minlo_nnll", 1, description="(0:disabled; 1:enabled) enable MiNLO NNLL")
+        self.add_default("minlo_nnll", 1, description="enable MiNLO NNLL. [0:disabled; 1:enabled]")
         self.add_default("minlo", 0, description="use MiNLO (if minlo is set for unsupported processes, Powheg will crash with an 'st_bornorder' error) [1:enabled]")
         self.add_default("minloscfac", 1, description="MiNLO scaling factor:  q2merge=q2merge * (minloscfac)**2")
-        self.add_default("mint_density_map", -1, description="use mint density map")
-        self.add_default("mintupbratlim", -1, description="mint upbr at lim")
+        self.add_default("mint_density_map", -1, description="keep track of the distribution of integrand values while doing the integration (for debugging).")
+        self.add_default("mintupbratlim", -1, description="while computing btilde upper bound, disregard points with btilde/born ratio greater than mintupbratlim")
         self.add_default("mintupbxless", -1, description="mint upbx less")
         self.add_default("mll_gencut", -1, description="cut on the invariant dilepton mass in GeV (minimum 15). Needed to avoid singularities from virtual photon decays to two massless leptons")
         self.add_default("mllmax", 13000, description="minimum invariant mass in GeV of lepton pairs from decay.")
@@ -260,20 +267,23 @@ class Registry(object):
         self.add_default("mockoffshelltop", 0, description="mock off-shell tops")
         self.add_default("model", 0, description="[0 = SM]")
         self.add_default("modept2gamlep", 0, description="pt_rel definition in setlocalscales")
+        self.add_default("msbar", 1, description="1 MSbar renormalization; 0 On-Shell renormalization" )
         self.add_default("MSbarscheme", 1, description="use five-flavour-scheme unless specified otherwise. [0:four-flavour-scheme]")
         self.add_default("Mumass", atlas_common.mass.mu, name="mass_mu", description="mass of muon in GeV")
         self.add_default("ncall1", 100, description="number of calls for initializing the integration grid")
         self.add_default("ncall1btl", -1, description="number of calls btilde (itr1)")
         self.add_default("ncall1btlbrn", -1, description="number of calls btilde born-level (itr1)")
         self.add_default("ncall1osres", -1, description="number of calls for initializing the integration grid of on-shell resonances (only required for DSUB_II)")
+        self.add_default("ncall1reg", -1, description="[-1:use Powheg default]")
         self.add_default("ncall1rm", -1, description="number of calls for initializing the integration grid for the remant. [<0:use ncall1]")
         self.add_default("ncall2", 100, description="number of calls for computing the integral and finding upper bound")
         self.add_default("ncall2btl", -1, description="number of calls btilde (itr2)")
         self.add_default("ncall2btlbrn", -1, description="Number of calls btilde born-level (itr2)")
         self.add_default("ncall2osres", -1, description="number of calls for computing the integral of on-shell resonances (only required for DSUB_II)")
+        self.add_default("ncall2reg", -1, description="[-1:use Powheg default]")
         self.add_default("ncall2rm", -1, description="number of calls for computing the integral and finding upper bound for the remnant. [<0:use ncall2]")
         self.add_default("ncallfrominput", 1, frozen=True, description="read ncall parameters from run card. [1:enabled]")
-        self.add_default("new_damp", -1, description="(-1:Powheg default)")
+        self.add_default("new_damp", -1, description="[-1:use Powheg default]")
         self.add_default("nloformfact", 0, description="include Higgs-specific corrections into GGS and GGP form factor. [1:enabled]")
         self.add_default("nlotestonly", 0, description="do NLO analysis only, using smooth isolation cut. [1:enabled]")
         self.add_default("nlowhich", 0, description="default is 0; set to 1 for no NLO corrections in decay")
@@ -281,96 +291,104 @@ class Registry(object):
         self.add_default("NNLO_reweighting_inputs", collections.OrderedDict(), description="dictionary of labels => (pre-existing) HNNLO output")
         self.add_default("nnlo", -1, description="enable NNLO rescaling. [-1:use Powheg default]")
         self.add_default("no_ew", 0, description="NLO EW corrections. [0:with; 1:without]")
+        self.add_default("no_photon_radiation", -1, description="[-1:use Powheg default]")
         self.add_default("no_strong", 0, description="NLO QCD corrections. [0:with; 1:without]")
         self.add_default("noevents", -1, description="do not generate events. [1:enabled]")
-        self.add_default("nores", 0, description="[1:enabled]")
+        self.add_default("nohad", 0, frozen=True, description="UNUSED. This specifies hadronization in Powheg's PYTHIA/HERWIG which we do not use.")
+        self.add_default("nores", 0, description="disable the resonance treatment. [1: disabled]")
         self.add_default("nospincorr", 0, description="wash out spin correlations. [1:enabled]")
         self.add_default("novirtual", -1, description="ignore virtual contributions. [1:enabled]")
         self.add_default("nubound", 100, description="number of calls to setup upper bounds for radiation")
         self.add_default("numevts", 5500, name="nEvents", description="number of events to be generated")
-        self.add_default("nwidthcutoff", -1, description="(-1:Powheg default)")
+        self.add_default("nwidthcutoff", -1, description="[-1:use Powheg default]")
         self.add_default("offshellscales", -1, description="off-shell scales")
         self.add_default("offshelltop", 1, description="default is now 1; set to zero to do simple on-shell computation")
-        self.add_default("olddij", -1, description="(-1:use Powheg default)")
+        self.add_default("olddij", -1, description="[-1:use Powheg default]")
         self.add_default("olpreset", -1, description="OpenLoops preset")
         self.add_default("olverbose", 0, description="OpenLoops verbosity")
+        self.add_default("onshellhiggs", 1, frozen=True, description="force the Higgs to be on-shell (i.e. gamma_H=0). Required for HV/HVJ. [1:enabled]")
         self.add_default("openloops-stability", 1, name="openloops_stability", description="write OpenLoops stability information to log file.")
         self.add_default("openloopsreal", 1, description="OpenLoops real diagrams [0:disabled]")
         self.add_default("openloopsvirtual", 1, description="OpenLoops virtual diagrams [0:disabled]")
         self.add_default("par_2gsupp", -1, description="[<0:use 1.0]")
         self.add_default("par_diexp", -1, description="ISR singularity exponent (p1). [<0:default to 1.0]")
         self.add_default("par_dijexp", -1, description="FSR singularity exponent (p2). [<0:default to 1.0]")
-        self.add_default("par_fsrtinycsi", -1, description="(-1:use Powheg default)")
-        self.add_default("par_fsrtinyy", -1, description="(-1:use Powheg default)")
-        self.add_default("par_isrtinycsi", -1, description="(-1:use Powheg default)")
-        self.add_default("par_isrtinyy", -1, description="(-1:use Powheg default)")
+        self.add_default("par_fsrtinycsi", -1, description="[-1:use Powheg default]")
+        self.add_default("par_fsrtinyy", -1, description="[-1:use Powheg default]")
+        self.add_default("par_isrtinycsi", -1, description="[-1:use Powheg default]")
+        self.add_default("par_isrtinyy", -1, description="[-1:use Powheg default]")
         self.add_default("parallelstage", -1, description="which stage to perform in parallel. [1...4:specify stage; -1:disabled]")
-        self.add_default("pdfreweight", 1, frozen=True, description="store PDF information. [1:enabled]")
+        self.add_default("pdfreweight", 1, frozen=True, description="store PDF information. Deprecated for processes with XML-reweighting. [1:enabled]")
         self.add_default("Phasespace", 1, name="phasespace", description="phasespace to use. [1:standard; 2:use separate unweighted events from event.total.lhe as input]")
-        self.add_default("photoninduced", -1, description="")
+        self.add_default("photoninduced", -1, description="[-1:use Powheg default]")
         self.add_default("PHOTOS_enabled", 1, description="use PHOTOS for photon radiation. [1:enabled]")
         self.add_default("phsp_Wm", atlas_common.mass.W, name="mass_W", description="W boson mass in GeV")
         self.add_default("phsp_Ww", atlas_common.width.W, name="width_W", description="W boson width in GeV")
         self.add_default("phsp_Zm", atlas_common.mass.Z, name="mass_Z", description="Z boson mass in GeV")
         self.add_default("phsp_Zw", atlas_common.width.Z, name="width_Z", description="Z boson width in GeV")
         self.add_default("phspseparation", 0.5, description="weight for phase space dual-channel sampling")
-        self.add_default("polecheck", -1, description="(-1:Powheg default)")
+        self.add_default("polecheck", -1, description="[-1:use Powheg default]")
+        self.add_default("powheg_top_decays_enabled", True, hidden=True, description="Have the input tops been decayed by Powheg. [False:undecayed, True:decayed]")
         self.add_default("powheg-c-lo", -1, name="powheg_c_lo", description="competition-at-LO scheme. [0:competition; 1:non-competition]")
         self.add_default("powheg-nc", -1, name="powheg_nc", description="competition-at-NLO scheme. [0:competition; 1:non-competition]")
-        self.add_default("powhegv2opt", -1, description="[-1:Powheg default]")
-        self.add_default("powheg_top_decays_enabled", True, hidden=True, description="Have the input tops been decayed by Powheg. [False:undecayed, True:decayed]")
-        self.add_default("psgen", -1, description="(-1:Powheg default)")
-        self.add_default("ptborncut", -1, description="(-1:Powheg default)")
+        self.add_default("powhegv2opt", -1, description="[-1:use Powheg default]")
+        self.add_default("psgen", -1, description="[-1:use Powheg default]")
+        self.add_default("ptborncut", -1, description="[-1:use Powheg default]")
         self.add_default("ptj_gencut", 20, description="generation cut on the jets pT in the phase space generator. Should be used when bornsuppfact is set to 0")
         self.add_default("ptmin_jet", 25, description="jet min pt in GeV for use in analysis code (not relevant here)")
-        self.add_default("ptsqmin", -1, description="minimum pT in GeV for generating emission off light quarks. [<0:default to 0.8]")
+        self.add_default("ptsqmin_em", 1e-6, description="minimum squared transverse momentum for photon radiation. Do NOT use it!")
+        self.add_default("ptsqmin", -1, description="minimum pT in GeV for generating gluon emission off light quarks. [<0:default to 0.8]")
         self.add_default("ptsupp", -1, frozen=True, description="DEPRECATED: only included because PowhegBox checks for it")
-        self.add_default("ptsuppfact", -1, description="(-1:use Powheg default) Born pT suppression factor")
-        self.add_default("ptVhigh", -1, description="(-1:Powheg default)")
-        self.add_default("ptVlow", -1, description="(-1:Powheg default)")
+        self.add_default("ptsuppfact", -1, description="Born pT suppression factor. [-1:use Powheg default]")
+        self.add_default("ptVhigh", -1, description="[-1:use Powheg default]")
+        self.add_default("ptVlow", -1, description="[-1:use Powheg default]")
         self.add_default("pyMEC", 1, description="try this flag to generate the corrections in decays (the default setting)")
-        self.add_default("q2mergefac", -1, description="(-1:Powheg default)")
-        self.add_default("qgproc", -1, description="(-1:Powheg default)")
+        self.add_default("q2mergefac", -1, description="[-1:use Powheg default]")
+        self.add_default("qed_qcd", 2, description="toggle QCD/QED corrections. [0: QCD only; 1: QED only;  2: QED+QCD]")
+        self.add_default("qgproc", -1, description="[-1:use Powheg default]")
         self.add_default("qmass", -1, description="mass of heavy quark in GeV")
-        self.add_default("qqbproc", -1, description="(-1:Powheg default)")
-        self.add_default("qqpproc", -1, description="(-1:Powheg default)")
-        self.add_default("qqproc", -1, description="(-1:Powheg default)")
-        self.add_default("quadrupleprec", -1, description="(-1:Powheg default)")
-        self.add_default("quarkmasseffects", 1, description="(0:disabled; 1:enabled) quark mass effects")
+        self.add_default("qqbproc", -1, description="[-1:use Powheg default]")
+        self.add_default("qqpproc", -1, description="[-1:use Powheg default]")
+        self.add_default("qqproc", -1, description="[-1:use Powheg default]")
+        self.add_default("quadrupleprec", -1, description="[-1:use Powheg default]")
+        self.add_default("quarkmasseffects", 1, description="quark mass effects. [0: disabled; 1: enabled]")
         self.add_default("R_jet", 0.4, description="jet radius for use in internal Powheg analysis code (not relevant here)")
         self.add_default("radregion", -1, description="only generate radiation in the selected singular region (otherwise all regions). [>=0:which region to use]")
-        self.add_default("raisingscales", -1, description="[0:disabled]")
+        self.add_default("raisingscales", -1, description="force CKKW scale to be increasing. [1: enabled]")
         self.add_default("rand1", 0, frozen=True, description="user-initiated random seed. [<0: defaults to 0]")
         self.add_default("rand2", 0, frozen=True, description="user-initiated random seed. [<0: defaults to 0]")
-        self.add_default("rapsuppfact", -1, description="(-1:Powheg default)")
+        self.add_default("rapsuppfact", -1, description="[-1:use Powheg default]")
         self.add_default("regridfix", -1, description="regularization grid is fixed")
         self.add_default("renscfact", 1.0, name="mu_R", description="renormalization scale factor: mu_ren = mu_ref * renscfact")
-        self.add_default("resc_em_alpha", -1, description="")
+        self.add_default("resc_em_alpha", -1, description="[-1:use Powheg default]")
         self.add_default("running_width", 0, description="use running width in propagator. (0:disabled; 1:enabled)")
         self.add_default("runningscale", 1, description="choice for mu_R and mu_F in Bbar integration.")
-        self.add_default("runningscales", 0, description="(0:use fixed factorisation/renormalisation scale; 1:use running scale)")
+        self.add_default("runningscales", 0, description="[0:use fixed factorisation/renormalisation scale; 1:use running scale]")
         self.add_default("runningwidth", 0, description="use running width in propagator. [1:enabled]")
         self.add_default("rwl_add", 0, frozen=True, description="rerun adding additional weights. [1:enabled]")
         self.add_default("rwl_file", "", frozen=True, description="XML file used for reweighting")
         self.add_default("rwl_format_rwgt", 1, frozen=True, description="Use LHE standard for weights instead of Powheg standard. [1:enabled]")
         self.add_default("rwl_group_events", 1000, description="Number of events to group together when running reweighting. [<0:defaults to 1000]")
-        self.add_default("scheme", 1, description="(0:Alpha(0); 1:G_mu) choice for EW NLO scheme")
-        self.add_default("semileptonic", -1, description="(-1:use Powheg default) only accept semileptonic decays")
+        self.add_default("scheme", 1, description="choice for EW NLO scheme. [0:Alpha(0); 1:G_mu]")
+        self.add_default("select_EW_virt", 2, description="EW virtual corrections. [0: none; 1: full; 2: Sudakov approx; 3: full - Sudakov approx]")
+        self.add_default("semileptonic", -1, description="only accept semileptonic decay]. [-1:use Powheg default]")
+        self.add_default("shortlist", -1, description="[-1:use Powheg default]")
+        self.add_default("shortlist_onlyb", -1, description="[-1:use Powheg default]")
         self.add_default("sin2cabibbo", atlas_common.sin2cabibbo, name="sin2cabibbo", description="sin(theta_Cabibbo)^2")
-        self.add_default("skipextratests", -1, description="(-1:use Powheg default)")
+        self.add_default("skipextratests", -1, description="[-1:use Powheg default]")
         self.add_default("SLHA", "'input_parameters.slha'", frozen=True, description="name of the SLHA input-file")
         self.add_default("smartsig", 1, frozen=True, description="remember equal amplitudes. [0:disabled]")
         self.add_default("Smass", atlas_common.mass.s, description="s-quark mass in GeV")
-        self.add_default("smincuts", -1, description="(-1:Powheg-default)")
-        self.add_default("softmismch", 1, frozen=True, description="Do soft step. [0:disabled]")
-        self.add_default("softonly", -1, description="(-1:Powheg-default)")
+        self.add_default("smincuts", -1, description="[-1:use Powheg default]")
+        self.add_default("softmismch", 1, frozen=True, description="do soft step. [0:disabled]")
+        self.add_default("softonly", -1, description="[-1:use Powheg default]")
         self.add_default("softtest", 1, description="check soft limits. [0:disabled]")
         self.add_default("stage2init", -1, description="[1:enabled]")
         self.add_default("sthw2", atlas_common.sin2thetaW, description="sin(theta_W)^2")
         self.add_default("storeinfo_rwgt", 0, frozen=True, description="write out PDF information for reweighting. [0:disabled; 1:enabled]")
-        self.add_default("storemintupb", 1, description="cache cross sections to speed up construction of upper bounding envelope. [1:enabled]")
-        self.add_default("sudakovbb", -1, description="(-1:Powheg-default)")
-        self.add_default("sudmw2mb", -1, description="(-1:Powheg-default)")
+        self.add_default("storemintupb", 1, description="cache cross sections (stage2 btilde calls) to speed up construction of upper bounding envelope. [1:enabled]")
+        self.add_default("sudakovbb", -1, description="[-1:use Powheg default]")
+        self.add_default("sudmw2mb", -1, description="[-1:use Powheg default]")
         self.add_default("sudscalevar", 1, description="also apply scale variation to Sudakov form factors in MiNLO. [0:disabled; 1:enabled]")
         self.add_default("Taumass", atlas_common.mass.tau, name="mass_tau", description="mass of tau in GeV")
         self.add_default("tbardec", 13, description="anti-top quark decay. [11:e-; 13:mu-; 15:tau-; 1:u~ d; 3:c~ s]")
@@ -389,13 +407,14 @@ class Registry(object):
         self.add_default("tdec/wwidth", atlas_common.width.W, name="width_W", description="W boson width in GeV")
         self.add_default("testplots", 0, frozen=True, description="plot NLO and PWHG distributions. [1:enabled]")
         self.add_default("testsuda", 0, frozen=True, description="test Sudakov form factor by numerical integration. [1:enabled]")
-        self.add_default("tevscale", -1, description="W form-factor scale, in TeV (-1:use Powheg default) ")
-        self.add_default("theta_damp", -1, description="(-1:Powheg default)")
-        self.add_default("tmass_phsp", -1, description="")
-        self.add_default("tmass", atlas_common.mass.t, name="mass_t", description="top quark mass in GeV")
+        self.add_default("tevscale", -1, description="W form-factor scale, in TeV . [-1:use Powheg default]")
+        self.add_default("theta_damp", -1, description="[-1:use Powheg default]")
+        self.add_default("tmass_phsp", -1, description="[-1:use Powheg default]")
         self.add_default("Tmass", atlas_common.mass.t, name="mass_t", description="top quark mass in GeV")
+        self.add_default("tmass", atlas_common.mass.t, name="mass_t", description="top quark mass in GeV")
         self.add_default("topdec", 11, description="top quark decay. [11:e+; 13:mu+; 15:tau+; 1:u d~; 3:c s~]")
         self.add_default("topdecaymode", 0, description="top quark decay. 5 digits indicating the maximum number of (e,mu,tau,u,c) allowed in decays")
+        self.add_default("toploop", 1, description="1 include top loop effects; 0 disregard top loop effects" )
         self.add_default("topmass", atlas_common.mass.t, name="mass_t", description="top quark mass in GeV")
         self.add_default("topwidth", atlas_common.width.t, name="width_t", description="top quark width in GeV")
         self.add_default("ttype", 1, description="specify top or anti-top. [1:t; -1:tbar]")
@@ -405,8 +424,8 @@ class Registry(object):
         self.add_default("Umass", atlas_common.mass.u, description="u-quark mass in GeV")
         self.add_default("use-old-grid", 1, frozen=True, description="use old integration grid if available. [0:disabled]")
         self.add_default("use-old-ubound", 1, frozen=True, description="read norm of upper bounding function from pwgubound.dat, if present. [1:enabled]")
-        self.add_default("use-OLP-interface", -1, name="use_OLP_interface", description="(-1:Powheg default)")
-        self.add_default("user_reshists_sep", -1, description="")
+        self.add_default("use-OLP-interface", -1, name="use_OLP_interface", description="[-1:use Powheg default]")
+        self.add_default("user_reshists_sep", -1, description="[-1:use Powheg default]")
         self.add_default("vdecaymode", None, description="vector boson decay mode")
         self.add_default("vdecaymodeW", None, description="W-boson decay mode.")
         self.add_default("vdecaymodeW1", None, description="first W decay mode.")
@@ -415,24 +434,25 @@ class Registry(object):
         self.add_default("vdecaymodew2", None, description="second W decay mode.")
         self.add_default("vdecaymodeZ", None, description="Z-boson decay mode.")
         self.add_default("verytinypars", 0, description="set all ISR/FSR grid parameters to 1e-12. [1:enabled]")
-        self.add_default("virtonly", -1, description="")
-        self.add_default("Vstep", -1, description="(-1:Powheg default)")
+        self.add_default("virtonly", -1, description="[-1:use Powheg default]")
+        self.add_default("Vstep", -1, description="[-1:use Powheg default]")
         self.add_default("wdecaymode", None, description="W-boson decay mode: 5 digits indicating the maximum number of (e,mu,tau,u,c) allowed in decays")
-        self.add_default("whichpwhgevent", -1, description="")
+        self.add_default("whichpwhgevent", -1, description="[-1:use Powheg default]")
         self.add_default("width_H", atlas_common.width.H, description="Higgs boson width in GeV")
         self.add_default("width_t", atlas_common.width.t, description="top quark width in GeV")
         self.add_default("width_W", atlas_common.width.W, name="width_W", description="W boson width in GeV")
         self.add_default("width_Z", atlas_common.width.Z, description="Z boson width in GeV")
         self.add_default("withbtilde", 1, frozen=True, description="do btilde step. [0:disabled]")
         self.add_default("withdamp", -1, description="enable hdamp and bornzerodamp. [1:enabled]")
-        self.add_default("withfluxfactor", -1, description="(-1:Powheg default)")
+        self.add_default("withfluxfactor", -1, description="[-1:use Powheg default]")
         self.add_default("withinterference", 1, description="(0:disabled; 1:enabled) include interference for like flavour charged leptons")
         self.add_default("withnegweights", 1, description="allow negative weights. [1:enabled]")
+        self.add_default("withregular", -1, description="[-1:use Powheg default]")
         self.add_default("withremnants", 1, frozen=True, description="do remnant step. [0:disabled]")
         self.add_default("withsubtr", 1, frozen=True, description="subtract real counterterms. [0:disabled]")
-        self.add_default("withthetacut", -1, description="(-1:Powheg default)")
-        self.add_default("Wmass", atlas_common.mass.W, name="mass_W", description="W boson mass in GeV")
+        self.add_default("withthetacut", -1, description="[-1:use Powheg default]")
         self.add_default("wmass", atlas_common.mass.W, name="mass_W", description="W boson mass in GeV")
+        self.add_default("Wmass", atlas_common.mass.W, name="mass_W", description="W boson mass in GeV")
         self.add_default("WmZevee", 0, hidden=True, description="WZ decay mode: Z->e(+)e(-) W->e(-)nu. [1:enabled]")
         self.add_default("WmZevmumu", 0, hidden=True, description="WZ decay mode: Z->mu(+)mu(-) W->e(-)nu. [1:enabled]")
         self.add_default("WmZevtautau", 0, hidden=True, description="WZ decay mode: Z->tau(+)tau(-) W->e(-)nu. [1:enabled]")
@@ -462,8 +482,8 @@ class Registry(object):
         self.add_default("WpZtauvtautau", 0, hidden=True, description="WZ decay mode: Z->tau(+)tau(-) W->tau(+)nu. [1:enabled]")
         self.add_default("WWevmuv", 0, hidden=True, description="WW decay mode: W->enu W->munu. [1:enabled]")
         self.add_default("WWevtauv", 0, hidden=True, description="WW decay mode: W->enu W->taunu. [1:enabled]")
-        self.add_default("wwidth", atlas_common.width.W, name="width_W", description="W boson width in GeV")
         self.add_default("Wwidth", atlas_common.width.W, name="width_W", description="W boson width in GeV")
+        self.add_default("wwidth", atlas_common.width.W, name="width_W", description="W boson width in GeV")
         self.add_default("WWlvlv", 0, hidden=True, description="WW decay mode: W->lnu W->lnu. [1:enabled]")
         self.add_default("WWlvqq", 0, hidden=True, description="WW decay mode: W->lnu W->qq. [1:enabled]")
         self.add_default("WWmuvtauv", 0, hidden=True, description="WW decay mode: W->munu W->taunu. [1:enabled]")
@@ -487,11 +507,11 @@ class Registry(object):
         self.add_default("xupbound", 1, description="increase upper bound for radiation generation by this factor")
         self.add_default("ZbbNLO", 1, description="correct for non-zero b-mass in Z->bb decays. [0:disabled]")
         self.add_default("zerowidth", 0, description="use on-shell quarks/bosons only. [1:enabled]")
-        self.add_default("zfixedwidth", -1, description="(-1:Powheg default)")
+        self.add_default("zfixedwidth", -1, description="[-1:use Powheg default]")
         self.add_default("zmass", atlas_common.mass.Z, description="Z boson mass in GeV")
         self.add_default("Zmass", atlas_common.mass.Z, name="mass_Z", description="Z boson mass in GeV")
-        self.add_default("Zwidth", atlas_common.width.Z, name="width_Z", description="Z boson width in GeV")
         self.add_default("zwidth", atlas_common.width.Z, name="width_Z", description="Z boson width in GeV")
+        self.add_default("Zwidth", atlas_common.width.Z, name="width_Z", description="Z boson width in GeV")
         self.add_default("ZZeeee", 0, hidden=True, description="ZZ decay mode: Z->ee Z->ee. [1:enabled]")
         self.add_default("ZZeetautau", 0, hidden=True, description="ZZ decay mode: Z->tautau Z->ee. [1:enabled]")
         self.add_default("ZZllll", 0, hidden=True, description="ZZ decay mode: Z->ll Z->ll. [1:enabled]")
diff --git a/Generators/PowhegControl/python/powheg_control.py b/Generators/PowhegControl/python/powheg_control.py
index e4a6dd066da21..4cad9fc858934 100644
--- a/Generators/PowhegControl/python/powheg_control.py
+++ b/Generators/PowhegControl/python/powheg_control.py
@@ -32,17 +32,14 @@ class PowhegControl(object):
         ## Name of output LHE file used by Generate_tf for showering
         self.__output_LHE_file = "PowhegOTF._1.events"
 
-        ## Number of cores to use
-        self.__cores = int(os.environ.pop("ATHENA_PROC_NUMBER", 1))
-
-        # Dictionary of named groups of event weights
+        ## Dictionary of named groups of event weights
         self.__event_weight_groups = collections.OrderedDict()
 
-        # Scheduler to determine algorithm ordering
+        ## Scheduler to determine algorithm ordering
         self.scheduler = Scheduler()
 
         # Load run arguments
-        process_kwargs = {}
+        process_kwargs = {"cores": int(os.environ.pop("ATHENA_PROC_NUMBER", 1))}
         if run_args is None:
             logger.warning("No run arguments found! Using defaults.")
         else:
@@ -75,25 +72,29 @@ class PowhegControl(object):
                 if parameter.is_visible:
                     setattr(self, parameter.name, parameter.value)
 
-        # Add validation of the output file
-        self.scheduler.add("output validator")
+        # Add appropriate directory cleanup for this process
+        self.scheduler.add("directory cleaner", self.process)
 
         # Schedule correct output file naming
         self.scheduler.add("output file renamer", self.__output_LHE_file)
 
-        # Enable parallel mode if AthenaMP mode is enabled
-        if self.__cores == 1:
+        # Enable parallel mode if AthenaMP mode is enabled. Also force multistage mode for RES.
+        if self.process.cores == 1 and self.process.powheg_version != "RES":
             self.scheduler.add("singlecore", self.process)
         else:
-            # Try to modify the transform opts to suppress athenaMP mode
-            logger.info("This job is running with an athenaMP-like whole-node setup, requesting {} cores".format(self.__cores))
-            self.scheduler.add("multicore", self.process, self.__cores)
-            self.process.parameters_by_name("manyseeds")[0].value = 1
-            if hasattr(run_opts, "nprocs"):
-                logger.info("Re-configuring to keep athena running serially while parallelising Powheg generation.")
-                run_opts.nprocs = 0
+            if self.process.cores == 1:
+                logger.info("Configuring this POWHEG-BOX-RES process to run in multistage mode")
             else:
-                logger.warning("Running in multicore mode but no 'nprocs' option was provided!")
+                # Try to modify the transform opts to suppress athenaMP mode
+                logger.info("This job is running with an athenaMP-like whole-node setup, requesting {} cores".format(self.process.cores))
+                if hasattr(run_opts, "nprocs"):
+                    logger.info("Re-configuring to keep athena running serially while parallelising POWHEG-BOX generation.")
+                    run_opts.nprocs = 0
+                else:
+                    logger.warning("Running in multicore mode but no 'nprocs' option was provided!")
+            self.scheduler.add("multicore", self.process)
+            self.scheduler.add("merge output", self.process.cores, self.nEvents)
+            self.process.parameters_by_name("manyseeds")[0].value = 1
 
         # Freeze the interface so that no new attributes can be added
         self.interface_frozen = True
@@ -101,14 +102,20 @@ class PowhegControl(object):
         # Print executable being used
         logger.info("Configured for event generation with: {}".format(self.process.executable))
 
-    def generate(self, use_external_run_card=False, create_run_card_only=False, use_XML_reweighting=True):
+    def generate(self, create_run_card_only=False, save_integration_grids=True, use_external_run_card=False, use_XML_reweighting=True):
         """! Run normal event generation.
 
-        @param use_external_run_card  Use a user-provided run card.
-        @param create_run_card_only   Only generate the run card.
-        @param use_XML_reweighting    Use XML-based reweighting
+        @param create_run_card_only    Only generate the run card.
+        @param save_integration_grids  Save the integration grids for future reuse.
+        @param use_external_run_card   Use a user-provided run card.
+        @param use_XML_reweighting     Use XML-based reweighting.
         """
         self.process.use_XML_reweighting = use_XML_reweighting
+
+        # Schedule integration gridpack creator if requested
+        if save_integration_grids:
+            self.scheduler.add("integration gridpack creator", self.process)
+
         # Run appropriate generation functions
         if not use_external_run_card:
             self.__generate_run_card()
@@ -123,10 +130,9 @@ class PowhegControl(object):
             logger.warning("Only fixed-order distributions can be produced with these settings!")
 
         # Scale-down number of events produced in each run if running in multicore mode
-        if self.__cores > 1:
-            self.scheduler.add("merge output", self.__cores, self.nEvents)
-            logger.info("Preparing to parallelise: running with {} jobs".format(self.__cores))
-            self.process.prepare_to_parallelise(self.__cores)
+        if self.process.cores > 1:
+            logger.info("Preparing to parallelise: running with {} jobs".format(self.process.cores))
+            self.process.prepare_to_parallelise(self.process.cores)
 
         # Print list of configurable parameters for users
         parameters_by_name = [x[1] for x in sorted(dict((p.name.lower(), p) for p in self.process.parameters).items(), key=lambda x: x[0])]
@@ -153,7 +159,7 @@ class PowhegControl(object):
 
         # Write out final runcard
         run_card_path = "{}/powheg.input".format(self.__run_directory)
-        logger.info("Writing Powheg runcard to {}".format(run_card_path))
+        logger.info("Writing POWHEG-BOX runcard to {}".format(run_card_path))
         with open(run_card_path, "w") as f_runcard:
             for parameter in sorted(self.process.parameters, key=lambda p: p.keyword.lower()):
                 if parameter.name == "bornsuppfact" and parameter.value > 0:
@@ -162,24 +168,30 @@ class PowhegControl(object):
                     event_weight_options.append(("negative event weights", "sign"))
                 # PDF variations
                 if parameter.name == "PDF" and isinstance(parameter.value, collections.Iterable):
-                    self.define_event_weight_group("PDF_variation", ["PDF"], combination_method="hessian")
-                    for PDF in map(int, parameter.value[1:]):
-                        self.add_weight_to_group("PDF_variation", "PDF set = {:d}".format(PDF), [PDF])
+                    if "PDF_variation" not in self.__event_weight_groups.keys(): # skip if this group already exists
+                        if len(parameter.value) < 2:
+                            logger.error("Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0] if len(parameter.value) > 0 else "<value>"))
+                            raise TypeError("Use 'PowhegConfig.PDF = {0}' rather than 'PowhegConfig.PDF = [{0}]'".format(parameter.value[0] if len(parameter.value) > 0 else "<value>"))
+                        self.define_event_weight_group("PDF_variation", ["PDF"], combination_method="hessian")
+                        for PDF in map(int, parameter.value[1:]):
+                            self.add_weight_to_group("PDF_variation", "PDF set = {:d}".format(PDF), [PDF])
                 # Scale variations
-                if parameter.name == "mu_F" and isinstance(parameter.value, collections.Iterable):
-                    self.define_event_weight_group("scale_variation", ["mu_R", "mu_F"], combination_method="envelope")
-                    mu_Rs = self.process.parameters_by_name("mu_R")[0].value
-                    mu_Fs = self.process.parameters_by_name("mu_F")[0].value
-                    if len(mu_Rs) != len(mu_Fs):
-                        raise ValueError("Number of mu_R and mu_F variations must be the same.")
-                    for mu_R, mu_F in zip(map(float, mu_Rs[1:]), map(float, mu_Fs[1:])):
-                        self.add_weight_to_group("scale_variation", "muR = {:.2f}, muF = {:.2f}".format(mu_R, mu_F), [mu_R, mu_F])
+                if parameter.name in ["mu_F", "mu_R"] and isinstance(parameter.value, collections.Iterable):
+                    if "scale_variation" not in self.__event_weight_groups.keys(): # skip if this group already exists
+                        mu_Rs = self.process.parameters_by_name("mu_R")[0].value
+                        mu_Fs = self.process.parameters_by_name("mu_F")[0].value
+                        if not isinstance(mu_Rs, collections.Iterable) or not isinstance(mu_Fs, collections.Iterable) or len(mu_Rs) != len(mu_Fs):
+                            logger.error("Number of mu_R and mu_F variations must be the same.")
+                            raise ValueError("Number of mu_R and mu_F variations must be the same.")
+                        self.define_event_weight_group("scale_variation", ["mu_R", "mu_F"], combination_method="envelope")
+                        for mu_R, mu_F in zip(map(float, mu_Rs[1:]), map(float, mu_Fs[1:])):
+                            self.add_weight_to_group("scale_variation", "muR = {:.2f}, muF = {:.2f}".format(mu_R, mu_F), [mu_R, mu_F])
                 f_runcard.write("{}\n".format(parameter))
 
         # Schedule cross-section_calculator
         if len(event_weight_options) > 0:
             self.scheduler.add("cross section calculator")
-            logger.warning("Powheg has been configured to run with {}".format(" and ".join([x[0] for x in event_weight_options])))
+            logger.warning("POWHEG-BOX has been configured to run with {}".format(" and ".join([x[0] for x in event_weight_options])))
             logger.warning("This means that event weights will vary in {}.".format(" and ".join([x[1] for x in event_weight_options])))
             logger.warning("The cross-section passed to the parton shower will be inaccurate.")
             logger.warning("Please use the cross-section printed in the log file before showering begins.")
@@ -304,5 +316,5 @@ class PowhegControl(object):
         # If the interface is frozen then raise an attribute error
         if hasattr(self, "interface_frozen") and self.interface_frozen:
             if not hasattr(self, key):
-                raise AttributeError("This Powheg process has no option '{}'".format(key))
+                raise AttributeError("This POWHEG-BOX process has no option '{}'".format(key))
         object.__setattr__(self, key, value)
diff --git a/Generators/PowhegControl/python/processes/powheg/HWj_EW.py b/Generators/PowhegControl/python/processes/powheg/HWj_EW.py
new file mode 100644
index 0000000000000..ca4870b16f37f
--- /dev/null
+++ b/Generators/PowhegControl/python/processes/powheg/HWj_EW.py
@@ -0,0 +1,189 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import Logging
+from ..powheg_RES import PowhegRES
+
+## Get handle to Athena logging
+logger = Logging.logging.getLogger("PowhegControl")
+
+
+class HWj_EW(PowhegRES):
+    """! Default Powheg configuration for associated Higgs boson and W-boson production plus one jet, with electroweak and quark mass effects.
+
+    Create a configurable object with all applicable Powheg options.
+    @author James Robinson  <james.robinson@cern.ch>
+    """
+
+    def __init__(self, base_directory, **kwargs):
+        """! Constructor: all process options are set here.
+
+        @param base_directory  path to PowhegBox code.
+        @param kwargs          dictionary of arguments from Generate_tf.
+        """
+        super(self.__class__, self).__init__(base_directory, "HWJ_ew", **kwargs)
+
+        ## List of allowed decay modes
+        self.allowed_decay_modes = ["w+ > e+ ve", "w- > e- ve~", "w+ > mu+ vm", "w- > mu- vm~", "w+ > tau+ vt",
+                                    "w- > tau- vt~", "w+ > j j", "w- > j j", "w+ > l+ vl", "w- > l- vl~", "w+ > all",
+                                    "w- > all"]
+
+        # Add all keywords for this process, overriding defaults if required
+        self.add_keyword("allrad", 1)
+        self.add_keyword("alphaem")
+        self.add_keyword("bmass")
+        self.add_keyword("bornktmin", 0.26)
+        self.add_keyword("bornonly")
+        self.add_keyword("bornsuppfact", 0.0)
+        self.add_keyword("bornsuppfactV", 700.0)
+        self.add_keyword("bornzerodamp")
+        self.add_keyword("bottomthr")
+        self.add_keyword("bottomthrpdf")
+        self.add_keyword("btildeborn")
+        self.add_keyword("btildecoll")
+        self.add_keyword("btildereal")
+        self.add_keyword("btildevirt")
+        self.add_keyword("btlscalect")
+        self.add_keyword("btlscalereal")
+        self.add_keyword("charmthr")
+        self.add_keyword("charmthrpdf")
+        self.add_keyword("chklimseed")
+        self.add_keyword("CKM_diagonal")
+        self.add_keyword("clobberlhe")
+        self.add_keyword("colltest")
+        self.add_keyword("comparison_paper")
+        self.add_keyword("compress_lhe")
+        self.add_keyword("compress_upb")
+        self.add_keyword("compute_rwgt")
+        self.add_keyword("doublefsr")
+        self.add_keyword("enhancereg")
+        self.add_keyword("evenmaxrat")
+        self.add_keyword("ew_renorm_scheme")
+        self.add_keyword("facscfact")
+        self.add_keyword("factsc2min")
+        self.add_keyword("fastbtlbound")
+        self.add_keyword("flg_debug")
+        self.add_keyword("foldcsi", 5)
+        self.add_keyword("foldphi", 5)
+        self.add_keyword("foldy", 5)
+        self.add_keyword("for_reweighting")
+        self.add_keyword("frensc2min")
+        self.add_keyword("fullrwgt")
+        self.add_keyword("hdamp")
+        self.add_keyword("hdecaymode")
+        self.add_keyword("hfact")
+        self.add_keyword("hmass")
+        self.add_keyword("icsimax")
+        self.add_keyword("idvecbos", hidden=True)
+        self.add_keyword("ih1")
+        self.add_keyword("ih2")
+        self.add_keyword("itmx1", 2)
+        self.add_keyword("itmx1btl")
+        self.add_keyword("itmx1btlbrn")
+        self.add_keyword("itmx1reg")
+        self.add_keyword("itmx1rm")
+        self.add_keyword("itmx2", 2)
+        self.add_keyword("itmx2btl")
+        self.add_keyword("itmx2btlbrn")
+        self.add_keyword("itmx2reg")
+        self.add_keyword("itmx2rm")
+        self.add_keyword("iupperfsr")
+        self.add_keyword("iupperisr")
+        self.add_keyword("iymax")
+        self.add_keyword("kappa_ghb")
+        self.add_keyword("kappa_ght")
+        self.add_keyword("kappa_ghw")
+        self.add_keyword("lambdaHHH")
+        self.add_keyword("lhans1")
+        self.add_keyword("lhans2")
+        self.add_keyword("LOevents")
+        self.add_keyword("manyseeds")
+        self.add_keyword("max_h_mass", 2.0 * self.parameters_by_name("beam_energy")[0].value)
+        self.add_keyword("max_io_bufsize")
+        self.add_keyword("max_w_mass", 2.0 * self.parameters_by_name("beam_energy")[0].value)
+        self.add_keyword("maxseeds")
+        self.add_keyword("min_h_mass")
+        self.add_keyword("min_w_mass", 10.0)
+        self.add_keyword("minlo_nnll")
+        self.add_keyword("minlo", 1)
+        self.add_keyword("mint_density_map")
+        self.add_keyword("mintupbratlim", 1000)
+        self.add_keyword("ncall1", 25000)
+        self.add_keyword("ncall1btl")
+        self.add_keyword("ncall1btlbrn")
+        self.add_keyword("ncall1reg")
+        self.add_keyword("ncall1rm")
+        self.add_keyword("ncall2", 150000)
+        self.add_keyword("ncall2btl")
+        self.add_keyword("ncall2btlbrn")
+        self.add_keyword("ncall2reg")
+        self.add_keyword("ncall2rm")
+        self.add_keyword("no_photon_radiation")
+        self.add_keyword("noevents")
+        self.add_keyword("nohad")
+        self.add_keyword("nores")
+        self.add_keyword("novirtual")
+        self.add_keyword("nubound", 100000)
+        self.add_keyword("olpreset")
+        self.add_keyword("olverbose")
+        self.add_keyword("onshellhiggs")
+        self.add_keyword("par_2gsupp")
+        self.add_keyword("par_diexp")
+        self.add_keyword("par_dijexp")
+        self.add_keyword("parallelstage")
+        self.add_keyword("pdfreweight")
+        self.add_keyword("ptsupp")
+        self.add_keyword("qed_qcd")
+        self.add_keyword("radregion")
+        self.add_keyword("raisingscales")
+        self.add_keyword("rand1")
+        self.add_keyword("rand2")
+        self.add_keyword("regridfix")
+        self.add_keyword("renscfact")
+        self.add_keyword("runningscales", 3, description="scale at underlying Born level. [0: mh+mw; 1: Ht; 2: sqrt(pt_l1*pt_l2); 3: sqrt((p_H+p_l1+p_l2)^2)]")
+        self.add_keyword("rwl_add")
+        self.add_keyword("rwl_file")
+        self.add_keyword("rwl_format_rwgt")
+        self.add_keyword("rwl_group_events")
+        self.add_keyword("select_EW_virt")
+        self.add_keyword("shortlist")
+        self.add_keyword("smartsig")
+        self.add_keyword("softmismch")
+        self.add_keyword("softonly")
+        self.add_keyword("softtest")
+        self.add_keyword("stage2init")
+        self.add_keyword("storeinfo_rwgt")
+        self.add_keyword("storemintupb")
+        self.add_keyword("sudscalevar")
+        self.add_keyword("testplots")
+        self.add_keyword("testsuda")
+        self.add_keyword("tmass")
+        self.add_keyword("ubexcess_correct")
+        self.add_keyword("ubsigmadetails", 0) # causes crash if enabled
+        self.add_keyword("use-old-grid")
+        self.add_keyword("use-old-ubound")
+        self.add_keyword("user_reshists_sep")
+        self.add_keyword("vdecaymode", self.allowed_decay_modes[0], name="decay_mode", description="W boson decay mode. [{}]".format("; ".join(self.allowed_decay_modes)))
+        self.add_keyword("virtonly")
+        self.add_keyword("whichpwhgevent")
+        self.add_keyword("withbtilde")
+        self.add_keyword("withdamp")
+        self.add_keyword("withnegweights")
+        self.add_keyword("withregular")
+        self.add_keyword("withremnants")
+        self.add_keyword("withsubtr")
+        self.add_keyword("xgriditeration")
+        self.add_keyword("xupbound", 2)
+        self.add_keyword("zerowidth")
+
+        # Add parameter validation functions
+        self.validation_functions.append("validate_decays")
+
+    def validate_decays(self):
+        """! Validate idvecbos and vdecaymode keywords."""
+        self.expose()  # convenience call to simplify syntax
+        self.check_decay_mode(self.decay_mode, self.allowed_decay_modes)
+        # Calculate appropriate decay mode numbers
+        self.parameters_by_keyword("idvecbos")[0].value = 24 * [-1, +1][self.decay_mode.startswith("w+")]
+        __decay_mode_lookup = {"e ve": 1, "mu vm": 2, "tau vt": 3, "j j": 0, "l vl": 11, "all": 10}
+        __decay_mode = self.decay_mode.split("> ")[1].replace("~", "").replace("+", "").replace("-", "")
+        self.parameters_by_keyword("vdecaymode")[0].value = __decay_mode_lookup[__decay_mode]
diff --git a/Generators/PowhegControl/python/processes/powheg/HZj_EW.py b/Generators/PowhegControl/python/processes/powheg/HZj_EW.py
new file mode 100644
index 0000000000000..4049c58ec3064
--- /dev/null
+++ b/Generators/PowhegControl/python/processes/powheg/HZj_EW.py
@@ -0,0 +1,192 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import Logging
+from ..powheg_RES import PowhegRES
+
+## Get handle to Athena logging
+logger = Logging.logging.getLogger("PowhegControl")
+
+
+class HZj_EW(PowhegRES):
+    """! Default Powheg configuration for associated Higgs boson and Z-boson production plus one jet, with electroweak and quark mass effects.
+
+    Create a configurable object with all applicable Powheg options.
+    @author James Robinson  <james.robinson@cern.ch>
+    """
+
+    def __init__(self, base_directory, **kwargs):
+        """! Constructor: all process options are set here.
+
+        @param base_directory  path to PowhegBox code.
+        @param kwargs          dictionary of arguments from Generate_tf.
+        """
+        super(self.__class__, self).__init__(base_directory, "HZJ_ew", **kwargs)
+
+        ## List of allowed decay modes
+        self.allowed_decay_modes = ["z > e+ e-", "z > mu+ mu-", "z > tau+ tau-", "z > ve ve~", "z > vm vm~",
+                                    "z > vt vt~", "z > j j", "z > l l~", "z > v v~", "z > all"]
+
+        # Add all keywords for this process, overriding defaults if required
+        self.add_keyword("allrad", 1)
+        self.add_keyword("alphaem")
+        self.add_keyword("bmass")
+        self.add_keyword("bornktmin", 0.26)
+        self.add_keyword("bornonly")
+        self.add_keyword("bornsuppfact", 0.0)
+        self.add_keyword("bornsuppfactV", 700.0)
+        self.add_keyword("bornzerodamp")
+        self.add_keyword("bottomthr")
+        self.add_keyword("bottomthrpdf")
+        self.add_keyword("btildeborn")
+        self.add_keyword("btildecoll")
+        self.add_keyword("btildereal")
+        self.add_keyword("btildevirt")
+        self.add_keyword("btlscalect")
+        self.add_keyword("btlscalereal")
+        self.add_keyword("charmthr")
+        self.add_keyword("charmthrpdf")
+        self.add_keyword("chklimseed")
+        self.add_keyword("CKM_diagonal")
+        self.add_keyword("clobberlhe")
+        self.add_keyword("colltest")
+        self.add_keyword("comparison_paper")
+        self.add_keyword("compress_lhe")
+        self.add_keyword("compress_upb")
+        self.add_keyword("compute_rwgt")
+        self.add_keyword("doublefsr")
+        self.add_keyword("enhancereg")
+        self.add_keyword("evenmaxrat")
+        self.add_keyword("ew_renorm_scheme")
+        self.add_keyword("facscfact")
+        self.add_keyword("factsc2min")
+        self.add_keyword("fastbtlbound")
+        self.add_keyword("flg_debug")
+        self.add_keyword("foldcsi", 5)
+        self.add_keyword("foldphi", 5)
+        self.add_keyword("foldy", 5)
+        self.add_keyword("for_reweighting")
+        self.add_keyword("frensc2min")
+        self.add_keyword("fullrwgt")
+        self.add_keyword("hdamp")
+        self.add_keyword("hdecaymode")
+        self.add_keyword("hfact")
+        self.add_keyword("hmass")
+        self.add_keyword("icsimax")
+        self.add_keyword("idvecbos", hidden=True)
+        self.add_keyword("ih1")
+        self.add_keyword("ih2")
+        self.add_keyword("itmx1", 2)
+        self.add_keyword("itmx1btl")
+        self.add_keyword("itmx1btlbrn")
+        self.add_keyword("itmx1reg")
+        self.add_keyword("itmx1rm")
+        self.add_keyword("itmx2", 2)
+        self.add_keyword("itmx2btl")
+        self.add_keyword("itmx2btlbrn")
+        self.add_keyword("itmx2reg")
+        self.add_keyword("itmx2rm")
+        self.add_keyword("iupperfsr")
+        self.add_keyword("iupperisr")
+        self.add_keyword("iymax")
+        self.add_keyword("kappa_ghb")
+        self.add_keyword("kappa_ght")
+        self.add_keyword("kappa_ghw")
+        self.add_keyword("lambdaHHH")
+        self.add_keyword("lhans1")
+        self.add_keyword("lhans2")
+        self.add_keyword("LOevents")
+        self.add_keyword("manyseeds")
+        self.add_keyword("max_h_mass", 2.0 * self.parameters_by_name("beam_energy")[0].value)
+        self.add_keyword("max_io_bufsize")
+        self.add_keyword("max_z_mass", 2.0 * self.parameters_by_name("beam_energy")[0].value)
+        self.add_keyword("maxseeds")
+        self.add_keyword("min_h_mass")
+        self.add_keyword("min_z_mass", 10.0)
+        self.add_keyword("minlo_nnll")
+        self.add_keyword("minlo", 1)
+        self.add_keyword("mint_density_map")
+        self.add_keyword("mintupbratlim", 1000)
+        self.add_keyword("ncall1", 25000)
+        self.add_keyword("ncall1btl")
+        self.add_keyword("ncall1btlbrn")
+        self.add_keyword("ncall1reg")
+        self.add_keyword("ncall1rm")
+        self.add_keyword("ncall2", 200000)
+        self.add_keyword("ncall2btl")
+        self.add_keyword("ncall2btlbrn")
+        self.add_keyword("ncall2reg")
+        self.add_keyword("ncall2rm")
+        self.add_keyword("no_photon_radiation")
+        self.add_keyword("noevents")
+        self.add_keyword("nohad")
+        self.add_keyword("nores")
+        self.add_keyword("novirtual")
+        self.add_keyword("nubound", 40000)
+        self.add_keyword("olpreset")
+        self.add_keyword("olverbose")
+        self.add_keyword("onshellhiggs")
+        self.add_keyword("par_2gsupp")
+        self.add_keyword("par_diexp")
+        self.add_keyword("par_dijexp")
+        self.add_keyword("parallelstage")
+        self.add_keyword("pdfreweight")
+        self.add_keyword("ptsupp")
+        self.add_keyword("ptVhigh")
+        self.add_keyword("ptVlow")
+        self.add_keyword("qed_qcd")
+        self.add_keyword("radregion")
+        self.add_keyword("raisingscales")
+        self.add_keyword("rand1")
+        self.add_keyword("rand2")
+        self.add_keyword("regridfix")
+        self.add_keyword("renscfact")
+        self.add_keyword("runningscales", 3, description="scale at underlying Born level. [0: mh+mw; 1: Ht; 2: sqrt(pt_l1*pt_l2); 3: sqrt((p_H+p_l1+p_l2)^2)]")
+        self.add_keyword("rwl_add")
+        self.add_keyword("rwl_file")
+        self.add_keyword("rwl_format_rwgt")
+        self.add_keyword("rwl_group_events")
+        self.add_keyword("select_EW_virt")
+        self.add_keyword("shortlist_onlyb")
+        self.add_keyword("shortlist")
+        self.add_keyword("smartsig")
+        self.add_keyword("softmismch")
+        self.add_keyword("softonly")
+        self.add_keyword("softtest")
+        self.add_keyword("stage2init")
+        self.add_keyword("storeinfo_rwgt")
+        self.add_keyword("storemintupb")
+        self.add_keyword("sudscalevar")
+        self.add_keyword("testplots")
+        self.add_keyword("testsuda")
+        self.add_keyword("tmass")
+        self.add_keyword("ubexcess_correct")
+        self.add_keyword("ubsigmadetails", 0) # causes crash if enabled
+        self.add_keyword("use-old-grid")
+        self.add_keyword("use-old-ubound")
+        self.add_keyword("user_reshists_sep")
+        self.add_keyword("vdecaymode", self.allowed_decay_modes[0], name="decay_mode", description="W boson decay mode. [{}]".format("; ".join(self.allowed_decay_modes)))
+        self.add_keyword("virtonly")
+        self.add_keyword("Vstep")
+        self.add_keyword("whichpwhgevent")
+        self.add_keyword("withbtilde")
+        self.add_keyword("withdamp")
+        self.add_keyword("withnegweights")
+        self.add_keyword("withregular")
+        self.add_keyword("withremnants")
+        self.add_keyword("withsubtr")
+        self.add_keyword("xgriditeration")
+        self.add_keyword("xupbound", 2)
+        self.add_keyword("zerowidth")
+
+        # Add parameter validation functions
+        self.validation_functions.append("validate_decays")
+
+    def validate_decays(self):
+        """! Validate idvecbos and vdecaymode keywords."""
+        self.expose()  # convenience call to simplify syntax
+        self.check_decay_mode(self.decay_mode, self.allowed_decay_modes)
+        # Calculate appropriate decay mode numbers
+        __decay_mode_lookup = {"e+ e-": 1, "mu+ mu-": 2, "tau+ tau-": 3,
+                               "ve ve~": 4, "vm vm~": 5, "vt vt~": 6,
+                               "j j": 0, "l l~": 11, "v v~": 12, "all": 10}
+        self.parameters_by_keyword("vdecaymode")[0].value = __decay_mode_lookup[self.decay_mode.split("> ")[1]]
diff --git a/Generators/PowhegControl/python/processes/powheg/Wy.py b/Generators/PowhegControl/python/processes/powheg/Wy.py
index 29e4b33d6a982..673a4928d1366 100644
--- a/Generators/PowhegControl/python/processes/powheg/Wy.py
+++ b/Generators/PowhegControl/python/processes/powheg/Wy.py
@@ -43,7 +43,7 @@ class Wy(PowhegV2):
         self.add_keyword("btlscalereal")
         self.add_keyword("charmthr")
         self.add_keyword("charmthrpdf")
-        self.add_keyword("check_bad_st2")
+        self.add_keyword("check_bad_st2", 1)
         self.add_keyword("CKM_Vcb")
         self.add_keyword("CKM_Vcd")
         self.add_keyword("CKM_Vcs")
@@ -69,9 +69,9 @@ class Wy(PowhegV2):
         self.add_keyword("fixedgrid")
         self.add_keyword("fixedscale")
         self.add_keyword("flg_debug")
-        self.add_keyword("foldcsi", 1)
-        self.add_keyword("foldphi", 1)
-        self.add_keyword("foldy", 1)
+        self.add_keyword("foldcsi", 5)
+        self.add_keyword("foldphi", 2)
+        self.add_keyword("foldy", 2)
         self.add_keyword("frensc2min", -1)
         self.add_keyword("fullrwgt")
         self.add_keyword("fullrwgtmode")
@@ -107,9 +107,9 @@ class Wy(PowhegV2):
         self.add_keyword("mintupbratlim")
         self.add_keyword("mintupbxless")
         self.add_keyword("modept2gamlep")
-        self.add_keyword("ncall1", 300000)
+        self.add_keyword("ncall1", 250000)
         self.add_keyword("ncall1rm")
-        self.add_keyword("ncall2", 1000000)
+        self.add_keyword("ncall2", 1600000)
         self.add_keyword("ncall2rm")
         self.add_keyword("ncallfrominput")
         self.add_keyword("nlotestonly")
diff --git a/Generators/PowhegControl/python/processes/powheg/__init__.py b/Generators/PowhegControl/python/processes/powheg/__init__.py
index dc0773a9d7cd5..d23e1d5493772 100644
--- a/Generators/PowhegControl/python/processes/powheg/__init__.py
+++ b/Generators/PowhegControl/python/processes/powheg/__init__.py
@@ -1,6 +1,7 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from bb import bb
+from bbH import bbH
 from bblvlv import bblvlv
 from chi0chi0 import chi0chi0
 from chi0chi1 import chi0chi1
@@ -13,7 +14,9 @@ from ggF_HZ import ggF_HZ
 from Hj import Hj
 from Hjj import Hjj
 from HWj import HWj
+from HWj_EW import HWj_EW
 from HZj import HZj
+from HZj_EW import HZj_EW
 from jj import jj
 from jjj import jjj
 from ssWWjj import ssWWjj
diff --git a/Generators/PowhegControl/python/processes/powheg/bbH.py b/Generators/PowhegControl/python/processes/powheg/bbH.py
new file mode 100644
index 0000000000000..44f1053f0acc7
--- /dev/null
+++ b/Generators/PowhegControl/python/processes/powheg/bbH.py
@@ -0,0 +1,133 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import Logging
+from ..powheg_V2 import PowhegV2
+
+## Get handle to Athena logging
+logger = Logging.logging.getLogger("PowhegControl")
+
+
+class bbH(PowhegV2):
+    """! Default Powheg configuration for Higgs boson production in association with top quarks.
+
+    Create a configurable object with all applicable Powheg options.
+
+    @author James Robinson  <james.robinson@cern.ch>
+    """
+
+    def __init__(self, base_directory, **kwargs):
+        """! Constructor: all process options are set here.
+
+        @param base_directory  path to PowhegBox code.
+        @param kwargs          dictionary of arguments from Generate_tf.
+        """
+        super(self.__class__, self).__init__(base_directory, "bbH", **kwargs)
+
+        # Add all keywords for this process, overriding defaults if required
+        self.add_keyword("alphas_from_lhapdf")
+        self.add_keyword("bornktmin")
+        self.add_keyword("bornonly")
+        self.add_keyword("bornsuppfact")
+        self.add_keyword("bornzerodamp")
+        self.add_keyword("bottomthr")
+        self.add_keyword("bottomthrpdf")
+        self.add_keyword("btildeborn")
+        self.add_keyword("btildecoll")
+        self.add_keyword("btildereal")
+        self.add_keyword("btildevirt")
+        self.add_keyword("btlscalect")
+        self.add_keyword("btlscalereal")
+        self.add_keyword("charmthr")
+        self.add_keyword("charmthrpdf")
+        self.add_keyword("check_bad_st2", 1)
+        self.add_keyword("clobberlhe")
+        self.add_keyword("colltest")
+        self.add_keyword("compress_lhe")
+        self.add_keyword("compress_upb")
+        self.add_keyword("compute_rwgt")
+        self.add_keyword("delta_mbbmin")
+        self.add_keyword("doublefsr")
+        self.add_keyword("evenmaxrat")
+        self.add_keyword("facscfact")
+        self.add_keyword("fakevirt")
+        self.add_keyword("fastbtlbound")
+        self.add_keyword("fixedgrid")
+        self.add_keyword("flg_debug")
+        self.add_keyword("foldcsi", 2)
+        self.add_keyword("foldphi", 2)
+        self.add_keyword("foldy", 2)
+        self.add_keyword("fullrwgt")
+        self.add_keyword("fullrwgtmode")
+        self.add_keyword("hdamp")
+        self.add_keyword("hdecaymode")
+        self.add_keyword("hfact")
+        self.add_keyword("hmass")
+        self.add_keyword("hwidth")
+        self.add_keyword("icsimax")
+        self.add_keyword("ih1")
+        self.add_keyword("ih2")
+        self.add_keyword("itmx1", 8)
+        self.add_keyword("itmx1rm")
+        self.add_keyword("itmx2", 4)
+        self.add_keyword("itmx2rm")
+        self.add_keyword("iupperfsr")
+        self.add_keyword("iupperisr")
+        self.add_keyword("iymax")
+        self.add_keyword("lhans1")
+        self.add_keyword("lhans2")
+        self.add_keyword("lhapdf6maxsets")
+        self.add_keyword("lhrwgt_descr")
+        self.add_keyword("lhrwgt_group_combine")
+        self.add_keyword("lhrwgt_group_name")
+        self.add_keyword("lhrwgt_id")
+        self.add_keyword("LOevents")
+        self.add_keyword("manyseeds")
+        self.add_keyword("max_io_bufsize")
+        self.add_keyword("maxseeds")
+        self.add_keyword("minlo")
+        self.add_keyword("mintupbratlim")
+        self.add_keyword("mintupbxless")
+        self.add_keyword("msbar")
+        self.add_keyword("ncall1", 2000000)
+        self.add_keyword("ncall1rm")
+        self.add_keyword("ncall2", 400000)
+        self.add_keyword("ncall2rm")
+        self.add_keyword("ncallfrominput")
+        self.add_keyword("noevents")
+        self.add_keyword("novirtual")
+        self.add_keyword("nubound", 10000)
+        self.add_keyword("olddij")
+        self.add_keyword("par_2gsupp")
+        self.add_keyword("par_diexp")
+        self.add_keyword("par_dijexp")
+        self.add_keyword("parallelstage")
+        self.add_keyword("pdfreweight")
+        self.add_keyword("ptsqmin")
+        self.add_keyword("ptsupp")
+        self.add_keyword("radregion")
+        self.add_keyword("rand1")
+        self.add_keyword("rand2")
+        self.add_keyword("renscfact")
+        self.add_keyword("runningscales")
+        self.add_keyword("rwl_add")
+        self.add_keyword("rwl_file")
+        self.add_keyword("rwl_format_rwgt")
+        self.add_keyword("rwl_group_events")
+        self.add_keyword("skipextratests")
+        self.add_keyword("smartsig")
+        self.add_keyword("softtest")
+        self.add_keyword("stage2init")
+        self.add_keyword("storeinfo_rwgt")
+        self.add_keyword("storemintupb")
+        self.add_keyword("testplots")
+        self.add_keyword("testsuda")
+        self.add_keyword("toploop")
+        self.add_keyword("ubexcess_correct")
+        self.add_keyword("ubsigmadetails")
+        self.add_keyword("use-old-grid")
+        self.add_keyword("use-old-ubound")
+        self.add_keyword("withdamp")
+        self.add_keyword("withnegweights")
+        self.add_keyword("withsubtr")
+        self.add_keyword("xgriditeration")
+        self.add_keyword("xupbound", 2)
diff --git a/Generators/PowhegControl/python/processes/powheg/jj.py b/Generators/PowhegControl/python/processes/powheg/jj.py
index ad81b41387137..540f3e12ee2be 100644
--- a/Generators/PowhegControl/python/processes/powheg/jj.py
+++ b/Generators/PowhegControl/python/processes/powheg/jj.py
@@ -20,6 +20,7 @@ class jj(PowhegV2):
         super(self.__class__, self).__init__(base_directory, "dijet", **kwargs)
 
         # Add all keywords for this process, overriding defaults if required
+        self.add_keyword("alphas_from_lhapdf")
         self.add_keyword("bornktmin", 10.0)
         self.add_keyword("bornonly")
         self.add_keyword("bornsuppfact")
diff --git a/Generators/PowhegControl/python/processes/powheg_RES.py b/Generators/PowhegControl/python/processes/powheg_RES.py
index 19d47e7463056..83f5475363309 100644
--- a/Generators/PowhegControl/python/processes/powheg_RES.py
+++ b/Generators/PowhegControl/python/processes/powheg_RES.py
@@ -1,6 +1,7 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from .powheg_base import PowhegBase
+import glob
 
 
 class PowhegRES(PowhegBase):
@@ -20,7 +21,54 @@ class PowhegRES(PowhegBase):
         """
         super(PowhegRES, self).__init__(base_directory, "POWHEG-BOX-RES", executable_name, **kwargs)
 
+    @property
+    def files_for_cleanup(self):
+        """! Wildcarded list of files created by this process that can be deleted."""
+        return [
+            "allborn_equiv",
+            "FlavRegList",
+            "mint*.top",
+            "parameters.ol",
+            "pwg*.top",
+            "pwg*stat.dat",
+            "pwgboundviolations*.dat",
+            "pwgcounters*.dat",
+            "pwgseeds.dat",
+            "pwhg_checklimits",
+            "sigreal_btl0_equiv",
+            "sigregular_equiv",
+            "sigvirtual_equiv"
+        ]
+
+    @property
+    def integration_file_names(self):
+        """! Wildcarded list of integration files that might be created by this process."""
+        return [
+            "pwg*upb*.dat",
+            "pwg*xgrid*.dat",
+            "pwgfullgrid*.dat",
+            "pwggrid*.dat",
+            "pwgubound*.dat"
+        ]
+
     @property
     def powheg_version(self):
         """! Version of PowhegBox process."""
         return "RES"
+
+    def stage_is_completed(self, stage):
+        """! Set whether the specified POWHEG-BOX generation stage is complete."""
+        if stage == 1:
+            required_files = ["pwg*xgrid*.dat"]
+        elif stage == 2:
+            required_files = ["pwg*upb*.dat", "pwggrid*.dat"]
+        elif stage == 3:
+            required_files = ["pwgfullgrid*.dat", "pwgubound*.dat"]
+        else:
+            return False
+
+        # Check that required files have been found
+        for required_file in required_files:
+            if not glob.glob(required_file):
+                return False
+        return True
diff --git a/Generators/PowhegControl/python/processes/powheg_V1.py b/Generators/PowhegControl/python/processes/powheg_V1.py
index 522ea4b84c1dc..0e5ada70380f2 100644
--- a/Generators/PowhegControl/python/processes/powheg_V1.py
+++ b/Generators/PowhegControl/python/processes/powheg_V1.py
@@ -19,6 +19,31 @@ class PowhegV1(PowhegBase):
         """
         super(PowhegV1, self).__init__(base_directory, "POWHEG-BOX", executable_name, is_reweightable=False, **kwargs)
 
+    @property
+    def files_for_cleanup(self):
+        """! Wildcarded list of files created by this process that can be deleted."""
+        return [
+            "FlavRegList",
+            "pwg*.top",
+            "pwgseeds.dat",
+            "pwgcounters*.dat",
+            "pwgubsigma.dat",
+            "pwhg_checklimits"
+        ]
+
+    @property
+    def integration_file_names(self):
+        """! Wildcarded list of integration files that might be created by this process."""
+        return [
+            "pwgbtildeupb*.dat",
+            "pwgfullgrid.dat",
+            "pwggrid*.dat",
+            "pwgremnupb*.dat",
+            "pwgstat*.dat",
+            "pwgubound*.dat",
+            "pwgxgrid.dat"
+        ]
+
     @property
     def powheg_version(self):
         """! Version of PowhegBox process."""
diff --git a/Generators/PowhegControl/python/processes/powheg_V2.py b/Generators/PowhegControl/python/processes/powheg_V2.py
index 031f7ec4cf8f2..5fd889c543f8b 100644
--- a/Generators/PowhegControl/python/processes/powheg_V2.py
+++ b/Generators/PowhegControl/python/processes/powheg_V2.py
@@ -1,7 +1,7 @@
 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
 
 from .powheg_base import PowhegBase
-
+import glob
 
 class PowhegV2(PowhegBase):
     """! Base class for PowhegBox V2 processes.
@@ -20,6 +20,57 @@ class PowhegV2(PowhegBase):
         """
         super(PowhegV2, self).__init__(base_directory, "POWHEG-BOX-V2", executable_name, **kwargs)
 
+    @property
+    def files_for_cleanup(self):
+        """! Wildcarded list of files created by this process that can be deleted."""
+        return [
+            "bornequiv",
+            "FlavRegList",
+            "fort.18",
+            "mint_upb_btildeupb.top",
+            "mint_upb_remnupb.top",
+            "pwg*.top",
+            "pwg*stat.dat",
+            "pwgboundviolations*.dat",
+            "pwgcounters*.dat",
+            "pwgseeds.dat",
+            "pwgubsigma.dat",
+            "pwhg_checklimits",
+            "realequiv*",
+            "reweighting_input.xml",
+            "virtequiv"
+        ]
+
+    @property
+    def integration_file_names(self):
+        """! Wildcarded list of integration files that might be created by this process."""
+        return [
+            "pwgbtildeupb*.dat",
+            "pwgfullgrid*.dat",
+            "pwggrid*.dat",
+            "pwggridinfo*.dat",
+            "pwgremnupb*.dat",
+            "pwgubound*.dat"
+            "pwgxgrid.dat",
+        ]
+
+    def stage_is_completed(self, stage):
+        """! Set whether the specified POWHEG-BOX generation stage is complete."""
+        if stage == 1:
+            required_files = ["pwg*xg*.dat"]
+        elif stage == 2:
+            required_files = ["pwg*upb*.dat", "pwggrid*.dat"]
+        elif stage == 3:
+            required_files = ["pwgfullgrid*.dat", "pwgubound*.dat"]
+        else:
+            return False
+
+        # Check that required files have been found
+        for required_file in required_files:
+            if not glob.glob(required_file):
+                return False
+        return True
+
     @property
     def powheg_version(self):
         """! Version of PowhegBox process."""
diff --git a/Generators/PowhegControl/python/processes/powheg_base.py b/Generators/PowhegControl/python/processes/powheg_base.py
index 51460c6d2f371..5609279fadb19 100644
--- a/Generators/PowhegControl/python/processes/powheg_base.py
+++ b/Generators/PowhegControl/python/processes/powheg_base.py
@@ -17,7 +17,7 @@ class PowhegBase(Configurable):
     @author James Robinson  <james.robinson@cern.ch>
     """
 
-    def __init__(self, base_directory, version, executable_name, powheg_executable="pwhg_main", is_reweightable=True, **kwargs):
+    def __init__(self, base_directory, version, executable_name, cores, powheg_executable="pwhg_main", is_reweightable=True, **kwargs):
         """! Constructor.
 
         @param base_directory  path to PowhegBox code.
@@ -29,6 +29,9 @@ class PowhegBase(Configurable):
         ## Powheg executable that will be used
         self.executable = os.path.join(base_directory, version, executable_name, powheg_executable)
 
+        ## Number of cores to use
+        self.cores = cores
+
         ## List of additional algorithms to schedule
         self.algorithms = []
 
@@ -65,6 +68,16 @@ class PowhegBase(Configurable):
         else:
             self.externals[alg_or_process.name] = alg_or_process
 
+    @property
+    def files_for_cleanup(self):
+        """! Wildcarded list of files created by this process that can be deleted."""
+        raise AttributeError("Names of unneeded files are not known for this process!")
+
+    @property
+    def integration_file_names(self):
+        """! Wildcarded list of integration files that might be created by this process."""
+        raise AttributeError("Integration file names are not known for this process!")
+
     @property
     def powheg_version(self):
         """! Version of PowhegBox process."""
@@ -82,6 +95,11 @@ class PowhegBase(Configurable):
         # Freeze parallelstage parameters before printing list for user
         [parameter.freeze() for parameter in self.parameters_by_name("parallelstage")]
 
+    def stage_is_completed(self, stage):
+        """! Set whether the specified POWHEG-BOX generation stage is complete."""
+        # Perform manual check to allow re-use of grids in multicore mode
+        return False
+
     def validate_parameters(self):
         """! Validate any parameters which need it before preparing runcard."""
         for function_name in self.validation_functions:
diff --git a/Generators/PowhegControl/share/PowhegControl_HWj_EW_Common.py b/Generators/PowhegControl/share/PowhegControl_HWj_EW_Common.py
new file mode 100644
index 0000000000000..94ffec088b6de
--- /dev/null
+++ b/Generators/PowhegControl/share/PowhegControl_HWj_EW_Common.py
@@ -0,0 +1,4 @@
+import PowhegControl
+transform_runArgs = runArgs if "runArgs" in dir() else None
+transform_opts = opts if "opts" in dir() else None
+PowhegConfig = PowhegControl.PowhegControl(process_name="HWj_EW", run_args=transform_runArgs, run_opts=transform_opts)
diff --git a/Generators/PowhegControl/share/PowhegControl_HZj_EW_Common.py b/Generators/PowhegControl/share/PowhegControl_HZj_EW_Common.py
new file mode 100644
index 0000000000000..f77c58d045551
--- /dev/null
+++ b/Generators/PowhegControl/share/PowhegControl_HZj_EW_Common.py
@@ -0,0 +1,4 @@
+import PowhegControl
+transform_runArgs = runArgs if "runArgs" in dir() else None
+transform_opts = opts if "opts" in dir() else None
+PowhegConfig = PowhegControl.PowhegControl(process_name="HZj_EW", run_args=transform_runArgs, run_opts=transform_opts)
diff --git a/Generators/PowhegControl/share/PowhegControl_Wy_Common.py b/Generators/PowhegControl/share/PowhegControl_Wy_Common.py
index 9250799869b70..ccdd80bec6413 100644
--- a/Generators/PowhegControl/share/PowhegControl_Wy_Common.py
+++ b/Generators/PowhegControl/share/PowhegControl_Wy_Common.py
@@ -1,5 +1,4 @@
 import PowhegControl
 transform_runArgs = runArgs if "runArgs" in dir() else None
 transform_opts = opts if "opts" in dir() else None
-PowhegControl.logger.warning("The Wy process is not currently supported")
-# PowhegConfig = PowhegControl.PowhegControl(process_name="Wy", run_args=transform_runArgs, run_opts=transform_opts)
+PowhegConfig = PowhegControl.PowhegControl(process_name="Wy", run_args=transform_runArgs, run_opts=transform_opts)
-- 
GitLab