diff --git a/CMakeLists.txt b/CMakeLists.txt
index ffab14c..b6a47f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,310 +1,315 @@
 cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 set(CMAKE_LEGACY_CYGWIN_WIN32 0)
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 
 project("HEJ" VERSION 2.0.5 LANGUAGES C CXX)
 
 # Set a default build type if none was specified
 set(default_build_type "RelWithDebInfo")
 
 if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
   message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
   set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
       STRING "Choose the type of build." FORCE)
   # Set the possible values of build type for cmake-gui
   set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
     "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
 endif()
 
 ## Flags for the compiler. No warning allowed.
 if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
 elseif (MSVC)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /EHsc")
 endif()
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 set(CMAKE_CXX_STANDARD 14)
 
 ## Create Version
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
 
 # Get the latest abbreviated commit hash of the working branch
 execute_process(
   COMMAND git rev-parse HEAD
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   OUTPUT_VARIABLE PROJECT_GIT_REVISION
   OUTPUT_STRIP_TRAILING_WHITESPACE
 )
 # Get the current working branch
 execute_process(
   COMMAND git rev-parse --abbrev-ref HEAD
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   OUTPUT_VARIABLE PROJECT_GIT_BRANCH
   OUTPUT_STRIP_TRAILING_WHITESPACE
   )
 
 ## target directories for install
 set(INSTALL_INCLUDE_DIR_BASE include)
 set(INSTALL_INCLUDE_DIR ${INSTALL_INCLUDE_DIR_BASE}/HEJ)
 set(INSTALL_BIN_DIR bin)
 set(INSTALL_LIB_DIR lib)
 set(INSTALL_CONFIG_DIR lib/cmake/HEJ)
 
 ## Template files
 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Templates/Version.hh.in
                 ${PROJECT_BINARY_DIR}/include/HEJ/Version.hh  @ONLY )
 
 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Templates/HEJ-config.cc.in
                 ${PROJECT_BINARY_DIR}/src/bin/HEJ-config.cc  @ONLY )
 
 # Generate CMake config file
 include(CMakePackageConfigHelpers)
 configure_package_config_file(
   cmake/Templates/hej-config.cmake.in
   ${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CONFIG_DIR}/hej-config.cmake
   INSTALL_DESTINATION ${INSTALL_CONFIG_DIR}
   PATH_VARS INSTALL_INCLUDE_DIR_BASE INSTALL_LIB_DIR
   )
 write_basic_package_version_file(
   ${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CONFIG_DIR}/hej-config-version.cmake
   COMPATIBILITY SameMajorVersion
   )
 install(
   FILES ${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CONFIG_DIR}/hej-config.cmake
     ${CMAKE_CURRENT_BINARY_DIR}/${INSTALL_CONFIG_DIR}/hej-config-version.cmake
   DESTINATION ${INSTALL_CONFIG_DIR})
 
 ## Add directories and find dependences
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include)
 
 find_package(fastjet REQUIRED)
 include_directories(${fastjet_INCLUDE_DIRS})
 find_package(CLHEP 2.3 REQUIRED)
 include_directories(${CLHEP_INCLUDE_DIRS})
 find_package(LHAPDF REQUIRED)
 include_directories(${LHAPDF_INCLUDE_DIRS})
 ## Amend unintuitive behaviour of FindBoost.cmake
 ## Priority of BOOST_ROOT over BOOSTROOT matches FindBoost.cmake
 ## at least for cmake 3.12
 if(DEFINED BOOST_ROOT)
   message("BOOST_ROOT set - only looking for Boost in ${BOOST_ROOT}")
   set(Boost_NO_BOOST_CMAKE ON)
   elseif(DEFINED BOOSTROOT)
   message("BOOSTROOT set - only looking for Boost in ${BOOSTROOT}")
   set(Boost_NO_BOOST_CMAKE ON)
 endif()
 find_package(Boost REQUIRED COMPONENTS iostreams)
 include_directories(${Boost_INCLUDE_DIRS})
 find_package(yaml-cpp) # requiring yaml does not work with fedora
 include_directories(${YAML_CPP_INCLUDE_DIR})
 if(${EXCLUDE_HepMC})
   message(STATUS "Skipping HepMC")
   # avoid "unused variable" warning if EXCLUDE_rivet is set by user
   set(EXCLUDE_rivet TRUE)
 else()
   find_package(HepMC 2)
 endif()
 if(${HepMC_FOUND})
   set(
     CMAKE_CXX_FLAGS
     "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_HepMC_VERSION=${HepMC_VERSION_MAJOR}"
     )
   include_directories(${HepMC_INCLUDE_DIRS})
   if(${EXCLUDE_rivet})
     message(STATUS "Skipping rivet")
   else()
     find_package(rivet)
   endif()
   if(${rivet_FOUND})
     include_directories(${rivet_INCLUDE_DIRS})
     set(
       CMAKE_CXX_FLAGS
       "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_RIVET"
       )
   endif()
 endif()
 if(${EXCLUDE_QCDloop})
   message(STATUS "Skipping QCDloop")
 else()
   find_package(QCDloop 2)
 endif()
 if(${QCDloop_FOUND})
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_QCDLOOP")
   include_directories(SYSTEM ${QCDloop_INCLUDE_DIRS})
 endif()
 if(${EXCLUDE_HighFive})
   message(STATUS "Skipping HighFive")
 else()
   find_package(HighFive QUIET)
   find_package_handle_standard_args( HighFive CONFIG_MODE )
 endif()
 if(${HighFive_FOUND})
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_HDF5")
   include_directories($<TARGET_PROPERTY:HighFive,INTERFACE_INCLUDE_DIRECTORIES>)
 endif()
 
 add_subdirectory(src)
 
 ## define executable
 add_executable(HEJ src/bin/HEJ.cc)
 
 ## link libraries
 target_link_libraries(HEJ hejlib)
 
 add_executable(HEJ-config src/bin/HEJ-config.cc)
 
-file(GLOB hej_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/HEJ/*.hh ${PROJECT_BINARY_DIR}/include/HEJ/*.hh)
+file(GLOB hej_headers
+  ${CMAKE_CURRENT_SOURCE_DIR}/include/HEJ/*.hh
+  ${PROJECT_BINARY_DIR}/include/HEJ/*.hh
+)
+file(GLOB hej_detail_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/HEJ/detail/*.hh)
 file(GLOB lhef_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/LHEF/*.h)
 install(FILES ${hej_headers} DESTINATION ${INSTALL_INCLUDE_DIR})
-install(FILES ${lhef_headers} DESTINATION include/LHEF/)
+install(FILES ${hej_detail_headers} DESTINATION ${INSTALL_INCLUDE_DIR}/detail/)
+install(FILES ${lhef_headers} DESTINATION ${INSTALL_INCLUDE_DIR_BASE}/LHEF/)
 install(TARGETS HEJ HEJ-config DESTINATION ${INSTALL_BIN_DIR})
 
 ## tests
 enable_testing()
 set(tst_dir "${CMAKE_CURRENT_SOURCE_DIR}/t")
 add_executable(test_classify ${tst_dir}/test_classify.cc)
 add_executable(test_psp ${tst_dir}/test_psp.cc)
 add_executable(test_ME_generic ${tst_dir}/test_ME_generic.cc)
 add_executable(check_res ${tst_dir}/check_res.cc)
 add_executable(check_lhe ${tst_dir}/check_lhe.cc)
 add_library(scales SHARED ${tst_dir}/scales.cc)
 add_executable(test_scale_import ${tst_dir}/test_scale_import)
 add_executable(test_descriptions ${tst_dir}/test_descriptions)
 add_executable(test_scale_arithmetics ${tst_dir}/test_scale_arithmetics)
 add_executable(test_parameters ${tst_dir}/test_parameters)
 add_executable(test_colours ${tst_dir}/test_colours)
 target_link_libraries(test_classify hejlib)
 target_link_libraries(test_psp hejlib)
 target_link_libraries(test_ME_generic hejlib)
 target_link_libraries(check_res hejlib)
 target_link_libraries(check_lhe hejlib)
 target_link_libraries(test_scale_import hejlib)
 target_link_libraries(test_descriptions hejlib)
 target_link_libraries(test_scale_arithmetics hejlib)
 target_link_libraries(test_parameters hejlib)
 target_link_libraries(test_colours hejlib)
 
 ## add tests
 add_test(
   NAME t_classify
   COMMAND test_classify ${tst_dir}/classify.lhe.gz
   )
 add_test(
   NAME t_psp
   COMMAND test_psp ${tst_dir}/psp_gen.lhe.gz
   )
 set(tst_ME_data_dir "${tst_dir}/ME_data")
 add_test(
   NAME t_ME_j
   COMMAND test_ME_generic ${tst_ME_data_dir}/config_mtinf.yml ${tst_ME_data_dir}/ME_jets_tree.dat ${tst_ME_data_dir}/PSP_jets.lhe.gz
   )
 add_test(
   NAME t_ME_h
   COMMAND test_ME_generic ${tst_ME_data_dir}/config_mtinf.yml ${tst_ME_data_dir}/ME_h_mtinf_tree.dat ${tst_ME_data_dir}/PSP_h.lhe.gz
   )
 # add_test(
 #   NAME t_ME_w
 #   COMMAND test_ME_generic ${tst_ME_data_dir}/config_w_ME.yml ${tst_ME_data_dir}/ME_w_tree.dat ${tst_ME_data_dir}/PSP_w.lhe.gz
 #   )
 add_test(
   NAME t_ME_w_FKL
   COMMAND test_ME_generic ${tst_ME_data_dir}/config_w_ME.yml ${tst_ME_data_dir}/ME_w_FKL_tree.dat ${tst_ME_data_dir}/PSP_w_FKL.lhe.gz
   )
 add_test(
   NAME t_ME_w_FKL_virt
   COMMAND test_ME_generic ${tst_ME_data_dir}/config_w_ME.yml ${tst_ME_data_dir}/ME_w_FKL_virt.dat ${tst_ME_data_dir}/PSP_w_FKL.lhe.gz
   )
 if(${QCDloop_FOUND})
   add_test(
     NAME t_ME_h_mt
     COMMAND test_ME_generic ${tst_ME_data_dir}/config_mt.yml ${tst_ME_data_dir}/ME_h_mt_tree.dat ${tst_ME_data_dir}/PSP_h.lhe.gz
     )
   add_test(
     NAME t_ME_h_mtmb
     COMMAND test_ME_generic ${tst_ME_data_dir}/config_mtmb.yml ${tst_ME_data_dir}/ME_h_mtmb_tree.dat ${tst_ME_data_dir}/PSP_h.lhe.gz
     )
 endif()
 add_test(
   NAME t_2j
   COMMAND check_res ${tst_dir}/2j.lhe.gz 3.49391e+07 419684
   )
 add_test(
   NAME t_3j
   COMMAND check_res ${tst_dir}/3j.lhe.gz  2.37902e+06 25746.6
   )
 add_test(
   NAME t_4j
   COMMAND check_res ${tst_dir}/4j.lhe.gz  603713 72822.6
   )
 add_test(
   NAME t_h_3j
   COMMAND check_res ${tst_dir}/h_3j.lhe.gz 0.821622 0.0220334
   )
 add_test(
   NAME t_h_3j_uno
   COMMAND check_res ${tst_dir}/h_3j_uno.lhe.gz 0.0261968 0.000341549 uno
   )
 if(${HepMC_FOUND})
   file(READ "${tst_dir}/jet_config.yml" config)
   file(WRITE "${tst_dir}/jet_config_withHepMC.yml" "${config}  - tst.hepmc")
   if(${rivet_FOUND})
     file(READ "${tst_dir}/jet_config_withHepMC.yml" config)
     file(WRITE "${tst_dir}/jet_config_withRivet.yml" "${config}\n\nanalysis:\n  rivet: MC_XS\n  output: tst")
     add_test(
       NAME t_main
       COMMAND HEJ  ${tst_dir}/jet_config_withRivet.yml ${tst_dir}/2j.lhe.gz
       )
   else()
     add_test(
       NAME t_main
       COMMAND HEJ  ${tst_dir}/jet_config_withHepMC.yml ${tst_dir}/2j.lhe.gz
       )
   endif()
   if(${HepMC_VERSION_MAJOR} GREATER 2)
     add_executable(check_hepmc ${tst_dir}/check_hepmc.cc)
     target_link_libraries(check_hepmc hejlib)
     add_test(
       NAME t_hepmc
       COMMAND check_hepmc tst.hepmc
       )
   endif()
 else()
   add_test(
     NAME t_main
     COMMAND HEJ  ${tst_dir}/jet_config.yml ${tst_dir}/2j.lhe.gz
     )
 endif()
 add_test(
   NAME t_lhe
   COMMAND check_lhe tst.lhe
   )
 add_test(
   NAME t_scale_import
   COMMAND test_scale_import ${tst_dir}/jet_config_with_import.yml
   )
 add_test(
   NAME t_descriptions
   COMMAND test_descriptions
   )
 add_test(
   NAME t_scale_arithmetics
   COMMAND test_scale_arithmetics ${tst_dir}/jet_config.yml ${tst_dir}/2j.lhe.gz
   )
 add_test(
   NAME test_parameters
   COMMAND test_parameters
   )
 add_test(
   NAME t_colour_flow
   COMMAND test_colours
   )
 if(${HighFive_FOUND})
   add_executable(test_hdf5 ${tst_dir}/test_hdf5.cc)
   target_link_libraries(test_hdf5 hejlib)
   add_test(
     NAME t_hdf5
     COMMAND test_hdf5 ${tst_dir}/Wm9-g4-repack.hdf5
     )
 endif()
diff --git a/doc/developer_manual/developer_manual.tex b/doc/developer_manual/developer_manual.tex
index cf857c3..74c8dcd 100644
--- a/doc/developer_manual/developer_manual.tex
+++ b/doc/developer_manual/developer_manual.tex
@@ -1,1544 +1,1545 @@
 \documentclass[a4paper,11pt]{article}
 
 \usepackage{fourier}
 \usepackage[T1]{fontenc}
 \usepackage{microtype}
 \usepackage{geometry}
 \usepackage{enumitem}
 \setlist[description]{leftmargin=\parindent,labelindent=\parindent}
 \usepackage{amsmath}
 \usepackage{amssymb}
 \usepackage[utf8x]{inputenc}
 \usepackage{graphicx}
 \usepackage{xcolor}
 \usepackage{todonotes}
 \usepackage{listings}
 \usepackage{xspace}
 \usepackage{tikz}
 \usepackage{subcaption}
 \usetikzlibrary{arrows.meta}
 \usetikzlibrary{shapes}
 \usetikzlibrary{calc}
 \usepackage[colorlinks,linkcolor={blue!50!black}]{hyperref}
 \graphicspath{{build/figures/}{figures/}}
 \emergencystretch \hsize
 
 \newcommand{\HEJ}{{\tt HEJ}\xspace}
 \newcommand{\HIGHEJ}{\emph{High Energy Jets}\xspace}
 \newcommand{\cmake}{\href{https://cmake.org/}{cmake}\xspace}
 \newcommand{\html}{\href{https://www.w3.org/html/}{html}\xspace}
 \newcommand{\YAML}{\href{http://yaml.org/}{YAML}\xspace}
 \newcommand{\QCDloop}{\href{https://github.com/scarrazza/qcdloop}{QCDloop}\xspace}
 
 \newcommand{\as}{\alpha_s}
 \DeclareRobustCommand{\mathgraphics}[1]{\vcenter{\hbox{\includegraphics{#1}}}}
 \def\spa#1.#2{\left\langle#1\,#2\right\rangle}
 \def\spb#1.#2{\left[#1\,#2\right]} \def\spaa#1.#2.#3{\langle\mskip-1mu{#1} |
   #2 | {#3}\mskip-1mu\rangle} \def\spbb#1.#2.#3{[\mskip-1mu{#1} | #2 |
   {#3}\mskip-1mu]} \def\spab#1.#2.#3{\langle\mskip-1mu{#1} | #2 |
   {#3}\mskip-1mu\rangle} \def\spba#1.#2.#3{\langle\mskip-1mu{#1}^+ | #2 |
   {#3}^+\mskip-1mu\rangle} \def\spav#1.#2.#3{\|\mskip-1mu{#1} | #2 |
   {#3}\mskip-1mu\|^2} \def\jc#1.#2.#3{j^{#1}_{#2#3}}
 
 \definecolor{darkgreen}{rgb}{0,0.4,0}
 \lstset{ %
  backgroundcolor=\color{lightgray},   % choose the background color; you must add \usepackage{color} or \usepackage{xcolor}
  basicstyle=\footnotesize\usefont{T1}{DejaVuSansMono-TLF}{m}{n},        % the size of the fonts that are used for the code
  breakatwhitespace=false,         % sets if automatic breaks should only happen at whitespace
  breaklines=false,                % sets automatic line breaking
  captionpos=t,                    % sets the caption-position to bottom
  commentstyle=\color{red},        % comment style
  deletekeywords={...},            % if you want to delete keywords from the given language
  escapeinside={\%*}{*)},          % if you want to add LaTeX within your code
  extendedchars=true,              % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8
  frame=false,                     % adds a frame around the code
  keepspaces=true,                 % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible)
  keywordstyle=\color{blue},       % keyword style
  otherkeywords={},                 % if you want to add more keywords to the set
  numbers=none,                    % where to put the line-numbers; possible values are (none, left, right)
  numbersep=5pt,                   % how far the line-numbers are from the code
  rulecolor=\color{black},         % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here))
  showspaces=false,                % show spaces everywhere adding particular underscores; it overrides 'showstringspaces'
  showstringspaces=false,          % underline spaces within strings only
  showtabs=false,                  % show tabs within strings adding particular underscores
  stepnumber=2,                    % the step between two line-numbers. If it's 1, each line will be numbered
  stringstyle=\color{gray},         % string literal style
  tabsize=2,                    % sets default tabsize to 2 spaces
  title=\lstname,
  emph={},
  emphstyle=\color{darkgreen}
 }
 
 \begin{document}
 
 \tikzstyle{mynode}=[rectangle split,rectangle split parts=2, draw,rectangle split part fill={lightgray, none}]
 
 
 \title{HEJ 2 developer manual}
 \author{}
 \maketitle
 \tableofcontents
 
 \newpage
 
 \section{Overview}
 \label{sec:overview}
 
 HEJ 2 is a C++ program and library implementing an algorithm to
 apply \HIGHEJ resummation~\cite{Andersen:2008ue,Andersen:2008gc} to
 pre-generated fixed-order events. This document is intended to give an
 overview over the concepts and structure of this implementation.
 
 \subsection{Project structure}
 \label{sec:project}
 
 HEJ 2 is developed under the \href{https://git-scm.com/}{git}
 version control system. The main repository is on the IPPP
 \href{https://gitlab.com/}{gitlab} server under
 \url{https://gitlab.dur.scotgrid.ac.uk/hej/hej}. To get a local
 copy, get an account on the gitlab server and use
 \begin{lstlisting}[language=sh,caption={}]
   git clone git@gitlab.dur.scotgrid.ac.uk:hej/hej.git
 \end{lstlisting}
 This should create a directory \texttt{hej} with the following
 contents:
 \begin{description}
 \item[doc:] Contains additional documentation, see section~\ref{sec:doc}.
 \item[include:] Contains the C++ header files.
 \item[src:] Contains the C++ source files.
 \item[t:] Contains the source code for the automated tests.
 \item[CMakeLists.txt:] Configuration file for the \cmake build
   system. See section~\ref{sec:cmake}.
 \item[cmake:] Auxiliary files for \cmake. This includes modules for
   finding installed software in \texttt{cmake/Modules} and templates for
   code generation during the build process in \texttt{cmake/Templates}.
 \item[config.yml:] Sample configuration file for running HEJ 2.
 \item[FixedOrderGen:] Contains the code for the fixed-order generator,
   see section~\ref{sec:HEJFOG}.
 \end{description}
 In the following all paths are given relative to the
 \texttt{hej} directory.
 
 \subsection{Documentation}
 \label{sec:doc}
 
 The \texttt{doc} directory contains user documentation in
 \texttt{doc/sphinx} and the configuration to generate source code
 documentation in \texttt{doc/doxygen}.
 
 The user documentation explains how to install and run HEJ 2. The
 format is
 \href{http://docutils.sourceforge.net/rst.html}{reStructuredText}, which
 is mostly human-readable. Other formats, like \html, can be generated with the
 \href{http://www.sphinx-doc.org/en/master/}{sphinx} generator with
 \begin{lstlisting}[language=sh,caption={}]
   make html
 \end{lstlisting}
 
 
 To document the source code we use
 \href{https://www.stack.nl/~dimitri/doxygen/}{doxygen}. To generate
 \html documentation, use the command
 \begin{lstlisting}[language=sh,caption={}]
   doxygen Doxyfile
 \end{lstlisting}
 in the \texttt{doc/doxygen} directory.
 
 \subsection{Build system}
 \label{sec:cmake}
 
 For the most part, HEJ 2 is a library providing classes and
 functions that can be used to add resummation to fixed-order events. In
 addition, there is a relatively small executable program leveraging this
 library to read in events from an input file and produce resummation
 events. Both the library and the program are built and installed with
 the help of \cmake.
 Debug information can be turned on by using
 \begin{lstlisting}[language=sh,caption={}]
   cmake base/directory -DCMAKE_BUILD_TYPE=Debug
   make install
 \end{lstlisting}
 This facilitates the use of debuggers like \href{https://www.gnu.org/software/gdb/}{gdb}.
 
 The main \cmake configuration file is \texttt{CMakeLists.txt}. It defines the
 compiler flags, software prerequisites, header and source files used to
 build HEJ 2, and the automated tests.
 \texttt{cmake/Modules} contains module files that help with the
 detection of the software prerequisites and \texttt{cmake/Templates}
 template files for the automatic generation of header and
 source files. For example, this allows to only keep the version
 information in one central location (\texttt{CMakeLists.txt}) and
 automatically generate a header file from the template \texttt{Version.hh.in} to propagate this to the C++ code.
 
 \subsection{General coding guidelines}
 \label{sec:notes}
 
 The goal is to make the HEJ 2 code well-structured and
 readable. Here are a number of guidelines to this end.
 
 \begin{description}
 \item[Observe the boy scout rule.] Always leave the code cleaner
   than how you found it. Ugly hacks can be useful for testing, but
   shouldn't make their way into the main branch.
 \item[Ask if something is unclear.] Often there is a good reason why
   code is written the way it is. Sometimes that reason is only obvious to
   the original author (use \lstinline!git blame! to find them), in which
   case they should be poked to add a comment. Sometimes there is no good
   reason, but nobody has had the time to come up with something better,
   yet. In some places the code might just be bad.
 \item[Don't break tests.] There are a number of tests in the \texttt{t}
   directory, which can be run with \lstinline!make test!. Ideally, all
   tests should run successfully in each git revision. If your latest
   commit broke a test and you haven't pushed to the central repository
   yet, you can fix it with \lstinline!git commit --amend!. If an earlier
   local commit broke a test, you can use \lstinline!git rebase -i! if
   you feel confident. Additionally each \lstinline!git push! is also
   automatically tested via the GitLab CI (see appendix~\ref{sec:gitlabCI}).
 \item[Test your new code.] When you add some new functionality, also add an
   automated test. This can be useful even if you don't know the
   ``correct'' result because it prevents the code from changing its behaviour
   silently in the future. \href{http://www.valgrind.org/}{valgrind} is a
   very useful tool to detect potential memory leaks.
 \item[Stick to the coding style.] It is somewhat easier to read code
   that has a uniform coding and indentation style. We don't have a
   strict style, but it helps if your code looks similar to what is
   already there.
 \end{description}
 
 \section{Program flow}
 \label{sec:flow}
 
 A run of the HEJ 2 program has three stages: initialisation,
 event processing, and cleanup. The following sections outline these
 stages and their relations to the various classes and functions in the
 code. Unless denoted otherwise, all classes and functions are part of
 the \lstinline!HEJ! namespace. The code for the HEJ 2 program is
 in \texttt{src/bin/HEJ.cc}, all other code comprises the HEJ 2
 library. Classes and free functions are usually implemented in header
 and source files with a corresponding name, i.e. the code for
 \lstinline!MyClass! can usually be found in
 \texttt{include/HEJ/MyClass.hh} and \texttt{src/MyClass.cc}.
 
 \subsection{Initialisation}
 \label{sec:init}
 
 The first step is to load and parse the \YAML configuration file. The
 entry point for this is the \lstinline!load_config! function and the
 related code can be found in \texttt{include/HEJ/YAMLreader.hh},
 \texttt{include/HEJ/config.hh} and the corresponding \texttt{.cc} files
 in the \texttt{src} directory. The implementation is based on the
 \href{https://github.com/jbeder/yaml-cpp}{yaml-cpp} library.
 The \lstinline!load_config! function returns a \lstinline!Config! object
 containing all settings. To detect potential mistakes as early as
 possible, we throw an exception whenever one of the following errors
 occurs:
 \begin{itemize}
 \item There is an unknown option in the \YAML file.
 \item A setting is invalid, for example a string is given where a number
   would be expected.
 \item An option value is not set.
 \end{itemize}
 The third rule is sometimes relaxed for ``advanced'' settings with an
 obvious default, like for importing custom scales or analyses.
 
 The information stored in the \lstinline!Config! object is then used to
 initialise various objects required for the event processing stage
 described in section~\ref{sec:processing}. First, the
 \lstinline!get_analysis! function creates an object that inherits from
 the \lstinline!Analysis! interface.\footnote{In the context of C++ the
 proper technical expression is ``pure abstract class''.} Using an
 interface allows us to decide the concrete type of the analysis at run
 time instead of having to make a compile-time decision. Depending on the
 settings, \lstinline!get_analysis! creates either a user-defined
 analysis loaded from an external library (see the user documentation
 \url{https://hej.web.cern.ch/HEJ/doc/current/user/}) or the default \lstinline!EmptyAnalysis!, which does
 nothing.
 
 Together with a number of further objects, whose roles are described in
 section~\ref{sec:processing}, we also initialise the global random
 number generator. We again use an interface to defer deciding the
 concrete type until the program is actually run. Currently, we support the
 \href{https://mixmax.hepforge.org/}{MIXMAX}
 (\texttt{include/HEJ/Mixmax.hh}) and Ranlux64
 (\texttt{include/HEJ/Ranlux64.hh}) random number generators, both are provided
 by \href{http://proj-clhep.web.cern.ch/}{CLHEP}.
 
 We also set up a \lstinline!HEJ::EventReader! object for reading events
 either in the the Les Houches event file format~\cite{Alwall:2006yp} or
 an \href{https://www.hdfgroup.org/}{HDF5}-based
 format~\cite{Hoeche:2019rti}. To allow making the decision at run time,
 \lstinline!HEJ::EventReader! is an abstract base class defined in
 \texttt{include/HEJ/EventReader.hh} and the implementations of the
 derived classes are in \texttt{include/HEJ/LesHouchesReader.hh},
 \texttt{include/HEJ/HDF5Reader.hh} and the corresponding \texttt{.cc}
 source files in the \texttt{src} directory. The
 \lstinline!LesHouchesReader! leverages
 \href{http://home.thep.lu.se/~leif/LHEF/}{\texttt{include/LHEF/LHEF.h}}. A
 small wrapper around the
 \href{https://www.boost.org/doc/libs/1_67_0/libs/iostreams/doc/index.html}{boost
 iostreams} library allows us to also read event files compressed with
 \href{https://www.gnu.org/software/gzip/}{gzip}. The wrapper code is in
 \texttt{include/HEJ/stream.hh} and the \texttt{src/stream.cc}.
 
 \subsection{Event processing}
 \label{sec:processing}
 
 In the second stage events are continously read from the event
 file. After jet clustering, a number of corresponding resummation events
 are generated for each input event and fed into the analysis and a
 number of output files. The roles of various classes and functions are
 illustrated in the following flow chart:
 \begin{center}
   \begin{tikzpicture}[node distance=2cm and 5mm]
     \node (reader) [mynode]
     {\lstinline!EventReader::read_event!\nodepart{second}{read event}};
     \node
     (data) [mynode,below=of reader]
     {\lstinline!Event::EventData! constructor\nodepart{second}{convert to \HEJ object}};
     \node
     (cluster) [mynode,below=of data]
     {\lstinline!Event::EventData::cluster!\nodepart{second}{cluster jets \&
     classify \lstinline!EventType!}};
     \node
     (resum) [mynode,below=of cluster]
     {\lstinline!EventReweighter::reweight!\nodepart{second}{perform resummation}};
     \node
     (cut) [mynode,below=of resum]
     {\lstinline!Analysis::pass_cuts!\nodepart{second}{apply cuts}};
     \node
     (fill) [mynode,below left=of cut]
     {\lstinline!Analysis::fill!\nodepart{second}{analyse event}};
     \node
     (write) [mynode,below right=of cut]
     {\lstinline!CombinedEventWriter::write!\nodepart{second}{write out event}};
     \node
     (control) [below=of cut] {};
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (reader.south) -- node[left] {\lstinline!LHEF::HEPEUP!} (data.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (data.south) -- node[left] {\lstinline!Event::EventData!} (cluster.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (cluster.south) -- node[left] {\lstinline!Event!} (resum.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (resum.south) --  (cut.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(resum.south)+(7mm, 0cm)$) -- ($(cut.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(resum.south)-(7mm, 0cm)$) -- node[left] {\lstinline!Event!} ($(cut.north)-(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cut.south)-(3mm,0mm)$) .. controls ($(control)-(3mm,0mm)$) ..node[left] {\lstinline!Event!} (fill.east);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cut.south)-(3mm,0mm)$)  .. controls ($(control)-(3mm,0mm)$) .. (write.west);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cut.south)+(3mm,0mm)$) .. controls ($(control)+(3mm,0mm)$) .. (fill.east);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cut.south)+(3mm,0mm)$)  .. controls ($(control)+(3mm,0mm)$) ..node[right] {\lstinline!Event!} (write.west);
   \end{tikzpicture}
 \end{center}
 
 \lstinline!EventData! is an intermediate container, its members are completely
 accessible. In contrast after jet clustering and classification the phase space
 inside \lstinline!Event! can not be changed any more
 (\href{https://wikipedia.org/wiki/Builder_pattern}{Builder design pattern}). The
 resummation is performed by the \lstinline!EventReweighter! class, which is
 described in more detail in section~\ref{sec:resum}. The
 \lstinline!CombinedEventWriter! writes events to zero or more output files. To
 this end, it contains a number of objects implementing the
 \lstinline!EventWriter! interface. These event writers typically write the
 events to a file in a given format. We currently have the
 \lstinline!LesHouchesWriter! for event files in the Les Houches Event File
 format and the \lstinline!HepMCWriter! for the
 \href{https://hepmc.web.cern.ch/hepmc/}{HepMC} format (Version 2 and 3).
 
 \subsection{Resummation}
 \label{sec:resum}
 
 In the \lstinline!EventReweighter::reweight! member function, we first
 classify the input fixed-order event (FKL, unordered, non-HEJ, \dots)
 and decide according to the user settings whether to discard, keep, or
 resum the event. If we perform resummation for the given event, we
 generate a number of trial \lstinline!PhaseSpacePoint! objects. Phase
 space generation is discussed in more detail in
 section~\ref{sec:pspgen}. We then perform jet clustering according to
 the settings for the resummation jets on each
 \lstinline!PhaseSpacePoint!, update the factorisation and
 renormalisation scale in the resulting \lstinline!Event! and reweight it
 according to the ratio of pdf factors and \HEJ matrix elements between
 resummation and original fixed-order event:
 \begin{center}
   \begin{tikzpicture}[node distance=1.5cm and 5mm]
     \node (in) {};
     \node (treat) [diamond,draw,below=of in,minimum size=3.5cm,
     label={[anchor=west, inner sep=8pt]west:discard},
     label={[anchor=east, inner sep=14pt]east:keep},
     label={[anchor=south, inner sep=20pt]south:reweight}
     ] {};
     \draw (treat.north west) -- (treat.south east);
     \draw (treat.north east) -- (treat.south west);
     \node
     (psp) [mynode,below=of treat]
     {\lstinline!PhaseSpacePoint! constructor};
     \node
     (cluster) [mynode,below=of psp]
     {\lstinline!Event::EventData::cluster!\nodepart{second}{cluster jets}};
     \node
     (colour) [mynode,below=of cluster]
     {\lstinline!Event::generate_colours()!\nodepart{second}{generate particle colour}};
     \node
     (gen_scales) [mynode,below=of colour]
     {\lstinline!ScaleGenerator::operator()!\nodepart{second}{update scales}};
     \node
     (rescale) [mynode,below=of gen_scales]
     {\lstinline!PDF::pdfpt!,
       \lstinline!MatrixElement!\nodepart{second}{reweight}};
     \node (out) [below of=rescale] {};
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (in.south) -- node[left] {\lstinline!Event!} (treat.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (treat.south) -- node[left] {\lstinline!Event!} (psp.north);
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (psp.south) --  (cluster.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(psp.south)+(7mm, 0cm)$) -- ($(cluster.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(psp.south)-(7mm, 0cm)$) -- node[left]
     {\lstinline!PhaseSpacePoint!} ($(cluster.north)-(7mm, 0cm)$);
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (cluster.south) --  (colour.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cluster.south)+(7mm, 0cm)$) -- ($(colour.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(cluster.south)-(7mm, 0cm)$) -- node[left]
     {\lstinline!Event!} ($(colour.north)-(7mm, 0cm)$);
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (colour.south) --  (gen_scales.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(colour.south)+(7mm, 0cm)$) -- ($(gen_scales.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(colour.south)-(7mm, 0cm)$) -- node[left]
     {\lstinline!Event!} ($(gen_scales.north)-(7mm, 0cm)$);
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (gen_scales.south) --  (rescale.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(gen_scales.south)+(7mm, 0cm)$) -- ($(rescale.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(gen_scales.south)-(7mm, 0cm)$) -- node[left]
     {\lstinline!Event!} ($(rescale.north)-(7mm, 0cm)$);
 
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (rescale.south) --  (out.north);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(rescale.south)+(7mm, 0cm)$) -- ($(out.north)+(7mm, 0cm)$);
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     ($(rescale.south)-(7mm, 0cm)$) -- node[left]
     {\lstinline!Event!} ($(out.north)-(7mm, 0cm)$);
 
     \node (helper) at ($(treat.east) + (15mm,0cm)$) {};
     \draw[-{Latex[length=3mm, width=1.5mm]}]
     (treat.east) -- ($(treat.east) + (15mm,0cm)$)
     -- node[left] {\lstinline!Event!} (helper |- gen_scales.east) -- (gen_scales.east)
     ;
   \end{tikzpicture}
 \end{center}
 
 \subsection{Phase space point generation}
 \label{sec:pspgen}
 
 The resummed and matched \HEJ cross section for pure jet production of
 FKL configurations is given by (cf. eq. (3) of~\cite{Andersen:2018tnm})
 \begin{align}
     \label{eq:resumdijetFKLmatched2}
 %    \begin{split}
       \sigma&_{2j}^\mathrm{resum, match}=\sum_{f_1, f_2}\ \sum_m
       \prod_{j=1}^m\left(
         \int_{p_{j\perp}^B=0}^{p_{j\perp}^B=\infty}
         \frac{\mathrm{d}^2\mathbf{p}_{j\perp}^B}{(2\pi)^3}\ \int
         \frac{\mathrm{d} y_j^B}{2} \right) \
       (2\pi)^4\ \delta^{(2)}\!\!\left(\sum_{k=1}^{m}
         \mathbf{p}_{k\perp}^B\right)\nonumber\\
       &\times\ x_a^B\ f_{a, f_1}(x_a^B, Q_a^B)\ x_b^B\ f_{b, f_2}(x_b^B, Q_b^B)\
       \frac{\overline{\left|\mathcal{M}_\text{LO}^{f_1f_2\to f_1g\cdots
           gf_2}\big(\big\{p^B_j\big\}\big)\right|}^2}{(\hat {s}^B)^2}\nonumber\\
 & \times (2\pi)^{-4+3m}\ 2^m \nonumber\\
 &\times\ \sum_{n=2}^\infty\
 \int_{p_{1\perp}=p_{\perp,\mathrm{min}} }^{p_{1\perp}=\infty}
       \frac{\mathrm{d}^2\mathbf{p}_{1\perp}}{(2\pi)^3}\
  \int_{p_{n\perp}=p_{\perp,\mathrm{min}}}^{p_{n\perp}=\infty}
        \frac{\mathrm{d}^2\mathbf{p}_{n\perp}}{(2\pi)^3}\
      \prod_{i=2}^{n-1}\int_{p_{i\perp}=\lambda}^{p_{i\perp}=\infty}
        \frac{\mathrm{d}^2\mathbf{p}_{i\perp}}{(2\pi)^3}\ (2\pi)^4\ \delta^{(2)}\!\!\left(\sum_{k=1}^n
         \mathbf{p}_{k\perp}\right )\\
      &\times \ \mathbf{T}_y \prod_{i=1}^n
        \left(\int \frac{\mathrm{d} y_i}{2}\right)\
       \mathcal{O}_{mj}^e\
       \left(\prod_{l=1}^{m-1}\delta^{(2)}(\mathbf{p}_{\mathcal{J}_{l}\perp}^B -
        \mathbf{j}_{l\perp})\right)\
        \left(\prod_{l=1}^m\delta(y^B_{\mathcal{J}_l}-y_{\mathcal{J}_l})\right)
   \ \mathcal{O}_{2j}(\{p_i\})\nonumber\\
      &\times \frac{(\hat{s}^B)^2}{\hat{s}^2}\ \frac{x_a f_{a,f_1}(x_a, Q_a)\ x_b f_{b,f_2}(x_b, Q_b)}{x_a^B\ f_{a,f_1}(x_a^B, Q_a^B)\ x_b^B\ f_{b,f_2}(x_b^B, Q_b^B)}\ \frac{\overline{\left|\mathcal{M}_{\mathrm{HEJ}}^{f_1 f_2\to f_1 g\cdots
             gf_2}(\{ p_i\})\right|}^2}{\overline{\left|\mathcal{M}_\text{LO, HEJ}^{f_1f_2\to f_1g\cdots
           gf_2}\big(\big\{p^B_j\big\}\big)\right|}^{2}} \,.\nonumber
 %    \end{split}
 \end{align}
 The first two lines correspond to the generation of the fixed-order
 input events with incoming partons $f_1, f_2$ and outgoing momenta
 $p_j^B$, where $\mathbf{p}_{j\perp}^B$ and $y_j^B$ denote the respective
 transverse momentum and rapidity. Note that, at leading order, these
 coincide with the fixed-order jet momenta $p_{\mathcal{J}_j}^B$.
 $f_{a,f_1}(x_a, Q_a),f_{b,f_2}(x_b, Q_b)$ are the pdf factors for the incoming partons with
 momentum fractions $x_a$ and $x_b$. The square of the partonic
 centre-of-mass energy is denoted by $\hat{s}^B$ and
 $\mathcal{M}_\text{LO}^{f_1f_2\to f_1g\cdots gf_2}$ is the
 leading-order matrix element.
 
 The third line is a factor accounting for the different multiplicities
 between fixed-order and resummation events. Lines four and five are
 the integration over the resummation phase space described in this
 section. $p_i$ are the momenta of the outgoing partons in resummation
 phase space. $\mathbf{T}_y$ denotes rapidity
 ordering and $\mathcal{O}_{mj}^e$ projects out the exclusive $m$-jet
 component. The relation between resummation and fixed-order momenta is
 fixed by the $\delta$ functions. The first sets each transverse fixed-order jet
 momentum to some function $\mathbf{j_{l\perp}}$ of the resummation
 momenta. The exact form is described in section~\ref{sec:ptj_res}. The second
 $\delta$ forces the rapidities of resummation and fixed-order jets to be
 the same. Finally, the last line is the reweighting of pdf and matrix
 element factors already shown in section~\ref{sec:resum}.
 
 There are two kinds of cut-off in the integration over the resummation
 partons. $\lambda$ is a technical cut-off connected to the cancellation
 of infrared divergencies between real and virtual corrections. Its
 numerical value is set in
 \texttt{include/HEJ/Constants.h}. $p_{\perp,\mathrm{min}}$ regulates
 and \emph{uncancelled} divergence in the extremal parton momenta. Its
 size is set by the user configuration \url{https://hej.web.cern.ch/HEJ/doc/current/user/HEJ.html#settings}.
 
 It is straightforward to generalise eq.~(\ref{eq:resumdijetFKLmatched2})
 to unordered configurations and processes with additional colourless
 emissions, for example a Higgs or electroweak boson. In the latter case only
 the fixed-order integration and the matrix elements change.
 
 \subsubsection{Gluon Multiplicity}
 \label{sec:psp_ng}
 
 The first step in evaluating the resummation phase space in
 eq.~(\ref{eq:resumdijetFKLmatched2}) is to randomly pick terms in the
 sum over the number of emissions. This sampling of the gluon
 multiplicity is done in the \lstinline!PhaseSpacePoint::sample_ng!
 function in \texttt{src/PhaseSpacePoint.cc}.
 
 The typical number of extra emissions depends strongly on the rapidity
 span of the underlying fixed-order event.  Let us, for example, consider
 a fixed-order FKL-type multi-jet configuration with rapidities
 $y_{j_f},\,y_{j_b}$ of the most forward and backward jets,
 respectively. By eq.~(\ref{eq:resumdijetFKLmatched2}), the jet
 multiplicity and the rapidity of each jet are conserved when adding
 resummation. This implies that additional hard radiation is restricted
 to rapidities $y$ within a region $y_{j_b} \lesssim y \lesssim
 y_{j_f}$. Within \HEJ, we require the most forward and most backward
 emissions to be hard \todo{specify how hard} in order to avoid divergences, so this constraint
 in fact applies to \emph{all} additional radiation.
 
 To simplify the remaining discussion, let us remove the FKL rapidity
 ordering
 \begin{equation}
   \label{eq:remove_y_order}
   \mathbf{T}_y \prod_{i=1}^n\int \frac{\mathrm{d}y_i}{2} =
   \frac{1}{n!}\prod_{i=1}^n\int
   \frac{\mathrm{d}y_i}{2}\,,
 \end{equation}
 where all rapidity integrals now cover a region which is approximately
 bounded by $y_{j_b}$ and $y_{j_f}$. Each of the $m$ jets has to contain at least
 one parton; selecting random emissions we can rewrite the phase space
 integrals as
 \begin{equation}
   \label{eq:select_jets}
   \frac{1}{n!}\prod_{i=1}^n\int [\mathrm{d}p_i] =
   \left(\prod_{i=1}^{m}\int [\mathrm{d}p_i]\ {\cal J}_i(p_i)\right)
   \frac{1}{n_g!}\prod_{i=m+1}^{m+n_g}\int [\mathrm{d}p_i]
 \end{equation}
 with jet selection functions
 \begin{equation}
   \label{eq:def_jet_selection}
   {\cal J}_i(p) =
   \begin{cases}
     1 &p\text{ clustered into jet }i\\
     0 & \text{otherwise}
   \end{cases}
 \end{equation}
 and $n_g \equiv n - m$. Here and in the following we use the short-hand
 notation $[\mathrm{d}p_i]$ to denote the phase-space measure for parton
 $i$. As is evident from eq.~\eqref{eq:select_jets}, adding an extra emission
 $n_g+1$ introduces a suppression factor $\tfrac{1}{n_g+1}$. However, the
 additional phase space integral also results in an enhancement proportional
 to $\Delta y_{j_f j_b} = y_{j_f} - y_{j_b}$. This is a result of the
 rapidity-independence of the MRK limit of the integrand, consisting of the
 matrix elements divided by the flux factor. Indeed, we observe that the
 typical number of gluon emissions is to a good approximation proportional to
 the rapidity separation and the phase space integral is dominated by events
 with $n_g \approx \Delta y_{j_f j_b}$.
 
 For the actual phase space sampling, we assume a Poisson distribution
 and extract the mean number of gluon emissions in different rapidity
 bins and fit the results to a linear function in $\Delta y_{j_f j_b}$,
 finding a coefficient of $0.975$ for the inclusive production of a Higgs
 boson with two jets. Here are the observed and fitted average gluon
 multiplicities as a function of $\Delta y_{j_f j_b}$:
 \begin{center}
   \includegraphics[width=.75\textwidth]{ng_mean}
 \end{center}
 As shown for two rapidity slices the assumption of a Poisson
 distribution is also a good approximation:
 \begin{center}
   \includegraphics[width=.49\textwidth]{{ng_1.5}.pdf}\hfill
   \includegraphics[width=.49\textwidth]{{ng_5.5}.pdf}
 \end{center}
 
 \subsubsection{Number of Gluons inside Jets}
 \label{sec:psp_ng_jet}
 
 For each of the $n_g$ gluon emissions we can split the phase-space
 integral into a (disconnected) region inside the jets and a remainder:
 \begin{equation}
   \label{eq:psp_split}
   \int [\mathrm{d}p_i] = \int [\mathrm{d}p_i]\,
   \theta\bigg(\sum_{j=1}^{m}{\cal J}_j(p_i)\bigg) + \int [\mathrm{d}p_i]\,
   \bigg[1-\theta\bigg(\sum_{j=1}^{m}{\cal J}_j(p_i)\bigg)\bigg]\,.
 \end{equation}
 The next step is to decide how many of the gluons will form part of a
 jet. This is done in the \lstinline!PhaseSpacePoint::sample_ng_jets!
 function.
 
 We choose an importance sampling which is flat in the plane
 spanned by the azimuthal angle $\phi$ and the rapidity $y$. This is
 observed in BFKL and valid in the limit of Multi-Regge-Kinematics
 (MRK). Furthermore, we assume anti-$k_t$ jets, which cover an area of
 $\pi R^2$.
 
 In principle, the total accessible area in the $y$-$\phi$ plane is given
 by $2\pi \Delta y_{fb}$, where $\Delta y_{fb}\geq \Delta y_{j_f j_b}$ is
 the a priori unknown rapidity separation between the most forward and
 backward partons. In most cases the extremal jets consist of single
 partons, so that $\Delta y_{fb} = \Delta y_{j_f j_b}$. For the less common
 case of two partons forming a jet we observe a maximum distance of $R$
 between the constituents and the jet centre. In rare cases jets have
 more than two constituents. Empirically, they are always within a
 distance of $\tfrac{5}{3}R$ to the centre of the jet, so
 $\Delta y_{fb} \leq \Delta y_{j_f j_b} + \tfrac{10}{3} R$. In practice, the
 extremal partons are required to carry a large fraction of the jet
 transverse momentum and will therefore be much closer to the jet axis.
 
 In summary, for sufficiently large rapidity separations we can use the
 approximation $\Delta y_{fb} \approx \Delta y_{j_f j_b}$. This scenario
 is depicted here:
 \begin{center}
   \includegraphics[width=0.5\linewidth]{ps_large_y}
 \end{center}
 If there is no overlap between jets, the probability $p_{\cal J, >}$ for
 an extra gluon to end up inside a jet is then given by
 \begin{equation}
   \label{eq:p_J_large}
   p_{\cal J, >} = \frac{(m - 1)\*R^2}{2\Delta y_{j_f j_b}}\,.
 \end{equation}
 For a very small rapidity separation, eq.~\eqref{eq:p_J_large}
 obviously overestimates the true probability. The maximum phase space
 covered by jets in the limit of a vanishing rapidity distance between
 all partons is $2mR \Delta y_{fb}$:
 \begin{center}
   \includegraphics[width=0.5\linewidth]{ps_small_y}
 \end{center}
 We therefore estimate the probability for a parton to end up inside a jet as
 \begin{equation}
   \label{eq:p_J}
   p_{\cal J} = \min\bigg(\frac{(m - 1)\*R^2}{2\Delta y_{j_f j_b}}, \frac{mR}{\pi}\bigg)\,.
 \end{equation}
 Here we compare this estimate with the actually observed
 fraction of additional emissions into jets as a function of the rapidity
 separation:
 \begin{center}
   \includegraphics[width=0.75\linewidth]{pJ}
 \end{center}
 
 \subsubsection{Gluons outside Jets}
 \label{sec:gluons_nonjet}
 
 Using our estimate for the probability of a gluon to be a jet
 constituent, we choose a number $n_{g,{\cal J}}$ of gluons inside
 jets, which also fixes the number $n_g - n_{g,{\cal J}}$ of gluons
 outside jets. As explained later on, we need to generate the momenta of
 the gluons outside jets first. This is done in
 \lstinline!PhaseSpacePoint::gen_non_jet!.
 
 The azimuthal angle $\phi$ is generated flat within $0\leq \phi \leq 2
 \pi$. The allowed rapidity interval is set by the most forward and
 backward partons, which are necessarily inside jets. Since these parton
 rapidities are not known at this point, we also have to postpone the
 rapidity generation for the gluons outside jets. For the scalar
 transverse momentum $p_\perp = |\mathbf{p}_\perp|$ of a gluon outside
 jets we use the parametrisation
 \begin{equation}
   \label{eq:p_nonjet}
   p_\perp = \lambda + \tilde{p}_\perp\*\tan(\tau\*r)\,, \qquad
   \tau = \arctan\bigg(\frac{p_{\perp{\cal J}_\text{min}} - \lambda}{\tilde{p}_\perp}\bigg)\,.
 \end{equation}
 For $r \in [0,1)$, $p_\perp$ is always less than the minimum momentum
 $p_{\perp{\cal J}_\text{min}}$ required for a jet. $\tilde{p}_\perp$ is
 a free parameter, a good empirical value is $\tilde{p}_\perp = [1.3 +
 0.2\*(n_g - n_{g,\cal J})]\,$GeV
 
 \subsubsection{Resummation jet momenta}
 \label{sec:ptj_res}
 
 On the one hand, each jet momentum is given by the sum of its
 constituent momenta. On the other hand, the resummation jet momenta are
 fixed by the constraints in line five of the master
 equation~\eqref{eq:resumdijetFKLmatched2}. We therefore have to
 calculate the resummation jet momenta from these constraints before
 generating the momenta of the gluons inside jets. This is done in
 \lstinline!PhaseSpacePoint::reshuffle! and in the free
 \lstinline!resummation_jet_momenta! function (declared in \texttt{resummation\_jet.hh}).
 
 The resummation jet momenta are determined by the $\delta$ functions in
 line five of eq.~(\ref{eq:resumdijetFKLmatched2}). The rapidities are
 fixed to the rapidities of the jets in the input fixed-order events, so
 that the FKL ordering is guaranteed to be preserved.
 
 In traditional \HEJ reshuffling the transverse momentum are given through
 \begin{equation}
 \label{eq:ptreassign_old}
 \mathbf{p}^B_{\mathcal{J}_{l\perp}} = \mathbf{j}_{l\perp} \equiv \mathbf{p}_{\mathcal{J}_{l}\perp}
 + \mathbf{q}_\perp \,\frac{|\mathbf{p}_{\mathcal{J}_{l}\perp}|}{P_\perp},
 \end{equation}
 where $\mathbf{q}_\perp = \sum_{j=1}^n \mathbf{p}_{i\perp}
 \bigg[1-\theta\bigg(\sum_{j=1}^{m}{\cal J}_j(p_i)\bigg)\bigg] $ is the
 total transverse momentum of all partons \emph{outside} jets and
 $P_\perp = \sum_{j=1}^m |\mathbf{p}_{\mathcal{J}_{j}\perp}|$. Since the
 total transverse momentum of an event vanishes, we can also use
 $\mathbf{q}_\perp = - \sum_{j=1}^m
 \mathbf{p}_{\mathcal{J}_{j}\perp}$. Eq.~(\ref{eq:ptreassign}) is a
 non-linear system of equations in the resummation jet momenta
 $\mathbf{p}_{\mathcal{J}_{l}\perp}$. Hence we would have to solve
 \begin{equation}
 \label{eq:ptreassign_eq}
 \mathbf{p}_{\mathcal{J}_{l}\perp}=\mathbf{j}^B_{l\perp} \equiv\mathbf{j}_{l\perp}^{-1}
 \left(\mathbf{p}^B_{\mathcal{J}_{l\perp}}\right)
 \end{equation}
 numerically.
 
 Since solving such a system is computationally expensive, we instead
 change the reshuffling around to be linear in the resummation jet
 momenta. Hence~\eqref{eq:ptreassign_eq} gets replaces by
 \begin{equation}
 \label{eq:ptreassign}
 \mathbf{p}_{\mathcal{J}_{l\perp}} = \mathbf{j}^B_{l\perp} \equiv \mathbf{p}^B_{\mathcal{J}_{l}\perp}
 - \mathbf{q}_\perp \,\frac{|\mathbf{p}^B_{\mathcal{J}_{l}\perp}|}{P^B_\perp},
 \end{equation}
 which is linear in the resummation momentum. Consequently the equivalent
 of~\eqref{eq:ptreassign_old} is non-linear in the Born momentum. However
 the exact form of~\eqref{eq:ptreassign_old} is not relevant for the resummation.
 Both methods have been tested for two and three jets with the \textsc{rivet}
 standard analysis \texttt{MC\_JETS}. They didn't show any differences even
 after $10^9$ events.
 
 The reshuffling relation~\eqref{eq:ptreassign} allows the transverse
 momenta $p^B_{\mathcal{J}_{l\perp}}$ of the fixed-order jets to be
 somewhat below the minimum transverse momentum of resummation jets. It
 is crucial that this difference does not become too large, as the
 fixed-order cross section diverges for vanishing transverse momenta. In
 the production of a Higgs boson with resummation jets above $30\,$GeV we observe
 that the contribution from fixed-order events with jets softer than
 about $20\,$GeV can be safely neglected. This is shown in the following
 plot of the differential cross section over the transverse momentum of
 the softest fixed-order jet:
 \begin{center}
   \includegraphics[width=.75\textwidth]{ptBMin}
 \end{center}
 
 Finally, we have to account for the fact that the reshuffling
 relation~\eqref{eq:ptreassign} is non-linear in the Born momenta. To
 arrive at the master formula~\eqref{eq:resumdijetFKLmatched2} for the
 cross section, we have introduced unity in the form of an integral over
 the Born momenta with $\delta$ functions in the integrand, that is
 \begin{equation}
   \label{eq:delta_intro}
   1 = \int_{p_{j\perp}^B=0}^{p_{j\perp}^B=\infty}
   \mathrm{d}^2\mathbf{p}_{j\perp}^B\delta^{(2)}(\mathbf{p}_{\mathcal{J}_{j\perp}}^B -
   \mathbf{j}_{j\perp})\,.
 \end{equation}
 If the arguments of the $\delta$ functions are not linear in the Born
 momenta, we have to compensate with additional Jacobians as
 factors. Explicitly, for the reshuffling relation~\eqref{eq:ptreassign}
 we have
 \begin{equation}
   \label{eq:delta_rewrite}
   \prod_{l=1}^m \delta^{(2)}(\mathbf{p}_{\mathcal{J}_{l\perp}}^B -
   \mathbf{j}_{l\perp}) = \Delta \prod_{l=1}^m \delta^{(2)}(\mathbf{p}_{\mathcal{J}_{l\perp}} -
   \mathbf{j}_{l\perp}^B)\,,
 \end{equation}
 where $\mathbf{j}_{l\perp}^B$ is given by~\eqref{eq:ptreassign_eq} and only
 depends on the Born momenta. We have extended the product to run to $m$
 instead of $m-1$ by eliminating the last $\delta$ function
 $\delta^{(2)}\!\!\left(\sum_{k=1}^n \mathbf{p}_{k\perp}\right )$.
 The Jacobian $\Delta$ is the determinant of a $2m \times 2m$ matrix with $l, l' = 1,\dots,m$
 and $X, X' = x,y$.
 \begin{equation}
   \label{eq:jacobian}
   \Delta = \left|\frac{\partial\,\mathbf{j}^B_{l'\perp}}{\partial\, \mathbf{p}^B_{{\cal J}_l \perp}} \right|
     = \left| \delta_{l l'} \delta_{X X'} - \frac{q_X\, p^B_{{\cal
         J}_{l'}X'}}{\left|\mathbf{p}^B_{{\cal J}_{l'} \perp}\right| P^B_\perp}\left(\delta_{l l'}
        - \frac{\left|\mathbf{p}^B_{{\cal J}_l \perp}\right|}{P^B_\perp}\right)\right|\,.
 \end{equation}
 The determinant is calculated in \lstinline!resummation_jet_weight!,
 again coming from the \texttt{resummation\_jet.hh} header.
 Having to introduce this Jacobian is not a disadvantage specific to the new
 reshuffling. If we instead use the old reshuffling
 relation~\eqref{eq:ptreassign_old} we \emph{also} have to introduce a
 similar Jacobian since we actually want to integrate over the
 resummation phase space and need to transform the argument of the
 $\delta$ function to be linear in the resummation momenta for this.
 
 \subsubsection{Gluons inside Jets}
 \label{sec:gluons_jet}
 
 After the steps outlined in section~\ref{sec:psp_ng_jet}, we have a
 total number of $m + n_{g,{\cal J}}$ constituents. In
 \lstinline!PhaseSpacePoint::distribute_jet_partons! we distribute them
 randomly among the jets such that each jet has at least one
 constituent. We then generate their momenta in
 \lstinline!PhaseSpacePoint::split! using the \lstinline!Splitter! class.
 
 The phase space integral for a jet ${\cal J}$ is given by
 \begin{equation}
   \label{eq:ps_jetparton} \prod_{i\text{ in }{\cal J}} \bigg(\int
 \mathrm{d}\mathbf{p}_{i\perp}\ \int \mathrm{d} y_i
 \bigg)\delta^{(2)}\Big(\sum_{i\text{ in }{\cal J}} \mathbf{p}_{i\perp} -
 \mathbf{j}_{\perp}^B\Big)\delta(y_{\mathcal{J}}-y^B_{\mathcal{J}})\,.
 \end{equation}
 For jets with a single constituent, the parton momentum is obiously equal to the
 jet momentum. In the case of two constituents, we observe that the
 partons are always inside the jet cone with radius $R$ and often very
 close to the jet centre. The following plots show the typical relative
 distance $\Delta R/R$ for this scenario:
 \begin{center}
   \includegraphics[width=0.45\linewidth]{dR_2}
   \includegraphics[width=0.45\linewidth]{dR_2_small}
 \end{center}
 According to this preference for small values of $\Delta R$, we
 parametrise the $\Delta R$ integrals as
 \begin{equation}
   \label{eq:dR_sampling}
   \frac{\Delta R}{R} =
   \begin{cases}
     0.25\,x_R & x_R < 0.4 \\
     1.5\,x_R - 0.5 & x_R \geq 0.4
   \end{cases}\,.
 \end{equation}
 Next, we generate $\Theta_1 \equiv \Theta$ and use the constraint $\Theta_2 = \Theta
 \pm \pi$. The transverse momentum of the first parton is then given by
 \begin{equation}
   \label{eq:delta_constraints}
   p_{1\perp} =
   \frac{p_{\mathcal{J} y} - \tan(\phi_2) p_{\mathcal{J} x}}{\sin(\phi_1)
     - \tan(\phi_2)\cos(\phi_1)}\,.
 \end{equation}
 We get $p_{2\perp}$ by exchanging $1 \leftrightarrow 2$ in the
 indices. To obtain the Jacobian of the transformation, we start from the
 single jet phase space eq.~(\ref{eq:ps_jetparton}) with the rapidity
 delta function already rewritten to be linear in the rapidity of the
 last parton, i.e.
 \begin{equation}
   \label{eq:jet_2p}
 \prod_{i=1,2} \bigg(\int
 \mathrm{d}\mathbf{p}_{i\perp}\ \int \mathrm{d} y_i
 \bigg)\delta^{(2)}\Big(\mathbf{p}_{1\perp} + \mathbf{p}_{2\perp} -
 \mathbf{j}_{\perp}^B\Big)\delta(y_2- \dots)\,.
 \end{equation}
 The integral over the second parton momentum is now trivial; we can just replace
 the integral over $y_2$ with the equivalent constraint
 \begin{equation}
   \label{eq:R2}
 \int \mathrm{d}R_2 \ \delta\bigg(R_2 - \bigg[\phi_{\cal J} - \arctan
 \bigg(\frac{p_{{\cal J}y} - p_{1y}}{p_{{\cal J}x} -
   p_{1x}}\bigg)\bigg]/\cos \Theta\bigg) \,.
 \end{equation}
 In order to fix the integral over $p_{1\perp}$ instead, we rewrite this
 $\delta$ function. This introduces the Jacobian
 \begin{equation}
   \label{eq:jac_pt1}
 \bigg|\frac{\partial p_{1\perp}}{\partial R_2} \bigg| =
 \frac{\cos(\Theta)\mathbf{p}_{2\perp}^2}{p_{{\cal J}\perp}\sin(\phi_{\cal J}-\phi_1)}\,.
 \end{equation}
 The final form of the integral over the two parton momenta is then
 \begin{equation}
   \label{eq:ps_jet_2p}
 \int \mathrm{d}R_1\ R_1 \int \mathrm{d}R_2 \int \mathrm{d}x_\Theta\ 2\pi \int
 \mathrm{d}p_{1\perp}\ p_{1\perp} \int \mathrm{d}p_{2\perp}
 \ \bigg|\frac{\partial p_{1\perp}}{\partial R_2} \bigg|\delta(p_{1\perp}
 -\dots) \delta(p_{2\perp} - \dots)\,.
 \end{equation}
 
 As is evident from section~\ref{sec:psp_ng_jet}, jets with three or more
 constituents are rare and an efficient phase-space sampling is less
 important. For such jets, we exploit the observation that partons with a
 distance larger than $R_{\text{max}} = \tfrac{5}{3} R$ to
 the jet centre are never clustered into the jet. Assuming $N$
 constituents, we generate all components
 for the first $N-1$ partons and fix the remaining parton with the
 $\delta$-functional. In order to end up inside the jet, we use the
 parametrisation
 \begin{align}
   \label{eq:ps_jet_param}
   \phi_i ={}& \phi_{\cal J} + \Delta \phi_i\,, & \Delta \phi_i ={}&  \Delta
                                                                  R_i
                                                                  \cos(\Theta_i)\,, \\
   y_i ={}& y_{\cal J} + \Delta y_i\,, & \Delta y_i ={}&  \Delta
                                                                  R_i
                                                                  \sin(\Theta_i)\,,
 \end{align}
 and generate $\Theta_i$ and $\Delta R_i$ randomly with $\Delta R_i \leq
 R_{\text{max}}$ and the empiric value $R_{\text{max}} = 5\*R/3$. We can
 then write the phase space integral for a single parton as $(p_\perp = |\mathbf{p}_\perp|)$
 \begin{equation}
   \label{eq:ps_jetparton_x}
   \int \mathrm{d}\mathbf{p}_{\perp}\ \int
         \mathrm{d} y \approx \int_{\Box} \mathrm{d}x_{\perp}
         \mathrm{d}x_{ R}
         \mathrm{d}x_{\theta}\
         2\*\pi\,\*R_{\text{max}}^2\,\*x_{R}\,\*p_{\perp}\,\*(p_{\perp,\text{max}}
         - p_{\perp,\text{min}})
 \end{equation}
 with
 \begin{align}
   \label{eq:ps_jetparton_parameters}
   \Delta \phi ={}&  R_{\text{max}}\*x_{R}\*\cos(2\*\pi\*x_\theta)\,,&
   \Delta y ={}& R_{\text{max}}\*x_{R}\*\sin(2\*\pi\*x_\theta)\,, \\
   p_{\perp} ={}& (p_{\perp,\text{max}} - p_{\perp,\text{min}})\*x_\perp +
   p_{\perp,\text{min}}\,.
 \end{align}
 $p_{\perp,\text{max}}$ is determined from the requirement that the total
 contribution from the first $n-1$ partons --- i.e. the projection onto the
 jet $p_{\perp}$ axis --- must never exceed the jet $p_\perp$. This gives
 \todo{This bound is too high}
 \begin{equation}
   \label{eq:pt_max}
   p_{i\perp,\text{max}} = \frac{p_{{\cal J}\perp} - \sum_{j<i} p_{j\perp}
     \cos \Delta
 \phi_j}{\cos \Delta
 \phi_i}\,.
 \end{equation}
 The $x$ and $y$ components of the last parton follow immediately from
 the first $\delta$ function. The last rapidity is fixed by the condition that
 the jet rapidity is kept fixed by the reshuffling, i.e.
 \begin{equation}
   \label{eq:yJ_delta}
   y^B_{\cal J} = y_{\cal J} = \frac 1 2 \ln \frac{\sum_{i=1}^n  E_i+ p_{iz}}{\sum_{i=1}^n E_i - p_{iz}}\,.
 \end{equation}
 With $E_n \pm p_{nz} = p_{n\perp}\exp(\pm y_n)$ this can be rewritten to
 \begin{equation}
   \label{eq:yn_quad_eq}
   \exp(2y_{\cal J}) = \frac{\sum_{i=1}^{n-1}  E_i+ p_{iz}+p_{n\perp} \exp(y_n)}{\sum_{i=1}^{n-1} E_i - p_{iz}+p_{n\perp} \exp(-y_n)}\,,
 \end{equation}
 which is a quadratic equation in $\exp(y_n)$. The physical solution is
 \begin{align}
   \label{eq:yn}
   y_n ={}& \log\Big(-b + \sqrt{b^2 + \exp(2y_{\cal J})}\,\Big)\,,\\
 b ={}& \bigg(\sum_{i=1}^{n-1}  E_i + p_{iz} - \exp(2y_{\cal J})
   \sum_{i=1}^{n-1}  E_i - p_{iz}\bigg)/(2 p_{n\perp})\,.
 \end{align}
 \todo{what's wrong with the following?} To eliminate the remaining rapidity
 integral, we transform the $\delta$ function to be linear in the
 rapidity $y$ of the last parton. The corresponding Jacobian is
 \begin{equation}
   \label{eq:jacobian_y}
   \bigg|\frac{\partial y_{\cal J}}{\partial y_n}\bigg|^{-1} = 2 \bigg( \frac{E_n +
     p_{nz}}{E_{\cal J} + p_{{\cal J}z}} + \frac{E_n - p_{nz}}{E_{\cal J} -
     p_{{\cal J}z}}\bigg)^{-1}\,.
 \end{equation}
 Finally, we check that all designated constituents are actually
 clustered into the considered jet.
 
 \subsubsection{Final steps}
 \label{sec:final}
 
 Knowing the rapidity span covered by the extremal partons, we can now
 generate the rapdities for the partons outside jets. We perform jet
 clustering on all partons and check in
 \lstinline!PhaseSpacePoint::jets_ok! that all the following criteria are
 fulfilled:
 \begin{itemize}
 \item The number of resummation jets must match the number of
   fixed-order jets.
 \item No partons designated to be outside jets may end up inside jets.
 \item All other outgoing partons \emph{must} end up inside jets.
 \item The extremal (in rapidity) partons must be inside the extremal
   jets. If there is, for example, an unordered forward emission, the
   most forward parton must end up inside the most forward jet and the
   next parton must end up inside second jet.
 \item The rapidities of fixed-order and resummation jets must match.
 \end{itemize}
 After this, we adjust the phase-space normalisation according to the
 third line of eq.~(\ref{eq:resumdijetFKLmatched2}), determine the
 flavours of the outgoing partons, and adopt any additional colourless
 bosons from the fixed-order input event. Finally, we use momentum
 conservation to reconstruct the momenta of the incoming partons.
 
 \subsection{Colour connection}
 \label{sec:Colour}
 
 \begin{figure}
   \input{src/ColourConnect.tex}
   \caption{Left: Non-crossing colour flow dominating in the MRK limit. The
     crossing of the colour line connecting to particle 2 can be resolved by
     writing particle 2 on the left. Right: A colour flow with a (manifest)
     colour-crossing. The crossing can only be resolved if one breaks the
     rapidities order, e.g. switching particles 2 and 3. From~\cite{Andersen:2017sht}.}
   \label{fig:Colour_crossing}
 \end{figure}
 
 After the phase space for the resummation event is generated, we can construct
 the colour for each particle. To generate the colour flow one has to call
 \lstinline!Event::generate_colours! on any \HEJ configuration. For non-\HEJ
 event we do not change the colour, and assume it is provided by the user (e.g.
 through the LHE file input). The colour connection is done in the large $N_c$
 (infinite number of colour) limit with leading colour in
 MRK~\cite{Andersen:2008ue, Andersen:2017sht}. The idea is to allow only
 $t$-channel colour exchange, without any crossing colour lines. For example the
 colour crossing in the colour connection on the left of
 figure~\ref{fig:Colour_crossing} can be resolved by switching \textit{particle
 2} to the left.
 
 We can write down the colour connections by following the colour flow from
 \textit{gluon a} to \textit{gluon b} and back to \textit{gluon a}, e.g.
 figure~\ref{fig:Colour_gleft} corresponds to $a123ba$. In such an expression any
 valid, non-crossing colour flow will connect all external legs while respecting
 the rapidity ordering. Thus configurations like the left of
 figure~\ref{fig:Colour_crossing} are allowed ($a134b2a$), but the right of the
 same figures breaks the rapidity ordering between 2 and 3 ($a1324ba$). Note that
 connections between $b$ and $a$ are in inverse order, e.g. $ab321a$ corresponds to~\ref{fig:Colour_gright} ($a123ba$) just with colour and anti-colour swapped.
 
 \begin{figure}
 \centering
 \subcaptionbox{$a123ba$\label{fig:Colour_gright}}{
   \includegraphics[height=0.25\textwidth]{figures/colour_gright.jpg}}
 \subcaptionbox{$a13b2a$\label{fig:Colour_gleft}}{
   \includegraphics[height=0.25\textwidth]{figures/colour_gleft.jpg}}
 \subcaptionbox{$a\_123ba$\label{fig:Colour_qx}}{
   \includegraphics[height=0.25\textwidth]{figures/colour_qx.jpg}}
 \subcaptionbox{$a\_23b1a$\label{fig:Colour_uno}}{
   \includegraphics[height=0.25\textwidth]{figures/colour_uno.jpg}}
 \subcaptionbox{$a14b3\_2a$\label{fig:Colour_qqx}}{
   \includegraphics[height=0.25\textwidth]{figures/colour_centralqqx.jpg}}
 \caption{Different colour non-crossing colour connections. Both incoming
   particles are drawn at the top or bottom and the outgoing left or right.
   The Feynman diagram is shown in black and the colour flow in blue.}
   %TODO Maybe make these plots nicer (in Latex/asy)
 \end{figure}
 
 If we replace two gluons with a quark, (anti-)quark pair we break one of the
 colour connections. Still the basic concept from before holds, we just have to
 treat the connection between two (anti-)quarks like an unmovable (anti-)colour.
 We denote such a connection by a underscore (e.g. $1\_a$). For example the
 equivalent of~\ref{fig:Colour_gright} ($a123ba$) with an incoming antiquark
 is~\ref{fig:Colour_qx} ($a\_123ba$). As said this also holds for other
 subleading configurations like unordered emission~\ref{fig:Colour_uno} or
 central quark-antiquark pairs~\ref{fig:Colour_qqx} \footnote{Obviously this can
 not be guaranteed for non-\HEJ configurations, e.g. $qQ\to Qq$ requires a
 $u$-channel exchange.}.
 
 Some rapidity ordering can have multiple possible colour connections,
 e.g.~\ref{fig:Colour_gright} and~\ref{fig:Colour_gleft}. This is always the case
 if a gluon radiates off a gluon line. In that case we randomly connect the gluon
 to either the colour or anti-colour. Thus in the generation we keep track
 whether we are on a quark or gluon line, and act accordingly.
 
 
 
 \subsection{The matrix element }
 \label{sec:ME}
 
 The derivation of the \HEJ matrix element is explained in some detail
 in~\cite{Andersen:2017kfc}, where also results for leading and
 subleading matrix elements for pure multijet production and production
 of a Higgs boson with at least two associated jets are listed. Matrix
 elements for $W$ and $Z/\gamma^*$ production together with jets are
 given in~\cite{Andersen:2012gk,Andersen:2016vkp}, but not yet included.
 
 The matrix elements are implemented in the \lstinline!MatrixElement!
 class. To discuss the structure, let us consider the squared matrix
 element for FKL multijet production with $n$ final-state partons:
 \begin{align}
   \label{eq:ME}
   \begin{split}
         \overline{\left|\mathcal{M}_\text{HEJ}^{f_1 f_2 \to f_1
           g\cdots g f_2}\right|}^2 = \ &\frac {(4\pi\alpha_s)^n} {4\ (N_c^2-1)}
     \cdot\ \textcolor{blue}{\frac {K_{f_1}(p_1^-, p_a^-)} {t_1}\ \cdot\ \frac{K_{f_2}(p_n^+, p_b^+)}{t_{n-1}}\  \cdot\ \left\|S_{f_1 f_2\to f_1 f_2}\right\|^2}\\
      & \cdot \prod_{i=1}^{n-2} \textcolor{gray}{\left( \frac{-C_A}{t_it_{i+1}}\
        V^\mu(q_i,q_{i+1})V_\mu(q_i,q_{i+1}) \right)}\\
      & \cdot \prod_{j=1}^{n-1} \textcolor{red}{\exp\left[\omega^0(q_{j\perp})(y_{j+1}-y_j)\right]}.
   \end{split}
 \end{align}
 The structure and momentum assignment of the unsquared matrix element is
 as illustrated here:
 \begin{center}
   \includegraphics{HEJ_amplitude}
 \end{center}
 The square
 of the complete matrix element as given in eq.~\eqref{eq:ME} is
 calculated by \lstinline!MatrixElement::operator()!.  The \textcolor{red}{last line} of
 eq.~\eqref{eq:ME} constitutes the all-order virtual correction,
 implemented in
 \lstinline!MatrixElement::virtual_corrections!.
 $\omega^0$ is the
 \textit{regularised Regge trajectory}
 \begin{equation}
   \label{eq:omega_0}
   \omega^0(q_\perp) = - C_A \frac{\alpha_s}{\pi} \log \left(\frac{q_\perp^2}{\lambda^2}\right)\,,
 \end{equation}
 where $\lambda$ is the slicing parameter limiting the softness of real
 gluon emissions, cf. eq.~\eqref{eq:resumdijetFKLmatched2}. $\lambda$ can be
 changed at runtime by setting \lstinline!regulator parameter! in
 \lstinline!conifg.yml!.
 
 The remaining parts, which correspond to the square of the leading-order
 HEJ matrix element $\overline{\left|\mathcal{M}_\text{LO,
 HEJ}^{f_1f_2\to f_1g\cdots
 gf_2}\big(\big\{p^B_j\big\}\big)\right|}^{2}$, are computed in
 \lstinline!MatrixElement::tree!. We can further factor off the
 scale-dependent ``parametric'' part
 \lstinline!MatrixElement::tree_param! containing all factors of the
 strong coupling $4\pi\alpha_s$. Using this function saves some CPU time
 when adjusting the renormalisation scale, see
 section~\ref{sec:resum}. The remaining ``kinematic'' factors are
 calculated in \lstinline!MatrixElement::kin!.
 
 \subsubsection{Matrix elements for Higgs plus dijet}
 \label{sec:ME_h_jets}
 
 In the production of a Higgs boson together with jets the parametric
 parts and the virtual corrections only require minor changes in the
 respective functions. However, in the ``kinematic'' parts we have to
 distinguish between several cases, which is done in
 \lstinline!MatrixElement::tree_kin_Higgs!. The Higgs boson can be
 \emph{central}, i.e. inside the rapidity range spanned by the extremal
 partons (\lstinline!MatrixElement::tree_kin_Higgs_central!) or
 \emph{peripheral} and outside this range
 (\lstinline!MatrixElement::tree_kin_Higgs_first!  or
 \lstinline!MatrixElement::tree_kin_Higgs_last!). In case there is also
 an unordered gluon emission the matrix element is already suppressed by one
 logarithm $\log(s/t)$. Therefore at NLL the Higgs boson can only be emitted
 centrally\footnote{In principle emitting a Higgs boson \textit{on the other
 side} of the unordered gluon is possible by contracting an unordered and
 external Higgs current. Obviously this would not cover all possible
 configurations, e.g. $qQ\to HgqQ$ requires contraction of the standard $Q\to Q$
 current with an (unknown) $q\to Hgq$ one.}.
 
 If a Higgs boson with momentum $p_H$ is emitted centrally, after parton
 $j$ in rapidity, the matrix element reads
 \begin{equation}
   \label{eq:ME_h_jets_central}
   \begin{split}
         \overline{\left|\mathcal{M}_\text{HEJ}^{f_1 f_2 \to f_1 g\cdot H
               \cdot g f_2}\right|}^2 = \ &\frac {\alpha_s^2 (4\pi\alpha_s)^n} {4\ (N_c^2-1)}
     \cdot\ \textcolor{blue}{\frac {K_{f_1}(p_1^-, p_a^-)} {t_1}\
 \cdot\ \frac{1}{t_j t_{j+1}} \cdot\ \frac{K_{f_2}(p_n^+, p_b^+)}{t_{n}}\  \cdot\ \left\|S_{f_1
           f_2\to f_1 H f_2}\right\|^2}\\
      & \cdot \prod_{\substack{i=1\\i \neq j}}^{n-1} \textcolor{gray}{\left( \frac{-C_A}{t_it_{i+1}}\
        V^\mu(q_i,q_{i+1})V_\mu(q_i,q_{i+1}) \right)}\\
      & \cdot \textcolor{red}{\prod_{i=1}^{n-1}
      \exp\left[\omega^0(q_{i\perp})\Delta y_i\right]}
   \end{split}
 \end{equation}
 with the momentum definitions
 \begin{center}
   \includegraphics{HEJ_central_Higgs_amplitude}
 \end{center}
 $q_i$ is the $i$th $t$-channel momentum and $\Delta y_i$ the rapidity
 gap between outgoing \emph{particles} (not partons) $i$ and $i+1$ in
 rapidity ordering.
 
 For \emph{peripheral} emission in the backward direction
 (\lstinline!MatrixElement::tree_kin_Higgs_first!) we first check whether
 the most backward parton is a gluon or an (anti-)quark. In the latter
 case the leading contribution to the matrix element arises through
 emission off the $t$-channel gluons and we can use the same formula
 eq.~(\ref{eq:ME_h_jets_central}) as for central emission. If the most
 backward parton is a gluon, the square of the matrix element can be
 written as
 \begin{equation}
   \label{eq:ME_h_jets_peripheral}
   \begin{split}
         \overline{\left|\mathcal{M}_\text{HEJ}^{g f_2 \to H g\cdot g f_2}\right|}^2 = \ &\frac {\alpha_s^2 (4\pi\alpha_s)^n} {\textcolor{blue}{4\ (N_c^2-1)}}
     \textcolor{blue}{\cdot\ K_{H}\
       \frac{K_{f_2}(p_n^+, p_b^+)}{t_{n-1}}\  \cdot\ \left\|S_{g
           f_2\to H g f_2}\right\|^2}\\
      & \cdot \prod_{\substack{i=1}}^{n-2} \textcolor{gray}{\left( \frac{-C_A}{t_it_{i+1}}\
        V^\mu(q_i,q_{i+1})V_\mu(q_i,q_{i+1}) \right)}\\
      & \cdot \textcolor{red}{\prod_{i=1}^{n-1}
      \exp\left[\omega^0(q_{i\perp}) (y_{i+1} - y_i)\right]}
   \end{split}
 \end{equation}
 with the momenta as follows:
 \begin{center}
   \includegraphics{HEJ_peripheral_Higgs_amplitude}
 \end{center}
 The \textcolor{blue}{blue part} is implemented in
 \lstinline!MatrixElement::MH2_forwardH!. All other building blocks are
 already available.\todo{Impact factors} The actual current contraction
 is calculated in \lstinline!MH2gq_outsideH! inside
 \lstinline!currents.cc!, which corresponds to $\tfrac{16 \pi^2}{t_1} \left\|S_{g
           f_2\to H g f_2}\right\|^2$.\todo{Fix this insane normalisation}
 
 The forward emission of a Higgs boson is completely analogous. We can
 use the same function \lstinline!MatrixElement::MH2_forwardH!, swapping
 $p_1 \leftrightarrow p_n,\,p_a \leftrightarrow p_b$.
 
 \subsubsection{FKL ladder and Lipatov vertices}
 \label{sec:FKL_ladder}
 
 The ``FKL ladder'' is the product
 \begin{equation}
   \label{eq:FKL_ladder}
   \prod_{i=1}^{n-2} \left( \frac{-C_A}{t_it_{i+1}}\
     V^\mu(q_i,q_{i+1})V_\mu(q_i,q_{i+1}) \right)
 \end{equation}
 appearing in the square of the matrix element for $n$ parton production,
 cf. eq.~(\ref{eq:ME}), and implemented in
 \lstinline!MatrixElement::FKL_ladder_weight!. The Lipatov vertex contraction
 $V^\mu(q_i,q_{i+1})V_\mu(q_i,q_{i+1})$ is implemented \lstinline!C2Lipatovots!.
 It is given by \todo{equation} \todo{mention difference between the two versions
 of \lstinline!C2Lipatovots!, maybe even get rid of one}.
 
 \subsubsection{Currents}
 \label{sec:currents}
 
 The current factors $\frac{K_{f_1}K_{f_2}}{t_1 t_{n-1}}\left\|S_{f_1
 f_2\to f_1 f_2}\right\|^2$ and their extensions for unordered and Higgs
 boson emissions are implemented in the \lstinline!jM2!$\dots$ functions
 of \texttt{src/currents.cc}. \todo{Only $\|S\|^2$ should be in currents}
 \footnote{The current implementation for
 Higgs production in \texttt{src/currents.cc} includes the $1/4$ factor
 inside $S$, opposing to~\eqref{eq:ME}. Thus the overall normalisation is
 unaffected.} The ``colour acceleration multiplier'' (CAM) $K_{f}$
 for a parton $f\in\{g,q,\bar{q}\}$ is defined as
 \begin{align}
   \label{eq:K_g}
  K_g(p_1^-, p_a^-) ={}& \frac{1}{2}\left(\frac{p_1^-}{p_a^-} + \frac{p_a^-}{p_1^-}\right)\left(C_A -
                         \frac{1}{C_A}\right)+\frac{1}{C_A}\\
   \label{eq:K_q}
   K_q(p_1^-, p_a^-) ={}&K_{\bar{q}}(p_1^-, p_a^-) = C_F\,.
 \end{align}
 The Higgs current CAM used in eq.~(\ref{eq:ME_h_jets_peripheral}) is
 \begin{equation}
   \label{eq:K_H}
   K_H = C_A\,.
 \end{equation}
 The current contractions are given by\todo{check all this
   carefully!}
 \begin{align}
   \label{eq:S}
   \left\|S_{f_1 f_2\to f_1 f_2}\right\|^2 ={}& \sum_{\substack{\lambda_a =
   +,-\\\lambda_b = +,-}} \left|j^{\lambda_a}_\mu(p_1, p_a)\
 j^{\lambda_b\,\mu}(p_n, p_b)\right|^2 = 2\sum_{\lambda =
   +,-} \left|j^{-}_\mu(p_1, p_a)\ j^{\lambda\,\mu}(p_n, p_b)\right|^2\,,\\
   \left\|S_{f_1 f_2\to f_1 H f_2}\right\|^2 ={}& \sum_{\substack{\lambda_a =
   +,-\\\lambda_b = +,-}} \left|j^{\lambda_a}_\mu(p_1, p_a)V_H^{\mu\nu}(q_j, q_{j+1})\
   j^{\lambda_b}_\nu(p_n, p_b)\right|^2\,,\\
   \left\|S_{g f_2 \to  H g f_2}\right\|^2 ={}& \sum_{
   \substack{
   \lambda_{a} = +,-\\
   \lambda_{1} =+,-\\
   \lambda_{b} = +,-
   }}
  \left|j^{\lambda_a\lambda_1}_{H\,\mu}(p_1, p_a, p_H)\ j^{\lambda_b\,\mu}(p_n, p_b)\right|^2\,.
 \end{align}
 The ``basic'' currents $j$ are independent of the parton flavour and read
 \begin{equation}
   \label{eq:j}
   j^\pm_\mu(p, q) = u^{\pm,\dagger}(p)\ \sigma^\pm_\mu\ u^{\pm}(q)\,,
 \end{equation}
 where $\sigma_\mu^\pm = (1, \pm \sigma_i)$ and $\sigma_i$ are the Pauli
 matrices
 \begin{equation}
   \label{eq:Pauli_matrices}
   \sigma_1 =
   \begin{pmatrix}
     0 & 1\\ 1 & 0
   \end{pmatrix}
 \,,
   \qquad \sigma_2 =
   \begin{pmatrix}
     0 & -i\\ i & 0
   \end{pmatrix}
 \,,
   \qquad \sigma_3 =
   \begin{pmatrix}
     1 & 0\\ 0 & -1
   \end{pmatrix}
 \,.
 \end{equation}
 The two-component chiral spinors are given by
 \begin{align}
   \label{eq:u_plus}
   u^+(p)={}& \left(\sqrt{p^+}, \sqrt{p^-} \hat{p}_\perp \right) \,,\\
   \label{eq:u_minus}
   u^-(p)={}& \left(\sqrt{p^-} \hat{p}^*_\perp, -\sqrt{p^+}\right)\,,
 \end{align}
 with $p^\pm = E\pm p_z,\, \hat{p}_\perp = \tfrac{p_\perp}{|p_\perp|},\,
 p_\perp = p_x + i p_y$. The spinors for vanishing transverse momentum
 are obtained by replacing $\hat{p_\perp} \to -1$.
 
 Explicitly, the currents read
 \begin{align}
   \label{eq:j-_explicit}
   j^-_\mu(p, q) ={}&
      \begin{pmatrix}
        \sqrt{p^+\,q^+} + \sqrt{p^-\,q^-} \hat{p}_{\perp} \hat{q}_{\perp}^*\\
        \sqrt{p^-\,q^+}\, \hat{p}_{\perp} + \sqrt{p^+\,q^-}\,\hat{q}_{\perp}^*\\
        -i \sqrt{p^-\,q^+}\, \hat{p}_{\perp} + i \sqrt{p^+\,q^-}\, \hat{q}_{\perp}^*\\
        \sqrt{p^+\,q^+} - \sqrt{p^-\,q^-}\, \hat{p}_{\perp}\, \hat{q}_{\perp}^*
      \end{pmatrix}\\
   j^+_\mu(p, q) ={}&\big(j^-_\mu(p, q)\big)^*
 \end{align}
 If $q= p_{\text{in}}$ is the momentum of an incoming parton, we have
 $\hat{p}_{\text{in} \perp} = -1$ and either $p_{\text{in}}^+ = 0$ or
 $p_{\text{in}}^- = 0$. The current simplifies further:\todo{Helicities flipped w.r.t code}
 \begin{align}
   \label{eq:j_explicit}
   j^-_\mu(p_{\text{out}}, p_{\text{in}}) ={}&
     \begin{pmatrix}
       \sqrt{p_{\text{in}}^+\,p_{\text{out}}^+}\\
       \sqrt{p_{\text{in}}^+\,p_{\text{out}}^-} \ \hat{p}_{\text{out}\,\perp}\\
       -i\,j^-_1\\
       j^-_0
     \end{pmatrix}
 & p_{\text{in}\,z} > 0\,,\\
   j^-_\mu(p_{\text{out}}, p_{\text{in}}) ={}&
     \begin{pmatrix}
       -\sqrt{p_{\text{in}}^-\,p_{\text{out}}^{-\phantom{+}}} \ \hat{p}_{\text{out}\,\perp}\\
       - \sqrt{p_{\text{in}}^-\,p_{\text{out}}^+}\\
       i\,j^-_1\\
       -j^-_0
     \end{pmatrix} & p_{\text{in}\,z} < 0\,.
 \end{align}
 
 \section{The fixed-order generator}
 \label{sec:HEJFOG}
 
 Even at leading order, standard fixed-order generators can only generate
 events with a limited number of final-state particles within reasonable
 CPU time. The purpose of the fixed-order generator is to supplement this
 with high-multiplicity input events according to the first two lines of
 eq.~\eqref{eq:resumdijetFKLmatched2} with the \HEJ approximation
 $\mathcal{M}_\text{LO, HEJ}^{f_1f_2\to f_1g\cdots gf_2}$ instead of the
 full fixed-order matrix element $\mathcal{M}_\text{LO}^{f_1f_2\to
 f_1g\cdots gf_2}$. Its usage is described in the user
 documentation \url{https://hej.web.cern.ch/HEJ/doc/current/user/HEJFOG.html}.
 
 \subsection{File structure}
 \label{sec:HEJFOG_structure}
 
 The code for the fixed-order generator is in the \texttt{FixedOrderGen}
 directory, which contains the following:
 \begin{description}
 \item[include:] Contains the C++ header files.
 \item[src:] Contains the C++ source files.
 \item[t:] Contains the source code for the automated tests.
 \item[CMakeLists.txt:] Configuration file for the \cmake build system.
 \item[configFO.yml:] Sample configuration file for the fixed-order generator.
 \end{description}
 The code is generally in the \lstinline!HEJFOG! namespace. Functions and
 classes \lstinline!MyClass! are usually declared in
 \texttt{include/MyClass.hh} and implemented in \texttt{src/MyClass.cc}.
 
 \subsection{Program flow}
 \label{sec:prog_flow}
 
 A single run of the fixed-order generator consists of three or four
 stages.
 
 First, we perform initialisation similar to HEJ 2, see
 section~\ref{sec:init}. Since there is a lot of overlap we frequently
 reuse classes and functions from HEJ 2, i.e. from the
 \lstinline!HEJ! namespace. The code for parsing the configuration file
 is in \texttt{include/config.hh} and implemented in
 \texttt{src/config.cc}.
 
 If partial unweighting is requested in the user settings \url{https://hej.web.cern.ch/HEJ/doc/current/user/HEJFOG.html#settings},
 the initialisation is followed by a calibration phase. We use a
 \lstinline!EventGenerator! to produce a number of trial
 events. We use these to calibrate the \lstinline!Unweighter! in
 its constructor and produce a first batch of partially unweighted
 events. This also allows us to estimate our unweighting efficiency.
 
 In the next step, we continue to generate events and potentially
 unweight them. Once the user-defined target number of events is reached,
 we adjust their weights according to the number of required trials. As
 in HEJ 2 (see section~\ref{sec:processing}), we pass the final
 events to a \lstinline!HEJ::Analysis! and a
 \lstinline!HEJ::CombinedEventWriter!.
 
 \subsection{Event generation}
 \label{sec:evgen}
 
 Event generation is performed by the
 \lstinline!EventGenerator::gen_event! member function. We begin by generating a
 \lstinline!PhaseSpacePoint!. This is not to be confused with
 the resummation phase space points represented by
 \lstinline!HEJ::PhaseSpacePoint!! After jet clustering, we compute the
 leading-order matrix element (see section~\ref{sec:ME}) and pdf factors.
 
 The phase space point generation is performed in the
 \lstinline!PhaseSpacePoint! constructor. We first construct the
 user-defined number of $n_p$ partons (by default gluons) in
 \lstinline!PhaseSpacePoint::gen_LO_partons!. We use flat sampling in
 rapidity and azimuthal angle. For the scalar transverse momenta, we
 distinguish between two cases. By default, they are generated based on a
 random variable $x_{p_\perp}$ according to
 \begin{equation}
   \label{eq:pt_sampling}
 p_\perp = p_{\perp,\text{min}} +
 \begin{cases}
    p_{\perp,\text{par}}
    \tan\left(
    x_{p_\perp}
    \arctan\left(
      \frac{p_{\perp,\text{max}} - p_{\perp,\text{min}}}{p_{\perp,\text{par}}}
      \right)
  \right)
 & y < y_\text{cut}
   \\
  - \tilde{p}_{\perp,\text{par}}\log\left(1 - x_{p_\perp}\left[1 -
      \exp\left(\frac{p_{\perp,\text{min}} -
          p_{\perp,\text{max}}}{\tilde{p}_{\perp,\text{par}}}\right)\right]\right)
 & y \geq y_\text{cut}
 \end{cases}\,,
 \end{equation}
 where $p_{\perp,\text{min}}$ is the minimum jet transverse momentum,
 $p_{\perp,\text{max}}$ is the maximum transverse parton momentum,
 tentatively set to the beam energy, and $y_\text{cut}$, $p_{\perp,\text{par}}$
 and $\tilde{p}_{\perp,\text{par}}$ are generation parameters set to
 heuristically determined values of
 \begin{align}
   y_\text{cut}&=3,\\
   p_{\perp,\text{par}}&=p_{\perp,\min}+\frac{n_p}{5}, \\
   \tilde{p}_{\perp,\text{par}}&=\frac{p_{\perp,\text{par}}}{1 +
     5(y-y_\text{cut})}.
 \end{align}
 The problem with this generation is that the transverse momenta peak at
 the minimum transverse momentum required for fixed-order jets. However,
 if we use the generated events as input for \HEJ resummation, events
 with such soft transverse momenta hardly contribute, see
 section~\ref{sec:ptj_res}. To generate efficient input for resummation,
 there is the user option \texttt{peak pt}, which specifies the
 dominant transverse momentum for resummation jets. If this option is
 set, most jets will be generated as above, but with
 $p_{\perp,\text{min}}$ set to the peak transverse momentum $p_{\perp,
 \text{peak}}$. In addition, there is a small chance of around $2\%$ to
 generate softer jets. The heuristic ansatz for the transverse momentum
 distribution in the ``soft'' region is
 \begin{equation}
   \label{FO_pt_soft}
   \frac{\partial \sigma}{\partial p_\perp} \propto e^{n_p\frac{p_\perp- p_{\perp,
 \text{peak}}}{\bar{p}_\perp}}\,,
 \end{equation}
 where $n_p$ is the number of partons and $\bar{p}_\perp \approx
 4\,$GeV. To achieve this distribution, we use
 \begin{equation}
   \label{eq:FO_pt_soft_sampling}
   p_\perp = p_{\perp, \text{peak}} + \bar{p}_\perp \frac{\log x_{p_\perp}}{n_p}
 \end{equation}
 and discard the phase space point if the parton is too soft, i.e. below the threshold for
 fixed-order jets.
 
 After ensuring that all partons form separate jets, we generate any
 potential colourless emissions. We then determine the incoming momenta
 and flavours in \lstinline!PhaseSpacePoint::reconstruct_incoming! and
 adjust the outgoing flavours to ensure an FKL configuration. Finally, we
 may reassign outgoing flavours to generate suppressed (for example
 unordered) configurations.
 
 \subsection{Unweighting}
 \label{sec:unweight}
 
 Straightforward event generation tends to produce many events with small
 weights. Those events have a negligible contribution to the final
 observables, but can take up considerable storage space and CPU time in
 later processing stages. This problem can be addressed by unweighting.
 
 For naive unweighting, one would determine the maximum weight
 $w_\text{max}$ of all events, discard each event with weight $w$ with a
 probability $p=w/w_\text{max}$, and set the weights of all remaining
 events to $w_\text{max}$. The downside to this procedure is that it also
 eliminates a sizeable fraction of events with moderate weight, so that
 the statistical convergence deteriorates.
 
 To ameliorate this problem, we perform unweighting only for events with
 sufficiently small weights. This is done by the
 \lstinline!Unweighter! class. In the constructor we estimate the
 mean and width of the weight-weight distribution from a sample of
 events. We use these estimates to determine the maximum weight below
 which unweighting is performed. The actual unweighting is the done in
 the \lstinline!Unweighter::unweight! function.
 
 \input{currents}
+\input{tensor}
 
 \appendix
 \section{Continuous Integration}
 \label{sec:gitlabCI}
 
 GitLab provides ways to directly test code via \textit{Continuous integrations}.
 The CI is controlled by \texttt{.gitlab-ci.yml}. For all options for the YAML
 file see \href{https://docs.gitlab.com/ee/ci/yaml/}{docs.gitlab.com/ee/ci/yaml/}.
 GitLab also provides a small tool to check that YAML syntax is correct under
 \lstinline!CI/CD > Pipelines > CI Lint! or
 \href{https://gitlab.dur.scotgrid.ac.uk/hej/HEJ/-/ci/lint}{gitlab.dur.scotgrid.ac.uk/hej/HEJ/-/ci/lint}.
 
 Currently the CI is configured to trigger a \textit{Pipeline} on each
 \lstinline!git push!. The corresponding \textit{GitLab runners} are configured
 under \lstinline!CI/CD Settings>Runners! in the GitLab UI. All runners use a
 \href{https://www.docker.com/}{docker} image as virtual environments\footnote{To
 use only Docker runners set the \lstinline!docker! tag in
 \texttt{.gitlab-ci.yml}.}. The specific docker images maintained separately. If
 you add a new dependences, please also provide a docker image for the CI. The
 goal to be able to test \HEJ with all possible configurations.
 
 Each pipeline contains multiple stages (see \lstinline!stages! in
 \texttt{.gitlab-ci.yml}) which are executed in order from top to bottom.
 Additionally each stage contains multiple jobs. For example the stage
 \textit{build} contains the jobs \lstinline!build:basic!,
 \lstinline!build:qcdloop!, \lstinline!build:rivet!, etc., which compile \HEJ for
 different environments and dependences, by using different in the Docker images.
 Jobs staring with an dot are ignored by the Runner, e.g. \lstinline!.HEJ_build!
 is only used as a template but never executed directly. Only after all jobs of
 the previous stage was executed without any error the next stage will start.
 
 To pass information between one stage and the next we use \lstinline!artifacts!.
 The runner will automatically load all artifacts form all
 \lstinline!dependencies! for each job\footnote{If no dependencies are defined
 \textit{all} artifacts from all previous jobs are downloaded. Thus please
 specify an empty dependence if you do not want to load any artifacts.}. For
 example the compiled \HEJ code from \lstinline!build:basic! gets loaded in
 \lstinline!test:basic! and \lstinline!FOG:build:basic!, without recompiling \HEJ
 again. Additionally artifacts can be downloaded from the GitLab web page, which
 could be handy for debugging.
 
 The actual commands are given in the \lstinline!before_script!,
 \lstinline!script! and \lstinline!after_script!
 \footnote{\lstinline!after_script! is always executed} sections, and are
 standard Linux shell commands (dependent on the docker image). Any failed
 command, i.e. returning not zero, stops the job and making the pipeline fail
 entirely. Most tests are just running \lstinline!make test! or are based on it.
 Thus, to emphasise it again, write tests for your code in \lstinline!cmake!. The
 CI is only intended to make automated testing in different environments easier.
 
 
 \bibliographystyle{JHEP}
 \bibliography{biblio}
 
 
 \end{document}
diff --git a/doc/developer_manual/tensor.tex b/doc/developer_manual/tensor.tex
new file mode 100644
index 0000000..31404d3
--- /dev/null
+++ b/doc/developer_manual/tensor.tex
@@ -0,0 +1,98 @@
+\section{Tensor Class}
+\label{sec:tensor}
+In the following section we detail the implementation and user
+interface to the tensor class used in the W+Jet subleading
+currents. The aim is to convert all currents to this class.
+
+\subsection{Template Class}
+\label{sec:template}
+The Tensor class is a template class. This means that it is declared as
+\lstinline!Tensor <N>!, with $N$, the rank of the tensor, specified when called.
+This means that this class breaks the mould and to keep the header file clean,
+an extra header, \texttt{include/HEJ/detail/Tensor\_impl.hh}, has been created
+which includes the implementation necessary for a template class.
+
+This grants us extra flexibility and ensures we do not have to create
+(and then maintain) multiple functions for different rank tensors,
+except in a few distinct cases.
+
+\subsection{Creating a Tensor}
+\label{sec:createTensor}
+The tensor class has several constructors and there are a few options
+open to prospective users. Firstly, if one has an old HEJ \lstinline!CCurrent! they
+simply wish to re-represent as a \lstinline!Tensor<1>!, it is
+possible to simply call \lstinline!Construct1Tensor(CCurrent j)!. One
+can also construct a Tensor class object with the use of a
+\lstinline!CLHEP::HepLorentzVector! with a similar
+syntax.
+
+One can also create a Tensor from scratch. One can calculate a
+standard \HEJ extremal quark current, $\langle p_1 | \mu | p_a \rangle$,
+where $p_a$ is the incoming momenta and $p_1$ the outgoing by the
+command: \lstinline!TCurrent(p1, h1, pa, ha)!, where \lstinline!h1! and \lstinline!ha! are the
+helicities of the particles \lstinline!p1! and \lstinline!pa!
+respectively. The order in which these particles must be supplied to
+this function is opposite to fermion flow (as with Feynman rules). So,
+if you wish to calculate the same current but for an anti-quark you simply
+need to swap the order of arguments.
+
+The light-cone momenta of those supplied in the arguments is checked
+to ensure that the correct incoming/outgoing labels are used for the
+particles, so there is no need for one to worry over the use of
+\lstinline!joi()! vs \lstinline!jio()! as in previous implementations of
+currents in \HEJ.
+
+Where this class sets itself apart from previous implementations comes
+from it being a template class, as explained in section~\ref{sec:template}.
+We can deal with much higher rank tensors with
+relative ease. One can construct $\langle p_1 | \mu \nu \rho| p_a \rangle$
+with no more effort than before, simply calling
+\lstinline!T3Current(p1, h1, pa, ha)!. A similar result can be
+obtained with \lstinline!T5Current(p1, h1, pa, ha)!, which gives the
+rank 5 version of this current.
+
+\subsection{Using the Tensor Class}
+\label{sec:UseTensor}
+There are several pre-existing Tensor class objects within HEJ, for
+example, \lstinline!eps(HLV k, HLV ref, bool pol)! will give you the
+polarisation tensor for a gluon with momenta \lstinline!k!, reference
+momentum \lstinline!ref! and polarisation \lstinline!pol!. One can
+contract Tensors together with the use of the member function
+Contract. The simplest \HEJ current can be calculated with the
+following snippet:
+
+\begin{lstlisting}[language=c++,caption={}]
+  Tensor<1> j1a = TCurrent(p1,h1,pa,ha);
+  Tensor<1> j4b = TCurrent(p4,h4,pb,hb);
+  COM 2jFKL = j1a.contract(j4b,1).at(0);
+\end{lstlisting}
+
+Where we have used \lstinline!Tensor::contract(Tensor<1> T, int i)!, which
+contracts Tensor \lstinline!T! with index \lstinline!i! of the Tensor this
+member function was called with. Notice that the contracted indices begin at
+1\todo{why? I would prefer starting at 0 - MH}. Also, that to access the value
+after contraction to a \lstinline!Tensor<0>! one has to use
+\lstinline!Tensor::at(i)!.
+
+One can contract a tensor of rank N with any tensor of rank
+1. Contractions of tensors of higher ranks have not been implemented
+at this stage.
+
+Notice this gives a lot of flexibility to calculate some very complex currents
+and easily contract them with others in the \HEJ formalism. For example, one can
+compute a Central-q$\bar{\text{q}}$ matrix element with a W boson emission from
+the Central-q$\bar{\text{q}}$ vertex with a single object that can then be
+contracted with external currents with ease.
+
+The Tensor class was implemented during the development of the W+Jets subleading
+processes (due to a need to easily construct more complex currents). This means
+that currently it is only used in the W+Jets subleading processes. It was also
+used to reimplement the pure jet central q$\bar{\text{q}}$ vertex, so once the
+central q$\bar{\text{q}}$ subleading process is implemented in the pure jets
+case fully, it will also be used there. The aim is for all processes to be moved
+over to using this Tensor class.
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "developer_manual"
+%%% End:
diff --git a/include/HEJ/Tensor.hh b/include/HEJ/Tensor.hh
index 470539e..bc5c180 100644
--- a/include/HEJ/Tensor.hh
+++ b/include/HEJ/Tensor.hh
@@ -1,204 +1,180 @@
 /** \file
  *  \brief Tensor Template Class declaration.
  *
  *  This file contains the declaration of the Tensor Template class. This
  *  is used to calculate some of the more complex currents within the
  *  W+Jets implementation particularly.
  *
  *  \authors   The HEJ collaboration (see AUTHORS for details)
  *  \date      2019
  *  \copyright GPLv2 or later
  */
 #pragma once
+
 #include <array>
+#include <complex>
+#include <valarray>
+
+namespace CLHEP {
+  class HepLorentzVector;
+}
+
+class CCurrent;
+
+typedef std::complex<double> COM;
 
-///@TODO remove function implementation from header
 ///@TODO put in some namespace
-template <unsigned int N, unsigned int D>
+template <unsigned int N>
 class Tensor{
 public:
 
-  //Constructor
+  //! Constructor
   Tensor();
   Tensor(COM x);
 
-  //Destructor
-  virtual ~Tensor();
-
+  //! Rank of Tensor
   int rank(){
     return N;
-  }
-
-  int dim(){
-    return D;
-  }
-
+  };
+  //! total number of entries
   int len(){
     return size;
-  }
-
-  COM at(int i){
-    return components[i];
-  }
-  COM at(int i, int j) {
-    return components[D*i +j];
-  }
-  COM at(int i, int j, int k) {
-    return components[D*(D*i + j)+ k];
-  }
-  COM at(int i,int j, int k,int l) {
-    return components[D*(D*(D*i +j) + k) + l];
-  }
-  COM at(int i,int j, int k,int l, int m){
-    return components[D*(D*(D*(D*i + j) + k) + l) + m];
-  }
-
-  bool isSet(){
-    if(components.size()==0)
-      return false;
-    else
-      return true;
-  }
-
-  void Fill(COM x){
-    components=x;
-  }
-
-  //Set component indexed by i,j,k,l,m
-  void Set(int i,COM x){
-    components[i] = x;
-  }
-  void Set(int i, int j, COM x) {
-    components[D*i +j] = x;
-  }
-  void Set(int i, int j, int k, COM x) {
-    components[D*(D*i + j)+ k] = x;
-  }
-  void Set(int i,int j, int k,int l,COM x) {
-    components[D*(D*(D*i +j) + k) + l] = x;
-  }
-  void Set(int i,int j, int k,int l, int m, COM x){
-    components[D*(D*(D*(D*i + j) + k) + l) + m] = x;
-  }
-
-  Tensor<N,D> operator*(const double x){
-    Tensor<N,D> newT;
-    newT.components=components*COM(x,0);
-    return newT;
-  }
-  Tensor<N,D> operator*(const COM x){
-    Tensor<N,D> newT;
-    newT.components=components*x;
-    return newT;
-  }
-  Tensor<N,D> operator/(const double x){
-    Tensor<N,D> newT;
-    newT.components=components/COM(x,0);
-    return newT;
-  }
-  Tensor<N,D> operator/(const COM x){
-    Tensor<N,D> newT;
-    newT.components=components/x;
-    return newT;
-  }
-  Tensor<N,D> operator+(const Tensor<N,D> T2){
-    Tensor<N,D> newT;
-    newT.components=components+T2.components;
-    return newT;
-  }
-  Tensor<N,D> operator-(const Tensor<N,D> T2){
-    Tensor<N,D> newT;
-    newT.components=components-T2.components;
-    return newT;
-  }
- void operator+=(const Tensor<N,D> T2){
-   components = components+T2.components;
- }
-  void operator-=(const Tensor<N,D> T2){
-    components=components-T2.components;
-  }
-
-  Tensor<N+1,D> rightprod(const Tensor<1,D> T2){
-    Tensor<N+1,D> newT;
-    for(int i=0; i<size;i++){
-      for(unsigned int j=0;j<D;j++){
-        newT.components[i*D+j]=components[i]*T2.components[j];
-      }
-    }
-    return newT;
-  }
-
-  Tensor<N+1,D> leftprod(const Tensor<1,D> T2){
-    Tensor<N+1,D> newT;
-    for(unsigned int j=0;j<D;j++){
-      for(int i=0; i<size;i++){
-        newT.components[j*size+i]=components[i]*T2.components[j];
-      }
-    }
-    return newT;
-  }
-
-  //T^(mu1...mk..mN)T2_(muk) contract kth index, where k member of [1,N]
-  Tensor<N-1,D> contract(const Tensor<1,D> T2, int k){
-    Tensor<N-1,D> newT;
-    for(int j=0; j<newT.len(); j++){
-      COM temp;
-      int itemp = pow(D,(N-k));
-      for (unsigned int i=0; i<D; i++){
-        int index = D*itemp*floor(j/itemp) + itemp*i +j%(itemp);
-        temp+=components[index]*T2.components[i]*sign(i);
-      }
-      newT.components[j]=temp;
-    }
-    return newT;
-  }
+  };
+
+  /**
+   * @{
+   * @TODO these functions are a mess and dangerous (out of bound)
+   *       better something like <code> COM at(std::array<int, N> idx) </code>
+   *       maybe in combination with <code> std::gslice <code>
+   */
+
+  //! Value of rank 1 Tensor for given i value.
+  COM at(int i);
+  //! Value of rank 2 Tensor for given (i,j) value.
+  COM at(int i, int j);
+  //! Value of rank 3 Tensor for given (i,j,k) value.
+  COM at(int i, int j, int k);
+  //! Value of rank 4 Tensor for given (i,j,k,l) value.
+  COM at(int i, int j, int k, int l);
+  //! Value of rank 3 Tensor for given (i,j,k,l,m) value.
+  COM at(int i, int j, int k, int l, int m);
+
+  //! Set all entries to x
+  void Fill(COM x);
+
+  //! Set value of rank 1 Tensor for given i value to x.
+  void Set(int i, COM x);
+  //! Set value of rank 2 Tensor for given i,j value to x.
+  void Set(int i, int j, COM x);
+  //! Set value of rank 3 Tensor for given i,j,k value to x.
+  void Set(int i, int j, int k, COM x);
+  //! Set value of rank 4 Tensor for given i,j,k,l value to x.
+  void Set(int i, int j, int k, int l, COM x);
+  //! Set value of rank 5 Tensor for given i,j,k,l,m value to x.
+  void Set(int i, int j, int k, int l, int m, COM x);
+  //!@}
+
+  Tensor<N> operator*(const double x);
+  Tensor<N> operator*(const COM x);
+  Tensor<N> operator/(const double x);
+  Tensor<N> operator/(const COM x);
+  Tensor<N> operator+(const Tensor<N> T2);
+  Tensor<N> operator-(const Tensor<N> T2);
+  void operator+=(const Tensor<N> T2);
+  void operator-=(const Tensor<N> T2);
+
+  /**
+   * \brief Multiply Tensor from Right: T1^(mu1...mk..mN-1)T2_(muN)
+   * @param T2           Tensor of Rank 1 to multiply from right with with.
+   * @returns            T1.contract(T2,1) -> T1^(mu,nu,rho...)T2^sigma
+   */
+  Tensor<N+1> rightprod(const Tensor<1> T2);
+
+  /**
+   * \brief Multiply Tensor from Left: T2_(muN)T1^(mu1...mk..mN-1)
+   * @param T2           Tensor of Rank 1 to multiply from left with with.
+   * @returns            T1.contract(T2,1) -> T2^sigma T1^(mu,nu,rho...)
+   */
+  Tensor<N+1> leftprod(const Tensor<1> T2);
+
+  /**
+   * \brief T^(mu1...mk..mN)T2_(muk) contract kth index, where k member of [1,N]
+   * @param T2           Tensor of Rank 1 to contract with.
+   * @param k            int to contract Tensor T2 with from original Tensor.
+   * @returns            T1.contract(T2,1) -> T1^(mu,nu,rho...)T2_mu
+   */
+  Tensor<N-1> contract(const Tensor<1> T2, int k);
 
   std::valarray<COM> components;
 
 private:
-
   int size;
-  COM sign(unsigned int i){
-    if(i==0)
-      return 1.;
-    else
-      return -1.;
-  }
-
+  COM sign(unsigned int i);
 };
 
-template <unsigned int N, unsigned int D> Tensor<N,D>::Tensor()
-{
-  size = pow(D,N);
-  components.resize(size);
-}
-template <unsigned int N, unsigned int D> Tensor<N,D>::Tensor(COM x) {
-  size = pow(D,N);
-  components.resize(size, x);
-}
-template <unsigned int N, unsigned int D> Tensor<N,D>::~Tensor() {}
-
-// Tensor Functions:
-// Tensor<1,4> Sigma(int i, int j, bool hel);
-// Tensor<2,4> Metric();
-// int tensor2listindex(std::array<int,5> indexlist);
-// int tensor2listindex(std::array<int,3> indexlist);
-// void perms41(int same4, int diff, std::vector<std::array<int,5>> * perms);
-// void perms32(int same3, int diff, std::vector<std::array<int,5>> * perms);
-// void perms311(int same3, int diff1, int diff2, std::vector<std::array<int,5>> * perms);
-// void perms221(int same2a, int same2b, int diff, std::vector<std::array<int,5>> * perms);
-// void perms2111(int same2, int diff1,int diff2,int diff3, std::vector<std::array<int,5>> * perms);
-// void perms21(int same, int diff, std::vector<std::array<int,3>> * perms);
-// void perms111(int diff1, int diff2, int diff3, std::vector<std::array<int,3>> * perms);
-
-Tensor<2,4> Metric();
-Tensor<1,4> TCurrent(CLHEP::HepLorentzVector p1, bool h1,
+/**
+ * \brief Returns +--- Metric
+ * @returns              Metric (+,-,-,-) {(1,0,0,0),(0,-1,0,0),(0,0,-1,0),(0,0,0,-1)}
+ */
+Tensor<2> Metric();
+
+/**
+ * \brief Calculates current <p1|mu|p2>
+ * @param p1       Momentum of Particle 1
+ * @param h1       Helicity of Particle 1 (Boolean, False = -h, True = +h)
+ * @param p2       Momentum of Particle 2
+ * @param h2       Helicity of Particle 2 (Boolean, False = -h, True = +h)
+ * @returns        Tensor T^mu = <p1|mu|p2> (in/out configuration considered in calc)
+ */
+Tensor<1> TCurrent(CLHEP::HepLorentzVector p1, bool h1,
                      CLHEP::HepLorentzVector p2, bool h2);
-Tensor<3,4> T3Current(CLHEP::HepLorentzVector p1, bool h1,
+
+/**
+ * \brief Calculates current <p1|mu nu rho|p2>
+ * @param p1       Momentum of Particle 1
+ * @param h1       Helicity of Particle 1 (Boolean, False = -h, True = +h)
+ * @param p2       Momentum of Particle 2
+ * @param h2       Helicity of Particle 2 (Boolean, False = -h, True = +h)
+ * @returns        Tensor T^mu^nu^rho = <p1|mu nu rho|p2> (in/out configuration considered in calc)
+ */
+Tensor<3> T3Current(CLHEP::HepLorentzVector p1, bool h1,
                       CLHEP::HepLorentzVector p2, bool h2);
-Tensor<5,4> T5Current(CLHEP::HepLorentzVector p1, bool h1,
+/**
+ * \brief Calculates current <p1|mu nu rho tau sigma|p2>
+ * @param p1       Momentum of Particle 1
+ * @param h1       Helicity of Particle 1 (Boolean, False = -h, True = +h)
+ * @param p2       Momentum of Particle 2
+ * @param h2       Helicity of Particle 2 (Boolean, False = -h, True = +h)
+ * @returns        Tensor T^mu^nu^rho = <p1|mu nu rho tau sigma|p2> (in/out configuration considered in calc)
+ */
+Tensor<5> T5Current(CLHEP::HepLorentzVector p1, bool h1,
                       CLHEP::HepLorentzVector p2, bool h2);
-Tensor<1,4> Construct1Tensor(CCurrent j);
-Tensor<1,4> Construct1Tensor(CLHEP::HepLorentzVector p);
-Tensor<1,4> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol);
+
+/**
+ * \brief Convert from CCurrent class
+ * @param j          Current in CCurrent format
+ * @returns          Current in Tensor Format
+ */
+Tensor<1> Construct1Tensor(CCurrent j);
+
+/**
+ * \brief Convert from HLV class
+ * @param p          Current in HLV format
+ * @returns          Current in Tensor Format
+ */
+Tensor<1> Construct1Tensor(CLHEP::HepLorentzVector p);
+
+/**
+ * \brief Construct Epsilon (Polarisation) Tensor
+ * @param k          Momentum of incoming/outgoing boson
+ * @param ref        Reference momentum for calculation
+ * @param pol        Polarisation of boson
+ * @returns          Polarisation Tensor E^mu
+ */
+Tensor<1> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol);
+
+//! Initialises Tensor values by iterating over permutations of gamma matrices.
 bool init_sigma_index();
+
+// implementation of template functions
+#include "HEJ/detail/Tensor_impl.hh"
diff --git a/include/HEJ/currents.hh b/include/HEJ/currents.hh
index 349518b..f40c8d0 100644
--- a/include/HEJ/currents.hh
+++ b/include/HEJ/currents.hh
@@ -1,1319 +1,1297 @@
 /**
  *  \authors   The HEJ collaboration (see AUTHORS for details)
  *  \date      2019
  *  \copyright GPLv2 or later
  */
 /** \file
  *  \brief Functions computing the square of current contractions.
  *
  *  This file contains all the necessary functions to compute the current
  *  contractions for all valid HEJ processes. PJETS, H+JETS and W+JETS along with
  *  some unordered counterparts.
  *
  *  @TODO add a namespace
  */
 #pragma once
 
 #include <complex>
 #include <vector>
-#include <valarray>
-#include <limits>
-
 #include <ostream>
 
 #include <CLHEP/Vector/LorentzVector.h>
 
 typedef std::complex<double> COM;
 typedef COM current[4];
 typedef CLHEP::HepLorentzVector HLV;
 
 //! Square of qQ->qenuQ W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @returns                    Square of the current contractions for qQ->qenuQ Scattering
  *
  *  This returns the square of the current contractions in qQ->qenuQ scattering
  *  with an emission of a W Boson.
  */
 double jMWqQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
               CLHEP::HepLorentzVector pnu,   CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qbarQ->qbarenuQ W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @returns                    Square of the current contractions for qbarQ->qbarenuQ Scattering
  *
  *  This returns the square of the current contractions in qbarQ->qbarenuQ scattering
  *  with an emission of a W Boson.
  */
 double jMWqbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
                  CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qQbar->qenuQbar W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @returns                    Square of the current contractions for qQbar->qenuQbar Scattering
  *
  *  This returns the square of the current contractions in qQbar->qenuQbar scattering
  *  with an emission of a W Boson.
  */
 double jMWqQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
                  CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qbarQbar->qbarenuQbar W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @returns                    Square of the current contractions for qbarQbar->qbarenuQbar Scattering
  *
  *  This returns the square of the current contractions in qbarQbar->qbarenuQbar scattering
  *  with an emission of a W Boson.
  */
 double jMWqbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
                     CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in,
                     CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! Square of qg->qenug W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @returns                    Square of the current contractions for qg->qenug Scattering
  *
  *  This returns the square of the current contractions in qg->qenug scattering
  *  with an emission of a W Boson.
  */
 double jMWqg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
               CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! Square of qbarg->qbarenug W+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @returns                    Square of the current contractions for qbarg->qbarenug Scattering
  *
  *  This returns the square of the current contractions in qbarg->qbarenug scattering
  *  with an emission of a W Boson.
  */
 double jMWqbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe,
                  CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 // W+Jets Unordered Functions
 
 //! qQg Wjets Unordered backwards opposite leg to W
 /**
  *  @param p1out                Momentum of final state quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @param pg                   Momentum of final state unordered gluon
  *  @returns                    Square of the current contractions for qQ->qQg Scattering
  *
  *  This returns the square of the current contractions in qQg->qQg scattering
  *  with an emission of a W Boson.
  */
 double junobMWqQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg);
 
 //! qbarQg Wjets Unordered backwards opposite leg to W
 /**
  *  @param p1out                Momentum of final state anti-quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @param pg                   Momentum of final state unordered gluon
  *  @returns                    Square of the current contractions for qbarQ->qbarQg Scattering
  *
  *  This returns the square of the current contractions in qbarQg->qbarQg scattering
  *  with an emission of a W Boson.
  */
 double junobMWqbarQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg);
 
 
 
 //! qQbarg Wjets Unordered backwards opposite leg to W
 /**
  *  @param p1out                Momentum of final state quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @param pg                   Momentum of final state unordered gluon
  *  @returns                    Square of the current contractions for qQbar->qQbarg Scattering
  *
  *  This returns the square of the current contractions in qQbarg->qQbarg scattering
  *  with an emission of a W Boson.
  */
 double junobMWqQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg);
 
 //! qbarQbarg Wjets Unordered backwards opposite leg to W
 /**
  *  @param p1out                Momentum of final state anti-quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @param pg                   Momentum of final state unordered gluon
  *  @returns                    Square of the current contractions for qbarQbar->qbarQbarg Scattering
  *
  *  This returns the square of the current contractions in qbarQbarg->qbarQbarg scattering
  *  with an emission of a W Boson.
  */
 double junobMWqbarQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg);
 
 
 //!Wjets Unordered forwards opposite leg to W
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @returns                    Square of the current contractions for qQ->gqQ Scattering
  *
  *  This returns the square of the current contractions in qQg->gqQ scattering
  *  with an emission of a W Boson.
  */
 double junofMWgqQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in);
 
 //!Wjets Unordered forwards opposite leg to W
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state anti-quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @returns                    Square of the current contractions for qbarQ->gqbarQ Scattering
  *
  *  This returns the square of the current contractions in qbarQg->gqbarQ scattering
  *  with an emission of a W Boson.
  */
 double junofMWgqbarQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in);
 
 //!Wjets Unordered forwards opposite leg to W
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @returns                    Square of the current contractions for qQbar->gqQbar Scattering
  *
  *  This returns the square of the current contractions in qQbarg->gqQbar scattering
  *  with an emission of a W Boson.
  */
 double junofMWgqQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in);
 
 //!Wjets Unordered forwards opposite leg to W
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state anti-quark a
  *  @param pe                   Momentum of final state electron
  *  @param pnu                  Momentum of final state Neutrino
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @returns                    Square of the current contractions for qbarQbar->gqbarQbar Scattering
  *
  *  This returns the square of the current contractions in qbarQbarg->gqbarQbar scattering
  *  with an emission of a W Boson.
  */
 double junofMWgqbarQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in);
 
 //!W+uno same leg
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @returns                    Square of the current contractions for qQ->qQg Scattering
  *
  *  This returns the square of the current contractions in gqQ->gqQ scattering
  *  with an emission of a W Boson.
  */
 double jM2WunogqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! @TODO What does this function do? Crossed contribution is Exqqx..?
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @returns                    Square of the current contractions for qQ->gqQ Scattering
  *
  *  This returns the square of the current contractions in gqQ->gqQ scattering
  *  with an emission of a W Boson.
  */
 double jM2WunogqQ_crossqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! W+uno same leg. quark anti-quark
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @returns                    Square of the current contractions for qQbar->gqQbar Scattering
  *
  *  This returns the square of the current contractions in gqQbar->gqQbar scattering
  *  with an emission of a W Boson. (Unordered Same Leg)
  */
 double jM2WunogqQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! W+uno same leg. quark gluon
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state quark a
  *  @param p2out                Momentum of final state gluon b
  *  @param p2in                 Momentum of intial state gluon b
  *  @returns                    Square of the current contractions for qg->gqg Scattering
  *
  *  This returns the square of the current contractions in qg->gqg scattering
  *  with an emission of a W Boson.
  */
 double jM2Wunogqg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! W+uno same leg. anti-quark quark
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state anti-quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state quark b
  *  @param p2in                 Momentum of intial state quark b
  *  @returns                    Square of the current contractions for qbarQ->gqbarQ Scattering
  *
  *  This returns the square of the current contractions in qbarQ->gqbarQ scattering
  *  with an emission of a W Boson.
  */
 double jM2WunogqbarQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! W+uno same leg. anti-quark anti-quark
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state anti-quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state anti-quark b
  *  @param p2in                 Momentum of intial state anti-quark b
  *  @returns                    Square of the current contractions for qbarQbar->gqbarQbar Scattering
  *
  *  This returns the square of the current contractions in gqbarQbar->qbarQbar scattering
  *  with an emission of a W Boson.
  */
 double jM2WunogqbarQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //! W+uno same leg. anti-quark gluon
 /**
  *  @param pg                   Momentum of final state unordered gluon
  *  @param p1out                Momentum of final state anti-quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param p1in                 Momentum of initial state anti-quark a
  *  @param p2out                Momentum of final state gluon b
  *  @param p2in                 Momentum of intial state gluon b
  *  @returns                    Square of the current contractions for ->gqbarg Scattering
  *
  *  This returns the square of the current contractions in qbarg->gqbarg scattering
  *  with an emission of a W Boson.
  */
 double jM2Wunogqbarg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //W+Jets qqxExtremal
 //! W+Extremal qqx. qxqQ
 /**
  *  @param pgin                 Momentum of initial state gluon
  *  @param pqout                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param pqbarout             Momentum of final state anti-quark a
  *  @param p2out                Momentum of initial state anti-quark b
  *  @param p2in                 Momentum of final state gluon b
  *  @returns                    Square of the current contractions for ->qbarqQ Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2WgQtoqbarqQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //W+Jets qqxExtremal
 //! W+Extremal qqx. qqxQ
 /**
  *  @param pgin                 Momentum of initial state gluon
  *  @param pqout                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param pqbarout             Momentum of final state anti-quark a
  *  @param p2out                Momentum of initial state anti-quark b
  *  @param p2in                 Momentum of final state gluon b
  *  @returns                    Square of the current contractions for ->qqbarQ Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2WgQtoqqbarQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //W+Jets qqxExtremal
 //! W+Extremal qqx. gg->qxqg
 /**
  *  @param pgin                 Momentum of initial state gluon
  *  @param pqout                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param pqbarout             Momentum of final state anti-quark a
  *  @param p2out                Momentum of initial state gluon b
  *  @param p2in                 Momentum of final state gluon b
  *  @returns                    Square of the current contractions for gg->qbarqg Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2Wggtoqbarqg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //W+Jets qqxExtremal
 //! W+Extremal qqx. gg->qqxg
 /**
  *  @param pgin                 Momentum of initial state gluon
  *  @param pqout                Momentum of final state quark a
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param pqbarout             Momentum of final state anti-quark a
  *  @param p2out                Momentum of initial state gluon a
  *  @param p2in                 Momentum of final state gluon b
  *  @returns                    Square of the current contractions for gg->qqbarg Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2Wggtoqqbarg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 //W+Jets qqxExtremal, W emission from opposite leg
 //! W+Extremal qqx. gg->qqxg. qqx on forwards leg, W emission backwards leg.
 /**
  *  @param pa                   Momentum of initial state (anti-)quark
  *  @param pb                   Momentum of initial state gluon
  *  @param p1                   Momentum of final state (anti-)quark (after W emission)
  *  @param p2                   Momentum of final state anti-quark
  *  @param p3                   Momentum of final state quark
  *  @param plbar                Momentum of final state anti-lepton
  *  @param pl                   Momentum of final state lepton
  *  @param aqlinepa             Is opposite extremal leg to qqx a quark or antiquark line
  *  @returns                    Square of the current contractions for gq->qqbarqW Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated via current contraction of existing currents.
  *  Assumes qqx split from forwards leg, W emission from backwards leg.
  *  Switch input (pa<->pb, p1<->pn) if calculating forwards qqx.
  */
 double jM2WgqtoQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p1,  CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, bool aqlinepa);
 
 //! W+Jets qqxCentral. qqx W emission.
 /**
  *  @param pa                Momentum of initial state particle a
  *  @param pb                Momentum of initial state particle b
  *  @param pl                Momentum of final state lepton
  *  @param plbar             Momentum of final state anti-lepton
  *  @param partons           Vector of outgoing parton momenta
  *  @param aqlinepa          Bool: True= pa is anti-quark
  *  @param aqlinepb          Bool: True= pb is anti-quark
  *  @param qqxmarker         Bool: Ordering of the qqbar pair produced (qqx vs qxq)
  *  @param nabove            Number of lipatov vertices "above" qqbar pair
  *  @param nbelow            Number of lipatov vertices "below" qqbar pair
  *  @returns                 Square of the current contractions for qq>qQQbarWq Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2WqqtoqQQq(HLV pa, HLV pb,HLV pl,HLV plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove);
 //emission from backwards leg
 
 //! W+Jets qqxCentral. W emission from backwards leg.
 /**
  *  @param ka                HLV: Momentum of initial state particle a
  *  @param kb                HLV: Momentum of initial state particle b
  *  @param pl                HLV: Momentum of final state lepton
  *  @param plbar             HLV: Momentum of final state anti-lepton
  *  @param partons           Vector(HLV): outgoing parton momenta
  *  @param aqlinepa          Bool: True= pa is anti-quark
  *  @param aqlinepb          Bool: True= pb is anti-quark
  *  @param qqxmarker         Bool: Ordering of the qqbar pair produced (qqx vs qxq)
  *  @param nabove            Int: Number of lipatov vertices "above" qqbar pair
  *  @param nbelow            Int: Number of lipatov vertices "below" qqbar pair
  *  @param forwards          Bool: Swap to emission off front leg TODO:remove so args can be const
  *  @returns                 Square of the current contractions for qq>qQQbarWq Scattering
  *
  *  Calculates the square of the current contractions with extremal qqbar pair
  *  production. This is calculated through the use of crossing symmetry.
  */
 double jM2WqqtoqQQqW(HLV ka, HLV kb,HLV pl,HLV plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove, int nbelow, bool forwards); //Doing
 
 
 
 //! Square of qQ->qQ Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @returns                    Square of the current contractions for qQ->qQ Scattering
  *
  *  This returns the square of the current contractions in qQ->qQ Pure Jet Scattering.
  */
 double jM2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qQbar->qQbar Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @returns                    Square of the current contractions for qQbar->qQbar Scattering
  *
  *  This returns the square of the current contractions in qQbar->qQbar Pure Jet Scattering.
  *  Note this can be used for qbarQ->qbarQ Scattering by inputting arguments appropriately.
  */
 double jM2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qbarQbar->qbarQbar Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @returns                    Square of the current contractions for qbarQbar->qbarQbar Scattering
  *
  *  This returns the square of the current contractions in qbarQbar->qbarQbar Pure Jet Scattering.
  */
 double jM2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                     CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qg->qg Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @returns                    Square of the current contractions for qg->qg Scattering
  *
  *  This returns the square of the current contractions in qg->qg Pure Jet Scattering.
  *  Note this can be used for gq->gq Scattering by inputting arguments appropriately.
  */
 double jM2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of qbarg->qbarg Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @returns                    Square of the current contractions for qbarg->qbarg Scattering
  *
  *  This returns the square of the current contractions in qbarg->qbarg Pure Jet Scattering.
  *  Note this can be used for gqbar->gqbar Scattering by inputting arguments appropriately.
  */
 double jM2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of gg->gg Pure Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state gluon
  *  @param p1in                 Momentum of initial state gluon
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @returns                    Square of the current contractions for gg->gg Scattering
  *
  *  This returns the square of the current contractions in gg->gg Pure Jet Scattering.
  */
 double jM2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in);
 
 
 //! Square of gg->gg Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state gluon
  *  @param p1in                 Momentum of initial state gluon
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for gg->gg Scattering
  *
  *  This returns the square of the current contractions in gg->gg Higgs+Jet Scattering.
  *
  *  g~p1 g~p2
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if g is backward, q1 is forward)
  */
 double MH2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
               CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
               double mt,
               bool include_bottom, double mb);
 
 //! Square of gq->gq Higgs+Jets Scattering Current with Higgs before Gluon
 /**
  *  @param p1out                Momentum of final state gluon
  *  @param p1in                 Momentum of initial state gluon
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param pH                   Momentum of Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contraction
  *
  */
 double MH2gq_outsideH(CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                       CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
                       CLHEP::HepLorentzVector pH,
                       double mt,
                       bool include_bottom, double mb);
 
 
 //! Square of qg->qg Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qg->qg Scattering
  *
  *  This returns the square of the current contractions in qg->qg Higgs+Jet Scattering.
  *
  *  q~p1 g~p2 (i.e. ALWAYS p1 for quark, p2 for gluon)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if g is backward, q1 is forward)
  */
 double MH2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
               CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
               double mt,
               bool include_bottom, double mb);
 
 
 //! Square of qbarg->qbarg Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarg->qbarg Scattering
  *
  *  This returns the square of the current contractions in qbarg->qbarg Higgs+Jet Scattering.
  *
  *  qbar~p1 g~p2 (i.e. ALWAYS p1 for anti-quark, p2 for gluon)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if g is backward, q1 is forward)
  */
 double MH2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
                  CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
                  double mt,
                  bool include_bottom, double mb);
 
 
 //! Square of qQ->qQ Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQ->qQ Scattering
  *
  *  This returns the square of the current contractions in qQ->qQ Higgs+Jet Scattering.
  *
  *  q~p1 Q~p2 (i.e. ALWAYS p1 for quark, p2 for quark)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if Q is backward, q1 is forward)
  */
 double MH2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
               CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
               double mt,
               bool include_bottom, double mb);
 
 //! Square of qQbar->qQbar Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                   Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQ->qQ Scattering
  *
  *  This returns the square of the current contractions in qQbar->qQbar Higgs+Jet Scattering.
  *
  *  q~p1 Qbar~p2 (i.e. ALWAYS p1 for quark, p2 for anti-quark)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if Qbar is backward, q1 is forward)
  */
 double MH2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
                  CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
                  double mt,
                  bool include_bottom, double mb);
 
 //! Square of qbarQ->qbarQ Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQ->qbarQ Scattering
  *
  *  This returns the square of the current contractions in qbarQ->qbarQ Higgs+Jet Scattering.
  *
  *  qbar~p1 Q~p2 (i.e. ALWAYS p1 for anti-quark, p2 for quark)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if Q is backward, q1 is forward)
  */
 double MH2qbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                  CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
                  CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
                  double mt,
                  bool include_bottom, double mb);
 
 
 //! Square of qbarQbar->qbarQbar Higgs+Jets Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param q1                   Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQbar->qbarQbar Scattering
  *
  *  This returns the square of the current contractions in qbarQbar->qbarQbar Higgs+Jet Scattering.
  *
  *  qbar~p1 Qbar~p2 (i.e. ALWAYS p1 for anti-quark, p2 for anti-quark)
  *  should be called with q1 meant to be contracted with p2 in first part of vertex
  *  (i.e. if Qbar is backward, q1 is forward)
  */
 double MH2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                     CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
                     CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2,
                     double mt,
                     bool include_bottom, double mb);
 
 
 // Unordered f
 
 //! Square of qQ->gqQ Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQ->gqQ Scattering
  *
  *  This returns the square of the current contractions in qQ->gqQ Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                    CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                    CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                    CLHEP::HepLorentzVector qH2,
                    double mt,
                    bool include_bottom, double mb);
 
 
 //! Square of qQbar->gqQbar Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQbar->gqQbar Scattering
  *
  *  This returns the square of the current contractions in qQbar->gqQbar Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                       CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                       CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                       CLHEP::HepLorentzVector qH2,
                       double mt,
                       bool include_bottom, double mb);
 
 //! Square of qbarQ->gqbarQ Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQ->gqbarQ Scattering
  *
  *  This returns the square of the current contractions in qbarQ->gqbarQ Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqbarHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                       CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                       CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                       CLHEP::HepLorentzVector qH2,
                       double mt,
                       bool include_bottom, double mb);
 
 //! Square of qbarQbar->gqbarQbar Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQbar->gqbarQbar Scattering
  *
  *  This returns the square of the current contractions in qbarQbar->gqbarQbar Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqbarHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                          CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                          CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                          CLHEP::HepLorentzVector qH2,
                          double mt,
                          bool include_bottom, double mb);
 
 
 //! Square of qg->gqg Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qg->gqg Scattering
  *
  *  This returns the square of the current contractions in qg->gqg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                    CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                    CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                    CLHEP::HepLorentzVector qH2,
                    double mt,
                    bool include_bottom, double mb);
 
 
 //! Square of qbarg->gqbarg Higgs+Jets Unordered f Scattering Current
 /**
  *  @param pg                   Momentum of unordered gluon
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param p2out                Momentum of final state gluon
  *  @param p2in                 Momentum of intial state gluon
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarg->gbarg Scattering
  *
  *  This returns the square of the current contractions in qbarg->gqbarg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: pg > p1out >> p2out
  */
 double jM2unogqbarHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,
                       CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out,
                       CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                       CLHEP::HepLorentzVector qH2,
                       double mt,
                       bool include_bottom, double mb);
 
 
 //Unordered b
 
 //! Square of qbarQ->qbarQg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQ->qbarQg Scattering
  *
  *  This returns the square of the current contractions in qbarQ->qbarQg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobqbarHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                        CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                        CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                        CLHEP::HepLorentzVector qH2,
                        double mt,
                        bool include_bottom, double mb);
 
 
 //! Square of qQ->qQg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQ->qQg Scattering
  *
  *  This returns the square of the current contractions in qQ->qQg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobqHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                     CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                     CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                     CLHEP::HepLorentzVector qH2,
                     double mt,
                     bool include_bottom, double mb);
 
 
 //! Square of qQbar->qQbarg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state quark
  *  @param p1in                 Momentum of initial state quark
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qQbar->qQbarg Scattering
  *
  *  This returns the square of the current contractions in qQbar->qQbarg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobqHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                        CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                        CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                        CLHEP::HepLorentzVector qH2,
                        double mt,
                        bool include_bottom, double mb);
 
 //! Square of qbarQbar->qbarQbarg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state anti-quark
  *  @param p1in                 Momentum of initial state anti-quark
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for qbarQbar->qbarQbarg Scattering
  *
  *  This returns the square of the current contractions in qbarQbar->qbarQbarg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobqbarHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                           CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                           CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                           CLHEP::HepLorentzVector qH2,
                           double mt,
                           bool include_bottom, double mb);
 
 
 //! Square of gQbar->gQbarg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state gluon
  *  @param p1in                 Momentum of initial state gluon
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state anti-quark
  *  @param p2in                 Momentum of intial state anti-quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for gQbar->gQbarg Scattering
  *
  *  This returns the square of the current contractions in gQbar->gQbarg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobgHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                        CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                        CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                        CLHEP::HepLorentzVector qH2,
                        double mt,
                        bool include_bottom, double mb);
 
 //! Square of gQ->gQg Higgs+Jets Unordered b Scattering Current
 /**
  *  @param p1out                Momentum of final state gluon
  *  @param p1in                 Momentum of initial state gluon
  *  @param pg                   Momentum of unordered b gluon
  *  @param p2out                Momentum of final state quark
  *  @param p2in                 Momentum of intial state quark
  *  @param qH1                  Momentum of t-channel propagator before Higgs
  *  @param qH2                  Momentum of t-channel propagator after Higgs
  *  @param mt                   Top quark mass
  *  @param include_bottom       Specifies whether bottom corrections are included
  *  @param mb                   Bottom quark mass
  *  @returns                    Square of the current contractions for gQ->gQg Scattering
  *
  *  This returns the square of the current contractions in gQ->gQg Higgs+Jet Scattering.
  *
  *  This construction is taking rapidity order: p1out >> p2out > pg
  */
 double jM2unobgHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
                     CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out,
                     CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1,
                     CLHEP::HepLorentzVector qH2,
                     double mt,
                     bool include_bottom, double mb);
 
 // impact factors for Higgs + jet
 
 
 //! Implements Eq. (4.22) in hep-ph/0301013 with modifications to incoming plus momenta
 /**
  * @param p2               Momentum of Particle 2
  * @param p1               Momentum of Particle 1
  * @param pH               Momentum of Higgs
  * @returns                Value of Eq. (4.22) in Hep-ph/0301013 with modifications
  *
  *  This gives the impact factor. First it determines first whether this is the case
  *  p1p\sim php>>p3p or the opposite
  */
 double C2gHgm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1,
               CLHEP::HepLorentzVector pH);
 
 
 //! Implements Eq. (4.23) in hep-ph/0301013 with modifications to incoming plus momenta
 /**
  * @param p2               Momentum of Particle 2
  * @param p1               Momentum of Particle 1
  * @param pH               Momentum of Higgs
  * @returns                Value of Eq. (4.23) in Hep-ph/0301013
  *
  *  This gives the impact factor. First it determines first whether this is the case
  *  p1p\sim php>>p3p or the opposite
  */
 double C2gHgp(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1,
               CLHEP::HepLorentzVector pH);
 
 
 //! Implements Eq. (4.22) in hep-ph/0301013
 /**
  * @param p2               Momentum of Particle 2
  * @param p1               Momentum of Particle 1
  * @param pH               Momentum of Higgs
  * @returns                Value of Eq. (4.22) in Hep-ph/0301013
  *
  *  This gives the impact factor. First it determines first whether this is the case
  *  p1p\sim php>>p3p or the opposite
  */
 double C2qHqm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1,
               CLHEP::HepLorentzVector pH);
 
 /** \class CCurrent currents.hh "include/HEJ/currents.hh"
  *  \brief This is the a new class structure for currents.
  */
 class CCurrent
 {
 public:
     CCurrent(COM sc0, COM sc1, COM sc2, COM sc3)
     :c0(sc0),c1(sc1),c2(sc2),c3(sc3)
     {};
     CCurrent(const CLHEP::HepLorentzVector p)
     {
         c0=p.e();
         c1=p.px();
         c2=p.py();
         c3=p.pz();
     };
     CCurrent()
     {};
     CCurrent operator+(const CCurrent& other);
     CCurrent operator-(const CCurrent& other);
     CCurrent operator*(const double x);
     CCurrent operator*(const COM x);
     CCurrent operator/(const double x);
     CCurrent operator/(const COM x);
 
     friend std::ostream& operator<<(std::ostream& os, const CCurrent& cur);
     COM dot(CLHEP::HepLorentzVector p1);
     COM dot(CCurrent p1);
     COM c0,c1,c2,c3;
 private:
 };
 
 /* std::ostream& operator <<(std::ostream& os, const CCurrent& cur); */
 CCurrent operator * ( double x, CCurrent& m);
 CCurrent operator * ( COM x, CCurrent& m);
 CCurrent operator / ( double x, CCurrent& m);
 CCurrent operator / ( COM x, CCurrent& m);
 
-
-//! Current <outgoing state | mu | incoming state>
-/**
- * These functions are a mess. There are many more defined in the source file than declared in the
- * header - and the arguments are mislabelled in some cases. Need to investigate.
- */
-//! @TODO remove
-[[deprecated("Use joi instead")]]
-void j (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin,current &cur);
-
 //! Current <incoming state | mu | outgoing state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
 void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur);
 
 //! Current <outgoing state | mu | outgoing state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
 void joo(HLV pi, bool heli, HLV pj, bool helj, current &cur);
 
 //! Current <outgoing state | mu | incoming state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
 void joi(HLV pout, bool helout, HLV pin, bool helin, current &cur);
 
 //! Current <outgoing state | mu | incoming state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
-//! @TODO remove
-[[deprecated("Use joi instead")]]
-CCurrent j (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin);
-
-//! Current <outgoing state | mu | incoming state>
-/**
- * These functions are a mess. There are many more defined in the source file than declared in the
- * header - and the arguments are mislabelled in some cases. Need to investigate.
- */
 CCurrent joi (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin);
 
 //! Current <incoming state | mu | outgoing state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
 CCurrent jio (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin);
 
 //! Current <outgoing state | mu | outgoing state>
 /**
  * These functions are a mess. There are many more defined in the source file than declared in the
  * header - and the arguments are mislabelled in some cases. Need to investigate.
  */
 CCurrent joo (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin);
 
 inline COM cdot(const current & j1, const current & j2)
 {
   return j1[0]*j2[0]-j1[1]*j2[1]-j1[2]*j2[2]-j1[3]*j2[3];
 }
 
 inline COM cdot(const HLV & p, const current & j1) {
   return j1[0]*p.e()-j1[1]*p.x()-j1[2]*p.y()-j1[3]*p.z();
 }
 
 inline void cmult(const COM & factor, const current & j1, current &cur)
 {
   cur[0]=factor*j1[0];
   cur[1]=factor*j1[1];
   cur[2]=factor*j1[2];
   cur[3]=factor*j1[3];
 }
 
 // WHY!?!
 inline void cadd(const current & j1, const current & j2, const current & j3,
           const current & j4, const current & j5, current &sum)
 {
   sum[0]=j1[0]+j2[0]+j3[0]+j4[0]+j5[0];
   sum[1]=j1[1]+j2[1]+j3[1]+j4[1]+j5[1];
   sum[2]=j1[2]+j2[2]+j3[2]+j4[2]+j5[2];
   sum[3]=j1[3]+j2[3]+j3[3]+j4[3]+j5[3];
 }
 
 inline void cadd(const current & j1, const current & j2, const current & j3,
           const current & j4, current &sum) {
   sum[0] = j1[0] + j2[0] + j3[0] + j4[0];
   sum[1] = j1[1] + j2[1] + j3[1] + j4[1];
   sum[2] = j1[2] + j2[2] + j3[2] + j4[2];
   sum[3] = j1[3] + j2[3] + j3[3] + j4[3];
 }
 
 inline void cadd(const current & j1, const current & j2, const current & j3,
          current &sum)
 {
   sum[0]=j1[0]+j2[0]+j3[0];
   sum[1]=j1[1]+j2[1]+j3[1];
   sum[2]=j1[2]+j2[2]+j3[2];
   sum[3]=j1[3]+j2[3]+j3[3];
 }
 
 inline void cadd(const current & j1, const current & j2, current &sum)
 {
   sum[0]=j1[0]+j2[0];
   sum[1]=j1[1]+j2[1];
   sum[2]=j1[2]+j2[2];
   sum[3]=j1[3]+j2[3];
 }
 
 inline double abs2(const COM & a)
 {
     return (a*conj(a)).real();
 }
 
 inline double vabs2(const CCurrent & cur)
 {
     return abs2(cur.c0)-abs2(cur.c1)-abs2(cur.c2)-abs2(cur.c3);
 }
 
 inline double vre(const CCurrent & a, const CCurrent & b)
 {
   return real(a.c0*conj(b.c0)-a.c1*conj(b.c1)-a.c2*conj(b.c2)-a.c3*conj(b.c3));
 }
 // @TODO: These are not currents and should be moved elsewhere.
 double K_g(double p1minus, double paminus);
 double K_g(CLHEP::HepLorentzVector const & pout, CLHEP::HepLorentzVector const & pin);
diff --git a/include/HEJ/detail/Tensor_impl.hh b/include/HEJ/detail/Tensor_impl.hh
new file mode 100644
index 0000000..5bcd19f
--- /dev/null
+++ b/include/HEJ/detail/Tensor_impl.hh
@@ -0,0 +1,168 @@
+/** \file
+ *  \brief Tensor Template Class Implementation.
+ *
+ *  This file contains the implementation of the Tensor Template functions
+ *
+ *  \authors The HEJ collaboration (see AUTHORS for details)
+ *  \date 2019
+ *  \copyright GPLv2 or later
+ */
+
+template <unsigned int N>
+Tensor<N>::Tensor(){
+  size = pow(4,N);
+  components.resize(size);
+}
+
+template <unsigned int N>
+Tensor<N>::Tensor(COM x) {
+  size = pow(4,N);
+  components.resize(size, x);
+}
+
+template <unsigned int N>
+COM Tensor<N>::at(int i){
+  return components[i];
+}
+template <unsigned int N>
+COM Tensor<N>::at(int i, int j) {
+  return components[4*i +j];
+}
+template <unsigned int N>
+COM Tensor<N>::at(int i, int j, int k) {
+  return components[4*(4*i + j)+ k];
+}
+template <unsigned int N>
+COM Tensor<N>::at(int i, int j, int k,int l) {
+  return components[4*(4*(4*i +j) + k) + l];
+}
+template <unsigned int N>
+COM Tensor<N>::at(int i, int j, int k, int l, int m){
+  return components[4*(4*(4*(4*i + j) + k) + l) + m];
+}
+
+template <unsigned int N>
+void Tensor<N>::Fill(COM x){
+  components=x;
+}
+
+template <unsigned int N>
+void Tensor<N>::Set(int i,COM x){
+  components[i] = x;
+}
+
+template <unsigned int N>
+void Tensor<N>::Set(int i, int j, COM x) {
+  components[4*i +j] = x;
+}
+
+template <unsigned int N>
+void Tensor<N>::Set(int i, int j, int k, COM x) {
+  components[4*(4*i + j)+ k] = x;
+}
+
+template <unsigned int N>
+void Tensor<N>::Set(int i, int j, int k, int l,COM x) {
+  components[4*(4*(4*i +j) + k) + l] = x;
+}
+
+template <unsigned int N>
+void Tensor<N>::Set(int i, int j, int k, int l, int m, COM x){
+  components[4*(4*(4*(4*i + j) + k) + l) + m] = x;
+}
+
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator*(const double x){
+  Tensor<N> newT;
+  newT.components=components*COM(x,0);
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator*(const COM x){
+  Tensor<N> newT;
+  newT.components=components*x;
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator/(const double x){
+  Tensor<N> newT;
+  newT.components=components/COM(x,0);
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator/(const COM x){
+  Tensor<N> newT;
+  newT.components=components/x;
+  return newT;
+}
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator+(const Tensor<N> T2){
+  Tensor<N> newT;
+  newT.components=components+T2.components;
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N> Tensor<N>::operator-(const Tensor<N> T2){
+  Tensor<N> newT;
+  newT.components=components-T2.components;
+  return newT;
+}
+
+template <unsigned int N>
+void Tensor<N>::operator+=(const Tensor<N> T2){
+  components = components+T2.components;
+}
+
+template <unsigned int N>
+void Tensor<N>::operator-=(const Tensor<N> T2){
+  components=components-T2.components;
+}
+
+template <unsigned int N>
+Tensor<N+1> Tensor<N>::rightprod(const Tensor<1> T2){
+  Tensor<N+1> newT;
+  for(int i=0; i<size;i++){
+    for(unsigned int j=0;j<4;j++){
+      newT.components[i*4+j]=components[i]*T2.components[j];
+    }
+  }
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N+1> Tensor<N>::leftprod(const Tensor<1> T2){
+  Tensor<N+1> newT;
+  for(unsigned int j=0;j<4;j++){
+    for(int i=0; i<size;i++){
+      newT.components[j*size+i]=components[i]*T2.components[j];
+    }
+  }
+  return newT;
+}
+
+template <unsigned int N>
+Tensor<N-1> Tensor<N>::contract(const Tensor<1> T2, int k){
+  Tensor<N-1> newT;
+  for(int j=0; j<newT.len(); j++){
+    COM temp;
+    int itemp = pow(4,(N-k));
+    for (unsigned int i=0; i<4; i++){
+      int index = 4*itemp*floor(j/itemp) + itemp*i +j%(itemp);
+      temp+=components[index]*T2.components[i]*sign(i);
+    }
+    newT.components[j]=temp;
+  }
+  return newT;
+}
+
+template <unsigned int N>
+COM Tensor<N>::sign(unsigned int i){
+  if(i==0)
+    return 1.;
+  else
+    return -1.;
+}
diff --git a/src/Tensor.cc b/src/Tensor.cc
index af7e882..0cac83b 100644
--- a/src/Tensor.cc
+++ b/src/Tensor.cc
@@ -1,795 +1,797 @@
 /**
  *  \authors   The HEJ collaboration (see AUTHORS for details)
  *  \date      2019
  *  \copyright GPLv2 or later
  */
-#include "HEJ/currents.hh"
 #include "HEJ/Tensor.hh"
 
 #include <array>
-
 #include <iostream>
 
+#include <CLHEP/Vector/LorentzVector.h>
+
+#include "HEJ/currents.hh" // only for CCurrent (?)
+
 namespace{
 // Tensor Template definitions
   short int sigma_index5[1024];
   short int sigma_index3[64];
   std::valarray<COM> permfactor5;
   std::valarray<COM> permfactor3;
   short int helfactor5[2][1024];
   short int helfactor3[2][64];
 
   // 2D sigma matrices
   const COM sigma0[2][2] = { {1.,0.},          {0.,          1.} };
   const COM sigma1[2][2] = { {0.,1.},          {1.,          0.} };
   const COM sigma2[2][2] = { {0,-1.*COM(0,1)}, {1.*COM(0,1), 0.} };
   const COM sigma3[2][2] = { {1.,0.},          {0.,         -1.} };
 
-  Tensor<1,4> Sigma(int i, int j, bool hel){
-    Tensor<1,4> newT;
+  Tensor<1> Sigma(int i, int j, bool hel){
+    Tensor<1> newT;
     if(hel){
       newT.components[0]=sigma0[i][j];
       newT.components[1]=sigma1[i][j];
       newT.components[2]=sigma2[i][j];
       newT.components[3]=sigma3[i][j];
     } else {
       newT.components[0]= sigma0[i][j];
       newT.components[1]=-sigma1[i][j];
       newT.components[2]=-sigma2[i][j];
       newT.components[3]=-sigma3[i][j];
     }
     return newT;
   }
 
   // map from a list of 5 tensor lorentz indices onto a single index 0<=i<1024
   // in 4 dimensional spacetime
 
   int tensor2listindex(std::array<int,5> indexlist){
     int mu=indexlist[0];
     int nu=indexlist[1];
     int sigma=indexlist[2];
     int tau=indexlist[3];
     int rho=indexlist[4];
     int myindex;
 
     myindex = 256*mu+64*nu+16*sigma+4*tau+rho;
 
     if(myindex<0||myindex>1023){
       std::cerr<<"bad index in tensor2listindex "<<std::endl;
       return 1024;
     }
     return myindex;
   }
 
   // map from a list of 3 tensor lorentz indices onto a single index 0<=i<64 in
   // 4 dimensional spacetime
   int tensor2listindex(std::array<int,3> indexlist){
     int mu=indexlist[0];
     int nu=indexlist[1];
     int sigma=indexlist[2];
     int myindex;
 
     myindex = 16*mu+4*nu+sigma;
 
     if(myindex<0||myindex>64){
       std::cerr<<"bad index in tensor2listindex "<<std::endl;
       return 64;
     }
     return myindex;
   }
 
   // generate all unique perms of vectors {a,a,a,a,b}, return in perms
   // set_permfactor is a bool which encodes the anticommutation relations of the
   // sigma matrices namely if we have sigma0, set_permfactor= false because it
   // commutes with all others otherwise we need to assign a minus sign to odd
   // permutations, set in permfactor
   // note, inital perm is always even
   void perms41(int same4, int diff, std::vector<std::array<int,5>> & perms){
     bool set_permfactor(true);
     if(same4==0||diff==0)
       set_permfactor=false;
 
     for(int diffpos=0;diffpos<5;diffpos++){
       std::array<int,5> tempvec={same4,same4,same4,same4,same4};
       tempvec[diffpos]=diff;
       perms.push_back(tempvec);
       if(set_permfactor){
         if(diffpos%2==1)
           permfactor5[tensor2listindex(tempvec)]=-1.;
       }
     }
   }
 
   // generate all unique perms of vectors {a,a,a,b,b}, return in perms
   // note, inital perm is always even
   void perms32(int same3, int diff, std::vector<std::array<int,5>> & perms){
     bool set_permfactor(true);
     if(same3==0||diff==0)
       set_permfactor=false;
 
     for(int diffpos1=0;diffpos1<5;diffpos1++){
       for(int diffpos2=diffpos1+1;diffpos2<5;diffpos2++){
         std::array<int,5> tempvec={same3,same3,same3,same3,same3};
         tempvec[diffpos1]=diff;
         tempvec[diffpos2]=diff;
         perms.push_back(tempvec);
         if(set_permfactor){
           if((diffpos2-diffpos1)%2==0)
             permfactor5[tensor2listindex(tempvec)]=-1.;
         }
       }
     }
   }
 
   // generate all unique perms of vectors {a,a,a,b,c}, return in perms
   // we have two bools since there are three distinct type of sigma matrices to
   // permute, so need to test if the 3xrepeated = sigma0 or if one of the
   // singles is sigma0
   // if diff1/diff2 are distinct, flipping them results in a change of perm,
   // otherwise it'll be symmetric under flip -> encode this in set_permfactor2
   // as long as diff2!=0 can ensure inital perm is even
   // if diff2=0 then it is not possible to ensure inital perm even -> encode in
   // bool signflip
   void perms311(int same3, int diff1, int diff2,
       std::vector<std::array<int,5>> & perms
   ){
     bool set_permfactor2(true);
     bool same0(false);
     bool diff0(false);
     bool signflip(false); // if true, inital perm is odd
 
     if(same3==0) // is the repeated matrix sigma0?
       same0 = true;
     else if(diff2==0){ // is one of the single matrices sigma0
       diff0=true;
       if((diff1%3-same3)!=-1)
         signflip=true;
       } else if(diff1==0){
         std::cerr<<"Note, only first and last argument may be zero"<<std::endl;
         return;
     }
 
     // possible outcomes: tt, ft, tf
 
     for(int diffpos1=0;diffpos1<5;diffpos1++){
       for(int diffpos2=diffpos1+1;diffpos2<5;diffpos2++){
         std::array<int,5> tempvec={same3,same3,same3,same3,same3};
         tempvec[diffpos1]=diff1;
         tempvec[diffpos2]=diff2;
         perms.push_back(tempvec);
 
         if(!same0 && !diff0){
         // full antisymmetric under exchange of same3,diff1,diff2
           if((diffpos2-diffpos1)%2==0){
             permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm
             // if this perm is odd, swapping diff1<->diff2 automatically even
             set_permfactor2=false;
           } else {
             permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm
             // if this perm is even, swapping diff1<->diff2 automatically odd
             set_permfactor2=true;
           }
         } else if(diff0){// one of the single matrices is sigma0
           if(signflip){ // initial config is odd!
             if(diffpos1%2==1){
               permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm
               // initally symmetric under diff1<->diff2 =>
               // if this perm is even, automatically even for first diffpos2
               set_permfactor2=false;
             } else {
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm
               // initally symmetric under diff1<->diff2 =>
               // if this perm is odd, automatically odd for first diffpos2
               set_permfactor2=true;
             }
           } else {// diff0=true, initial config is even
             if(diffpos1%2==1){
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm
               // initally symmetric under diff1<->diff2 =>
               // if this perm is odd, automatically odd for first diffpos2
               set_permfactor2=true;
             } else {
               permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm
               // initally symmetric under diff1<->diff2 =>
               // if this perm is even, automatically even for first diffpos2
               set_permfactor2=false;
             }
           }
           if((diffpos2-diffpos1-1)%2==1)
             set_permfactor2=!set_permfactor2; // change to account for diffpos2
         } else if(same0){
           // the repeated matrix is sigma0
           // => only relative positions of diff1, diff2 matter.
           // always even before flip  because diff1pos<diff2pos
           permfactor5[tensor2listindex(tempvec)]=COM(0,1);
           // if this perm is odd, swapping diff1<->diff2 automatically odd
           set_permfactor2=true;
         }
 
         tempvec[diffpos1]=diff2;
         tempvec[diffpos2]=diff1;
         perms.push_back(tempvec);
 
         if(set_permfactor2)
           permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);
         else
           permfactor5[tensor2listindex(tempvec)]=COM(0,1);
 
       }
     }
   } // end perms311
 
   // generate all unique perms of vectors {a,a,b,b,c}, return in perms
   void perms221(int same2a, int same2b, int diff,
       std::vector<std::array<int,5>> & perms
   ){
     bool set_permfactor1(true);
     bool set_permfactor2(true);
     if(same2b==0){
       std::cerr<<"second entry in perms221() shouldn't be zero" <<std::endl;
       return;
     } else if(same2a==0)
       set_permfactor1=false;
     else if(diff==0)
       set_permfactor2=false;
 
     for(int samepos=0;samepos<5;samepos++){
       int permcount = 0;
       for(int samepos2=samepos+1;samepos2<5;samepos2++){
         for(int diffpos=0;diffpos<5;diffpos++){
           if(diffpos==samepos||diffpos==samepos2) continue;
 
           std::array<int,5> tempvec={same2a,same2a,same2a,same2a,same2a};
           tempvec[samepos]=same2b;
           tempvec[samepos2]=same2b;
           tempvec[diffpos]=diff;
           perms.push_back(tempvec);
 
           if(set_permfactor1){
             if(set_permfactor2){// full anti-symmetry
               if(permcount%2==1)
           permfactor5[tensor2listindex(tempvec)]=-1.;
             } else { // diff is sigma0
               if( ((samepos2-samepos-1)%3>0)
                   && (abs(abs(samepos2-diffpos)-abs(samepos-diffpos))%3>0) )
                 permfactor5[tensor2listindex(tempvec)]=-1.;
             }
           } else { // same2a is sigma0
             if((diffpos>samepos) && (diffpos<samepos2))
               permfactor5[tensor2listindex(tempvec)]=-1.;
           }
           permcount++;
         }
       }
     }
   }
 
   // generate all unique perms of vectors {a,a,b,b,c}, return in perms
   // there must be a sigma zero if we have 4 different matrices in string
   // bool is true if sigma0 is the repeated matrix
   void perms2111(int same2, int diff1,int diff2,int diff3,
       std::vector<std::array<int,5>> & perms
   ){
     bool twozero(false);
     if(same2==0)
       twozero=true;
     else if (diff1!=0){
       std::cerr<<"One of first or second argurments must be a zero"<<std::endl;
       return;
     } else if(diff2==0|| diff3==0){
       std::cerr<<"Only first and second arguments may be a zero."<<std::endl;
       return;
     }
 
     int permcount = 0;
 
     for(int diffpos1=0;diffpos1<5;diffpos1++){
       for(int diffpos2=0;diffpos2<5;diffpos2++){
         if(diffpos2==diffpos1) continue;
         for(int diffpos3=0;diffpos3<5;diffpos3++){
           if(diffpos3==diffpos2||diffpos3==diffpos1) continue;
 
           std::array<int,5> tempvec={same2,same2,same2,same2,same2};
           tempvec[diffpos1]=diff1;
           tempvec[diffpos2]=diff2;
           tempvec[diffpos3]=diff3;
           perms.push_back(tempvec);
 
           if(twozero){// don't care about exact positions of singles, just order
             if(diffpos2>diffpos3 && diffpos3>diffpos1)
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd
             else if(diffpos1>diffpos2 && diffpos2>diffpos3)
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd
             else if(diffpos3>diffpos1 && diffpos1>diffpos2)
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd
             else
               permfactor5[tensor2listindex(tempvec)]=COM(0,1);// evwn
           } else {
             if(permcount%2==1)
               permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);
             else
               permfactor5[tensor2listindex(tempvec)]=COM(0,1);
           }
           permcount++;
         }
       }
     }
   }
 
   void perms21(int same, int diff, std::vector<std::array<int,3>> & perms){
 
     bool set_permfactor(true);
     if(same==0||diff==0)
       set_permfactor=false;
 
     for(int diffpos=0; diffpos<3;diffpos++){
       std::array<int,3> tempvec={same,same,same};
       tempvec[diffpos]=diff;
       perms.push_back(tempvec);
       if(set_permfactor && diffpos==1)
         permfactor3[tensor2listindex(tempvec)]=-1.;
     }
   }
 
   void perms111(int diff1, int diff2, int diff3,
     std::vector<std::array<int,3>> & perms
   ){
     bool sig_zero(false);
     if(diff1==0)
       sig_zero=true;
     else if(diff2==0||diff3==0){
       std::cerr<<"Only first argument may be a zero."<<std::endl;
       return;
     }
     int permcount=0;
     for(int pos1=0;pos1<3;pos1++){
       for(int pos2=pos1+1;pos2<3;pos2++){
         std::array<int,3> tempvec={diff1,diff1,diff1};
         tempvec[pos1]=diff2;
         tempvec[pos2]=diff3;
         perms.push_back(tempvec);
         if(sig_zero){
           permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even
         } else if(permcount%2==1){
           permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd
         } else {
           permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even
         }
 
         tempvec[pos1]=diff3;
         tempvec[pos2]=diff2;
         perms.push_back(tempvec);
 
         if(sig_zero){
           permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd
         } else if(permcount%2==1){
           permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even
         } else {
           permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd
         }
         permcount++;
       }
     }
   }
 
   void SpinorO(CLHEP::HepLorentzVector p, bool hel, COM *sp){
     // sp is pointer to COM sp[2]
     COM pplus = p.e() +p.z();
     COM pminus = p.e() -p.z();
     COM sqpp= sqrt(pplus);
     COM sqpm= sqrt(pminus);
     COM pperp = p.x() + COM(0,1)*p.y();
 
     // if hel=+
     if(hel){
       sp[0] = sqpp;
       sp[1] = sqpm*pperp/abs(pperp);
     } else {
       sp[0] = sqpm*conj(pperp)/abs(pperp);
       sp[1] = -sqpp;
     }
   }
 
   void SpinorIp(COM sqpp, bool hel, COM *sp){
     // if hel=+
     if(hel){
       sp[0] = sqpp;
       sp[1] = 0.;
     } else {
       sp[0] = 0.;
       sp[1] = -sqpp;
     }
   }
 
   void SpinorIm(COM sqpm, bool hel, COM *sp){
     // if hel=+
     if(hel){
       sp[0] = 0;
       sp[1] = -sqpm;
     } else {
       sp[0] = -sqpm;
       sp[1] = 0.;
     }
   }
 
   void Spinor(CLHEP::HepLorentzVector p, bool hel, COM *sp){
     COM pplus = p.e() +p.z();
     COM pminus = p.e() -p.z();
 
     // If incoming along +ve z
     if (pminus==0.){
       COM sqpp= sqrt(pplus);
       SpinorIp(sqpp,hel,sp);
     }
     // If incoming along -ve z
     else if(pplus==0.){
       COM sqpm= sqrt(pminus);
       SpinorIm(sqpm,hel,sp);
     }
     // Outgoing
     else {
       SpinorO(p,hel,sp);
     }
   }
 } // anonymous namespace
 
-Tensor<2,4> Metric(){
-  Tensor<2,4> g(0.);
+Tensor<2> Metric(){
+  Tensor<2> g(0.);
   g.Set(0,0, 1.);
   g.Set(1,1, -1.);
   g.Set(2,2, -1.);
   g.Set(3,3, -1.);
   return g;
 }
 
 // <1|mu|2>
-Tensor<1,4> TCurrent(CLHEP::HepLorentzVector p1, bool h1,
+Tensor<1> TCurrent(CLHEP::HepLorentzVector p1, bool h1,
                      CLHEP::HepLorentzVector p2, bool h2
 ){
   COM sp1[2];
   COM sp2[2];
-  Tensor<1,4> newT(0.);
+  Tensor<1> newT(0.);
 
   CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 };
   CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 };
 
   if(h1!=h2){
     return newT;
   }
 
   Spinor(p1new, h1, sp1);
   Spinor(p2new, h2, sp2);
 
   for(int i=0;i<2;i++){
     for(int j=0; j<2; j++){
       newT+=(Sigma(i,j,h2)*sp2[j])*conj(sp1[i]);
     }
   }
   return newT;
 }
 // <1|mu nu sigma|2>
-Tensor<3,4> T3Current(CLHEP::HepLorentzVector p1, bool h1,
+Tensor<3> T3Current(CLHEP::HepLorentzVector p1, bool h1,
   CLHEP::HepLorentzVector p2, bool h2
 ){
 
   COM sp1[2];
   COM sp2[2];
 
-  Tensor<3,4> newT(0.);
+  Tensor<3> newT(0.);
 
   CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 };
   CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 };
 
   if(h1!=h2){
     return newT;
   }
 
   Spinor(p1new, h1, sp1);
   Spinor(p2new, h2, sp2);
 
   COM current[4];
 
   for(int i=0; i<2;i++){
     for(int j=0; j<2;j++){
       current[0]+=conj(sp1[i])*sigma0[i][j]*sp2[j];
       current[1]+=conj(sp1[i])*sigma1[i][j]*sp2[j];
       current[2]+=conj(sp1[i])*sigma2[i][j]*sp2[j];
       current[3]+=conj(sp1[i])*sigma3[i][j]*sp2[j];
     }
   }
 
   for( int itensor=0; itensor<newT.len(); itensor++ ){
     double hfact = double( helfactor3[h2][itensor] );
     newT.components[itensor] = current[sigma_index3[itensor]] * hfact
                               * permfactor3[itensor];
   }
 
   return newT;
 }
 
 // <1|mu nu sigma tau rho|2>
-Tensor<5,4> T5Current(CLHEP::HepLorentzVector p1, bool h1,
+Tensor<5> T5Current(CLHEP::HepLorentzVector p1, bool h1,
                       CLHEP::HepLorentzVector p2, bool h2
 ){
 
   COM sp1[2];
   COM sp2[2];
 
-  Tensor<5,4> newT(0.);
+  Tensor<5> newT(0.);
 
   CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 };
   CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 };
 
   if(h1!=h2){
     return newT;
   }
 
   Spinor(p1new, h1, sp1);
   Spinor(p2new, h2, sp2);
 
   COM current[4];
 
   for(int i=0; i<2;i++){
     for(int j=0; j<2;j++){
       current[0]+=conj(sp1[i])*sigma0[i][j]*sp2[j];
       current[1]+=conj(sp1[i])*sigma1[i][j]*sp2[j];
       current[2]+=conj(sp1[i])*sigma2[i][j]*sp2[j];
       current[3]+=conj(sp1[i])*sigma3[i][j]*sp2[j];
     }
   }
 
   for(int itensor=0;itensor<newT.len();itensor++){
     double hfact = double(helfactor5[h2][itensor]);
     newT.components[itensor] = current[sigma_index5[itensor]] * hfact
                               * permfactor5[itensor];
   }
 
   return newT;
 }
 
-Tensor<1,4> Construct1Tensor(CCurrent j){
-  Tensor<1,4> newT;
+Tensor<1> Construct1Tensor(CCurrent j){
+  Tensor<1> newT;
   newT.components={j.c0,j.c1,j.c2,j.c3};
   return newT;
 }
 
-Tensor<1,4> Construct1Tensor(CLHEP::HepLorentzVector p){
-  Tensor<1,4> newT;
+Tensor<1> Construct1Tensor(CLHEP::HepLorentzVector p){
+  Tensor<1> newT;
   newT.components={p.e(),p.x(),p.y(),p.z()};
   return newT;
 }
 
-Tensor<1,4> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol){
+Tensor<1> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol){
 
-  Tensor<1,4> polvec;
+  Tensor<1> polvec;
   COM spk[2];
   COM spr[2];
   COM denom;
 
   CLHEP::HepLorentzVector knew{ k.e()<0?-k:k };
 
   Spinor(knew, pol, spk);
   Spinor(ref, !pol, spr);
   denom  = pow(-1.,pol)*sqrt(2)*(conj(spr[0])*spk[0] + conj(spr[1])*spk[1]);
   polvec = TCurrent(ref,!pol,knew,!pol)/denom;
 
   return polvec;
 }
 
 // slow function! - but only need to evaluate once.
 bool init_sigma_index(){
 
   // initialize permfactor(3) to list of ones (change to minus one for each odd
   // permutation and multiply by i for all permutations in perms2111, perms311,
   // perms111)
   permfactor5.resize(1024,1.);
   permfactor3.resize(64,1.);
 
   // first set sigma_index (5)
   std::vector<std::array<int,5>> sigma0indices;
   std::vector<std::array<int,5>> sigma1indices;
   std::vector<std::array<int,5>> sigma2indices;
   std::vector<std::array<int,5>> sigma3indices;
 
   // need to generate all possible permuations of {i,j,k,l,m}
   // where each index can be {0,1,2,3,4}
   // 1024 possibilities
 
   // perms with 5 same
   sigma0indices.push_back({0,0,0,0,0});
   sigma1indices.push_back({1,1,1,1,1});
   sigma2indices.push_back({2,2,2,2,2});
   sigma3indices.push_back({3,3,3,3,3});
 
   // perms with 4 same
   perms41(1,0,sigma0indices);
   perms41(2,0,sigma0indices);
   perms41(3,0,sigma0indices);
   perms41(0,1,sigma1indices);
   perms41(2,1,sigma1indices);
   perms41(3,1,sigma1indices);
   perms41(0,2,sigma2indices);
   perms41(1,2,sigma2indices);
   perms41(3,2,sigma2indices);
   perms41(0,3,sigma3indices);
   perms41(1,3,sigma3indices);
   perms41(2,3,sigma3indices);
 
   // perms with 3 same, 2 same
   perms32(0,1,sigma0indices);
   perms32(0,2,sigma0indices);
   perms32(0,3,sigma0indices);
   perms32(1,0,sigma1indices);
   perms32(1,2,sigma1indices);
   perms32(1,3,sigma1indices);
   perms32(2,0,sigma2indices);
   perms32(2,1,sigma2indices);
   perms32(2,3,sigma2indices);
   perms32(3,0,sigma3indices);
   perms32(3,1,sigma3indices);
   perms32(3,2,sigma3indices);
 
   // perms with 3 same, 2 different
   perms311(1,2,3,sigma0indices);
   perms311(2,3,1,sigma0indices);
   perms311(3,1,2,sigma0indices);
   perms311(0,2,3,sigma1indices);
   perms311(2,3,0,sigma1indices);
   perms311(3,2,0,sigma1indices);
   perms311(0,3,1,sigma2indices);
   perms311(1,3,0,sigma2indices);
   perms311(3,1,0,sigma2indices);
   perms311(0,1,2,sigma3indices);
   perms311(1,2,0,sigma3indices);
   perms311(2,1,0,sigma3indices);
 
   perms221(1,2,0,sigma0indices);
   perms221(1,3,0,sigma0indices);
   perms221(2,3,0,sigma0indices);
   perms221(0,2,1,sigma1indices);
   perms221(0,3,1,sigma1indices);
   perms221(2,3,1,sigma1indices);
   perms221(0,1,2,sigma2indices);
   perms221(0,3,2,sigma2indices);
   perms221(1,3,2,sigma2indices);
   perms221(0,1,3,sigma3indices);
   perms221(0,2,3,sigma3indices);
   perms221(1,2,3,sigma3indices);
 
   perms2111(0,1,2,3,sigma0indices);
   perms2111(1,0,2,3,sigma1indices);
   perms2111(2,0,3,1,sigma2indices);
   perms2111(3,0,1,2,sigma3indices);
 
   if(sigma0indices.size()!=256){
     std::cerr<<"sigma_index not set: ";
     std::cerr<<"sigma0indices has "<< sigma0indices.size() << " components" << std::endl;
     return false;
   } else if(sigma1indices.size()!=256){
     std::cerr<<"sigma_index not set: ";
     std::cerr<<"sigma1indices has "<< sigma0indices.size() << " components" << std::endl;
     return false;
   } else if(sigma2indices.size()!=256){
     std::cerr<<"sigma_index not set: ";
     std::cerr<<"sigma2indices has "<< sigma0indices.size() << " components" << std::endl;
     return false;
   } else if(sigma3indices.size()!=256){
     std::cerr<<"sigma_index not set: ";
     std::cerr<<"sigma3indices has "<< sigma0indices.size() << " components" << std::endl;
     return false;
   }
 
   for(int i=0;i<256;i++){
     // map each unique set of tensor indices to its position in a list
     int index0 = tensor2listindex(sigma0indices.at(i));
     int index1 = tensor2listindex(sigma1indices.at(i));
     int index2 = tensor2listindex(sigma2indices.at(i));
     int index3 = tensor2listindex(sigma3indices.at(i));
     sigma_index5[index0]=0;
     sigma_index5[index1]=1;
     sigma_index5[index2]=2;
     sigma_index5[index3]=3;
 
     short int sign[4]={1,-1,-1,-1};
     // plus->true->1
     helfactor5[1][index0] = sign[sigma0indices.at(i)[1]]
                           * sign[sigma0indices.at(i)[3]];
     helfactor5[1][index1] = sign[sigma1indices.at(i)[1]]
                           * sign[sigma1indices.at(i)[3]];
     helfactor5[1][index2] = sign[sigma2indices.at(i)[1]]
                           * sign[sigma2indices.at(i)[3]];
     helfactor5[1][index3] = sign[sigma3indices.at(i)[1]]
                           * sign[sigma3indices.at(i)[3]];
     // minus->false->0
     helfactor5[0][index0] = sign[sigma0indices.at(i)[0]]
                           * sign[sigma0indices.at(i)[2]]
                           * sign[sigma0indices.at(i)[4]];
     helfactor5[0][index1] = sign[sigma1indices.at(i)[0]]
                           * sign[sigma1indices.at(i)[2]]
                           * sign[sigma1indices.at(i)[4]];
     helfactor5[0][index2] = sign[sigma2indices.at(i)[0]]
                           * sign[sigma2indices.at(i)[2]]
                           * sign[sigma2indices.at(i)[4]];
     helfactor5[0][index3] = sign[sigma3indices.at(i)[0]]
                           * sign[sigma3indices.at(i)[2]]
                           * sign[sigma3indices.at(i)[4]];
   }
 
   // now set sigma_index3
   std::vector<std::array<int,3>> sigma0indices3;
   std::vector<std::array<int,3>> sigma1indices3;
   std::vector<std::array<int,3>> sigma2indices3;
   std::vector<std::array<int,3>> sigma3indices3;
 
   // perms with 3 same
   sigma0indices3.push_back({0,0,0});
   sigma1indices3.push_back({1,1,1});
   sigma2indices3.push_back({2,2,2});
   sigma3indices3.push_back({3,3,3});
 
   // 2 same
   perms21(1,0,sigma0indices3);
   perms21(2,0,sigma0indices3);
   perms21(3,0,sigma0indices3);
   perms21(0,1,sigma1indices3);
   perms21(2,1,sigma1indices3);
   perms21(3,1,sigma1indices3);
   perms21(0,2,sigma2indices3);
   perms21(1,2,sigma2indices3);
   perms21(3,2,sigma2indices3);
   perms21(0,3,sigma3indices3);
   perms21(1,3,sigma3indices3);
   perms21(2,3,sigma3indices3);
 
   // none same
   perms111(1,2,3,sigma0indices3);
   perms111(0,2,3,sigma1indices3);
   perms111(0,3,1,sigma2indices3);
   perms111(0,1,2,sigma3indices3);
 
   if(sigma0indices3.size()!=16){
     std::cerr<<"sigma_index3 not set: ";
     std::cerr<<"sigma0indices3 has "<< sigma0indices3.size() << " components" << std::endl;
     return false;
   } else if(sigma1indices3.size()!=16){
     std::cerr<<"sigma_index3 not set: ";
     std::cerr<<"sigma1indices3 has "<< sigma0indices3.size() << " components" << std::endl;
     return false;
   } else if(sigma2indices3.size()!=16){
     std::cerr<<"sigma_index3 not set: ";
     std::cerr<<"sigma2indices3 has "<< sigma0indices3.size() << " components" << std::endl;
     return false;
   } else if(sigma3indices3.size()!=16){
     std::cerr<<"sigma_index3 not set: ";
     std::cerr<<"sigma3indices3 has "<< sigma0indices3.size() << " components" << std::endl;
     return false;
   }
 
   for(int i=0;i<16;i++){
     int index0 = tensor2listindex(sigma0indices3.at(i));
     int index1 = tensor2listindex(sigma1indices3.at(i));
     int index2 = tensor2listindex(sigma2indices3.at(i));
     int index3 = tensor2listindex(sigma3indices3.at(i));
     sigma_index3[index0]=0;
     sigma_index3[index1]=1;
     sigma_index3[index2]=2;
     sigma_index3[index3]=3;
 
     short int sign[4]={1,-1,-1,-1};
     // plus->true->1
     helfactor3[1][index0] = sign[sigma0indices3.at(i)[1]];
     helfactor3[1][index1] = sign[sigma1indices3.at(i)[1]];
     helfactor3[1][index2] = sign[sigma2indices3.at(i)[1]];
     helfactor3[1][index3] = sign[sigma3indices3.at(i)[1]];
     // minus->false->0
     helfactor3[0][index0] = sign[sigma0indices3.at(i)[0]]
                           * sign[sigma0indices3.at(i)[2]];
     helfactor3[0][index1] = sign[sigma1indices3.at(i)[0]]
                           * sign[sigma1indices3.at(i)[2]];
     helfactor3[0][index2] = sign[sigma2indices3.at(i)[0]]
                           * sign[sigma2indices3.at(i)[2]];
     helfactor3[0][index3] = sign[sigma3indices3.at(i)[0]]
                           * sign[sigma3indices3.at(i)[2]];
   }
   return true;
 } // end init_sigma_index
diff --git a/src/Wjets.cc b/src/Wjets.cc
index ddd3d38..76ca70a 100644
--- a/src/Wjets.cc
+++ b/src/Wjets.cc
@@ -1,2072 +1,2072 @@
 /**
  *  \authors   The HEJ collaboration (see AUTHORS for details)
  *  \date      2019
  *  \copyright GPLv2 or later
  */
 #include "HEJ/currents.hh"
 #include "HEJ/utility.hh"
 #include "HEJ/Tensor.hh"
 #include "HEJ/Constants.hh"
 
 #include <array>
 
 #include <iostream>
 
 
 
 namespace { // Helper Functions
   // FKL W Helper Functions
   void jW (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin, current cur)
   {
     // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5)
     // Need to swap e and nu for events with W- --> e- nubar!
     if (helin==helout && hele==helnu) {
       CLHEP::HepLorentzVector qa=pout+pe+pnu;
       CLHEP::HepLorentzVector qb=pin-pe-pnu;
       double ta(qa.m2()),tb(qb.m2());
 
       current t65,vout,vin,temp2,temp3,temp5;
       joo(pnu,helnu,pe,hele,t65);
       vout[0]=pout.e();
       vout[1]=pout.x();
       vout[2]=pout.y();
       vout[3]=pout.z();
       vin[0]=pin.e();
       vin[1]=pin.x();
       vin[2]=pin.y();
       vin[3]=pin.z();
 
       COM brac615=cdot(t65,vout);
       COM brac645=cdot(t65,vin);
 
       // prod1565 and prod6465 are zero for Ws (not Zs)!!
       // noalias(temp)=prod(trans(CurrentOutOut(pout,helout,pnu,helout)),metric);
       joo(pout,helout,pnu,helout,temp2);
       // noalias(temp2)=prod(temp,ctemp);
       COM prod1665=cdot(temp2,t65);
       // noalias(temp)=prod(trans(Current(pe,helin,pin,helin)),metric);
       // noalias(temp2)=prod(temp,ctemp);
       joi(pe,helin,pin,helin,temp3);
       COM prod5465=cdot(temp3,t65);
       // noalias(temp)=prod(trans(Current(pnu,helin,pin,helin)),metric);
       // noalias(temp2)=prod(temp,ctemp);
 
       joo(pout,helout,pe,helout,temp2);
       joi(pnu,helnu,pin,helin,temp3);
       joi(pout,helout,pin,helin,temp5);
 
       current term1,term2,term3,sum;
       cmult(2.*brac615/ta+2.*brac645/tb,temp5,term1);
       cmult(prod1665/ta,temp3,term2);
       cmult(-prod5465/tb,temp2,term3);
 
      //    cur=((2.*brac615*Current(pout,helout,pin,helin)+prod1565*Current(pe,helin,pin,helin)+prod1665*Current(pnu,helin,pin,helin))/ta + (2.*brac645*Current(pout,helout,pin,helin)-prod5465*CurrentOutOut(pout,helout,pe,helout)-prod6465*CurrentOutOut(pout,helout,pnu,helout))/tb);
       //    cur=((2.*brac615*temp5+prod1565*temp3+prod1665*temp4)/ta + (2.*brac645*temp5-prod5465*temp1-prod6465*temp2)/tb);
       cadd(term1,term2,term3,sum);
       //    std::cout<<"sum: ("<<sum[0]<<","<<sum[1]<<","<<sum[2]<<","<<sum[3]<<")\n";
       cur[0]=sum[0];
       cur[1]=sum[1];
       cur[2]=sum[2];
       cur[3]=sum[3];
     }
   }
 
   void jWbar (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin, current cur)
   {
     // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5)
     // Need to swap e and nu for events with W- --> e- nubar!
     if (helin==helout && hele==helnu) {
       CLHEP::HepLorentzVector qa=pout+pe+pnu;
       CLHEP::HepLorentzVector qb=pin-pe-pnu;
       double ta(qa.m2()),tb(qb.m2());
 
       current t65,vout,vin,temp2,temp3,temp5;
       joo(pnu,helnu,pe,hele,t65);
       vout[0]=pout.e();
       vout[1]=pout.x();
       vout[2]=pout.y();
       vout[3]=pout.z();
       vin[0]=pin.e();
       vin[1]=pin.x();
       vin[2]=pin.y();
       vin[3]=pin.z();
 
       COM brac615=cdot(t65,vout);
       COM brac645=cdot(t65,vin);
 
       // prod1565 and prod6465 are zero for Ws (not Zs)!!
       joo(pe,helout,pout,helout,temp2);  //  temp2 is <5|alpha|1>
       COM prod5165=cdot(temp2,t65);
       jio(pin,helin,pnu,helin,temp3);      // temp3 is <4|alpha|6>
       COM prod4665=cdot(temp3,t65);
 
       joo(pnu,helout,pout,helout,temp2);  // temp2 is now <6|mu|1>
       jio(pin,helin,pe,helin,temp3);        // temp3 is now <4|mu|5>
       jio(pin,helin,pout,helout,temp5);     //  temp5 is <4|mu|1>
 
       current term1,term2,term3,sum;
       cmult(-2.*brac615/ta-2.*brac645/tb,temp5,term1);
       cmult(-prod5165/ta,temp3,term2);
       cmult(prod4665/tb,temp2,term3);
 
      //    cur=((2.*brac615*Current(pout,helout,pin,helin)+prod1565*Current(pe,helin,pin,helin)+prod1665*Current(pnu,helin,pin,helin))/ta + (2.*brac645*Current(pout,helout,pin,helin)-prod5465*CurrentOutOut(pout,helout,pe,helout)-prod6465*CurrentOutOut(pout,helout,pnu,helout))/tb);
       //    cur=((2.*brac615*temp5+prod1565*temp3+prod1665*temp4)/ta + (2.*brac645*temp5-prod5465*temp1-prod6465*temp2)/tb);
       cadd(term1,term2,term3,sum);
       //    std::cout<<"term1: ("<<temp5[0]<<"  "<<temp5[1]<<"  "<<temp5[2]<<"  "<<temp5[3]<<")"<<std::endl;
       //    std::cout<<"sum: ("<<sum[0]<<","<<sum[1]<<","<<sum[2]<<","<<sum[3]<<")\n";
       cur[0]=sum[0];
       cur[1]=sum[1];
       cur[2]=sum[2];
       cur[3]=sum[3];
     }
   }
 
   double WProp (const CLHEP::HepLorentzVector & plbar, const CLHEP::HepLorentzVector & pl){
     COM propW = COM(0.,-1.)/((pl+plbar).m2() -HEJ::MW*HEJ::MW + COM(0.,1.)*HEJ::MW*HEJ::GammaW);
     double PropFactor=(propW*conj(propW)).real();
     return PropFactor;
   }
 
 CCurrent jW (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin)
 {
 
   COM cur[4];
 
   cur[0]=0.;
   cur[1]=0.;
   cur[2]=0.;
   cur[3]=0.;
   CCurrent sum(0.,0.,0.,0.);
 
   // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5)
   // Need to swap e and nu for events with W- --> e- nubar!
   if (helin==helout && hele==helnu) {
     CLHEP::HepLorentzVector qa=pout+pe+pnu;
     CLHEP::HepLorentzVector qb=pin-pe-pnu;
     double ta(qa.m2()),tb(qb.m2());
 
     CCurrent temp2,temp3,temp5;
     CCurrent t65 = joo(pnu,helnu,pe,hele);
     CCurrent vout(pout.e(),pout.x(),pout.y(),pout.z());
     CCurrent vin(pin.e(),pin.x(),pin.y(),pin.z());
 
     COM brac615=t65.dot(vout);
     COM brac645=t65.dot(vin);
 
 
     // prod1565 and prod6465 are zero for Ws (not Zs)!!
     temp2 = joo(pout,helout,pnu,helout);
     COM prod1665=temp2.dot(t65);
     temp3 = joi(pe,helin,pin,helin);
     COM prod5465=temp3.dot(t65);
 
     temp2=joo(pout,helout,pe,helout);
     temp3=joi(pnu,helnu,pin,helin);
     temp5=joi(pout,helout,pin,helin);
 
     CCurrent term1,term2,term3;
     term1=(2.*brac615/ta+2.*brac645/tb)*temp5;
     term2=(prod1665/ta)*temp3;
     term3=(-prod5465/tb)*temp2;
 
     sum=term1+term2+term3;
   }
 
   return sum;
 }
 
 CCurrent jWbar (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin)
 {
 
     COM cur[4];
 
     cur[0]=0.;
     cur[1]=0.;
     cur[2]=0.;
     cur[3]=0.;
     CCurrent sum(0.,0.,0.,0.);
 
   // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5)
   // Need to swap e and nu for events with W- --> e- nubar!
   if (helin==helout && hele==helnu) {
     CLHEP::HepLorentzVector qa=pout+pe+pnu;
     CLHEP::HepLorentzVector qb=pin-pe-pnu;
     double ta(qa.m2()),tb(qb.m2());
 
     CCurrent temp2,temp3,temp5;
     CCurrent t65 = joo(pnu,helnu,pe,hele);
     CCurrent vout(pout.e(),pout.x(),pout.y(),pout.z());
     CCurrent vin(pin.e(),pin.x(),pin.y(),pin.z());
 
     COM brac615=t65.dot(vout);
     COM brac645=t65.dot(vin);
 
     // prod1565 and prod6465 are zero for Ws (not Zs)!!
     temp2 = joo(pe,helout,pout,helout);  //  temp2 is <5|alpha|1>
     COM prod5165=temp2.dot(t65);
     temp3 = jio(pin,helin,pnu,helin);      // temp3 is <4|alpha|6>
     COM prod4665=temp3.dot(t65);
 
     temp2=joo(pnu,helout,pout,helout);  // temp2 is now <6|mu|1>
     temp3=jio(pin,helin,pe,helin);        // temp3 is now <4|mu|5>
     temp5=jio(pin,helin,pout,helout);     //  temp5 is <4|mu|1>
 
     CCurrent term1,term2,term3;
     term1 =(-2.*brac615/ta-2.*brac645/tb)*temp5;
     term2 =(-prod5165/ta)*temp3;
     term3 =(prod4665/tb)*temp2;
 
     sum = term1 + term2 + term3;
   }
 
   return sum;
 }
 
 
   // Extremal quark current with W emission. Using Tensor class rather than CCurrent
-  Tensor <1,4> jW(HLV pin, HLV pout, HLV plbar, HLV pl, bool aqline){
+  Tensor <1> jW(HLV pin, HLV pout, HLV plbar, HLV pl, bool aqline){
     // Build the external quark line W Emmision
-    Tensor<1,4> ABCurr = TCurrent(pl, false, plbar, false);
-    Tensor<1,4> Tp4W = Construct1Tensor((pout+pl+plbar));//p4+pw
-    Tensor<1,4> TpbW = Construct1Tensor((pin-pl-plbar));//pb-pw
+    Tensor<1> ABCurr = TCurrent(pl, false, plbar, false);
+    Tensor<1> Tp4W = Construct1Tensor((pout+pl+plbar));//p4+pw
+    Tensor<1> TpbW = Construct1Tensor((pin-pl-plbar));//pb-pw
 
-    Tensor<3,4> J4bBlank;
+    Tensor<3> J4bBlank;
     if (aqline){
       J4bBlank = T3Current(pin,false,pout,false);
     }
     else{
       J4bBlank = T3Current(pout,false,pin,false);
     }
     double t4AB = (pout+pl+plbar).m2();
     double tbAB = (pin-pl-plbar).m2();
 
-    Tensor<2,4> J4b1 = (J4bBlank.contract(Tp4W,2))/t4AB;
-    Tensor<2,4> J4b2 = (J4bBlank.contract(TpbW,2))/tbAB;
+    Tensor<2> J4b1 = (J4bBlank.contract(Tp4W,2))/t4AB;
+    Tensor<2> J4b2 = (J4bBlank.contract(TpbW,2))/tbAB;
 
-    Tensor<2,4> T4bmMom(0.);
+    Tensor<2> T4bmMom(0.);
 
     if (aqline){
       for(int mu=0; mu<4;mu++){
         for(int nu=0;nu<4;nu++){
           T4bmMom.Set(mu,nu, (J4b1.at(nu,mu) + J4b2.at(mu,nu))*(COM(0,-1)));
         }
       }
     }
     else{
       for(int mu=0; mu<4;mu++){
         for(int nu=0;nu<4;nu++){
           T4bmMom.Set(nu,mu, (J4b1.at(nu,mu) + J4b2.at(mu,nu))*(COM(0,1)));
         }
       }
     }
-    Tensor<1,4> T4bm = T4bmMom.contract(ABCurr,1);
+    Tensor<1> T4bm = T4bmMom.contract(ABCurr,1);
 
     return T4bm;
   }
 
 
 
   // Relevant W+Jets Unordered Contribution Helper Functions
   // W+Jets Uno
   double jM2Wuno(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector plbar, CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pa, bool h1, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector pb, bool h2, bool pol)
   {
     static bool is_sigma_index_set(false);
 
     if(!is_sigma_index_set){
       //std::cout<<"Setting sigma_index...." << std::endl;
       if(init_sigma_index())
   is_sigma_index_set = true;
       else
   return 0.;
     }
 
     CLHEP::HepLorentzVector pW = pl+plbar;
     CLHEP::HepLorentzVector q1g=pa-pW-p1-pg;
     CLHEP::HepLorentzVector q1 = pa-p1-pW;
     CLHEP::HepLorentzVector q2 = p2-pb;
 
     const double taW  = (pa-pW).m2();
     const double taW1 = (pa-pW-p1).m2();
     const double tb2  = (pb-p2).m2();
     const double tb2g = (pb-p2-pg).m2();
     const double s1W  = (p1+pW).m2();
     const double s1gW = (p1+pW+pg).m2();
     const double s1g  = (p1+pg).m2();
     const double tag  = (pa-pg).m2();
     const double taWg = (pa-pW-pg).m2();
 
     //use p1 as ref vec in pol tensor
-    Tensor<1,4> epsg = eps(pg,p2,pol);
-    Tensor<1,4> epsW = TCurrent(pl,false,plbar,false);
-    Tensor<1,4> j2b = TCurrent(p2,h2,pb,h2);
+    Tensor<1> epsg = eps(pg,p2,pol);
+    Tensor<1> epsW = TCurrent(pl,false,plbar,false);
+    Tensor<1> j2b = TCurrent(p2,h2,pb,h2);
 
-    Tensor<1,4> Tq1q2 = Construct1Tensor((q1+q2)/taW1 + (pb/pb.dot(pg)
+    Tensor<1> Tq1q2 = Construct1Tensor((q1+q2)/taW1 + (pb/pb.dot(pg)
       + p2/p2.dot(pg)) * tb2/(2*tb2g));
-    Tensor<1,4> Tq1g = Construct1Tensor((-pg-q1))/taW1;
-    Tensor<1,4> Tq2g = Construct1Tensor((pg-q2));
-    Tensor<1,4> TqaW = Construct1Tensor((pa-pW));//pa-pw
-    Tensor<1,4> Tqag = Construct1Tensor((pa-pg));
-    Tensor<1,4> TqaWg = Construct1Tensor((pa-pg-pW));
-    Tensor<1,4> Tp1g = Construct1Tensor((p1+pg));
-    Tensor<1,4> Tp1W = Construct1Tensor((p1+pW));//p1+pw
-    Tensor<1,4> Tp1gW = Construct1Tensor((p1+pg+pW));//p1+pw+pg
-
-    Tensor<2,4> g=Metric();
-
-    Tensor<3,4> J31a = T3Current(p1, h1, pa, h1);
-    Tensor<2,4> J2_qaW =J31a.contract(TqaW/taW, 2);
-    Tensor<2,4> J2_p1W =J31a.contract(Tp1W/s1W, 2);
-    Tensor<3,4> L1a =J2_qaW.leftprod(Tq1q2);
-    Tensor<3,4> L1b =J2_p1W.leftprod(Tq1q2);
-    Tensor<3,4> L2a = J2_qaW.leftprod(Tq1g);
-    Tensor<3,4> L2b = J2_p1W.leftprod(Tq1g);
-    Tensor<3,4> L3 = (g.rightprod(J2_qaW.contract(Tq2g,1)+J2_p1W.contract(Tq2g,2)))/taW1;
-    Tensor<3,4> L(0.);
-
-    Tensor<5,4> J51a = T5Current(p1, h1, pa, h1);
-
-    Tensor<4,4> J_qaW = J51a.contract(TqaW,4);
-    Tensor<4,4> J_qag = J51a.contract(Tqag,4);
-    Tensor<4,4> J_p1gW = J51a.contract(Tp1gW,4);
-
-    Tensor<3,4> U1a = J_qaW.contract(Tp1g,2);
-    Tensor<3,4> U1b = J_p1gW.contract(Tp1g,2);
-    Tensor<3,4> U1c = J_p1gW.contract(Tp1W,2);
-    Tensor<3,4> U1(0.);
-
-    Tensor<3,4> U2a = J_qaW.contract(TqaWg,2);
-    Tensor<3,4> U2b = J_qag.contract(TqaWg,2);
-    Tensor<3,4> U2c = J_qag.contract(Tp1W,2);
-    Tensor<3,4> U2(0.);
+    Tensor<1> Tq1g = Construct1Tensor((-pg-q1))/taW1;
+    Tensor<1> Tq2g = Construct1Tensor((pg-q2));
+    Tensor<1> TqaW = Construct1Tensor((pa-pW));//pa-pw
+    Tensor<1> Tqag = Construct1Tensor((pa-pg));
+    Tensor<1> TqaWg = Construct1Tensor((pa-pg-pW));
+    Tensor<1> Tp1g = Construct1Tensor((p1+pg));
+    Tensor<1> Tp1W = Construct1Tensor((p1+pW));//p1+pw
+    Tensor<1> Tp1gW = Construct1Tensor((p1+pg+pW));//p1+pw+pg
+
+    Tensor<2> g=Metric();
+
+    Tensor<3> J31a = T3Current(p1, h1, pa, h1);
+    Tensor<2> J2_qaW =J31a.contract(TqaW/taW, 2);
+    Tensor<2> J2_p1W =J31a.contract(Tp1W/s1W, 2);
+    Tensor<3> L1a =J2_qaW.leftprod(Tq1q2);
+    Tensor<3> L1b =J2_p1W.leftprod(Tq1q2);
+    Tensor<3> L2a = J2_qaW.leftprod(Tq1g);
+    Tensor<3> L2b = J2_p1W.leftprod(Tq1g);
+    Tensor<3> L3 = (g.rightprod(J2_qaW.contract(Tq2g,1)+J2_p1W.contract(Tq2g,2)))/taW1;
+    Tensor<3> L(0.);
+
+    Tensor<5> J51a = T5Current(p1, h1, pa, h1);
+
+    Tensor<4> J_qaW = J51a.contract(TqaW,4);
+    Tensor<4> J_qag = J51a.contract(Tqag,4);
+    Tensor<4> J_p1gW = J51a.contract(Tp1gW,4);
+
+    Tensor<3> U1a = J_qaW.contract(Tp1g,2);
+    Tensor<3> U1b = J_p1gW.contract(Tp1g,2);
+    Tensor<3> U1c = J_p1gW.contract(Tp1W,2);
+    Tensor<3> U1(0.);
+
+    Tensor<3> U2a = J_qaW.contract(TqaWg,2);
+    Tensor<3> U2b = J_qag.contract(TqaWg,2);
+    Tensor<3> U2c = J_qag.contract(Tp1W,2);
+    Tensor<3> U2(0.);
 
     for(int nu=0; nu<4;nu++){
       for(int mu=0;mu<4;mu++){
         for(int rho=0;rho<4;rho++){
           L.Set(nu, mu, rho, L1a.at(nu,mu,rho) + L1b.at(nu,rho,mu)
             + L2a.at(mu,nu,rho) + L2b.at(mu,rho,nu) + L3.at(mu,nu,rho));
           U1.Set(nu, mu, rho, U1a.at(nu, mu, rho) / (s1g*taW)
             + U1b.at(nu,rho,mu) / (s1g*s1gW) + U1c.at(rho,nu,mu) / (s1W*s1gW));
           U2.Set(nu,mu,rho,U2a.at(mu,nu,rho) / (taWg*taW)
             + U2b.at(mu,rho,nu) / (taWg*tag) + U2c.at(rho,mu,nu) / (s1W*tag));
         }
       }
     }
 
     COM X = ((((U1-L).contract(epsW,3)).contract(j2b,2)).contract(epsg,1)).at(0);
     COM Y = ((((U2+L).contract(epsW,3)).contract(j2b,2)).contract(epsg,1)).at(0);
 
     double amp = HEJ::C_A*HEJ::C_F*HEJ::C_F/2.*(norm(X)+norm(Y)) - HEJ::C_F/2.*(X*conj(Y)).real();
 
     double t1 = q1g.m2();
     double t2 = q2.m2();
 
     double WPropfact = WProp(plbar, pl);
 
     //Divide by WProp
     amp*=WPropfact;
 
     //Divide by t-channels
     amp/=(t1*t2);
 
     //Average over initial states
     amp/=(4.*HEJ::C_A*HEJ::C_A);
 
     return amp;
   }
 
 
 
   // Relevant Wqqx Helper Functions.
   //g->qxqlxl (Calculates gluon to qqx Current. See JV_\mu in WSubleading Notes)
-  Tensor <1,4> gtqqxW(CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar){
+  Tensor <1> gtqqxW(CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar){
 
     double s2AB=(pl+plbar+pq).m2();
     double s3AB=(pl+plbar+pqbar).m2();
 
-    Tensor<1,4> Tpq = Construct1Tensor(pq);
-    Tensor<1,4> Tpqbar = Construct1Tensor(pqbar);
-    Tensor<1,4> TAB = Construct1Tensor(pl+plbar);
+    Tensor<1> Tpq = Construct1Tensor(pq);
+    Tensor<1> Tpqbar = Construct1Tensor(pqbar);
+    Tensor<1> TAB = Construct1Tensor(pl+plbar);
 
     // Define llx current.
-    Tensor<1,4> ABCur = TCurrent(pl, false, plbar, false);
+    Tensor<1> ABCur = TCurrent(pl, false, plbar, false);
 
     //blank 3 Gamma Current
-    Tensor<3,4> JV23 = T3Current(pq,false,pqbar,false);
+    Tensor<3> JV23 = T3Current(pq,false,pqbar,false);
 
     // Components of g->qqW before W Contraction
-    Tensor<2,4> JV1 = JV23.contract((Tpq + TAB),2)/(s2AB);
-    Tensor<2,4> JV2 = JV23.contract((Tpqbar + TAB),2)/(s3AB);
+    Tensor<2> JV1 = JV23.contract((Tpq + TAB),2)/(s2AB);
+    Tensor<2> JV2 = JV23.contract((Tpqbar + TAB),2)/(s3AB);
 
     // g->qqW Current. Note Minus between terms due to momentum flow.
     // Also note: (-I)^2 from W vert. (I) from Quark prop.
-    Tensor<1,4> JVCur = (JV1.contract(ABCur,1) - JV2.contract(ABCur,2))*COM(0.,-1.);
+    Tensor<1> JVCur = (JV1.contract(ABCur,1) - JV2.contract(ABCur,2))*COM(0.,-1.);
 
     return JVCur;
   }
 
   // Helper Functions Calculate the Crossed Contribution
-  Tensor <2,4> MCrossW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
+  Tensor <2> MCrossW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
 
     // Useful propagator factors
     double s2AB=(pl+plbar+pq).m2();
     double s3AB=(pl+plbar+pqbar).m2();
 
     CLHEP::HepLorentzVector q1, q3;
     q1=pa;
     for(int i=0; i<nabove+1;i++){
       q1=q1-partons.at(i);
     }
     q3 = q1 - pq - pqbar - pl - plbar;
 
     double tcro1=(q3+pq).m2();
     double tcro2=(q1-pqbar).m2();
 
-    Tensor<1,4> Tp1 = Construct1Tensor(p1);
-    Tensor<1,4> Tp4 = Construct1Tensor(p4);
-    Tensor<1,4> Tpa = Construct1Tensor(pa);
-    Tensor<1,4> Tpb = Construct1Tensor(pb);
-    Tensor<1,4> Tpq = Construct1Tensor(pq);
-    Tensor<1,4> Tpqbar = Construct1Tensor(pqbar);
-    Tensor<1,4> TAB = Construct1Tensor(pl+plbar);
-    Tensor<1,4> Tq1 = Construct1Tensor(q1);
-    Tensor<1,4> Tq3 = Construct1Tensor(q3);
-    Tensor<2,4> g=Metric();
+    Tensor<1> Tp1 = Construct1Tensor(p1);
+    Tensor<1> Tp4 = Construct1Tensor(p4);
+    Tensor<1> Tpa = Construct1Tensor(pa);
+    Tensor<1> Tpb = Construct1Tensor(pb);
+    Tensor<1> Tpq = Construct1Tensor(pq);
+    Tensor<1> Tpqbar = Construct1Tensor(pqbar);
+    Tensor<1> TAB = Construct1Tensor(pl+plbar);
+    Tensor<1> Tq1 = Construct1Tensor(q1);
+    Tensor<1> Tq3 = Construct1Tensor(q3);
+    Tensor<2> g=Metric();
 
     // Define llx current.
-    Tensor<1,4> ABCur = TCurrent(pl, false, plbar,false);
+    Tensor<1> ABCur = TCurrent(pl, false, plbar,false);
 
     //Blank 5 gamma Current
-    Tensor<5,4> J523 = T5Current(pq,false,pqbar,false);
+    Tensor<5> J523 = T5Current(pq,false,pqbar,false);
 
     // 4 gamma currents (with 1 contraction already).
-    Tensor<4,4> J_q3q = J523.contract((Tq3+Tpq),2);
-    Tensor<4,4> J_2AB = J523.contract((Tpq+TAB),2);
+    Tensor<4> J_q3q = J523.contract((Tq3+Tpq),2);
+    Tensor<4> J_2AB = J523.contract((Tpq+TAB),2);
 
     // Components of Crossed Vertex Contribution
-    Tensor<3,4> Xcro1 = J_q3q.contract((Tpqbar + TAB),3);
-    Tensor<3,4> Xcro2 = J_q3q.contract((Tq1-Tpqbar),3);
-    Tensor<3,4> Xcro3 = J_2AB.contract((Tq1-Tpqbar),3);
+    Tensor<3> Xcro1 = J_q3q.contract((Tpqbar + TAB),3);
+    Tensor<3> Xcro2 = J_q3q.contract((Tq1-Tpqbar),3);
+    Tensor<3> Xcro3 = J_2AB.contract((Tq1-Tpqbar),3);
 
     // Term Denominators Taken Care of at this stage
-    Tensor<2,4> Xcro1Cont = Xcro1.contract(ABCur,3)/(tcro1*s3AB);
-    Tensor<2,4> Xcro2Cont = Xcro2.contract(ABCur,2)/(tcro1*tcro2);
-    Tensor<2,4> Xcro3Cont = Xcro3.contract(ABCur,1)/(s2AB*tcro2);
+    Tensor<2> Xcro1Cont = Xcro1.contract(ABCur,3)/(tcro1*s3AB);
+    Tensor<2> Xcro2Cont = Xcro2.contract(ABCur,2)/(tcro1*tcro2);
+    Tensor<2> Xcro3Cont = Xcro3.contract(ABCur,1)/(s2AB*tcro2);
 
     //Initialise the Crossed Vertex Object
-    Tensor<2,4> Xcro(0.);
+    Tensor<2> Xcro(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
         Xcro.Set(mu,nu, -(-Xcro1Cont.at(nu,mu)+Xcro2Cont.at(nu,mu)+Xcro3Cont.at(nu,mu)));
       }
     }
 
 
     return Xcro;
   }
 
   // Helper Functions Calculate the Uncrossed Contribution
-  Tensor <2,4> MUncrossW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
+  Tensor <2> MUncrossW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
 
     double s2AB=(pl+plbar+pq).m2();
     double s3AB=(pl+plbar+pqbar).m2();
 
     CLHEP::HepLorentzVector q1, q3;
     q1=pa;
     for(int i=0; i<nabove+1;i++){
       q1=q1-partons.at(i);
     }
     q3 = q1 - pl - plbar - pq - pqbar;
     double tunc1 = (q1-pq).m2();
     double tunc2 = (q3+pqbar).m2();
 
-    Tensor<1,4> Tp1 = Construct1Tensor(p1);
-    Tensor<1,4> Tp4 = Construct1Tensor(p4);
-    Tensor<1,4> Tpa = Construct1Tensor(pa);
-    Tensor<1,4> Tpb = Construct1Tensor(pb);
-    Tensor<1,4> Tpq = Construct1Tensor(pq);
-    Tensor<1,4> Tpqbar = Construct1Tensor(pqbar);
-    Tensor<1,4> TAB = Construct1Tensor(pl+plbar);
-    Tensor<1,4> Tq1 = Construct1Tensor(q1);
-    Tensor<1,4> Tq3 = Construct1Tensor(q3);
-    Tensor<2,4> g=Metric();
+    Tensor<1> Tp1 = Construct1Tensor(p1);
+    Tensor<1> Tp4 = Construct1Tensor(p4);
+    Tensor<1> Tpa = Construct1Tensor(pa);
+    Tensor<1> Tpb = Construct1Tensor(pb);
+    Tensor<1> Tpq = Construct1Tensor(pq);
+    Tensor<1> Tpqbar = Construct1Tensor(pqbar);
+    Tensor<1> TAB = Construct1Tensor(pl+plbar);
+    Tensor<1> Tq1 = Construct1Tensor(q1);
+    Tensor<1> Tq3 = Construct1Tensor(q3);
+    Tensor<2> g=Metric();
 
 
     // Define llx current.
-    Tensor<1,4> ABCur = TCurrent(pl, false, plbar, false);
+    Tensor<1> ABCur = TCurrent(pl, false, plbar, false);
 
     //Blank 5 gamma Current
-    Tensor<5,4> J523 = T5Current(pq,false,pqbar,false);
+    Tensor<5> J523 = T5Current(pq,false,pqbar,false);
 
     // 4 gamma currents (with 1 contraction already).
-    Tensor<4,4> J_2AB = J523.contract((Tpq+TAB),2);
-    Tensor<4,4> J_q1q = J523.contract((Tq1-Tpq),2);
+    Tensor<4> J_2AB = J523.contract((Tpq+TAB),2);
+    Tensor<4> J_q1q = J523.contract((Tq1-Tpq),2);
 
     // 2 Contractions taken care of.
-    Tensor<3,4> Xunc1 = J_2AB.contract((Tq3+Tpqbar),3);
-    Tensor<3,4> Xunc2 = J_q1q.contract((Tq3+Tpqbar),3);
-    Tensor<3,4> Xunc3 = J_q1q.contract((Tpqbar+TAB),3);
+    Tensor<3> Xunc1 = J_2AB.contract((Tq3+Tpqbar),3);
+    Tensor<3> Xunc2 = J_q1q.contract((Tq3+Tpqbar),3);
+    Tensor<3> Xunc3 = J_q1q.contract((Tpqbar+TAB),3);
 
     // Term Denominators Taken Care of at this stage
-    Tensor<2,4> Xunc1Cont = Xunc1.contract(ABCur,1)/(s2AB*tunc2);
-    Tensor<2,4> Xunc2Cont = Xunc2.contract(ABCur,2)/(tunc1*tunc2);
-    Tensor<2,4> Xunc3Cont = Xunc3.contract(ABCur,3)/(tunc1*s3AB);
+    Tensor<2> Xunc1Cont = Xunc1.contract(ABCur,1)/(s2AB*tunc2);
+    Tensor<2> Xunc2Cont = Xunc2.contract(ABCur,2)/(tunc1*tunc2);
+    Tensor<2> Xunc3Cont = Xunc3.contract(ABCur,3)/(tunc1*s3AB);
 
     //Initialise the Uncrossed Vertex Object
-    Tensor<2,4> Xunc(0.);
+    Tensor<2> Xunc(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
         Xunc.Set(mu,nu,-(- Xunc1Cont.at(mu,nu)+Xunc2Cont.at(mu,nu) +Xunc3Cont.at(mu,nu)));
       }
     }
 
     return Xunc;
   }
 
 
   // Helper Functions Calculate the g->qqxW (Eikonal) Contributions
-  Tensor <2,4> MSymW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
+  Tensor <2> MSymW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){
 
     double sa2=(pa+pq).m2();
     double s12=(p1+pq).m2();
     double sa3=(pa+pqbar).m2();
     double s13=(p1+pqbar).m2();
     double saA=(pa+pl).m2();
     double s1A=(p1+pl).m2();
     double saB=(pa+plbar).m2();
     double s1B=(p1+plbar).m2();
     double sb2=(pb+pq).m2();
     double s42=(p4+pq).m2();
     double sb3=(pb+pqbar).m2();
     double s43=(p4+pqbar).m2();
     double sbA=(pb+pl).m2();
     double s4A=(p4+pl).m2();
     double sbB=(pb+plbar).m2();
     double s4B=(p4+plbar).m2();
     double s23AB=(pl+plbar+pq+pqbar).m2();
 
     CLHEP::HepLorentzVector q1,q3;
     q1=pa;
     for(int i=0;i<nabove+1;i++){
       q1-=partons.at(i);
     }
     q3=q1-pq-pqbar-plbar-pl;
     double t1 = (q1).m2();
     double t3 = (q3).m2();
 
     //Define Tensors to be used
-    Tensor<1,4> Tp1 = Construct1Tensor(p1);
-    Tensor<1,4> Tp4 = Construct1Tensor(p4);
-    Tensor<1,4> Tpa = Construct1Tensor(pa);
-    Tensor<1,4> Tpb = Construct1Tensor(pb);
-    Tensor<1,4> Tpq = Construct1Tensor(pq);
-    Tensor<1,4> Tpqbar = Construct1Tensor(pqbar);
-    Tensor<1,4> TAB = Construct1Tensor(pl+plbar);
-    Tensor<1,4> Tq1 = Construct1Tensor(q1);
-    Tensor<1,4> Tq3 = Construct1Tensor(q3);
-    Tensor<2,4> g=Metric();
+    Tensor<1> Tp1 = Construct1Tensor(p1);
+    Tensor<1> Tp4 = Construct1Tensor(p4);
+    Tensor<1> Tpa = Construct1Tensor(pa);
+    Tensor<1> Tpb = Construct1Tensor(pb);
+    Tensor<1> Tpq = Construct1Tensor(pq);
+    Tensor<1> Tpqbar = Construct1Tensor(pqbar);
+    Tensor<1> TAB = Construct1Tensor(pl+plbar);
+    Tensor<1> Tq1 = Construct1Tensor(q1);
+    Tensor<1> Tq3 = Construct1Tensor(q3);
+    Tensor<2> g=Metric();
 
     // g->qqW Current (Factors of sqrt2 dealt with in this function.)
-    Tensor<1,4> JV = gtqqxW(pq,pqbar,pl,plbar);
+    Tensor<1> JV = gtqqxW(pq,pqbar,pl,plbar);
 
     // 1a gluon emisson Contribution
-    Tensor<3,4> X1a = g.rightprod(Tp1*(t1/(s12+s13+s1A+s1B)) + Tpa*(t1/(sa2+sa3+saA+saB)));
-    Tensor<2,4> X1aCont = X1a.contract(JV,3);
+    Tensor<3> X1a = g.rightprod(Tp1*(t1/(s12+s13+s1A+s1B)) + Tpa*(t1/(sa2+sa3+saA+saB)));
+    Tensor<2> X1aCont = X1a.contract(JV,3);
 
     //4b gluon emission Contribution
-    Tensor<3,4> X4b = g.rightprod(Tp4*(t3/(s42+s43+s4A+s4B)) + Tpb*(t3/(sb2+sb3+sbA+sbB)));
-    Tensor<2,4> X4bCont = X4b.contract(JV,3);
+    Tensor<3> X4b = g.rightprod(Tp4*(t3/(s42+s43+s4A+s4B)) + Tpb*(t3/(sb2+sb3+sbA+sbB)));
+    Tensor<2> X4bCont = X4b.contract(JV,3);
 
     //Set up each term of 3G diagram.
-    Tensor<3,4> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar+TAB);
-    Tensor<3,4> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar-TAB);
-    Tensor<3,4> X3g3 = g.leftprod((Tq1+Tq3));
+    Tensor<3> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar+TAB);
+    Tensor<3> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar-TAB);
+    Tensor<3> X3g3 = g.leftprod((Tq1+Tq3));
 
     // Note the contraction of indices changes term by term
-    Tensor<2,4> X3g1Cont = X3g1.contract(JV,3);
-    Tensor<2,4> X3g2Cont = X3g2.contract(JV,2);
-    Tensor<2,4> X3g3Cont = X3g3.contract(JV,1);
+    Tensor<2> X3g1Cont = X3g1.contract(JV,3);
+    Tensor<2> X3g2Cont = X3g2.contract(JV,2);
+    Tensor<2> X3g3Cont = X3g3.contract(JV,1);
 
     // XSym is an amalgamation of x1a, X4b and X3g. Makes sense from a colour factor point of view.
-    Tensor<2,4>Xsym(0.);
+    Tensor<2>Xsym(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
   Xsym.Set(mu,nu, (X3g1Cont.at(nu,mu) + X3g2Cont.at(mu,nu) - X3g3Cont.at(nu,mu))
      + (X1aCont.at(mu,nu) - X4bCont.at(mu,nu)) );
       }
     }
     return Xsym/s23AB;
   }
 
-  Tensor <2,4> MCross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
+  Tensor <2> MCross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
 
     CLHEP::HepLorentzVector q1;
     q1=pa;
     for(int i=0;i<nabove+1;i++){
       q1-=partons.at(i);
     }
 
     double t2=(q1-pqbar).m2();
 
-    Tensor<1,4> Tq1 = Construct1Tensor(q1-pqbar);
+    Tensor<1> Tq1 = Construct1Tensor(q1-pqbar);
 
     //Blank 3 gamma Current
-    Tensor<3,4> J323 = T3Current(pq,hq,pqbar,hq);
+    Tensor<3> J323 = T3Current(pq,hq,pqbar,hq);
 
     // 2 gamma current (with 1 contraction already).
-    Tensor<2,4> XCroCont = J323.contract((Tq1),2)/(t2);
+    Tensor<2> XCroCont = J323.contract((Tq1),2)/(t2);
 
     //Initialise the Crossed Vertex
-    Tensor<2,4> Xcro(0.);
+    Tensor<2> Xcro(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
         Xcro.Set(mu,nu, (XCroCont.at(nu,mu)));
       }
     }
 
     return Xcro;
   }
 
 
   // Helper Functions Calculate the Uncrossed Contribution
-  Tensor <2,4> MUncross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
+  Tensor <2> MUncross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
 
     CLHEP::HepLorentzVector q1;
     q1=pa;
     for(int i=0;i<nabove+1;i++){
       q1-=partons.at(i);
     }
     double t2 = (q1-pq).m2();
 
-    Tensor<1,4> Tq1 = Construct1Tensor(q1-pq);
+    Tensor<1> Tq1 = Construct1Tensor(q1-pq);
 
     //Blank 3 gamma Current
-    Tensor<3,4> J323 = T3Current(pq,hq,pqbar,hq);
+    Tensor<3> J323 = T3Current(pq,hq,pqbar,hq);
 
     // 2 gamma currents (with 1 contraction already).
-    Tensor<2,4> XUncCont = J323.contract((Tq1),2)/t2;
+    Tensor<2> XUncCont = J323.contract((Tq1),2)/t2;
 
     //Initialise the Uncrossed Vertex
-    Tensor<2,4> Xunc(0.);
+    Tensor<2> Xunc(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
   Xunc.Set(mu,nu,-(XUncCont.at(mu,nu)));
       }
     }
 
     return Xunc;
   }
 
 
   // Helper Functions Calculate the Eikonal Contributions
-  Tensor <2,4> MSym(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
+  Tensor <2> MSym(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){
 
     CLHEP::HepLorentzVector q1, q3;
     q1=pa;
     for(int i=0;i<nabove+1;i++){
       q1-=partons.at(i);
     }
     q3 = q1-pq-pqbar;
     double t1 = (q1).m2();
     double t3 = (q3).m2();
 
     double s23 = (pq+pqbar).m2();
     double sa2 = (pa+pq).m2();
     double sa3 = (pa+pqbar).m2();
     double s12 = (p1+pq).m2();
     double s13 = (p1+pqbar).m2();
     double sb2 = (pb+pq).m2();
     double sb3 = (pb+pqbar).m2();
     double s42 = (p4+pq).m2();
     double s43 = (p4+pqbar).m2();
 
     //Define Tensors to be used
-    Tensor<1,4> Tp1 = Construct1Tensor(p1);
-    Tensor<1,4> Tp4 = Construct1Tensor(p4);
-    Tensor<1,4> Tpa = Construct1Tensor(pa);
-    Tensor<1,4> Tpb = Construct1Tensor(pb);
-    Tensor<1,4> Tpq = Construct1Tensor(pq);
-    Tensor<1,4> Tpqbar = Construct1Tensor(pqbar);
-    Tensor<1,4> Tq1 = Construct1Tensor(q1);
-    Tensor<1,4> Tq3 = Construct1Tensor(q3);
-    Tensor<2,4> g=Metric();
-
-    Tensor<1,4> qqxCur = TCurrent(pq, hq, pqbar, hq);
+    Tensor<1> Tp1 = Construct1Tensor(p1);
+    Tensor<1> Tp4 = Construct1Tensor(p4);
+    Tensor<1> Tpa = Construct1Tensor(pa);
+    Tensor<1> Tpb = Construct1Tensor(pb);
+    Tensor<1> Tpq = Construct1Tensor(pq);
+    Tensor<1> Tpqbar = Construct1Tensor(pqbar);
+    Tensor<1> Tq1 = Construct1Tensor(q1);
+    Tensor<1> Tq3 = Construct1Tensor(q3);
+    Tensor<2> g=Metric();
+
+    Tensor<1> qqxCur = TCurrent(pq, hq, pqbar, hq);
 
     // // 1a gluon emisson Contribution
-    Tensor<3,4> X1a = g.rightprod(Tp1*(t1/(s12+s13))+Tpa*(t1/(sa2+sa3)));
-    Tensor<2,4> X1aCont = X1a.contract(qqxCur,3);
+    Tensor<3> X1a = g.rightprod(Tp1*(t1/(s12+s13))+Tpa*(t1/(sa2+sa3)));
+    Tensor<2> X1aCont = X1a.contract(qqxCur,3);
 
     // //4b gluon emission Contribution
-    Tensor<3,4> X4b = g.rightprod(Tp4*(t3/(s42+s43)) + Tpb*(t3/(sb2+sb3)));
-    Tensor<2,4> X4bCont = X4b.contract(qqxCur,3);
+    Tensor<3> X4b = g.rightprod(Tp4*(t3/(s42+s43)) + Tpb*(t3/(sb2+sb3)));
+    Tensor<2> X4bCont = X4b.contract(qqxCur,3);
 
     // New Formulation Corresponding to New Analytics
-    Tensor<3,4> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar);
-    Tensor<3,4> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar);
-    Tensor<3,4> X3g3 = g.leftprod((Tq1+Tq3));
+    Tensor<3> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar);
+    Tensor<3> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar);
+    Tensor<3> X3g3 = g.leftprod((Tq1+Tq3));
 
     // Note the contraction of indices changes term by term
-    Tensor<2,4> X3g1Cont = X3g1.contract(qqxCur,3);
-    Tensor<2,4> X3g2Cont = X3g2.contract(qqxCur,2);
-    Tensor<2,4> X3g3Cont = X3g3.contract(qqxCur,1);
+    Tensor<2> X3g1Cont = X3g1.contract(qqxCur,3);
+    Tensor<2> X3g2Cont = X3g2.contract(qqxCur,2);
+    Tensor<2> X3g3Cont = X3g3.contract(qqxCur,1);
 
-    Tensor<2,4>Xsym(0.);
+    Tensor<2>Xsym(0.);
 
     for(int mu=0; mu<4;mu++){
       for(int nu=0;nu<4;nu++){
         Xsym.Set(mu, nu, COM(0,1) * ( (X3g1Cont.at(nu,mu) + X3g2Cont.at(mu,nu)
           - X3g3Cont.at(nu,mu)) + (X1aCont.at(mu,nu) - X4bCont.at(mu,nu)) ) );
       }
     }
     return Xsym/s23;
   }
 } // Anonymous Namespace helper functions
 
 // W+Jets FKL Contributions
 double jMWqQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   current mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf^2
   return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 double jMWqQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   current mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
   jio(p2in,true,p2out,true,mj2p);
   jio(p2in,false,p2out,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf^2
   return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 double jMWqbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   current mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf^2
   return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 double jMWqbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   current mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
   jio(p2in,true,p2out,true,mj2p);
   jio(p2in,false,p2out,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf^2
   return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 double jMWqg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qg->qenug scattering
 // p1: quark
 // p2: gluon
 {
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current mj1m,mj2p,mj2m;
 
   jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
 
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   // mj1m.mj2p
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   const double K = K_g(p2out, p2in);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
   double sst = K/HEJ::C_A*(a2Mmp+a2Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf*Ca=4
   return HEJ::C_F*HEJ::C_A*WPropfact*sst/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 double jMWqbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qg->qenug scattering
 // p1: quark
 // p2: gluon
 {
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current mj1m,mj2p,mj2m;
 
   jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m);
 
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   // mj1m.mj2p
   COM Mmp=cdot(mj1m,mj2p);
 
   // mj1m.mj2m
   COM Mmm=cdot(mj1m,mj2m);
 
   const double K = K_g(p2out, p2in);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
   double sst = K/HEJ::C_A*(a2Mmp+a2Mmm);
 
   double WPropfact = WProp(pe, pnu);
 
   // Division by colour and Helicity average (Nc2-1)(4)
   // Multiply by Cf*Ca=4
   return HEJ::C_F*HEJ::C_A*WPropfact*sst/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4);
 
 }
 
 
 // W+Jets Unordered Contributions
 //qQ->qQWg_unob
 double junobMWqQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);
   CLHEP::HepLorentzVector q3=-(p2in-p2out);
 
   mj1m=jW(p1out,false,pe,false,pnu,false,p1in,false);
   mj2p=joi(p2out,true,p2in,true);
   mj2m=joi(p2out,false,p2in,false);
 
 
   // Dot products of these which occur again and again
   COM MWmp=mj1m.dot(mj2p);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgbm,jgbp,j2gm,j2gp;
   j2gp=joo(p2out,true,pg,true);
   j2gm=joo(p2out,false,pg,false);
   jgbp=joi(pg,true,p2in,true);
   jgbm=joi(pg,false,p2in,false);
 
   CCurrent qsum(q2+q3);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
   CCurrent p2o(p2out);
   CCurrent p2i(p2in);
 
 
   Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2();
   Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2();
 
   U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2();
   U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2();
   U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2();
 
 
   double amm,amp;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp);
 
   double ampsq=-(amm+amp);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
 
   // Now add the t-channels
   double th=q2.m2()*q1.m2();
   ampsq/=th;
   ampsq/=16.;
 
 
   return ampsq;
 
 
 }
 
 //qQbar->qQbarWg_unob
 double junobMWqQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);
   CLHEP::HepLorentzVector q3=-(p2in-p2out);
 
   mj1m=jW(p1out,false,pe,false,pnu,false,p1in,false);
   mj2p=jio(p2in,true,p2out,true);
   mj2m=jio(p2in,false,p2out,false);
 
 
   // Dot products of these which occur again and again
   COM MWmp=mj1m.dot(mj2p);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgbm,jgbp,j2gm,j2gp;
   j2gp=joo(pg,true,p2out,true);
   j2gm=joo(pg,false,p2out,false);
   jgbp=jio(p2in,true,pg,true);
   jgbm=jio(p2in,false,pg,false);
 
   CCurrent qsum(q2+q3);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
   CCurrent p2o(p2out);
   CCurrent p2i(p2in);
 
 
   Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2();
   Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2();
 
   U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2();
   U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2();
   U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2();
 
   double amm,amp;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp);
 
   double ampsq=-(amm+amp);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*q1.m2();
   ampsq/=th;
   ampsq/=16.;
 
 
   return ampsq;
 
 
 }
 
 //qbarQ->qbarQWg_unob
 double junobMWqbarQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);
   CLHEP::HepLorentzVector q3=-(p2in-p2out);
 
   mj1m=jWbar(p1out,false,pe,false,pnu,false,p1in,false);
   mj2p=joi(p2out,true,p2in,true);
   mj2m=joi(p2out,false,p2in,false);
 
 
   // Dot products of these which occur again and again
   COM MWmp=mj1m.dot(mj2p);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgbm,jgbp,j2gm,j2gp;
   j2gp=joo(p2out,true,pg,true);
   j2gm=joo(p2out,false,pg,false);
   jgbp=joi(pg,true,p2in,true);
   jgbm=joi(pg,false,p2in,false);
 
   CCurrent qsum(q2+q3);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
   CCurrent p2o(p2out);
   CCurrent p2i(p2in);
 
 
   Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2();
   Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2();
 
   U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2();
   U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2();
   U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2();
 
 
   double amm,amp;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp);
 
   double ampsq=-(amm+amp);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*q1.m2();
   ampsq/=th;
   ampsq/=16.;
 
   return ampsq;
 
 
 }
 
 //qbarQbar->qbarQbarWg_unob
 double junobMWqbarQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj1m,mj2p,mj2m;
   CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);
   CLHEP::HepLorentzVector q3=-(p2in-p2out);
 
   mj1m=jWbar(p1out,false,pe,false,pnu,false,p1in,false);
   mj2p=jio(p2in,true,p2out,true);
   mj2m=jio(p2in,false,p2out,false);
 
 
   // Dot products of these which occur again and again
   COM MWmp=mj1m.dot(mj2p);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgbm,jgbp,j2gm,j2gp;
   j2gp=joo(pg,true,p2out,true);
   j2gm=joo(pg,false,p2out,false);
   jgbp=jio(p2in,true,pg,true);
   jgbm=jio(p2in,false,pg,false);
 
   CCurrent qsum(q2+q3);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
   CCurrent p2o(p2out);
   CCurrent p2i(p2in);
 
 
   Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2();
   Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2();
 
   U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2();
   U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2();
   U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2();
 
 
   double amm,amp;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp);
 
   double ampsq=-(amm+amp);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*q1.m2();
   ampsq/=th;
   ampsq/=16.;
 
   return ampsq;
 
 
 }
 
 ////////////////////////////////////////////////////////////////////
 //qQ->qQWg_unof
 double junofMWgqQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj2m,mj1p,mj1m;
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector qg=p1in-p1out-pg;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu);
 
   mj2m=jW(p2out,false,pe,false,pnu,false,p2in,false);
   mj1p=joi(p1out,true,p1in,true);
   mj1m=joi(p1out,false,p1in,false);
 
 
   // Dot products of these which occur again and again
   COM MWpm=mj1p.dot(mj2m);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgam,jgap,j2gm,j2gp;
   j2gp=joo(p1out,true,pg,true);
   j2gm=joo(p1out,false,pg,false);
   jgap=joi(pg,true,p1in,true);
   jgam=joi(pg,false,p1in,false);
 
   CCurrent qsum(q1+qg);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
   CCurrent p1o(p1out);
   CCurrent p1i(p1in);
 
   Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2();
   Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2();
 
 
   U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2();
   U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2();
   U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2();
 
   double amm,apm;
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm);
 
   double ampsq=-(apm+amm);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*qg.m2();
   ampsq/=th;
   ampsq/=16.;
 
   return ampsq;
 
 
 }
 
 //qQbar->qQbarWg_unof
 double junofMWgqQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj2m,mj1p,mj1m;
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector qg=p1in-p1out-pg;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu);
 
   mj2m=jWbar(p2out,false,pe,false,pnu,false,p2in,false);
   mj1p=joi(p1out,true,p1in,true);
   mj1m=joi(p1out,false,p1in,false);
 
 
   // Dot products of these which occur again and again
   COM MWpm=mj1p.dot(mj2m);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgam,jgap,j2gm,j2gp;
   j2gp=joo(p1out,true,pg,true);
   j2gm=joo(p1out,false,pg,false);
   jgap=joi(pg,true,p1in,true);
   jgam=joi(pg,false,p1in,false);
 
   CCurrent qsum(q1+qg);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
   CCurrent p1o(p1out);
   CCurrent p1i(p1in);
 
   Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2();
   Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2();
 
 
   U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2();
   U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2();
   U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2();
 
   double amm,apm;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm);
 
   double ampsq=-(apm+amm);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*qg.m2();
   ampsq/=th;
   ampsq/=16.;
 
   return ampsq;
 }
 
 //qbarQ->qbarQWg_unof
 double junofMWgqbarQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj2m,mj1p,mj1m;
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector qg=p1in-p1out-pg;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu);
 
   mj2m=jW(p2out,false,pe,false,pnu,false,p2in,false);
   mj1p=jio(p1in,true,p1out,true);
   mj1m=jio(p1in,false,p1out,false);
 
 
   // Dot products of these which occur again and again
   COM MWpm=mj1p.dot(mj2m);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgam,jgap,j2gm,j2gp;
   j2gp=joo(pg,true,p1out,true);
   j2gm=joo(pg,false,p1out,false);
   jgap=jio(p1in,true,pg,true);
   jgam=jio(p1in,false,pg,false);
 
   CCurrent qsum(q1+qg);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
   CCurrent p1o(p1out);
   CCurrent p1i(p1in);
 
   Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2();
   Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2();
 
 
   U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2();
   U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2();
   U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2();
 
   double amm,apm;
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm);
 
   double ampsq=-(apm+amm);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
   // Now add the t-channels
   double th=q2.m2()*qg.m2();
   ampsq/=th;
   ampsq/=16.;
 
   return ampsq;
 
 
 }
 
 //qbarQbar->qbarQbarWg_unof
 double junofMWgqbarQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qQ->qenuQ scattering
 // p1: quark (with W emittance)
 // p2: Quark
 {
   CCurrent mj2m,mj1p,mj1m;
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector qg=p1in-p1out-pg;
   CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu);
 
   mj2m=jWbar(p2out,false,pe,false,pnu,false,p2in,false);
   mj1p=jio(p1in,true,p1out,true);
   mj1m=jio(p1in,false,p1out,false);
 
 
   // Dot products of these which occur again and again
   COM MWpm=mj1p.dot(mj2m);  // And now for the Higgs ones
   COM MWmm=mj1m.dot(mj2m);
 
   CCurrent jgam,jgap,j2gm,j2gp;
   j2gp=joo(pg,true,p1out,true);
   j2gm=joo(pg,false,p1out,false);
   jgap=jio(p1in,true,pg,true);
   jgam=jio(p1in,false,pg,false);
 
   CCurrent qsum(q1+qg);
 
   CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
   CCurrent p1o(p1out);
   CCurrent p1i(p1in);
 
   Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2();
   Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2();
 
   U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2();
   U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2();
 
   U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2();
   U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2();
 
   double amm,apm;
 
   amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm);
   apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm);
 
 
 
   double ampsq=-(apm+amm);
   //Divide by WProp
   double WPropfact = WProp(pe, pnu);
   ampsq*=WPropfact;
 
 
   // Now add the t-channels
   double th=q2.m2()*qg.m2();
   ampsq/=th;
   ampsq/=16.;
   return ampsq;
 
 
 }
 
 
 
 ///TODO make this comment more visible
 /// Naming scheme jM2-Wuno-g-({q/qbar}{Q/Qbar/g})
 ///TODO Spit naming for more complicated functions?
 /// e.g. jM2WqqtoqQQq -> jM2_Wqq_to_qQQq
 double jM2WunogqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   return ME2;
 
 }
 
 //same as function above but actually obtaining the antiquark line by crossing symmetry, where p1out and p1in are expected to be negative.
 //should give same result as jM2WunogqbarQ below (verified)
 double jM2WunogqQ_crossqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   return ME2;
 
 }
 
 double jM2WunogqQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   return ME2;
 
 }
 
 double jM2Wunogqg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   double ratio; // p2-/pb- in the notes
   if (p2in.pz()>0.) // if the gluon is the positive
     ratio=p2out.plus()/p2in.plus();
   else // the gluon is the negative
     ratio=p2out.minus()/p2in.minus();
 
   double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F;
   ME2*=cam;
 
   return ME2;
 
 }
 
 double jM2WunogqbarQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   return ME2;
 
 }
 
 double jM2WunogqbarQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   return ME2;
 
 }
 
 double jM2Wunogqbarg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   double ratio; // p2-/pb- in the notes
   if (p2in.pz()>0.) // if the gluon is the positive
     ratio=p2out.plus()/p2in.plus();
   else // the gluon is the negative
     ratio=p2out.minus()/p2in.minus();
 
   double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F;
   ME2*=cam;
 
   return ME2;
 
 }
 
 
 // W+Jets qqxExtremal
 // W+Jets qqxExtremal Currents - wqq emission
 double jM2WgQtoqbarqQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   //Correct colour averaging
   ME2*=(3.0/8.0);
 
   return ME2;
 
 }
 
 double jM2WgQtoqqbarQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in){
 
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   //Correct colour averaging
   ME2*=(3.0/8.0);
 
   return ME2;
 
 }
 
 
 double jM2Wggtoqbarqg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   double ratio; // p2-/pb- in the notes
   if (p2in.pz()>0.) // if the gluon is the positive
     ratio=p2out.plus()/p2in.plus();
   else // the gluon is the negative
     ratio=p2out.minus()/p2in.minus();
 
   double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F;
   ME2*=cam;
 
   //Correct colour averaging
   ME2*=(3.0/8.0);
 
   return ME2;
 }
 
 double jM2Wggtoqqbarg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in){
 
   //COM temp;
   double ME2mpp=0.;
   double ME2mpm=0.;
   double ME2mmp=0.;
   double ME2mmm=0.;
   double ME2;
 
   ME2mpp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,true);
   ME2mpm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,false);
   ME2mmp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,true);
   ME2mmm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,false);
 
   //Helicity sum
   ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm;
 
   double ratio; // p2-/pb- in the notes
   if (p2in.pz()>0.) // if the gluon is the positive
     ratio=p2out.plus()/p2in.plus();
   else // the gluon is the negative
     ratio=p2out.minus()/p2in.minus();
 
   double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F;
   ME2*=cam;
 
   //Correct colour averaging
   ME2*=(3.0/8.0);
 
   return ME2;
 
 }
 
 
 namespace {
 //Function to calculate Term 1 in Equation 3.23 in James Cockburn's Thesis.
-  Tensor<1,4> qggm1(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
+  Tensor<1> qggm1(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
 
     double t1 = (p3-pb)*(p3-pb);
-    Tensor<1,4> Tp3 = Construct1Tensor((p3));//p3
-    Tensor<1,4> Tpb = Construct1Tensor((pb));//pb
+    Tensor<1> Tp3 = Construct1Tensor((p3));//p3
+    Tensor<1> Tpb = Construct1Tensor((pb));//pb
     // Gauge choice in polarisation tensor. (see JC's Thesis)
-    Tensor<1,4> epsg = eps(pb, refmom, helg);
-    Tensor<3,4> qqCurBlank = T3Current(p2,hel2,p3,hel2);
-    Tensor<2,4> qqCur = qqCurBlank.contract(Tp3-Tpb,2);
-    Tensor<1,4> gqqCur = qqCur.contract(epsg,2)/t1;
+    Tensor<1> epsg = eps(pb, refmom, helg);
+    Tensor<3> qqCurBlank = T3Current(p2,hel2,p3,hel2);
+    Tensor<2> qqCur = qqCurBlank.contract(Tp3-Tpb,2);
+    Tensor<1> gqqCur = qqCur.contract(epsg,2)/t1;
 
     return gqqCur*(-1);
 }
 
 //Function to calculate Term 2 in Equation 3.23 in James Cockburn's Thesis.
-  Tensor<1,4> qggm2(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
+  Tensor<1> qggm2(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
 
     double t1 = (p2-pb)*(p2-pb);
-    Tensor<1,4> Tp2 = Construct1Tensor((p2));//p2
-    Tensor<1,4> Tpb = Construct1Tensor((pb));//pb
+    Tensor<1> Tp2 = Construct1Tensor((p2));//p2
+    Tensor<1> Tpb = Construct1Tensor((pb));//pb
     // Gauge choice in polarisation tensor. (see JC's Thesis)
-    Tensor<1,4> epsg = eps(pb,refmom, helg);
-    Tensor<3,4> qqCurBlank = T3Current(p2,hel2,p3,hel2);
-    Tensor<2,4> qqCur = qqCurBlank.contract(Tp2-Tpb,2);
-    Tensor<1,4> gqqCur = qqCur.contract(epsg,1)/t1;
+    Tensor<1> epsg = eps(pb,refmom, helg);
+    Tensor<3> qqCurBlank = T3Current(p2,hel2,p3,hel2);
+    Tensor<2> qqCur = qqCurBlank.contract(Tp2-Tpb,2);
+    Tensor<1> gqqCur = qqCur.contract(epsg,1)/t1;
 
     return gqqCur;
 }
 
 //Function to calculate Term 3 in Equation 3.23 in James Cockburn's Thesis.
-  Tensor<1,4> qggm3(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
+  Tensor<1> qggm3(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){
 
     double s23 = (p2+p3)*(p2+p3);
-    Tensor<1,4> Tp2 = Construct1Tensor((p2));//p2
-    Tensor<1,4> Tp3 = Construct1Tensor((p3));//p3
-    Tensor<1,4> Tpb = Construct1Tensor((pb));//pb
+    Tensor<1> Tp2 = Construct1Tensor((p2));//p2
+    Tensor<1> Tp3 = Construct1Tensor((p3));//p3
+    Tensor<1> Tpb = Construct1Tensor((pb));//pb
     // Gauge choice in polarisation tensor. (see JC's Thesis)
-    Tensor<1,4> epsg = eps(pb, refmom, helg);
-    Tensor<2,4> g=Metric();
-    Tensor<3,4> qqCurBlank1 = g.leftprod(Tp2+Tp3)/s23;
-    Tensor<3,4> qqCurBlank2 = g.leftprod(Tpb)/s23;
-    Tensor<1,4> Cur23 = TCurrent(p2,hel2, p3,hel2);
+    Tensor<1> epsg = eps(pb, refmom, helg);
+    Tensor<2> g=Metric();
+    Tensor<3> qqCurBlank1 = g.leftprod(Tp2+Tp3)/s23;
+    Tensor<3> qqCurBlank2 = g.leftprod(Tpb)/s23;
+    Tensor<1> Cur23 = TCurrent(p2,hel2, p3,hel2);
 
-    Tensor<2,4> qqCur1 = qqCurBlank1.contract(Cur23,3);
-    Tensor<2,4> qqCur2 = qqCurBlank2.contract(Cur23,3);
-    Tensor<2,4> qqCur3 = qqCurBlank2.contract(Cur23,1);
+    Tensor<2> qqCur1 = qqCurBlank1.contract(Cur23,3);
+    Tensor<2> qqCur2 = qqCurBlank2.contract(Cur23,3);
+    Tensor<2> qqCur3 = qqCurBlank2.contract(Cur23,1);
 
-    Tensor<1,4> gqqCur = (qqCur1.contract(epsg,1)
+    Tensor<1> gqqCur = (qqCur1.contract(epsg,1)
                           - qqCur2.contract(epsg,2)
                           + qqCur3.contract(epsg,1))*2*COM(0,1);
     return gqqCur;
 }
 }
 
 // no wqq emission
 double jM2WgqtoQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p1,  CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, bool aqlinepa){
 
   static bool is_sigma_index_set(false);
   if(!is_sigma_index_set){
     if(init_sigma_index())
       is_sigma_index_set = true;
     else
       return 0.;}
 
   // 2 independent helicity choices (complex conjugation related).
-  Tensor<1,4> TMmmm1 = qggm1(pb,p2,p3,false,false, pa);
-  Tensor<1,4> TMmmm2 = qggm2(pb,p2,p3,false,false, pa);
-  Tensor<1,4> TMmmm3 = qggm3(pb,p2,p3,false,false, pa);
-  Tensor<1,4> TMpmm1 = qggm1(pb,p2,p3,false,true, pa);
-  Tensor<1,4> TMpmm2 = qggm2(pb,p2,p3,false,true, pa);
-  Tensor<1,4> TMpmm3 = qggm3(pb,p2,p3,false,true, pa);
+  Tensor<1> TMmmm1 = qggm1(pb,p2,p3,false,false, pa);
+  Tensor<1> TMmmm2 = qggm2(pb,p2,p3,false,false, pa);
+  Tensor<1> TMmmm3 = qggm3(pb,p2,p3,false,false, pa);
+  Tensor<1> TMpmm1 = qggm1(pb,p2,p3,false,true, pa);
+  Tensor<1> TMpmm2 = qggm2(pb,p2,p3,false,true, pa);
+  Tensor<1> TMpmm3 = qggm3(pb,p2,p3,false,true, pa);
 
   // Build the external quark line W Emmision
-  Tensor<1,4> cur1a = jW(pa,p1,plbar,pl, aqlinepa);
+  Tensor<1> cur1a = jW(pa,p1,plbar,pl, aqlinepa);
 
   //Contract with the qqxCurrent.
   COM Mmmm1 = TMmmm1.contract(cur1a,1).at(0);
   COM Mmmm2 = TMmmm2.contract(cur1a,1).at(0);
   COM Mmmm3 = TMmmm3.contract(cur1a,1).at(0);
   COM Mpmm1 = TMpmm1.contract(cur1a,1).at(0);
   COM Mpmm2 = TMpmm2.contract(cur1a,1).at(0);
   COM Mpmm3 = TMpmm3.contract(cur1a,1).at(0);
 
   //Colour factors:
   COM cm1m1,cm2m2,cm3m3,cm1m2,cm1m3,cm2m3;
   cm1m1=8./3.;
   cm2m2=8./3.;
   cm3m3=6.;
   cm1m2 =-1./3.;
   cm1m3 = -3.*COM(0.,1.);
   cm2m3 = 3.*COM(0.,1.);
 
   //Sqaure and sum for each helicity config:
   double Mmmm = real(cm1m1*pow(abs(Mmmm1),2)+cm2m2*pow(abs(Mmmm2),2)+cm3m3*pow(abs(Mmmm3),2)+2.*real(cm1m2*Mmmm1*conj(Mmmm2))+2.*real(cm1m3*Mmmm1*conj(Mmmm3))+2.*real(cm2m3*Mmmm2*conj(Mmmm3)));
   double Mpmm = real(cm1m1*pow(abs(Mpmm1),2)+cm2m2*pow(abs(Mpmm2),2)+cm3m3*pow(abs(Mpmm3),2)+2.*real(cm1m2*Mpmm1*conj(Mpmm2))+2.*real(cm1m3*Mpmm1*conj(Mpmm3))+2.*real(cm2m3*Mpmm2*conj(Mpmm3)));
 
   // Divide by WProp
   double WPropfact = WProp(plbar, pl);
 
   return (2*WPropfact*(Mmmm+Mpmm)/24./4.)/(pa-p1-pl-plbar).m2()/(p2+p3-pb).m2();
 }
 
 
 // W+Jets qqxCentral
 double jM2WqqtoqQQq(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove)
 {
 
   static bool is_sigma_index_set(false);
   if(!is_sigma_index_set){
     if(init_sigma_index())
       is_sigma_index_set = true;
     else
       return 0.;}
 
   HLV pq, pqbar, p1, p4;
   if (qqxmarker){
     pqbar = partons[nabove+1];
     pq = partons[nabove+2];}
   else{
     pq = partons[nabove+1];
     pqbar = partons[nabove+2];}
 
   p1 = partons.front();
   p4 = partons.back();
 
-  Tensor<1,4> T1am, T4bm, T1ap, T4bp;
+  Tensor<1> T1am, T4bm, T1ap, T4bp;
   if(!(aqlinepa)){
     T1ap = TCurrent(p1, true, pa, true);
     T1am = TCurrent(p1, false, pa, false);}
   else if(aqlinepa){
     T1ap = TCurrent(pa, true, p1, true);
     T1am = TCurrent(pa, false, p1, false);}
   if(!(aqlinepb)){
     T4bp = TCurrent(p4, true, pb, true);
     T4bm = TCurrent(p4, false, pb, false);}
   else if(aqlinepb){
     T4bp = TCurrent(pb, true, p4, true);
     T4bm = TCurrent(pb, false, p4, false);}
 
   // Calculate the 3 separate contributions to the effective vertex
-  Tensor<2,4> Xunc = MUncrossW(pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
-  Tensor<2,4> Xcro = MCrossW(  pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
-  Tensor<2,4> Xsym = MSymW(    pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
+  Tensor<2> Xunc = MUncrossW(pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
+  Tensor<2> Xcro = MCrossW(  pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
+  Tensor<2> Xsym = MSymW(    pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove);
 
   // 4 Different Helicity Choices (Differs from Pure Jet Case, where there is also the choice in qqbar helicity.
   // (- - hel choice)
   COM M_mmUnc = (((Xunc).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mmCro = (((Xcro).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mmSym = (((Xsym).contract(T1am,1)).contract(T4bm,1)).at(0);
   // (- + hel choice)
   COM M_mpUnc = (((Xunc).contract(T1am,1)).contract(T4bp,1)).at(0);
   COM M_mpCro = (((Xcro).contract(T1am,1)).contract(T4bp,1)).at(0);
   COM M_mpSym = (((Xsym).contract(T1am,1)).contract(T4bp,1)).at(0);
   // (+ - hel choice)
   COM M_pmUnc = (((Xunc).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_pmCro = (((Xcro).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_pmSym = (((Xsym).contract(T1ap,1)).contract(T4bm,1)).at(0);
   // (+ + hel choice)
   COM M_ppUnc = (((Xunc).contract(T1ap,1)).contract(T4bp,1)).at(0);
   COM M_ppCro = (((Xcro).contract(T1ap,1)).contract(T4bp,1)).at(0);
   COM M_ppSym = (((Xsym).contract(T1ap,1)).contract(T4bp,1)).at(0);
 
   //Colour factors:
   COM cmsms,cmumu,cmcmc,cmsmu,cmsmc,cmumc;
   cmsms=3.;
   cmumu=4./3.;
   cmcmc=4./3.;
   cmsmu =3./2.*COM(0.,1.);
   cmsmc = -3./2.*COM(0.,1.);
   cmumc = -1./6.;
 
   // Work Out Interference in each case of helicity:
   double amp_mm = real(cmsms*pow(abs(M_mmSym),2)
              +cmumu*pow(abs(M_mmUnc),2)
              +cmcmc*pow(abs(M_mmCro),2)
              +2.*real(cmsmu*M_mmSym*conj(M_mmUnc))
              +2.*real(cmsmc*M_mmSym*conj(M_mmCro))
              +2.*real(cmumc*M_mmUnc*conj(M_mmCro)));
 
   double amp_mp = real(cmsms*pow(abs(M_mpSym),2)
              +cmumu*pow(abs(M_mpUnc),2)
              +cmcmc*pow(abs(M_mpCro),2)
              +2.*real(cmsmu*M_mpSym*conj(M_mpUnc))
              +2.*real(cmsmc*M_mpSym*conj(M_mpCro))
              +2.*real(cmumc*M_mpUnc*conj(M_mpCro)));
 
   double amp_pm = real(cmsms*pow(abs(M_pmSym),2)
              +cmumu*pow(abs(M_pmUnc),2)
              +cmcmc*pow(abs(M_pmCro),2)
              +2.*real(cmsmu*M_pmSym*conj(M_pmUnc))
              +2.*real(cmsmc*M_pmSym*conj(M_pmCro))
              +2.*real(cmumc*M_pmUnc*conj(M_pmCro)));
 
   double amp_pp = real(cmsms*pow(abs(M_ppSym),2)
              +cmumu*pow(abs(M_ppUnc),2)
              +cmcmc*pow(abs(M_ppCro),2)
              +2.*real(cmsmu*M_ppSym*conj(M_ppUnc))
              +2.*real(cmsmc*M_ppSym*conj(M_ppCro))
              +2.*real(cmumc*M_ppUnc*conj(M_ppCro)));
 
   double amp=((amp_mm+amp_mp+amp_pm+amp_pp)/(9.*4.));
 
 
 
   CLHEP::HepLorentzVector q1,q3;
   q1=pa;
   for(int i=0;i<nabove+1;i++){
     q1-=partons.at(i);
   }
   q3 = q1 - pq - pqbar - pl - plbar;
 
   double t1 = (q1).m2();
   double t3 = (q3).m2();
 
   //Divide by t-channels
   amp/=(t1*t1*t3*t3);
 
   //Divide by WProp
   double WPropfact = WProp(plbar, pl);
   amp*=WPropfact;
 
 
   return amp;
 }
 
 // no wqq emission
 double jM2WqqtoqQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<CLHEP::HepLorentzVector> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove, int nbelow, bool forwards){
 
   static bool is_sigma_index_set(false);
   if(!is_sigma_index_set){
     if(init_sigma_index())
       is_sigma_index_set = true;
     else
       return 0.;
   }
 
   if (!forwards){ //If Emission from Leg a instead, flip process.
     HLV dummymom = pa;
     bool dummybool= aqlinepa;
     int dummyint = nabove;
     pa = pb;
     pb = dummymom;
     std::reverse(partons.begin(),partons.end());
     qqxmarker = !(qqxmarker);
     aqlinepa = aqlinepb;
     aqlinepb = dummybool;
     nabove = nbelow;
     nbelow = dummyint;
   }
 
   HLV pq, pqbar, p1,p4;
   if (qqxmarker){
     pqbar = partons[nabove+1];
     pq = partons[nabove+2];}
   else{
     pq = partons[nabove+1];
     pqbar = partons[nabove+2];}
 
   p1 = partons.front();
   p4 = partons.back();
 
-  Tensor<1,4> T1am(0.), T1ap(0.);
+  Tensor<1> T1am(0.), T1ap(0.);
   if(!(aqlinepa)){
     T1ap = TCurrent(p1, true, pa, true);
     T1am = TCurrent(p1, false, pa, false);}
   else if(aqlinepa){
     T1ap = TCurrent(pa, true, p1, true);
     T1am = TCurrent(pa, false, p1, false);}
 
-  Tensor <1,4> T4bm = jW(pb, p4, plbar, pl, aqlinepb);
+  Tensor <1> T4bm = jW(pb, p4, plbar, pl, aqlinepb);
 
   // Calculate the 3 separate contributions to the effective vertex
-  Tensor<2,4> Xunc_m = MUncross(pa, pq, pqbar,partons, false, nabove);
-  Tensor<2,4> Xcro_m = MCross(  pa, pq, pqbar,partons, false, nabove);
-  Tensor<2,4> Xsym_m = MSym(    pa, p1, pb, p4, pq, pqbar, partons, false, nabove);
+  Tensor<2> Xunc_m = MUncross(pa, pq, pqbar,partons, false, nabove);
+  Tensor<2> Xcro_m = MCross(  pa, pq, pqbar,partons, false, nabove);
+  Tensor<2> Xsym_m = MSym(    pa, p1, pb, p4, pq, pqbar, partons, false, nabove);
 
-  Tensor<2,4> Xunc_p = MUncross(pa, pq, pqbar,partons, true, nabove);
-  Tensor<2,4> Xcro_p = MCross(  pa, pq, pqbar,partons, true, nabove);
-  Tensor<2,4> Xsym_p = MSym(    pa, p1, pb, p4, pq, pqbar, partons, true, nabove);
+  Tensor<2> Xunc_p = MUncross(pa, pq, pqbar,partons, true, nabove);
+  Tensor<2> Xcro_p = MCross(  pa, pq, pqbar,partons, true, nabove);
+  Tensor<2> Xsym_p = MSym(    pa, p1, pb, p4, pq, pqbar, partons, true, nabove);
 
 
   // (- - hel choice)
   COM M_mmUnc = (((Xunc_m).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mmCro = (((Xcro_m).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mmSym = (((Xsym_m).contract(T1am,1)).contract(T4bm,1)).at(0);
   // (- + hel choice)
   COM M_mpUnc = (((Xunc_p).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mpCro = (((Xcro_p).contract(T1am,1)).contract(T4bm,1)).at(0);
   COM M_mpSym = (((Xsym_p).contract(T1am,1)).contract(T4bm,1)).at(0);
   // (+ - hel choice)
   COM M_pmUnc = (((Xunc_m).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_pmCro = (((Xcro_m).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_pmSym = (((Xsym_m).contract(T1ap,1)).contract(T4bm,1)).at(0);
   // (+ + hel choice)
   COM M_ppUnc = (((Xunc_p).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_ppCro = (((Xcro_p).contract(T1ap,1)).contract(T4bm,1)).at(0);
   COM M_ppSym = (((Xsym_p).contract(T1ap,1)).contract(T4bm,1)).at(0);
 
   //Colour factors:
   COM cmsms,cmumu,cmcmc,cmsmu,cmsmc,cmumc;
   cmsms=3.;
   cmumu=4./3.;
   cmcmc=4./3.;
   cmsmu =3./2.*COM(0.,1.);
   cmsmc = -3./2.*COM(0.,1.);
   cmumc = -1./6.;
 
   // Work Out Interference in each case of helicity:
   double amp_mm = real(cmsms*pow(abs(M_mmSym),2)
              +cmumu*pow(abs(M_mmUnc),2)
              +cmcmc*pow(abs(M_mmCro),2)
              +2.*real(cmsmu*M_mmSym*conj(M_mmUnc))
              +2.*real(cmsmc*M_mmSym*conj(M_mmCro))
              +2.*real(cmumc*M_mmUnc*conj(M_mmCro)));
 
   double amp_mp = real(cmsms*pow(abs(M_mpSym),2)
              +cmumu*pow(abs(M_mpUnc),2)
              +cmcmc*pow(abs(M_mpCro),2)
              +2.*real(cmsmu*M_mpSym*conj(M_mpUnc))
              +2.*real(cmsmc*M_mpSym*conj(M_mpCro))
              +2.*real(cmumc*M_mpUnc*conj(M_mpCro)));
 
   double amp_pm = real(cmsms*pow(abs(M_pmSym),2)
              +cmumu*pow(abs(M_pmUnc),2)
              +cmcmc*pow(abs(M_pmCro),2)
              +2.*real(cmsmu*M_pmSym*conj(M_pmUnc))
              +2.*real(cmsmc*M_pmSym*conj(M_pmCro))
              +2.*real(cmumc*M_pmUnc*conj(M_pmCro)));
 
   double amp_pp = real(cmsms*pow(abs(M_ppSym),2)
              +cmumu*pow(abs(M_ppUnc),2)
              +cmcmc*pow(abs(M_ppCro),2)
              +2.*real(cmsmu*M_ppSym*conj(M_ppUnc))
              +2.*real(cmsmc*M_ppSym*conj(M_ppCro))
              +2.*real(cmumc*M_ppUnc*conj(M_ppCro)));
 
   double amp=((amp_mm+amp_mp+amp_pm+amp_pp)/(9.*4.));
 
   CLHEP::HepLorentzVector q1,q3;
   q1=pa;
   for(int i=0;i<nabove+1;i++){
     q1-=partons.at(i);
   }
   q3 = q1 - pq - pqbar;
 
   double t1 = (q1).m2();
   double t3 = (q3).m2();
 
   //Divide by t-channels
   amp/=(t1*t1*t3*t3);
 
   //Divide by WProp
   double WPropfact = WProp(plbar, pl);
   amp*=WPropfact;
 
   return amp;
 }
diff --git a/src/currents.cc b/src/currents.cc
index 26542a9..cb956e0 100644
--- a/src/currents.cc
+++ b/src/currents.cc
@@ -1,3198 +1,3166 @@
 /**
  *  \authors   The HEJ collaboration (see AUTHORS for details)
  *  \date      2019
  *  \copyright GPLv2 or later
  */
 #include "HEJ/currents.hh"
 
 #include <iostream>
 #include <limits>
 #include <utility>
 #include <vector>
 
 #ifdef HEJ_BUILD_WITH_QCDLOOP
 #include "qcdloop/qcdloop.h"
 #endif
 
 #include "HEJ/Constants.hh"
 #include "HEJ/exceptions.hh"
 #include "HEJ/PDG_codes.hh"
 
 const COM looprwfactor = (COM(0.,1.)*M_PI*M_PI)/pow((2.*M_PI),4);
 constexpr double infinity = std::numeric_limits<double>::infinity();
 
 namespace {
   // Loop integrals
   #ifdef HEJ_BUILD_WITH_QCDLOOP
 
   COM B0DD(CLHEP::HepLorentzVector q, double mq)
   {
     static std::vector<std::complex<double>> result(3);
     static auto ql_B0 = [](){
       ql::Bubble<std::complex<double>,double,double> ql_B0;
       ql_B0.setCacheSize(100);
       return ql_B0;
     }();
     static std::vector<double> masses(2);
     static std::vector<double> momenta(1);
     for(auto & m: masses) m = mq*mq;
     momenta.front() = q.m2();
     ql_B0.integral(result, 1, masses, momenta);
     return result[0];
   }
   COM C0DD(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq)
   {
     static std::vector<std::complex<double>> result(3);
     static auto ql_C0 = [](){
       ql::Triangle<std::complex<double>,double,double> ql_C0;
       ql_C0.setCacheSize(100);
       return ql_C0;
     }();
     static std::vector<double> masses(3);
     static std::vector<double> momenta(3);
     for(auto & m: masses) m = mq*mq;
     momenta[0] = q1.m2();
     momenta[1] = q2.m2();
     momenta[2] = (q1+q2).m2();
     ql_C0.integral(result, 1, masses, momenta);
     return result[0];
   }
   COM D0DD(CLHEP::HepLorentzVector q1,CLHEP::HepLorentzVector q2, CLHEP::HepLorentzVector q3, double mq)
   {
     static std::vector<std::complex<double>> result(3);
     static auto ql_D0 = [](){
       ql::Box<std::complex<double>,double,double> ql_D0;
       ql_D0.setCacheSize(100);
       return ql_D0;
     }();
     static std::vector<double> masses(4);
     static std::vector<double> momenta(6);
     for(auto & m: masses) m = mq*mq;
     momenta[0] = q1.m2();
     momenta[1] = q2.m2();
     momenta[2] = q3.m2();
     momenta[3] = (q1+q2+q3).m2();
     momenta[4] = (q1+q2).m2();
     momenta[5] = (q2+q3).m2();
     ql_D0.integral(result, 1, masses, momenta);
     return result[0];
   }
 
   COM A1(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt)
   // As given in Eq. (B.2) of VDD
   {
     double q12,q22,Q2;
     CLHEP::HepLorentzVector Q;
     double Delta3,mt2;
     COM ans(COM(0.,0.));
 
     q12=q1.m2();
     q22=q2.m2();
     Q=-q1-q2; // Define all momenta ingoing as in appendix of VDD
     Q2=Q.m2();
 
     Delta3=q12*q12+q22*q22+Q2*Q2-2*q12*q22-2*q12*Q2-2*q22*Q2;
     if (mt < 0.)
       std::cerr<<"Problem in A1! mt = "<<mt<<std::endl;
     mt2=mt*mt;
 
     ans=looprwfactor*COM(0,-1)*C0DD(q1,q2,mt)*( 4.*mt2/Delta3*(Q2-q12-q22)
         -1.-4.*q12*q22/Delta3-12.*q12*q22*Q2/Delta3/Delta3*(q12+q22-Q2) )
       - looprwfactor*COM(0,-1)*( B0DD(q2,mt)-B0DD(Q,mt) )
         * ( 2.*q22/Delta3+12.*q12*q22/Delta3/Delta3*(q22-q12+Q2) )
       - looprwfactor*COM(0,-1)*( B0DD(q1,mt)-B0DD(Q,mt) )
         * ( 2.*q12/Delta3+12.*q12*q22/Delta3/Delta3*(q12-q22+Q2) )
       - 2./Delta3/16/M_PI/M_PI*(q12+q22-Q2);
 
     return ans;
 
   }
 
 
   COM A2(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt)
   // As given in Eq. (B.2) of VDD, but with high energy limit
   // of invariants taken.
   {
     double q12,q22,Q2;
     CLHEP::HepLorentzVector Q;
     double Delta3,mt2;
     COM ans(COM(0.,0.));
 
     if (mt < 0.)
       std::cerr<<"Problem in A2! mt = "<<mt<<std::endl;
     mt2=mt*mt;
 
     q12=q1.m2();
     q22=q2.m2();
     Q=-q1-q2; // Define all momenta ingoing as in appendix of VDD
     Q2=Q.m2();
 
     Delta3=q12*q12+q22*q22+Q2*Q2-2*q12*q22-2*q12*Q2-2*q22*Q2;
     ans=looprwfactor*COM(0,-1)*C0DD(q1,q2,mt)*( 2.*mt2+1./2.*(q12+q22-Q2)
         +2.*q12*q22*Q2/Delta3 )
       +looprwfactor*COM(0,-1)*(B0DD(q2,mt)-B0DD(Q,mt))
         *q22*(q22-q12-Q2)/Delta3
       +looprwfactor*COM(0,-1)*(B0DD(q1,mt)-B0DD(Q,mt))
         *q12*(q12-q22-Q2)/Delta3+1./16/M_PI/M_PI;
 
     return ans;
   }
 
 #else // no QCDloop
 
   COM A1(CLHEP::HepLorentzVector, CLHEP::HepLorentzVector, double) {
     throw std::logic_error{"A1 called without QCDloop support"};
   }
 
   COM A2(CLHEP::HepLorentzVector, CLHEP::HepLorentzVector, double) {
     throw std::logic_error{"A2 called without QCDloop support"};
   }
 
 #endif
 
   void to_current(const CLHEP::HepLorentzVector & q, current & ret){
     ret[0]=q.e();
     ret[1]=q.x();
     ret[2]=q.y();
     ret[3]=q.z();
   }
 
   constexpr double C_A = 3.;
   constexpr double C_F = 4./3.;
   // using ParticleID = HEJ::pid::ParticleID;
 
 
 } // namespace anonymous
 
   // Colour acceleration multiplier for gluons see eq. (7) in arXiv:0910.5113
   // @TODO: this is not a current and should be moved somewhere else
   double K_g(double p1minus, double paminus) {
     return 1./2.*(p1minus/paminus + paminus/p1minus)*(HEJ::C_A - 1./HEJ::C_A) + 1./HEJ::C_A;
   }
   double K_g(
       CLHEP::HepLorentzVector const & pout,
       CLHEP::HepLorentzVector const & pin
   ) {
     if(pin.z() > 0) return K_g(pout.plus(), pin.plus());
     return K_g(pout.minus(), pin.minus());
   }
 
 
 CCurrent CCurrent::operator+(const CCurrent& other)
 {
     COM result_c0=c0 + other.c0;
     COM result_c1=c1 + other.c1;
     COM result_c2=c2 + other.c2;
     COM result_c3=c3 + other.c3;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 CCurrent CCurrent::operator-(const CCurrent& other)
 {
     COM result_c0=c0 - other.c0;
     COM result_c1=c1 - other.c1;
     COM result_c2=c2 - other.c2;
     COM result_c3=c3 - other.c3;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 CCurrent CCurrent::operator*(const double x)
 {
     COM result_c0=x*CCurrent::c0;
     COM result_c1=x*CCurrent::c1;
     COM result_c2=x*CCurrent::c2;
     COM result_c3=x*CCurrent::c3;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 CCurrent CCurrent::operator/(const double x)
 {
     COM result_c0=CCurrent::c0/x;
     COM result_c1=CCurrent::c1/x;
     COM result_c2=CCurrent::c2/x;
     COM result_c3=CCurrent::c3/x;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 CCurrent CCurrent::operator*(const COM x)
 {
     COM result_c0=x*CCurrent::c0;
     COM result_c1=x*CCurrent::c1;
     COM result_c2=x*CCurrent::c2;
     COM result_c3=x*CCurrent::c3;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 CCurrent CCurrent::operator/(const COM x)
 {
     COM result_c0=(CCurrent::c0)/x;
     COM result_c1=(CCurrent::c1)/x;
     COM result_c2=(CCurrent::c2)/x;
     COM result_c3=(CCurrent::c3)/x;
 
     return CCurrent(result_c0,result_c1,result_c2,result_c3);
 }
 
 std::ostream& operator <<(std::ostream& os, const CCurrent& cur)
 {
     os << "("<<cur.c0<< " ; "<<cur.c1<<" , "<<cur.c2<<" , "<<cur.c3<<")";
     return os;
 }
 
 CCurrent operator * ( double x, CCurrent& m)
 {
     return m*x;
 }
 
 CCurrent operator * ( COM x, CCurrent& m)
 {
     return m*x;
 }
 
 CCurrent operator / ( double x, CCurrent& m)
 {
     return m/x;
 }
 
 CCurrent operator / ( COM x, CCurrent& m)
 {
     return m/x;
 }
 
 COM CCurrent::dot(CLHEP::HepLorentzVector p1)
 {
     //  Current goes (E,px,py,pz)
     //  std::cout<<"current = ("<<c0<<","<<c1<<","<<c2<<","<<c3<<")\n";
     //  Vector goes (px,py,pz,E)
     //  std::cout<<"vector = ("<<p1[0]<<","<<p1[1]<<","<<p1[2]<<","<<p1[3]<<")\n";
     return p1[3]*c0-p1[0]*c1-p1[1]*c2-p1[2]*c3;
 }
 
 COM CCurrent::dot(CCurrent p1)
 {
     return p1.c0*c0-p1.c1*c1-p1.c2*c2-p1.c3*c3;
 }
 
 //Current Functions
 
 // Current for <outgoing state | mu | incoming state>
 /// @TODO always use this instead of "j"
 /// @TODO isn't this jio with flipt helicities?
 void joi(HLV pout, bool helout, HLV pin, bool helin, current &cur) {
   cur[0]=0.;
   cur[1]=0.;
   cur[2]=0.;
   cur[3]=0.;
 
   const double sqpop = sqrt(pout.plus());
   const double sqpom = sqrt(pout.minus());
   const COM poperp = pout.x() + COM(0, 1) * pout.y();
 
   if (helout != helin) {
     throw std::invalid_argument{"Non-matching helicities"};
   } else if (helout == false) { // negative helicity
     if (pin.plus() > pin.minus()) { // if forward
       const double sqpip = sqrt(pin.plus());
       cur[0] = sqpop * sqpip;
       cur[1] = sqpom * sqpip * poperp / abs(poperp);
       cur[2] = -COM(0,1) * cur[1];
       cur[3] = cur[0];
     } else { // if backward
       const double sqpim = sqrt(pin.minus());
       cur[0] = -sqpom * sqpim * poperp / abs(poperp);
       cur[1] = -sqpim * sqpop;
       cur[2] = COM(0,1) * cur[1];
       cur[3] = -cur[0];
     }
   } else { // positive helicity
     if (pin.plus() > pin.minus()) { // if forward
       const double sqpip = sqrt(pin.plus());
       cur[0] = sqpop * sqpip;
       cur[1] = sqpom * sqpip * conj(poperp) / abs(poperp);
       cur[2] = COM(0,1) * cur[1];
       cur[3] = cur[0];
     } else { // if backward
       const double sqpim = sqrt(pin.minus());
       cur[0] = -sqpom * sqpim * conj(poperp) / abs(poperp);
       cur[1] = -sqpim * sqpop;
       cur[2] = -COM(0,1) * cur[1];
       cur[3] = -cur[0];
     }
   }
 }
 
 CCurrent joi (HLV pout, bool helout, HLV pin, bool helin)
 {
   current cur;
   joi(pout, helout, pin, helin, cur);
   return CCurrent(cur[0],cur[1],cur[2],cur[3]);
 }
 
-/// @TODO remove this
-void j (HLV pout, bool helout, HLV pin, bool helin,current &cur) {
-  joi(pout, helout, pin, helin, cur);
-}
-
-/// @TODO remove this
-CCurrent j (HLV pout, bool helout, HLV pin, bool helin)
-{
-    return joi(pout, helout, pin, helin);
-}
-
-
 // Current for <incoming state | mu | outgoing state>
 void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur) {
 
   cur[0] = 0.0;
   cur[1] = 0.0;
   cur[2] = 0.0;
   cur[3] = 0.0;
   const double sqpop = sqrt(pout.plus());
   const double sqpom = sqrt(pout.minus());
   const COM poperp = pout.x() + COM(0, 1) * pout.y();
 
 
   if (helout != helin) {
     throw std::invalid_argument{"Non-matching helicities"};
   } else if (helout == false) { // negative helicity
     if (pin.plus() > pin.minus()) { // if forward
       const double sqpip = sqrt(pin.plus());
       cur[0] = sqpop * sqpip;
       cur[1] = sqpom * sqpip * conj(poperp) / abs(poperp);
       cur[2] = COM(0,1) * cur[1];
       cur[3] = cur[0];
     } else { // if backward
       const double sqpim = sqrt(pin.minus());
       cur[0] = -sqpom * sqpim * conj(poperp) / abs(poperp);
       cur[1] = -sqpim * sqpop;
       cur[2] = -COM(0,1) * cur[1];
       cur[3] = -cur[0];
     }
   } else { // positive helicity
     if (pin.plus() > pin.minus()) { // if forward
       const double sqpip = sqrt(pin.plus());
       cur[0] = sqpop * sqpip;
       cur[1] = sqpom * sqpip * poperp / abs(poperp);
       cur[2] = -COM(0,1) * cur[1];
       cur[3] = cur[0];
     } else { // if backward
       const double sqpim = sqrt(pin.minus());
       cur[0] = -sqpom * sqpim * poperp / abs(poperp);
       cur[1] = -sqpim * sqpop;
       cur[2] = COM(0,1) * cur[1];
       cur[3] = -cur[0];
     }
   }
 }
 
 CCurrent jio (HLV pin, bool helin, HLV pout, bool helout)
 {
     current cur;
     jio(pin, helin, pout, helout, cur);
     return CCurrent(cur[0],cur[1],cur[2],cur[3]);
 }
 
 
 // Current for <outgoing state | mu | outgoing state>
 void joo(HLV pi, bool heli, HLV pj, bool helj, current &cur) {
 
   // Zero our current
   cur[0] = 0.0;
   cur[1] = 0.0;
   cur[2] = 0.0;
   cur[3] = 0.0;
   if (heli!=helj) {
     throw std::invalid_argument{"Non-matching helicities"};
   } else if ( heli == true ) { // If positive helicity swap momenta
     std::swap(pi,pj);
   }
 
   const double sqpjp = sqrt(pj.plus());
   const double sqpjm = sqrt(pj.minus());
   const double sqpip = sqrt(pi.plus());
   const double sqpim = sqrt(pi.minus());
 
   const COM piperp = pi.x() + COM(0,1) * pi.y();
   const COM pjperp = pj.x() + COM(0,1) * pj.y();
   const COM phasei = piperp / abs(piperp);
   const COM phasej = pjperp / abs(pjperp);
 
   cur[0] = sqpim * sqpjm * phasei * conj(phasej) + sqpip * sqpjp;
   cur[1] = sqpim * sqpjp * phasei + sqpip * sqpjm * conj(phasej);
   cur[2] = -COM(0, 1) * (sqpim * sqpjp * phasei - sqpip * sqpjm * conj(phasej));
   cur[3] = -sqpim * sqpjm * phasei * conj(phasej) + sqpip * sqpjp;
 }
 
 CCurrent joo (HLV pi, bool heli, HLV pj, bool helj)
 {
   current cur;
   joo(pi, heli, pj, helj, cur);
   return CCurrent(cur[0],cur[1],cur[2],cur[3]);
 }
 
-namespace {
-  /// @TODO unused function
-  // double jM2 (CLHEP::HepLorentzVector p1out, bool hel1out, CLHEP::HepLorentzVector p1in, bool hel1in, CLHEP::HepLorentzVector p2out, bool hel2out, CLHEP::HepLorentzVector p2in, bool hel2in)
-  // {
-  //   CLHEP::HepLorentzVector q1=p1in-p1out;
-  //   CLHEP::HepLorentzVector q2=-(p2in-p2out);
-  //   current C1,C2;
-  //   j (p1out,hel1out,p1in,hel1in, C1);
-  //   j (p2out,hel2out,p2in,hel2in, C2);
-
-  //   std::cout << "# From Currents, C1 : ("<<C1[0]<<","<<C1[1]<<","<<C1[2]<<","<<C1[3]<<"\n";
-  //   std::cout << "# From Currents, C2 : ("<<C2[0]<<","<<C2[1]<<","<<C2[2]<<","<<C2[3]<<"\n";
-
-  //   COM M=cdot(C1,C2);
-
-  //   return (M*conj(M)).real()/(q1.m2()*q2.m2());
-  // }
-
-} // namespace anonymous
-
 double jM2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   //  std::cerr<<"Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<std::endl;
 
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
   current mj1m,mj1p,mj2m,mj2p;
   joi(p1out,true,p1in,true,mj1p);
   joi(p1out,false,p1in,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   double sst=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm);
 
   // Multiply by Cf^2
   return HEJ::C_F*HEJ::C_F*(sst)/(q1.m2()*q2.m2());
 }
 
 double jM2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current mj1m,mj1p,mj2m,mj2p;
   joi(p1out,true,p1in,true,mj1p);
   joi(p1out,false,p1in,false,mj1m);
   jio(p2in,true,p2out,true,mj2p);
   jio(p2in,false,p2out,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   double sumsq=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm);
 
   // Multiply by Cf^2
   return C_F*C_F*(sumsq)/(q1.m2()*q2.m2());
 }
 
 double jM2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 {
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current mj1m,mj1p,mj2m,mj2p;
   jio(p1in,true,p1out,true,mj1p);
   jio(p1in,false,p1out,false,mj1m);
   jio(p2in,true,p2out,true,mj2p);
   jio(p2in,false,p2out,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   double sumsq=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm);
 
   // Multiply by Cf^2
   return C_F*C_F*(sumsq)/(q1.m2()*q2.m2());
 }
 
 double jM2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qg scattering
 // p1: quark
 // p2: gluon
 {
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   current mj1m,mj1p,mj2m,mj2p;
   joi(p1out,true,p1in,true,mj1p);
   joi(p1out,false,p1in,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   const double K = K_g(p2out, p2in);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
   double a2Mpp=abs2(Mpp);
   double a2Mpm=abs2(Mpm);
   double sst = K/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm);
 
   // Cf*Ca=4
   return C_F*C_A*sst/(q1.m2()*q2.m2());
 
 }
 
 double jM2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for qg scattering
 // p1: quark
 // p2: gluon
 {
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   current mj1m,mj1p,mj2m,mj2p;
   jio(p1in,true,p1out,true,mj1p);
   jio(p1in,false,p1out,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   const double K = K_g(p2out, p2in);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
   double a2Mpp=abs2(Mpp);
   double a2Mpm=abs2(Mpm);
   double sst = K/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm);
 
   // Cf*Ca=4
   return C_F*C_A*sst/(q1.m2()*q2.m2());
 
 }
 
 double jM2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in)
 // Calculates the square of the current contractions for gg scattering
 // p1: gluon
 // p2: gluon
 {
   CLHEP::HepLorentzVector q1=p1in-p1out;
   CLHEP::HepLorentzVector q2=-(p2in-p2out);
 
   current mj1m,mj1p,mj2m,mj2p;
   joi(p1out,true,p1in,true,mj1p);
   joi(p1out,false,p1in,false,mj1m);
   joi(p2out,true,p2in,true,mj2p);
   joi(p2out,false,p2in,false,mj2m);
 
   COM Mmp=cdot(mj1m,mj2p);
   COM Mmm=cdot(mj1m,mj2m);
   COM Mpp=cdot(mj1p,mj2p);
   COM Mpm=cdot(mj1p,mj2m);
 
   const double K_g1 = K_g(p1out, p1in);
   const double K_g2 = K_g(p2out, p2in);
 
   // sum of spinor strings ||^2
   double a2Mmp=abs2(Mmp);
   double a2Mmm=abs2(Mmm);
   double a2Mpp=abs2(Mpp);
   double a2Mpm=abs2(Mpm);
   double sst = K_g1/C_A*K_g2/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm);
   // Ca*Ca=9
   return C_A*C_A*sst/(q1.m2()*q2.m2());
 }
 
 namespace {
   /**
    * @brief Higgs vertex contracted with current @param C1 and @param C2
    */
   COM cHdot(const current & C1, const current & C2, const current & q1,
             const current & q2, double mt, bool incBot, double mb)
   {
     if (mt == infinity) {
       return (cdot(C1,C2)*cdot(q1,q2)-cdot(C1,q2)*cdot(C2,q1))/(6*M_PI*HEJ::vev);
     }
     else {
       CLHEP::HepLorentzVector vq1,vq2;
       vq1.set(q1[1].real(),q1[2].real(),q1[3].real(),q1[0].real());
       vq2.set(q2[1].real(),q2[2].real(),q2[3].real(),q2[0].real());
       // first minus sign obtained because of q1-difference to VDD
       // std::cout<<"A1 : " << A1(-vq1,vq2)<<std::endl;
       // std::cout<<"A2 : " << A2(-vq1,vq2)<<std::endl;
       if(!(incBot))
         // Factor is because 4 mt^2 g^2/HEJ::vev A1 -> 16 pi mt^2/HEJ::vev alphas,
         // and we divide by a factor 4 at the amp sqaured level later
         // which I absorb here (i.e. I divide by 2)
         /// @TODO move factor 1/2 from S to |ME|^2 => consistent with general notation
         return 8.*M_PI*mt*mt/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mt)-cdot(C1,C2)*A2(-vq1,vq2,mt));
       else
         return 8.*M_PI*mt*mt/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mt)-cdot(C1,C2)*A2(-vq1,vq2,mt))
              + 8.*M_PI*mb*mb/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mb)-cdot(C1,C2)*A2(-vq1,vq2,mb));
     }
   }
 } // namespace anonymous
 
 double MH2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
               CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
               CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2,
               double mt, bool incBot, double mb)
 {
 //   CLHEP::HepLorentzVector q1=p1in-p1out;
 //   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current j1p,j1m,j2p,j2m, q1v, q2v;
 
   joi (p1out,true,p1in,true,j1p);
   joi (p1out,false,p1in,false,j1m);
 
   joi (p2out,true,p2in,true,j2p);
   joi (p2out,false,p2in,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
   COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
 
   double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm);
   // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 {
 //   CLHEP::HepLorentzVector q1=p1in-p1out;
 //   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   joi (p1out,true,p1in,true,j1p);
   joi (p1out,false,p1in,false,j1m);
 
   jio (p2in,true,p2out,true,j2p);
   jio (p2in,false,p2out,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
   COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
 
   double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm);
   // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2qbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 {
 //   CLHEP::HepLorentzVector q1=p1in-p1out;
 //   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   jio (p1in,true,p1out,true,j1p);
   jio (p1in,false,p1out,false,j1m);
 
   joi (p2out,true,p2in,true,j2p);
   joi (p2out,false,p2in,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
   COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
 
   double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm);
   // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 {
 //   CLHEP::HepLorentzVector q1=p1in-p1out;
 //   CLHEP::HepLorentzVector q2=-(p2in-p2out);
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   jio (p1in,true,p1out,true,j1p);
   jio (p1in,false,p1out,false,j1m);
 
   jio (p2in,true,p2out,true,j2p);
   jio (p2in,false,p2out,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
   COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
 
   double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm);
   // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 // q~p1 g~p2 (i.e. ALWAYS p1 for quark, p2 for gluon)
 // should be called with q1 meant to be contracted with p2 in first part of vertex
 // (i.e. if g is backward, q1 is forward)
 {
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   joi (p1out,true,p1in,true,j1p);
   joi (p1out,false,p1in,false,j1m);
 
   joi (p2out,true,p2in,true,j2p);
   joi (p2out,false,p2in,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   // First, calculate the non-flipping amplitudes:
 
   COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
   COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
 
   //cout << "Bits in MH2qg: " << Mpp << " " << Mpm << " " << Mmp << " " << Mmm << endl;
 
   const double K = K_g(p2out, p2in);
 
   double sst=K/C_A*(abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm));
 
   // Cf*Ca=4
   // return 4.*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 // qbar~p1 g~p2 (i.e. ALWAYS p1 for anti-quark, p2 for gluon)
 // should be called with q1 meant to be contracted with p2 in first part of vertex
 // (i.e. if g is backward, q1 is forward)
 {
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   jio (p1in,true,p1out,true,j1p);
   jio (p1in,false,p1out,false,j1m);
 
   joi (p2out,true,p2in,true,j2p);
   joi (p2out,false,p2in,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   // First, calculate the non-flipping amplitudes:
 
   COM amp,amm,apm,app;
   app=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   apm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
   amp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   amm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
 
   double MH2sum = abs2(app)+abs2(amm)+abs2(apm)+abs2(amp);
 
   const double K = K_g(p2out, p2in);
   MH2sum*=K/C_A;
 
   // Cf*Ca=4
   // return 4.*MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 double MH2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb)
 // g~p1 g~p2
 // should be called with q1 meant to be contracted with p2 in first part of vertex
 // (i.e. if g is backward, q1 is forward)
 {
   current j1p,j1m,j2p,j2m,q1v,q2v;
 
   joi (p1out,true,p1in,true,j1p);
   joi (p1out,false,p1in,false,j1m);
 
   joi (p2out,true,p2in,true,j2p);
   joi (p2out,false,p2in,false,j2m);
 
   to_current(q1, q1v);
   to_current(q2, q2v);
 
   // First, calculate the non-flipping amplitudes:
 
   COM amp,amm,apm,app;
   app=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb);
   apm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb);
   amp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb);
   amm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb);
 
   double MH2sum = abs2(app)+abs2(amm)+abs2(apm)+abs2(amp);
 
   const double K_g1 = K_g(p1out, p1in);
   const double K_g2 = K_g(p2out, p2in);
 
   MH2sum*=K_g1/C_A*K_g2/C_A;
 
   // Ca*Ca=9
   // return 9.*MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
   return MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2());
 }
 
 // // Z's stuff
 // void jZ(HLV pin, HLV pout, HLV pem, HLV pep, bool HelPartons, bool HelLeptons, current cur) {
 
 //  // Init current to zero
 //  cur[0] = 0.0;
 //  cur[1] = 0.0;
 //  cur[2] = 0.0;
 //  cur[3] = 0.0;
 
 //  // Temporary variables
 //  COM temp;
 //  current Term_1, Term_2, Term_3, Term_4, J_temp, TempCur1, TempCur2;
 
 //  // Momentum of virtual gluons aroun weak boson emission site
 //  HLV qa = pout + pep + pem;
 //  HLV qb = pin  - pep - pem;
 
 //  double ta = qa.m2();
 //  double tb = qb.m2();
 
 //  // Out-Out currents:
 //  current Em_Ep, Out_Em, Out_Ep;
 
 //  // Other currents:
 //  current Out_In, Em_In, Ep_In;
 
 //  joi(pout, HelPartons, pin, HelPartons, Out_In);
 //  joi(pem,  HelLeptons, pin, HelPartons, Em_In);
 //  joi(pep,  HelLeptons, pin, HelPartons, Ep_In);
 
 //  joo(pem,  HelLeptons, pep, HelLeptons, Em_Ep);
 //  joo(pout, HelPartons, pem, HelLeptons, Out_Em);
 //  joo(pout, HelPartons, pep, HelLeptons, Out_Ep);
 
 //  if (HelLeptons == HelPartons) {
 
 //    temp = 2.0 * cdot(pout, Em_Ep);
 //    cmult(temp / ta, Out_In, Term_1);
 
 //    temp = cdot(Out_Em, Em_Ep);
 //    cmult(temp / ta , Em_In, Term_2);
 
 //    temp = 2.0 * cdot(pin, Em_Ep);
 //    cmult(temp / tb, Out_In, Term_3);
 
 //    temp = -cdot(Ep_In, Em_Ep);
 //    cmult(temp / tb, Out_Ep, Term_4);
 
 //    cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //    cur[0] = J_temp[0];
 //    cur[1] = J_temp[1];
 //    cur[2] = J_temp[2];
 //    cur[3] = J_temp[3];
 //  }
 
 //  else {
 //    if (HelPartons == true) {
 //      temp = 2.0 * cdot(pout, Em_Ep);
 //      cmult(temp / ta, Out_In, Term_1);
 
 //      joo(pout, true, pep, true, TempCur1);
 //      joi(pep,  true, pin, true, TempCur2);
 
 //      temp = cdot(TempCur1, Em_Ep);
 //      cmult(temp / ta , TempCur2, Term_2);
 
 //      temp = 2.0 * cdot(pin, Em_Ep);
 //      cmult(temp / tb, Out_In, Term_3);
 
 //      joo(pout, true, pem, true, TempCur1);
 //      joi(pem,  true, pin, true, TempCur2);
 
 //      temp = -cdot(TempCur2, Em_Ep);
 //      cmult(temp / tb, TempCur1, Term_4);
 
 //      cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //      cur[0] = J_temp[0];
 //      cur[1] = J_temp[1];
 //      cur[2] = J_temp[2];
 //      cur[3] = J_temp[3];
 //    }
 
 //    else {
 //      temp = 2.0 * cdot(pout, Em_Ep);
 //      cmult(temp / ta, Out_In, Term_1);
 
 //      joo(pout, false, pep, false, TempCur1);
 //      joi(pep,  false, pin, false, TempCur2);
 
 //      temp = cdot(TempCur1, Em_Ep);
 //      cmult(temp / ta, TempCur2, Term_2);
 
 //      temp = 2.0 * cdot(pin, Em_Ep);
 //      cmult(temp / tb, Out_In, Term_3);
 
 //      joo(pout, false, pem, false, TempCur1);
 //      joi(pem,  false, pin, false, TempCur2);
 
 //      temp = -cdot(TempCur2, Em_Ep);
 //      cmult(temp / tb, TempCur1, Term_4);
 
 //      cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //      cur[0] = J_temp[0];
 //      cur[1] = J_temp[1];
 //      cur[2] = J_temp[2];
 //      cur[3] = J_temp[3];
 //    }
 
 //  }
 // }
 
 // void jZbar(HLV pin, HLV pout, HLV pem, HLV pep, bool HelPartons, bool HelLeptons, current cur) {
 
 //  // Init current to zero
 //  cur[0] = 0.0;
 //  cur[1] = 0.0;
 //  cur[2] = 0.0;
 //  cur[3] = 0.0;
 
 //  // Temporary variables
 //  COM temp;
 //  current Term_1, Term_2, Term_3, Term_4, J_temp, TempCur1, TempCur2;
 
 //  // Transfered 4-momenta
 //  HLV qa = pout + pep + pem;
 //  HLV qb = pin  - pep - pem;
 
 //  // The square of the transfered 4-momenta
 //  double ta = qa.m2();
 //  double tb = qb.m2();
 
 //  // Out-Out currents:
 //  current Em_Ep, Em_Out, Ep_Out;
 
 //  // In-Out currents:
 //  current In_Out, In_Em, In_Ep;
 
 //  // Safe to use the currents since helicity structure is ok
 //  if (HelPartons == HelLeptons) {
 //    jio(pin, HelPartons, pout, HelPartons, In_Out);
 //    joo(pem, HelLeptons, pep,  HelLeptons, Em_Ep);
 //    jio(pin, HelPartons, pem,  HelLeptons, In_Em);
 //    jio(pin, HelPartons, pep,  HelLeptons, In_Ep);
 //    joo(pem, HelLeptons, pout, HelPartons, Em_Out);
 //    joo(pep, HelLeptons, pout, HelPartons, Ep_Out);
 //  }
 
 //  else {
 //    jio(pin, HelPartons, pout, HelPartons, In_Out);
 //    joo(pem, HelLeptons, pep,  HelLeptons, Em_Ep);
 
 //    In_Em[0] = 0.0;
 //    In_Em[1] = 0.0;
 //    In_Em[2] = 0.0;
 //    In_Em[3] = 0.0;
 
 //    In_Ep[0] = 0.0;
 //    In_Ep[1] = 0.0;
 //    In_Ep[2] = 0.0;
 //    In_Ep[3] = 0.0;
 
 //    Em_Out[0] = 0.0;
 //    Em_Out[1] = 0.0;
 //    Em_Out[2] = 0.0;
 //    Em_Out[3] = 0.0;
 
 //    Ep_Out[0] = 0.0;
 //    Ep_Out[1] = 0.0;
 //    Ep_Out[2] = 0.0;
 //    Ep_Out[3] = 0.0;
 //  }
 
 //  if (HelLeptons == HelPartons) {
 
 //    temp = 2.0 * cdot(pout, Em_Ep);
 //    cmult(temp / ta, In_Out, Term_1);
 
 //    temp = cdot(Ep_Out, Em_Ep);
 //    cmult(temp / ta, In_Ep, Term_2);
 
 //    temp = 2.0 * cdot(pin, Em_Ep);
 //    cmult(temp / tb, In_Out, Term_3);
 
 //    temp = - cdot(In_Em, Em_Ep);
 //    cmult(temp / tb, Em_Out, Term_4);
 
 //    cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //    cur[0] = J_temp[0];
 //    cur[1] = J_temp[1];
 //    cur[2] = J_temp[2];
 //    cur[3] = J_temp[3];
 //  }
 
 //  else {
 //    if (HelPartons == true) {
 
 //      temp = 2.0 * cdot(pout, Em_Ep);
 //      cmult(temp / ta, In_Out, Term_1);
 
 //      joo(pem, true, pout, true, TempCur1);
 //      jio(pin, true, pem,  true, TempCur2);
 
 //      temp = cdot(TempCur1, Em_Ep);
 //      cmult(temp / ta , TempCur2, Term_2);
 
 //      temp = 2.0 * cdot(pin, Em_Ep);
 //      cmult(temp / tb, In_Out, Term_3);
 
 //      joo(pep, true, pout, true, TempCur1);
 //      jio(pin, true, pep,  true, TempCur2);
 
 //      temp = - cdot(TempCur2, Em_Ep);
 //      cmult(temp / tb, TempCur1, Term_4);
 
 //      cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //      cur[0] = J_temp[0];
 //      cur[1] = J_temp[1];
 //      cur[2] = J_temp[2];
 //      cur[3] = J_temp[3];
 //    }
 
 //    else {
 
 //      temp = 2.0 * cdot(pout, Em_Ep);
 //      cmult(temp / ta, In_Out, Term_1);
 
 //      joo(pem, false, pout, false, TempCur1);
 //      jio(pin, false, pem,  false, TempCur2);
 
 //      temp = cdot(TempCur1, Em_Ep);
 //      cmult(temp / ta , TempCur2, Term_2);
 
 //      temp = 2.0 * cdot(pin, Em_Ep);
 //      cmult(temp / tb, In_Out, Term_3);
 
 //      joo(pep, false, pout, false, TempCur1);
 //      jio(pin, false, pep,  false, TempCur2);
 
 //      temp = - cdot(TempCur2, Em_Ep);
 //      cmult(temp / tb, TempCur1, Term_4);
 
 //      cadd(Term_1, Term_2, Term_3, Term_4, J_temp);
 
 //      cur[0] = J_temp[0];
 //      cur[1] = J_temp[1];
 //      cur[2] = J_temp[2];
 //      cur[3] = J_temp[3];
 //    }
 //  }
 // }
 
 // // Progagators
 // COM PZ(double s) {
 
 //  double MZ, GammaZ;
 
 //  MZ       = 9.118800e+01;  // Mass of the mediating gauge boson
 //  GammaZ   = 2.441404e+00;  // Z peak width
 
 //  // Return Z Prop value
 //  return 1.0 / (s - MZ * MZ + COM(0.0, 1.0) * GammaZ * MZ);
 // }
 
 // COM PG(double s) {
 //  return 1.0 / s;
 // }
 
 // // Non-gluonic with pa emitting
 // std::vector <double> jMZqQ (HLV pa, HLV pb, HLV p1, HLV p2, HLV pep, HLV pem, std::vector <double> VProducts, std::vector < std::vector <double> > Virtuals, int aptype, int bptype, bool UseVirtuals, bool BottomLineEmit) {
 
 //  std::vector <double> ScaledWeights;
 
 //  double Sum;
 
 //  // Propagator factors
 //  COM PZs = PZ((pep + pem).m2());
 //  COM PGs = PG((pep + pem).m2());
 
 
 //  // Emitting current initialisation
 //  current j1pptop, j1pmtop; // Emission from top line
 //  current j1ppbot, j1pmbot; // Emission from bottom line
 
 //  // Non-emitting current initialisation
 //  current j2ptop, j2mtop;   // Emission from top line
 //  current j2pbot, j2mbot;   // Emission from bottom line
 
 //  // Currents for top emission
 //  // Upper current calculations
 //  // if a is a quark
 //  if (aptype > 0) {
 //    jZ(pa, p1, pem, pep, true,  true,  j1pptop);
 //    jZ(pa, p1, pem, pep, true,  false, j1pmtop);
 //  }
 //  // if a is an antiquark
 //  else {
 //    jZbar(pa, p1, pem, pep, true,  true,  j1pptop);
 //    jZbar(pa, p1, pem, pep, true,  false, j1pmtop);
 //  }
 
 //  // Lower current calculations
 //  // if b is a quark
 //  if (bptype > 0) {
 //    joi(p2, true,  pb, true,  j2ptop);
 //    joi(p2, false, pb, false, j2mtop);
 //  }
 //  // if b is an antiquark
 //  else {
 //    jio(pb, true,  p2, true,  j2ptop);
 //    jio(pb, false, p2, false, j2mtop);
 //  }
 
 //  // Currents for bottom emission
 //  // Lower current calculations
 //  if (bptype > 0) {
 //    jZ(pb, p2, pem, pep, true,  true,  j1ppbot);
 //    jZ(pb, p2, pem, pep, true,  false, j1pmbot);
 //  }
 //  else {
 //    jZbar(pb, p2, pem, pep, true,  true,  j1ppbot);
 //    jZbar(pb, p2, pem, pep, true,  false, j1pmbot);
 //  }
 
 //  // Upper current calculations
 //  if (aptype > 0) {
 //    joi(p1, true,  pa, true,  j2pbot);
 //    joi(p1, false, pa, false, j2mbot);
 //  }
 //  else {
 //    jio(pa, true,  p1, true,  j2pbot);
 //    jio(pa, false, p1, false, j2mbot);
 //  }
 
 //  COM Coeff[2][8];
 
 //  if (!Interference) {
 
 //    double ZCharge_a_P = Zq(aptype, true);
 //    double ZCharge_a_M = Zq(aptype, false);
 //    double ZCharge_b_P = Zq(bptype, true);
 //    double ZCharge_b_M = Zq(bptype, false);
 
 //    if (BottomLineEmit) {
 //      // Emission from top-line quark (pa/p1 line)
 //      Coeff[0][0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2ptop);
 //      Coeff[0][1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2mtop);
 //      Coeff[0][2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2ptop);
 //      Coeff[0][3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2mtop);
 //      Coeff[0][4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop));
 //      Coeff[0][5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop));
 //      Coeff[0][6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop));
 //      Coeff[0][7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop));
 //    }
 
 //    else {
 //      // Emission from bottom-line quark (pb/p2 line)
 //      Coeff[1][0] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1ppbot, j2pbot);
 //      Coeff[1][7] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1ppbot, j2mbot);
 //      Coeff[1][2] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1pmbot, j2pbot);
 //      Coeff[1][5] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1pmbot, j2mbot);
 //      Coeff[1][4] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2pbot));
 //      Coeff[1][3] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2mbot));
 //      Coeff[1][6] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2pbot));
 //      Coeff[1][1] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2mbot));
 //    }
 //  }
 
 //  // Else calculate all the possiblities
 //  else {
 
 //    double ZCharge_a_P = Zq(aptype, true);
 //    double ZCharge_a_M = Zq(aptype, false);
 //    double ZCharge_b_P = Zq(bptype, true);
 //    double ZCharge_b_M = Zq(bptype, false);
 
 //    // Emission from top-line quark (pa/p1 line)
 //    Coeff[0][0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2ptop);
 //    Coeff[0][1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2mtop);
 //    Coeff[0][2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2ptop);
 //    Coeff[0][3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2mtop);
 //    Coeff[0][4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop));
 //    Coeff[0][5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop));
 //    Coeff[0][6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop));
 //    Coeff[0][7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop));
 
 //    // Emission from bottom-line quark (pb/p2 line)
 //    Coeff[1][0] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1ppbot, j2pbot);
 //    Coeff[1][7] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1ppbot, j2mbot);
 //    Coeff[1][2] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1pmbot, j2pbot);
 //    Coeff[1][5] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) *      cdot(j1pmbot, j2mbot);
 //    Coeff[1][4] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2pbot));
 //    Coeff[1][3] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2mbot));
 //    Coeff[1][6] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2pbot));
 //    Coeff[1][1] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2mbot));
 //  }
 
 //  // Find the numbers of scales
 //  int ScaleCount;
 //  #if calcscaleunc
 //    ScaleCount = 20;
 //  #else
 //    ScaleCount = 1;
 //  #endif
 
 //  // For each scale...
 //  for (int j = 0; j < ScaleCount; j++) {
 
 //    Sum = 0.0;
 
 //    // If we want to compare back to the W's code only emit from one quark and only couple to left handed particles
 //    // virtuals arent here since they are calculated and included in weight() call.
 //    if (!Interference) {
 
 //      if (BottomLineEmit) for (int i = 0; i < 8; i++) Sum += abs2(Coeff[1][i]) * VProducts.at(1);
 //      else                for (int i = 0; i < 8; i++) Sum += abs2(Coeff[0][i]) * VProducts.at(0);
 //    }
 
 //    // Else work out the full interference
 //    else {
 
 //      // For the full calculation...
 //      if (UseVirtuals) {
 //        for (int i = 0; i < 8; i++) {
 //          Sum += abs2(Coeff[0][i])  * VProducts.at(0) * Virtuals.at(j).at(0)
 //               + abs2(Coeff[1][i])  * VProducts.at(1) * Virtuals.at(j).at(1)
 //                     + 2.0 * real(Coeff[0][i] * conj(Coeff[1][i])) * VProducts.at(2) * Virtuals.at(j).at(2);
 //        }
 //      }
 
 //      // For the tree level calculation...
 //      else {
 //        for (int i = 0; i < 8; i++) {
 //          Sum += abs2(Coeff[0][i])  * VProducts.at(0)
 //               + abs2(Coeff[1][i])  * VProducts.at(1)
 //        + 2.0 * real(Coeff[0][i] * conj(Coeff[1][i])) * VProducts.at(2);
 //        }
 //      }
 //    }
 
 //    // Add this to the vector to be returned with the other factors of C_A and the helicity sum/average factors.
 //    ScaledWeights.push_back(Sum / 18.0);
 //  }
 
 //  // Return all the scale values
 //  return ScaledWeights;
 // }
 
 // // Semi-gluonic with pa emitting
 // std::vector <double> jMZqg (HLV pa, HLV pb, HLV p1, HLV p2, HLV pep, HLV pem, std::vector <double> VProducts, std::vector < std::vector <double> > Virtuals, int aptype, int bptype, bool UseVirtuals, bool BottomLineEmit) {
 
 //  COM Coeff[8];
 
 //  double Sum;
 
 //  std::vector <double> ScaledWeights;
 
 //  COM PZs = PZ((pep + pem).m2());
 //  COM PGs = PG((pep + pem).m2());
 
 //  // Emitting current initialisation - Emission from top line
 //  current j1pptop, j1pmtop;
 
 //  // Non-emitting current initialisation - Emission from top line
 //  current j2ptop, j2mtop;
 
 //  // Currents for top emission
 //  // Upper current calculations
 //  if (aptype > 0) {
 //    jZ   (pa, p1, pem, pep, true,  true,  j1pptop);
 //    jZ   (pa, p1, pem, pep, true,  false, j1pmtop);
 //  }
 //  else {
 //    jZbar(pa, p1, pem, pep, true,  true,  j1pptop);
 //    jZbar(pa, p1, pem, pep, true,  false, j1pmtop);
 //  }
 
 //  // Lower current calculations
 //  joi(p2, true,  pb, true,  j2ptop);
 //  joi(p2, false, pb, false, j2mtop);
 
 //  // Calculate all the possiblities
 //  double ZCharge_a_P = Zq(aptype, true);
 //  double ZCharge_a_M = Zq(aptype, false);
 
 //  // Emission from top-line quark (pa/p1 line)
 //  Coeff[0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2ptop);
 //  Coeff[1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pptop, j2mtop);
 //  Coeff[2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2ptop);
 //  Coeff[3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) *      cdot(j1pmtop, j2mtop);
 //  Coeff[4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop));
 //  Coeff[5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop));
 //  Coeff[6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop));
 //  Coeff[7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop));
 
 //  // Calculate gluon colour accelerated factor
 //  double CAMFactor, z;
 
 //  // If b is a forward moving gluon define z (C.F. multiple jets papers)
 //  if (pb.pz() > 0) z = p2.plus()  / pb.plus();
 //  else             z = p2.minus() / pb.minus();
 
 //  CAMFactor = (1.0 - 1.0 / 9.0) / 2.0 * (z + 1.0 / z) + 1.0 / 9.0;
 
 //  // Find the numbers of scales
 //  int ScaleCount;
 //  #if calcscaleunc
 //    ScaleCount = 20;
 //  #else
 //    ScaleCount = 1;
 //  #endif
 
 //  // For each scale...
 //  for (int j = 0; j < ScaleCount; j++) {
 
 //    Sum = 0.0;
 
 //    // If we dont want the interference
 //    if (!Interference) for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0);
 
 //    // Else work out the full interference
 //    else {
 //      if (UseVirtuals) {
 //        for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0) * Virtuals.at(j).at(0);
 //      }
 //      else {
 //        for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0);
 //      }
 //    }
 
 //    // Add this to the vector to be returned with the other factors of C_A, the colour accelerated factor and the helicity sum/average factors.: (4/3)*3/32
 //    ScaledWeights.push_back(CAMFactor * Sum / 8.0);
 //  }
 
 //  return ScaledWeights;
 // }
 
 // // Electroweak Charge Functions
 // double Zq (int PID, bool Helcitiy) {
 
 //  double temp;
 
 //  // Positive Spin
 //  if (Helcitiy == true) {
 //    if (PID ==   1 || PID ==  3 || PID ==  5) temp = (+ 1.0 * stw2 / 3.0) / ctw;
 //    if (PID ==   2 || PID ==  4)              temp = (- 2.0 * stw2 / 3.0) / ctw;
 //    if (PID ==  -1 || PID == -3 || PID == -5) temp = (- 1.0 * stw2 / 3.0) / ctw;
 //    if (PID ==  -2 || PID == -4)              temp = (+ 2.0 * stw2 / 3.0) / ctw;
 
 //    // If electron or positron
 //    if (PID ==  7 || PID == -7) temp = Zep;
 //  }
 
 //  // Negative Spin
 //  else {
 //    if (PID ==  1 || PID ==  3 || PID ==  5) temp = (-0.5 + 1.0 * stw2 / 3.0) / ctw;
 //    if (PID ==  2 || PID ==  4)              temp = ( 0.5 - 2.0 * stw2 / 3.0) / ctw;
 //    if (PID == -1 || PID == -3 || PID == -5) temp = ( 0.5 - 1.0 * stw2 / 3.0) / ctw;
 //    if (PID == -2 || PID == -4)              temp = (-0.5 + 2.0 * stw2 / 3.0) / ctw;
 
 //    // If electron or positron
 //    if (PID ==  7 || PID == -7) temp = Zem;
 
 //  }
 
 //  return temp;
 // }
 
 // double Gq (int PID) {
 
 //  if (!VirtualPhoton) return 0.0;
 
 //  if (PID == -1) return  1.0 * ee / 3.0;
 //  if (PID == -2) return -2.0 * ee / 3.0;
 //  if (PID == -3) return  1.0 * ee / 3.0;
 //  if (PID == -4) return -2.0 * ee / 3.0;
 //  if (PID == -5) return  1.0 * ee / 3.0;
 //  if (PID ==  1) return -1.0 * ee / 3.0;
 //  if (PID ==  2) return  2.0 * ee / 3.0;
 //  if (PID ==  3) return -1.0 * ee / 3.0;
 //  if (PID ==  4) return  2.0 * ee / 3.0;
 //  if (PID ==  5) return -1.0 * ee / 3.0;
 
 //  std::cout << "ERROR! No Electroweak Charge Found at line " << __LINE__ << "..." << std::endl;
 //  return 0.0;
 // }
 
 
 namespace {
 
   //@{
   /// @brief Higgs vertex contracted with one current
 
   CCurrent jH (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin,
               bool helin, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2,
               double mt, bool incBot, double mb)
   {
 
       CCurrent j2 = joi(pout,helout,pin,helin);
       CCurrent jq2(q2.e(),q2.px(),q2.py(),q2.pz());
 
       if(mt == infinity)
         return ((q1.dot(q2))*j2 - j2.dot(q1)*jq2)/(3*M_PI*HEJ::vev);
       else
       {
         if(incBot)
           return (-16.*M_PI*mb*mb/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j2*A2(-q1,q2,mb))
                + (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt));
         else
           return (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt));
       }
   }
 
   CCurrent jioH (CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector pout,
                 bool helout, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2,
                 double mt, bool incBot, double mb)
   {
 
       CCurrent j2 = jio(pin,helin,pout,helout);
       CCurrent jq2(q2.e(),q2.px(),q2.py(),q2.pz());
 
       if(mt == infinity)
         return ((q1.dot(q2))*j2 - j2.dot(q1)*jq2)/(3*M_PI*HEJ::vev);
       else
       {
         if(incBot)
           return (-16.*M_PI*mb*mb/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j2*A2(-q1,q2,mb))
                + (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt));
         else
           return (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt));
       }
   }
 
   CCurrent jHtop (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin,
                   bool helin, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2,
                   double mt, bool incBot, double mb)
   {
 
       CCurrent j1 = joi(pout,helout,pin,helin);
       CCurrent jq1(q1.e(),q1.px(),q1.py(),q1.pz());
 
       if(mt == infinity)
         return ((q1.dot(q2))*j1 - j1.dot(q2)*jq1)/(3*M_PI*HEJ::vev);
       else
       {
         if(incBot)
           return (-16.*M_PI*mb*mb/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j1*A2(-q1,q2,mb))
                + (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt));
         else
           return (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt));
       }
   }
 
 
   CCurrent jioHtop (CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector pout,
                     bool helout, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2,
                     double mt, bool incBot, double mb)
   {
 
       CCurrent j1 = jio(pin,helin,pout,helout);
       CCurrent jq1(q1.e(),q1.px(),q1.py(),q1.pz());
 
       if(mt == infinity)
         return ((q1.dot(q2))*j1 - j1.dot(q2)*jq1)/(3*M_PI*HEJ::vev);
       else
       {
         if(incBot)
           return (-16.*M_PI*mb*mb/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j1*A2(-q1,q2,mb))
                + (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt));
         else
           return (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt));
       }
   }
   //@}
 } // namespace anonymous
 
 double jM2unogqHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=joi(p1out,true,p1in,true);
     mj1m=joi(p1out,false,p1in,false);
     mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     //  std::cout<< p1out.rapidity() << "  " << p2out.rapidity()<< "  " << qH1 << "  " << qH2 << "\n" <<MHmm << "  " << MHmp << "  "  << MHpm << "  " << MHpp << std::endl;
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(p1out,true,pg,true);
     j2gm=joo(p1out,false,pg,false);
     jgap=joi(pg,true,p1in,true);
     jgam=joi(pg,false,p1in,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=HEJ::C_F*HEJ::C_F/HEJ::C_A/HEJ::C_A;  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     return ampsq;
 }
 
 double jM2unogqbarHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=jio(p1in,true,p1out,true);
     mj1m=jio(p1in,false,p1out,false);
     mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(pg,true,p1out,true);
     j2gm=joo(pg,false,p1out,false);
     jgap=jio(p1in,true,pg,true);
     jgam=jio(p1in,false,pg,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     return ampsq;
 }
 
 double jM2unogqHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=joi(p1out,true,p1in,true);
     mj1m=joi(p1out,false,p1in,false);
     mjH2p=jioH(p2in,true,p2out,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jioH(p2in,false,p2out,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(p1out,true,pg,true);
     j2gm=joo(p1out,false,pg,false);
     jgap=joi(pg,true,p1in,true);
     jgam=joi(pg,false,p1in,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     return ampsq;
 }
 
 double jM2unogqbarHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=jio(p1in,true,p1out,true);
     mj1m=jio(p1in,false,p1out,false);
     mjH2p=jioH(p2in,true,p2out,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jioH(p2in,false,p2out,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(pg,true,p1out,true);
     j2gm=joo(pg,false,p1out,false);
     jgap=jio(p1in,true,pg,true);
     jgam=jio(p1in,false,pg,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     //Higgs coupling is included in Hjets.C
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
 
     return ampsq;
 }
 
 double jM2unogqHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=joi(p1out,true,p1in,true);
     mj1m=joi(p1out,false,p1in,false);
     mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(p1out,true,pg,true);
     j2gm=joo(p1out,false,pg,false);
     jgap=joi(pg,true,p1in,true);
     jgam=joi(pg,false,p1in,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4./9.*4./9.;  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     // here we need 2 to match with the normalization
     // gq is 9./4. times the qQ
     //Higgs coupling is included in Hjets.C
 
     const double K = K_g(p2out, p2in);
 
     return ampsq*K/C_A*9./4.; //ca/cf = 9/4
 }
 
 double jM2unogqbarHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     //  This construction is taking rapidity order: pg > p1out >> p2out
     //  std::cerr<<"This Uno Current: "<<p1out<<"  "<<p1in<<"  "<<p2out<<"  "<<p2in<<"  "<<pg<<std::endl;
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out);   // Bottom End
     CLHEP::HepLorentzVector qg=p1in-p1out-pg;  // Extra bit post-gluon
 
     CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p;
     mj1p=jio(p1in,true,p1out,true);
     mj1m=jio(p1in,false,p1out,false);
     mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb);
     mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb);
 
     // Dot products of these which occur again and again
     COM MHmp=mj1m.dot(mjH2p);  // And now for the Higgs ones
     COM MHmm=mj1m.dot(mjH2m);
     COM MHpp=mj1p.dot(mjH2p);
     COM MHpm=mj1p.dot(mjH2m);
 
     // Currents with pg
     CCurrent jgam,jgap,j2gm,j2gp;
     j2gp=joo(pg,true,p1out,true);
     j2gm=joo(pg,false,p1out,false);
     jgap=jio(p1in,true,pg,true);
     jgam=jio(p1in,false,pg,false);
 
     CCurrent qsum(q1+qg);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in);
     CCurrent p1o(p1out);
     CCurrent p1i(p1in);
 
     Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2();
     Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2();
     Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2();
     Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2();
 
     U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2();
     U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2();
     U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2();
     U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2();
     U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2();
     U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH1.m2()*qg.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4./9.*4./9.;  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     // here we need 2 to match with the normalization
     // gq is 9./4. times the qQ
     //Higgs coupling is included in Hjets.C
 
     const double K = K_g(p2out, p2in);
 
     return ampsq*K/C_F;
 }
 
 double jM2unobqHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     // std::cout << "####################\n";
     // std::cout << "# p1in : "<<p1in<< " "<<p1in.plus()<<" "<<p1in.minus()<<std::endl;
     // std::cout << "# p2in : "<<p2in<< " "<<p2in.plus()<<" "<<p2in.minus()<<std::endl;
     // std::cout << "# p1out : "<<p1out<< " "<<p1out.rapidity()<<std::endl;
     // std::cout << "# (qH1-qH2) : "<<(qH1-qH2)<< " "<<(qH1-qH2).rapidity()<<std::endl;
     // std::cout << "# pg : "<<pg<< " "<<pg.rapidity()<<std::endl;
     // std::cout << "# p2out : "<<p2out<< " "<<p2out.rapidity()<<std::endl;
     // std::cout << "####################\n";
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2, mt, incBot, mb);
     mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2, mt, incBot, mb);
     mj2p=joi(p2out,true,p2in,true);
     mj2m=joi(p2out,false,p2in,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(p2out,true,pg,true);
     j2gm=joo(p2out,false,pg,false);
     jgbp=joi(pg,true,p2in,true);
     jgbm=joi(pg,false,p2in,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m
         + (p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m
         +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p
         +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p
         +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     // 1/3. = 1/C_A ?
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     const double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=HEJ::C_F*HEJ::C_F/(HEJ::C_A*HEJ::C_A);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
 
     return ampsq;
 }
 
 
 
 double jM2unobqbarHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jioHtop(p1in,true,p1out,true,qH1,qH2, mt, incBot, mb);
     mjH1m=jioHtop(p1in,false,p1out,false,qH1,qH2, mt, incBot, mb);
     mj2p=joi(p2out,true,p2in,true);
     mj2m=joi(p2out,false,p2in,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(p2out,true,pg,true);
     j2gm=joo(p2out,false,pg,false);
     jgbp=joi(pg,true,p2in,true);
     jgbm=joi(pg,false,p2in,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     return ampsq;
 }
 
 
 
 double jM2unobqHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb);
     mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb);
     mj2p=jio(p2in,true,p2out,true);
     mj2m=jio(p2in,false,p2out,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(pg,true,p2out,true);
     j2gm=joo(pg,false,p2out,false);
     jgbp=jio(p2in,true,pg,true);
     jgbm=jio(p2in,false,pg,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     return ampsq;
 }
 
 
 
 double jM2unobqbarHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jioHtop(p1in,true,p1out,true,qH1,qH2,mt, incBot, mb);
     mjH1m=jioHtop(p1in,false,p1out,false,qH1,qH2,mt, incBot, mb);
     mj2p=jio(p2in,true,p2out,true);
     mj2m=jio(p2in,false,p2out,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(pg,true,p2out,true);
     j2gm=joo(pg,false,p2out,false);
     jgbp=jio(p2in,true,pg,true);
     jgbm=jio(p2in,false,pg,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4.*4./(9.*9.);  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
 
 
     return ampsq;
 }
 
 double jM2unobgHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
     // std::cout << "####################\n";
     // std::cout << "# p1in : "<<p1in<< " "<<p1in.plus()<<" "<<p1in.minus()<<std::endl;
     // std::cout << "# p2in : "<<p2in<< " "<<p2in.plus()<<" "<<p2in.minus()<<std::endl;
     // std::cout << "# p1out : "<<p1out<< " "<<p1out.rapidity()<<std::endl;
     // std::cout << "# (qH1-qH2) : "<<(qH1-qH2)<< " "<<(qH1-qH2).rapidity()<<std::endl;
     // std::cout << "# pg : "<<pg<< " "<<pg.rapidity()<<std::endl;
     // std::cout << "# p2out : "<<p2out<< " "<<p2out.rapidity()<<std::endl;
     // std::cout << "####################\n";
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb);
     mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb);
     mj2p=joi(p2out,true,p2in,true);
     mj2m=joi(p2out,false,p2in,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(p2out,true,pg,true);
     j2gm=joo(p2out,false,pg,false);
     jgbp=joi(pg,true,p2in,true);
     jgbm=joi(pg,false,p2in,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4./9.*4./9.;  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     // need twice to match the normalization
     //Higgs coupling is included in Hjets.C
 
     const double K = K_g(p1out, p1in);
 
     return ampsq*K/C_F;
 }
 
 
 
 double jM2unobgHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb)
 {
 
     CLHEP::HepLorentzVector q1=p1in-p1out;  // Top End
     CLHEP::HepLorentzVector q2=-(p2in-p2out-pg);  // Extra bit pre-gluon
     CLHEP::HepLorentzVector q3=-(p2in-p2out);   // Bottom End
 
     //  std::cerr<<"Current:  "<<q1.m2()<<"  "<<q2.m2()<<std::endl;
     CCurrent mjH1m,mjH1p,mj2m,mj2p;
     mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb);
     mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb);
     mj2p=jio(p2in,true,p2out,true);
     mj2m=jio(p2in,false,p2out,false);
 
     // Dot products of these which occur again and again
     COM MHmp=mjH1m.dot(mj2p);  // And now for the Higgs ones
     COM MHmm=mjH1m.dot(mj2m);
     COM MHpp=mjH1p.dot(mj2p);
     COM MHpm=mjH1p.dot(mj2m);
 
 
     // Currents with pg
     CCurrent jgbm,jgbp,j2gm,j2gp;
     j2gp=joo(pg,true,p2out,true);
     j2gm=joo(pg,false,p2out,false);
     jgbp=jio(p2in,true,pg,true);
     jgbm=jio(p2in,false,pg,false);
 
     CCurrent qsum(q2+q3);
 
     CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in);
     CCurrent p2o(p2out);
     CCurrent p2i(p2in);
 
     CCurrent pplus((p1in+p1out)/2.);
     CCurrent pminus((p2in+p2out)/2.);
 
     // COM test=pminus.dot(p1in);
 
 
     Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2();
     Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2();
     Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2();
     Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2();
     U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2();
     U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2();
     U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2();
     U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2();
     U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2();
     U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2();
     U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2();
     U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2();
 
     const double cf=HEJ::C_F;
     double amm,amp,apm,app;
 
     amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm);
     amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp);
     apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm);
     app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp);
     double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2());
 
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
   // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999)
   //   std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << "  " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl;
 
     // Now add the t-channels for the Higgs
     double th=qH2.m2()*q2.m2();
     ampsq/=th;
     ampsq/=16.;
     ampsq*=4./9.*4./9.;  // Factor of (Cf/Ca) for each quark to match MH2qQ.
     //Higgs coupling is included in Hjets.C
 
     const double K = K_g(p1out, p1in);
 
     return ampsq*K/C_F; //ca/cf = 9/4
 
 }
 
 // Begin finite mass stuff
 #ifdef HEJ_BUILD_WITH_QCDLOOP
 namespace {
 
 
   // All the stuff needed for the box functions in qg->qgH now...
 
   //COM E1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM E1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2=-(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor*(-s12*D0DD(k2, k1, q2, mq)*(1 - 8.*mq*mq/s12 + S2/(2.*s12) +
           S2*(s12 - 8.*mq*mq)*(s34 + S1)/(2.*s12*Delta) +
           2.*(s34 + S1)*(s34 + S1)/Delta +
           S2*pow((s34 + S1),3)/Delta/Delta) - ((s12 + S2)*C0DD(k2,
             k1 + q2, mq) -
           s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) -
           S1*C0DD(k1, q2,
             mq))*(S2*(s12 - 4.*mq*mq)/(2.*s12*Delta) +
           2.*(s34 + S1)/Delta +
           S2*pow((s34 + S1),2)/Delta/Delta) + (C0DD(k1, q2, mq) -
           C0DD(k1 + k2, q2, mq))*(1. - 4.*mq*mq/s12) -
        C0DD(k1 + k2, q2, mq)*2.*s34/
          S1 - (B0DD(k1 + q2, mq) -
           B0DD(k1 + k2 + q2, mq))*2.*s34*(s34 +
            S1)/(S1*Delta) + (B0DD(q2, mq) -
           B0DD(k1 + k2 + q2, mq) +
           s12*C0DD(k1 + k2, q2,
             mq))*(2.*s34*(s34 +
              S1)*(S1 - S2)/(Delta*Sigma) +
           2.*s34*(s34 + S1)/(S1*Delta)) + (B0DD(k1 + k2, mq) -
           B0DD(k1 + k2 + q2,
            mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*2.*(s34 +
           S1)*(2.*s12*s34 -
            S2*(S1 + S2))/(Delta*Sigma));
   }
   //COM F1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM F1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor*(-S2*D0DD(k1, k2, q2,
          mq)*(0.5 - (s12 - 8.*mq*mq)*(s34 + S2)/(2.*Delta) -
           s12*pow((s34 + S2),3)/Delta/Delta) + ((s12 + S1)*C0DD(k1,
             k2 + q2, mq) -
           s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) -
           S2*C0DD(k2, q2,
             mq))*(S2*(s12 - 4.*mq*mq)/(2.*s12*Delta) +
           S2*pow((s34 + S2),2)/Delta/Delta) - (C0DD(k1 + k2, q2, mq) - C0DD(k1, k2 + q2, mq))*(1. - 4.*mq*mq/s12) -
        C0DD(k1, k2 + q2, mq) + (B0DD(k2 + q2, mq) -
           B0DD(k1 + k2 + q2,
            mq))*2.*pow((s34 + S2),2)/((s12 + S1)*Delta) - (B0DD(
            q2, mq) - B0DD(k1 + k2 + q2, mq) +
           s12*C0DD(k1 + k2, q2, mq))*2.*s34*(s34 +
           S2)*(S2 - S1)/(Delta*Sigma) + (B0DD(
            k1 + k2, mq) -
           B0DD(k1 + k2 + q2,
            mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*2.*(s34 +
           S2)*(2.*s12*s34 -
            S2*(S1 + S2))/(Delta*Sigma));
   }
   //COM G1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM G1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
 
     return looprwfactor*(S2*D0DD(k1, q2, k2,
          mq)*(Delta/s12/s12 - 4.*mq*mq/s12) -
        S2*((s12 + S1)*C0DD(k1, k2 + q2, mq) -
           S1*C0DD(k1, q2, mq))*(1./
            s12/s12 - (s12 - 4.*mq*mq)/(2.*s12*Delta)) -
        S2*((s12 + S2)*C0DD(k1 + q2, k2, mq) -
           S2*C0DD(k2, q2, mq))*(1./
            s12/s12 + (s12 - 4.*mq*mq)/(2.*s12*Delta)) -
        C0DD(k1, q2, mq) - (C0DD(k1, k2 + q2, mq) -
           C0DD(k1, q2, mq))*4.*mq*mq/
          s12 + (B0DD(k1 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2./
          s12 + (B0DD(k1 + q2, mq) -
           B0DD(q2, mq))*2.*s34/(s12*S1) + (B0DD(k2 + q2, mq) -
           B0DD(k1 + k2 + q2, mq))*2.*(s34 + S2)/(s12*(s12 + S1)));
   }
   //COM E4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM E4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor* (-s12*D0DD(k2, k1, q2,
          mq)*(0.5 - (S1 - 8.*mq*mq)*(s34 + S1)/(2.*Delta) -
           s12*pow((s34 + S1),3)/Delta/Delta) + ((s12 + S2)*C0DD(k2,
             k1 + q2, mq) -
           s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) -
           S1*C0DD(k1, q2, mq))*((S1 - 4.*mq*mq)/(2.*Delta) +
            s12*pow((s34 + S1),2)/Delta/Delta) -
        C0DD(k1 + k2, q2, mq) + (B0DD(k1 + q2, mq) -
           B0DD(k1 + k2 + q2, mq))*(2.*s34/Delta +
           2.*s12*(s34 + S1)/((s12 + S2)*Delta)) - (B0DD(
            q2, mq) - B0DD(k1 + k2 + q2, mq) +
           s12*C0DD(k1 + k2, q2,
             mq))*((2.*s34*(2.*s12*s34 - S2*(S1 + S2) +
               s12*(S1 -
                  S2)))/(Delta*Sigma)) + (B0DD(k1 + k2, mq) -
           B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*((2.*s12*(2.*s12*s34 - S1*(S1 + S2) +
               s34*(S2 - S1)))/(Delta*Sigma)));
   }
   //COM F4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM F4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor* (-s12*D0DD(k1, k2, q2,
          mq)*(0.5 + (S1 - 8.*mq*mq)*(s34 + S2)/(2.*Delta) +
           s12*pow((s34 + S2),3)/Delta/Delta) - ((s12 + S1)*C0DD(k1,
             k2 + q2, mq) -
           s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) -
           S2*C0DD(k2, q2, mq))*((S1 - 4.*mq*mq)/(2.*Delta) +
            s12*pow((s34 + S2),2)/Delta/Delta) -
        C0DD(k1 + k2, q2, mq) - (B0DD(k2 + q2, mq) -
           B0DD(k1 + k2 + q2, mq))*2.*(s34 +
            S2)/Delta + (B0DD(q2, mq) -
           B0DD(k1 + k2 + q2, mq) +
           s12*C0DD(k1 + k2, q2, mq))*2.*s34*(2.*s12*s34 -
            S1*(S1 + S2) +
            s12*(S2 - S1))/(Delta*Sigma) - (B0DD(k1 + k2, mq) -
           B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*(2.*s12*(2.*s12*s34 - S2*(S1 + S2) +
              s34*(S1 - S2))/(Delta*Sigma)));
   }
   //COM G4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM G4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
 
     return looprwfactor* (-D0DD(k1, q2, k2,
           mq)*(Delta/s12 + (s12 + S1)/2. -
           4.*mq*mq) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) -
           S1*C0DD(k1, q2, mq))*(1./
            s12 - (S1 - 4.*mq*mq)/(2.*Delta)) + ((s12 + S2)*C0DD(
             k1 + q2, k2, mq) -
           S2*C0DD(k2, q2, mq))*(1./
            s12 + (S1 - 4.*mq*mq)/(2.*Delta)) + (B0DD(
            k1 + k2 + q2, mq) -
           B0DD(k1 + q2, mq))*2./(s12 + S2));
   }
   //COM E10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM E10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor*(-s12*D0DD(k2, k1, q2, mq)*((s34 + S1)/Delta +
            12.*mq*mq*S1*(s34 + S1)/Delta/Delta -
            4.*s12*S1*pow((s34 + S1),3)/Delta/Delta/Delta) - ((s12 + S2)*C0DD(k2, k1 + q2, mq) -
            s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) -
             S1*C0DD(k1, q2, mq))*(1./Delta +
            4.*mq*mq*S1/Delta/Delta -
            4.*s12*S1*pow((s34 + S1),2)/Delta/Delta/Delta) +
         C0DD(k1 + k2, q2, mq)*(4.*s12*s34*(S1 - S2)/(Delta*Sigma) -
            4.*(s12 -
               2.*mq*mq)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma)) + (B0DD(k1 + q2, mq) -
            B0DD(k1 + k2 + q2, mq))*(4.*(s34 + S1)/((s12 + S2)*Delta) +
            8.*S1*(s34 + S1)/Delta/Delta) + (B0DD(q2, mq) -
            B0DD(k1 + k2 + q2, mq) +
            s12*C0DD(k1 + k2, q2, mq))*(12.*s34*(2.*s12 + S1 +
               S2)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma*Sigma) -
            4.*s34*(4.*s12 + 3.*S1 +
                S2)/(Delta*Sigma) +
            8.*s12*s34*(s34*(s12 + S2) -
                S1*(s34 +
                   S1))/(Delta*Delta*Sigma)) + (B0DD(k1 + k2, mq) -
            B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2,
              mq))*(12.*s12*(2.*s34 + S1 +
               S2)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma*Sigma) +
            8.*s12*S1*(s34*(s12 + S2) -
                S1*(s34 +
                   S1))/(Delta*Delta*Sigma))) + (COM(0.,1.)/(4.*M_PI*M_PI))*((2.*s12*s34 -
           S1*(S1 + S2))/(Delta*Sigma));
   }
 
   //COM F10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM F10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, Sigma, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
     Sigma = 4.*s12*s34 - pow(S1+S2,2);
 
     return looprwfactor* (s12*D0DD(k1, k2, q2,
           mq)*((s34 + S2)/Delta - 4.*mq*mq/Delta +
            12.*mq*mq*s34*(s12 + S1)/Delta/Delta -
            4.*s12*pow((s34 + S2),2)/Delta/Delta -
            4.*s12*S1*pow((s34 + S2),3)/Delta/Delta/Delta) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) -
            s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) -
             S2*C0DD(k2, q2, mq))*(1./Delta +
            4.*mq*mq*S1/Delta/Delta -
            4.*s12*(s34 + S2)/Delta/Delta -
            4.*s12*S1*pow((s34 + S2),2)/Delta/Delta/Delta) -
         C0DD(k1 + k2, q2, mq)*(4.*s12*s34/(S2*Delta) +
            4.*s12*s34*(S2 - S1)/(Delta*Sigma) +
            4.*(s12 -
               2.*mq*mq)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma)) - (B0DD(
             k2 + q2, mq) -
            B0DD(k1 + k2 + q2, mq))*(4.*s34/(S2*Delta) +
            8.*s34*(s12 + S1)/Delta/Delta) - (B0DD(q2, mq) -
            B0DD(k1 + k2 + q2, mq) +
            s12*C0DD(k1 + k2, q2,
              mq))*(-12*s34*(2*s12 + S1 +
               S2)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma*Sigma) -
            4.*s12*s34*s34/(S2*Delta*Delta) +
            4.*s34*S1/(Delta*Sigma) -
            4.*s34*(s12*s34*(2.*s12 + S2) -
                S1*S1*(2.*s12 +
                   S1))/(Delta*Delta*Sigma)) - (B0DD(k1 + k2, mq) -
            B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*(-12.*s12*(2.*s34 + S1 +
               S2)*(2.*s12*s34 -
                S1*(S1 + S2))/(Delta*Sigma*Sigma) +
            8.*s12*(2.*s34 + S1)/(Delta*Sigma) -
            8.*s12*s34*(2.*s12*s34 - S1*(S1 + S2) +
                s12*(S2 -
                   S1))/(Delta*Delta*Sigma))) + (COM(0.,1.)/(4.*M_PI*M_PI))*((2.*s12*s34 -
           S1*(S1 + S2))/(Delta*Sigma));
 
   }
 
   //COM G10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM G10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //CLHEP::HepLorentzVector q2=k3+k4;
     CLHEP::HepLorentzVector q2 = -(k1+k2+kh);
     double Delta, S1, S2, s12, s34;
     S1 = 2.*k1.dot(q2);
     S2 = 2.*k2.dot(q2);
     s12 = 2.*k1.dot(k2);
     //s34 = 2.*k3.dot(k4);
     s34 = q2.m2();
     Delta = s12*s34 - S1*S2;
 
     return looprwfactor* (-D0DD(k1, q2, k2, mq)*(1. +
           4.*S1*mq*mq/Delta) + ((s12 + S1)*C0DD(k1,
             k2 + q2, mq) -
           S1*C0DD(k1, q2, mq))*(1./Delta +
           4.*S1*mq*mq/Delta/Delta) - ((s12 + S2)*C0DD(k1 + q2,
             k2, mq) - S2*C0DD(k2, q2, mq))*(1./Delta +
           4.*S1*mq*mq/Delta/Delta) + (B0DD(k1 + k2 + q2, mq) -
           B0DD(k1 + q2, mq))*4.*(s34 +
            S1)/(Delta*(s12 + S2)) + (B0DD(q2, mq) -
           B0DD(k2 + q2, mq))*4.*s34/(Delta*S2));
   }
 
   //COM H1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return E1(k1,k2,k3,k4,mq)+F1(k1,k2,k3,k4,mq)+G1(k1,k2,k3,k4,mq);
     return E1(k1,k2,kh,mq)+F1(k1,k2,kh,mq)+G1(k1,k2,kh,mq);
   }
   //COM H4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return E4(k1,k2,k3,k4,mq)+F4(k1,k2,k3,k4,mq)+G4(k1,k2,k3,k4,mq);
     return E4(k1,k2,kh,mq)+F4(k1,k2,kh,mq)+G4(k1,k2,kh,mq);
   }
   //COM H10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return E10(k1,k2,k3,k4,mq)+F10(k1,k2,k3,k4,mq)+G10(k1,k2,k3,k4,mq);
     return E10(k1,k2,kh,mq)+F10(k1,k2,kh,mq)+G10(k1,k2,kh,mq);
   }
   //COM H2(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H2(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return -1.*H1(k2,k1,k3,k4,mq);
     return -1.*H1(k2,k1,kh,mq);
   }
   //COM H5(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H5(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return -1.*H4(k2,k1,k3,k4,mq);
     return -1.*H4(k2,k1,kh,mq);
   }
   //COM H12(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq)
   COM H12(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq)
   {
     //return -1.*H10(k2,k1,k3,k4,mq);
     return -1.*H10(k2,k1,kh,mq);
   }
 
   // FL and FT functions
   COM FL(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq)
   {
     CLHEP::HepLorentzVector Q = q1 + q2;
     double detQ2 = q1.m2()*q2.m2() - q1.dot(q2)*q1.dot(q2);
     return -1./(2.*detQ2)*((2.-
            3.*q1.m2()*q2.dot(Q)/detQ2)*(B0DD(q1, mq) -
            B0DD(Q, mq)) + (2. -
            3.*q2.m2()*q1.dot(Q)/detQ2)*(B0DD(q2, mq) -
            B0DD(Q, mq)) - (4.*mq*mq + q1.m2() + q2.m2() +
            Q.m2() - 3.*q1.m2()*q2.m2()*Q.m2()/detQ2)*C0DD(
           q1, q2, mq) - 2.);
   }
   COM FT(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq)
   {
     CLHEP::HepLorentzVector Q = q1 + q2;
     double detQ2 = q1.m2()*q2.m2() - q1.dot(q2)*q1.dot(q2);
     return -1./(2.*detQ2)*(Q.m2()*(B0DD(q1, mq) + B0DD(q2, mq) - 2.*B0DD(Q, mq) -
             2.*q1.dot(q2)*C0DD(q1, q2, mq)) + (q1.m2() -
             q2.m2()) *(B0DD(q1, mq) - B0DD(q2, mq))) -
       q1.dot(q2)*FL(q1, q2, mq);
   }
 
   CLHEP::HepLorentzVector ParityFlip(CLHEP::HepLorentzVector p)
   {
     CLHEP::HepLorentzVector flippedVector;
     flippedVector.setE(p.e());
     flippedVector.setX(-p.x());
     flippedVector.setY(-p.y());
     flippedVector.setZ(-p.z());
     return flippedVector;
   }
   /// @brief HC amp for qg->qgH with finite top (i.e. j^{++}_H)
   void g_gH_HC(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1,
     CLHEP::HepLorentzVector pH, double mq, current &retAns)
   {
     current cura1,pacur,p1cur,pHcur,conjeps1,conjepsH1,epsa,epsHa,epsHapart1,
       epsHapart2,conjepsH1part1,conjepsH1part2;
     COM ang1a,sqa1;
 
     const double F = 4.*mq*mq/HEJ::vev;
     // Easier to have the whole thing as current object so I can use cdot functionality.
     // Means I need to write pa,p1 as current objects
     to_current(pa, pacur);
     to_current(p1,p1cur);
     to_current(pH,pHcur);
     bool gluonforward = true;
     if(pa.z() < 0)
       gluonforward = false;
     //HEJ gauge
     jio(pa,false,p1,false,cura1);
 
     if(gluonforward){
       // sqrt(2pa_-/p1_-)*p1_perp/abs(p1_perp)
       ang1a = sqrt(pa.plus()*p1.minus())*(p1.x()+COM(0.,1.)*p1.y())/p1.perp();
       // sqrt(2pa_-/p1_-)*p1_perp*/abs(p1_perp)
       sqa1 = sqrt(pa.plus()*p1.minus())*(p1.x()-COM(0.,1.)*p1.y())/p1.perp();
     } else {
       ang1a = sqrt(pa.minus()*p1.plus());
       sqa1 = sqrt(pa.minus()*p1.plus());
     }
 
 
     const double prop = (pa-p1-pH).m2();
 
     cmult(-1./sqrt(2)/ang1a,cura1,conjeps1);
     cmult(1./sqrt(2)/sqa1,cura1,epsa);
 
     const COM Fta = FT(-pa,pa-pH,mq)/(pa-pH).m2();
     const COM Ft1 = FT(-p1-pH,p1,mq)/(p1+pH).m2();
 
     const COM h4 = H4(p1,-pa,pH,mq);
     const COM h5 = H5(p1,-pa,pH,mq);
     const COM h10 = H10(p1,-pa,pH,mq);
     const COM h12 = H12(p1,-pa,pH,mq);
 
 
     cmult(Fta*pa.dot(pH), epsa, epsHapart1);
     cmult(-1.*Fta*cdot(pHcur,epsa), pacur, epsHapart2);
     cmult(Ft1*cdot(pHcur,conjeps1), p1cur, conjepsH1part1);
     cmult(-Ft1*p1.dot(pH), conjeps1, conjepsH1part2);
     cadd(epsHapart1, epsHapart2, epsHa);
     cadd(conjepsH1part1, conjepsH1part2, conjepsH1);
     const COM aH1 = cdot(pHcur, cura1);
 
     current T1,T2,T3,T4,T5,T6,T7,T8,T9,T10;
 
     if(gluonforward){
       cmult(sqrt(2.)*sqrt(p1.plus()/pa.plus())*prop/sqa1, conjepsH1, T1);
       cmult(-sqrt(2.)*sqrt(pa.plus()/p1.plus())*prop/ang1a, epsHa, T2);
     }
     else{
       cmult(-sqrt(2.)*sqrt(p1.minus()/pa.minus())
           *((p1.x()-COM(0.,1.)*p1.y())/p1.perp())*prop/sqa1, conjepsH1, T1);
       cmult(sqrt(2.)*sqrt(pa.minus()/p1.minus())
           *((p1.x()-COM(0.,1.)*p1.y())/p1.perp())*prop/ang1a, epsHa, T2);
     }
 
     cmult(sqrt(2.)/ang1a*aH1, epsHa, T3);
     cmult(sqrt(2.)/sqa1*aH1, conjepsH1, T4);
 
     cmult(-sqrt(2.)*Fta*pa.dot(p1)*aH1/sqa1, conjeps1, T5);
     cmult(-sqrt(2.)*Ft1*pa.dot(p1)*aH1/ang1a, epsa, T6);
 
     cmult(-aH1/sqrt(2.)/sqa1*h4*8.*COM(0.,1.)*M_PI*M_PI, conjeps1, T7);
     cmult(aH1/sqrt(2.)/ang1a*h5*8.*COM(0.,1.)*M_PI*M_PI, epsa, T8);
     cmult(aH1*aH1/2./ang1a/sqa1*h10*8.*COM(0.,1.)*M_PI*M_PI, pacur, T9);
     cmult(-aH1*aH1/2./ang1a/sqa1*h12*8.*COM(0.,1.)*M_PI*M_PI, p1cur, T10);
 
     current ans;
     for(int i=0;i<4;i++)
     {
         ans[i] = T1[i]+T2[i]+T3[i]+T4[i]+T5[i]+T6[i]+T7[i]+T8[i]+T9[i]+T10[i];
     }
 
     retAns[0] = F/prop*ans[0];
     retAns[1] = F/prop*ans[1];
     retAns[2] = F/prop*ans[2];
     retAns[3] = F/prop*ans[3];
   }
 
   /// @brief HNC amp for qg->qgH with finite top (i.e. j^{+-}_H)
   void g_gH_HNC(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH, double mq, current &retAns)
   {
     const double F = 4.*mq*mq/HEJ::vev;
     COM ang1a,sqa1;
     current conjepsH1,epsHa,p1cur,pacur,pHcur,conjeps1,epsa,paplusp1cur,
       p1minuspacur,cur1a,cura1,epsHapart1,epsHapart2,conjepsH1part1,
       conjepsH1part2;
     // Find here if pa, meaning the gluon, is forward or backward
     bool gluonforward = true;
     if(pa.z() < 0)
       gluonforward = false;
 
     jio(pa,true,p1,true,cura1);
     joi(p1,true,pa,true,cur1a);
 
     to_current(pa,pacur);
     to_current(p1,p1cur);
     to_current(pH,pHcur);
     to_current(pa+p1,paplusp1cur);
     to_current(p1-pa,p1minuspacur);
     const COM aH1 = cdot(pHcur,cura1);
     const COM oneHa = std::conj(aH1); // = cdot(pHcur,cur1a)
 
     if(gluonforward){
       // sqrt(2pa_-/p1_-)*p1_perp/abs(p1_perp)
       ang1a = sqrt(pa.plus()*p1.minus())*(p1.x()+COM(0.,1.)*p1.y())/p1.perp();
       // sqrt(2pa_-/p1_-)*p1_perp*/abs(p1_perp)
       sqa1 = sqrt(pa.plus()*p1.minus())*(p1.x()-COM(0.,1.)*p1.y())/p1.perp();
       }
     else {
       ang1a = sqrt(pa.minus()*p1.plus());
       sqa1 = sqrt(pa.minus()*p1.plus());
     }
 
     const double prop = (pa-p1-pH).m2();
 
     cmult(1./sqrt(2)/sqa1, cur1a, epsa);
     cmult(-1./sqrt(2)/sqa1, cura1, conjeps1);
     const COM phase = cdot(conjeps1, epsa);
     const COM Fta = FT(-pa,pa-pH,mq)/(pa-pH).m2();
     const COM Ft1 = FT(-p1-pH,p1,mq)/(p1+pH).m2();
     const COM Falpha = FT(p1-pa,pa-p1-pH,mq);
     const COM Fbeta = FL(p1-pa,pa-p1-pH,mq);
 
     const COM h1 = H1(p1,-pa, pH, mq);
     const COM h2 = H2(p1,-pa, pH, mq);
     const COM h4 = H4(p1,-pa, pH, mq);
     const COM h5 = H5(p1,-pa, pH, mq);
     const COM h10 = H10(p1,-pa, pH, mq);
     const COM h12 = H12(p1,-pa, pH, mq);
 
     cmult(Fta*pa.dot(pH), epsa, epsHapart1);
     cmult(-1.*Fta*cdot(pHcur,epsa), pacur, epsHapart2);
     cmult(Ft1*cdot(pHcur,conjeps1), p1cur, conjepsH1part1);
     cmult(-Ft1*p1.dot(pH), conjeps1, conjepsH1part2);
     cadd(epsHapart1, epsHapart2, epsHa);
     cadd(conjepsH1part1, conjepsH1part2, conjepsH1);
 
     current T1,T2,T3,T4,T5a,T5b,T6,T7,T8a,T8b,T9,T10,T11a,
       T11b,T12a,T12b,T13;
 
     if(gluonforward){
       cmult(sqrt(2.)*sqrt(p1.plus()/pa.plus())*prop/sqa1, conjepsH1, T1);
       cmult(-sqrt(2.)*sqrt(pa.plus()/p1.plus())*prop/sqa1, epsHa, T2);
     }
     else{
       cmult(-sqrt(2.)*sqrt(p1.minus()/pa.minus())*((p1.x()-COM(0.,1.)*p1.y())/p1.perp())
           *prop/sqa1, conjepsH1, T1);
       cmult(sqrt(2.)*sqrt(pa.minus()/p1.minus())*((p1.x()+COM(0.,1.)*p1.y())/p1.perp())
           *prop/sqa1, epsHa, T2);
     }
 
     const COM boxdiagFact = 8.*COM(0.,1.)*M_PI*M_PI;
 
     cmult(aH1*sqrt(2.)/sqa1, epsHa, T3);
     cmult(oneHa*sqrt(2.)/sqa1, conjepsH1, T4);
     cmult(-2.*phase*Fta*pa.dot(pH), p1cur, T5a);
     cmult(2.*phase*Ft1*p1.dot(pH), pacur, T5b);
     cmult(-sqrt(2.)*Fta*p1.dot(pa)*oneHa/sqa1, conjeps1, T6);
     cmult(-sqrt(2.)*Ft1*pa.dot(p1)*aH1/sqa1, epsa, T7);
 
     cmult(-boxdiagFact*phase*h2, pacur, T8a);
     cmult(boxdiagFact*phase*h1, p1cur, T8b);
     cmult(boxdiagFact*aH1/sqrt(2.)/sqa1*h5, epsa, T9);
     cmult(-boxdiagFact*oneHa/sqrt(2.)/sqa1*h4, conjeps1, T10);
     cmult(boxdiagFact*aH1*oneHa/2./sqa1/sqa1*h10, pacur, T11a);
     cmult(-boxdiagFact*aH1*oneHa/2./sqa1/sqa1*h12, p1cur, T11b);
 
     cmult(-phase/(pa-p1).m2()*Falpha*(p1-pa).dot(pa-p1-pH), paplusp1cur, T12a);
     cmult(phase/(pa-p1).m2()*Falpha*(pa+p1).dot(pa-p1-pH), p1minuspacur, T12b);
     cmult(-phase*Fbeta*(pa-p1-pH).m2(), paplusp1cur, T13);
 
     current ans;
     for(int i=0;i<4;i++)
     {
       ans[i] = T1[i]+T2[i]+T3[i]+T4[i]+T5a[i]+T5b[i]+T6[i]+T7[i]+T8a[i]+T8b[i]+T9[i]+T10[i]+T11a[i]+T11b[i]+T12a[i]+T12b[i]+T13[i];
     }
 
     retAns[0] = F/prop*ans[0];
     retAns[1] = F/prop*ans[1];
     retAns[2] = F/prop*ans[2];
     retAns[3] = F/prop*ans[3];
   }
 
 } // namespace anonymous
 // JDC - new amplitude with Higgs emitted close to gluon with full mt effects. Keep usual HEJ-style function call
 double MH2gq_outsideH(CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pH, double mq, bool includeBottom, double mq2)
 {
 
   current cur2bplus,cur2bminus, cur2bplusFlip, cur2bminusFlip;
   current retAns,retAnsb;
   joi(p2out,true,p2in,true,cur2bplus);
   joi(p2out,false,p2in,false,cur2bminus);
   joi(ParityFlip(p2out),true,ParityFlip(p2in),true,cur2bplusFlip);
   joi(ParityFlip(p2out),false,ParityFlip(p2in),false,cur2bminusFlip);
 
   COM app1,app2,apm1,apm2;
   COM app3, app4, apm3, apm4;
 
   if(!includeBottom)
   {
     g_gH_HC(p1in,p1out,pH,mq,retAns);
     app1=cdot(retAns,cur2bplus);
     app2=cdot(retAns,cur2bminus);
 
     g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns);
     app3=cdot(retAns,cur2bplusFlip);
     app4=cdot(retAns,cur2bminusFlip);
 
     // And non-conserving bits
     g_gH_HNC(p1in,p1out,pH,mq,retAns);
     apm1=cdot(retAns,cur2bplus);
     apm2=cdot(retAns,cur2bminus);
 
     g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns);
     apm3=cdot(retAns,cur2bplusFlip);
     apm4=cdot(retAns,cur2bminusFlip);
   } else {
     g_gH_HC(p1in,p1out,pH,mq,retAns);
     g_gH_HC(p1in,p1out,pH,mq2,retAnsb);
     app1=cdot(retAns,cur2bplus) + cdot(retAnsb,cur2bplus);
     app2=cdot(retAns,cur2bminus) + cdot(retAnsb,cur2bminus);
 
     g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns);
     g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq2,retAnsb);
     app3=cdot(retAns,cur2bplusFlip) + cdot(retAnsb,cur2bplusFlip);
     app4=cdot(retAns,cur2bminusFlip) + cdot(retAnsb,cur2bminusFlip);
 
     // And non-conserving bits
     g_gH_HNC(p1in,p1out,pH,mq,retAns);
     g_gH_HNC(p1in,p1out,pH,mq2,retAnsb);
     apm1=cdot(retAns,cur2bplus) + cdot(retAnsb,cur2bplus);
     apm2=cdot(retAns,cur2bminus) + cdot(retAnsb,cur2bminus);
 
     g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns);
     g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq2,retAnsb);
     apm3=cdot(retAns,cur2bplusFlip) + cdot(retAnsb,cur2bplusFlip);
     apm4=cdot(retAns,cur2bminusFlip) + cdot(retAnsb,cur2bminusFlip);
   }
 
   return abs2(app1) + abs2(app2) + abs2(app3) + abs2(app4) + abs2(apm1)
     + abs2(apm2) + abs2(apm3) + abs2(apm4);
 }
 #endif // HEJ_BUILD_WITH_QCDLOOP
 
 double C2gHgm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH)
 {
   static double A=1./(3.*M_PI*HEJ::vev);
   // Implements Eq. (4.22) in hep-ph/0301013 with modifications to incoming plus momenta
   double s12,p1p,p2p;
   COM p1perp,p3perp,phperp;
   // Determine first whether this is the case p1p\sim php>>p3p og the opposite
   s12=p1.invariantMass2(-p2);
   if (p2.pz()>0.) { // case considered in hep-ph/0301013
     p1p=p1.plus();
     p2p=p2.plus();
   } else { // opposite case
     p1p=p1.minus();
     p2p=p2.minus();
   }
   p1perp=p1.px()+COM(0,1)*p1.py();
   phperp=pH.px()+COM(0,1)*pH.py();
   p3perp=-(p1perp+phperp);
 
   COM temp=COM(0,1)*A/(2.*s12)*(p2p/p1p*conj(p1perp)*p3perp+p1p/p2p*p1perp*conj(p3perp));
   temp=temp*conj(temp);
   return temp.real();
 }
 
 double C2gHgp(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH)
 {
   static double A=1./(3.*M_PI*HEJ::vev);
   // Implements Eq. (4.23) in hep-ph/0301013
   double s12,php,p1p,phm;
   COM p1perp,p3perp,phperp;
   // Determine first whether this is the case p1p\sim php>>p3p or the opposite
   s12=p1.invariantMass2(-p2);
   if (p2.pz()>0.) { // case considered in hep-ph/0301013
     php=pH.plus();
     phm=pH.minus();
     p1p=p1.plus();
   } else { // opposite case
     php=pH.minus();
     phm=pH.plus();
     p1p=p1.minus();
   }
   p1perp=p1.px()+COM(0,1)*p1.py();
   phperp=pH.px()+COM(0,1)*pH.py();
   p3perp=-(p1perp+phperp);
 
   COM temp=-COM(0,1)*A/(2.*s12)*( conj(p1perp*p3perp)*pow(php/p1p,2)/(1.+php/p1p)
     +s12*(pow(conj(phperp),2)/(pow(abs(phperp),2)+p1p*phm)
       -pow(conj(p3perp)
       +(1.+php/p1p)*conj(p1perp),2)/((1.+php/p1p)*(pH.m2()+2.*p1.dot(pH)))) );
   temp=temp*conj(temp);
   return temp.real();
 }
 
 double C2qHqm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH)
 {
   static double A=1./(3.*M_PI*HEJ::vev);
   // Implements Eq. (4.22) in hep-ph/0301013
   double s12,p2p,p1p;
   COM p1perp,p3perp,phperp;
   // Determine first whether this is the case p1p\sim php>>p3p or the opposite
   s12=p1.invariantMass2(-p2);
   if (p2.pz()>0.) { // case considered in hep-ph/0301013
     p2p=p2.plus();
     p1p=p1.plus();
   } else { // opposite case
     p2p=p2.minus();
     p1p=p1.minus();
   }
   p1perp=p1.px()+COM(0,1)*p1.py();
   phperp=pH.px()+COM(0,1)*pH.py();
   p3perp=-(p1perp+phperp);
 
   COM temp=A/(2.*s12)*( sqrt(p2p/p1p)*p3perp*conj(p1perp)
     +sqrt(p1p/p2p)*p1perp*conj(p3perp) );
   temp=temp*conj(temp);
   return temp.real();
 }