diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a7bde1..ae387d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,435 +1,443 @@ 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 EXACT) endif() if(${HepMC_FOUND}) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_HepMC2" ) 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_HepMC3}) message(STATUS "Skipping HepMC3") else() ## version 3.1: Finding version not possible in 3.1.1, see HepMC3 git 29e7a6c3 find_package(HepMC3) ## print standard message find_package_handle_standard_args( HepMC3 FOUND_VAR HepMC3_FOUND REQUIRED_VARS HEPMC3_INCLUDE_DIR HEPMC3_LIBRARIES # VERSION_VAR # HEPMC3_VERSION ) if(${HepMC3_FOUND}) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHEJ_BUILD_WITH_HepMC3" ) include_directories(${HEPMC3_INCLUDE_DIR}) 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_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 ${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") set(tst_ME_data_dir "${tst_dir}/ME_data") # test event classification add_executable(test_classify ${tst_dir}/test_classify.cc) target_link_libraries(test_classify hejlib) add_test( NAME t_classify COMMAND test_classify ) add_executable(test_classify_ref ${tst_dir}/test_classify_ref.cc) target_link_libraries(test_classify_ref hejlib) add_test( NAME t_classify_ref COMMAND test_classify_ref ${tst_dir}/classify_ref ${tst_dir}/classify.lhe.gz ) add_test( NAME t_classify_ref_4j COMMAND test_classify_ref ${tst_dir}/classify_ref_4j ${tst_dir}/4j.lhe.gz ) # test phase space point add_executable(test_psp ${tst_dir}/test_psp.cc) target_link_libraries(test_psp hejlib) add_test( NAME t_psp COMMAND test_psp ${tst_dir}/psp_gen.lhe.gz ) # test importing scales add_library(scales SHARED ${tst_dir}/scales.cc) add_executable(test_scale_import ${tst_dir}/test_scale_import) target_link_libraries(test_scale_import hejlib) add_test( NAME t_scale_import COMMAND test_scale_import ${tst_dir}/jet_config_with_import.yml ) # test scale arithmetic (e.g. 2*H_T/4) add_executable(test_scale_arithmetics ${tst_dir}/test_scale_arithmetics) target_link_libraries(test_scale_arithmetics hejlib) add_test( NAME t_scale_arithmetics COMMAND test_scale_arithmetics ${tst_dir}/jet_config.yml ${tst_dir}/2j.lhe.gz ) # test "ParameterDescription" add_executable(test_descriptions ${tst_dir}/test_descriptions) target_link_libraries(test_descriptions hejlib) add_test( NAME t_descriptions COMMAND test_descriptions ) # test "EventParameters*Weight" add_executable(test_parameters ${tst_dir}/test_parameters) target_link_libraries(test_parameters hejlib) add_test( NAME test_parameters COMMAND test_parameters ) # test colour generation add_executable(test_colours ${tst_dir}/test_colours) target_link_libraries(test_colours hejlib) add_test( NAME t_colour_flow COMMAND test_colours ) # test matrix elements add_executable(test_ME_generic ${tst_dir}/test_ME_generic.cc) target_link_libraries(test_ME_generic hejlib) 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 ) 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_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 ) add_test( NAME t_ME_Wp COMMAND test_ME_generic ${tst_ME_data_dir}/config_w_ME.yml ${tst_ME_data_dir}/ME_Wp.dat ${tst_ME_data_dir}/PSP_Wp.lhe.gz ) add_test( NAME t_ME_Wm COMMAND test_ME_generic ${tst_ME_data_dir}/config_w_ME.yml ${tst_ME_data_dir}/ME_Wm.dat ${tst_ME_data_dir}/PSP_Wm.lhe.gz ) # test main executable file(COPY "${tst_dir}/jet_config.yml" DESTINATION "${CMAKE_BINARY_DIR}") set(test_config "${CMAKE_BINARY_DIR}/jet_config.yml") if(${HepMC3_FOUND}) file(READ ${test_config} config) file(WRITE ${test_config} "${config} - tst.hepmc\n") endif() if(${HepMC_FOUND}) file(READ ${test_config} config) file(WRITE ${test_config} "${config} - tst.hepmc2\n") if(${rivet_FOUND}) file(READ ${test_config} config) file(WRITE ${test_config} "${config}\nanalysis:\n rivet: MC_XS\n output: tst\n") endif() endif() set(test_cmd_main "$<TARGET_FILE:HEJ>\\\;${test_config}\\\;${tst_dir}/2j.lhe.gz") # check that HepMC3 output is correct if(${HepMC3_FOUND}) add_executable(check_hepmc ${tst_dir}/check_hepmc.cc) target_link_libraries(check_hepmc hejlib) set(test_cmd_hepmc "$<TARGET_FILE:check_hepmc>\\\;tst.hepmc") else() set(test_cmd_hepmc "") endif() # check that LHEF output is correct add_executable(check_lhe ${tst_dir}/check_lhe.cc) target_link_libraries(check_lhe hejlib) set(tes_cmd_lhe "$<TARGET_FILE:check_lhe>\\\;tst.lhe") # Run dependent tests in one command to ensure correct execution order # Note: The commands are concatenated with "\;" to escape CMake lists. # Thus arguments have to be escaped twice "\\\;". # e.g. "cmd1\;cmd2\\\;arg1\\\;arg2" is executed like "cmd1 && cmd2 arg1 arg2" add_test( NAME t_main COMMAND ${CMAKE_COMMAND} -DCMDS=${test_cmd_main}\;${test_cmd_hepmc}\;${test_cmd_lhe} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run_multiple_tests.cmake ) # check HDF5 reader 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() # check rivet interface if(${RIVET_FOUND}) add_executable(check_rivet ${tst_dir}/check_rivet.cc) target_link_libraries(check_rivet hejlib) add_test( NAME t_rivet COMMAND check_rivet ) endif() # test boson reconstruction add_executable(cmp_events ${tst_dir}/cmp_events.cc) target_link_libraries(cmp_events hejlib) add_test( NAME t_epnu_2j_noW COMMAND cmp_events ${tst_dir}/epnu2jLOFKL_unweight.lhe.tar.gz ${tst_dir}/epnu2jLOFKL_unweight_noW.lhe.gz ) # test resummed result add_executable(check_res ${tst_dir}/check_res.cc) target_link_libraries(check_res hejlib) if(${TEST_ALL}) # deactivate long tests by default 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_3j_unof + COMMAND check_res ${tst_dir}/3j.lhe.gz 133399 4688.83 unof + ) + add_test( + NAME t_3j_unob + COMMAND check_res ${tst_dir}/3j.lhe.gz 105247 3449.45 unob + ) + 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_unof COMMAND check_res ${tst_dir}/h_3j_uno.lhe.gz 0.0127362 0.000271555 unof ) add_test( NAME t_h_3j_unob COMMAND check_res ${tst_dir}/h_3j_uno.lhe.gz 0.0130615 0.000224793 unob ) add_test( NAME t_epnu_2j COMMAND check_res ${tst_dir}/epnu2jLOFKL_unweight.lhe.tar.gz 262.7 3 ) add_test( NAME t_MGepnu_3j COMMAND check_res ${tst_dir}/MGepnu3j_unweighted.tar.gz 38.9512 1 ) add_test( NAME t_MGemnubar_3j COMMAND check_res ${tst_dir}/MGemnubar3j_unweighted.tar.gz 24.1575 1 ) add_test( NAME t_MGepnu_3j_unof COMMAND check_res ${tst_dir}/MGepnu3j_unweighted.tar.gz 9.63702 0.128355 unof ) add_test( NAME t_MGepnu_3j_unob COMMAND check_res ${tst_dir}/MGepnu3j_unweighted.tar.gz 9.70119 0.108436 unob ) add_test( NAME t_MGepnu_3j_splitf COMMAND check_res ${tst_dir}/MGepnu3j_unweighted.tar.gz 2.91995 0.0463182 splitf ) add_test( NAME t_MGepnu_3j_splitb COMMAND check_res ${tst_dir}/MGepnu3j_unweighted.tar.gz 3.40708 0.0550975 splitb ) add_test( NAME t_MGepnu_4j COMMAND check_res ${tst_dir}/MGepnu4j_unweighted.tar.gz 10.2542 0.135106 ) add_test( NAME t_MGemnubar_4j COMMAND check_res ${tst_dir}/MGemnubar4j_unweighted.tar.gz 5.57909 0.0300496 ) add_test( NAME t_MGepnu_4j_qqxmid COMMAND check_res ${tst_dir}/MGepnu4j_unweighted.tar.gz 0.732084 0.005 qqxmid ) endif() diff --git a/Changes.md b/Changes.md index 712d775..ed7de34 100644 --- a/Changes.md +++ b/Changes.md @@ -1,58 +1,60 @@ # Changelog This is the log for changes to the HEJ program. Further changes to the HEJ API are documented in `Changes-API.md`. If you are using HEJ as a library, please also read the changes there. ## Version 2.X ### 2.X.0 * Resummation for W bosons with jets - New subleading processes `extremal qqx` & `central qqx` for a quark and anti-quark in the final state, e.g. `g g => u d_bar Wm g` (the other subleading processes also work with W's) - `HEJFOG` can generate mutliple jets together with a (off-shell) W bosons decaying into lepton & neutrino +* Resummation can now be performed on `unordered` subleading processes + in pure jets. * Allow multiplication and division of multiple scale functions e.g. `H_T/2*m_j1j2` * Print cross sections at end of run * Follow HepMC convention for particle Status codes: incoming = 11, decaying = 2, outgoing = 1 (unchanged) * Partons now have a Colour charge - Colours are read from and written to LHE files - For reweighted events the colours are created according to leading colour in the FKL limit * Allow changing the regulator lambda in input (`regulator parameter`, only for advanced users) * Use `git-lfs` for raw data in test (`make test` now requires `git-lfs`) * Added support to read `hdf5` event files suggested in [arXiv:1905.05120](https://arxiv.org/abs/1905.05120) (needs [HighFive](https://github.com/BlueBrain/HighFive)) * Support input with avarage weight equal to the cross section (`IDWTUP=1 or 4`) * Rename `non-HEJ` Processes to `non-resummable` * Dropped support for HepMC 3.0.0, either HepMC version 2 or >3.1 is required - It is now possible to write out both HepMC 2 and HepMC 3 events at the same time ## 2.0.5 * Fixed event classification for input not ordered in rapidity ### 2.0.4 * Fixed wrong path of `HEJ_INCLUDE_DIR` in `hej-config.cmake` ### 2.0.3 * Fixed parsing of (numerical factor) * (base scale) in configuration * Don't change scale names, but sanitise Rivet output file names instead ### 2.0.2 * Changed scale names to `"_over_"` and `"_times_"` for proper file names (was `"/"` and `"*"` before) ### 2.0.1 * Fixed name of fixed-order generator in error message. diff --git a/FixedOrderGen/include/Subleading.hh b/FixedOrderGen/include/Subleading.hh index c209b2d..36f2976 100644 --- a/FixedOrderGen/include/Subleading.hh +++ b/FixedOrderGen/include/Subleading.hh @@ -1,20 +1,24 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once namespace HEJFOG{ - /** - * Bit position of different subleading channels - * e.g. (unsigned int) 1 => only unordered - */ - enum Subleading: unsigned { - none = 0u, - all = ~0u, - uno = 1u, - unordered = uno, - qqx = 2u - }; + namespace channels{ + /** + * Bit position of different subleading channels + * e.g. (unsigned int) 1 => only unordered + */ + enum Subleading: unsigned { + none = 0u, + all = ~0u, + uno = 1u, + unordered = uno, + qqx = 2u + }; + } + + using Subleading = channels::Subleading; } diff --git a/FixedOrderGen/src/config.cc b/FixedOrderGen/src/config.cc index 2a87eb6..48aeaff 100644 --- a/FixedOrderGen/src/config.cc +++ b/FixedOrderGen/src/config.cc @@ -1,411 +1,409 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "config.hh" #include <cctype> #include "Subleading.hh" #include "HEJ/config.hh" #include "HEJ/YAMLreader.hh" namespace HEJFOG{ using HEJ::set_from_yaml; using HEJ::set_from_yaml_if_defined; using HEJ::pid::ParticleID; namespace{ //! Get YAML tree of supported options /** * The configuration file is checked against this tree of options * in assert_all_options_known. */ YAML::Node const & get_supported_options(){ const static YAML::Node supported = [](){ YAML::Node supported; static const auto opts = { "process", "events", "subleading fraction","subleading channels", "scales", "scale factors", "max scale ratio", "pdf", "event output", "analysis", "import scales" }; // add subnodes to "supported" - the assigned value is irrelevant for(auto && opt: opts) supported[opt] = ""; for(auto && jet_opt: {"min pt", "peak pt", "algorithm", "R", "max rapidity"}){ supported["jets"][jet_opt] = ""; } for(auto && particle_type: {"Higgs", "Wp", "W+", "Wm", "W-", "Z"}){ for(auto && particle_opt: {"mass", "width"}){ supported["particle properties"][particle_type][particle_opt] = ""; } supported["particle properties"][particle_type]["decays"]["into"] = ""; supported["particle properties"][particle_type]["decays"]["branching ratio"] = ""; } for(auto && opt: {"mt", "use impact factors", "include bottom", "mb"}){ supported["Higgs coupling"][opt] = ""; } for(auto && beam_opt: {"energy", "particles"}){ supported["beam"][beam_opt] = ""; } for(auto && unweight_opt: {"sample size", "max deviation"}){ supported["unweight"][unweight_opt] = ""; } for(auto && opt: {"name", "seed"}){ supported["random generator"][opt] = ""; } return supported; }(); return supported; } JetParameters get_jet_parameters( YAML::Node const & node, std::string const & entry ){ const auto p = HEJ::get_jet_parameters(node, entry); JetParameters result; result.def = p.def; result.min_pt = p.min_pt; set_from_yaml(result.max_y, node, entry, "max rapidity"); set_from_yaml_if_defined(result.peak_pt, node, entry, "peak pt"); if(result.peak_pt && *result.peak_pt <= result.min_pt) throw std::invalid_argument{ "Value of option 'peak pt' has to be larger than 'min pt'." }; return result; } Beam get_Beam( YAML::Node const & node, std::string const & entry ){ Beam beam; std::vector<HEJ::ParticleID> particles; set_from_yaml(beam.energy, node, entry, "energy"); set_from_yaml_if_defined(particles, node, entry, "particles"); if(! particles.empty()){ for(HEJ::ParticleID particle: particles){ if(particle != HEJ::pid::p && particle != HEJ::pid::p_bar){ throw std::invalid_argument{ "Unsupported value in option " + entry + ": particles:" " only proton ('p') and antiproton ('p_bar') beams are supported" }; } } if(particles.size() != 2){ throw std::invalid_argument{"Not exactly two beam particles"}; } beam.particles.front() = particles.front(); beam.particles.back() = particles.back(); } return beam; } std::vector<std::string> split( std::string const & str, std::string const & delims ){ std::vector<std::string> result; for(size_t begin, end = 0; end != str.npos;){ begin = str.find_first_not_of(delims, end); if(begin == str.npos) break; end = str.find_first_of(delims, begin + 1); result.emplace_back(str.substr(begin, end - begin)); } return result; } std::invalid_argument invalid_incoming(std::string const & what){ return std::invalid_argument{ "Incoming particle type " + what + " not supported," " incoming particles have to be 'p', 'p_bar' or partons" }; } std::invalid_argument invalid_outgoing(std::string const & what){ return std::invalid_argument{ "Outgoing particle type " + what + " not supported," " outgoing particles have to be 'j', 'photon', 'H', 'Wm', 'Wp', 'e-', 'e+', 'nu_e', 'nu_e_bar'" }; } HEJ::ParticleID reconstruct_boson_id( std::vector<HEJ::ParticleID> const & ids ){ assert(ids.size()==2); const int pidsum = ids[0] + ids[1]; if(pidsum == +1) { assert(HEJ::is_antilepton(ids[0])); if(HEJ::is_antineutrino(ids[0])) { throw HEJ::not_implemented{"lepton-flavour violating final state"}; } assert(HEJ::is_neutrino(ids[1])); // charged antilepton + neutrino means we had a W+ return HEJ::pid::Wp; } if(pidsum == -1) { assert(HEJ::is_antilepton(ids[0])); if(HEJ::is_neutrino(ids[1])) { throw HEJ::not_implemented{"lepton-flavour violating final state"}; } assert(HEJ::is_antineutrino(ids[0])); // charged lepton + antineutrino means we had a W- return HEJ::pid::Wm; } throw HEJ::not_implemented{ "final state with leptons "+HEJ::name(ids[0])+" and "+HEJ::name(ids[1]) +" not supported" }; } Process get_process( YAML::Node const & node, std::string const & entry ){ Process result; std::string process_string; set_from_yaml(process_string, node, entry); assert(! process_string.empty()); const auto particles = split(process_string, " \n\t\v=>"); if(particles.size() < 3){ throw std::invalid_argument{ "Bad format in option process: '" + process_string + "', expected format is 'in1 in2 => out1 ...'" }; } result.incoming.front() = HEJ::to_ParticleID(particles[0]); result.incoming.back() = HEJ::to_ParticleID(particles[1]); for(size_t i = 0; i < result.incoming.size(); ++i){ const HEJ::ParticleID in = result.incoming[i]; if( in != HEJ::pid::proton && in != HEJ::pid::p_bar && !HEJ::is_parton(in) ){ throw invalid_incoming(particles[i]); } } result.njets = 0; for(size_t i = result.incoming.size(); i < particles.size(); ++i){ assert(! particles[i].empty()); if(particles[i] == "j") ++result.njets; else if(std::isdigit(particles[i].front()) && particles[i].back() == 'j') result.njets += std::stoi(particles[i]); else{ const auto pid = HEJ::to_ParticleID(particles[i]); if(pid==HEJ::pid::Higgs || pid==HEJ::pid::Wp || pid==HEJ::pid::Wm){ if(result.boson) throw std::invalid_argument{ "More than one outgoing boson is not supported" }; if(!result.boson_decay.empty()) throw std::invalid_argument{ "Production of a boson together with a lepton is not supported" }; result.boson = pid; } else if (HEJ::is_anylepton(pid)){ // Do not accept more leptons, if two leptons are already mentioned if( result.boson_decay.size()>=2 ) throw std::invalid_argument{"Too many leptons provided"}; if(result.boson) throw std::invalid_argument{ "Production of a lepton together with a boson is not supported" }; result.boson_decay.emplace_back(pid); } else { throw invalid_outgoing(particles[i]); } } } if(result.njets < 2){ throw std::invalid_argument{ "Process has to include at least two jets ('j')" }; } if(!result.boson_decay.empty()){ std::sort(begin(result.boson_decay),end(result.boson_decay)); assert(!result.boson); result.boson = reconstruct_boson_id(result.boson_decay); } return result; } HEJFOG::Subleading to_subleading_channel(YAML::Node const & yaml){ std::string name; - using HEJFOG::Subleading; + using namespace HEJFOG::channels; set_from_yaml(name, yaml); if(name == "none") return none; if(name == "all") return all; if(name == "unordered" || name == "uno") return uno; if(name == "qqx") return qqx; throw HEJ::unknown_option("Unknown subleading channel '"+name+"'"); } unsigned int get_subleading_channels(YAML::Node const & node){ using YAML::NodeType; - using HEJFOG::Subleading; + using namespace HEJFOG::channels; // all channels allowed by default if(!node) return all; switch(node.Type()){ case NodeType::Undefined: return all; case NodeType::Null: return none; case NodeType::Scalar: return to_subleading_channel(node); case NodeType::Map: throw HEJ::invalid_type{"map is not a valid option for subleading channels"}; case NodeType::Sequence: unsigned int channels = HEJFOG::Subleading::none; for(auto && channel_node: node){ channels |= get_subleading_channels(channel_node); } return channels; } throw std::logic_error{"unreachable"}; } Decay get_decay(YAML::Node const & node){ Decay decay; set_from_yaml(decay.products, node, "into"); decay.branching_ratio=1; set_from_yaml_if_defined(decay.branching_ratio, node, "branching ratio"); return decay; } std::vector<Decay> get_decays(YAML::Node const & node){ using YAML::NodeType; if(!node) return {}; switch(node.Type()){ case NodeType::Null: case NodeType::Undefined: return {}; case NodeType::Scalar: throw HEJ::invalid_type{"value is not a list of decays"}; case NodeType::Map: return {get_decay(node)}; case NodeType::Sequence: std::vector<Decay> result; for(auto && decay_str: node){ result.emplace_back(get_decay(decay_str)); } return result; } throw std::logic_error{"unreachable"}; } ParticleProperties get_particle_properties( YAML::Node const & node, std::string const & entry ){ ParticleProperties result; set_from_yaml(result.mass, node, entry, "mass"); set_from_yaml(result.width, node, entry, "width"); try{ result.decays = get_decays(node[entry]["decays"]); } catch(HEJ::missing_option const & ex){ throw HEJ::missing_option{entry + ": decays: " + ex.what()}; } catch(HEJ::invalid_type const & ex){ throw HEJ::invalid_type{entry + ": decays: " + ex.what()}; } return result; } ParticlesPropMap get_all_particles_properties(YAML::Node const & node){ ParticlesPropMap result; for(auto const & entry: node) { const auto name = entry.first.as<std::string>(); const auto id = HEJ::to_ParticleID(name); result.emplace(id, get_particle_properties(node,name)); } return result; } UnweightSettings get_unweight( YAML::Node const & node, std::string const & entry ){ UnweightSettings result; set_from_yaml(result.sample_size, node, entry, "sample size"); if(result.sample_size <= 0){ throw std::invalid_argument{ "negative sample size " + std::to_string(result.sample_size) }; } set_from_yaml(result.max_dev, node, entry, "max deviation"); return result; } Config to_Config(YAML::Node const & yaml){ try{ HEJ::assert_all_options_known(yaml, get_supported_options()); } catch(HEJ::unknown_option const & ex){ throw HEJ::unknown_option{std::string{"Unknown option '"} + ex.what() + "'"}; } Config config; config.process = get_process(yaml, "process"); set_from_yaml(config.events, yaml, "events"); config.jets = get_jet_parameters(yaml, "jets"); config.beam = get_Beam(yaml, "beam"); for(size_t i = 0; i < config.process.incoming.size(); ++i){ const auto & in = config.process.incoming[i]; using namespace HEJ::pid; if( (in == p || in == p_bar) && in != config.beam.particles[i]){ throw std::invalid_argument{ "Particle type of beam " + std::to_string(i+1) + " incompatible" + " with type of incoming particle " + std::to_string(i+1) }; } } set_from_yaml(config.pdf_id, yaml, "pdf"); set_from_yaml(config.subleading_fraction, yaml, "subleading fraction"); if(config.subleading_fraction < 0 || config.subleading_fraction > 1){ throw std::invalid_argument{ "subleading fraction has to be between 0 and 1" }; } if(config.subleading_fraction == 0) config.subleading_channels = Subleading::none; else config.subleading_channels = get_subleading_channels(yaml["subleading channels"]); - if(!config.process.boson && config.subleading_channels != Subleading::none) - throw HEJ::not_implemented("Subleading processes for pure Jet production not implemented yet"); if(yaml["particle properties"]){ config.particles_properties = get_all_particles_properties( yaml["particle properties"]); } if(config.process.boson && config.particles_properties.find(*(config.process.boson)) == config.particles_properties.end()) throw HEJ::missing_option("Process wants to generate boson " +std::to_string(*(config.process.boson))+", but particle properties are missing"); set_from_yaml_if_defined(config.analysis_parameters, yaml, "analysis"); config.scales = HEJ::to_ScaleConfig(yaml); set_from_yaml_if_defined(config.output, yaml, "event output"); config.rng = HEJ::to_RNGConfig(yaml, "random generator"); config.Higgs_coupling = HEJ::get_Higgs_coupling(yaml, "Higgs coupling"); if(yaml["unweight"]) config.unweight = get_unweight(yaml, "unweight"); return config; } } // namespace anonymous Config load_config(std::string const & config_file){ try{ return to_Config(YAML::LoadFile(config_file)); } catch(...){ std::cerr << "Error reading " << config_file << ":\n "; throw; } } } diff --git a/doc/developer_manual/currents.tex b/doc/developer_manual/currents.tex index 8892772..16e795c 100644 --- a/doc/developer_manual/currents.tex +++ b/doc/developer_manual/currents.tex @@ -1,592 +1,592 @@ \section{Currents} \label{sec:currents_impl} The following section contains a list of all the currents implemented in \HEJ. Clean up of the code structure is ongoing. All $W$+Jet currents are located in \texttt{src/Wjets.cc}, all Higgs+Jets currents are defined in \texttt{src/Hjets.cc}, and pure jet currents are defined in in \texttt{src/jets.cc}. All of these have their own separate header files: \texttt{include/HEJ/Wjets.hh}, \texttt{include/HEJ/Hjets.hh} and \texttt{include/HEJ/jets.hh} respectively. The naming convention for the current contraction $\left\|S_{f_1 f_2\to f_1 f_2}\right\|^2$ is \lstinline!ME_[Boson]_[subleading-type]_[incoming]!. For example \lstinline!ME_W_unob_qq! corresponds to the contraction $j_W^\mu j_{\text{uno}, \mu}$ ($qQ\to \bar{q}WQg$). For bosons on the same side as the subleading we drop the connecting underscore, e.g. \lstinline!ME_Wuno_qq! gives $j_{W,\text{uno}}^\mu j_\mu$ ($qQ\to g\bar{q}WQ$). \subsection{Pure Jets} \subsubsection{Quark} \label{sec:current_quark} \begin{align} j_\mu(p_i,p_j)=\bar{u}(p_i)\gamma_\mu u(p_j) \end{align} The exact for depends on the helicity and direction (forward/backwards) for the quarks. Currently all different contractions of incoming and outgoing states are defined in \lstinline!joi!, \lstinline!jio! and \lstinline!joo!. \subsubsection{Gluon} In \HEJ the currents for gluons and quarks are the same, up to a colour factor $K_g/C_F$, where \begin{align} 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}. \end{align} Thus we can just reuse the results from sec.~\ref{sec:current_quark}. \subsubsection{Single unordered gluon} Configuration $q(p_a) \to g(p_1) q(p_2) g^*(\tilde{q}_2)$~\cite{Andersen:2017kfc} \begin{align} \label{eq:juno} \begin{split} &j^{{\rm uno}\; \mu\ cd}(p_2,p_1,p_a) = i \varepsilon_{1\nu} \left( T_{2i}^{c}T_{ia}^d\ \left(U_1^{\mu\nu}-L^{\mu\nu} \right) + T_{2i}^{d}T_{ia}^c\ \left(U_2^{\mu\nu} + L^{\mu\nu} \right) \right). \\ U_1^{\mu\nu} &= \frac1{s_{21}} \left( j_{21}^\nu j_{1a}^\mu + 2 p_2^\nu j_{2a}^\mu \right) \qquad \qquad U_2^{\mu\nu} = \frac1{t_{a1}} \left( 2 j_{2a}^\mu p_a^\nu - j_{21}^\mu j_{1a}^\nu \right) \\ L^{\mu\nu} &= \frac1{t_{a2}} \left(-2p_1^\mu j_{2a}^\nu+2p_1.j_{2a} g^{\mu\nu} + (\tilde{q}_1+\tilde{q}_2)^\nu j_{2a}^\mu + \frac{t_{b2}}{2} j_{2a}^\mu \left( \frac{p_2^\nu}{p_1.p_2} + \frac{p_b^\nu}{p_1.p_b} \right) \right) , \end{split} \end{align} -$j^{{\rm uno}\; \mu}$ is currently not calculated as a separate current, but always as needed for the ME (i.e. in \lstinline!jM2unoXXX!). +$j^{{\rm uno}\; \mu}$ is currently not calculated as a separate current, but always as needed for the ME (i.e. in \lstinline!ME_unob_XX!). \subsection{Higgs} Different rapidity orderings \todo{give name of functions} \begin{enumerate} \item $qQ\to HqQ/qHQ/qQH$ (any rapidity order, full LO ME) $\Rightarrow$ see~\ref{sec:V_H} \item $qg\to Hqg$ (Higgs outside quark) $\Rightarrow$ see~\ref{sec:V_H} \item $qg\to qHg$ (central Higgs) $\Rightarrow$ see~\ref{sec:V_H} \item $qg\to qgH$ (Higgs outside gluon) $\Rightarrow$ see~\ref{sec:jH_mt} \item $gg\to gHg$ (central Higgs) $\Rightarrow$ see~\ref{sec:V_H} \item $gg\to ggH$ (Higgs outside gluon) $\Rightarrow$ see~\ref{sec:jH_mt} \end{enumerate} \subsubsection{Higgs gluon vertex} \label{sec:V_H} The coupling of the Higgs boson to gluons via a virtual quark loop can be written as \begin{align} \label{eq:VH} V^{\mu\nu}_H(q_1, q_2) = \mathgraphics{build/figures/V_H.pdf} &= \frac{\alpha_s m^2}{\pi v}\big[ g^{\mu\nu} T_1(q_1, q_2) - q_2^\mu q_1^\nu T_2(q_1, q_2) \big]\, \\ &\xrightarrow{m \to \infty} \frac{\alpha_s}{3\pi v} \left(g^{\mu\nu} q_1\cdot q_2 - q_2^\mu q_1^\nu\right). \end{align} The outgoing momentum of the Higgs boson is $p_H = q_1 - q_2$. As a contraction with two currents this by implemented in \lstinline!cHdot! inside \texttt{src/Hjets.cc}. The form factors $T_1$ and $T_2$ are then given by~\cite{DelDuca:2003ba} \begin{align} \label{eq:T_1} T_1(q_1, q_2) ={}& -C_0(q_1, q_2)\*\left[2\*m^2+\frac{1}{2}\*\left(q_1^2+q_2^2-p_H^2\right)+\frac{2\*q_1^2\*q_2^2\*p_H^2}{\lambda}\right]\notag\\ &-\left[B_0(q_2)-B_0(p_H)\right]\*\frac{q_2^2}{\lambda}\*\left(q_2^2-q_1^2-p_H^2\right)\notag\\ &-\left[B_0(q_1)-B_0(p_H)\right]\*\frac{q_1^2}{\lambda}\*\left(q_1^2-q_2^2-p_H^2\right)-1\,,\displaybreak[0]\\ \label{eq:T_2} T_2(q_1, q_2) ={}& C_0(q_1, q_2)\*\left[\frac{4\*m^2}{\lambda}\*\left(p_H^2-q_1^2-q_2^2\right)-1-\frac{4\*q_1^2\*q_2^2}{\lambda} - \frac{12\*q_1^2\*q_2^2\*p_H^2}{\lambda^2}\*\left(q_1^2+q_2^2-p_H^2\right)\right]\notag\\ &-\left[B_0(q_2)-B_0(p_H)\right]\*\left[\frac{2\*q_2^2}{\lambda}+\frac{12\*q_1^2\*q_2^2}{\lambda^2}\*\left(q_2^2-q_1^2+p_H^2\right)\right]\notag\\ &-\left[B_0(q_1)-B_0(p_H)\right]\*\left[\frac{2\*q_1^2}{\lambda}+\frac{12\*q_1^2\*q_2^2}{\lambda^2}\*\left(q_1^2-q_2^2+p_H^2\right)\right]\notag\\ &-\frac{2}{\lambda}\*\left(q_1^2+q_2^2-p_H^2\right)\,, \end{align} where we have used the scalar bubble and triangle integrals \begin{align} \label{eq:B0} B_0\left(p\right) ={}& \int \frac{d^dl}{i\pi^{\frac{d}{2}}} \frac{1}{\left(l^2-m^2\right)\left((l+p)^2-m^2\right)}\,,\\ \label{eq:C0} C_0\left(p,q\right) ={}& \int \frac{d^dl}{i\pi^{\frac{d}{2}}} \frac{1}{\left(l^2-m^2\right)\left((l+p)^2-m^2\right)\left((l+p-q)^2-m^2\right)}\,, \end{align} and the K\"{a}ll\'{e}n function \begin{equation} \label{eq:lambda} \lambda = q_1^4 + q_2^4 + p_H^4 - 2\*q_1^2\*q_2^2 - 2\*q_1^2\*p_H^2- 2\*q_2^2\*p_H^2\,. \end{equation} The Integrals as such are provided by \QCDloop{} (see wrapper functions \lstinline!B0DD! and \lstinline!C0DD! in \texttt{src/Hjets.cc}). In the code we are sticking to the convention of~\cite{DelDuca:2003ba}, thus instead of the $T_{1/2}$ we implement (in the functions \lstinline!A1! and \lstinline!A2!) \begin{align} \label{eq:A_1} A_1(q_1, q_2) ={}& \frac{i}{16\pi^2}\*T_2(-q_1, q_2)\,,\\ \label{eq:A_2} A_2(q_1, q_2) ={}& -\frac{i}{16\pi^2}\*T_1(-q_1, q_2)\,. \end{align} \subsubsection{Peripheral Higgs emission - Finite quark mass} \label{sec:jH_mt} We describe the emission of a peripheral Higgs boson close to a scattering gluon with an effective current. In the following we consider a lightcone decomposition of the gluon momenta, i.e. $p^\pm = E \pm p_z$ and $p_\perp = p_x + i p_y$. The incoming gluon momentum $p_a$ defines the $-$ direction, so that $p_a^+ = p_{a\perp} = 0$. The outgoing momenta are $p_1$ for the gluon and $p_H$ for the Higgs boson. We choose the following polarisation vectors: \begin{equation} \label{eq:pol_vectors} \epsilon_\mu^\pm(p_a) = \frac{j_\mu^\pm(p_1, p_a)}{\sqrt{2} \bar{u}^\pm(p_a)u^\mp(p_1)}\,, \quad \epsilon_\mu^{\pm,*}(p_1) = -\frac{j_\mu^\pm(p_1, p_a)}{\sqrt{2} \bar{u}^\mp(p_1)u^\pm(p_a)}\,. \end{equation} Following~\cite{DelDuca:2001fn}, we introduce effective polarisation vectors to describe the contraction with the Higgs-boson production vertex eq.~\eqref{eq:VH}: \begin{align} \label{eq:eps_H} \epsilon_{H,\mu}(p_a) = \frac{T_2(p_a, p_a-p_H)}{(p_a-p_H)^2}\big[p_a\cdot p_H\epsilon_\mu(p_a) - p_H\cdot\epsilon(p_a) p_{a,\mu}\big]\,,\\ \epsilon_{H,\mu}^*(p_1) = -\frac{T_2(p_1+p_H, p_1)}{(p_1+p_H)^2}\big[p_1\cdot p_H\epsilon_\mu^*(p_1) - p_H\cdot\epsilon^*(p_1) p_{1,\mu}\big]\,, \end{align} We also employ the usual short-hand notation \begin{equation} \label{eq:spinor_helicity} \spa i.j = \bar{u}^-(p_i)u^+(p_j)\,,\qquad \spb i.j = \bar{u}^+(p_i)u^-(p_j)\,, \qquad[ i | H | j\rangle = j_\mu^+(p_i, p_j)p_H^\mu\,. \end{equation} Without loss of generality, we consider only the case where the incoming gluon has positive helicity. The remaining helicity configurations can be obtained through parity transformation. Labelling the effective current by the helicities of the gluons we obtain for the same-helicity case \begin{equation} \label{eq:jH_same_helicity} \begin{split} j_{H,\mu}^{++}{}&(p_1,p_a,p_H) = \frac{m^2}{\pi v}\bigg[\\ &-\sqrt{\frac{2p_1^-}{p_a^-}}\frac{p_{1\perp}^*}{|p_{1\perp}|}\frac{t_2}{\spb a.1}\epsilon^{+,*}_{H,\mu}(p_1) +\sqrt{\frac{2p_a^-}{p_1^-}}\frac{p_{1\perp}^*}{|p_{1\perp}|}\frac{t_2}{\spa 1.a}\epsilon^{+}_{H,\mu}(p_a)\\ &+ [1|H|a\rangle \bigg( \frac{\sqrt{2}}{\spa 1.a}\epsilon^{+}_{H,\mu}(p_a) + \frac{\sqrt{2}}{\spb a.1}\epsilon^{+,*}_{H,\mu}(p_1)-\frac{\spa 1.a T_2(p_a, p_a-p_H)}{\sqrt{2}(p_a-p_H)^2}\epsilon^{+,*}_{\mu}(p_1)\\ & \qquad -\frac{\spb a.1 T_2(p_1+p_H, p_1)}{\sqrt{2}(p_1+p_H)^2}\epsilon^{+}_{\mu}(p_a)-\frac{RH_4}{\sqrt{2}\spb a.1}\epsilon^{+,*}_{\mu}(p_1)+\frac{RH_5}{\sqrt{2}\spa 1.a}\epsilon^{+}_{\mu}(p_a) \bigg)\\ & - \frac{[1|H|a\rangle^2}{2 t_1}(p_{a,\mu} RH_{10} - p_{1,\mu} RH_{12})\bigg] \end{split} \end{equation} with $t_1 = (p_a-p_1)^2$, $t_2 = (p_a-p_1-p_H)^2$ and $R = 8 \pi^2$. Eq.~\eqref{eq:jH_same_helicity} is implemented by \lstinline!g_gH_HC! in \texttt{src/Hjets.cc} \footnote{\lstinline!g_gH_HC! and \lstinline!g_gH_HNC! includes an additional $1/t_2$ factor, which should be in the Matrix element instead.}. The currents with a helicity flip is given through \begin{equation} \label{eq:jH_helicity_flip} \begin{split} j_{H,\mu}^{+-}{}&(p_1,p_a,p_H) = \frac{m^2}{\pi v}\bigg[\\ &-\sqrt{\frac{2p_1^-}{p_a^-}}\frac{p_{1\perp}^*}{|p_{1\perp}|}\frac{t_2}{\spb a.1}\epsilon^{-,*}_{H,\mu}(p_1) +\sqrt{\frac{2p_a^-}{p_1^-}}\frac{p_{1\perp}}{|p_{1\perp}|}\frac{t_2}{\spb a.1}\epsilon^{+}_{H,\mu}(p_a)\\ &+ [1|H|a\rangle \left( \frac{\sqrt{2}}{\spb a.1} \epsilon^{-,*}_{H,\mu}(p_1) -\frac{\spa 1.a T_2(p_a, p_a-p_H)}{\sqrt{2}(p_a-p_H)^2}\epsilon^{-,*}_{\mu}(p_1) - \frac{RH_4}{\sqrt{2}\spb a.1}\epsilon^{-,*}_{\mu}(p_1)\right) \\ &+ [a|H|1\rangle \left( \frac{\sqrt{2}}{\spb a.1}\epsilon^{+}_{H,\mu}(p_a) -\frac{\spa 1.a T_2(p_1+p_H,p_1)}{\sqrt{2}(p_1+p_H)^2}\epsilon^{+}_{\mu}(p_a) +\frac{RH_5}{\sqrt{2}\spb a.1}\epsilon^{+}_{\mu}(p_a) \right)\\ & - \frac{[1|H|a\rangle [a|H|1\rangle}{2 \spb a.1 ^2}(p_{a,\mu} RH_{10} - p_{1,\mu} RH_{12})\\ &+ \frac{\spa 1.a}{\spb a.1}\bigg(RH_1p_{1,\mu}-RH_2p_{a,\mu}+2 p_1\cdot p_H \frac{T_2(p_1+p_H, p_1)}{(p_1+p_H)^2} p_{a,\mu} \\ & \qquad- 2p_a \cdot p_H \frac{T_2(p_a, p_a-p_H)}{(p_a-p_H)^2} p_{1,\mu}+ T_1(p_a-p_1, p_a-p_1-p_H)\frac{(p_1 + p_a)_\mu}{t_1}\\ &\qquad-\frac{(p_1+p_a)\cdot p_H}{t_1} T_2(p_a-p_1, p_a-p_1-p_H)(p_1 - p_a)_\mu \bigg) \bigg]\,, \end{split} \end{equation} and implemented by \lstinline!g_gH_HNC! again in \texttt{src/Hjets.cc}. If we instead choose the gluon momentum in the $+$ direction, so that $p_a^- = p_{a\perp} = 0$, the corresponding currents are obtained by replacing $p_1^- \to p_1^+, p_a^- \to p_a^+, \frac{p_{1\perp}}{|p_{1\perp}|} \to -1$ in the second line of eq.~\eqref{eq:jH_same_helicity} and eq.~\eqref{eq:jH_helicity_flip} (see variables \lstinline!ang1a! and \lstinline!sqa1! in the implementation). The form factors $H_1,H_2,H_4,H_5, H_{10}, H_{12}$ are given in~\cite{DelDuca:2003ba}, and are implemented under their name in \texttt{src/Hjets.cc}. They reduce down to fundamental QCD integrals, which are again provided by \QCDloop. \subsubsection{Peripheral Higgs emission - Infinite top mass} \label{sec:jH_eff} To get the result with infinite top mass we could either take the limit $m_t\to \infty$ in~\eqref{eq:jH_helicity_flip} and~\eqref{eq:jH_same_helicity}, or use the \textit{impact factors} as given in~\cite{DelDuca:2003ba}. Both methods are equivalent, and lead to the same result. For the first one would find \begin{align} \lim_{m_t\to\infty} m_t^2 H_1 &= i \frac{1}{24 \pi^2}\\ \lim_{m_t\to\infty} m_t^2 H_2 &=-i \frac{1}{24 \pi^2}\\ \lim_{m_t\to\infty} m_t^2 H_4 &= i \frac{1}{24 \pi^2}\\ \lim_{m_t\to\infty} m_t^2 H_5 &=-i \frac{1}{24 \pi^2}\\ \lim_{m_t\to\infty} m_t^2 H_{10} &= 0 \\ \lim_{m_t\to\infty} m_t^2 H_{12} &= 0. \end{align} \todo{double check this, see James thesis eq. 4.33} However only the second method is implemented in the code through \lstinline!C2gHgp! and \lstinline!C2gHgm! inside \texttt{src/Hjets.cc}, each function calculates the square of eq. (4.23) and (4.22) from~\cite{DelDuca:2003ba} respectively. \subsection{$W$+Jets} \label{sec:currents_W} \subsubsection{Quark+$W$} \begin{figure} \centering \begin{minipage}[b]{0.2\textwidth} \includegraphics[width=\textwidth]{figures/Wbits.pdf} \end{minipage} \begin{minipage}[b]{0.1\textwidth} \centering{=} \vspace{0.7cm} \end{minipage} \begin{minipage}[b]{0.2\textwidth} \includegraphics[width=\textwidth]{figures/Wbits2.pdf} \end{minipage} \begin{minipage}[b]{0.1\textwidth} \centering{+} \vspace{0.7cm} \end{minipage} \begin{minipage}[b]{0.2\textwidth} \includegraphics[width=\textwidth]{figures/Wbits3.pdf} \end{minipage} \caption{The $j_W$ current is constructed from the two diagrams which contribute to the emission of a $W$-boson from a given quark line.} \label{fig:jW} \end{figure} For a $W$ emission we require a fermion. The $j_W$ current is actually a sum of two separate contributions, see figure~\ref{fig:jW}, one with a $W$-emission from the initial state, and one with the $W$-emission from the final state. Mathematically this can be seen as the following two terms~\cite{Andersen:2012gk}\todo{cite W subleading paper}: \begin{align} \label{eq:Weffcur1} j_W^\mu(p_a,p_{\ell},p_{\bar{\ell}}, p_1) =&\ \frac{g_W^2}{2}\ \frac1{p_W^2-M_W^2+i\ \Gamma_W M_W}\ \bar{u}^-(p_\ell) \gamma_\alpha v^-(p_{\bar\ell})\nonumber \\ & \cdot \left( \frac{ \bar{u}^-(p_1) \gamma^\alpha (\slashed{p}_W + \slashed{p}_1)\gamma^\mu u^-(p_a)}{(p_W+p_1)^2} + \frac{ \bar{u}^-(p_1)\gamma^\mu (\slashed{p}_a + \slashed{p}_W)\gamma^\alpha u^-(p_a)}{(p_a-p_W)^2} \right). \end{align} There are a couple of subtleties here. There is a minus sign distinction between the quark-anti-quark cases due to the fermion flow of the propagator in the current. Note that the type of $W$ emission (+ or -) will depend on the quark flavour, and that the handedness of the quark-line is given by whether its a quark or anti-quark. \subsubsection{$W$+uno} \begin{figure} \centering \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/wuno1} \caption{} \label{fig:U1diags} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/wuno2} \caption{} \label{fig:U2diags} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/wuno3} \caption{} \label{fig:Cdiags} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/wuno4} \caption{} \label{fig:Ddiags} \end{subfigure} \vspace{0.4cm} \caption{Examples of each of the four categories of Feynman diagram which contribute to at leading-order; there are twelve in total. (a) is an example where the gluon and $W$ boson are emitted from the same quark line and the gluon comes after the $t$-channel propagator. In (b), the gluon and $W$ boson are emitted from the same quark line and the gluon comes before the $t$-channel proagator. In (c) the gluon is emitted from the $t$-channel gluon and in (d) the gluon is emitted from the $b$--$3$ quark line.} \label{fig:Wunodiags} \end{figure} It is necessary to include subleading processes in $W$+Jets also. All of these currents have been built for the \lstinline!Tensor! Class detailed in section~\ref{sec:tensor}. Similarly to the pure jet case, the uno currents are not calculated separately, and only in the ME functions when required in the \texttt{src/Wjets.cc} file. For unordered emissions a new current is required, $j_{W,{\rm uno}}$, it is only non-zero for $h_a=h_1=-$ and hence we have suppressed its helicity indices. It is derived from the 12 leading-order Feynman diagrams in the QMRK limit (see figure~\ref{fig:Wunodiags}). Using $T^m_{ij}$ represent fundamental colour matrices between quark state $i$ and $j$ with adjoint index $m$ we find \begin{align}\label{eq:wunocurrent} \begin{split} j^{d\,\mu}_{\rm W,uno}(p_a,p_1,p_2,p_\ell,p_{\bar{\ell}}) =& \ i \varepsilon_{\nu}(p_1)\ \bar{u}^-(p_\ell) \gamma_\rho v^-(p_{\bar \ell}) \\ & \quad \times\ \left(T^1_{2i} T^d_{ia} (\tilde U_1^{\nu\mu\rho}-\tilde L^{\nu\mu\rho}) + T^d_{2i} T^1_{ia} (\tilde U_2^{\nu\mu\rho}+\tilde L^{\nu\mu\rho}) \right), \end{split} \end{align} where expressions for $\tilde U_{1,2}^{\nu\mu\rho}$ and $\tilde L^{\nu\mu\rho}$ are given as: \begin{align} \label{eq:U1tensor} \begin{split} \tilde U_1^{\nu\mu\rho} =&\frac{\langle 2|\nu (\slashed{p}_2+ \slashed{p}_1)\mu (\slashed{p}_a - \slashed{p}_W)\rho P_L |a\rangle }{s_{12}t_{aW}} + \frac{\langle 2|\nu (\slashed{p}_2+ \slashed{p}_1)\rho P_L (\slashed{p}_2+\slashed{p}_1 + \slashed{p}_W)\mu |a\rangle }{s_{12}s_{12W}} \\ &+ \frac{\langle 2|\rho P_L (\slashed{p}_2+ \slashed{p}_W) \nu (\slashed{p}_1 + \slashed{p}_2+\slashed{p}_W)\mu |a\rangle}{s_{2W}s_{12W}}. \end{split} \end{align} \begin{align} \label{eq:U2tensor} \begin{split} \tilde U_2^{\nu\mu\rho} =&\frac{\langle 2|\mu (\slashed{p}_a-\slashed{p}_W-\slashed{p}_1)\nu (\slashed{p}_a - \slashed{p}_W)\rho P_L |a\rangle }{t_{aW1}t_{aW}} + \frac{\langle 2|\mu (\slashed{p}_a-\slashed{p}_W- \slashed{p}_1)\rho P_L (\slashed{p}_a-\slashed{p}_1) \nu |a\rangle }{t_{a1W}t_{a1}} \\ &+ \frac{\langle 2|\rho P_L (\slashed{p}_2+ \slashed{p}_W) \mu (\slashed{p}_a-\slashed{p}_1)\nu |a\rangle}{s_{2W}t_{a1}}. \end{split} \end{align} \begin{align} \label{eq:Ltensor} \tilde L^{\nu\mu\rho} &= \frac{q_2^2}{2t_{aW2}} \left[\frac{\langle 2 |\mu (\slashed{p}_a - \slashed{p}_W) \rho P_L | a\rangle}{t_{aW}} + \frac{\langle 2 |\rho P_L (\slashed{p}_2 + \slashed{p}_W) \mu | a\rangle }{s_{2W}} \right] \cdot \left( \frac{p_b^{\nu}}{p_b\cdot p_1} + \frac{p_3^{\nu}}{p_3\cdot p_1} \right) \nonumber \\ &\quad+\frac{1}{t_{aW2}}\left[\frac{\langle 2 |\sigma (\slashed{p}_a - \slashed{p}_W) \rho P_L | a\rangle}{t_{aW}} + \frac{\langle 2 |\rho P_L (\slashed{p}_2 + \slashed{p}_W) \sigma | a\rangle }{s_{2W}} \right] \nonumber \\ &\vphantom{+\frac{1}{t_{aW2}}}\quad\cdot \left( g^{\sigma \mu} (q_1 +q_2)^\nu + g^{\mu \nu}(-q_2 +p_1)^\sigma+ g^{\nu \sigma}(-p_1 -q_1)^\mu \right). \end{align} \subsubsection{$W$+Extremal $\mathbf{q\bar{q}}$} The $W$+Jet sub-leading processes containing an extremal $q\bar{q}$ are related by crossing symmetry to the $W$+Jet unordered processes. This means that one can simply perform a crossing symmetry argument on eq.~\ref{eq:wunocurrent} to arrive at the extremal $q\bar{q}$ current required.We show the basic structure of the extremal $q\bar{q}$ current in figure~\ref{fig:qgimp}, neglecting the $W$-emission for simplicity. \begin{figure} \centering \includegraphics[width=0.3\textwidth]{{qqbarex_schem}} \caption{Schematic structure of the $gq \to \bar{Q}Qq$ amplitude in the limit $y_1 \sim y_2 \ll y_3$} \label{fig:qgimp} \end{figure} \begin{figure} \centering \begin{subfigure}{0.45\textwidth} \centering \includegraphics{qqbarex1} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{qqbarex2} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{qqbarex4} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{qqbarex5} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{qqbarex3} \end{subfigure} \caption{The five tree-level graphs which contribute to the process $gq \to \bar{Q}Qq$.} \label{fig:qg_qQQ_graphs} \end{figure} We can obtain the current for $g\rightarrow W q \bar{q}$ by evaluating the current for $W$ plus unordered emissions with the normal arguments $p_a \leftrightarrow -p_1 $ interchanged. This is a non-trivial statement: due to the minimality of the approximations made, the crossing symmetry normally present in the full amplitude may be extended to the factorised current. We must again note that swapping $p_a \leftrightarrow -p_1$ will lead to $u$-spinors with momenta with negative energy. These are identical to $v$-spinors with momenta with positive energy, up to an overall phase which is common to all terms, and can therefore be neglected. Mathematically, this is given by: \begin{align}\label{eq:crossedJ} j^\mu_{\rm W,g\to Q\bar{Q}}(p_a,p_1,p_2,p_\ell,p_{\bar{\ell}}) =i \varepsilon_{g\nu} \langle \ell | \rho | \bar \ell \rangle_L \left(T^1_{2i} T^d_{ia} (\tilde U_{1,X}^{\nu\mu\rho}-\tilde L^{\nu\mu\rho}_X) + T^d_{2i} T^1_{ia} (\tilde U_{2,X}^{\nu\mu\rho}+\tilde L_X^{\nu\mu\rho}) \right), \end{align} where the components are now given by \begin{align} \label{eq:U1tensorX} \begin{split} \tilde U_{1,X}^{\nu\mu\rho} =&\frac{\langle 2|\nu (\slashed{p}_a- \slashed{p}_2)\mu (\slashed{p}_1 + \slashed{p}_W)\rho P_L |1\rangle }{t_{a2}s_{1W}} + \frac{\langle 2|\nu (\slashed{p}_a- \slashed{p}_2)\rho P_L (\slashed{p}_a-\slashed{p}_2 - \slashed{p}_W)\mu |1\rangle }{t_{a2}t_{a2W}} \\ &- \frac{\langle 2|\rho P_L (\slashed{p}_2+ \slashed{p}_W) \nu (\slashed{p}_a - \slashed{p}_2-\slashed{p}_W)\mu |1\rangle}{s_{2W}t_{a2W}}, \\ \tilde U_{2,X}^{\nu\mu\rho} =&-\frac{\langle 2|\mu (\slashed{p}_a-\slashed{p}_W-\slashed{p}_1)\nu (\slashed{p}_1 + \slashed{p}_W)\rho P_L |1\rangle }{t_{aW1}s_{1W}} + \frac{\langle 2|\mu (\slashed{p}_a-\slashed{p}_W- \slashed{p}_1)\rho P_L (\slashed{p}_a-\slashed{p}_1) \nu |1\rangle }{t_{a1W}t_{a1}} \\ &+ \frac{\langle 2|\rho P_L (\slashed{p}_2+ \slashed{p}_W) \mu (\slashed{p}_a-\slashed{p}_1)\nu |1\rangle}{s_{2W}t_{a1}}, \\ \tilde L^{\nu\mu\rho}_X &= \frac{q_2^2}{2s_{1W2}} \left[\frac{\langle 2 |\mu (\slashed{p}_1 + \slashed{p}_W) \rho P_L | 1\rangle}{s_{1W}} + \frac{\langle 2 |\rho P_L (\slashed{p}_2 + \slashed{p}_W) \mu | 1\rangle }{s_{2W}} \right] \cdot \left( \frac{p_b^{\nu}}{p_a\cdot p_b} + \frac{p_3^{\nu}}{p_a\cdot p_3} \right) \\ &\quad+\frac{1}{s_{W12}}\left[-\frac{\langle 2 |\sigma (\slashed{p}_1 + \slashed{p}_W) \rho P_L | a\rangle}{t_{aW}} + \frac{\langle 2 |\rho P_L (\slashed{p}_2 + \slashed{p}_W) \sigma | 1\rangle }{s_{2W}} \right] \\ &\vphantom{+\frac{1}{t_{aW2}}}\quad\cdot \left( g^{\sigma \mu} (q_1 +q_2)^\nu + g^{\mu \nu}(-q_2 +p_1)^\sigma+ g^{\nu \sigma}(-p_1 -q_1)^\mu \right). \end{split} \end{align} Notice in particular the similarity to the $W$+uno scenario (from which this has been derived). \subsubsection{Central $\mathbf{q\bar{q}}$ Vertex} The final subleading process in the $W$+Jet case is the Central $q\bar{q}$ vertex. This subleading process does not require an altered current, but an effective vertex which is contracted with two regular \HEJ currents. This complexity is dealt with nicely by the \lstinline!Tensor! class, which is detailed in section~\ref{sec:tensor}. The $W$-emission can be from the central effective vertex (scenario dealt with by the function \texttt{jM2WqqtoqQQq()} in the file \texttt{src/Wjets.cc}); or from either of the external quark legs (scenario dealt with by \texttt{jM2WqqtoqQQqW()} in same file). In the pure jets case, there are 7 separate diagrams which contribute to this, which can be seen in figure~\ref{fig:qq_qQQq_graphs}. In the $W$+Jets case, there are then 45 separate contributions. \begin{figure} \centering \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen1} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen2} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen3} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen4} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen5} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen6} \end{subfigure} \begin{subfigure}{0.45\textwidth} \centering \includegraphics{figures/qqbarcen7} \end{subfigure} \caption{All Feynman diagrams which contribute to $qq' \to qQ\bar{Q}q'$ at leading order.} \label{fig:qq_qQQq_graphs} \end{figure} The end result is of the effective vertex, after derivation, is: \begin{align} \label{eq:EffectiveVertexqqbar} \begin{split} V^{\mu\nu}_{\text{Eff}}=& \frac{C_1}{s_{23AB}}\left(X^{\mu\nu\sigma}_{1a}\hat{t_1} + X^{\mu\nu\sigma}_{4b}\hat{t_3} +V^{\mu\nu\sigma}_{3g}\right)J_{\text{V} \sigma}(p_2,p_A,p_B,p_3) \\ &\quad +iC_2X^{\mu\nu}_{Unc}+iC_3X^{\mu\nu}_{Cro}, \end{split} \end{align} where: \begin{eqnarray} \begin{split} C_1=&T^e_{1q}T^g_{qa}T^e_{23}T^g_{4b} - T^g_{1q}T^e_{qa}T^e_{23}T^g_{4b} = f^{egc}T^c_{1a}T^e_{23}T^g_{4b}, \\ C_2=&T^g_{1a}T^g_{2q}T^{g'}_{q3}T^{g'}_{4b} \\ C_3=&T^g_{1a}T^{g'}_{2q}T^g_{q3}T^{g'}_{4b} \end{split} \end{eqnarray} are the colour factors of different contributions. The following tensor structures correspond to groupings of diagrams in figure~\ref{fig:qq_qQQq_graphs}. \begin{eqnarray} \label{eq:1aFixed} X_{1a}^{\mu\nu\sigma} &= \frac{-g^{\mu\nu}}{s_{23AB}\hat{t_3}}\left(\frac{p^\sigma_a}{(s_{a23AB})} + \frac{p^\sigma_1}{(s_{123AB})}\right) \\ \label{eq:4bFixed} X_{4b}^{\mu\nu\sigma} &=\frac{g^{\mu\nu}}{s_{23AB}\hat{t_1}}\left(\frac{p^\sigma_b}{(s_{23bAB})}+\frac{p^\sigma_4}{(s_{234AB}}\right) \end{eqnarray} correspond to the first and second row of diagrams in figure~\ref{fig:qq_qQQq_graphs}. \begin{align} \label{eq:3GluonWEmit} \begin{split} X^{\mu\nu}_{3g}=\frac{1}{ \hat{t}_1s_{23AB}\,\hat{t}_3} \bigg[&\left(q_1+p_2+p_3+p_A+p_B\right)^\nu g^{\mu\sigma}+ \\ &\quad\left(q_3-p_2-p_3-p_A-p_B\right)^\mu g^{\sigma\nu}- \\ & \qquad\left(q_1+q_3\right)^\sigma g^{\mu\nu}\bigg]J_{\text{V} \sigma}(p_2,p_A,p_B,p_3) \end{split} \end{align} corresponds to the left diagram on the third row in figure~\ref{fig:qq_qQQq_graphs}. One notes that all of these contributions have the same colour factor, and as such we can group them together nicely before summing over helicities etc. As such, the function \texttt{MSymW()} in \texttt{src/Wjets.cc} returns a \lstinline!Tensor! containing the information from these 5 groupings of contributions (30 diagrams in total). \begin{align} \begin{split} X^{\mu\nu}_{Unc}=\frac{\langle A|\sigma P_L|B\rangle}{\hat{t_1}\hat{t_3}} \bar{u}_2&\left[-\frac{ \gamma^\sigma P_L(\slashed{p}_2+\slashed{p}_A+\slashed{p}_B)\gamma^\mu (\slashed{q}_3+ \slashed{p}_3)\gamma^\nu}{(s_{2AB})(t_{unc_{2}})}\right.+ \\ &\qquad\left. \frac{\gamma^\mu(\slashed{q}_1-\slashed{p}_2)\gamma^\sigma P_L(\slashed{q}_3+\slashed{p}_3)\gamma^\nu}{(t_{unc_{1}})(t_{unc_{2}})}\right. + \\ &\qquad\qquad\left. \frac{\gamma^\mu(\slashed{q}_1-\slashed{p}_2)\gamma^\nu(\slashed{p}_3+\slashed{p}_A+\slashed{p}_B)\gamma^\sigma P_L }{(t_{unc_1})(s_{3AB})}\right]v_3 \end{split} \end{align} corresponds to the diagram on the right of row three in figure~\ref{fig:qq_qQQq_graphs}. This contribution to the effective vertex can be obtained in the code with the function \texttt{MUncW()} in file \texttt{src/Wjets.cc}. \begin{align} \begin{split} X^{\mu\nu}_{Cro}=\frac{\langle A|\sigma P_L|B\rangle}{\hat{t_1}\hat{t_3}} \bar{u}_2&\left[-\frac{ \gamma^\nu(\slashed{q}_3+\slashed{p}_2)\gamma^\mu (\slashed{p}_3+\slashed{p}_A+\slashed{p}_B)\gamma^\sigma P_L}{(t_{cro_1})(s_{3AB})}\right.+ \\ &\qquad\left. \frac{\gamma^\nu(\slashed{q}_3+\slashed{p}_2)\gamma^\sigma P_L(\slashed{q}_1-\slashed{p}_3)\gamma^\mu}{(t_{cro_{1}})(t_{cro_{2}})}\right.+ \\ &\qquad\qquad\left . \frac{\gamma^\sigma P_L(\slashed{p}_2+\slashed{p}_A+\slashed{p}_B)\gamma^\nu(\slashed{q}_1-\slashed{p}_3)\gamma^\mu }{(s_{2AB})(t_{cro_2})}\right]v_3 \end{split} \end{align} corresponds to the last diagram in figure~\ref{fig:qq_qQQq_graphs}. This contribution to the effective vertex can be obtained in the code with the function \texttt{MCroW()} in file \texttt{src/Wjets.cc}. %%% Local Variables: %%% mode: latex %%% TeX-master: "developer_manual" %%% End: diff --git a/doc/sphinx/HEJ.rst b/doc/sphinx/HEJ.rst index cc56fe2..de02a72 100644 --- a/doc/sphinx/HEJ.rst +++ b/doc/sphinx/HEJ.rst @@ -1,327 +1,325 @@ .. _`Running HEJ 2`: Running HEJ 2 ============= Quick start ----------- In order to run HEJ 2, you need a configuration file and a file containing fixed-order events. A sample configuration is given by the :file:`config.yml` file distributed together with HEJ 2. Events in the Les Houches Event File format can be generated with standard Monte Carlo generators like `MadGraph5_aMC@NLO <https://launchpad.net/mg5amcnlo>`_ or `Sherpa <https://sherpa.hepforge.org/trac/wiki>`_. If HEJ 2 was compiled with `HDF5 <https://www.hdfgroup.org/>`_ support, it can also read event files in the format suggested in `arXiv:1905.05120 <https://arxiv.org/abs/1905.05120>`_. HEJ 2 assumes that the cross section is given by the sum of the event weights. Depending on the fixed-order generator it may be necessary to adjust the weights in the Les Houches Event File accordingly. The processes supported by HEJ 2 are - Pure multijet production - Production of a Higgs boson with jets - Production of a W boson with jets .. - *TODO* Production of a Z boson or photon with jets where at least two jets are required in each case. For the time being, only leading-order events are supported. After generating an event file :file:`events.lhe` adjust the parameters under the `fixed order jets`_ setting in :file:`config.yml` to the settings in the fixed-order generation. Resummation can then be added by running:: HEJ config.yml events.lhe Using the default settings, this will produce an output event file :file:`HEJ.lhe` with events including high-energy resummation. When using the `Docker image <https://hub.docker.com/r/hejdock/hej>`_, HEJ can be run with .. code-block:: bash docker run -v $PWD:$PWD -w $PWD hejdock/hej HEJ config.yml events.lhe .. _`HEJ 2 settings`: Settings -------- HEJ 2 configuration files follow the `YAML <http://yaml.org/>`_ format. The following configuration parameters are supported: .. _`trials`: **trials** High-energy resummation is performed by generating a number of resummation phase space configurations corresponding to an input fixed-order event. This parameter specifies how many such configurations HEJ 2 should try to generate for each input event. Typical values vary between 10 and 100. .. _`min extparton pt`: **min extparton pt** Specifies the minimum transverse momentum in GeV of the most forward and the most backward parton. This setting is needed to regulate an otherwise uncancelled divergence. Its value should be slightly below the minimum transverse momentum of jets specified by `resummation jets: min pt`_. See also the `max ext soft pt fraction`_ setting. .. _`max ext soft pt fraction`: **max ext soft pt fraction** Specifies the maximum fraction that soft radiation can contribute to the transverse momentum of each the most forward and the most backward jet. Values between around 0.05 and 0.1 are recommended. See also the `min extparton pt`_ setting. .. _`fixed order jets`: **fixed order jets** This tag collects a number of settings specifying the jet definition in the event input. The settings should correspond to the ones used in the fixed-order Monte Carlo that generated the input events. .. _`fixed order jets: min pt`: **min pt** Minimum transverse momentum in GeV of fixed-order jets. .. _`fixed order jets: algorithm`: **algorithm** The algorithm used to define jets. Allowed settings are :code:`kt`, :code:`cambridge`, :code:`antikt`, :code:`cambridge for passive`. See the `FastJet <http://fastjet.fr/>`_ documentation for a description of these algorithms. .. _`fixed order jets: R`: **R** The R parameter used in the jet algorithm, roughly corresponding to the jet radius in the plane spanned by the rapidity and the azimuthal angle. .. _`resummation jets`: **resummation jets** This tag collects a number of settings specifying the jet definition in the observed, i.e. resummed events. These settings are optional, by default the same values as for the `fixed order jets`_ are assumed. .. _`resummation jets: min pt`: **min pt** Minimum transverse momentum in GeV of resummation jets. This should be between 25% and 50% larger than the minimum transverse momentum of fixed order jets set by `fixed order jets: min pt`_. .. _`resummation jets: algorithm`: **algorithm** The algorithm used to define jets. The HEJ 2 approach to resummation relies on properties of :code:`antikt` jets, so this value is strongly recommended. For a list of possible other values, see the `fixed order jets: algorithm`_ setting. .. _`resummation jets: R`: **R** The R parameter used in the jet algorithm. .. _`FKL`: **FKL** Specifies how to treat events respecting FKL rapidity ordering. These configurations are dominant in the high-energy limit. The possible values are :code:`reweight` to enable resummation, :code:`keep` to keep the events as they are up to a possible change of renormalisation and factorisation scale, and :code:`discard` to discard these events. .. _`unordered`: **unordered** Specifies how to treat events with one emission that does not respect FKL ordering, e.g. :code:`u d => g u d`. In the high-energy limit, such configurations are logarithmically suppressed compared to FKL configurations. - The possible values are the same as for the `FKL`_ setting, but - :code:`reweight` is currently only supported for Higgs or W bosons plus jets - production. + The possible values are the same as for the `FKL`_ setting. .. _`extremal qqx`: **extremal qqx** Specifies how to treat events with a quark-antiquark pair as extremal partons in rapidity, e.g. :code:`g d => u u_bar d`. In the high-energy limit, such configurations are logarithmically suppressed compared to FKL configurations. The possible values are the same as for the `FKL`_ setting, but :code:`reweight` is currently only supported for W boson plus jets production. .. _`central qqx`: **central qqx** Specifies how to treat events with a quark-antiquark pair central in rapidity, e.g. :code:`g g => g u u_bar g`. In the high-energy limit, such configurations are logarithmically suppressed compared to FKL configurations. The possible values are the same as for the `FKL`_ setting, but :code:`reweight` is currently only supported for W boson plus jets production. .. _`non-resummable`: **non-resummable** Specifies how to treat events where no resummation is possible. The allowed values are :code:`keep` to keep the events as they are up to a possible change of renormalisation and factorisation scale and :code:`discard` to discard these events. .. _`scales`: **scales** Specifies the renormalisation and factorisation scales for the output events. This can either be a single entry or a list :code:`[scale1, scale2, ...]`. For the case of a list the first entry defines the central scale. Possible values are fixed numbers to set the scale in GeV or the following: - :code:`H_T`: The sum of the scalar transverse momenta of all final-state particles - :code:`max jet pperp`: The maximum transverse momentum of all jets - :code:`jet invariant mass`: Sum of the invariant masses of all jets - :code:`m_j1j2`: Invariant mass between the two hardest jets. Scales can be multiplied or divided by overall factors, e.g. :code:`H_T/2`. It is also possible to import scales from an external library, see :ref:`Custom scales` .. _`scale factors`: **scale factors** A list of numeric factors by which each of the `scales`_ should be multiplied. Renormalisation and factorisation scales are varied independently. For example, a list with entries :code:`[0.5, 2]` would give the four scale choices (0.5μ\ :sub:`r`, 0.5μ\ :sub:`f`); (0.5μ\ :sub:`r`, 2μ\ :sub:`f`); (2μ\ :sub:`r`, 0.5μ\ :sub:`f`); (2μ\ :sub:`r`, 2μ\ :sub:`f`) in this order. The ordering corresponds to the order of the final event weights. .. _`max scale ratio`: **max scale ratio** Specifies the maximum factor by which renormalisation and factorisation scales may difer. For a value of :code:`2` and the example given for the `scale factors`_ the scale choices (0.5μ\ :sub:`r`, 2μ\ :sub:`f`) and (2μ\ :sub:`r`, 0.5μ\ :sub:`f`) will be discarded. .. _`log correction`: **log correction** Whether to include corrections due to the evolution of the strong coupling constant in the virtual corrections. Allowed values are :code:`true` and :code:`false`. .. _`event output`: **event output** Specifies the name of a single event output file or a list of such files. The file format is either specified explicitly or derived from the suffix. For example, :code:`events.lhe` or, equivalently :code:`Les Houches: events.lhe` generates an output event file :code:`events.lhe` in the Les Houches format. The supported formats are - :code:`file.lhe` or :code:`Les Houches: file`: The Les Houches event file format. - :code:`file.hepmc2` or :code:`HepMC2: file`: HepMC format version 2. - :code:`file.hepmc3` or :code:`HepMC3: file`: HepMC format version 3. - :code:`file.hepmc` or :code:`HepMC: file`: The latest supported version of the HepMC format, currently version 3. .. _`random generator`: **random generator** Sets parameters for random number generation. .. _`random generator: name`: **name** Which random number generator to use. Currently, :code:`mixmax` and :code:`ranlux64` are supported. Mixmax is recommended. See the `CLHEP documentation <http://proj-clhep.web.cern.ch/proj-clhep/index.html#docu>`_ for details on the generators. .. _`random generator: seed`: **seed** The seed for random generation. This should be a single number for :code:`mixmax` and the name of a state file for :code:`ranlux64`. .. _`analysis`: **analysis** Name and Setting for the event analyses; either a custom analysis plugin or Rivet. For the first the :code:`plugin` sub-entry should be set to the analysis file path. All further entries are passed on to the analysis. To use Rivet a list of Rivet analyses have to be given in :code:`rivet` and prefix for the yoda file has to be set through :code:`output`. See :ref:`Writing custom analyses` for details. .. _`Higgs coupling`: **Higgs coupling** This collects a number of settings concerning the effective coupling of the Higgs boson to gluons. This is only relevant for the production process of a Higgs boson with jets and only supported if HEJ 2 was compiled with `QCDLoop <https://github.com/scarrazza/qcdloop>`_ support. .. _`Higgs coupling: use impact factors`: **use impact factors** Whether to use impact factors for the coupling to the most forward and most backward partons. Impact factors imply the infinite top-quark mass limit. .. _`Higgs coupling: mt`: **mt** The value of the top-quark mass in GeV. If this is not specified, the limit of an infinite mass is taken. .. _`Higgs coupling: include bottom`: **include bottom** Whether to include the Higgs coupling to bottom quarks. .. _`Higgs coupling: mb`: **mb** The value of the bottom-quark mass in GeV. Only used for the Higgs coupling, external bottom-quarks are always assumed to be massless. Advanced Settings ~~~~~~~~~~~~~~~~~ All of the following settings are optional. Please **do not set** any of the following options, unless you know exactly what you are doing. The default behaviour gives the most reliable results for a wide range of observables. .. _`regulator parameter`: **regulator parameter** Slicing parameter to regularise the subtraction term, called :math:`\lambda` in `arxiv:1706.01002 <https://arxiv.org/abs/1706.01002>`_. Default is 0.2 diff --git a/doc/sphinx/HEJFOG.rst b/doc/sphinx/HEJFOG.rst index 70046d7..4a22e7d 100644 --- a/doc/sphinx/HEJFOG.rst +++ b/doc/sphinx/HEJFOG.rst @@ -1,311 +1,310 @@ The HEJ Fixed Order Generator ============================= For high jet multiplicities event generation with standard fixed-order generators becomes increasingly cumbersome. For example, the leading-order production of a Higgs Boson with five or more jets is computationally prohibitively expensive. To this end, HEJ 2 provides the ``HEJFOG`` fixed-order generator that allows to generate events with high jet multiplicities. To facilitate the computation the limit of Multi-Regge Kinematics with large invariant masses between all outgoing particles is assumed in the matrix elements. The typical use of the ``HEJFOG`` is to supplement low-multiplicity events from standard generators with high-multiplicity events before using the HEJ 2 program to add high-energy resummation. Installation ------------ The ``HEJFOG`` comes bundled together with HEJ 2 and the installation is very similar. After downloading HEJ 2 and installing the prerequisites as described in :ref:`Installation` the ``HEJFOG`` can be installed with:: cmake /path/to/FixedOrderGen -DCMAKE_INSTALL_PREFIX=target/directory make install where :file:`/path/to/FixedOrderGen` refers to the :file:`FixedOrderGen` subdirectory in the HEJ 2 directory. If HEJ 2 was installed to a non-standard location, it may be necessary to specify the directory containing :file:`HEJ-config.cmake`. If the base installation directory is :file:`/path/to/HEJ`, :file:`HEJ-config.cmake` should be found in :file:`/path/to/HEJ/lib/cmake/HEJ` and the commands for installing the ``HEJFOG`` would read:: cmake /path/to/FixedOrderGen -DHEJ_DIR=/path/to/HEJ/lib/cmake/HEJ -DCMAKE_INSTALL_PREFIX=target/directory make install The installation can be tested with:: make test provided that the CT10nlo PDF set is installed. Running the fixed-order generator --------------------------------- After installing the ``HEJFOG`` you can modify the provided configuration file :file:`configFO.yml` and run the generator with:: HEJFOG configFO.yml The resulting event file, by default named :file:`HEJFO.lhe`, can then be fed into HEJ 2 like any event file generated from a standard fixed-order generator, see :ref:`Running HEJ 2`. Settings -------- Similar to HEJ 2, the ``HEJFOG`` uses a `YAML <http://yaml.org/>`_ configuration file. The settings are .. _`process`: **process** The scattering process for which events are being generated. The format is :code:`in1 in2 => out1 out2 ...` The incoming particles, :code:`in1`, :code:`in2` can be - quarks: :code:`u`, :code:`d`, :code:`u_bar`, and so on - gluons: :code:`g` - protons :code:`p` or antiprotons :code:`p_bar` The outgoing particles, can be - jets: :code:`j`, multiple jets can be grouped together e.g. :code:`2j` - bosons: Any gauge boson, they require `particle properties`_ - leptons: if they can be reconstructed to a :code:`W+` or :code:`W-`, e.g. :code:`e+ nu_e` At most one of the outgoing particles can be a boson, the rest has to be partonic. At the moment only Higgs :code:`h`, :code:`W+` and :code:`W-` bosons are supported. All other outgoing particles are jets. There have to be at least two jets. Instead of the leptons decays of the bosons can be added through the :ref:`particle properties<particle properties: particle: decays>`. The latter is required to decay a Higgs boson. So :code:`p p => Wp j j` is the same as :code:`p p => e+ nu_e 2j`, if the decay :code:`Wp => e+ nu_e` is specified in `particle properties`_. .. _`events`: **events** Specifies the number of events to generate. .. _`jets`: **jets** Defines the properties of the generated jets. .. _`jets: min pt`: **min pt** Minimum jet transverse momentum in GeV. .. _`jets: peak pt`: **peak pt** Optional setting to specify the dominant jet transverse momentum in GeV. If the generated events are used as input for HEJ resummation, this should be set to the minimum transverse momentum of the resummation jets. In all cases it has to be larger than :code:`min pt`. The effect is that only a small fraction of jets will be generated with a transverse momentum below the value of this setting. .. _`jets: algorithm`: **algorithm** The algorithm used to define jets. Allowed settings are :code:`kt`, :code:`cambridge`, :code:`antikt`, :code:`cambridge for passive`. See the `FastJet <http://fastjet.fr/>`_ documentation for a description of these algorithms. .. _`jets: R`: **R** The R parameter used in the jet algorithm. .. _`jets: max rapidity`: **max rapidity** Maximum absolute value of the jet rapidity. .. _`beam`: **beam** Defines various properties of the collider beam. .. _`beam: energy`: **energy** The beam energy in GeV. For example, the 13 TeV LHC corresponds to a value of 6500. .. _`beam: particles`: **particles** A list :code:`[p1, p2]` of two beam particles. The only supported entries are protons :code:`p` and antiprotons :code:`p_bar`. .. _`pdf`: **pdf** The `LHAPDF number <https://lhapdf.hepforge.org/pdfsets>`_ of the PDF set. For example, 230000 corresponds to an NNPDF 2.3 NLO PDF set. .. _`subleading fraction`: **subleading fraction** This setting is related to the fraction of events that are not a FKL configuration. All possible subleading process are listed in :ref:`subleading channels<subleading channels>`. This value must be positive and not larger than 1. It should typically be chosen between 0.01 and 0.1. Note that while this parameter influences the chance of generating subleading configurations, it generally does not correspond to the actual fraction of subleading events. .. _`subleading channels`: **subleading channels** Optional parameters to select a specific subleading process, multiple channels can be selected at once. If multiple subleading configurations are possible one will be selected at random for each event, thus each final state will include at most one subleading process, e.g. either :code:`unordered` or :code:`qqx`. Only has an effect if :code:`subleading fraction` is non-zero. The following values are allowed: - :code:`all`: All channels allowed. This is the default. - :code:`none`: No subleading contribution, only the leading (FKL) configurations are allowed. This is equivalent to :code:`subleading fraction: 0`. - :code:`unordered`: Unordered emission allowed. Unordered emission are any rapidity ordering where exactly one gluon is emitted outside the rapidity ordering required in FKL events. More precisely, if at least one of the incoming particles is a quark or antiquark and there are more than two jets in the final state, :code:`subleading fraction` states the probability that the flavours of the outgoing particles are assigned in such a way that an unordered - configuration arises. Unordered emissions are currently not implemented - for pure jet production. + configuration arises. - :code:`qqx`: Production of a quark-antiquark pair. In the leading (FKL) configurations all partons except for the most backward and forward ones are gluons. If the :code:`qqx` channel is allowed, :code:`subleading fraction` gives the probability of emitting a quark-antiquark pair in place of two gluons that are adjacent in rapidity. Quark-antiquark pairs are currently only implemented for W boson production. .. _`unweight`: **unweight** This setting defines the parameters for the partial unweighting of events. You can disable unweighting by removing this entry from the configuration file. .. _`unweight: sample size`: **sample size** The number of weighted events used to calibrate the unweighting. A good default is to set this to the number of target `events`_. If the number of `events`_ is large this can lead to significant memory consumption and a lower value should be chosen. Contrarily, for large multiplicities the unweighting efficiency becomes worse and the sample size should be increased. .. _`unweight: max deviation`: **max deviation** Controls the range of events to which unweighting is applied. A larger value means that a larger fraction of events are unweighted. Typical values are between -1 and 1. .. _`particle properties`: **particle properties** Specifies various properties of the different particles (Higgs, W or Z). This is only relevant if the chosen `process`_ is the production of the corresponding particles with jets. E.g. for the `process`_ :code:`p p => h 2j` the :code:`mass`, :code:`width` and (optionally) :code:`decays` of the :code:`Higgs` boson are required, while all other particle properties will be ignored. .. _`particle properties: particle`: **Higgs, W+, W- or Z** The particle (Higgs, |W+|, |W-|, Z) for which the following properties are defined. .. |W+| replace:: W\ :sup:`+` .. |W-| replace:: W\ :sup:`-` .. _`particle properties: particle: mass`: **mass** The mass of the particle in GeV. .. _`particle properties: particle: width`: **width** The total decay width of the particle in GeV. .. _`particle properties: particle: decays`: **decays** Optional setting specifying the decays of the particle. Only the decay into two particles is implemented. Each decay has the form :code:`{into: [p1,p2], branching ratio: r}` where :code:`p1` and :code:`p2` are the particle names of the decay product (e.g. :code:`photon`) and :code:`r` is the branching ratio. The branching ratio is optional (:code:`1` by default). Decays of a Higgs boson are treated as the production and subsequent decay of an on-shell Higgs boson, so decays into e.g. Z bosons are not supported. In contrast W bosons are decayed off-shell, thus the branching ratio should not be changed or set to :code:`1`. .. _`scales`: **scales** Specifies the renormalisation and factorisation scales for the output events. For details, see the corresponding entry in the HEJ 2 :ref:`HEJ 2 settings`. Note that this should usually be a single value, as the weights resulting from additional scale choices will simply be ignored when adding high-energy resummation with HEJ 2. .. _`event output`: **event output** Specifies the name of a single event output file or a list of such files. See the corresponding entry in the HEJ 2 :ref:`HEJ 2 settings` for details. .. _`RanLux init`: .. _`random generator`: **random generator** Sets parameters for random number generation. See the HEJ 2 :ref:`HEJ 2 settings` for details. .. _`analysis`: **analysis** Specifies the name and settings for a custom analysis library. This can be useful to specify cuts at the fixed-order level. See the corresponding entry in the HEJ 2 :ref:`HEJ 2 settings` for details. .. _`Higgs coupling`: **Higgs coupling** This collects a number of settings concerning the effective coupling of the Higgs boson to gluons. See the corresponding entry in the HEJ 2 :ref:`HEJ 2 settings` for details. diff --git a/include/HEJ/jets.hh b/include/HEJ/jets.hh index 94ba2c5..178a631 100644 --- a/include/HEJ/jets.hh +++ b/include/HEJ/jets.hh @@ -1,257 +1,339 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ /** \file * \brief Functions computing the square of current contractions in pure jets. * * This file contains all the necessary functions to compute the - * current contractions for all valid pure jet HEJ processes. It will - * also contain some pure jet ME components used in other process ME - * calculations + * current contractions for all valid pure jet HEJ processes, which + * so far is FKL and unordered processes. It will also contain some + * pure jet ME components used in other process ME calculations * * @TODO add a namespace */ #pragma once #include <complex> #include <ostream> #include <CLHEP/Vector/LorentzVector.h> typedef std::complex<double> COM; typedef COM current[4]; typedef CLHEP::HepLorentzVector HLV; //! 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 */ double ME_qQ (HLV p1out, HLV p1in, HLV p2out, HLV 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 * * @note this can be used for qbarQ->qbarQ Scattering by inputting arguments * appropriately. */ double ME_qQbar (HLV p1out, HLV p1in, HLV p2out, HLV 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 */ double ME_qbarQbar (HLV p1out, HLV p1in, HLV p2out, HLV 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 * * @note this can be used for gq->gq Scattering by inputting arguments * appropriately. */ double ME_qg (HLV p1out, HLV p1in, HLV p2out, HLV 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 * * @note this can be used for gqbar->gqbar Scattering by inputting arguments * appropriately. */ double ME_qbarg (HLV p1out, HLV p1in, HLV p2out, HLV 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 */ double ME_gg (HLV p1out, HLV p1in, HLV p2out, HLV p2in); +//Unordered Backwards contributions: +//! Square of qQ->qQ Pure Jets Scattering Current +/** + * @param p1out Momentum of final state quark + * @param p1in Momentum of initial state quark + * @param pg Momentum of unordered gluon + * @param p2out Momentum of final state quark + * @param p2in Momentum of intial state quark + * @returns Square of the current contractions for qQ->qQ Scattering + */ +double ME_unob_qQ (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + +//! Square of qbarQ->qbarQ Pure Jets Unordered backwards Scattering Current +/** + * @param p1out Momentum of final state anti-quark + * @param p1in Momentum of initial state anti-quark + * @param pg Momentum of unordered gluon + * @param p2out Momentum of final state quark + * @param p2in Momentum of intial state quark + * @returns Square of the current contractions for qbarQ->qbarQ Scattering + * + * @note this can be used for unof contributions by inputting + * arguments appropriately. + */ +double ME_unob_qbarQ (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + +//! Square of qQbar->qQbar Pure Jets Unordered backwards Scattering Current +/** + * @param p1out Momentum of final state quark + * @param p1in Momentum of initial state quark + * @param pg Momentum of unordered gluon + * @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 + * + * @note this can be used for unof contributions by inputting + * arguments appropriately. + */ +double ME_unob_qQbar (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + +//! Square of qbarQbar->qbarQbar Pure Jets Unordered backwards Scattering Current +/** + * @param p1out Momentum of final state anti-quark + * @param p1in Momentum of initial state anti-quark + * @param pg Momentum of unordered gluon + * @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 + * + * @note this can be used for unof contributions by inputting + * arguments appropriately. + */ +double ME_unob_qbarQbar (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + +//! Square of qg->qg Pure Jets Unordered backwards Scattering Current +/** + * @param p1out Momentum of final state gluon + * @param p1in Momentum of initial state gluon + * @param pg Momentum of unordered gluon + * @param p2out Momentum of final state quark + * @param p2in Momentum of intial state quark + * @returns Square of the current contractions for qg->qg Scattering + * + * @note this can be used for unof contributions by inputting + * arguments appropriately. + */ +double ME_unob_qg (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + +//! Square of qbarg->qbarg Pure Jets Unordered backwards Scattering Current +/** + * @param p1out Momentum of final state gluon + * @param p1in Momentum of initial state gluon + * @param pg Momentum of unordered gluon + * @param p2out Momentum of final state anti-quark + * @param p2in Momentum of intial state anti-quark + * @returns Square of the current contractions for qbarg->qbarg Scattering + * + * @note this can be used for unof contributions by inputting + * arguments appropriately. + */ +double ME_unob_qbarg (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in); + /** \class CCurrent jets.hh "include/HEJ/jets.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 HLV 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(HLV p1); COM dot(CCurrent p1); COM c0,c1,c2,c3; }; /* 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 <incoming state | mu | outgoing state> /** * This is a wrapper function around \see joi() note helicity flip to * give same answer. */ void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur); //! Current <outgoing state | mu | outgoing state> /** * @param pi bra state momentum * @param heli helicity of pi * @param pj ket state momentum * @param helj helicity of pj. (must be same as heli) * @param cur reference to current which is saved. * * This function is for building <i (out)| mu |j (out)> currents. It * must be called with pi as the bra, and pj as the ket. * * @TODO Remove heli/helj and just have helicity of current as argument. */ void joo(HLV pi, bool heli, HLV pj, bool helj, current &cur); //! Current <outgoing state | mu | incoming state> /** * @param pout bra state momentum * @param helout helicity of pout * @param pin ket state momentum * @param helin helicity of pin. (must be same as helout) * @param cur reference to current which is saved. * * This function is for building <out| mu |in> currents. It must be * called with pout as the bra, and pin as the ket. jio calls this * with flipped helicity * * @TODO Remove helout/helin and just have helicity of current as argument. */ void joi(HLV pout, bool helout, HLV pin, bool helin, current &cur); //! Current <outgoing state | mu | incoming state> /** * This is a wrapper function around the void function of the same name. \see joi */ CCurrent joi (HLV pout, bool helout, HLV pin, bool helin); //! Current <incoming state | mu | outgoing state> /** * This is a wrapper function around the void function of the same name. \see jio */ CCurrent jio (HLV pout, bool helout, HLV pin, bool helin); //! Current <outgoing state | mu | outgoing state> /** * This is a wrapper function around the void function of the same name. \see joo */ CCurrent joo (HLV pout, bool helout, HLV 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(HLV const & pout, HLV const & pin); diff --git a/src/MatrixElement.cc b/src/MatrixElement.cc index cbfba22..3fbdbe7 100644 --- a/src/MatrixElement.cc +++ b/src/MatrixElement.cc @@ -1,1704 +1,1773 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/MatrixElement.hh" #include <algorithm> #include <assert.h> #include <limits> #include <math.h> #include <stddef.h> #include <unordered_map> #include <utility> #include "CLHEP/Vector/LorentzVector.h" #include "fastjet/ClusterSequence.hh" #include "HEJ/Constants.hh" #include "HEJ/Wjets.hh" #include "HEJ/Hjets.hh" #include "HEJ/jets.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/event_types.hh" #include "HEJ/Event.hh" #include "HEJ/exceptions.hh" #include "HEJ/Particle.hh" #include "HEJ/utility.hh" namespace HEJ{ double MatrixElement::omega0( double alpha_s, double mur, fastjet::PseudoJet const & q_j ) const { const double lambda = param_.regulator_lambda; const double result = - alpha_s*N_C/M_PI*log(q_j.perp2()/(lambda*lambda)); if(! param_.log_correction) return result; // use alpha_s(sqrt(q_j*lambda)), evolved to mur return ( 1. + alpha_s/(4.*M_PI)*beta0*log(mur*mur/(q_j.perp()*lambda)) )*result; } Weights MatrixElement::operator()(Event const & event) const { return tree(event)*virtual_corrections(event); } Weights MatrixElement::tree(Event const & event) const { return tree_param(event)*tree_kin(event); } Weights MatrixElement::tree_param(Event const & event) const { if(! is_resummable(event.type())) { return Weights{0., std::vector<double>(event.variations().size(), 0.)}; } Weights result; // only compute once for each renormalisation scale std::unordered_map<double, double> known; result.central = tree_param(event, event.central().mur); known.emplace(event.central().mur, result.central); for(auto const & var: event.variations()) { const auto ME_it = known.find(var.mur); if(ME_it == end(known)) { const double wt = tree_param(event, var.mur); result.variations.emplace_back(wt); known.emplace(var.mur, wt); } else { result.variations.emplace_back(ME_it->second); } } return result; } Weights MatrixElement::virtual_corrections(Event const & event) const { if(! is_resummable(event.type())) { return Weights{0., std::vector<double>(event.variations().size(), 0.)}; } Weights result; // only compute once for each renormalisation scale std::unordered_map<double, double> known; result.central = virtual_corrections(event, event.central().mur); known.emplace(event.central().mur, result.central); for(auto const & var: event.variations()) { const auto ME_it = known.find(var.mur); if(ME_it == end(known)) { const double wt = virtual_corrections(event, var.mur); result.variations.emplace_back(wt); known.emplace(var.mur, wt); } else { result.variations.emplace_back(ME_it->second); } } return result; } double MatrixElement::virtual_corrections_W( Event const & event, double mur, Particle const & WBoson ) const{ auto const & in = event.incoming(); const auto partons = filter_partons(event.outgoing()); fastjet::PseudoJet const & pa = in.front().p; #ifndef NDEBUG fastjet::PseudoJet const & pb = in.back().p; double const norm = (in.front().p + in.back().p).E(); #endif assert(std::is_sorted(partons.begin(), partons.end(), rapidity_less{})); assert(partons.size() >= 2); assert(pa.pz() < pb.pz()); fastjet::PseudoJet q = pa - partons[0].p; size_t first_idx = 0; size_t last_idx = partons.size() - 1; bool wc = true; bool wqq = false; // With extremal qqx or unordered gluon outside the extremal // partons then it is not part of the FKL ladder and does not // contribute to the virtual corrections. W emitted from the // most backward leg must be taken into account in t-channel if (event.type() == event_type::FKL) { if (in[0].type != partons[0].type ){ q -= WBoson.p; wc = false; } } else if (event.type() == event_type::unob) { q -= partons[1].p; ++first_idx; if (in[0].type != partons[1].type ){ q -= WBoson.p; wc = false; } } else if (event.type() == event_type::qqxexb) { q -= partons[1].p; ++first_idx; if (abs(partons[0].type) != abs(partons[1].type)){ q -= WBoson.p; wc = false; } } if(event.type() == event_type::unof || event.type() == event_type::qqxexf){ --last_idx; } size_t first_idx_qqx = last_idx; size_t last_idx_qqx = last_idx; //if qqxMid event, virtual correction do not occur between //qqx pair. if(event.type() == event_type::qqxmid){ const auto backquark = std::find_if( begin(partons) + 1, end(partons) - 1 , [](Particle const & s){ return (s.type != pid::gluon); } ); if(backquark == end(partons) || (backquark+1)->type==pid::gluon) return 0; if(abs(backquark->type) != abs((backquark+1)->type)) { wqq=true; wc=false; } last_idx = std::distance(begin(partons), backquark); first_idx_qqx = last_idx+1; } double exponent = 0; const double alpha_s = alpha_s_(mur); for(size_t j = first_idx; j < last_idx; ++j){ exponent += omega0(alpha_s, mur, q)*( partons[j+1].rapidity() - partons[j].rapidity() ); q -=partons[j+1].p; } // End Loop one if (last_idx != first_idx_qqx) q -= partons[last_idx+1].p; if (wqq) q -= WBoson.p; for(size_t j = first_idx_qqx; j < last_idx_qqx; ++j){ exponent += omega0(alpha_s, mur, q)*( partons[j+1].rapidity() - partons[j].rapidity() ); q -= partons[j+1].p; } if (wc) q -= WBoson.p; assert( nearby(q, -1*pb, norm) || is_AWZH_boson(partons.back().type) || event.type() == event_type::unof || event.type() == event_type::qqxexf ); return exp(exponent); } double MatrixElement::virtual_corrections( Event const & event, double mur ) const{ auto const & in = event.incoming(); auto const & out = event.outgoing(); fastjet::PseudoJet const & pa = in.front().p; #ifndef NDEBUG fastjet::PseudoJet const & pb = in.back().p; double const norm = (in.front().p + in.back().p).E(); #endif const auto AWZH_boson = std::find_if( begin(out), end(out), [](Particle const & p){ return is_AWZH_boson(p); } ); if(AWZH_boson != end(out) && abs(AWZH_boson->type) == pid::Wp){ return virtual_corrections_W(event, mur, *AWZH_boson); } assert(std::is_sorted(out.begin(), out.end(), rapidity_less{})); assert(out.size() >= 2); assert(pa.pz() < pb.pz()); fastjet::PseudoJet q = pa - out[0].p; size_t first_idx = 0; size_t last_idx = out.size() - 1; // if there is a Higgs boson, extremal qqx or unordered gluon // outside the extremal partons then it is not part of the FKL // ladder and does not contribute to the virtual corrections if((out.front().type == pid::Higgs) || event.type() == event_type::unob || event.type() == event_type::qqxexb){ q -= out[1].p; ++first_idx; } if((out.back().type == pid::Higgs) || event.type() == event_type::unof || event.type() == event_type::qqxexf){ --last_idx; } size_t first_idx_qqx = last_idx; size_t last_idx_qqx = last_idx; //if qqxMid event, virtual correction do not occur between //qqx pair. if(event.type() == event_type::qqxmid){ const auto backquark = std::find_if( begin(out) + 1, end(out) - 1 , [](Particle const & s){ return (s.type != pid::gluon && is_parton(s.type)); } ); if(backquark == end(out) || (backquark+1)->type==pid::gluon) return 0; last_idx = std::distance(begin(out), backquark); first_idx_qqx = last_idx+1; } double exponent = 0; const double alpha_s = alpha_s_(mur); for(size_t j = first_idx; j < last_idx; ++j){ exponent += omega0(alpha_s, mur, q)*( out[j+1].rapidity() - out[j].rapidity() ); q -= out[j+1].p; } if (last_idx != first_idx_qqx) q -= out[last_idx+1].p; for(size_t j = first_idx_qqx; j < last_idx_qqx; ++j){ exponent += omega0(alpha_s, mur, q)*( out[j+1].rapidity() - out[j].rapidity() ); q -= out[j+1].p; } assert( nearby(q, -1*pb, norm) || out.back().type == pid::Higgs || event.type() == event_type::unof || event.type() == event_type::qqxexf ); return exp(exponent); } } // namespace HEJ namespace { //! Lipatov vertex for partons emitted into extremal jets double C2Lipatov( CLHEP::HepLorentzVector const & qav, CLHEP::HepLorentzVector const & qbv, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & p2 ){ CLHEP::HepLorentzVector temptrans=-(qav+qbv); CLHEP::HepLorentzVector p5=qav-qbv; CLHEP::HepLorentzVector CL=temptrans + p1*(qav.m2()/p5.dot(p1) + 2.*p5.dot(p2)/p1.dot(p2)) - p2*(qbv.m2()/p5.dot(p2) + 2.*p5.dot(p1)/p1.dot(p2)); return -CL.dot(CL); } //! Lipatov vertex with soft subtraction for partons emitted into extremal jets double C2Lipatovots( CLHEP::HepLorentzVector const & qav, CLHEP::HepLorentzVector const & qbv, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & p2, double lambda ) { double kperp=(qav-qbv).perp(); if (kperp>lambda) return C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2()); double Cls=(C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2())); return Cls-4./(kperp*kperp); } //! Lipatov vertex double C2Lipatov( // B CLHEP::HepLorentzVector const & qav, CLHEP::HepLorentzVector const & qbv, CLHEP::HepLorentzVector const & pim, CLHEP::HepLorentzVector const & pip, CLHEP::HepLorentzVector const & pom, CLHEP::HepLorentzVector const & pop ){ CLHEP::HepLorentzVector temptrans=-(qav+qbv); CLHEP::HepLorentzVector p5=qav-qbv; CLHEP::HepLorentzVector CL=temptrans + qav.m2()*(1./p5.dot(pip)*pip + 1./p5.dot(pop)*pop)/2. - qbv.m2()*(1./p5.dot(pim)*pim + 1./p5.dot(pom)*pom)/2. + ( pip*(p5.dot(pim)/pip.dot(pim) + p5.dot(pom)/pip.dot(pom)) + pop*(p5.dot(pim)/pop.dot(pim) + p5.dot(pom)/pop.dot(pom)) - pim*(p5.dot(pip)/pip.dot(pim) + p5.dot(pop)/pop.dot(pim)) - pom*(p5.dot(pip)/pip.dot(pom) + p5.dot(pop)/pop.dot(pom)) )/2.; return -CL.dot(CL); } //! Lipatov vertex with soft subtraction double C2Lipatovots( CLHEP::HepLorentzVector const & qav, CLHEP::HepLorentzVector const & qbv, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & p2, double lambda ) { double kperp=(qav-qbv).perp(); if (kperp>lambda) return C2Lipatov(qav, qbv, pa, pb, p1, p2)/(qav.m2()*qbv.m2()); double Cls=(C2Lipatov(qav, qbv, pa, pb, p1, p2)/(qav.m2()*qbv.m2())); double temp=Cls-4./(kperp*kperp); return temp; } /** Matrix element squared for tree-level current-current scattering * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID + * @param pg Unordered gluon momentum + * @param pn Particle n Momentum + * @param pb Particle b Momentum + * @param p1 Particle 1 Momentum + * @param pa Particle a Momentum + * @returns ME Squared for Tree-Level Current-Current Scattering + */ + double ME_uno_current( + int aptype, int bptype, + CLHEP::HepLorentzVector const & pg, + CLHEP::HepLorentzVector const & pn, + CLHEP::HepLorentzVector const & pb, + CLHEP::HepLorentzVector const & p1, + CLHEP::HepLorentzVector const & pa + ){ + assert(aptype!=21); // aptype cannot be gluon + if (bptype==21) { + if (aptype > 0) + return ME_unob_qg(pg,p1,pa,pn,pb); + else + return ME_unob_qbarg(pg,p1,pa,pn,pb); + } + else if (bptype<0) { // ----- || ----- + if (aptype > 0) + return ME_unob_qQbar(pg,p1,pa,pn,pb); + else + return ME_unob_qbarQbar(pg,p1,pa,pn,pb); + } + else { //bptype == quark + if (aptype > 0) + return ME_unob_qQ(pg,p1,pa,pn,pb); + else + return ME_unob_qbarQ(pg,p1,pa,pn,pb); + } + } + + /** Matrix element squared for tree-level current-current scattering + * @param aptype Particle a PDG ID + * @param bptype Particle b PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @returns ME Squared for Tree-Level Current-Current Scattering */ double ME_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa ){ if (aptype==21&&bptype==21) { return ME_gg(pn,pb,p1,pa); } else if (aptype==21&&bptype!=21) { if (bptype > 0) return ME_qg(pn,pb,p1,pa); else return ME_qbarg(pn,pb,p1,pa); } else if (bptype==21&&aptype!=21) { // ----- || ----- if (aptype > 0) return ME_qg(p1,pa,pn,pb); else return ME_qbarg(p1,pa,pn,pb); } else { // they are both quark if (bptype>0) { if (aptype>0) return ME_qQ(pn,pb,p1,pa); else return ME_qQbar(pn,pb,p1,pa); } else { if (aptype>0) return ME_qQbar(p1,pa,pn,pb); else return ME_qbarQbar(pn,pb,p1,pa); } } throw std::logic_error("unknown particle types"); } /** Matrix element squared for tree-level current-current scattering With W+Jets * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @param wc Boolean. True->W Emitted from b. Else; emitted from leg a * @returns ME Squared for Tree-Level Current-Current Scattering */ double ME_W_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wc ){ // We know it cannot be gg incoming. assert(!(aptype==21 && bptype==21)); if (aptype==21&&bptype!=21) { if (bptype > 0) return ME_W_qg(pn,plbar,pl,pb,p1,pa); else return ME_W_qbarg(pn,plbar,pl,pb,p1,pa); } else if (bptype==21&&aptype!=21) { // ----- || ----- if (aptype > 0) return ME_W_qg(p1,plbar,pl,pa,pn,pb); else return ME_W_qbarg(p1,plbar,pl,pa,pn,pb); } else { // they are both quark if (wc==true){ // emission off b, (first argument pbout) if (bptype>0) { if (aptype>0) return ME_W_qQ(pn,plbar,pl,pb,p1,pa); else return ME_W_qQbar(pn,plbar,pl,pb,p1,pa); } else { if (aptype>0) return ME_W_qbarQ(pn,plbar,pl,pb,p1,pa); else return ME_W_qbarQbar(pn,plbar,pl,pb,p1,pa); } } else{ // emission off a, (first argument paout) if (aptype > 0) { if (bptype > 0) return ME_W_qQ(p1,plbar,pl,pa,pn,pb); else return ME_W_qQbar(p1,plbar,pl,pa,pn,pb); } else { // a is anti-quark if (bptype > 0) return ME_W_qbarQ(p1,plbar,pl,pa,pn,pb); else return ME_W_qbarQbar(p1,plbar,pl,pa,pn,pb); } } } throw std::logic_error("unknown particle types"); } /** Matrix element squared for backwards uno tree-level current-current * scattering With W+Jets * * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @param pg Unordered gluon momentum * @param wc Boolean. True->W Emitted from b. Else; emitted from leg a * @returns ME Squared for unob Tree-Level Current-Current Scattering */ double ME_W_unob_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pg, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wc ){ // we know they are not both gluons if (bptype == 21 && aptype != 21) { // b gluon => W emission off a if (aptype > 0) return ME_Wuno_qg(p1,pa,pn,pb,pg,plbar,pl); else return ME_Wuno_qbarg(p1,pa,pn,pb,pg,plbar,pl); } else { // they are both quark if (wc) {// emission off b, i.e. b is first current if (bptype>0){ if (aptype>0) return ME_W_unob_qQ(p1,pa,pn,pb,pg,plbar,pl); else return ME_W_unob_qQbar(p1,pa,pn,pb,pg,plbar,pl); } else{ if (aptype>0) return ME_W_unob_qbarQ(p1,pa,pn,pb,pg,plbar,pl); else return ME_W_unob_qbarQbar(p1,pa,pn,pb,pg,plbar,pl); } } else {// wc == false, emission off a, i.e. a is first current if (aptype > 0) { if (bptype > 0) //qq return ME_Wuno_qQ(p1,pa,pn,pb,pg,plbar,pl); else //qqbar return ME_Wuno_qQbar(p1,pa,pn,pb,pg,plbar,pl); } else { // a is anti-quark if (bptype > 0) //qbarq return ME_Wuno_qbarQ(p1,pa,pn,pb,pg,plbar,pl); else //qbarqbar return ME_Wuno_qbarQbar(p1,pa,pn,pb,pg,plbar,pl); } } } throw std::logic_error("unknown particle types"); } /** Matrix element squared for uno forward tree-level current-current * scattering With W+Jets * * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @param pg Unordered gluon momentum * @param wc Boolean. True->W Emitted from b. Else; emitted from leg a * @returns ME Squared for unof Tree-Level Current-Current Scattering */ double ME_W_unof_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pg, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wc ){ // we know they are not both gluons if (aptype==21 && bptype!=21) {//a gluon => W emission off b if (bptype > 0) return ME_Wuno_qg(pn, pb, p1, pa, pg, plbar, pl); else return ME_Wuno_qbarg(pn, pb, p1, pa, pg, plbar, pl); } else { // they are both quark if (wc) {// emission off b, i.e. b is first current if (bptype>0){ if (aptype>0) return ME_Wuno_qQ(pn, pb, p1, pa, pg, plbar, pl); else return ME_Wuno_qQbar(pn, pb, p1, pa, pg, plbar, pl); } else{ if (aptype>0) return ME_Wuno_qbarQ(pn, pb, p1, pa, pg, plbar, pl); else return ME_Wuno_qbarQbar(pn, pb, p1, pa, pg, plbar, pl); } } else {// wc == false, emission off a, i.e. a is first current if (aptype > 0) { if (bptype > 0) //qq return ME_W_unof_qQ(p1, pa, pn, pb, pg, plbar, pl); - // return ME_W_unof_qQ(pn,pb,p1,pa,pg,plbar,pl); else //qqbar return ME_W_unof_qQbar(p1, pa, pn, pb, pg, plbar, pl); } else { // a is anti-quark if (bptype > 0) //qbarq return ME_W_unof_qbarQ(p1, pa, pn, pb, pg, plbar, pl); else //qbarqbar return ME_W_unof_qbarQbar(p1, pa, pn, pb, pg, plbar, pl); } } } throw std::logic_error("unknown particle types"); } /** \brief Matrix element squared for backward qqx tree-level current-current * scattering With W+Jets * * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pa Initial state a Momentum * @param pb Initial state b Momentum * @param pq Final state q Momentum * @param pqbar Final state qbar Momentum * @param pn Final state n Momentum * @param plbar Final state anti-lepton momentum * @param pl Final state lepton momentum * @param wc Boolean. True->W Emitted from b. Else; emitted from leg a * @returns ME Squared for qqxb Tree-Level Current-Current Scattering */ double ME_W_qqxb_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & pq, CLHEP::HepLorentzVector const & pqbar, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wc ){ // CAM factors for the qqx amps, and qqbar ordering (default, qbar extremal) bool swapQuarkAntiquark=false; double CFbackward; if (pqbar.rapidity() > pq.rapidity()){ swapQuarkAntiquark=true; CFbackward = (0.5*(3.-1./3.)*(pa.minus()/(pq.minus())+(pq.minus())/pa.minus())+1./3.)*3./4.; } else{ CFbackward = (0.5*(3.-1./3.)*(pa.minus()/(pqbar.minus())+(pqbar.minus())/pa.minus())+1./3.)*3./4.; } // With qqbar we could have 2 incoming gluons and W Emission if (aptype==21&&bptype==21) {//a gluon, b gluon gg->qqbarWg // This will be a wqqx emission as there is no other possible W Emission Site. if (swapQuarkAntiquark) return ME_WExqqx_qqbarg(pa, pqbar, plbar, pl, pq, pn, pb)*CFbackward; else return ME_WExqqx_qbarqg(pa, pq, plbar, pl, pqbar, pn, pb)*CFbackward; } else if (aptype==21&&bptype!=21 ) {//a gluon => W emission off b leg or qqx if (!wc){ // W Emitted from backwards qqx if (swapQuarkAntiquark) return ME_WExqqx_qqbarQ(pa, pqbar, plbar, pl, pq, pn, pb)*CFbackward; else return ME_WExqqx_qbarqQ(pa, pq, plbar, pl, pqbar, pn, pb)*CFbackward; } else { // W Must be emitted from forwards leg. if(bptype > 0){ if (swapQuarkAntiquark) return ME_W_Exqqx_QQq(pb, pa, pn, pqbar, pq, plbar, pl, false)*CFbackward; else return ME_W_Exqqx_QQq(pb, pa, pn, pq, pqbar, plbar, pl, false)*CFbackward; } else { if (swapQuarkAntiquark) return ME_W_Exqqx_QQq(pb, pa, pn, pqbar, pq, plbar, pl, true)*CFbackward; else return ME_W_Exqqx_QQq(pb, pa, pn, pq, pqbar, plbar, pl, true)*CFbackward; } } } throw std::logic_error("Incompatible incoming particle types with qqxb"); } /* \brief Matrix element squared for forward qqx tree-level current-current * scattering With W+Jets * * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pa Initial state a Momentum * @param pb Initial state b Momentum * @param pq Final state q Momentum * @param pqbar Final state qbar Momentum * @param p1 Final state 1 Momentum * @param plbar Final state anti-lepton momentum * @param pl Final state lepton momentum * @param wc Boolean. True->W Emitted from b. Else; emitted from leg a * @returns ME Squared for qqxf Tree-Level Current-Current Scattering */ double ME_W_qqxf_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & pq, CLHEP::HepLorentzVector const & pqbar, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wc ){ // CAM factors for the qqx amps, and qqbar ordering (default, qbar extremal) bool swapQuarkAntiquark=false; double CFforward; if (pqbar.rapidity() < pq.rapidity()){ swapQuarkAntiquark=true; CFforward = (0.5*(3.-1./3.)*(pb.plus()/(pq.plus())+(pq.plus())/pb.plus())+1./3.)*3./4.; } else{ CFforward = (0.5*(3.-1./3.)*(pb.plus()/(pqbar.plus())+(pqbar.plus())/pb.plus())+1./3.)*3./4.; } // With qqbar we could have 2 incoming gluons and W Emission if (aptype==21&&bptype==21) {//a gluon, b gluon gg->qqbarWg // This will be a wqqx emission as there is no other possible W Emission Site. if (swapQuarkAntiquark) return ME_WExqqx_qqbarg(pb, pqbar, plbar, pl, pq, p1, pa)*CFforward; else return ME_WExqqx_qbarqg(pb, pq, plbar, pl, pqbar, p1, pa)*CFforward; } else if (bptype==21&&aptype!=21) {// b gluon => W emission off a or qqx if (wc){ // W Emitted from forwards qqx if (swapQuarkAntiquark) return ME_WExqqx_qqbarQ(pb, pqbar, plbar, pl, pq, p1, pa)*CFforward; else return ME_WExqqx_qbarqQ(pb, pq, plbar, pl, pqbar, p1, pa)*CFforward; } // W Must be emitted from backwards leg. if (aptype > 0){ if (swapQuarkAntiquark) return ME_W_Exqqx_QQq(pa, pb, p1, pqbar, pq, plbar, pl, false)*CFforward; else return ME_W_Exqqx_QQq(pa, pb, p1, pq, pqbar, plbar, pl, false)*CFforward; } else { if (swapQuarkAntiquark) return ME_W_Exqqx_QQq(pa, pb, p1, pqbar, pq, plbar, pl, true)*CFforward; else return ME_W_Exqqx_QQq(pa, pb, p1, pq, pqbar, plbar, pl, true)*CFforward; } } throw std::logic_error("Incompatible incoming particle types with qqxf"); } /* \brief Matrix element squared for central qqx tree-level current-current * scattering With W+Jets * * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param nabove Number of gluons emitted before central qqxpair * @param nbelow Number of gluons emitted after central qqxpair * @param pa Initial state a Momentum * @param pb Initial state b Momentum\ * @param pq Final state qbar Momentum * @param pqbar Final state q Momentum * @param partons Vector of all outgoing partons * @param plbar Final state anti-lepton momentum * @param pl Final state lepton momentum * @param wqq Boolean. True siginfies W boson is emitted from Central qqx * @param wc Boolean. wc=true signifies w boson emitted from leg b; if wqq=false. * @returns ME Squared for qqxmid Tree-Level Current-Current Scattering */ double ME_W_qqxmid_current( int aptype, int bptype, int nabove, int nbelow, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & pq, CLHEP::HepLorentzVector const & pqbar, std::vector<HLV> const & partons, CLHEP::HepLorentzVector const & plbar, CLHEP::HepLorentzVector const & pl, bool const wqq, bool const wc ){ // CAM factors for the qqx amps, and qqbar ordering (default, pq backwards) bool swapQuarkAntiquark=false; if (pqbar.rapidity() < pq.rapidity()){ swapQuarkAntiquark=true; } double wt=1.; if (aptype==21) wt*=K_g(partons.front(),pa)/HEJ::C_F; if (bptype==21) wt*=K_g(partons.back(),pb)/HEJ::C_F; if (aptype <=0 && bptype <=0){ // Both External AntiQuark if (wqq==1){//emission from central qqbar return wt*ME_WCenqqx_qq(pa, pb, pl, plbar, partons,true,true, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, true,true, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*ME_W_Cenqqx_qq(pa, pb, pl,plbar, partons, true,true, swapQuarkAntiquark, nabove, nbelow, false); } } // end both antiquark else if (aptype<=0){ // a is antiquark if (wqq==1){//emission from central qqbar return wt*ME_WCenqqx_qq(pa, pb, pl, plbar, partons, false, true, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons,false,true, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, false, true, swapQuarkAntiquark, nabove, nbelow, false); } } // end a is antiquark else if (bptype<=0){ // b is antiquark if (wqq==1){//emission from central qqbar return wt*ME_WCenqqx_qq(pa, pb, pl, plbar, partons, true, false, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, true, false, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, true, false, swapQuarkAntiquark, nabove, nbelow, false); } } //end b is antiquark else{ //Both Quark or gluon if (wqq==1){//emission from central qqbar return wt*ME_WCenqqx_qq(pa, pb, pl, plbar, partons, false, false, swapQuarkAntiquark, nabove);} else if (wc==1){//emission from b leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, false, false, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*ME_W_Cenqqx_qq(pa, pb, pl, plbar, partons, false, false, swapQuarkAntiquark, nabove, nbelow, false); } } throw std::logic_error("unknown particle types"); } /** \brief Matrix element squared for tree-level current-current scattering with Higgs * @param aptype Particle a PDG ID * @param bptype Particle b PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @param qH t-channel momentum before Higgs * @param qHp1 t-channel momentum after Higgs * @returns ME Squared for Tree-Level Current-Current Scattering with Higgs */ double ME_Higgs_current( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & qH, // t-channel momentum before Higgs CLHEP::HepLorentzVector const & qHp1, // t-channel momentum after Higgs double mt, bool include_bottom, double mb ){ if (aptype==21&&bptype==21) // gg initial state return ME_H_gg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else if (aptype==21&&bptype!=21) { if (bptype > 0) return ME_H_qg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.; else return ME_H_qbarg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.; } else if (bptype==21&&aptype!=21) { if (aptype > 0) return ME_H_qg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.; else return ME_H_qbarg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.; } else { // they are both quark if (bptype>0) { if (aptype>0) return ME_H_qQ(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.); else return ME_H_qQbar(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.); } else { if (aptype>0) return ME_H_qQbar(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4.*4./(9.*9.); else return ME_H_qbarQbar(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.); } } throw std::logic_error("unknown particle types"); } /** \brief Current matrix element squared with Higgs and unordered backward emission * @param aptype Particle A PDG ID * @param bptype Particle B PDG ID * @param pn Particle n Momentum * @param pb Particle b Momentum * @param pg Unordered back Particle Momentum * @param p1 Particle 1 Momentum * @param pa Particle a Momentum * @param qH t-channel momentum before Higgs * @param qHp1 t-channel momentum after Higgs * @returns ME Squared with Higgs and unordered backward emission * * @note This function assumes unordered gluon backwards from pa-p1 current. * For unof, reverse call order */ double ME_Higgs_current_uno( int aptype, int bptype, CLHEP::HepLorentzVector const & pg, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & qH, // t-channel momentum before Higgs CLHEP::HepLorentzVector const & qHp1, // t-channel momentum after Higgs double mt, bool include_bottom, double mb ){ if (bptype==21&&aptype!=21) { if (aptype > 0) return ME_H_unob_gQ(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); else return ME_H_unob_gQbar(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); } else { // they are both quark if (aptype>0) { if (bptype>0) return ME_H_unob_qQ(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); else return ME_H_unob_qbarQ(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); } else { if (bptype>0) return ME_H_unob_qQbar(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); else return ME_H_unob_qbarQbar(pg,p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb); } } throw std::logic_error("unknown particle types"); } CLHEP::HepLorentzVector to_HepLorentzVector(HEJ::Particle const & particle){ return {particle.p.px(), particle.p.py(), particle.p.pz(), particle.p.E()}; } void validate(HEJ::MatrixElementConfig const & config) { #ifndef HEJ_BUILD_WITH_QCDLOOP if(!config.Higgs_coupling.use_impact_factors) { throw std::invalid_argument{ "Invalid Higgs coupling settings.\n" "HEJ without QCDloop support can only use impact factors.\n" "Set use_impact_factors to true or recompile HEJ.\n" }; } #endif if(config.Higgs_coupling.use_impact_factors && config.Higgs_coupling.mt != std::numeric_limits<double>::infinity()) { throw std::invalid_argument{ "Conflicting settings: " "impact factors may only be used in the infinite top mass limit" }; } } } // namespace anonymous namespace HEJ{ MatrixElement::MatrixElement( std::function<double (double)> alpha_s, MatrixElementConfig conf ): alpha_s_{std::move(alpha_s)}, param_{std::move(conf)} { validate(param_); } double MatrixElement::tree_kin( Event const & ev ) const { if(! is_resummable(ev.type())) return 0.; auto AWZH_boson = std::find_if( begin(ev.outgoing()), end(ev.outgoing()), [](Particle const & p){return is_AWZH_boson(p);} ); if(AWZH_boson == end(ev.outgoing())) return tree_kin_jets(ev); switch(AWZH_boson->type){ case pid::Higgs: return tree_kin_Higgs(ev); case pid::Wp: case pid::Wm: return tree_kin_W(ev); // TODO case pid::photon: case pid::Z: default: throw not_implemented("Emission of boson of unsupported type"); } } namespace{ constexpr int extremal_jet_idx = 1; constexpr int no_extremal_jet_idx = 0; bool treat_as_extremal(Particle const & parton){ return parton.p.user_index() == extremal_jet_idx; } template<class InputIterator> double FKL_ladder_weight( InputIterator begin_gluon, InputIterator end_gluon, CLHEP::HepLorentzVector const & q0, CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pn, double lambda ){ double wt = 1; auto qi = q0; for(auto gluon_it = begin_gluon; gluon_it != end_gluon; ++gluon_it){ assert(gluon_it->type == pid::gluon); const auto g = to_HepLorentzVector(*gluon_it); const auto qip1 = qi - g; if(treat_as_extremal(*gluon_it)){ wt *= C2Lipatovots(qip1, qi, pa, pb, lambda)*C_A; } else{ wt *= C2Lipatovots(qip1, qi, pa, pb, p1, pn, lambda)*C_A; } qi = qip1; } return wt; } } // namespace anonymous std::vector<Particle> MatrixElement::tag_extremal_jet_partons( Event const & ev ) const{ auto out_partons = filter_partons(ev.outgoing()); if(out_partons.size() == ev.jets().size()){ // no additional emissions in extremal jets, don't need to tag anything for(auto & parton: out_partons){ parton.p.set_user_index(no_extremal_jet_idx); } return out_partons; } // TODO: avoid reclustering fastjet::ClusterSequence cs(to_PseudoJet(out_partons), ev.jet_def()); const auto jets = sorted_by_rapidity(cs.inclusive_jets(ev.min_jet_pt())); assert(jets.size() >= 2); auto most_backward = begin(jets); auto most_forward = end(jets) - 1; // skip jets caused by unordered emission or qqx if(ev.type() == event_type::unob || ev.type() == event_type::qqxexb){ assert(jets.size() >= 3); ++most_backward; } else if(ev.type() == event_type::unof || ev.type() == event_type::qqxexf){ assert(jets.size() >= 3); --most_forward; } const auto extremal_jet_indices = cs.particle_jet_indices( {*most_backward, *most_forward} ); assert(extremal_jet_indices.size() == out_partons.size()); for(size_t i = 0; i < out_partons.size(); ++i){ assert(HEJ::is_parton(out_partons[i])); const int idx = (extremal_jet_indices[i]>=0)? extremal_jet_idx: no_extremal_jet_idx; out_partons[i].p.set_user_index(idx); } return out_partons; } + namespace { + template<class InIter, class partIter> + double tree_kin_jets_uno(InIter BeginIn, InIter EndIn, partIter BeginPart, + partIter EndPart, double lambda){ + + const auto pa = to_HepLorentzVector(*BeginIn); + const auto pb = to_HepLorentzVector(*(EndIn-1)); + + const auto pg = to_HepLorentzVector(*BeginPart); + const auto p1 = to_HepLorentzVector(*(BeginPart+1)); + const auto pn = to_HepLorentzVector(*(EndPart-1)); + + const double current_factor = ME_uno_current( + (BeginIn)->type, (EndIn-1)->type, pg, pn, pb, p1, pa + )/(4.*(N_C*N_C - 1.)); + const double ladder_factor = FKL_ladder_weight( + (BeginPart+2), (EndPart-1), + pa-p1-pg, pa, pb, p1, pn, lambda + ); + + return current_factor*ladder_factor; + } + } + double MatrixElement::tree_kin_jets(Event const & ev) const { auto const & incoming = ev.incoming(); const auto partons = tag_extremal_jet_partons(ev); - if(is_uno(ev.type())){ - throw not_implemented("unordered emission not implemented for pure jets"); - } + if (ev.type()==HEJ::event_type::unordered_backward){ + return tree_kin_jets_uno(incoming.begin(), incoming.end(), + partons.begin(), partons.end(), + param_.regulator_lambda); + } + else if (ev.type()==HEJ::event_type::unordered_forward){ + return tree_kin_jets_uno(incoming.rbegin(), incoming.rend(), + partons.rbegin(), partons.rend(), + param_.regulator_lambda); + } const auto pa = to_HepLorentzVector(incoming[0]); const auto pb = to_HepLorentzVector(incoming[1]); const auto p1 = to_HepLorentzVector(partons.front()); const auto pn = to_HepLorentzVector(partons.back()); return ME_current( incoming[0].type, incoming[1].type, pn, pb, p1, pa )/(4.*(N_C*N_C - 1.))*FKL_ladder_weight( begin(partons) + 1, end(partons) - 1, pa - p1, pa, pb, p1, pn, param_.regulator_lambda ); } namespace{ double tree_kin_W_FKL( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ auto p1 = to_HepLorentzVector(partons[0]); auto pn = to_HepLorentzVector(partons[partons.size() - 1]); const auto begin_ladder = cbegin(partons) + 1; const auto end_ladder = cend(partons) - 1; bool wc = aptype==partons[0].type; //leg b emits w auto q0 = pa - p1; if(!wc) q0 -= pl + plbar; const double current_factor = ME_W_current( aptype, bptype, pn, pb, p1, pa, plbar, pl, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder, q0, pa, pb, p1, pn, lambda ); return current_factor*ladder_factor; } double tree_kin_W_unob( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ auto pg = to_HepLorentzVector(partons[0]); auto p1 = to_HepLorentzVector(partons[1]); auto pn = to_HepLorentzVector(partons[partons.size() - 1]); const auto begin_ladder = cbegin(partons) + 2; const auto end_ladder = cend(partons) - 1; bool wc = aptype==partons[1].type; //leg b emits w auto q0 = pa - p1 -pg; if(!wc) q0 -= pl + plbar; const double current_factor = ME_W_unob_current( aptype, bptype, pn, pb, p1, pa, pg, plbar, pl, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder, q0, pa, pb, p1, pn, lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } double tree_kin_W_unof( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ auto p1 = to_HepLorentzVector(partons[0]); auto pn = to_HepLorentzVector(partons[partons.size() - 2]); auto pg = to_HepLorentzVector(partons[partons.size() - 1]); const auto begin_ladder = cbegin(partons) + 1; const auto end_ladder = cend(partons) - 2; bool wc = aptype==partons[0].type; //leg b emits w auto q0 = pa - p1; if(!wc) q0 -= pl + plbar; const double current_factor = ME_W_unof_current( aptype, bptype, pn, pb, p1, pa, pg, plbar, pl, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder, q0, pa, pb, p1, pn, lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } double tree_kin_W_qqxb( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ HLV pq,pqbar; if(is_quark(partons[0])){ pq = to_HepLorentzVector(partons[0]); pqbar = to_HepLorentzVector(partons[1]); } else{ pq = to_HepLorentzVector(partons[1]); pqbar = to_HepLorentzVector(partons[0]); } auto p1 = to_HepLorentzVector(partons[0]); auto pn = to_HepLorentzVector(partons[partons.size() - 1]); const auto begin_ladder = cbegin(partons) + 2; const auto end_ladder = cend(partons) - 1; bool wc = bptype!=partons.back().type; //leg b emits w auto q0 = pa - pq - pqbar; if(!wc) q0 -= pl + plbar; const double current_factor = ME_W_qqxb_current( aptype, bptype, pa, pb, pq, pqbar, pn, plbar, pl, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder, q0, pa, pb, p1, pn, lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } double tree_kin_W_qqxf( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ HLV pq,pqbar; if(is_quark(partons[partons.size() - 1])){ pq = to_HepLorentzVector(partons[partons.size() - 1]); pqbar = to_HepLorentzVector(partons[partons.size() - 2]); } else{ pq = to_HepLorentzVector(partons[partons.size() - 2]); pqbar = to_HepLorentzVector(partons[partons.size() - 1]); } auto p1 = to_HepLorentzVector(partons[0]); auto pn = to_HepLorentzVector(partons[partons.size() - 1]); const auto begin_ladder = cbegin(partons) + 1; const auto end_ladder = cend(partons) - 2; bool wc = aptype==partons.front().type; //leg b emits w auto q0 = pa - p1; if(!wc) q0 -= pl + plbar; const double current_factor = ME_W_qqxf_current( aptype, bptype, pa, pb, pq, pqbar, p1, plbar, pl, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder, q0, pa, pb, p1, pn, lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } double tree_kin_W_qqxmid( int aptype, int bptype, HLV pa, HLV pb, std::vector<Particle> const & partons, HLV plbar, HLV pl, double lambda ){ HLV pq,pqbar; const auto backmidquark = std::find_if( begin(partons)+1, end(partons)-1, [](Particle const & s){ return s.type != pid::gluon; } ); assert(backmidquark!=end(partons)-1); if (is_quark(backmidquark->type)){ pq = to_HepLorentzVector(*backmidquark); pqbar = to_HepLorentzVector(*(backmidquark+1)); } else { pqbar = to_HepLorentzVector(*backmidquark); pq = to_HepLorentzVector(*(backmidquark+1)); } auto p1 = to_HepLorentzVector(partons[0]); auto pn = to_HepLorentzVector(partons[partons.size() - 1]); auto q0 = pa - p1; // t-channel momentum after qqx auto qqxt = q0; bool wc, wqq; if (backmidquark->type == -(backmidquark+1)->type){ // Central qqx does not emit wqq=false; if (aptype==partons[0].type) { wc = true; } else{ wc = false; q0-=pl+plbar; } } else{ wqq = true; wc = false; qqxt-=pl+plbar; } const auto begin_ladder = cbegin(partons) + 1; const auto end_ladder_1 = (backmidquark); const auto begin_ladder_2 = (backmidquark+2); const auto end_ladder = cend(partons) - 1; for(auto parton_it = begin_ladder; parton_it < begin_ladder_2; ++parton_it){ qqxt -= to_HepLorentzVector(*parton_it); } int nabove = std::distance(begin_ladder, backmidquark); int nbelow = std::distance(begin_ladder_2, end_ladder); std::vector<HLV> partonsHLV; partonsHLV.reserve(partons.size()); for (size_t i = 0; i != partons.size(); ++i) { partonsHLV.push_back(to_HepLorentzVector(partons[i])); } const double current_factor = ME_W_qqxmid_current( aptype, bptype, nabove, nbelow, pa, pb, pq, pqbar, partonsHLV, plbar, pl, wqq, wc ); const double ladder_factor = FKL_ladder_weight( begin_ladder, end_ladder_1, q0, pa, pb, p1, pn, lambda )*FKL_ladder_weight( begin_ladder_2, end_ladder, qqxt, pa, pb, p1, pn, lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } } // namespace anonymous double MatrixElement::tree_kin_W(Event const & ev) const { using namespace event_type; auto const & incoming(ev.incoming()); auto const & decays(ev.decays()); HLV plbar, pl; for (auto& x: decays) { if (x.second.at(0).type < 0){ plbar = to_HepLorentzVector(x.second.at(0)); pl = to_HepLorentzVector(x.second.at(1)); } else{ pl = to_HepLorentzVector(x.second.at(0)); plbar = to_HepLorentzVector(x.second.at(1)); } } const auto pa = to_HepLorentzVector(incoming[0]); const auto pb = to_HepLorentzVector(incoming[1]); const auto partons = tag_extremal_jet_partons(ev); if(ev.type() == unordered_backward){ return tree_kin_W_unob(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } if(ev.type() == unordered_forward){ return tree_kin_W_unof(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } if(ev.type() == extremal_qqxb){ return tree_kin_W_qqxb(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } if(ev.type() == extremal_qqxf){ return tree_kin_W_qqxf(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } if(ev.type() == central_qqx){ return tree_kin_W_qqxmid(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } return tree_kin_W_FKL(incoming[0].type, incoming[1].type, pa, pb, partons, plbar, pl, param_.regulator_lambda); } double MatrixElement::tree_kin_Higgs(Event const & ev) const { if(is_uno(ev.type())){ return tree_kin_Higgs_between(ev); } if(ev.outgoing().front().type == pid::Higgs){ return tree_kin_Higgs_first(ev); } if(ev.outgoing().back().type == pid::Higgs){ return tree_kin_Higgs_last(ev); } return tree_kin_Higgs_between(ev); } namespace { // Colour acceleration multipliers, for gluons see eq. (7) in arXiv:0910.5113 #ifdef HEJ_BUILD_WITH_QCDLOOP // TODO: code duplication with jets.cc double K_g(double p1minus, double paminus) { return 1./2.*(p1minus/paminus + paminus/p1minus)*(C_A - 1./C_A) + 1./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()); } double K( ParticleID type, CLHEP::HepLorentzVector const & pout, CLHEP::HepLorentzVector const & pin ) { if(type == ParticleID::gluon) return K_g(pout, pin); return C_F; } #endif // Colour factor in strict MRK limit double K_MRK(ParticleID type) { return (type == ParticleID::gluon)?C_A:C_F; } } double MatrixElement::MH2_forwardH( CLHEP::HepLorentzVector const & p1out, CLHEP::HepLorentzVector const & p1in, ParticleID type2, CLHEP::HepLorentzVector const & p2out, CLHEP::HepLorentzVector const & p2in, CLHEP::HepLorentzVector const & pH, double t1, double t2 ) const{ ignore(p2out, p2in); const double shat = p1in.invariantMass2(p2in); // gluon case #ifdef HEJ_BUILD_WITH_QCDLOOP if(!param_.Higgs_coupling.use_impact_factors){ return K(type2, p2out, p2in)*C_A*1./(16*M_PI*M_PI)*t1/t2*ME_Houtside_gq( p1out, p1in, p2out, p2in, pH, param_.Higgs_coupling.mt, param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb )/(4*(N_C*N_C - 1)); } #endif return K_MRK(type2)/C_A*9./2.*shat*shat*( C2gHgp(p1in,p1out,pH) + C2gHgm(p1in,p1out,pH) )/(t1*t2); } double MatrixElement::tree_kin_Higgs_first(Event const & ev) const { auto const & incoming = ev.incoming(); auto const & outgoing = ev.outgoing(); assert(outgoing.front().type == pid::Higgs); if(outgoing[1].type != pid::gluon) { assert(incoming.front().type == outgoing[1].type); return tree_kin_Higgs_between(ev); } const auto pH = to_HepLorentzVector(outgoing.front()); const auto partons = tag_extremal_jet_partons( ev ); const auto pa = to_HepLorentzVector(incoming[0]); const auto pb = to_HepLorentzVector(incoming[1]); const auto p1 = to_HepLorentzVector(partons.front()); const auto pn = to_HepLorentzVector(partons.back()); const auto q0 = pa - p1 - pH; const double t1 = q0.m2(); const double t2 = (pn - pb).m2(); return MH2_forwardH( p1, pa, incoming[1].type, pn, pb, pH, t1, t2 )*FKL_ladder_weight( begin(partons) + 1, end(partons) - 1, q0, pa, pb, p1, pn, param_.regulator_lambda ); } double MatrixElement::tree_kin_Higgs_last(Event const & ev) const { auto const & incoming = ev.incoming(); auto const & outgoing = ev.outgoing(); assert(outgoing.back().type == pid::Higgs); if(outgoing[outgoing.size()-2].type != pid::gluon) { assert(incoming.back().type == outgoing[outgoing.size()-2].type); return tree_kin_Higgs_between(ev); } const auto pH = to_HepLorentzVector(outgoing.back()); const auto partons = tag_extremal_jet_partons( ev ); const auto pa = to_HepLorentzVector(incoming[0]); const auto pb = to_HepLorentzVector(incoming[1]); auto p1 = to_HepLorentzVector(partons.front()); const auto pn = to_HepLorentzVector(partons.back()); auto q0 = pa - p1; const double t1 = q0.m2(); const double t2 = (pn + pH - pb).m2(); return MH2_forwardH( pn, pb, incoming[0].type, p1, pa, pH, t2, t1 )*FKL_ladder_weight( begin(partons) + 1, end(partons) - 1, q0, pa, pb, p1, pn, param_.regulator_lambda ); } namespace { template<class InIter, class partIter> double tree_kin_Higgs_uno(InIter BeginIn, InIter EndIn, partIter BeginPart, partIter EndPart, const HLV & qH, const HLV & qHp1, double mt, bool inc_bot, double mb){ const auto pa = to_HepLorentzVector(*BeginIn); const auto pb = to_HepLorentzVector(*(EndIn-1)); const auto pg = to_HepLorentzVector(*BeginPart); const auto p1 = to_HepLorentzVector(*(BeginPart+1)); const auto pn = to_HepLorentzVector(*(EndPart-1)); return ME_Higgs_current_uno( (BeginIn)->type, (EndIn-1)->type, pg, pn, pb, p1, pa, qH, qHp1, mt, inc_bot, mb ); } } double MatrixElement::tree_kin_Higgs_between(Event const & ev) const { using namespace event_type; auto const & incoming = ev.incoming(); auto const & outgoing = ev.outgoing(); const auto the_Higgs = std::find_if( begin(outgoing), end(outgoing), [](Particle const & s){ return s.type == pid::Higgs; } ); assert(the_Higgs != end(outgoing)); const auto pH = to_HepLorentzVector(*the_Higgs); const auto partons = tag_extremal_jet_partons(ev); const auto pa = to_HepLorentzVector(incoming[0]); const auto pb = to_HepLorentzVector(incoming[1]); auto p1 = to_HepLorentzVector( partons[(ev.type() == unob)?1:0] ); auto pn = to_HepLorentzVector( partons[partons.size() - ((ev.type() == unof)?2:1)] ); auto first_after_Higgs = begin(partons) + (the_Higgs-begin(outgoing)); assert( (first_after_Higgs == end(partons) && ( (ev.type() == unob) || partons.back().type != pid::gluon )) || first_after_Higgs->rapidity() >= the_Higgs->rapidity() ); assert( (first_after_Higgs == begin(partons) && ( (ev.type() == unof) || partons.front().type != pid::gluon )) || (first_after_Higgs-1)->rapidity() <= the_Higgs->rapidity() ); // always treat the Higgs as if it were in between the extremal FKL partons if(first_after_Higgs == begin(partons)) ++first_after_Higgs; else if(first_after_Higgs == end(partons)) --first_after_Higgs; // t-channel momentum before Higgs auto qH = pa; for(auto parton_it = begin(partons); parton_it != first_after_Higgs; ++parton_it){ qH -= to_HepLorentzVector(*parton_it); } auto q0 = pa - p1; auto begin_ladder = begin(partons) + 1; auto end_ladder = end(partons) - 1; double current_factor; if(ev.type() == unob){ current_factor = HEJ::C_A*HEJ::C_A/2*tree_kin_Higgs_uno( begin(incoming), end(incoming), begin(partons), end(partons), qH, qH-pH, param_.Higgs_coupling.mt, param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb ); const auto p_unob = to_HepLorentzVector(partons.front()); q0 -= p_unob; p1 += p_unob; ++begin_ladder; } else if(ev.type() == unof){ current_factor = HEJ::C_A*HEJ::C_A/2*tree_kin_Higgs_uno( rbegin(incoming), rend(incoming), rbegin(partons), rend(partons), qH-pH, qH, param_.Higgs_coupling.mt, param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb ); pn += to_HepLorentzVector(partons.back()); --end_ladder; } else{ current_factor = ME_Higgs_current( incoming[0].type, incoming[1].type, pn, pb, p1, pa, qH, qH - pH, param_.Higgs_coupling.mt, param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb ); } const double ladder_factor = FKL_ladder_weight( begin_ladder, first_after_Higgs, q0, pa, pb, p1, pn, param_.regulator_lambda )*FKL_ladder_weight( first_after_Higgs, end_ladder, qH - pH, pa, pb, p1, pn, param_.regulator_lambda ); return current_factor*C_A*C_A/(N_C*N_C-1.)*ladder_factor; } namespace { double get_AWZH_coupling(Event const & ev, double alpha_s) { const auto AWZH_boson = std::find_if( begin(ev.outgoing()), end(ev.outgoing()), [](auto const & p){return is_AWZH_boson(p);} ); if(AWZH_boson == end(ev.outgoing())) return 1.; switch(AWZH_boson->type){ case pid::Higgs: return alpha_s*alpha_s; case pid::Wp: case pid::Wm: return gw*gw*gw*gw/4.; // TODO case pid::photon: case pid::Z: default: throw not_implemented("Emission of boson of unsupported type"); } } } double MatrixElement::tree_param(Event const & ev, double mur) const { assert(is_resummable(ev.type())); const auto begin_partons = ev.begin_partons(); const auto end_partons = ev.end_partons(); const auto num_partons = std::distance(begin_partons, end_partons); const double alpha_s = alpha_s_(mur); const double gs2 = 4.*M_PI*alpha_s; double res = std::pow(gs2, num_partons); if(param_.log_correction){ // use alpha_s(q_perp), evolved to mur assert(num_partons >= 2); const auto first_emission = std::next(begin_partons); const auto last_emission = std::prev(end_partons); for(auto parton = first_emission; parton != last_emission; ++parton){ res *= 1. + alpha_s/(2.*M_PI)*beta0*log(mur/parton->perp()); } } return get_AWZH_coupling(ev, alpha_s)*res; } } // namespace HEJ diff --git a/src/jets.cc b/src/jets.cc index fb90832..c97ca19 100644 --- a/src/jets.cc +++ b/src/jets.cc @@ -1,276 +1,369 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/jets.hh" #include "HEJ/Constants.hh" // 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( HLV const & pout, HLV 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(HLV p1) { // Current goes (E,px,py,pz) // Vector goes (px,py,pz,E) 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 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]); } void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur) { joi(pout, !helout, pin, !helin, cur); } 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]); } 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{ //@{ /** * @brief Pure Jet FKL Contributions, function to handle all incoming types. * @param p1out Outgoing Particle 1. * @param p1in Incoming Particle 1. * @param p2out Outgoing Particle 2 * @param p2in Incoming Particle 2 * @param aqlineb Bool. Is Backwards quark line an anti-quark line? * @param aqlinef Bool. Is Forwards quark line an anti-quark line? * * Calculates j_\mu j^\mu. * Handles all possible incoming states. */ double j_j(HLV p1out, HLV p1in, HLV p2out, HLV p2in, bool aqlineb, bool aqlinef){ HLV q1=p1in-p1out; HLV q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; // Note need to flip helicities in anti-quark case. joi(p1out,!aqlineb, p1in,!aqlineb, mj1p); joi(p1out, aqlineb, p1in, aqlineb, mj1m); joi(p2out,!aqlinef, p2in,!aqlinef, mj2p); joi(p2out, aqlinef, p2in, aqlinef, 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()); } } //anonymous namespace double ME_qQ(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, false, false); } double ME_qQbar(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, false, true); } double ME_qbarQbar(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, true, true); } double ME_qg(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, false, false)*K_g(p2out, p2in)/HEJ::C_F; } double ME_qbarg(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, true, false)*K_g(p2out, p2in)/(HEJ::C_F); } double ME_gg(HLV p1out, HLV p1in, HLV p2out, HLV p2in){ return j_j(p1out, p1in, p2out, p2in, false, false)*K_g(p1out, p1in)*K_g(p2out, p2in)/(HEJ::C_F*HEJ::C_F); } //@} + +namespace{ + double juno_j(HLV pg, HLV p1out, HLV p1in, HLV p2out, + HLV p2in, bool aqlinea, bool aqlineb){ + // This construction is taking rapidity order: pg > p1out >> p2out + HLV q1=p1in-p1out; // Top End + HLV q2=-(p2in-p2out); // Bottom End + HLV qg=p1in-p1out-pg; // Extra bit post-gluon + + // Note <p1|eps|pa> current split into two by gauge choice. + // See James C's Thesis (p72). <p1|eps|pa> -> <p1|pg><pg|pa> + CCurrent mj1p=joi(p1out,!aqlinea,p1in,!aqlinea); + CCurrent mj1m=joi(p1out,aqlinea,p1in,aqlinea); + CCurrent jgap=joi(pg,!aqlinea,p1in,!aqlinea); + CCurrent jgam=joi(pg,aqlinea,p1in,aqlinea); + + // Note for function joo(): <p1+|pg+> = <pg-|p1->. + CCurrent j2gp=joo(p1out,!aqlinea,pg,!aqlinea); + CCurrent j2gm=joo(p1out,aqlinea,pg,aqlinea); + + CCurrent mj2p=joi(p2out,!aqlineb,p2in,!aqlineb); + CCurrent mj2m=joi(p2out,aqlineb,p2in,aqlineb); + + // Dot products of these which occur again and again + COM Mmp=mj1m.dot(mj2p); + COM Mmm=mj1m.dot(mj2m); + COM Mpp=mj1p.dot(mj2p); + COM Mpm=mj1p.dot(mj2m); + + CCurrent p1o(p1out),p2o(p2out),p2i(p2in),qsum(q1+qg),p1i(p1in); + + CCurrent Lmm=(qsum*(Mmm)+(-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m + +(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*Mmm/2.))/q1.m2(); + CCurrent Lmp=(qsum*(Mmp) + (-2.*mj2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2p + +(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*Mmp/2.))/q1.m2(); + CCurrent Lpm=(qsum*(Mpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m + +(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*Mpm/2.))/q1.m2(); + CCurrent Lpp=(qsum*(Mpp) + (-2.*mj2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2p + +(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*Mpp/2.))/q1.m2(); + + CCurrent U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*Mmm)/(p1out+pg).m2(); + CCurrent U1mp=(jgam.dot(mj2p)*j2gm+2.*p1o*Mmp)/(p1out+pg).m2(); + CCurrent U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*Mpm)/(p1out+pg).m2(); + CCurrent U1pp=(jgap.dot(mj2p)*j2gp+2.*p1o*Mpp)/(p1out+pg).m2(); + CCurrent U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*Mmm)/(p1in-pg).m2(); + CCurrent U2mp=((-1.)*j2gm.dot(mj2p)*jgam+2.*p1i*Mmp)/(p1in-pg).m2(); + CCurrent U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*Mpm)/(p1in-pg).m2(); + CCurrent U2pp=((-1.)*j2gp.dot(mj2p)*jgap+2.*p1i*Mpp)/(p1in-pg).m2(); + + constexpr double cf=HEJ::C_F; + + double amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); + double amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); + double apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); + double app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); + double ampsq=-(amm+amp+apm+app); + + //Divide by t-channels + ampsq/=q2.m2()*qg.m2(); + ampsq/=16.; + + // Factor of (Cf/Ca) for each quark to match j_j. + ampsq*=(HEJ::C_F*HEJ::C_F)/(HEJ::C_A*HEJ::C_A); + + return ampsq; + + } +} + +//Unordered bits for pure jet +double ME_unob_qQ (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, false, false); +} + +double ME_unob_qbarQ (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, true, false); +} + +double ME_unob_qQbar (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, false, true); +} + +double ME_unob_qbarQbar (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, true, true); +} + +double ME_unob_qg (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, false, false)*K_g(p2out,p2in)/HEJ::C_F; +} + +double ME_unob_qbarg (HLV pg, HLV p1out, HLV p1in, HLV p2out, HLV p2in){ + return juno_j(pg, p1out, p1in, p2out, p2in, true, false)*K_g(p2out,p2in)/HEJ::C_F; +} diff --git a/t/ME_data/ME_jets_tree.dat b/t/ME_data/ME_jets_tree.dat index fc2be65..0f36db3 100644 --- a/t/ME_data/ME_jets_tree.dat +++ b/t/ME_data/ME_jets_tree.dat @@ -1,672 +1,742 @@ 1089423.187 16.03009374 6634.608547 75414606.57 77554.50738 197575.0454 76983.13177 38.35809694 14.34964854 2.299306716e+10 769524899.8 20.89671172 76.68018946 8308.664153 2450736.574 52.24359459 497.7665557 5051.865522 94571.50832 1362099715 3690.443315 4732694.851 33060865.81 38851015.2 30289.18618 283948.732 14123.1659 40.56212546 6.779515122e+12 25724.24084 4.464903667 26.15970999 28358522.83 481820.3073 33.14640689 91.72649968 322690.8843 39.04279288 65541087.6 2256.832837 51.04918081 21658.09425 675.8508089 0.003214397574 413076.4025 1194042.703 15261824.18 1.190018997e+13 25852091.94 765101.1953 579.2342295 23845182.04 92.16369985 705.5684735 828764.9832 81.971147 1436684.808 70.01623522 230.5658106 8794.725516 890.1697598 97617236.05 31101.11974 10351668.97 187539232.1 93875.71518 43031260.49 4.067125353 6035.796288 16569782.71 46.2510317 52.88862266 0.5556956436 606771384.7 293585.0788 8415963.902 29.5069149 18.96420915 6.321441102e+14 3.592998225 129.9175932 19.85723932 20438567.28 2.633206648e+10 2051545.14 13.98077027 342.1399233 17.65245465 79250.23744 1030.69768 73407.42532 237883.1282 79.44231257 81668.43497 93415340.81 430.286772 2209.749603 568258.2296 173145.2499 1620285.613 337.6920671 153.562771 416.0616338 2187.267876 22.41576042 49.58992905 559801.7855 45.11194021 584508.9206 35.3041943 202.7925831 15.00277101 46.15144698 4.588470323e+13 597.3210575 39.62999028 5228016720 822065.5972 1.826581842e+10 6.479966482 486208349.5 62.22613221 21.46207828 792.2244925 98.46049107 192.195726 539903191.6 7888.570415 559946441.6 99.19582481 967.8349215 1186287.112 296.9970515 393.8848181 46.84865591 27.79939609 70102.51858 68.89626885 2702.415147 257.708207 155288432.1 1225359.249 90576.73064 9434.676956 88.90057162 4378317.363 15680420.87 6567.795332 94.80131393 44.21436446 61.79707787 44.41095665 7385.16094 227.1571585 94986.49609 67239897.71 96.37463492 2911.906879 49.889402 6585.792276 336579403.2 564.3980943 1554303.479 33573.8975 2.437369584e+10 226746.4443 75.83290452 27.75735686 94778193.37 59.97102623 64.15185493 7.774417686e+13 7438.779369 22.08782146 434613.7211 34293520.02 68775.95004 307606184.4 150615.387 899713.4452 9.223973371e+11 59817.02462 348.4932635 2609243018 24597079.8 98.70527236 83.33745442 12560815.61 1358729.011 6976819.18 7425.681281 488.6665953 13.67398052 401.1059245 1888.653087 4009.955386 175.1044182 864180.0454 37.7515354 47187493.74 109.4430381 359.7148155 2.340917207e+11 179.4280073 9827.615509 51.43706602 159.8742767 2066998.073 21197190.52 154.5419162 20.22828093 96.58078786 54.45061659 65.30848921 27.46863884 399638.3233 48.71138495 1579072.132 67717150.9 1034311422 2300.166812 542.347043 225.023696 15.39245502 5.045806172 408439.9118 2850069.206 412.6441358 461.2402375 22.40894016 37199025.96 16799601.72 1283263.103 19.12993911 4119931.525 138990.0255 122.7744597 18733.45006 56.21459033 343399063.9 40.69967214 1257.945403 2.549605794e+11 100938.8483 197079455.9 18898.20284 65974.22935 2007851.613 6824.687033 4076901842 7253481.757 3.002058086 1662154.497 3.070682383e+12 163.8653423 560506230.7 1510.132538 26693.22493 0.1285518109 494554.148 24594487.35 271745.3087 155.6774454 0.01468054527 3.34264067 1588023.004 11.02440854 2.276304783 2060679.506 1.060994634 7899476.433 11392931.55 0.002283073032 223.8249674 64.14820176 222013139.2 17285137.17 4904.948169 4.325556105e+10 2.025060646 64.72904144 0.7119503103 0.3108282312 127.8083553 231480500.9 3004499.276 35310522.85 9501.295688 34.48365857 0.1237148274 137.304491 22906.44193 2845.690168 1425.623527 8.059398488 2836.653576 545.9404471 6676238.836 453869217.1 3046455.67 3824.741211 1733.364341 163997517.5 46856740.63 18247.63995 55504734.26 1281.154525 0.01317003733 26796232.71 614.7809373 124.9917797 13.32414443 2.061438665 1437324478 7.653466138 215267780.4 304925.7977 12340855.35 1.292474046 4012100939 918.1699992 0.001829689464 266.1514907 19586.50145 9843.077092 34563.10338 2.665695419e+14 194168.4335 182.9208313 1.789617285 115011741.8 1.600475143 0.9039184064 54.16404691 3836249.251 0.1453799136 83576.30659 75918.72599 255875.4377 0.0940918961 8139.618634 +41.2113043 +41.2113043 +18.2434106 +18.2434106 +18.2434106 +18.2434106 497813992.4 9158737.332 81.5174511 +0.1756986828 +0.1756986828 +0.07788028858 +0.07788028858 +0.07788028858 +0.07788028858 85205.83347 1827.041926 5434428.481 34601.43212 645859.4651 8.409921219 +0.00878465753 +0.00878465753 +0.00878465753 +0.0200891802 +0.0200891802 102240.6791 0.3455555689 +5.186512555e-05 +5.186512555e-05 +2.095582296e-05 +2.095582296e-05 +2.095582296e-05 +2.095582296e-05 2.273623498e+11 2139040773 82682.82602 +1.697773045 +1.697773045 +1.697773045 +3.928017028 +3.928017028 164684299.3 6840.694229 6292.264217 1.266028837 23696.0817 9776772.75 146.8084842 40186.198 578656.2198 0.05760079494 1308.62247 2846240637 2269.666603 0.05728404415 97.64433608 816.0835471 +2.245768012 +2.245768012 +2.245768012 +5.059168555 +5.059168555 0.003537766648 715128749.1 581519.0926 28878.33931 606.7268882 8.540999968 1.843057112 14728.95688 0.09287199376 +0.0001302392694 +0.0001302392694 +5.236903901e-05 +5.236903901e-05 +5.236903901e-05 4.952792168 +0.03410256159 +0.03410256159 +0.01401286426 +0.01401286426 +0.01401286426 39703045.24 0.2253239938 0.4007086942 0.6679356978 8985.245646 1459.149121 222.574255 1410.034894 49.66459517 280057.7217 11990414.03 22.39502507 6652.821533 412.6309921 3976669.212 376.5293878 0.04993631096 325.2221445 0.001056663136 0.6094009495 0.01755460768 4169089.697 120922.3418 19.94386406 1.034905758 899064.7273 13370.52361 12.9511581 7.43997218 0.2195708041 22.69922572 1364456.758 37.31335252 193721994.5 5387171012 83382.68593 4356.219769 4.959390234 280348.136 4068.591503 497.1128967 1220.499616 37070808.46 5.029130002 13411.495 21606019.92 13.50033011 10356.03697 0.853804882 0.004144159842 66.5696697 215.1472766 1.80856617 47652781.08 187.4720271 0.02309225892 221825.3003 68502271.85 89524.33999 63.06068401 35193.88681 0.1324344626 0.07415048828 1.316536312 1914484.13 239.8833788 404.8578233 311149.7413 31.91203802 6765.191464 3683.120991 111.8561994 622181.6379 3.495906967 1.324392325 2932853.167 1221.022853 0.3964612919 772.5117573 1587.443569 16407.82538 1153370.819 697976.9971 5293.102236 0.6273574623 433333.6561 667.0010151 279.5253754 13.71499773 27581.98765 0.1265026607 0.1265655615 0.217545965 119235.7842 1207.825866 1.168584528 442927.4532 11025.74448 12920.20556 6.440028505 0.01867492246 0.009209754218 3.078810838 1.895501574 4354.355041 1376.801012 281.0956164 12.62981914 0.01896307384 1.469952339 1070.389041 0.3140297342 17576.52171 19.46940005 72639.28176 1.00064982 10.58896856 146.5709549 240963.5215 21441702.88 9436.867787 1807651761 253.6931177 33906.26088 73290.29485 58.88693751 0.1874080618 128856.1698 37.9170344 999.730091 79.29102322 4297075.439 2815203002 1.065757865 41.63356752 3132937.645 0.006570811459 114610718.1 19766422.36 104.7817608 978.6047854 1114.98705 2962094.183 4303175.509 40918.11534 6.458644406 0.01513394186 10888.55623 1429.371661 72470.14267 1239031.521 0.01533517898 9486.889743 9312.872953 0.001369262882 263.7126988 27397.40987 6.460887231e+11 20.47552795 11886.05681 359511.4015 16322071.14 5.495229 94.06819575 11159.01276 497280.7644 152.8232363 2819.864026 1840.922093 105.3416519 1.51196546 893.0699171 274.2733387 213.9840929 29.84435445 0.06575134529 68473.33981 0.04814411438 95307.18205 0.2103887883 87533.03201 170.1269759 12266.74779 4.906472106 1289.949588 206.2206679 1339736.494 3265180.524 817632.5321 777148.2976 45580.38902 112.3471097 40.46375548 113.0563114 0.5022425417 125.6469752 1250753.214 119.6687695 7890.066678 255592.6823 0.09544112407 80.43028795 168.8638851 231.3586602 9.003352253 3865310.035 0.0327080534 0.2259241849 0.3309640842 70628514.93 1.342293964 1558415395 1.535156072 1105643165 11.12340492 19553.68065 0.03262635444 43.60758633 149.96132 16.71798701 862303.2755 3779.707836 227.1354158 0.04181934127 0.007441956106 0.06547652512 562.1841603 0.1962099745 47427.77928 278196156.8 3272270.994 3.274695664 3.671659367 0.8773587215 3475.635402 150.1691185 79249376.57 100282855 1034000.854 34631.08123 0.2021471708 11338.25051 365.9254869 3614.640649 38892.33006 3206.818315 495.3831508 3131.024396 1216.930767 3.68554273 0.0007587392874 27267.82366 66215.88611 12270.6996 2181.519341 9.799873017 84.23360373 350624.9294 2324.233559 0.210264797 1438761.868 160.6723109 39.13994322 2317.668587 32196.71663 0.02293846799 177.7024259 294490.6299 963.9483044 683.7845476 12.22284439 4350.875864 132.6662523 800.0540763 0.6752102469 6384.094581 667.7145567 88.5979278 65957.42139 0.1009745291 7074.842515 512.2889019 11.48214352 2.877973951 1.31777398 7.553015302 0.01771209643 0.01420982393 +3.754178119e-07 +1.116826573e-06 +1.116826573e-06 +3.754178119e-07 +3.754178119e-07 +3.754178119e-07 +1.769703186e-06 +4.356179554e-06 +4.356179554e-06 +1.769703186e-06 +1.769703186e-06 +1.769703186e-06 5.350111784 5171856.193 0.6877419322 +1.22182262e-05 +1.22182262e-05 +1.22182262e-05 +2.818920729e-05 +2.818920729e-05 +2.708089303e-05 +2.708089303e-05 +2.708089303e-05 +6.339285468e-05 +6.339285468e-05 +222.6777557 +222.6777557 +222.6777557 +501.1839533 +501.1839533 diff --git a/t/ME_data/PSP_jets.lhe.gz b/t/ME_data/PSP_jets.lhe.gz index b471729..3ac0130 100644 --- a/t/ME_data/PSP_jets.lhe.gz +++ b/t/ME_data/PSP_jets.lhe.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98254005df93663441f19013925d3dd40575ffcbfd666387a05cfd6d1b64c489 -size 161645 +oid sha256:c8a0adcc7453343934c235a295515b2838b371f8aef4d52b6ffe61301774efe6 +size 163612