diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..27ce9b2 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,17 @@ +## Authors of the HEJ collaboration +(sorted by first name) + +# Current contributors + +Andreas Maier +Helen Brooks +James Black +Jennifer Smillie +Jeppe R. Andersen +Marian Heil + +# Former contributors + +James Cockburn +Tuomas Hapola +Jack J. Medley diff --git a/FixedOrderGen/cmake/Templates/Version.hh.in b/FixedOrderGen/cmake/Templates/Version.hh.in index 0d3e63a..ad8fc13 100644 --- a/FixedOrderGen/cmake/Templates/Version.hh.in +++ b/FixedOrderGen/cmake/Templates/Version.hh.in @@ -1,47 +1,50 @@ -/** \file Version.hh - * \brief The file gives the current HEJ Fixed Order Generator Version +/** \file Version.hh + * \brief The file gives the current HEJ Fixed Order Generator Version + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later */ - #pragma once #include <string> /// @brief Full name of this package. #define HEJFOG_PACKAGE_NAME "@PROJECT_NAME@" /// @brief Version string of this package #define HEJFOG_VERSION "@PROJECT_VERSION@" /// @brief Full name and version of this package. #define HEJFOG_PACKAGE_STRING "@PROJECT_NAME@ @PROJECT_VERSION@" /// @brief Major version of this package #define HEJFOG_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ /// @brief Minor version of this package #define HEJFOG_VERSION_MINOR @PROJECT_VERSION_MINOR@ /// @brief Patch version of this package #define HEJFOG_VERSION_PATCH @PROJECT_VERSION_PATCH@ /// @brief Git revision of this package #define HEJFOG_GIT_revision "@PROJECT_GIT_REVISION@" /// @brief Git branch name of this package #define HEJFOG_GIT_branch "@PROJECT_GIT_BRANCH@" namespace HEJFOG { namespace Version { inline std::string String() { return HEJFOG_VERSION; } inline std::string package_name() { return HEJFOG_PACKAGE_NAME; } inline std::string package_name_full() { return HEJFOG_PACKAGE_STRING; } inline int Major() { return HEJFOG_VERSION_MAJOR; } inline int Minor() { return HEJFOG_VERSION_MINOR; } inline int Patch() { return HEJFOG_VERSION_PATCH; } inline std::string revision() { return HEJFOG_GIT_revision; } }; } diff --git a/FixedOrderGen/include/Beam.hh b/FixedOrderGen/include/Beam.hh index 3d61ace..73f7380 100644 --- a/FixedOrderGen/include/Beam.hh +++ b/FixedOrderGen/include/Beam.hh @@ -1,14 +1,19 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <array> #include "HEJ/PDG_codes.hh" namespace HEJFOG{ struct Beam{ double energy; std::array<HEJ::ParticleID, 2> particles{{ HEJ::pid::proton, HEJ::pid::proton }}; }; } diff --git a/FixedOrderGen/include/Decay.hh b/FixedOrderGen/include/Decay.hh index ffe883c..64cae8d 100644 --- a/FixedOrderGen/include/Decay.hh +++ b/FixedOrderGen/include/Decay.hh @@ -1,11 +1,16 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include "HEJ/PDG_codes.hh" #include <vector> namespace HEJFOG{ struct Decay{ std::vector<HEJ::pid::ParticleID> products; double branching_ratio; }; } diff --git a/FixedOrderGen/include/EventGenerator.hh b/FixedOrderGen/include/EventGenerator.hh index e2064c7..896f0f6 100644 --- a/FixedOrderGen/include/EventGenerator.hh +++ b/FixedOrderGen/include/EventGenerator.hh @@ -1,57 +1,62 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include "HEJ/MatrixElement.hh" #include "HEJ/optional.hh" #include "HEJ/PDF.hh" #include "HEJ/RNG.hh" #include "Beam.hh" #include "JetParameters.hh" #include "ParticleProperties.hh" #include "Process.hh" #include "Status.hh" namespace HEJ{ class Event; class HiggsCouplingSettings; class ScaleGenerator; } //! Namespace for HEJ Fixed Order Generator namespace HEJFOG{ class EventGenerator{ public: EventGenerator( Process process, Beam beam, HEJ::ScaleGenerator scale_gen, JetParameters jets, int pdf_id, double subl_change, unsigned int subl_channels, ParticlesPropMap particles_properties, HEJ::HiggsCouplingSettings Higgs_coupling, HEJ::RNG & ran ); HEJ::optional<HEJ::Event> gen_event(); Status status() const { return status_; } private: HEJ::PDF pdf_; HEJ::MatrixElement ME_; HEJ::ScaleGenerator scale_gen_; Process process_; JetParameters jets_; Beam beam_; Status status_; double subl_change_; unsigned int subl_channels_; ParticlesPropMap particles_properties_; std::reference_wrapper<HEJ::RNG> ran_; }; } diff --git a/FixedOrderGen/include/JetParameters.hh b/FixedOrderGen/include/JetParameters.hh index 4c65067..8649fff 100644 --- a/FixedOrderGen/include/JetParameters.hh +++ b/FixedOrderGen/include/JetParameters.hh @@ -1,14 +1,19 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include "fastjet/JetDefinition.hh" #include "HEJ/optional.hh" namespace HEJFOG{ struct JetParameters{ fastjet::JetDefinition def; double min_pt; double max_y; HEJ::optional<double> peak_pt; }; } diff --git a/FixedOrderGen/include/ParticleProperties.hh b/FixedOrderGen/include/ParticleProperties.hh index 08a296d..d38a0ec 100644 --- a/FixedOrderGen/include/ParticleProperties.hh +++ b/FixedOrderGen/include/ParticleProperties.hh @@ -1,23 +1,28 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <vector> #include <unordered_map> #include "Decay.hh" namespace HEJFOG{ struct ParticleProperties{ double mass; double width; std::vector<Decay> decays; }; #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6) // gcc version < 6 explicitly needs hash function for enum // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 using ParticlesPropMap = std::unordered_map<HEJ::ParticleID, ParticleProperties, std::hash<int>>; #else using ParticlesPropMap = std::unordered_map<HEJ::ParticleID, ParticleProperties>; #endif } diff --git a/FixedOrderGen/include/PhaseSpacePoint.hh b/FixedOrderGen/include/PhaseSpacePoint.hh index 32f6378..7587acb 100644 --- a/FixedOrderGen/include/PhaseSpacePoint.hh +++ b/FixedOrderGen/include/PhaseSpacePoint.hh @@ -1,219 +1,222 @@ -/** \file PhaseSpacePoint.hh - * \brief Contains the PhaseSpacePoint Class +/** \file PhaseSpacePoint.hh + * \brief Contains the PhaseSpacePoint Class + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later */ - #pragma once #include <bitset> #include <vector> #include "HEJ/Event.hh" #include "HEJ/Particle.hh" #include "HEJ/PDF.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/RNG.hh" #include "JetParameters.hh" #include "ParticleProperties.hh" #include "Status.hh" namespace HEJFOG{ class Process; using HEJ::Particle; //! A point in resummation phase space class PhaseSpacePoint{ public: //! Default PhaseSpacePoint Constructor PhaseSpacePoint() = default; //! PhaseSpacePoint Constructor /** * @param proc The process to generate * @param jet_properties Jet defintion & cuts * @param pdf The pdf set (used for sampling) * @param E_beam Energie of the beam * @param subl_chance Chance to turn a potentially unordered * emission into an actual one * @param subl_channels Possible subleading channels. * see HEJFOG::Subleading * @param particle_properties Properties of producted boson * * Initially, only FKL phase space points are generated. subl_chance gives * the change of turning one emissions into a subleading configuration, * i.e. either unordered or central quark/anti-quark pair. Unordered * emissions require that the most extremal emission in any direction is * a quark or anti-quark and the next emission is a gluon. Quark/anti-quark * pairs are only generated for W processes. At most one subleading * emission will be generated in this way. */ PhaseSpacePoint( Process const & proc, JetParameters const & jet_properties, HEJ::PDF & pdf, double E_beam, double subl_chance, unsigned int subl_channels, ParticlesPropMap const & particles_properties, HEJ::RNG & ran ); //! Get Weight Function /** * @returns Weight of Event */ double weight() const{ return weight_; } Status status() const{ return status_; } //! Get Incoming Function /** * @returns Incoming Particles */ std::array<Particle, 2> const & incoming() const{ return incoming_; } //! Get Outgoing Function /** * @returns Outgoing Particles */ std::vector<Particle> const & outgoing() const{ return outgoing_; } std::unordered_map<size_t, std::vector<Particle>> const & decays() const{ return decays_; } private: /** * @internal * @brief Generate LO parton momentum * * @param count Number of partons to generate * @param is_pure_jets If true ensures momentum conservation in x and y * @param jet_param Jet properties to fulfil * @param max_pt max allowed pt for a parton (typically E_CMS) * @param ran Random Number Generator * * @returns Momentum of partons * * Ensures that each parton is in its own jet. * Generation is independent of parton flavour. Output is sorted in rapidity. */ std::vector<fastjet::PseudoJet> gen_LO_partons( int count, bool is_pure_jets, JetParameters const & jet_param, double max_pt, HEJ::RNG & ran ); std::vector<Particle> gen_enu( std::vector<HEJ::pid::ParticleID> const & pair, HEJ::RNG & ran ); Particle gen_boson( HEJ::ParticleID bosonid, double mass, double width, HEJ::RNG & ran ); template<class ParticleMomenta> fastjet::PseudoJet gen_last_momentum( ParticleMomenta const & other_momenta, double mass_square, double y ) const; bool jets_ok( std::vector<fastjet::PseudoJet> const & Born_jets, std::vector<fastjet::PseudoJet> const & partons ) const; /** * @internal * @brief Generate incoming partons according to the PDF * * @param uf Scale used in the PDF */ void reconstruct_incoming( Process const & proc, unsigned int subl_channels, HEJ::PDF & pdf, double E_beam, double uf, HEJ::RNG & ran ); /** * @internal * @brief Returns list of all allowed initial states partons */ std::array<std::bitset<11>,2> filter_partons( Process const & proc, unsigned int const subl_channels, HEJ::RNG & ran ); HEJ::ParticleID generate_incoming_id( size_t beam_idx, double x, double uf, HEJ::PDF & pdf, std::bitset<11> allowed_partons, HEJ::RNG & ran ); bool momentum_conserved(double ep) const; HEJ::Particle const & most_backward_FKL( std::vector<HEJ::Particle> const & partons ) const; HEJ::Particle const & most_forward_FKL( std::vector<HEJ::Particle> const & partons ) const; HEJ::Particle & most_backward_FKL(std::vector<HEJ::Particle> & partons) const; HEJ::Particle & most_forward_FKL(std::vector<HEJ::Particle> & partons) const; bool extremal_FKL_ok( std::vector<fastjet::PseudoJet> const & partons ) const; double random_normal(double stddev, HEJ::RNG & ran); /** * @internal * @brief Turns a FKL configuration into a subleading one * * @param chance Change to switch to subleading configuration * @param channels Allowed channels for subleading process * @param proc Process to decide which subleading * configurations are allowed * * With a chance of "chance" the FKL configuration is either turned into * a unordered configuration or, for A/W/Z bosons, a configuration with * a central quark/anti-quark pair. */ void maybe_turn_to_subl(double chance, unsigned int channels, Process const & proc, HEJ::RNG & ran); void turn_to_uno(bool can_be_uno_backward, bool can_be_uno_forward, HEJ::RNG & ran); void turn_to_qqx(bool allow_strange, HEJ::RNG & ran); std::vector<Particle> decay_boson( HEJ::Particle const & parent, std::vector<Decay> const & decays, HEJ::RNG & ran ); /// @brief setup outgoing partons to ensure correct coupling to boson void couple_boson(HEJ::ParticleID boson, HEJ::RNG & ran); Decay select_decay_channel( std::vector<Decay> const & decays, HEJ::RNG & ran ); double gen_hard_pt( int np, double ptmin, double ptmax, double y, HEJ::RNG & ran ); double gen_soft_pt(int np, double ptmax, HEJ::RNG & ran); double gen_parton_pt( int count, JetParameters const & jet_param, double ptmax, double y, HEJ::RNG & ran ); double weight_; Status status_; std::array<Particle, 2> incoming_; std::vector<Particle> outgoing_; //! Particle decays in the format {outgoing index, decay products} std::unordered_map<size_t, std::vector<Particle>> decays_; }; HEJ::Event::EventData to_EventData(PhaseSpacePoint const & psp); } diff --git a/FixedOrderGen/include/Process.hh b/FixedOrderGen/include/Process.hh index 33d0a48..d2b0beb 100644 --- a/FixedOrderGen/include/Process.hh +++ b/FixedOrderGen/include/Process.hh @@ -1,17 +1,22 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <array> #include <vector> #include "HEJ/PDG_codes.hh" #include "HEJ/optional.hh" namespace HEJFOG{ struct Process{ std::array<HEJ::ParticleID, 2> incoming; int njets; HEJ::optional<HEJ::ParticleID> boson; std::vector <HEJ::ParticleID> leptons; }; } diff --git a/FixedOrderGen/include/Status.hh b/FixedOrderGen/include/Status.hh index 599af0b..5639b49 100644 --- a/FixedOrderGen/include/Status.hh +++ b/FixedOrderGen/include/Status.hh @@ -1,22 +1,27 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <string> #include <stdexcept> namespace HEJFOG{ enum Status{ good, not_enough_jets, too_much_energy }; inline std::string to_string(Status s){ switch(s){ case good: return "good"; case not_enough_jets: return "not enough jets"; case too_much_energy: return "too much energy"; default:; } throw std::logic_error{"unreachable"}; } } diff --git a/FixedOrderGen/include/Subleading.hh b/FixedOrderGen/include/Subleading.hh index 57ea71a..c209b2d 100644 --- a/FixedOrderGen/include/Subleading.hh +++ b/FixedOrderGen/include/Subleading.hh @@ -1,15 +1,20 @@ +/** + * \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 }; } diff --git a/FixedOrderGen/include/UnweightSettings.hh b/FixedOrderGen/include/UnweightSettings.hh index a633622..f552638 100644 --- a/FixedOrderGen/include/UnweightSettings.hh +++ b/FixedOrderGen/include/UnweightSettings.hh @@ -1,8 +1,13 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once namespace HEJFOG { struct UnweightSettings { int sample_size; double max_dev; }; } diff --git a/FixedOrderGen/include/Unweighter.hh b/FixedOrderGen/include/Unweighter.hh index e7fe40b..5223e9d 100644 --- a/FixedOrderGen/include/Unweighter.hh +++ b/FixedOrderGen/include/Unweighter.hh @@ -1,72 +1,77 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <limits> #include <cmath> #include "HEJ/optional.hh" #include "HEJ/RNG.hh" namespace HEJ { class Event; } namespace HEJFOG { namespace detail { bool has_jet_softer_than(HEJ::Event const & ev, double pt); template<typename Iterator> double calc_cut( Iterator begin, Iterator end, double max_dev, double min_pt ) { double mean = 0.; double err = 0.; double awt_sum = 0.; for(; begin != end; ++begin){ if(has_jet_softer_than(*begin, min_pt)) continue; const double awt = std::abs(begin->central().weight); const double tmp = awt*std::log(awt); mean += tmp; err += tmp*tmp; awt_sum += awt; } mean /= awt_sum; err = std::sqrt(err)/awt_sum; return std::exp(mean + max_dev*err); } } class Unweighter { public: template<typename Iterator> Unweighter( Iterator begin, Iterator end, double max_dev, HEJ::RNG & ran, /* minimum pt of jets for an event to be considered for unweighting * * If the 'jets: peak pt' option is set to the *resummation* jet * threshold, events with softer jets will have a spurious * large weight, although they hardly contribute after resummation. * This destroys the unweighting efficiency. * By setting min_unweight_pt to the same threshold, we can exclude * these events from unweighting. */ double min_unweight_pt = 0. ): cut_{detail::calc_cut(begin, end, max_dev, min_unweight_pt)}, min_unweight_pt_{min_unweight_pt}, ran_{ran} {} HEJ::optional<HEJ::Event> unweight(HEJ::Event ev) const; private: double cut_; double min_unweight_pt_; std::reference_wrapper<HEJ::RNG> ran_; std::function<bool(HEJ::Event const &)> unweight_ok_; }; } diff --git a/FixedOrderGen/include/config.hh b/FixedOrderGen/include/config.hh index e34b2ec..71c748b 100644 --- a/FixedOrderGen/include/config.hh +++ b/FixedOrderGen/include/config.hh @@ -1,38 +1,43 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include "yaml-cpp/yaml.h" #include "HEJ/HiggsCouplingSettings.hh" #include "HEJ/optional.hh" #include "HEJ/config.hh" #include "HEJ/output_formats.hh" #include "HEJ/exceptions.hh" #include "Process.hh" #include "JetParameters.hh" #include "Beam.hh" #include "ParticleProperties.hh" #include "UnweightSettings.hh" namespace HEJFOG{ struct Config{ Process process; int events; JetParameters jets; Beam beam; int pdf_id; double subleading_fraction; unsigned int subleading_channels; //! < see HEJFOG::Subleading ParticlesPropMap particles_properties; YAML::Node analysis_parameters; HEJ::ScaleConfig scales; std::vector<HEJ::OutputFile> output; HEJ::RNGConfig rng; HEJ::HiggsCouplingSettings Higgs_coupling; HEJ::optional<UnweightSettings> unweight; }; Config load_config(std::string const & config_file); } diff --git a/FixedOrderGen/src/EventGenerator.cc b/FixedOrderGen/src/EventGenerator.cc index c97839a..da0f2a5 100644 --- a/FixedOrderGen/src/EventGenerator.cc +++ b/FixedOrderGen/src/EventGenerator.cc @@ -1,80 +1,85 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "EventGenerator.hh" #include "Process.hh" #include "Beam.hh" #include "JetParameters.hh" #include "PhaseSpacePoint.hh" #include "HEJ/Event.hh" #include "HEJ/config.hh" namespace HEJFOG{ EventGenerator::EventGenerator( Process process, Beam beam, HEJ::ScaleGenerator scale_gen, JetParameters jets, int pdf_id, double subl_change, unsigned int subl_channels, ParticlesPropMap particles_properties, HEJ::HiggsCouplingSettings Higgs_coupling, HEJ::RNG & ran ): pdf_{pdf_id, beam.particles[0], beam.particles[1]}, ME_{ [this](double mu){ return pdf_.Halphas(mu); }, HEJ::MatrixElementConfig{ false, std::move(Higgs_coupling) } }, scale_gen_{std::move(scale_gen)}, process_{std::move(process)}, jets_{std::move(jets)}, beam_{std::move(beam)}, subl_change_{subl_change}, subl_channels_{subl_channels}, particles_properties_{std::move(particles_properties)}, ran_{ran} { } HEJ::optional<HEJ::Event> EventGenerator::gen_event(){ HEJFOG::PhaseSpacePoint psp{ process_, jets_, pdf_, beam_.energy, subl_change_, subl_channels_, particles_properties_, ran_ }; status_ = psp.status(); if(status_ != good) return {}; HEJ::Event ev = scale_gen_( HEJ::Event{ to_EventData( std::move(psp) ).cluster( jets_.def, jets_.min_pt) } ); ev.generate_colours(ran_); const double shat = HEJ::shat(ev); const double xa = (ev.incoming()[0].E()-ev.incoming()[0].pz())/(2.*beam_.energy); const double xb = (ev.incoming()[1].E()+ev.incoming()[1].pz())/(2.*beam_.energy); // evaluate matrix element ev.parameters() *= ME_.tree(ev)/(shat*shat); // and PDFs ev.central().weight *= pdf_.pdfpt(0,xa,ev.central().muf, ev.incoming()[0].type); ev.central().weight *= pdf_.pdfpt(0,xb,ev.central().muf, ev.incoming()[1].type); for(size_t i = 0; i < ev.variations().size(); ++i){ auto & var = ev.variations(i); var.weight *= pdf_.pdfpt(0,xa,var.muf, ev.incoming()[0].type); var.weight *= pdf_.pdfpt(0,xb,var.muf, ev.incoming()[1].type); } return ev; } } diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc index 46f2473..d5d80d5 100644 --- a/FixedOrderGen/src/PhaseSpacePoint.cc +++ b/FixedOrderGen/src/PhaseSpacePoint.cc @@ -1,737 +1,742 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "PhaseSpacePoint.hh" #include <algorithm> #include "CLHEP/Vector/LorentzVector.h" #include "HEJ/Constants.hh" #include "HEJ/exceptions.hh" #include "HEJ/kinematics.hh" #include "HEJ/Particle.hh" #include "HEJ/utility.hh" #include "Process.hh" #include "Subleading.hh" using namespace HEJ; namespace HEJFOG{ static_assert( std::numeric_limits<double>::has_quiet_NaN, "no quiet NaN for double" ); constexpr double NaN = std::numeric_limits<double>::quiet_NaN(); HEJ::Event::EventData to_EventData(PhaseSpacePoint const & psp){ HEJ::Event::EventData result; result.incoming = psp.incoming(); assert(result.incoming.size() == 2); result.outgoing=psp.outgoing(); // technically Event::EventData doesn't have to be sorted, // but PhaseSpacePoint should be anyway assert( std::is_sorted( begin(result.outgoing), end(result.outgoing), HEJ::rapidity_less{} ) ); assert(result.outgoing.size() >= 2); result.decays=psp.decays(); result.parameters.central= {NaN, NaN, psp.weight() }; return result; } namespace{ bool can_swap_to_uno( HEJ::Particle const & p1, HEJ::Particle const & p2 ){ return is_parton(p1) && p1.type != pid::gluon && p2.type == pid::gluon; } size_t count_gluons(std::vector<Particle>::const_iterator first, std::vector<Particle>::const_iterator last){ return std::count_if(first, last, [](Particle const & p) {return p.type == pid::gluon;}); } /** assumes FKL configurations between first and last, * else there can be a quark in a non-extreme position * e.g. uno configuration gqg would pass */ bool can_change_to_qqx( std::vector<Particle>::const_iterator first, std::vector<Particle>::const_iterator last){ return 1 < count_gluons(first,last); } bool is_AWZ_proccess(Process const & proc){ return proc.boson && is_AWZ_boson(*proc.boson); } bool is_up_type(Particle const & part){ return HEJ::is_anyquark(part) && !(abs(part.type)%2); } bool is_down_type(Particle const & part){ return HEJ::is_anyquark(part) && abs(part.type)%2; } bool can_couple_to_W(Particle const & part, pid::ParticleID const W_id){ const int W_charge = W_id>0?1:-1; return abs(part.type)<5 && ( (W_charge*part.type > 0 && is_up_type(part)) || (W_charge*part.type < 0 && is_down_type(part)) ); } } void PhaseSpacePoint::maybe_turn_to_subl( double chance, unsigned int const channels, Process const & proc, HEJ::RNG & ran ){ if(proc.njets <= 2) return; assert(outgoing_.size() >= 2); // decide what kind of subleading process is allowed bool allow_uno = false; bool allow_strange = true; const size_t nout = outgoing_.size(); const bool can_be_uno_backward = (channels&Subleading::uno) && can_swap_to_uno(outgoing_[0], outgoing_[1]); const bool can_be_uno_forward = (channels&Subleading::uno) && can_swap_to_uno(outgoing_[nout-1], outgoing_[nout-2]); allow_uno = can_be_uno_backward || can_be_uno_forward; bool allow_qqx = false; if(is_AWZ_proccess(proc)) { allow_qqx = (channels&Subleading::qqx) && can_change_to_qqx(outgoing_.cbegin(), outgoing_.cend()); if(std::none_of(outgoing_.cbegin(), outgoing_.cend(), [&proc](Particle const & p){ return can_couple_to_W(p, *proc.boson);})) { // enforce qqx if A/W/Z can't couple somewhere else assert(allow_qqx); allow_uno = false; chance = 1.; // strange not allowed for W if(abs(*proc.boson)== pid::Wp) allow_strange = false; } } if(!allow_uno && !allow_qqx) return; if(ran.flat() < chance){ weight_ /= chance; if(allow_uno && !allow_qqx){ turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran); } else if (!allow_uno && allow_qqx) { turn_to_qqx(allow_strange, ran); } else { assert( allow_uno && allow_qqx); if(ran.flat() < 0.5) turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran); else turn_to_qqx(allow_strange, ran); weight_ *= 2.; } } else weight_ /= 1 - chance; } void PhaseSpacePoint::turn_to_uno( const bool can_be_uno_backward, const bool can_be_uno_forward, HEJ::RNG & ran ){ if(!can_be_uno_backward && !can_be_uno_forward) return; const size_t nout = outgoing_.size(); if(can_be_uno_backward && can_be_uno_forward){ if(ran.flat() < 0.5){ std::swap(outgoing_[0].type, outgoing_[1].type); } else { std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type); } weight_ *= 2.; } else if(can_be_uno_backward){ std::swap(outgoing_[0].type, outgoing_[1].type); } else { assert(can_be_uno_forward); std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type); } } void PhaseSpacePoint::turn_to_qqx(const bool allow_strange, HEJ::RNG & ran){ /// find first and last gluon in FKL chain auto first = std::find_if(outgoing_.begin(), outgoing_.end(), [](Particle const & p){return p.type == pid::gluon;}); std::vector<Particle*> FKL_gluons; for(auto p = first; p!=outgoing_.end(); ++p){ if(p->type == pid::gluon) FKL_gluons.push_back(&*p); else if(is_anyquark(*p)) break; } const size_t ng = FKL_gluons.size(); if(ng < 2) throw std::logic_error("not enough gluons to create qqx"); // select flavour of quark const double r1 = 2.*ran.flat()-1.; const double max_flavour = allow_strange?n_f:n_f-1; weight_ *= max_flavour*2; int flavour = pid::down + std::floor(std::abs(r1)*max_flavour); flavour*=r1<0.?-1:1; // select gluon for switch const size_t idx = floor((ng-1) * ran.flat()); weight_ *= (ng-1); FKL_gluons[idx]->type = ParticleID(flavour); FKL_gluons[idx+1]->type = ParticleID(-flavour); } template<class ParticleMomenta> fastjet::PseudoJet PhaseSpacePoint::gen_last_momentum( ParticleMomenta const & other_momenta, const double mass_square, const double y ) const { std::array<double,2> pt{0.,0.}; for (auto const & p: other_momenta) { pt[0]-= p.px(); pt[1]-= p.py(); } const double mperp = sqrt(pt[0]*pt[0]+pt[1]*pt[1]+mass_square); const double pz=mperp*sinh(y); const double E=mperp*cosh(y); return {pt[0], pt[1], pz, E}; } namespace { //! adds a particle to target (in correct rapidity ordering) //! @returns positon of insertion auto insert_particle(std::vector<HEJ::Particle> & target, HEJ::Particle && particle ){ const auto pos = std::upper_bound( begin(target),end(target),particle,rapidity_less{} ); target.insert(pos, std::move(particle)); return pos; } } PhaseSpacePoint::PhaseSpacePoint( Process const & proc, JetParameters const & jet_param, HEJ::PDF & pdf, double E_beam, double const subl_chance, unsigned int const subl_channels, ParticlesPropMap const & particles_properties, HEJ::RNG & ran ) { assert(proc.njets >= 2); if(proc.boson && particles_properties.find(*(proc.boson)) == particles_properties.end()) throw HEJ::missing_option("Boson " +std::to_string(*(proc.boson))+" can't be generated: missing properties"); status_ = good; weight_ = 1; const int nout = proc.njets + (proc.boson?1:0) + proc.leptons.size(); outgoing_.reserve(nout); // generate parton momenta const bool is_pure_jets = (nout == proc.njets); auto partons = gen_LO_partons( proc.njets, is_pure_jets, jet_param, E_beam, ran ); // pre fill flavour with gluons for(auto&& p_out: partons) { outgoing_.emplace_back(Particle{pid::gluon, std::move(p_out), {}}); } if(status_ != good) return; // create phase space point for (lepton,neutrino)-pair of W+/W- // @TODO this have massive overlap with the "create boson" section if(proc.leptons.size()==2){ auto pair(gen_enu(proc.leptons,ran)); for(auto&& p: pair) insert_particle(outgoing_, std::move(p)); } // create boson if(proc.boson){ const auto & boson_prop = particles_properties.at(*proc.boson); auto boson(gen_boson(*proc.boson, boson_prop.mass, boson_prop.width, ran)); const auto pos{insert_particle(outgoing_, std::move(boson))}; if(! boson_prop.decays.empty()){ const size_t boson_idx = std::distance(begin(outgoing_), pos); decays_.emplace( boson_idx, decay_boson(outgoing_[boson_idx], boson_prop.decays, ran) ); } } // normalisation of momentum-conserving delta function weight_ *= pow(2*M_PI, 4); /** @TODO * uf (jet_param.min_pt) doesn't correspond to our final scale choice. * The HEJ scale generators currently expect a full event as input, * so fixing this is not completely trivial */ reconstruct_incoming(proc, subl_channels, pdf, E_beam, jet_param.min_pt, ran); if(status_ != good) return; // set outgoing states most_backward_FKL(outgoing_).type = incoming_[0].type; most_forward_FKL(outgoing_).type = incoming_[1].type; maybe_turn_to_subl(subl_chance, subl_channels, proc, ran); if(proc.boson) couple_boson(*proc.boson, ran); } double PhaseSpacePoint::gen_hard_pt( int np , double ptmin, double ptmax, double y, HEJ::RNG & ran ) { // heuristic parameters for pt sampling const double ptpar = ptmin + np/5.; const double arg_small_y = atan((ptmax - ptmin)/ptpar); const double y_cut = 3.; const double r1 = ran.flat(); if(y < y_cut){ const double pt = ptmin + ptpar*tan(r1*arg_small_y); const double temp = cos(r1*arg_small_y); weight_ *= pt*ptpar*arg_small_y/(temp*temp); return pt; } const double ptpar2 = ptpar/(1 + 5*(y-y_cut)); const double temp = 1. - std::exp((ptmin-ptmax)/ptpar2); const double pt = ptmin - ptpar2*std::log(1-r1*temp); weight_ *= pt*ptpar2*temp/(1-r1*temp); return pt; } double PhaseSpacePoint::gen_soft_pt(int np, double max_pt, HEJ::RNG & ran) { constexpr double ptpar = 4.; const double r = ran.flat(); const double pt = max_pt + ptpar/np*std::log(r); weight_ *= pt*ptpar/(np*r); return pt; } double PhaseSpacePoint::gen_parton_pt( int count, JetParameters const & jet_param, double max_pt, double y, HEJ::RNG & ran ) { constexpr double p_small_pt = 0.02; if(! jet_param.peak_pt) { return gen_hard_pt(count, jet_param.min_pt, max_pt, y, ran); } const double r = ran.flat(); if(r > p_small_pt) { weight_ /= 1. - p_small_pt; return gen_hard_pt(count, *jet_param.peak_pt, max_pt, y, ran); } weight_ /= p_small_pt; const double pt = gen_soft_pt(count, *jet_param.peak_pt, ran); if(pt < jet_param.min_pt) { weight_=0.0; status_ = not_enough_jets; return jet_param.min_pt; } return pt; } std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_LO_partons( int np, bool is_pure_jets, JetParameters const & jet_param, double max_pt, HEJ::RNG & ran ){ if (np<2) throw std::invalid_argument{"Not enough partons in gen_LO_partons"}; weight_ /= pow(16.*pow(M_PI,3),np); weight_ /= std::tgamma(np+1); //remove rapidity ordering std::vector<fastjet::PseudoJet> partons; partons.reserve(np); for(int i = 0; i < np; ++i){ const double y = -jet_param.max_y + 2*jet_param.max_y*ran.flat(); weight_ *= 2*jet_param.max_y; const bool is_last_parton = i+1 == np; if(is_pure_jets && is_last_parton) { constexpr double parton_mass_sq = 0.; partons.emplace_back(gen_last_momentum(partons, parton_mass_sq, y)); break; } const double phi = 2*M_PI*ran.flat(); weight_ *= 2.0*M_PI; const double pt = gen_parton_pt(np, jet_param, max_pt, y, ran); if(weight_ == 0.0) return {}; partons.emplace_back(fastjet::PtYPhiM(pt, y, phi)); assert(jet_param.min_pt <= partons[i].pt()); assert(partons[i].pt() <= max_pt+1e-5); } // Need to check that at LO, the number of jets = number of partons; fastjet::ClusterSequence cs(partons, jet_param.def); auto cluster_jets=cs.inclusive_jets(jet_param.min_pt); if (cluster_jets.size()!=unsigned(np)){ weight_=0.0; status_ = not_enough_jets; return {}; } std::sort(begin(partons), end(partons), rapidity_less{}); return partons; } std::vector<Particle> PhaseSpacePoint::gen_enu( std::vector<HEJ::pid::ParticleID> const & pair, HEJ::RNG & ran ){ assert(pair.size() == 2); // Now we know the transverse momentum of the W, given by the array kt // double pW[4]; // Choose its mass according to Breit-Wigner double r1=ran.flat(); double sW=HEJ::MW*(HEJ::MW + HEJ::GammaW*tan((M_PI*r1)/2. + (-1. + r1)*atan(HEJ::MW/HEJ::GammaW))); // Multiply by derivate (d sap)/(d r) { static double temp=atan(HEJ::MW/HEJ::GammaW); weight_*=(HEJ::GammaW*HEJ::MW*(M_PI+2.*temp))/(1.+cos(M_PI*r1+2.*(-1.+r1)*temp)); } // Generate a yW Gaussian distributed around 0 double yW; { double lninvr1,r1,r2,temp,a; r1=ran.flat(); r2=ran.flat(); lninvr1=-log(r1); a=0.7; // tuned number temp=a*sqrt(2.*lninvr1)*cos(2.*M_PI*r2); yW=temp; weight_=weight_*(exp(temp*temp/2./a/a))*sqrt(2.*M_PI)*a; } auto p = gen_last_momentum(outgoing_, sW, yW); CLHEP::HepLorentzVector pWv(p.px(),p.py(),p.pz(),p.e()); double ppW[4],ppWs; CLHEP::HepLorentzVector ppWv,appWv,pd1,pd2; ppWs=sqrt(sW)/2.; // Choose theta and phi double pptheta=2.*M_PI*ran.flat(); double cosppphi=2.*ran.flat()-1.; weight_*=2.*M_PI*2.; double sinphi=sqrt(1.-cosppphi*cosppphi); // Know 0 < phi < pi weight_*=1./(pow(2.*M_PI,3)*2.)/(4.); // Divide by 8, *2, see WPhaseSpace.tex @TODO where?!? // (phi -> cosphi now so no sinphi in J) // construct 4-vector in W rest frame ppW[0]=ppWs; ppW[1]=ppWs*cos(pptheta)*sinphi; ppW[2]=ppWs*sin(pptheta)*sinphi; ppW[3]=ppWs*cosppphi; ppWv.set(ppW[1],ppW[2],ppW[3],ppW[0]); appWv.set(-ppW[1],-ppW[2],-ppW[3],ppW[0]); // translate to lab frame pd1=ppWv.boost(pWv.boostVector()); //particle pd2=appWv.boost(pWv.boostVector()); //anti-particle // assign particle and anti-particle momentum // find the particle, assuming the pair is ordered (anti-lepton,lepton) HEJ::Particle alepton{pair[0], fastjet::PseudoJet{pd2.px(),pd2.py(),pd2.pz(),pd2.e()}, {}}; HEJ::Particle lepton{pair[1], fastjet::PseudoJet{pd1.px(),pd1.py(),pd1.pz(),pd1.e()}, {}}; return std::vector<HEJ::Particle>{alepton,lepton}; } Particle PhaseSpacePoint::gen_boson( HEJ::ParticleID bosonid, double mass, double width, HEJ::RNG & ran ){ // Usual phase space measure weight_ /= 16.*pow(M_PI, 3); // Generate a y Gaussian distributed around 0 /// @TODO: magic number only for Higgs /// @TODO better sampling for W const double y = random_normal(1.6, ran); const double r1 = ran.flat(); const double sH = mass*( mass + width*tan(M_PI/2.*r1 + (r1-1.)*atan(mass/width)) ); auto p = gen_last_momentum(outgoing_, sH, y); return Particle{bosonid, std::move(p), {}}; } Particle const & PhaseSpacePoint::most_backward_FKL( std::vector<Particle> const & partons ) const{ if(!HEJ::is_parton(partons[0])) return partons[1]; return partons[0]; } Particle const & PhaseSpacePoint::most_forward_FKL( std::vector<Particle> const & partons ) const{ const size_t last_idx = partons.size() - 1; if(!HEJ::is_parton(partons[last_idx])) return partons[last_idx-1]; return partons[last_idx]; } Particle & PhaseSpacePoint::most_backward_FKL( std::vector<Particle> & partons ) const{ if(!HEJ::is_parton(partons[0])) return partons[1]; return partons[0]; } Particle & PhaseSpacePoint::most_forward_FKL( std::vector<Particle> & partons ) const{ const size_t last_idx = partons.size() - 1; if(!HEJ::is_parton(partons[last_idx])) return partons[last_idx-1]; return partons[last_idx]; } namespace { /// partons are ordered: even = anti, 0 = gluon ParticleID index_to_pid(size_t i){ if(!i) return pid::gluon; return static_cast<ParticleID>(i%2?(i+1)/2:-i/2); } /// partons are ordered: even = anti, 0 = gluon size_t pid_to_index(ParticleID id){ if(id==pid::gluon) return 0; return id>0?id*2-1:abs(id)*2; } std::bitset<11> init_allowed(ParticleID const id){ if(abs(id) == pid::proton) return ~0; std::bitset<11> out = 0; if(is_parton(id)) out[pid_to_index(id)] = 1; return out; } /// decides which "index" (see index_to_pid) are allowed for process std::bitset<11> allowed_quarks(ParticleID const boson){ std::bitset<11> allowed = ~0; if(abs(boson) == pid::Wp){ // special case W: // Wp: anti-down or up-type quark, no b/t -> 0001100110(1) = 205 // Wm: down or anti-up-type quark, no b/t -> 0010011001(1) = 307 allowed = boson>0?205:307; } return allowed; } } /** * checks which partons are allowed as initial state: * 1. only allow what is given in the Runcard (p -> all) * 2. A/W/Z require something to couple to * a) no qqx => no incoming gluon * b) 2j => no incoming gluon * c) 3j => can couple OR is gluon => 2 gluons become qqx later */ std::array<std::bitset<11>,2> PhaseSpacePoint::filter_partons( Process const & proc, unsigned int const subl_channels, HEJ::RNG & ran ){ std::array<std::bitset<11>,2> allowed_partons{ init_allowed(proc.incoming[0]), init_allowed(proc.incoming[1]) }; bool const allow_qqx = subl_channels&Subleading::qqx; // special case A/W/Z if(is_AWZ_proccess(proc) && ((proc.njets < 4) || !allow_qqx)){ // all possible incoming states auto allowed(allowed_quarks(*proc.boson)); if(proc.njets == 2 || !allow_qqx) allowed[0]=0; // possible states per leg std::array<std::bitset<11>,2> const maybe_partons{ allowed_partons[0]&allowed, allowed_partons[1]&allowed}; if(maybe_partons[0].any() && maybe_partons[1].any()){ // two options to get allowed initial state => choose one at random const size_t idx = ran.flat() < 0.5; allowed_partons[idx] = maybe_partons[idx]; // else choose the possible } else if(maybe_partons[0].any()) { allowed_partons[0] = maybe_partons[0]; } else if(maybe_partons[1].any()) { allowed_partons[1] = maybe_partons[1]; } else{ throw std::invalid_argument{"Incoming state not allowed."}; } } return allowed_partons; } void PhaseSpacePoint::reconstruct_incoming( Process const & proc, unsigned int const subl_channels, HEJ::PDF & pdf, double E_beam, double uf, HEJ::RNG & ran ){ std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_); // calculate xa, xb const double sqrts=2*E_beam; const double xa=(incoming_[0].p.e()-incoming_[0].p.pz())/sqrts; const double xb=(incoming_[1].p.e()+incoming_[1].p.pz())/sqrts; // abort if phase space point is outside of collider energy reach if (xa>1. || xb>1.){ weight_=0; status_ = too_much_energy; return; } auto const & ids = proc.incoming; std::array<std::bitset<11>,2> allowed_partons( filter_partons(proc, subl_channels, ran)); for(size_t i = 0; i < 2; ++i){ if(ids[i] == pid::proton || ids[i] == pid::p_bar){ // pick ids according to pdfs incoming_[i].type = generate_incoming_id(i, i?xb:xa, uf, pdf, allowed_partons[i], ran); } else { assert(allowed_partons[i][pid_to_index(ids[i])]); incoming_[i].type = ids[i]; } } assert(momentum_conserved(1e-7)); } HEJ::ParticleID PhaseSpacePoint::generate_incoming_id( size_t const beam_idx, double const x, double const uf, HEJ::PDF & pdf, std::bitset<11> allowed_partons, HEJ::RNG & ran ){ std::array<double,11> pdf_wt; pdf_wt[0] = allowed_partons[0]?fabs(pdf.pdfpt(beam_idx,x,uf,pid::gluon)):0.; double pdftot = pdf_wt[0]; for(size_t i = 1; i < pdf_wt.size(); ++i){ pdf_wt[i] = allowed_partons[i]?4./9.*fabs(pdf.pdfpt(beam_idx,x,uf,index_to_pid(i))):0; pdftot += pdf_wt[i]; } const double r1 = pdftot * ran.flat(); double sum = 0; for(size_t i=0; i < pdf_wt.size(); ++i){ if (r1 < (sum+=pdf_wt[i])){ weight_*= pdftot/pdf_wt[i]; return index_to_pid(i); } } std::cerr << "Error in choosing incoming parton: "<<x<<" "<<uf<<" " <<sum<<" "<<pdftot<<" "<<r1<<std::endl; throw std::logic_error{"Failed to choose parton flavour"}; } void PhaseSpacePoint::couple_boson( HEJ::ParticleID const boson, HEJ::RNG & ran ){ if(abs(boson) != pid::Wp) return; // only matters for W /// @TODO this could be use to sanity check gamma and Z // find all possible quarks std::vector<Particle*> allowed_parts; for(auto & part: outgoing_){ // Wp -> up OR anti-down, Wm -> anti-up OR down, no bottom if ( can_couple_to_W(part, boson) ) allowed_parts.push_back(&part); } if(allowed_parts.size() == 0){ throw std::logic_error{"Found no parton for coupling with boson"}; } // select one and flip it size_t idx = 0; if(allowed_parts.size() > 1){ /// @TODO more efficient sampling /// old code: probability[i] = exp(parton[i].y - W.y) idx = floor(ran.flat()*allowed_parts.size()); weight_ *= allowed_parts.size(); } const int W_charge = boson>0?1:-1; allowed_parts[idx]->type = static_cast<ParticleID>( allowed_parts[idx]->type - W_charge ); } double PhaseSpacePoint::random_normal( double stddev, HEJ::RNG & ran ){ const double r1 = ran.flat(); const double r2 = ran.flat(); const double lninvr1 = -log(r1); const double result = stddev*sqrt(2.*lninvr1)*cos(2.*M_PI*r2); weight_ *= exp(result*result/(2*stddev*stddev))*sqrt(2.*M_PI)*stddev; return result; } bool PhaseSpacePoint::momentum_conserved(double ep) const{ fastjet::PseudoJet diff; for(auto const & in: incoming()) diff += in.p; for(auto const & out: outgoing()) diff -= out.p; return nearby_ep(diff, fastjet::PseudoJet{}, ep); } Decay PhaseSpacePoint::select_decay_channel( std::vector<Decay> const & decays, HEJ::RNG & ran ){ double br_total = 0.; for(auto const & decay: decays) br_total += decay.branching_ratio; // adjust weight // this is given by (channel branching ratio)/(chance to pick channel) // where (chance to pick channel) = // (channel branching ratio)/(total branching ratio) weight_ *= br_total; const double r1 = br_total*ran.flat(); double br_sum = 0.; for(auto const & decay: decays){ br_sum += decay.branching_ratio; if(r1 < br_sum) return decay; } throw std::logic_error{"unreachable"}; } std::vector<Particle> PhaseSpacePoint::decay_boson( HEJ::Particle const & parent, std::vector<Decay> const & decays, HEJ::RNG & ran ){ const auto channel = select_decay_channel(decays, ran); if(channel.products.size() != 2){ throw HEJ::not_implemented{ "only decays into two particles are implemented" }; } std::vector<Particle> decay_products(channel.products.size()); for(size_t i = 0; i < channel.products.size(); ++i){ decay_products[i].type = channel.products[i]; } // choose polar and azimuth angle in parent rest frame const double E = parent.m()/2; const double theta = 2.*M_PI*ran.flat(); const double cos_phi = 2.*ran.flat()-1.; const double sin_phi = sqrt(1. - cos_phi*cos_phi); // Know 0 < phi < pi const double px = E*cos(theta)*sin_phi; const double py = E*sin(theta)*sin_phi; const double pz = E*cos_phi; decay_products[0].p.reset(px, py, pz, E); decay_products[1].p.reset(-px, -py, -pz, E); for(auto & particle: decay_products) particle.p.boost(parent.p); return decay_products; } } diff --git a/FixedOrderGen/src/Unweighter.cc b/FixedOrderGen/src/Unweighter.cc index 7bb1695..16996e5 100644 --- a/FixedOrderGen/src/Unweighter.cc +++ b/FixedOrderGen/src/Unweighter.cc @@ -1,26 +1,31 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "Unweighter.hh" #include <cassert> #include "HEJ/Event.hh" namespace HEJFOG { namespace detail { bool has_jet_softer_than(HEJ::Event const & ev, double pt) { assert(! ev.jets().empty()); const auto softest_jet = fastjet::sorted_by_pt(ev.jets()).back(); return softest_jet.pt() < pt; } } HEJ::optional<HEJ::Event> Unweighter::unweight(HEJ::Event ev) const { if(detail::has_jet_softer_than(ev, min_unweight_pt_)) return ev; const double awt = std::abs(ev.central().weight); if(ran_.get().flat() < awt/cut_) { if(awt < cut_) ev.parameters() *= cut_/awt; return ev; } return {}; } } diff --git a/FixedOrderGen/src/config.cc b/FixedOrderGen/src/config.cc index c3b3057..cf43551 100644 --- a/FixedOrderGen/src/config.cc +++ b/FixedOrderGen/src/config.cc @@ -1,388 +1,393 @@ +/** + * \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', 'e-', 'e+', 'nu_e', 'nu_e_bar'" }; } bool leptons_flavours_OK(std::vector<ParticleID> const & pid) { assert(pid.size()==2); assert(is_sorted(begin(pid),end(pid))); // Check it is a W+/W- const int pidsum = pid[0]+pid[1]; if (HEJ::is_antineutrino(pid[0])){ if (pidsum!=-1) return false; } else { if (pidsum!=1) return false; } return true; } 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){ if(result.boson){ throw std::invalid_argument{ "More than one outgoing boson 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.leptons.size()==2||result.boson){ throw std::invalid_argument { "Too many leptons required " }; } result.leptons.emplace_back(pid); } else { throw invalid_outgoing(particles[i]); } } } std::sort(std::begin(result.leptons),std::end(result.leptons)); if(result.njets < 2){ throw std::invalid_argument{ "Process has to include at least two jets ('j')" }; } if((result.leptons.size()>0) && (!leptons_flavours_OK(result.leptons))){ throw std::invalid_argument{ "Requested process has unsupported combinations of leptons" }; } return result; } HEJFOG::Subleading to_subleading_channel(YAML::Node const & yaml){ std::string name; using HEJFOG::Subleading; 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; // 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"); set_from_yaml(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(); set_from_yaml(result.back().products, decay_str, "into"); set_from_yaml(result.back().branching_ratio, decay_str, "branching ratio"); } 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/FixedOrderGen/src/main.cc b/FixedOrderGen/src/main.cc index 01b9b80..806d0d8 100644 --- a/FixedOrderGen/src/main.cc +++ b/FixedOrderGen/src/main.cc @@ -1,228 +1,228 @@ /** - * Name: main.cc - * Authors: Jeppe R. Andersen + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later */ - #include <algorithm> #include <chrono> #include <fstream> #include <iostream> #include <map> #include <memory> #include "yaml-cpp/yaml.h" #include "LHEF/LHEF.h" #include "HEJ/CombinedEventWriter.hh" #include "HEJ/CrossSectionAccumulator.hh" #include "HEJ/get_analysis.hh" #include "HEJ/LesHouchesWriter.hh" #include "HEJ/make_RNG.hh" #include "HEJ/ProgressBar.hh" #include "HEJ/stream.hh" #include "config.hh" #include "EventGenerator.hh" #include "PhaseSpacePoint.hh" #include "Unweighter.hh" #include "Version.hh" namespace{ constexpr auto banner = " __ ___ __ ______ __ __ \n" " / / / (_)___ _/ /_ / ____/___ ___ _________ ___ __ / /__ / /______ \n" " / /_/ / / __ `/ __ \\ / __/ / __ \\/ _ \\/ ___/ __ `/ / / / __ / / _ \\/ __/ ___/ \n" " / __ / / /_/ / / / / / /___/ / / / __/ / / /_/ / /_/ / / /_/ / __/ /_(__ ) \n" " /_/ /_/_/\\__, /_/ /_/ /_____/_/ /_/\\___/_/ \\__, /\\__, / \\____/\\___/\\__/____/ \n" " ____///__/ __ ____ ///__//____/ ______ __ \n" " / ____(_) _____ ____/ / / __ \\_________/ /__ _____ / ____/__ ____ ___ _________ _/ /_____ _____\n" " / /_ / / |/_/ _ \\/ __ / / / / / ___/ __ / _ \\/ ___/ / / __/ _ \\/ __ \\/ _ \\/ ___/ __ `/ __/ __ \\/ ___/\n" " / __/ / /> </ __/ /_/ / / /_/ / / / /_/ / __/ / / /_/ / __/ / / / __/ / / /_/ / /_/ /_/ / / \n" " /_/ /_/_/|_|\\___/\\__,_/ \\____/_/ \\__,_/\\___/_/ \\____/\\___/_/ /_/\\___/_/ \\__,_/\\__/\\____/_/ \n" ; constexpr double invGeV2_to_pb = 389379292.; constexpr long long max_warmup_events = 10000; } HEJFOG::Config load_config(char const * filename){ try{ return HEJFOG::load_config(filename); } catch(std::exception const & exc){ std::cerr << "Error: " << exc.what() << '\n'; std::exit(EXIT_FAILURE); } } std::unique_ptr<HEJ::Analysis> get_analysis( YAML::Node const & parameters ){ try{ return HEJ::get_analysis(parameters); } catch(std::exception const & exc){ std::cerr << "Failed to load analysis: " << exc.what() << '\n'; std::exit(EXIT_FAILURE); } } int main(int argn, char** argv) { using namespace std::string_literals; if (argn < 2) { std::cerr << "\n# Usage:\n." << argv[0] << " config_file\n"; return EXIT_FAILURE; } std::cout << banner; std::cout << "Version " << HEJFOG::Version::String() << ", revision " << HEJFOG::Version::revision() << std::endl; fastjet::ClusterSequence::print_banner(); using clock = std::chrono::system_clock; const auto start_time = clock::now(); // read configuration auto config = load_config(argv[1]); std::unique_ptr<HEJ::Analysis> analysis = get_analysis( config.analysis_parameters ); assert(analysis != nullptr); auto ran = HEJ::make_RNG(config.rng.name, config.rng.seed); assert(ran != nullptr); HEJ::ScaleGenerator scale_gen{ config.scales.base, config.scales.factors, config.scales.max_ratio }; HEJFOG::EventGenerator generator{ config.process, config.beam, std::move(scale_gen), config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, *ran }; LHEF::HEPRUP heprup; heprup.IDBMUP=std::pair<long,long>(config.beam.particles[0], config.beam.particles[1]); heprup.EBMUP=std::make_pair(config.beam.energy, config.beam.energy); heprup.PDFGUP=std::make_pair(0,0); heprup.PDFSUP=std::make_pair(config.pdf_id,config.pdf_id); heprup.NPRUP=1; heprup.XSECUP=std::vector<double>(1.); heprup.XERRUP=std::vector<double>(1.); heprup.LPRUP=std::vector<int>{1}; heprup.generators.emplace_back(LHEF::XMLTag{}); heprup.generators.back().name = HEJFOG::Version::package_name(); heprup.generators.back().version = HEJFOG::Version::String(); HEJ::CombinedEventWriter writer{config.output, heprup}; HEJ::optional<HEJFOG::Unweighter> unweighter{}; std::map<HEJFOG::Status, int> status_counter; std::vector<HEJ::Event> events; int trials = 0; // warm-up phase to train unweighter if(config.unweight) { std::cout << "Calibrating unweighting ...\n"; const auto warmup_start = clock::now(); const size_t warmup_events = config.unweight->sample_size; HEJ::ProgressBar<size_t> warmup_progress{std::cout, warmup_events}; for(; events.size() < warmup_events; ++trials){ auto ev = generator.gen_event(); ++status_counter[generator.status()]; assert( (generator.status() == HEJFOG::good) == bool(ev) ); if(generator.status() == HEJFOG::good && analysis->pass_cuts(*ev, *ev)) { events.emplace_back(std::move(*ev)); ++warmup_progress; } } std::cout << std::endl; unweighter = HEJFOG::Unweighter{ begin(events), end(events), config.unweight->max_dev, *ran, config.jets.peak_pt?(*config.jets.peak_pt):0. }; std::vector<HEJ::Event> unweighted_events; for(auto && ev: events) { auto unweighted = unweighter->unweight(std::move(ev)); if(unweighted) { unweighted_events.emplace_back(std::move(*unweighted)); } } events = std::move(unweighted_events); if(events.empty()) { std::cerr << "Failed to generate events. Please increase \"unweight: sample size\"" " or reduce \"unweight: max deviation\"\n"; return EXIT_FAILURE; } const auto warmup_end = clock::now(); const double completion = static_cast<double>(events.size())/config.events; const std::chrono::duration<double> remaining_time = (warmup_end- warmup_start)*(1./completion - 1); const auto finish = clock::to_time_t( std::chrono::time_point_cast<std::chrono::seconds>(warmup_end + remaining_time) ); std::cout << "Generated " << events.size() << "/" << config.events << " events (" << static_cast<int>(std::round(100*completion)) << "%)\n" << "Estimated remaining generation time: " << remaining_time.count() << " seconds (" << std::put_time(std::localtime(&finish), "%c") << ")\n\n"; } HEJ::ProgressBar<long long> progress{std::cout, config.events}; progress.increment(events.size()); events.reserve(config.events); for(; events.size() < static_cast<size_t>(config.events); ++trials){ auto ev = generator.gen_event(); ++status_counter[generator.status()]; assert( (generator.status() == HEJFOG::good) == bool(ev) ); if(generator.status() == HEJFOG::good && analysis->pass_cuts(*ev, *ev)) { if(unweighter) { auto unweighted = unweighter->unweight(std::move(*ev)); if(! unweighted) continue; ev = std::move(unweighted); } events.emplace_back(std::move(*ev)); ++progress; } } std::cout << std::endl; HEJ::CrossSectionAccumulator xs; for(auto & ev: events){ ev.parameters() *= invGeV2_to_pb/trials; analysis->fill(ev, ev); writer.write(ev); xs.fill(ev); } analysis->finalise(); const std::chrono::duration<double> run_time = (clock::now() - start_time); std::cout << "\nTask Runtime: " << run_time.count() << " seconds.\n\n"; std::cout << xs << '\n'; for(auto && entry: status_counter){ const double fraction = static_cast<double>(entry.second)/trials; const int percent = std::round(100*fraction); std::cout << "status " << std::left << std::setw(16) << (to_string(entry.first) + ":") << " ["; for(int i = 0; i < percent/2; ++i) std::cout << '#'; for(int i = percent/2; i < 50; ++i) std::cout << ' '; std::cout << "] " << percent << "%\n"; } } diff --git a/FixedOrderGen/t/2j.cc b/FixedOrderGen/t/2j.cc index ea68d04..ae63974 100644 --- a/FixedOrderGen/t/2j.cc +++ b/FixedOrderGen/t/2j.cc @@ -1,60 +1,65 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include <cmath> #include <cassert> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Mixmax.hh" #include "HEJ/Event.hh" #include "HEJ/PDF.hh" #include "HEJ/MatrixElement.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 86.42031848*1e6; //calculated with "combined" HEJ svn r3480 auto config = load_config("config_2j.yml"); HEJ::Mixmax ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n'; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.01*xs); } diff --git a/FixedOrderGen/t/4j.cc b/FixedOrderGen/t/4j.cc index a597242..09919f1 100644 --- a/FixedOrderGen/t/4j.cc +++ b/FixedOrderGen/t/4j.cc @@ -1,61 +1,66 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include <cmath> #include <cassert> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Mixmax.hh" #include "HEJ/Event.hh" #include "HEJ/PDF.hh" #include "HEJ/MatrixElement.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 0.81063619*1e6; //calculated with "combined" HEJ svn r3480 auto config = load_config("config_2j.yml"); config.process.njets = 4; HEJ::Mixmax ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n'; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.03*xs); } diff --git a/FixedOrderGen/t/W_2j_classify.cc b/FixedOrderGen/t/W_2j_classify.cc index 4cddbf0..5dfc5c8 100644 --- a/FixedOrderGen/t/W_2j_classify.cc +++ b/FixedOrderGen/t/W_2j_classify.cc @@ -1,147 +1,152 @@ -// check that the PSP generates only "valid" W + 2 jets events - +/** + * \brief check that the PSP generates only "valid" W + 2 jets events + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include "JetParameters.hh" #include "ParticleProperties.hh" #include "PhaseSpacePoint.hh" #include "Process.hh" #include "Subleading.hh" #include "HEJ/Mixmax.hh" #include "HEJ/PDF.hh" #include "HEJ/utility.hh" using namespace HEJFOG; using namespace HEJ; namespace { void print_psp(PhaseSpacePoint const & psp){ std::cerr << "Process:\n" << psp.incoming()[0].type << " + "<< psp.incoming()[1].type << " -> "; for(auto const & out: psp.outgoing()){ std::cerr << out.type << " "; } std::cerr << "\n"; } void bail_out(PhaseSpacePoint const & psp, std::string msg){ print_psp(psp); throw std::logic_error{msg}; } bool is_up_type(Particle const & part){ return HEJ::is_anyquark(part) && !(abs(part.type)%2); } bool is_down_type(Particle const & part){ return HEJ::is_anyquark(part) && abs(part.type)%2; } bool check_W2j(PhaseSpacePoint const & psp, ParticleID const W_type){ bool found_quark = false; bool found_anti = false; std::vector<Particle> out_partons; std::vector<Particle> Wp; for(auto const & p: psp.outgoing()){ if(p.type == W_type) Wp.push_back(p); else if(is_parton(p)) out_partons.push_back(p); else bail_out(psp, "Found particle with is not " +std::to_string(int(W_type))+" or parton"); } if(Wp.size() != 1 || out_partons.size() != 2){ bail_out(psp, "Found wrong number of outgoing partons"); } for(size_t j=0; j<2; ++j){ auto const & in = psp.incoming()[j]; auto const & out = out_partons[j]; if(is_quark(in) || is_antiquark(in)) { found_quark = true; if(in.type != out.type) { // switch in quark type -> Wp couples to it if(found_anti){ // already found qq for coupling to W bail_out(psp, "Found second up/down pair"); } else if(abs(in.type)>4 || abs(out.type)>4){ bail_out(psp, "Found bottom/top pair"); } found_anti = true; if( is_up_type(in)) { // "up" in if(W_type > 0){ // -> only allowed u -> Wp + d if(in.type < 0 || is_up_type(out) || out.type < 0) bail_out(psp, "u -/> Wp + d"); } else { // -> only allowed ux -> Wm + dx if(in.type > 0 || is_up_type(out) || out.type > 0) bail_out(psp, "ux -/> Wm + dx"); } } else { // "down" in if(W_type > 0){ // -> only allowed dx -> Wp + ux if(in.type > 0 || is_down_type(out) || out.type > 0) bail_out(psp, "dx -/> Wp + ux"); } else { // -> only allowed d -> Wm + u if(in.type < 0 || is_down_type(out) || out.type < 0) bail_out(psp, "d -/> Wm + u"); } } } } } if(!found_quark) { bail_out(psp, "Found no initial quarks"); } else if(!found_anti){ bail_out(psp, "Found no up/down pair"); } return true; } } int main(){ constexpr size_t n_psp_base = 1337; const JetParameters jet_para{ fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 30, 5, 30}; PDF pdf(11000, pid::proton, pid::proton); constexpr double E_cms = 13000.; constexpr double subl_change = 0.5; constexpr auto subl_channels = Subleading::all; const ParticlesPropMap boson_prop{ {pid::Wp, {91.1876, 2.085, {Decay{ {pid::e_bar, pid::nu_e}, 1.}} }}, {pid::Wm, {91.1876, 2.085, {Decay{ {pid::e, pid::nu_e_bar}, 1.}} }} }; HEJ::Mixmax ran{}; // Wp2j Process proc {{pid::proton,pid::proton}, 2, pid::Wp}; size_t n_psp = n_psp_base; for( size_t i = 0; i<n_psp; ++i){ const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels, boson_prop, ran}; if(psp.status()==good){ check_W2j(psp, *proc.boson); } else { // bad process -> try again ++n_psp; } } std::cout << "Wp+2j: Took " << n_psp << " to generate " << n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl; // Wm2j proc = Process{{pid::proton,pid::proton}, 2, pid::Wm}; n_psp = n_psp_base; for( size_t i = 0; i<n_psp; ++i){ const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels, boson_prop, ran}; if(psp.status()==good){ check_W2j(psp, *proc.boson); } else { // bad process -> try again ++n_psp; } } std::cout << "Wm+2j: Took " << n_psp << " to generate " << n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl; std::cout << "All processes passed." << std::endl; return EXIT_SUCCESS; } diff --git a/FixedOrderGen/t/W_nj_classify.cc b/FixedOrderGen/t/W_nj_classify.cc index 2da7126..9e832ab 100644 --- a/FixedOrderGen/t/W_nj_classify.cc +++ b/FixedOrderGen/t/W_nj_classify.cc @@ -1,179 +1,184 @@ -// check that the PSP generates the all W+jet subleading processes - +/** + * \brief check that the PSP generates the all W+jet subleading processes + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include "JetParameters.hh" #include "ParticleProperties.hh" #include "PhaseSpacePoint.hh" #include "Process.hh" #include "Subleading.hh" #include "HEJ/Event.hh" #include "HEJ/Mixmax.hh" #include "HEJ/PDF.hh" #include "HEJ/utility.hh" using namespace HEJFOG; using namespace HEJ; namespace { void print_psp(PhaseSpacePoint const & psp){ std::cerr << "Process:\n" << psp.incoming()[0].type << " + "<< psp.incoming()[1].type << " -> "; for(auto const & out: psp.outgoing()){ std::cerr << out.type << " "; } std::cerr << "\n"; } void bail_out(PhaseSpacePoint const & psp, std::string msg){ print_psp(psp); throw std::logic_error{msg}; } } int main(){ constexpr size_t n_psp_base = 10375; const JetParameters jet_para{ fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 30, 5, 30}; PDF pdf(11000, pid::proton, pid::proton); constexpr double E_cms = 13000.; constexpr double subl_change = 0.8; const ParticlesPropMap boson_prop{ {pid::Wp, {91.1876, 2.085, {Decay{ {pid::e_bar, pid::nu_e}, 1.}} }}, {pid::Wm, {91.1876, 2.085, {Decay{ {pid::e, pid::nu_e_bar}, 1.}} }} }; HEJ::Mixmax ran{}; auto subl_channels = Subleading::all; std::vector<event_type::EventType> allowed_types{event_type::FKL, event_type::unob, event_type::unof, event_type::qqxexb, event_type::qqxexf}; std::cout << "Wp3j" << std::endl; // Wp3j Process proc {{pid::proton,pid::proton}, 3, pid::Wp}; size_t n_psp = n_psp_base; std::unordered_map<event_type::EventType, size_t> type_counter; for( size_t i = 0; i<n_psp; ++i){ const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels, boson_prop, ran}; if(psp.status()==good){ const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt) }; ++type_counter[ev.type()]; if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type()) == allowed_types.cend()) { bail_out(psp, "Found not allowed event of type " +std::string(event_type::names[ev.type()])); } } else { // bad process -> try again ++n_psp; } } std::cout << "Wp+3j: Took " << n_psp << " to generate " << n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl; std::cout << "States by classification:\n"; for(auto const & entry: type_counter){ const double fraction = static_cast<double>(entry.second)/n_psp_base; const int percent = std::round(100*fraction); std::cout << std::left << std::setw(25) << (event_type::names[entry.first] + std::string(":")) << entry.second << " (" << percent << "%)\n"; } for(auto const & t: allowed_types){ if(type_counter[t] < 0.05 * n_psp_base){ std::cerr << "Less than 5% of the events are of type " << event_type::names[t] << std::endl; return EXIT_FAILURE; } } // Wm3j - only uno proc = Process{{pid::proton,pid::proton}, 3, pid::Wm}; n_psp = n_psp_base; subl_channels = Subleading::uno; allowed_types = {event_type::FKL, event_type::unob, event_type::unof}; type_counter.clear(); for( size_t i = 0; i<n_psp; ++i){ const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels, boson_prop, ran}; if(psp.status()==good){ const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt) }; ++type_counter[ev.type()]; if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type()) == allowed_types.cend()) { bail_out(psp, "Found not allowed event of type " +std::string(event_type::names[ev.type()])); } } else { // bad process -> try again ++n_psp; } } std::cout << "Wm+3j (only uno): Took " << n_psp << " to generate " << n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl; std::cout << "States by classification:\n"; for(auto const & entry: type_counter){ const double fraction = static_cast<double>(entry.second)/n_psp_base; const int percent = std::round(100*fraction); std::cout << std::left << std::setw(25) << (event_type::names[entry.first] + std::string(":")) << entry.second << " (" << percent << "%)\n"; } for(auto const & t: allowed_types){ if(type_counter[t] < 0.05 * n_psp_base){ std::cerr << "Less than 5% of the events are of type " << event_type::names[t] << std::endl; return EXIT_FAILURE; } } // Wm4j proc = Process{{pid::proton,pid::proton}, 4, pid::Wm}; n_psp = n_psp_base; subl_channels = Subleading::all; allowed_types = {event_type::FKL, event_type::unob, event_type::unof, event_type::qqxexb, event_type::qqxexf, event_type::qqxmid}; type_counter.clear(); for( size_t i = 0; i<n_psp; ++i){ const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels, boson_prop, ran}; if(psp.status()==good){ const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt)}; ++type_counter[ev.type()]; if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type()) == allowed_types.cend()) { bail_out(psp, "Found not allowed event of type " +std::string(event_type::names[ev.type()])); } } else { // bad process -> try again ++n_psp; } } std::cout << "Wm+4j: Took " << n_psp << " to generate " << n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl; std::cout << "States by classification:\n"; for(auto const & entry: type_counter){ const double fraction = static_cast<double>(entry.second)/n_psp_base; const int percent = std::round(100*fraction); std::cout << std::left << std::setw(25) << (event_type::names[entry.first] + std::string(":")) << entry.second << " (" << percent << "%)\n"; } for(auto const & t: allowed_types){ if(type_counter[t] < 0.03 * n_psp_base){ std::cerr << "Less than 3% of the events are of type " << event_type::names[t] << std::endl; return EXIT_FAILURE; } } std::cout << "All processes passed." << std::endl; return EXIT_SUCCESS; } diff --git a/FixedOrderGen/t/h_2j.cc b/FixedOrderGen/t/h_2j.cc index 4ad315d..8bdc382 100644 --- a/FixedOrderGen/t/h_2j.cc +++ b/FixedOrderGen/t/h_2j.cc @@ -1,68 +1,73 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include <cmath> #include <cassert> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Ranlux64.hh" #include "HEJ/Event.hh" #include "HEJ/PDF.hh" #include "HEJ/MatrixElement.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 2.04928; // +- 0.00377252 //calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20 auto config = load_config("config_h_2j.yml"); HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; const auto the_Higgs = std::find_if( begin(ev->outgoing()), end(ev->outgoing()), [](HEJ::Particle const & p){ return p.type == HEJ::ParticleID::h; } ); assert(the_Higgs != end(ev->outgoing())); if(std::abs(the_Higgs->rapidity()) > 5.) continue; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << std::endl; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.01*xs); } diff --git a/FixedOrderGen/t/h_2j_decay.cc b/FixedOrderGen/t/h_2j_decay.cc index e404707..82de38a 100644 --- a/FixedOrderGen/t/h_2j_decay.cc +++ b/FixedOrderGen/t/h_2j_decay.cc @@ -1,87 +1,92 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include <cmath> #include <cassert> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Event.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/Particle.hh" #include "HEJ/PDF.hh" #include "HEJ/Ranlux64.hh" #include "HEJ/utility.hh" using namespace HEJFOG; bool pass_dR_cut( std::vector<fastjet::PseudoJet> const & jets, std::vector<HEJ::Particle> const & photons ){ constexpr double delta_R_min = 0.7; for(auto const & jet: jets){ for(auto const & photon: photons){ if(jet.delta_R(photon.p) < delta_R_min) return false; } } return true; } int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 0.00429198; // +- 1.0488e-05 //calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20 auto config = load_config("config_h_2j_decay.yml"); HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); assert(ev->decays().size() == 1); const auto decay = begin(ev->decays()); assert(ev->outgoing().size() > decay->first); const auto & the_Higgs = ev->outgoing()[decay->first]; assert(the_Higgs.type == HEJ::pid::Higgs); assert(decay->second.size() == 2); auto const & gamma = decay->second; assert(gamma[0].type == HEJ::pid::photon); assert(gamma[1].type == HEJ::pid::photon); assert(HEJ::nearby_ep(gamma[0].p + gamma[1].p, the_Higgs.p, 1e-6)); if(!pass_dR_cut(ev->jets(), gamma)) continue; ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << std::endl; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.012*xs); } diff --git a/FixedOrderGen/t/h_3j.cc b/FixedOrderGen/t/h_3j.cc index bb2baff..459dfae 100644 --- a/FixedOrderGen/t/h_3j.cc +++ b/FixedOrderGen/t/h_3j.cc @@ -1,69 +1,74 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif #include <algorithm> #include <cmath> #include <cassert> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Ranlux64.hh" #include "HEJ/Event.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/PDF.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 1.07807; // +- 0.0071 //calculated with HEJ revision 93efdc851b02a907a6fcc63956387f9f4c1111c2 +1 auto config = load_config("config_h_2j.yml"); config.process.njets = 3; HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; const auto the_Higgs = std::find_if( begin(ev->outgoing()), end(ev->outgoing()), [](HEJ::Particle const & p){ return p.type == HEJ::ParticleID::h; } ); assert(the_Higgs != end(ev->outgoing())); if(std::abs(the_Higgs->rapidity()) > 5.) continue; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << std::endl; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.02*xs); } diff --git a/FixedOrderGen/t/h_3j_uno1.cc b/FixedOrderGen/t/h_3j_uno1.cc index c100dcb..2005230 100644 --- a/FixedOrderGen/t/h_3j_uno1.cc +++ b/FixedOrderGen/t/h_3j_uno1.cc @@ -1,73 +1,79 @@ +/** + * check that adding uno emissions doesn't change the FKL cross section + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif -// check that adding uno emissions doesn't change the FKL cross section #include <algorithm> #include <cassert> #include <cmath> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Ranlux64.hh" #include "Subleading.hh" #include "HEJ/Event.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/PDF.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 0.0243548; // +- 0.000119862 //calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20 auto config = load_config("config_h_2j.yml"); config.process.njets = 3; config.process.incoming = {HEJ::pid::u, HEJ::pid::u}; config.subleading_channels = HEJFOG::Subleading::uno; HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; int uno_found = 0; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); if(ev->type() != HEJ::event_type::FKL){ ++uno_found; continue; } ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n'; std::cout << uno_found << " events with unordered emission" << std::endl; assert(uno_found > 0); assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.05*xs); } diff --git a/FixedOrderGen/t/h_3j_uno2.cc b/FixedOrderGen/t/h_3j_uno2.cc index 4dc4770..5341658 100644 --- a/FixedOrderGen/t/h_3j_uno2.cc +++ b/FixedOrderGen/t/h_3j_uno2.cc @@ -1,68 +1,74 @@ +/** + * check uno cross section + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif -// check uno cross section #include <algorithm> #include <cassert> #include <cmath> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Ranlux64.hh" #include "Subleading.hh" #include "HEJ/Event.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/PDF.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 0.00347538; // +- 3.85875e-05 //calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20 auto config = load_config("config_h_2j.yml"); config.process.njets = 3; config.process.incoming = {HEJ::pid::u, HEJ::pid::u}; config.subleading_fraction = 1.; config.subleading_channels = HEJFOG::Subleading::uno; HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); if(ev->type() == HEJ::event_type::FKL) continue; ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << std::endl; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.05*xs); } diff --git a/FixedOrderGen/t/h_5j.cc b/FixedOrderGen/t/h_5j.cc index a1b60e8..f280fc9 100644 --- a/FixedOrderGen/t/h_5j.cc +++ b/FixedOrderGen/t/h_5j.cc @@ -1,64 +1,70 @@ +/** + * This is a regression test + * the reference cross section has not been checked against any other program + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #ifdef NDEBUG #undef NDEBUG #endif -// This is a regression test -// the reference cross section has not been checked against any other program #include <algorithm> #include <cassert> #include <cmath> #include <iostream> #include "config.hh" #include "EventGenerator.hh" #include "HEJ/Ranlux64.hh" #include "HEJ/Event.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/PDF.hh" using namespace HEJFOG; int main(){ constexpr double invGeV2_to_pb = 389379292.; constexpr double xs_ref = 0.252273; // +- 0.00657742 //calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20 auto config = load_config("config_h_2j.yml"); config.process.njets = 5; HEJ::Ranlux64 ran{}; HEJFOG::EventGenerator generator{ config.process, config.beam, HEJ::ScaleGenerator{ config.scales.base, config.scales.factors, config.scales.max_ratio }, config.jets, config.pdf_id, config.subleading_fraction, config.subleading_channels, config.particles_properties, config.Higgs_coupling, ran }; double xs = 0., xs_err = 0.; for (int trials = 0; trials < config.events; ++trials){ auto ev = generator.gen_event(); if(generator.status() != good) continue; assert(ev); ev->central().weight *= invGeV2_to_pb; ev->central().weight /= config.events; xs += ev->central().weight; xs_err += ev->central().weight*ev->central().weight; } xs_err = std::sqrt(xs_err); std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << std::endl; assert(std::abs(xs - xs_ref) < 3*xs_err); assert(xs_err < 0.06*xs); } diff --git a/README b/README new file mode 100644 index 0000000..f66566a --- /dev/null +++ b/README @@ -0,0 +1,60 @@ +------------------------------------------ +- High Energy Jets - +------------------------------------------ + +High Energy Jets (HEJ) is a Monte Carlo generator for all-order summation of +high-energy logarithms. It can be used as both a C++ library and standalone +executable. + +For further informations and questions please visit + + http://hej.web.cern.ch/ + +The latest version can be downloaded from + + https://phab.hepforge.org/source/hej/repository/v2.0/ + +------------- Installation ------------- + +HEJ can be installed via CMake version 3.1 or later (https://cmake.org/) by +running + + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=target/directory + make install + +Replace "target/directory" with the directory where HEJ should be installed to. + +HEJ depends on multiple external packages, a full list is given in the user +documentation (i.e. http://hej.web.cern.ch/). The minimal requirements are: + + A compiler supporting the C++14 standard (e.g. gcc 5 or later) + CLHEP (https://gitlab.cern.ch/CLHEP/CLHEP) + FastJet (http://fastjet.fr/) + IOStreams and uBLAS for the boost library (https://boost.org/) + LHAPDF (https://lhapdf.hepforge.org/) + yaml-cpp (https://github.com/jbeder/yaml-cpp) + +We also provide a Fixed Order Generator for the HEJ matrix elements as a +separate executable. To install it run the same commands as above in the +"FixedOrderGen" directory. + +------------- Documentation ------------- + +All documentation is hosted on + + http://hej.web.cern.ch/ + +To generate the user documentation locally run +(requires sphinx http://sphinx-doc.org/) + + cd doc/sphinx + make html + firefox _build/html/index.html + +The code documentation can be build through doxygen (http://doxygen.org/); + + cd doc/doxygen + doxygen Doxyfile + firefox html/index.html diff --git a/cmake/Templates/Version.hh.in b/cmake/Templates/Version.hh.in index 6babcbe..76e0a6e 100644 --- a/cmake/Templates/Version.hh.in +++ b/cmake/Templates/Version.hh.in @@ -1,47 +1,50 @@ -/** \file Version.hh - * \brief The file gives the current HEJ Version +/** \file Version.hh + * \brief The file gives the current HEJ Version + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later */ - #pragma once #include <string> /// @brief Full name of this package. #define HEJ_PACKAGE_NAME "@PROJECT_NAME@" /// @brief HEJ version string #define HEJ_VERSION "@PROJECT_VERSION@" /// @brief Full name and version of this package. #define HEJ_PACKAGE_STRING "@PROJECT_NAME@ @PROJECT_VERSION@" /// @brief Major version of this package #define HEJ_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ /// @brief Minor version of this package #define HEJ_VERSION_MINOR @PROJECT_VERSION_MINOR@ /// @brief Patch version of this package #define HEJ_VERSION_PATCH @PROJECT_VERSION_PATCH@ /// @brief Git revision of this package #define HEJ_GIT_revision "@PROJECT_GIT_REVISION@" /// @brief Git branch name of this package #define HEJ_GIT_branch "@PROJECT_GIT_BRANCH@" namespace HEJ { namespace Version { inline std::string String() { return HEJ_VERSION; } inline std::string package_name() { return HEJ_PACKAGE_NAME; } inline std::string package_name_full() { return HEJ_PACKAGE_STRING; } inline int Major() { return HEJ_VERSION_MAJOR; } inline int Minor() { return HEJ_VERSION_MINOR; } inline int Patch() { return HEJ_VERSION_PATCH; } inline std::string revision() { return HEJ_GIT_revision; } }; } diff --git a/doc/doxygen/biblio.bib b/doc/doxygen/biblio.bib index 3e960be..e41ce28 100644 --- a/doc/doxygen/biblio.bib +++ b/doc/doxygen/biblio.bib @@ -1,86 +1,97 @@ @article{Andersen:2011hs, author = "Andersen, Jeppe R. and Smillie, Jennifer M.", title = "{Multiple Jets at the LHC with High Energy Jets}", journal = "JHEP", volume = "06", year = "2011", pages = "010", doi = "10.1007/JHEP06(2011)010", eprint = "1101.5394", archivePrefix = "arXiv", primaryClass = "hep-ph", reportNumber = "CP3-ORIGINS-2011-02, EDINBURGH-2011-03", SLACcitation = "%%CITATION = ARXIV:1101.5394;%%" } @article{James:1993np, author = "James, F.", title = "{RANLUX: A FORTRAN implementation of the high quality pseudorandom number generator of Luscher}", journal = "Comput. Phys. Commun.", volume = "79", year = "1994", pages = "111-114", doi = "10.1016/0010-4655(94)90233-X", note = "[Erratum: Comput. Phys. Commun.97,357(1996)]", reportNumber = "CERN-CN-93-13", SLACcitation = "%%CITATION = CPHCB,79,111;%%" } @article{Luscher:1993dy, author = "Luscher, Martin", title = "{A Portable high quality random number generator for lattice field theory simulations}", journal = "Comput. Phys. Commun.", volume = "79", year = "1994", pages = "100-110", doi = "10.1016/0010-4655(94)90232-1", eprint = "hep-lat/9309020", archivePrefix = "arXiv", primaryClass = "hep-lat", reportNumber = "DESY-93-133", SLACcitation = "%%CITATION = HEP-LAT/9309020;%%" } @article{Savvidy:2014ana, author = "Savvidy, Konstantin G.", title = "{The MIXMAX random number generator}", journal = "Comput. Phys. Commun.", volume = "196", year = "2015", pages = "161-165", doi = "10.1016/j.cpc.2015.06.003", eprint = "1403.5355", archivePrefix = "arXiv", primaryClass = "hep-lat", reportNumber = "NITS-PHY-2014, NITS-PHY-2014003", SLACcitation = "%%CITATION = ARXIV:1403.5355;%%" } @inproceedings{Boos:2001cv, author = "Boos, E. and others", title = "{Generic user process interface for event generators}", booktitle = "{Physics at TeV colliders. Proceedings, Euro Summer School, Les Houches, France, May 21-June 1, 2001}", url = "http://lss.fnal.gov/archive/preprint/fermilab-conf-01-496-t.shtml", year = "2001", eprint = "hep-ph/0109068", archivePrefix = "arXiv", primaryClass = "hep-ph", reportNumber = "FERMILAB-CONF-01-496-T", SLACcitation = "%%CITATION = HEP-PH/0109068;%%" } @article{Andersen:2011zd, author = "Andersen, Jeppe R. and Lonnblad, Leif and Smillie, Jennifer M.", title = "{A Parton Shower for High Energy Jets}", journal = "JHEP", volume = "07", year = "2011", pages = "110", doi = "10.1007/JHEP07(2011)110", eprint = "1104.1316", archivePrefix = "arXiv", primaryClass = "hep-ph", reportNumber = "CERN-PH-TH-2011-072, CP3-ORIGINS-2011-14, EDINBURGH-2011-16, LU-TP-11-15, MCNET-11-12, LU-TP --11-15", SLACcitation = "%%CITATION = ARXIV:1104.1316;%%" } +@article{Hoeche:2019rti, + author = "Höche, Stefan and Prestel, Stefan and Schulz, Holger", + title = "{Simulation of vector boson plus many jet final states at + the high luminosity LHC}", + year = "2019", + eprint = "1905.05120", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "FERMILAB-PUB-19-192-T, LU-TP 19-14, MCNET-19-09", + SLACcitation = "%%CITATION = ARXIV:1905.05120;%%" +} diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox index 60cbb24..dceb8d4 100644 --- a/doc/doxygen/mainpage.dox +++ b/doc/doxygen/mainpage.dox @@ -1,225 +1,224 @@ namespace HEJ { // so that doxygen links names in this namespace /** * @mainpage * * @section intro Introduction * * HEJ 2 is a library for all-order resummation of high-energy * logarithms. It includes a program to add resummation to fixed-order * events. User documentation for the program can be found <a * href="https://hej.web.cern.ch/HEJ/doc/2.0/user/">here</a>. This * documentation is instead aimed at users of the library itself. * * @section overview Overview * - * The main functionality is contained in the HEJ namespace. Particles - * are defined via the Particle struct, which consists of the particle - * four-momentum and its identifier according to the <a + * The main functionality is contained in the HEJ namespace. Particles are + * defined via the Particle struct, which consists of the particle + * four-momentum, its identifier according to the <a * href="http://pdg.lbl.gov/2017/reviews/rpp2017-rev-monte-carlo-numbering.pdf"> - * PDG Monte Carlo numbering scheme </a>. Given a number of incoming and - * outgoing particles, the square of the resummation matrix element can - * be calculated with the help of the MatrixElement class. + * PDG Monte Carlo numbering scheme </a> and an optional Colour charge. Given a + * number of incoming and outgoing particles, the square of the resummation + * matrix element can be calculated with the help of the MatrixElement class. * * The EventReweighter class adds resummation to existing fixed-order * events. Both fixed-order and resummation events are objects of the - * Event class, which are created from UnclusteredEvent objects with the + * Event class, which are created from EventData objects with the * help of a <a * href="http://fastjet.fr/repo/doxygen-3.3.1/classfastjet_1_1JetDefinition.html">jet - * definition according to the fastjet</a> library. UnclusteredEvent + * definition according to the fastjet</a> library. EventData * objects can be assembled manually or converted from input events in - * the LesHouches standard, read from file with a LHEF::Reader. + * the LesHouches standard, read from file with a EventReader (e.g. + * LesHouchesReader or HDF5Reader). * * Events can be saved with one of the EventWriter classes. Currently, * there is support for the Les Houches event file format with the * LesHouchesWriter class. If HEJ 2 was installed with HepMC 2 or 3 * support, the respective format is available through the HepMCWriter * class. * * Further classes of interest are the interfaces to the Mixmax and * Ranlux64 random number generators, the PDF class to interact with <a * href="https://lhapdf.hepforge.org/"> LHAPDF </a> and the ScaleGenerator * and ScaleConfig classes to calculate renormalisation and factorisation * scales for a given Event. * * @section example Example * * As an example, we show a toy program that computes the square of a * matrix element in the HEJ approximation for a single event. First, we * include the necessary header files: * @code{.cpp} * #include "HEJ/Event.hh" * #include "HEJ/MatrixElement.hh" * @endcode * We then specify the incoming and outgoing particles. A particle - * has a type and four-momentum \f$(p_x, p_y, p_z, E)\f$. For instance, an - * incoming gluon could be defined as + * has a type, a four-momentum \f$(p_x, p_y, p_z, E)\f$ and optionally a colour + * charge. For instance, an incoming gluon could be defined as * @code{.cpp} * fastjet::PseudoJet momentum{0, 0, 308., 308.}; - * HEJ::Particle gluon_in{HEJ::ParticleID::gluon, momentum}; + * HEJ::Colour colours{501,502}; + * HEJ::Particle gluon_in{HEJ::ParticleID::gluon, momentum, colours}; * @endcode * We collect all incoming and outgoing particles in a partonic event. Here - * is an example for a partonic \f$gu \to gghu\f$ event: + * is an example for a partonic \f$gu \to gghu\f$ event (omitting colours): * @code{.cpp} - * HEJ::UnclusteredEvent partonic_event; + * HEJ::Event::EventData partonic_event; * * // incoming particles * partonic_event.incoming[0] = { * HEJ::ParticleID::gluon, * { 0., 0., 308., 308.} * }; * partonic_event.incoming[1] = { * HEJ::ParticleID::up, * { 0., 0.,-164., 164.} * }; * // outgoing particles * partonic_event.outgoing.push_back({ * HEJ::ParticleID::higgs, * { 98., 82., 14., 180.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::up, * { 68.,-54., 36., 94.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::gluon, * {-72., 9., 48., 87.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::gluon, * {-94.,-37., 46., 111.} * }); * @endcode * Alternatively, we could read the event from a Les Houches event file, - * possibly compressed with gzip. For this, the additional header - * files @c HEJ/stream.hh and @c LHEF/LHEF.h have to be - * included. + * possibly compressed with gzip. For this, the additional header file + * @c HEJ/LesHouchesReader.hh have to be included. * @code{.cpp} - * HEJ::istream in{"events.lhe.gz"}; - * LHEF::Reader reader{in}; - * reader.readEvent(); - * HEJ::UnclusteredEvent partonic_event{reader.hepeup}; + * HEJ::LesHouchesReader reader{"events.lhe.gz"}; + * reader.read_event(); + * HEJ::Event::EventData partonic_event{reader.hepeup()}; * @endcode * * In this specific example we will later choose a constant value for the * strong coupling, so that the HEJ matrix element does not depend on the * renormalisation scale. However, in a more general scenario, we will want * to set a central scale: * @code{.cpp} - * partonic_event.central.mur = 50.; + * partonic_event.parameters.central.mur = 50.; * @endcode * It is possible to add more scales in order to perform scale variation: * @code{.cpp} - * partonic_event.variations.resize(2); - * partonic_event.variations[0].mur = 25.; - * partonic_event.variations[1].mur = 100.; + * partonic_event.parameters.variations.resize(2); + * partonic_event.parameters.variations[0].mur = 25.; + * partonic_event.parameters.variations[1].mur = 100.; * @endcode * * In the next step, we leverage FastJet to construct an event with * clustered jets. Here, we use antikt jets with R=0.4 and transverse * momenta of at least 30 GeV. * @code{.cpp} * const fastjet::JetDefinition jet_def{ * fastjet::JetAlgorithm::antikt_algorithm, 0.4 * }; * const double min_jet_pt = 30.; - * HEJ::Event event{partonic_event, jet_def, min_jet_pt}; + * HEJ::Event event{partonic_event.cluster(jet_def, min_jet_pt)}; * @endcode * In order to calculate the Matrix element, we now have to fix the physics * parameters. For the sake of simplicity, we assume an effective coupling * of the Higgs boson to gluons in the limit of an infinite top-quark mass - * and a fixed value of $\alpha_s = 0.118$ for the strong coupling. + * and a fixed value of \f$\alpha_s = 0.118\f$ for the strong coupling. * @code{.cpp} * const auto alpha_s = [](double /* mu_r */) { return 0.118; }; * HEJ::MatrixElementConfig ME_config; * // whether to include corrections from the * // evolution of \alpha_s in virtual corrections * ME_config.log_correction = false; * HEJ::MatrixElement ME{alpha_s, ME_config}; * @endcode * If QCDLoop is installed, we can also take into account the full loop * effects with finite top and bottom quark masses: * @code{.cpp} * HEJ::MatrixElementConfig ME_config; * ME_config.Higgs_coupling.use_impact_factors = false; * ME_config.Higgs_coupling.mt = 163; * ME_config.Higgs_coupling.include_bottom = true; * ME_config.Higgs_coupling.mb = 2.8; * @endcode * Finally, we can compute and print the square of the matrix element with * @code{.cpp} * std::cout << "HEJ ME: " << ME(event).central << '\n'; * @endcode * In the case of scale variation, the weight associated with the scale * @c event.variations[i].mur is @c ME(event).variations[i]. * * Collecting the above pieces, we have the following program: * @code{.cpp} * #include "HEJ/Event.hh" * #include "HEJ/MatrixElement.hh" * * int main(){ - * HEJ::UnclusteredEvent partonic_event; + * HEJ::Event::EventData partonic_event; * // incoming particles * partonic_event.incoming[0] = { * HEJ::ParticleID::gluon, * { 0., 0., 308., 308.} * }; * partonic_event.incoming[1] = { * HEJ::ParticleID::up, * { 0., 0.,-164., 164.} * }; * // outgoing particles * partonic_event.outgoing.push_back({ * HEJ::ParticleID::higgs, * { 98., 82., 14., 180.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::up, * { 68.,-54., 36., 94.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::gluon, * {-72., 9., 48., 87.} * }); * partonic_event.outgoing.push_back({ * HEJ::ParticleID::gluon, * {-94.,-37., 46., 111.} * }); * * const fastjet::JetDefinition jet_def{ * fastjet::JetAlgorithm::antikt_algorithm, 0.4 * }; * const double min_jet_pt = 30.; - * HEJ::Event event{partonic_event, jet_def, min_jet_pt}; - * + * HEJ::Event event{partonic_event.cluster(jet_def, min_jet_pt)}; * const auto alpha_s = [](double /* mu_r */) { return 0.118; }; * HEJ::MatrixElementConfig ME_config; * // whether to include corrections from the * // evolution of \alpha_s in virtual corrections * ME_config.log_correction = false; * HEJ::MatrixElement ME{alpha_s, ME_config}; * * std::cout * << "HEJ ME: " << ME(event).central * << " = tree * virtual = " << ME.tree(event).central * << " * " << ME.virtual_corrections(event).central * << '\n'; * } * @endcode * After saving the above code to a file @c matrix_element.cc, it * can be compiled into an executable @c matrix_element with a * suitable compiler. For example, with @c g++ this can be done * with the command * @code{.sh} * g++ -o matrix_element matrix_element.cc -lHEJ -lfastjet * @endcode * If HEJ or any of the required libraries was installed to a * non-standard location, it may be necessary to explicitly specify the * paths to the required header and library files. This can be done with * the @c HEJ-config executable and similar programs for the * other dependencies: * @code{.sh} * g++ $(fastjet-config --cxxflags) $(HEJ-config --cxxflags) -o matrix_element matrix_element.cc $(HEJ-config --libs) $(fastjet-config --libs) * @endcode */ } diff --git a/include/HEJ/Analysis.hh b/include/HEJ/Analysis.hh index 003667d..f00d7fc 100644 --- a/include/HEJ/Analysis.hh +++ b/include/HEJ/Analysis.hh @@ -1,47 +1,47 @@ /** \file * \brief Header file for the Analysis interface * * This header contains declarations that faciliate creating custom analyses * to be used with HEJ 2. * \todo link to user documentation * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once //! Main HEJ 2 Namespace namespace HEJ{ class Event; //! Analysis base class /** * This is the interface that all analyses should implement, * i.e. all custom analyses have to be derived from this struct. */ struct Analysis{ //! Fill event into analysis (e.g. to histograms) /** * @param res_event The event in resummation phase space * @param FO_event The original fixed-order event */ virtual void fill(Event const & res_event, Event const & FO_event) = 0; //! Decide whether an event passes the cuts /** * @param res_event The event in resummation phase space * @param FO_event The original fixed-order event * @returns Whether the event passes all cuts */ virtual bool pass_cuts(Event const & res_event, Event const & FO_event) = 0; //! Finalise analysis /** * This function is called after all events have been processed and * can be used for example to print out or save the results. */ virtual void finalise() = 0; virtual ~Analysis() = default; }; } diff --git a/include/HEJ/CombinedEventWriter.hh b/include/HEJ/CombinedEventWriter.hh index 160da19..5f1ba18 100644 --- a/include/HEJ/CombinedEventWriter.hh +++ b/include/HEJ/CombinedEventWriter.hh @@ -1,45 +1,44 @@ /** \file * \brief Declares the CombinedEventWriter class * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include <vector> #include "HEJ/EventWriter.hh" #include "HEJ/output_formats.hh" namespace LHEF{ struct HEPRUP; } namespace HEJ{ //! Write event output to zero or more output files. class CombinedEventWriter: public EventWriter{ public: //!Constructor /** * @param outfiles Specifies files output should be written to. * Each entry in the vector contains a file name * and output format. * @param heprup General process information */ CombinedEventWriter( std::vector<OutputFile> const & outfiles, LHEF::HEPRUP const & heprup ); //! Write one event to all output files void write(Event const &) override; private: std::vector<std::unique_ptr<EventWriter>> writers_; }; } diff --git a/include/HEJ/Constants.hh b/include/HEJ/Constants.hh index 4568911..7b43915 100644 --- a/include/HEJ/Constants.hh +++ b/include/HEJ/Constants.hh @@ -1,39 +1,39 @@ /** \file * \brief Header file defining all global constants used for HEJ * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once namespace HEJ{ /// @name QCD parameters //@{ constexpr double N_C = 3.; //!< number of Colours constexpr double C_A = N_C; //!< \f$C_A\f$ constexpr double C_F = (N_C*N_C - 1.)/(2.*N_C); //!< \f$C_F\f$ constexpr double t_f = 0.5; //!< \f$t_f\f$ constexpr double n_f = 5.; //!< number light flavours constexpr double beta0 = 11./3.*C_A - 4./3.*t_f*n_f; //!< \f$\beta_0\f$ //@} /// @name QFT parameters //@{ constexpr double vev = 246.2196508; //!< Higgs vacuum expectation value in GeV constexpr double gw = 0.653233; constexpr double MW = 80.419; // The W mass in GeV/c^2 constexpr double GammaW = 2.0476; // the W width in GeV/c^2 //@} /// @name Generation Parameters //@{ //! Default scale for virtual correction, \f$\lambda\f$ cf. eq. (20) in \cite Andersen:2011hs constexpr double CLAMBDA = 0.2; constexpr double CMINPT = 0.2; //!< minimal \f$p_t\f$ of all partons //@} /// @name Conventional Parameters //@{ //! Value of first colour for colour dressing, according to LHE convention \cite Boos:2001cv constexpr int COLOUR_OFFSET = 501; //@} } diff --git a/include/HEJ/CrossSectionAccumulator.hh b/include/HEJ/CrossSectionAccumulator.hh index 013ffa5..2b76fd5 100644 --- a/include/HEJ/CrossSectionAccumulator.hh +++ b/include/HEJ/CrossSectionAccumulator.hh @@ -1,69 +1,74 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #pragma once #include <map> #include <ostream> #include <iomanip> #include <string> #include "HEJ/Event.hh" #include "HEJ/event_types.hh" namespace HEJ { template<typename T> struct XSWithError { T value = T{}; T error = T{}; }; /** * @brief Sum of Cross Section for different subproccess */ class CrossSectionAccumulator { public: void fill(HEJ::Event const & ev) { const double wt = ev.central().weight; auto & entry = xs_[ev.type()]; entry.value += wt; entry.error += wt*wt; total_.value += wt; total_.error += wt*wt; } auto begin() const { return std::begin(xs_); } auto end() const { return std::end(xs_); } //! total Cross Section and error XSWithError<double> total() const { return total_; } private: std::map<HEJ::event_type::EventType, XSWithError<double>> xs_; XSWithError<double> total_; }; std::ostream& operator<<(std::ostream& os, const CrossSectionAccumulator& xs){ const std::streamsize orig_prec = os.precision(); os << std::scientific << std::setprecision(3) << " " << std::left << std::setw(25) << "Cross section: " << xs.total().value << " +- " << std::sqrt(xs.total().error) << " (pb)\n"; for(auto const & xs_type: xs) { os << " " << std::left << std::scientific <<std::setw(25) << (HEJ::event_type::names[xs_type.first] + std::string(": ")); os << xs_type.second.value << " +- " << std::sqrt(xs_type.second.error) << " (pb) " << std::fixed << std::setprecision(3) << "[" <<std::setw(6) <<std::right<< ((xs_type.second.value)/xs.total().value)*100 << "%]" << std::endl; } os << std::defaultfloat; os.precision(orig_prec); return os; } } diff --git a/include/HEJ/EmptyAnalysis.hh b/include/HEJ/EmptyAnalysis.hh index f0d1933..6905b0e 100644 --- a/include/HEJ/EmptyAnalysis.hh +++ b/include/HEJ/EmptyAnalysis.hh @@ -1,48 +1,47 @@ /** \file * \brief Declaration of the trivial (empty) analysis * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include "HEJ/Analysis.hh" //! YAML Namespace namespace YAML{ class Node; } namespace HEJ{ /** An analysis that does nothing * * This analysis is used by default if no user analysis is specified. * The member functions don't do anything and events passed to the * analysis are simply ignored. */ struct EmptyAnalysis: Analysis{ static std::unique_ptr<Analysis> create(YAML::Node const & parameters); //! Fill event into analysis (e.g. to histograms) /** * This function does nothing */ virtual void fill(Event const &, Event const &) override; //! Whether a resummation event passes all cuts /** * There are no cuts, so all events pass */ virtual bool pass_cuts(Event const &, Event const &) override; //! Finalise analysis /** * This function does nothing */ virtual void finalise() override; virtual ~EmptyAnalysis() override = default; }; } diff --git a/include/HEJ/Event.hh b/include/HEJ/Event.hh index 5140f8f..3b08c7e 100644 --- a/include/HEJ/Event.hh +++ b/include/HEJ/Event.hh @@ -1,282 +1,281 @@ /** \file * \brief Declares the Event class and helpers * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <array> #include <memory> #include <string> #include <unordered_map> #include <vector> #include "HEJ/event_types.hh" #include "HEJ/Parameters.hh" #include "HEJ/Particle.hh" #include "HEJ/RNG.hh" #include "fastjet/ClusterSequence.hh" namespace LHEF{ class HEPEUP; class HEPRUP; } namespace fastjet{ class JetDefinition; } namespace HEJ{ struct UnclusteredEvent; /** @brief An event with clustered jets * * This is the main HEJ 2 event class. * It contains kinematic information including jet clustering, * parameter (e.g. scale) settings and the event weight. */ class Event{ public: class EventData; //! No default Constructor Event() = delete; //! Event Constructor adding jet clustering to an unclustered event //! @deprecated UnclusteredEvent will be replaced by EventData in HEJ 2.2.0 [[deprecated("UnclusteredEvent will be replaced by EventData")]] Event( UnclusteredEvent const & ev, fastjet::JetDefinition const & jet_def, double min_jet_pt ); //! Incoming particles std::array<Particle, 2> const & incoming() const{ return incoming_; } //! Outgoing particles std::vector<Particle> const & outgoing() const{ return outgoing_; } //! Particle decays /** * The key in the returned map corresponds to the index in the * vector returned by outgoing() */ std::unordered_map<size_t, std::vector<Particle>> const & decays() const{ return decays_; } //! The jets formed by the outgoing partons, sorted in rapidity std::vector<fastjet::PseudoJet> const & jets() const{ return jets_; } //! All chosen parameter, i.e. scale choices (const version) Parameters<EventParameters> const & parameters() const{ return parameters_; } //! All chosen parameter, i.e. scale choices Parameters<EventParameters> & parameters(){ return parameters_; } //! Central parameter choice (const version) EventParameters const & central() const{ return parameters_.central; } //! Central parameter choice EventParameters & central(){ return parameters_.central; } //! Parameter (scale) variations (const version) std::vector<EventParameters> const & variations() const{ return parameters_.variations; } //! Parameter (scale) variations std::vector<EventParameters> & variations(){ return parameters_.variations; } //! Parameter (scale) variation (const version) /** * @param i Index of the requested variation */ EventParameters const & variations(size_t i) const{ return parameters_.variations[i]; } //! Parameter (scale) variation /** * @param i Index of the requested variation */ EventParameters & variations(size_t i){ return parameters_.variations[i]; } //! Indices of the jets the outgoing partons belong to /** * @param jets Jets to be tested * @returns A vector containing, for each outgoing parton, * the index in the vector of jets the considered parton * belongs to. If the parton is not inside any of the * passed jets, the corresponding index is set to -1. */ std::vector<int> particle_jet_indices( std::vector<fastjet::PseudoJet> const & jets ) const{ return cs_.particle_jet_indices(jets); } //! Jet definition used for clustering fastjet::JetDefinition const & jet_def() const{ return cs_.jet_def(); } //! Minimum jet transverse momentum double min_jet_pt() const{ return min_jet_pt_; } //! Event type event_type::EventType type() const{ return type_; } //! Give colours to each particle /** * @returns true if new colours are generated, i.e. same as is_HEJ() * @details Colour ordering is done according to leading colour in the MRK * limit, see \cite Andersen:2011zd. This only affects \ref * is_HEJ() "HEJ" configurations, all other \ref event_type * "EventTypes" will be ignored. * @note This overwrites all previously set colours. */ bool generate_colours(HEJ::RNG &); private: //! \internal //! @brief Construct Event explicitly from input. /** This is only intended to be called from EventData. * * \warning The input is taken _as is_, sorting and classification has to be * done externally, i.e. by EventData */ Event( std::array<Particle, 2> && incoming, std::vector<Particle> && outgoing, std::unordered_map<size_t, std::vector<Particle>> && decays, Parameters<EventParameters> && parameters, fastjet::JetDefinition const & jet_def, double const min_jet_pt ); std::array<Particle, 2> incoming_; std::vector<Particle> outgoing_; std::unordered_map<size_t, std::vector<Particle>> decays_; std::vector<fastjet::PseudoJet> jets_; Parameters<EventParameters> parameters_; fastjet::ClusterSequence cs_; double min_jet_pt_; event_type::EventType type_; }; // end class Event //! Class to store general Event setup, i.e. Phase space and weights class Event::EventData{ public: //! Default Constructor EventData() = default; //! Constructor from LesHouches event information EventData(LHEF::HEPEUP const & hepeup); //! Constructor with all values given EventData( std::array<Particle, 2> const & incoming_, std::vector<Particle> const & outgoing_, std::unordered_map<size_t, std::vector<Particle>> const & decays_, Parameters<EventParameters> const & parameters_ ): incoming(incoming_), outgoing(outgoing_), decays(decays_), parameters(parameters_) {}; //! Move Constructor with all values given EventData( std::array<Particle, 2> && incoming_, std::vector<Particle> && outgoing_, std::unordered_map<size_t, std::vector<Particle>> && decays_, Parameters<EventParameters> && parameters_ ): incoming(std::move(incoming_)), outgoing(std::move(outgoing_)), decays(std::move(decays_)), parameters(std::move(parameters_)) {}; //! Generate an Event from the stored EventData. /** * @details Do jet clustering and classification. * Use this to generate an Event. * * @note Calling this function destroys EventData * * @param jet_def Jet definition * @param min_jet_pt minimal \f$p_T\f$ for each jet * * @returns Full clustered and classified event. */ Event cluster( fastjet::JetDefinition const & jet_def, double const min_jet_pt); //! Alias for cluster() Event operator()( fastjet::JetDefinition const & jet_def, double const min_jet_pt){ return cluster(jet_def, min_jet_pt); }; //! Sort particles in rapidity void sort(); //! Reconstruct intermediate particles from final-state leptons /** * Final-state leptons are created from virtual photons, W, or Z bosons. * This function tries to reconstruct such intermediate bosons if they * are not part of the event record. */ void reconstruct_intermediate(); std::array<Particle, 2> incoming; std::vector<Particle> outgoing; std::unordered_map<size_t, std::vector<Particle>> decays; Parameters<EventParameters> parameters; }; // end class EventData //! Print Event std::ostream& operator<<(std::ostream & os, Event const & ev); //! Square of the partonic centre-of-mass energy \f$\hat{s}\f$ double shat(Event const & ev); //! Convert an event to a LHEF::HEPEUP LHEF::HEPEUP to_HEPEUP(Event const & event, LHEF::HEPRUP *); // put deprecated warning at the end, so don't get the warning inside Event.hh, // additionally doxygen can not identify [[deprecated]] correctly struct [[deprecated("UnclusteredEvent will be replaced by EventData")]] UnclusteredEvent; //! An event before jet clustering //! @deprecated UnclusteredEvent will be replaced by EventData in HEJ 2.2.0 struct UnclusteredEvent{ //! Default Constructor UnclusteredEvent() = default; //! Constructor from LesHouches event information UnclusteredEvent(LHEF::HEPEUP const & hepeup); std::array<Particle, 2> incoming; /**< Incoming Particles */ std::vector<Particle> outgoing; /**< Outgoing Particles */ //! Particle decays in the format {outgoing index, decay products} std::unordered_map<size_t, std::vector<Particle>> decays; //! Central parameter (e.g. scale) choice EventParameters central; std::vector<EventParameters> variations; /**< For parameter variation */ }; } diff --git a/include/HEJ/EventReader.hh b/include/HEJ/EventReader.hh index ff920b6..f001f6a 100644 --- a/include/HEJ/EventReader.hh +++ b/include/HEJ/EventReader.hh @@ -1,44 +1,44 @@ /** \file * \brief Header file for event reader interface * * This header defines an abstract base class for reading events from files. * - * \authors Jeppe Andersen, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <memory> #include <string> #include "LHEF/LHEF.h" namespace HEJ{ class EventData; // Abstract base class for reading events from files struct EventReader { //! Read an event virtual bool read_event() = 0; //! Access header text virtual std::string const & header() const = 0; //! Access run information virtual LHEF::HEPRUP const & heprup() const = 0; //! Access last read event virtual LHEF::HEPEUP const & hepeup() const = 0; virtual ~EventReader() = default; }; //! Factory function for event readers /** * @param infile The name of the input file * @returns A pointer to an instance of an EventReader * for the input file */ std::unique_ptr<EventReader> make_reader(std::string const & filename); } diff --git a/include/HEJ/EventReweighter.hh b/include/HEJ/EventReweighter.hh index e139ce1..feb50bb 100644 --- a/include/HEJ/EventReweighter.hh +++ b/include/HEJ/EventReweighter.hh @@ -1,190 +1,201 @@ /** \file * \brief Declares the EventReweighter class * * EventReweighter is the main class used within HEJ 2. It reweights the * resummation events. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <array> #include <functional> #include <utility> #include <vector> #include "HEJ/config.hh" #include "HEJ/event_types.hh" #include "HEJ/MatrixElement.hh" +#include "HEJ/Parameters.hh" #include "HEJ/PDF.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/RNG.hh" #include "HEJ/ScaleFunction.hh" -#include "HEJ/Parameters.hh" +#include "HEJ/StatusCode.hh" namespace LHEF { class HEPRUP; } namespace HEJ{ class Event; //! Beam parameters /** * Currently, only symmetric beams are supported, * so there is a single beam energy. */ struct Beam{ double E; /**< Beam energy */ std::array<ParticleID, 2> type; /**< Beam particles */ }; //! Main class for reweighting events in HEJ. class EventReweighter{ using EventType = event_type::EventType; public: EventReweighter( Beam beam, /**< Beam Energy */ int pdf_id, /**< PDF ID */ ScaleGenerator scale_gen, /**< Scale settings */ EventReweighterConfig conf, /**< Configuration parameters */ HEJ::RNG & ran /**< Random number generator */ ); EventReweighter( LHEF::HEPRUP const & heprup, /**< LHEF event header */ ScaleGenerator scale_gen, /**< Scale settings */ EventReweighterConfig conf, /**< Configuration parameters */ HEJ::RNG & ran /**< Random number generator */ ); //! Get the used pdf PDF const & pdf() const; //! Generate resummation events for a given fixed-order event /** * @param ev Fixed-order event corresponding * to the resummation events * @param num_events Number of trial resummation configurations. * @returns A vector of resummation events. * * The result vector depends on the type of the input event and the * treatment of different types as specified in the constructor: * * \ref reweight The result vector contains between * 0 and num_events resummation events. * * \ref keep If the input event passes the resummation jet cuts * the result vector contains one event. Otherwise it is empty. * * \ref discard The result vector is empty */ std::vector<Event> reweight( Event const & ev, int num_events ); + //! Gives all StatusCodes of the last reweight() + /** + * Each StatusCode corresponds to one tried generation. Only good + * StatusCodes generated an event. + */ + std::vector<StatusCode> const & status() const { + return status_; + } + private: template<typename... T> PDF const & pdf(T&& ...); /** \internal * \brief main generation/reweighting function: * generate phase space points and divide out Born factors */ std::vector<Event> gen_res_events( Event const & ev, int num_events ); std::vector<Event> rescale( Event const & Born_ev, std::vector<Event> events ) const; /** \internal * \brief Do the Jets pass the resummation Cuts? * * @param ev Event in Question * @returns 0 or 1 depending on if ev passes Jet Cuts */ bool jets_pass_resummation_cuts(Event const & ev) const; /** \internal * \brief pdf_factors Function * * @param ev Event in Question * @returns EventFactor due to PDFs * * Calculates the Central value and the variation due * to the PDF choice made. */ Weights pdf_factors(Event const & ev) const; /** \internal * \brief matrix_elements Function * * @param ev Event in question * @returns EventFactor due to MatrixElements * * Calculates the Central value and the variation due * to the Matrix Element. */ Weights matrix_elements(Event const & ev) const; /** \internal * \brief Scale-dependent part of fixed-order matrix element * * @param ev Event in question * @returns EventFactor scale variation due to FO-ME. * * This is only called to compute the scale variation for events where * we don't do resummation (e.g. non-FKL). * Since at tree level the scale dependence is just due to alpha_s, * it is enough to return the alpha_s(mur) factors in the matrix element. * The rest drops out in the ratio of (output event ME)/(input event ME), * so we never have to compute it. */ Weights fixed_order_scale_ME(Event const & ev) const; /** \internal * \brief Computes the tree level matrix element * * @param ev Event in Question * @returns HEJ approximation to Tree level Matrix Element * * This computes the HEJ approximation to the tree level FO * Matrix element which is used within the LO weighting process. */ double tree_matrix_element(Event const & ev) const; //! \internal General parameters EventReweighterConfig param_; //! \internal Beam energy double E_beam_; //! \internal PDF PDF pdf_; //! \internal Object to calculate the square of the matrix element MatrixElement MEt2_; //! \internal Object to calculate event renormalisation and factorisation scales ScaleGenerator scale_gen_; /** \internal random number generator * * \note We use a reference_wrapper so that EventReweighter objects can * still be copied (which would be impossible with a reference). */ std::reference_wrapper<HEJ::RNG> ran_; + std::vector<StatusCode> status_; }; template<typename... T> PDF const & EventReweighter::pdf(T&&... t){ return pdf_ = PDF{std::forward<T>(t)...}; } } diff --git a/include/HEJ/EventWriter.hh b/include/HEJ/EventWriter.hh index 997a510..b335dd4 100644 --- a/include/HEJ/EventWriter.hh +++ b/include/HEJ/EventWriter.hh @@ -1,21 +1,21 @@ /** \file * \brief Header file for the EventWriter interface. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once namespace HEJ{ class Event; //! Pure abstract base class for event writers struct EventWriter{ //! Write an event virtual void write(Event const &) = 0; virtual ~EventWriter() = default; }; } diff --git a/include/HEJ/HDF5Reader.hh b/include/HEJ/HDF5Reader.hh index c3eba20..13bc75e 100644 --- a/include/HEJ/HDF5Reader.hh +++ b/include/HEJ/HDF5Reader.hh @@ -1,43 +1,44 @@ /** \file * \brief Header file for reading events in the HDF5 event format. * - * This format is specified in arXiv:1905.05120. - * - * \authors Jeppe Andersen, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include "HEJ/EventReader.hh" namespace HEJ{ - //! Class for writing events to a file in the Les Houches Event File format + //! Class for reading events from a file in the HDF5 file format + /** + * @details This format is specified in \cite Hoeche:2019rti. + */ class HDF5Reader : public EventReader{ public: //! Contruct object reading from the given file explicit HDF5Reader(std::string const & filename); //! Read an event bool read_event() override; //! Access header text std::string const & header() const override; //! Access run information LHEF::HEPRUP const & heprup() const override; //! Access last read event LHEF::HEPEUP const & hepeup() const override; private: struct HDF5ReaderImpl; struct HDF5ReaderImplDeleter { void operator()(HDF5ReaderImpl* p); }; std::unique_ptr<HDF5ReaderImpl, HDF5ReaderImplDeleter> impl_; }; } diff --git a/include/HEJ/HepMCInterface.hh b/include/HEJ/HepMCInterface.hh index b920dbf..94c788e 100644 --- a/include/HEJ/HepMCInterface.hh +++ b/include/HEJ/HepMCInterface.hh @@ -1,73 +1,72 @@ /** \file * \brief Header file for the HepMCInterface * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <sys/types.h> #include <vector> namespace HepMC{ class GenCrossSection; class GenEvent; } namespace HEJ{ class Event; class EventParameters; //! This class converts the Events into HepMC::GenEvents /** * \details The output is depended on the HepMC version HEJ is compiled with, * both HepMC 2 and HepMC 3 are supported. If HEJ 2 is compiled * without HepMC calling this interface will throw an error. * * This interface will also keep track of the cross section of all the events that * being fed into it. */ class HepMCInterface{ public: HepMCInterface(); /** * \brief main function to convert an event into HepMC::GenEvent * * \param event Event to convert * \param weight_index optional selection of specific weight * (negative value gives central weight) */ HepMC::GenEvent operator()(Event const & event, ssize_t weight_index = -1); /** * \brief initialise the event kinematics (everything but the weights) * * \param event Event to convert * \param weight_index optional selection of specific weight * (negative value gives central weight) */ HepMC::GenEvent init_kinematics(Event const & event); /** * \brief Sets the central value from \p event to \p out_ev * * \param out_ev HepMC::GenEvent to write to * \param event Event to convert * \param weight_index optional selection of specific weight * (negative value gives "central") */ void set_central(HepMC::GenEvent & out_ev, Event const & event, ssize_t weight_index = -1); /** * \brief Add the event \p variations to \p out_ev */ void add_variation(HepMC::GenEvent & out_ev, std::vector<EventParameters> const & variations); private: size_t event_count_; double tot_weight_; double tot_weight2_; HepMC::GenCrossSection cross_section() const; }; } diff --git a/include/HEJ/HepMCWriter.hh b/include/HEJ/HepMCWriter.hh index f696713..0c5ce91 100644 --- a/include/HEJ/HepMCWriter.hh +++ b/include/HEJ/HepMCWriter.hh @@ -1,55 +1,54 @@ /** \file * \brief Contains the EventWriter for HepMC Output. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include <string> #include "HEJ/EventWriter.hh" namespace LHEF { class HEPRUP; } namespace HEJ{ class Event; //! This is an event writer specifically for HepMC output. /** * \internal Implementation note: * This uses the pimpl ("pointer to implementation") idiom. * HepMC support is optional and the implementation depends on the * HepMC version. Without pimpl, we would have to specify the HepMC version * via the preprocessor whenever this header is included. We don't want to * burden users of the HEJ library (for example the HEJ fixed-order generator) * with those details */ class HepMCWriter: public EventWriter{ public: //! Constructor /** * @param file name of the output file * @param heprup general process information */ HepMCWriter(std::string const & file, LHEF::HEPRUP heprup); ~HepMCWriter() override = default; //! Write an event to the output file void write(Event const & ev) override; private: struct HepMCWriterImpl; struct HepMCWriterImplDeleter { void operator()(HepMCWriterImpl* p); }; std::unique_ptr<HepMCWriterImpl, HepMCWriterImplDeleter> impl_; }; } diff --git a/include/HEJ/HiggsCouplingSettings.hh b/include/HEJ/HiggsCouplingSettings.hh index 9518ee4..1bcabb9 100644 --- a/include/HEJ/HiggsCouplingSettings.hh +++ b/include/HEJ/HiggsCouplingSettings.hh @@ -1,24 +1,24 @@ /** \file * \brief Defines the settings for Higgs boson coupling to gluons * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <limits> namespace HEJ{ //! Settings for Higgs boson coupling to gluons struct HiggsCouplingSettings{ //! Top quark mass double mt = std::numeric_limits<double>::infinity(); //! Bottom quark mass double mb = 4.7; //! Whether to use impact factors bool use_impact_factors = true; //! Whether to include bottom quark effects bool include_bottom = false; }; } diff --git a/include/HEJ/JetSplitter.hh b/include/HEJ/JetSplitter.hh index 71e0183..e3246ff 100644 --- a/include/HEJ/JetSplitter.hh +++ b/include/HEJ/JetSplitter.hh @@ -1,78 +1,77 @@ /** * \file * \brief Declaration of the JetSplitter class * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <functional> #include <vector> #include "fastjet/JetDefinition.hh" #include "HEJ/RNG.hh" namespace fastjet { class PseudoJet; } namespace HEJ { //! Class to split jets into their constituents class JetSplitter { public: struct SplitResult { std::vector<fastjet::PseudoJet> constituents; double weight; }; //! Constructor /** * @param jet_def Jet definition * @param min_pt Minimum jet transverse momentum * @param ran Random number generator */ JetSplitter( fastjet::JetDefinition jet_def, double min_pt, HEJ::RNG & ran ): R_{jet_def.R()}, min_jet_pt_{min_pt}, jet_def_{jet_def}, ran_{ran} {} //! Split a get into constituents /** * @param j2split Jet to be split * @param ncons Number of constituents * @returns The constituent momenta * together with the associated weight */ SplitResult split(fastjet::PseudoJet const & j2split, int ncons) const; //! Maximum distance of constituents to jet axis static constexpr double R_factor = 5./3.; private: //! \internal split jet into two partons SplitResult Split2(fastjet::PseudoJet const & j2split) const; /** \internal * @brief sample y-phi distance to jet pt axis for a jet splitting into two * partons * * @param wt Multiplied by the weight of the sampling point * @returns The distance in units of the jet radius */ double sample_distance_2p(double & wt) const; double R_; double min_jet_pt_; fastjet::JetDefinition jet_def_; std::reference_wrapper<HEJ::RNG> ran_; }; } diff --git a/include/HEJ/LesHouchesReader.hh b/include/HEJ/LesHouchesReader.hh index 56656f6..982172a 100644 --- a/include/HEJ/LesHouchesReader.hh +++ b/include/HEJ/LesHouchesReader.hh @@ -1,53 +1,52 @@ /** \file * \brief Header file for reading events in the Les Houches Event File format. * - * \authors Jeppe Andersen, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include "LHEF/LHEF.h" #include "HEJ/Event.hh" #include "HEJ/EventReader.hh" #include "HEJ/stream.hh" - namespace HEJ{ - //! Class for writing events to a file in the Les Houches Event File format + //! Class for reading events from a file in the Les Houches Event File format class LesHouchesReader : public EventReader{ public: //! Contruct object reading from the given file explicit LesHouchesReader(std::string const & filename): stream_{filename}, reader_{stream_} {} //! Read an event bool read_event() override { return reader_.readEvent(); } //! Access header text std::string const & header() const override { return reader_.headerBlock; } //! Access run information LHEF::HEPRUP const & heprup() const override { return reader_.heprup; } //! Access last read event LHEF::HEPEUP const & hepeup() const override { return reader_.hepeup; } private: HEJ::istream stream_; LHEF::Reader reader_; }; } diff --git a/include/HEJ/LesHouchesWriter.hh b/include/HEJ/LesHouchesWriter.hh index 7d23e79..777d34f 100644 --- a/include/HEJ/LesHouchesWriter.hh +++ b/include/HEJ/LesHouchesWriter.hh @@ -1,61 +1,60 @@ /** \file * \brief Contains the writer for LesHouches output * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <fstream> #include <memory> #include <string> #include "LHEF/LHEF.h" #include "HEJ/EventWriter.hh" namespace HEJ{ class Event; //! Class for writing events to a file in the Les Houches Event File format class LesHouchesWriter : public EventWriter{ public: //! Constructor /** * @param file Name of output file * @param heprup General process information */ LesHouchesWriter(std::string const & file, LHEF::HEPRUP heprup); LesHouchesWriter(LesHouchesWriter const & other) = delete; LesHouchesWriter & operator=(LesHouchesWriter const & other) = delete; /** @TODO in principle, this class should be movable * but that somehow(?) breaks the write member function */ LesHouchesWriter(LesHouchesWriter && other) = delete; LesHouchesWriter & operator=(LesHouchesWriter && other) = delete; ~LesHouchesWriter() override; //! Write an event to the file specified in the constructor void write(Event const & ev) override; private: void write_init(){ writer_->init(); } void rewrite_init(); LHEF::HEPRUP & heprup(){ return writer_->heprup; } LHEF::HEPEUP & hepeup(){ return writer_->hepeup; } std::fstream out_; std::unique_ptr<LHEF::Writer> writer_; }; } diff --git a/include/HEJ/MatrixElement.hh b/include/HEJ/MatrixElement.hh index cfcd15f..de56a71 100644 --- a/include/HEJ/MatrixElement.hh +++ b/include/HEJ/MatrixElement.hh @@ -1,191 +1,191 @@ /** \file * \brief Contains the MatrixElement Class * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <functional> #include <vector> #include "fastjet/PseudoJet.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/Parameters.hh" #include "HEJ/config.hh" namespace CLHEP { class HepLorentzVector; } namespace HEJ{ class Event; class Particle; //! Class to calculate the squares of matrix elements class MatrixElement{ public: /** \brief MatrixElement Constructor * @param alpha_s Function taking the renormalisation scale * and returning the strong coupling constant * @param conf General matrix element settings */ MatrixElement( std::function<double (double)> alpha_s, MatrixElementConfig conf ); /** * \brief squares of regulated HEJ matrix elements * @param event The event for which to calculate matrix elements * @returns The squares of HEJ matrix elements including virtual corrections * * This function returns one value for the central parameter choice * and one additional value for each entry in \ref Event.variations(). * See eq. (22) in \cite Andersen:2011hs for the definition of the squared * matrix element. * * \internal Relation to standard HEJ Met2: MatrixElement = Met2*shat^2/(pdfta*pdftb) */ Weights operator()(Event const & event) const; //! Squares of HEJ tree-level matrix elements /** * @param event The event for which to calculate matrix elements * @returns The squares of HEJ matrix elements without virtual corrections * * cf. eq. (22) in \cite Andersen:2011hs */ Weights tree(Event const & event) const; /** * \brief Virtual corrections to matrix element squares * @param event The event for which to calculate matrix elements * @returns The virtual corrections to the squares of the matrix elements * * The all order virtual corrections to LL in the MRK limit is * given by replacing 1/t in the scattering amplitude according to the * lipatov ansatz. * * cf. second-to-last line of eq. (22) in \cite Andersen:2011hs * note that indices are off by one, i.e. out[0].p corresponds to p_1 */ Weights virtual_corrections(Event const & event) const; /** * \brief Scale-dependent part of tree-level matrix element squares * @param event The event for which to calculate matrix elements * @returns The scale-dependent part of the squares of the * tree-level matrix elements * * The tree-level matrix elements factorises into a renormalisation-scale * dependent part, given by the strong coupling to some power, and a * scale-independent remainder. This function only returns the former parts * for the central scale choice and all \ref Event.variations(). * * @see tree, tree_kin */ Weights tree_param( Event const & event ) const; /** * \brief Kinematic part of tree-level matrix element squares * @param event The event for which to calculate matrix elements * @returns The kinematic part of the squares of the * tree-level matrix elements * * The tree-level matrix elements factorises into a renormalisation-scale * dependent part, given by the strong coupling to some power, and a * scale-independent remainder. This function only returns the latter part. * Since it does not depend on the parameter variations, only a single value * is returned. * * @see tree, tree_param */ double tree_kin(Event const & event) const; private: double tree_param( Event const & event, double mur ) const; double virtual_corrections_W( Event const & event, double mur, Particle const & WBoson ) const; double virtual_corrections( Event const & event, double mur ) const; //! \internal cf. last line of eq. (22) in \cite Andersen:2011hs double omega0( double alpha_s, double mur, fastjet::PseudoJet const & q_j ) const; double tree_kin_jets( Event const & ev ) const; double tree_kin_W( Event const & ev ) const; double tree_kin_Higgs( Event const & ev ) const; double tree_kin_Higgs_first( Event const & ev ) const; double tree_kin_Higgs_last( Event const & ev ) const; /** * \internal * \brief Higgs inbetween extremal partons. * * Note that in the case of unordered emission, the Higgs is *always* * treated as if in between the extremal (FKL) partons, even if its * rapidity is outside the extremal parton rapidities */ double tree_kin_Higgs_between( Event const & ev ) const; double tree_param_partons( double alpha_s, double mur, std::vector<Particle> const & partons ) const; std::vector<int> in_extremal_jet_indices( std::vector<fastjet::PseudoJet> const & partons ) const; std::vector<Particle> tag_extremal_jet_partons( Event const & ev ) const; double MH2_forwardH( CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, pid::ParticleID type2, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pH, double t1, double t2 ) const; std::function<double (double)> alpha_s_; MatrixElementConfig param_; }; } diff --git a/include/HEJ/Mixmax.hh b/include/HEJ/Mixmax.hh index 5f9677e..6fdb84c 100644 --- a/include/HEJ/Mixmax.hh +++ b/include/HEJ/Mixmax.hh @@ -1,35 +1,35 @@ /** \file * \brief The Mixmax random number generator * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <CLHEP/Random/Randomize.h> #include <CLHEP/Random/MixMaxRng.h> #include "HEJ/RNG.hh" namespace HEJ { //! MIXMAX random number generator /** * For details on MIXMAX, see \cite Savvidy:2014ana */ class Mixmax : public DefaultRNG { public: Mixmax() = default; Mixmax(long seed): ran_{seed} {}; //! Generate pseudorandom number between 0 and 1 double flat() override { return ran_.flat(); }; private: CLHEP::MixMaxRng ran_; }; } diff --git a/include/HEJ/PDF.hh b/include/HEJ/PDF.hh index c5dddbf..63ad94e 100644 --- a/include/HEJ/PDF.hh +++ b/include/HEJ/PDF.hh @@ -1,77 +1,76 @@ /** \file * * \brief Contains all the necessary classes and functions for interaction with PDFs. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <array> #include <memory> #include "LHAPDF/LHAPDF.h" #include "HEJ/PDG_codes.hh" namespace HEJ{ //! Class for interaction with a PDF set class PDF { public: /** * \brief PDF Constructor * @param id Particle ID according to PDG * @param beam1 Particle ID of particle in beam 1 * @param beam2 Particle ID of particle in beam 2 */ PDF(int id, ParticleID beam1, ParticleID beam2); /** * \brief Calculate the pdf value x*f(x, q) * @param beam_idx Beam number (0 or 1) * @param x Momentum fraction * @param q Energy scale * @param id PDG particle id * @returns x*f(x, q) * * Returns 0 if x or q are outside the range covered by the PDF set */ double pdfpt(size_t beam_idx, double x, double q, ParticleID id) const; /** * \brief Value of the strong coupling \f$\alpha_s(q)\f$ at the given scale * @param q Renormalisation scale * @returns Value of the strong coupling constant */ double Halphas(double q) const; //! Check if the energy scale is within the range covered by the PDF set /** * @param q Energy Scale * @returns true if q is within the covered range, false otherwise */ bool inRangeQ(double q) const; //! Check if the momentum fraction is within the range covered by the PDF set /** * @param x Momentum Fraction * @returns true if x is within the covered range, false otherwise */ bool inRangeX(double x) const; #if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 //! PDF id of the current set int id() const; #endif private: #if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 std::unique_ptr<LHAPDF::PDF> pdf; #endif std::array<int, 2> beamtype; }; } diff --git a/include/HEJ/PDG_codes.hh b/include/HEJ/PDG_codes.hh index ffdad16..97a6c4c 100644 --- a/include/HEJ/PDG_codes.hh +++ b/include/HEJ/PDG_codes.hh @@ -1,217 +1,216 @@ /** \file PDG_codes.hh * \brief Contains the Particle IDs of all relevant SM particles. * * Large enumeration included which has multiple entries for potential * alternative names of different particles. There are also functions * which can be used to determine if a particle is a parton or if * it is a non-gluon boson. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <string> namespace HEJ { //! particle ids according to PDG namespace pid { //! The possible particle identities. We use PDG IDs as standard. enum ParticleID{ d = 1, /*!< Down Quark */ down = d, /*!< Down Quark */ u = 2, /*!< Up Quark */ up = u, /*!< Up Quark */ s = 3, /*!< Strange Quark */ strange = s, /*!< Strange Quark */ c = 4, /*!< Charm Quark */ charm = c, /*!< Charm Quark */ b = 5, /*!< Bottom Quark */ bottom = b, /*!< Bottom Quark */ t = 6, /*!< Top Quark */ top = t, /*!< Top Quark */ e = 11, /*!< Electron */ electron = e, /*!< Electron */ nu_e = 12, /*!< Electron Neutrino */ electron_neutrino = nu_e, /*!< Electron neutrino */ mu = 13, /*!< Muon */ muon = mu, /*!< Muon */ nu_mu = 14, /*!< Muon Neutrino */ muon_neutrino = nu_mu, /*!< Muon Neutrino */ tau = 15, /*!< Tau */ nu_tau = 16, /*!< Tau Neutrino */ tau_neutrino = nu_tau, /*!< Tau Neutrino */ d_bar = -d, /*!< Anti-Down Quark */ antidown = d_bar, /*!< Anti-Down Quark */ u_bar = -u, /*!< Anti-Up quark */ antiup = -u, /*!< Anti-Up quark */ s_bar = -s, /*!< Anti-Strange Quark */ antistrange = -s, /*!< Anti-Strange Quark */ c_bar = -c, /*!< Anti-Charm Quark */ anticharm = -c, /*!< Anti-Charm Quark */ b_bar = -b, /*!< Anti-Bottom Quark */ antibottom = -b, /*!< Anti-Bottom Quark */ t_bar = -t, /*!< Anti-Top Quark */ antitop = -t, /*!< Anti-Top Quark */ e_bar = -e, /*!< Positron */ positron = e_bar, /*!< Positron */ antielectron = positron, /*!< Positron */ nu_e_bar = -nu_e, /*!< Electron Anti-Neutrino */ electron_antineutrino = nu_e_bar,/*!< Electron Anti-Neutrino */ mu_bar = -mu, /*!< Anti-Muon */ antimuon = -mu, /*!< Anti-Muon */ nu_mu_bar = -nu_mu, /*!< Muon Anti-Neutrino */ muon_antineutrino = nu_mu_bar, /*!< Muon Anti-Neutrino */ tau_bar = -tau, /*!< Anti-Tau */ antitau = tau_bar, /*!< Anti-Tau */ nu_tau_bar = -nu_tau, /*!< Tau Anti-Neutrino */ tau_antineutrino = nu_tau_bar, /*!< Tau Anti-Neutrino */ gluon = 21, /*!< Gluon */ g = gluon, /*!< Gluon */ photon = 22, /*!< Photon */ gamma = photon, /*!< Photon */ Z = 23, /*!< Z Boson */ Wp = 24, /*!< W- Boson */ Wm = -Wp, /*!< W+ Boson */ h = 25, /*!< Higgs Boson */ Higgs = h, /*!< Higgs Boson */ higgs = h, /*!< Higgs Boson */ p = 2212, /*!< Proton */ proton = p, /*!< Proton */ p_bar = -p, /*!< Anti-Proton */ antiproton = p_bar, /*!< Anti-Proton */ }; } using ParticleID = pid::ParticleID; //! Convert a particle name to the corresponding PDG particle ID ParticleID to_ParticleID(std::string const & name); //! Get the of the particle with the given PDG ID std::string name(ParticleID id); /** * \brief Function to determine if particle is a parton * @param id PDG ID of particle * @returns true if the particle is a parton, false otherwise */ inline constexpr bool is_parton(ParticleID id){ return id == pid::gluon || std::abs(id) <= pid::top; } /** * \brief Function to determine if particle is a quark * @param id PDG ID of particle * @returns true if the particle is a quark, false otherwise */ inline constexpr bool is_quark(ParticleID id){ return (id >= pid::down && id <= pid::top); } /** * \brief Function to determine if particle is an antiquark * @param id PDG ID of particle * @returns true if the particle is an antiquark, false otherwise */ inline constexpr bool is_antiquark(ParticleID id){ return (id <= pid::d_bar && id >= pid::t_bar); } /** * \brief Function to determine if particle is an (anti-)quark * @param id PDG ID of particle * @returns true if the particle is a quark or antiquark, false otherwise */ inline constexpr bool is_anyquark(ParticleID id){ return (id && id >= pid::t_bar && id <= pid::t); } /** * \brief function to determine if the particle is a photon, W, Z, or Higgs boson * @param id PDG ID of particle * @returns true if the partice is an A,W,Z, or H, false otherwise */ inline constexpr bool is_AWZH_boson(ParticleID id){ return id == pid::Wm || (id >= pid::photon && id <= pid::Higgs); } /** * \brief function to determine if the particle is a photon, W or Z * @param id PDG ID of particle * @returns true if the partice is an A,W,Z, or H, false otherwise */ inline constexpr bool is_AWZ_boson(ParticleID id){ return id == pid::Wm || (id >= pid::photon && id <= pid::Wp); } /** * \brief Function to determine if particle is a lepton * @param id PDG ID of particle * @returns true if the particle is a lepton, false otherwise */ inline constexpr bool is_lepton(ParticleID id){ return (id >= pid::electron && id <= pid::tau_neutrino); } /** * \brief Function to determine if particle is an antilepton * @param id PDG ID of particle * @returns true if the particle is an antilepton, false otherwise */ inline constexpr bool is_antilepton(ParticleID id){ return (id <= pid::positron && id >= pid::nu_tau_bar); } /** * \brief Function to determine if particle is an (anti-)lepton * @param id PDG ID of particle * @returns true if the particle is a lepton or antilepton, false otherwise */ inline constexpr bool is_anylepton(ParticleID id){ return ( is_lepton(id) || is_antilepton(id)); } /** * \brief Function to determine if particle is a neutrino * @param id PDG ID of particle * @returns true if the particle is a neutrino, false otherwise */ inline constexpr bool is_neutrino(ParticleID id){ return (id == pid::nu_e || id == pid::tau_neutrino || id == pid::muon_neutrino); } /** * \brief Function to determine if particle is an antineutrino * @param id PDG ID of particle * @returns true if the particle is an antineutrino, false otherwise */ inline constexpr bool is_antineutrino(ParticleID id){ return (id == pid::nu_e_bar || id == pid::nu_tau_bar || id == pid::nu_mu_bar); } /** * \brief Function to determine if particle is an (anti-)neutrino * @param id PDG ID of particle * @returns true if the particle is a neutrino or antineutrino, false otherwise */ inline constexpr bool is_anyneutrino(ParticleID id){ return ( is_neutrino(id)||is_antineutrino(id)); } } diff --git a/include/HEJ/Parameters.hh b/include/HEJ/Parameters.hh index b9ed559..840d2e4 100644 --- a/include/HEJ/Parameters.hh +++ b/include/HEJ/Parameters.hh @@ -1,155 +1,155 @@ /** \file * \brief Containers for Parameter variations, e.g. different Weights * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <memory> #include <vector> #include "HEJ/exceptions.hh" namespace HEJ{ //! Collection of parameters, e.g. Weights, assigned to a single event /** * A number of member functions of the MatrixElement class return Parameters * objects containing the squares of the matrix elements for the various * scale choices. */ template<class T> struct Parameters { T central; std::vector<T> variations; template<class T_ext> Parameters<T>& operator*=(Parameters<T_ext> const & other); Parameters<T>& operator*=(double factor); template<class T_ext> Parameters<T>& operator/=(Parameters<T_ext> const & other); Parameters<T>& operator/=(double factor); }; template<class T1, class T2> inline Parameters<T1> operator*(Parameters<T1> a, Parameters<T2> const & b) { a*=b; return a; } template<class T> inline Parameters<T> operator*(Parameters<T> a, double b) { a*=b; return a; } template<class T> inline Parameters<T> operator*(double b, Parameters<T> a) { a*=b; return a; } template<class T1, class T2> inline Parameters<T1> operator/(Parameters<T1> a, Parameters<T2> const & b) { a/=b; return a; } template<class T> inline Parameters<T> operator/(Parameters<T> a, double b) { a/=b; return a; } //! Alias for weight container, e.g. used by the MatrixElement using Weights = Parameters<double>; //! Description of event parameters, see also EventParameters struct ParameterDescription { //! Name of central scale choice (e.g. "H_T/2") std::string scale_name; //! Actual renormalisation scale divided by central scale double mur_factor; //! Actual factorisation scale divided by central scale double muf_factor; ParameterDescription() = default; ParameterDescription( std::string scale_name, double mur_factor, double muf_factor ): scale_name{scale_name}, mur_factor{mur_factor}, muf_factor{muf_factor} {}; }; //! Event parameters struct EventParameters{ double mur; /**< Value of the Renormalisation Scale */ double muf; /**< Value of the Factorisation Scale */ double weight; /**< Event Weight */ //! Optional description std::shared_ptr<ParameterDescription> description = nullptr; //! multiply weight by factor EventParameters& operator*=(double factor){ weight*=factor; return *this; }; //! divide weight by factor EventParameters& operator/=(double factor){ weight/=factor; return *this; }; }; inline EventParameters operator*(EventParameters a, double b){ a*=b; return a; } inline EventParameters operator*(double b, EventParameters a){ a*=b; return a; } inline EventParameters operator/(EventParameters a, double b){ a/=b; return a; } //! @{ //! @internal Implementation of template functions template<class T> template<class T_ext> Parameters<T>& Parameters<T>::operator*=(Parameters<T_ext> const & other) { if(other.variations.size() != variations.size()) { throw std::invalid_argument{"Wrong number of Parameters"}; } central *= other.central; for(std::size_t i = 0; i < variations.size(); ++i) { variations[i] *= other.variations[i]; } return *this; }; template<class T> Parameters<T>& Parameters<T>::operator*=(double factor) { central *= factor; for(auto & wt: variations) wt *= factor; return *this; }; template<class T> template<class T_ext> Parameters<T>& Parameters<T>::operator/=(Parameters<T_ext> const & other) { if(other.variations.size() != variations.size()) { throw std::invalid_argument{"Wrong number of Parameters"}; } central /= other.central; for(std::size_t i = 0; i < variations.size(); ++i) { variations[i] /= other.variations[i]; } return *this; }; template<class T> Parameters<T>& Parameters<T>::operator/=(double factor) { central /= factor; for(auto & wt: variations) wt /= factor; return *this; }; //! @} } diff --git a/include/HEJ/Particle.hh b/include/HEJ/Particle.hh index f5a3843..3dcd0fd 100644 --- a/include/HEJ/Particle.hh +++ b/include/HEJ/Particle.hh @@ -1,208 +1,207 @@ /** * \file Particle.hh * \brief Contains the particle struct * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <utility> #include "fastjet/PseudoJet.hh" #include "HEJ/optional.hh" #include "HEJ/PDG_codes.hh" namespace HEJ { using Colour = std::pair<int,int>; //! Class representing a particle struct Particle { //! particle type ParticleID type; //! particle momentum fastjet::PseudoJet p; //! (optional) colour & anti-colour optional<Colour> colour; //! get rapidity double rapidity() const{ return p.rapidity(); } //! get transverse momentum double perp() const{ return p.perp(); } //! get momentum in x direction double px() const{ return p.px(); } //! get momentum in y direction double py() const{ return p.py(); } //! get momentum in z direction double pz() const{ return p.pz(); } //! get energy double E() const{ return p.E(); } //! get mass double m() const{ return p.m(); } }; //! Functor to compare rapidities /** * This can be used whenever a rapidity comparison function is needed, * for example in many standard library functions. * * @see pz_less */ struct rapidity_less{ template<class FourVector> bool operator()(FourVector const & p1, FourVector const & p2){ return p1.rapidity() < p2.rapidity(); } }; //! Functor to compare momenta in z direction /** * This can be used whenever a pz comparison function is needed, * for example in many standard library functions. * * @see rapidity_less */ struct pz_less{ template<class FourVector> bool operator()(FourVector const & p1, FourVector const & p2){ return p1.pz() < p2.pz(); } }; //! Convert a vector of Particles to a vector of particle momenta inline std::vector<fastjet::PseudoJet> to_PseudoJet( std::vector<Particle> const & v ){ std::vector<fastjet::PseudoJet> result; for(auto && sp: v) result.emplace_back(sp.p); return result; } //! Check if a particle is a parton, i.e. quark, antiquark, or gluon inline bool is_parton(Particle const & p){ return is_parton(p.type); } //! Check if a particle is a quark inline bool is_quark(Particle const & p){ return is_quark(p.type); } //! Check if a particle is an anti-quark inline bool is_antiquark(Particle const & p){ return is_antiquark(p.type); } //! Check if a particle is a quark or anit-quark inline bool is_anyquark(Particle const & p){ return is_anyquark(p.type); } /** * \brief Function to determine if particle is a lepton * @param p the particle * @returns true if the particle is a lepton, false otherwise */ inline constexpr bool is_lepton(Particle const & p){ return is_lepton(p.type); } /** * \brief Function to determine if particle is an antilepton * @param p the particle * @returns true if the particle is an antilepton, false otherwise */ inline constexpr bool is_antilepton(Particle const & p){ return is_antilepton(p.type); } /** * \brief Function to determine if particle is an (anti-)lepton * @param p the particle * @returns true if the particle is a lepton or antilepton, false otherwise */ inline constexpr bool is_anylepton(Particle const & p){ return is_anylepton(p.type); } /** * \brief Function to determine if particle is a neutrino * @param p the particle * @returns true if the particle is a neutrino, false otherwise */ inline constexpr bool is_neutrino(Particle const & p){ return is_neutrino(p.type); } /** * \brief Function to determine if particle is an antineutrino * @param p the particle * @returns true if the particle is an antineutrino, false otherwise */ inline constexpr bool is_antineutrino(Particle const & p){ return is_antineutrino(p.type); } /** * \brief Function to determine if particle is an (anti-)neutrino * @param p the particle * @returns true if the particle is a neutrino or antineutrino, false otherwise */ inline constexpr bool is_anyneutrino(Particle const & p){ return is_anyneutrino(p.type); } //! Check if a particle is a photon, W or Z boson inline bool is_AWZ_boson(Particle const & particle){ return is_AWZ_boson(particle.type); } //! Check if a particle is a photon, W, Z, or Higgs boson inline bool is_AWZH_boson(Particle const & particle){ return is_AWZH_boson(particle.type); } //! Extract all partons from a vector of particles inline std::vector<Particle> filter_partons( std::vector<Particle> const & v ){ std::vector<Particle> result; result.reserve(v.size()); std::copy_if( begin(v), end(v), std::back_inserter(result), [](Particle const & p){ return is_parton(p); } ); return result; } } diff --git a/include/HEJ/PhaseSpacePoint.hh b/include/HEJ/PhaseSpacePoint.hh index 85ba9b6..1f51139 100644 --- a/include/HEJ/PhaseSpacePoint.hh +++ b/include/HEJ/PhaseSpacePoint.hh @@ -1,175 +1,182 @@ /** \file * \brief Contains the PhaseSpacePoint Class * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <array> #include <functional> #include <unordered_map> #include <vector> #include "HEJ/config.hh" #include "HEJ/Particle.hh" #include "HEJ/RNG.hh" +#include "HEJ/StatusCode.hh" namespace HEJ{ class Event; //! A point in resummation phase space class PhaseSpacePoint{ public: //! Default PhaseSpacePoint Constructor PhaseSpacePoint() = default; //! PhaseSpacePoint Constructor /** * @param ev Clustered Jet Event * @param conf Configuration parameters * @param ran Random number generator */ PhaseSpacePoint( Event const & ev, PhaseSpacePointConfig conf, RNG & ran ); //! Get phase space point weight double weight() const{ return weight_; } //! Access incoming particles std::array<Particle, 2> const & incoming() const{ return incoming_; } //! Access outgoing particles std::vector<Particle> const & outgoing() const{ return outgoing_; } //! Particle decays /** * The key in the returned map corresponds to the index in the * vector returned by outgoing() */ std::unordered_map<size_t, std::vector<Particle>> const & decays() const{ return decays_; } + //! Status code of generation + StatusCode status() const{ + return status_; + } + static constexpr int ng_max = 1000; //< maximum number of extra gluons private: //! /internal returns the clustered jets sorted in rapidity std::vector<fastjet::PseudoJet> cluster_jets( std::vector<fastjet::PseudoJet> const & partons ) const; bool pass_resummation_cuts( std::vector<fastjet::PseudoJet> const & jets ) const; bool pass_extremal_cuts( fastjet::PseudoJet const & ext_parton, fastjet::PseudoJet const & jet ) const; int sample_ng(std::vector<fastjet::PseudoJet> const & Born_jets); int sample_ng_jets(int ng, std::vector<fastjet::PseudoJet> const & Born_jets); double probability_in_jet( std::vector<fastjet::PseudoJet> const & Born_jets ) const; std::vector<fastjet::PseudoJet> gen_non_jet( int ng_non_jet, double ptmin, double ptmax ); void rescale_rapidities( std::vector<fastjet::PseudoJet> & partons, double ymin, double ymax ); std::vector<fastjet::PseudoJet> reshuffle( std::vector<fastjet::PseudoJet> const & Born_jets, fastjet::PseudoJet const & q ); /** \internal * final jet test: * - number of jets must match Born kinematics * - no partons designated as nonjet may end up inside jets * - all other outgoing partons *must* end up inside jets * - the extremal (in rapidity) partons must be inside the extremal jets * - rapidities must be the same (by construction) */ bool jets_ok( std::vector<fastjet::PseudoJet> const & Born_jets, std::vector<fastjet::PseudoJet> const & partons ) const; void reconstruct_incoming(std::array<Particle, 2> const & Born_incoming); double phase_space_normalisation( int num_Born_jets, int num_res_partons ) const; std::vector<fastjet::PseudoJet> split( std::vector<fastjet::PseudoJet> const & jets, int ng_jets ); std::vector<int> distribute_jet_partons( int ng_jets, std::vector<fastjet::PseudoJet> const & jets ); std::vector<fastjet::PseudoJet> split( std::vector<fastjet::PseudoJet> const & jets, std::vector<int> const & np_in_jet ); bool split_preserved_jets( std::vector<fastjet::PseudoJet> const & jets, std::vector<fastjet::PseudoJet> const & jet_partons ) const; template<class Particle> Particle const & most_backward_FKL( std::vector<Particle> const & partons ) const; template<class Particle> Particle const & most_forward_FKL( std::vector<Particle> const & partons ) const; template<class Particle> Particle & most_backward_FKL(std::vector<Particle> & partons) const; template<class Particle> Particle & most_forward_FKL(std::vector<Particle> & partons) const; bool extremal_ok( std::vector<fastjet::PseudoJet> const & partons ) const; /** \internal * \brief relabels qqx-pair with its PDG IDs. * \param event Born Event * * This function will label the qqx pair in a qqx event back to their * original types from the input event. * * \note This function assumes outgoing_ to be pure partonic when called, * i.e. A/W/Z/h bosons should _not be set_ at this stage */ void label_qqx(Event const & event); void copy_AWZH_boson_from(Event const & event); bool momentum_conserved() const; bool unob_, unof_, qqxb_, qqxf_, qqxmid_; double weight_; PhaseSpacePointConfig param_; std::array<Particle, 2> incoming_; std::vector<Particle> outgoing_; //! \internal Particle decays in the format {outgoing index, decay products} std::unordered_map<size_t, std::vector<Particle>> decays_; std::reference_wrapper<HEJ::RNG> ran_; + + StatusCode status_; }; } diff --git a/include/HEJ/ProgressBar.hh b/include/HEJ/ProgressBar.hh index 5f7f32d..aeaa9d3 100644 --- a/include/HEJ/ProgressBar.hh +++ b/include/HEJ/ProgressBar.hh @@ -1,93 +1,93 @@ /** \file * \brief Contains the ProgressBar class * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <ostream> #include <functional> #include <stdexcept> namespace HEJ { //! Class representing (and printing) a progress bar template<typename T> class ProgressBar { public: //! Constructor /** * @param out Output stream * @param max Maximum value of the progress parameter * * This will print a fixed-width progress bar, which is initially at 0%. */ ProgressBar(std::ostream & out, T max) : out_{out}, max_{max} { if(max <= 0) { throw std::invalid_argument{ "Maximum in progress bar has to be positive" }; } print_bar(); } //! Increment progress /** * @param count Value to add to the current progress parameter * * After updating the progess parameter, the progress bar is updated * to a percentage that corresponds to the ratio of the current and * maximum progress parameters. */ ProgressBar & increment(T count) { counter_ += count; update_progress(); return *this; } //! Increase progress by one unit /** * After updating the progess parameter, the progress bar is updated * to a percentage that corresponds to the ratio of the current and * maximum progress parameters. */ ProgressBar & operator++() { ++counter_; update_progress(); return *this; } private: void update_progress() { counter_ = std::min(counter_, max_); const int ndots = (100*counter_)/max_; const int new_dots = ndots - ndots_; if(new_dots > 0) { for(int dot = 0; dot < new_dots; ++dot) out_.get() << '.'; out_.get().flush(); ndots_ = ndots; } } void print_bar() const { out_.get() << "0% "; for(int i = 10; i <= 100; i+= 10){ out_.get() << " " + std::to_string(i) + "%"; } out_.get() << "\n|"; for(int i = 10; i <= 100; i+= 10){ out_.get() << "---------|"; } out_.get() << '\n'; } std::reference_wrapper<std::ostream> out_; T counter_ = 0; T ndots_ = 0; T max_; }; } diff --git a/include/HEJ/RNG.hh b/include/HEJ/RNG.hh index 9cd36f6..120b126 100644 --- a/include/HEJ/RNG.hh +++ b/include/HEJ/RNG.hh @@ -1,45 +1,45 @@ /** \file * \brief Interface for pseudorandom number generators * * We select our random number generator at runtime according to the * configuration file. This interface guarantees that we can use all * generators in the same way. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <limits> namespace HEJ { //! Interface for random number generator struct RNG { //! Generate random number in (0,1] virtual double flat() = 0; //! Minimum number that can be generated virtual unsigned min() const = 0; //! Maximum number that can be generated virtual unsigned max() const = 0; //! Generate random number in [min(), max()] virtual unsigned operator()() = 0; virtual ~RNG() = default; }; //! Helper struct with default implementations struct DefaultRNG : virtual RNG { unsigned min() const override { return 0u; } unsigned max() const override { return std::numeric_limits<unsigned>::max() - 1; } unsigned operator()() override { return flat()*std::numeric_limits<unsigned int>::max(); } }; } diff --git a/include/HEJ/Ranlux64.hh b/include/HEJ/Ranlux64.hh index c11c3c7..687e38e 100644 --- a/include/HEJ/Ranlux64.hh +++ b/include/HEJ/Ranlux64.hh @@ -1,34 +1,34 @@ /** \file * \brief Contains a class for the ranlux64 random number generator * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <string> #include <CLHEP/Random/Ranlux64Engine.h> #include "HEJ/RNG.hh" namespace HEJ { //! Ranlux64 random number generator /** * For details on ranlux64, see \cite Luscher:1993dy, \cite James:1993np */ class Ranlux64 : public DefaultRNG { public: Ranlux64(); Ranlux64(std::string const & seed_file); //! Generate pseudorandom number between 0 and 1 double flat() override; private: CLHEP::Ranlux64Engine ran_; }; } diff --git a/include/HEJ/RivetAnalysis.hh b/include/HEJ/RivetAnalysis.hh index e36b88d..cac5738 100644 --- a/include/HEJ/RivetAnalysis.hh +++ b/include/HEJ/RivetAnalysis.hh @@ -1,69 +1,68 @@ /** \file * \brief HEJ 2 interface to rivet analyses * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include <string> #include <vector> #include "HEJ/Analysis.hh" #include "HEJ/HepMCInterface.hh" namespace Rivet { class AnalysisHandler; } namespace YAML { class Node; } namespace HEJ { /** * @brief Class representing a Rivet analysis * * This class inherits from Analysis and can therefore be used * like any other HEJ 2 analysis. */ class RivetAnalysis: public HEJ::Analysis { public: static std::unique_ptr<Analysis> create(YAML::Node const & config); //! Constructor /** * @param config Configuration parameters * * config["analysis"] should be the name of a single Rivet analysis or * a list of Rivet analyses. config["output"] is the prefix for * the .yoda output files. */ RivetAnalysis(YAML::Node const & config); //! Pass an event to the underlying Rivet analysis void fill(HEJ::Event const & event, HEJ::Event const &) override; bool pass_cuts(HEJ::Event const &, HEJ::Event const &) override {return true;} //< no additional cuts are applied void finalise() override; private: std::vector<std::string> analyses_names_; const std::string output_name_; /// struct to organise the infos per rivet run/scale setting struct rivet_info { std::unique_ptr<Rivet::AnalysisHandler> handler; std::string name; HEJ::HepMCInterface hepmc; }; std::vector<rivet_info> rivet_runs_; /** * \internal * @brief Calculates the scale variation from the first event for the output file */ void init(HEJ::Event const & event); bool first_event_; }; } diff --git a/include/HEJ/ScaleFunction.hh b/include/HEJ/ScaleFunction.hh index 42c2c99..e84b7a7 100644 --- a/include/HEJ/ScaleFunction.hh +++ b/include/HEJ/ScaleFunction.hh @@ -1,174 +1,174 @@ /** \file * \brief Functions to calculate the (renormalisation and factorisation) scales for an event * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <functional> #include <memory> #include <string> #include <utility> #include <vector> namespace HEJ{ class Event; //! Class to calculate the scale associated with an event class ScaleFunction { public: //! Constructor /** * @param name Name of the scale choice (e.g. H_T) * @param fun Function used to calculate the scale */ ScaleFunction(std::string name, std::function<double(Event const &)> fun): name_{std::move(name)}, fun_{std::move(fun)} {} //! Name of the scale choice std::string const & name() const { return name_; } //! Calculate the scale associated with an event double operator()(Event const & ev) const { return fun_(ev); } private: friend ScaleFunction operator*(double factor, ScaleFunction base_scale); friend ScaleFunction operator/(ScaleFunction base_scale, double denom); friend ScaleFunction operator*(ScaleFunction func1, ScaleFunction func2); friend ScaleFunction operator/(ScaleFunction func1, ScaleFunction func2); std::string name_; std::function<double(Event const &)> fun_; }; //! Multiply a scale choice by a constant factor /** * For example, multiplying 0.5 and a scale function for H_T * will result in a scale function for H_T/2. */ ScaleFunction operator*(double factor, ScaleFunction base_scale); //! Multiply a scale choice by a second one /** * For example, multiplying H_T and m_j1j2 * will result in a scale function for H_T*m_j1j2. */ ScaleFunction operator*(ScaleFunction factor, ScaleFunction base_scale); //! Divide a scale choice by a constant factor /** * For example, dividing a scale function for H_T by 2 * will result in a scale function for H_T/2. */ ScaleFunction operator/(ScaleFunction base_scale, double denom); //! Divide a scale choice by a second one /** * For example, dividing a scale function for H_T by m_j1j2 * will result in a scale function for H_T/m_j1j2. */ ScaleFunction operator/(ScaleFunction base_scale, ScaleFunction denom); //! Calculate \f$H_T\f$ for the input event /** * \f$H_T\f$ is the sum of the (scalar) transverse momenta of all * final-state particles */ double H_T(Event const &); //! The maximum of all (scalar) jet transverse momentum double max_jet_pt(Event const &); //! The invariant mass of the sum of all jet momenta double jet_invariant_mass(Event const &); //! Invariant mass of the two hardest jets double m_j1j2(Event const &); //! Functor that returns a fixed scale regardless of the input event class FixedScale { public: explicit FixedScale(double mu): mu_{mu} {} double operator()(Event const &) const { return mu_; } private: double mu_; }; class ParameterDescription; //! Generate combinations of renormalisation and factorisation scales class ScaleGenerator{ public: ScaleGenerator() = default; /** \brief Constructor * @param scale_functions_begin Iterator to first base scale * @param scale_functions_end Iterator past last base scale * @param scale_factors_begin Iterator to first scale factor * @param scale_factors_end Iterator past last scale factor * @param max_scale_ratio Maximum ratio between renormalisation * and factorisation scale */ template<class ScaleFunIterator, class FactorIterator> ScaleGenerator( ScaleFunIterator scale_functions_begin, ScaleFunIterator scale_functions_end, FactorIterator scale_factors_begin, FactorIterator scale_factors_end, double max_scale_ratio ): scales_(scale_functions_begin, scale_functions_end), scale_factors_(scale_factors_begin, scale_factors_end), max_scale_ratio_{max_scale_ratio} { gen_descriptions(); } /** \brief Constructor * @param scales Base scales * @param scale_factors Factors to multiply the base scales * @param max_scale_ratio Maximum ratio between renormalisation * and factorisation scale */ ScaleGenerator( std::vector<ScaleFunction> scales, std::vector<double> scale_factors, double max_scale_ratio ): scales_(std::move(scales)), scale_factors_(std::move(scale_factors)), max_scale_ratio_{max_scale_ratio} { gen_descriptions(); } /** \brief Adjust event parameters, adding scale variation * * The central renormalisation and factorisation scale of the returned * event is given be the first base scale passed to the constructor. * The scale variation (stored in event.variation()) is constructed as * follows: For each base scale according to the arguments of the * constructor we add one variation where both renormalisation and * factorisation scale are set according to the current base scale. * Then, all combinations where the base renormalisation and factorisation * scales are multiplied by one of the scale factors are added. * The case were both scales are multiplied by one is skipped. * Scale combinations where the ratio is larger than the maximum scale ratio * set in the constructor are likewise discarded. */ Event operator()(Event event) const; private: void gen_descriptions(); std::vector<ScaleFunction> scales_; std::vector<double> scale_factors_; std::vector<std::shared_ptr<ParameterDescription>> descriptions_; double max_scale_ratio_; }; } diff --git a/include/HEJ/StatusCode.hh b/include/HEJ/StatusCode.hh new file mode 100644 index 0000000..9e04007 --- /dev/null +++ b/include/HEJ/StatusCode.hh @@ -0,0 +1,39 @@ +/** \file + * \brief Header file for status codes of event generation + * + * \authors Jeppe Andersen, Marian Heil, Andreas Maier, Jennifer Smillie + * \date 2019 + * \copyright GPLv2 or later + */ +#pragma once + +namespace HEJ { + enum StatusCode{ + good, + discard, + empty_jets, + failed_reshuffle, + failed_resummation_cuts, + failed_split, + too_much_energy, + wrong_jets, + unspecified // should never appear + }; + + // @TODO better names + inline std::string to_string(StatusCode s){ + switch(s){ + case good: return "good"; + case discard: return "discard"; + case empty_jets: return "empty jets"; + case failed_reshuffle: return "failed reshuffle"; + case failed_resummation_cuts: return "below cuts"; + case failed_split: return "failed split"; + case too_much_energy: return "too much energy"; + case wrong_jets: return "wrong jets"; + case unspecified: return "unspecified"; + default:; + } + throw std::logic_error{"unreachable"}; + } + } // HEJ diff --git a/include/HEJ/Tensor.hh b/include/HEJ/Tensor.hh index b02ae30..470539e 100644 --- a/include/HEJ/Tensor.hh +++ b/include/HEJ/Tensor.hh @@ -1,201 +1,204 @@ /** \file * \brief Tensor Template Class declaration. * * This file contains the declaration of the Tensor Template class. This * is used to calculate some of the more complex currents within the * W+Jets implementation particularly. + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later */ - #pragma once #include <array> ///@TODO remove function implementation from header ///@TODO put in some namespace template <unsigned int N, unsigned int D> class Tensor{ public: //Constructor Tensor(); Tensor(COM x); //Destructor virtual ~Tensor(); int rank(){ return N; } int dim(){ return D; } int len(){ return size; } COM at(int i){ return components[i]; } COM at(int i, int j) { return components[D*i +j]; } COM at(int i, int j, int k) { return components[D*(D*i + j)+ k]; } COM at(int i,int j, int k,int l) { return components[D*(D*(D*i +j) + k) + l]; } COM at(int i,int j, int k,int l, int m){ return components[D*(D*(D*(D*i + j) + k) + l) + m]; } bool isSet(){ if(components.size()==0) return false; else return true; } void Fill(COM x){ components=x; } //Set component indexed by i,j,k,l,m void Set(int i,COM x){ components[i] = x; } void Set(int i, int j, COM x) { components[D*i +j] = x; } void Set(int i, int j, int k, COM x) { components[D*(D*i + j)+ k] = x; } void Set(int i,int j, int k,int l,COM x) { components[D*(D*(D*i +j) + k) + l] = x; } void Set(int i,int j, int k,int l, int m, COM x){ components[D*(D*(D*(D*i + j) + k) + l) + m] = x; } Tensor<N,D> operator*(const double x){ Tensor<N,D> newT; newT.components=components*COM(x,0); return newT; } Tensor<N,D> operator*(const COM x){ Tensor<N,D> newT; newT.components=components*x; return newT; } Tensor<N,D> operator/(const double x){ Tensor<N,D> newT; newT.components=components/COM(x,0); return newT; } Tensor<N,D> operator/(const COM x){ Tensor<N,D> newT; newT.components=components/x; return newT; } Tensor<N,D> operator+(const Tensor<N,D> T2){ Tensor<N,D> newT; newT.components=components+T2.components; return newT; } Tensor<N,D> operator-(const Tensor<N,D> T2){ Tensor<N,D> newT; newT.components=components-T2.components; return newT; } void operator+=(const Tensor<N,D> T2){ components = components+T2.components; } void operator-=(const Tensor<N,D> T2){ components=components-T2.components; } Tensor<N+1,D> rightprod(const Tensor<1,D> T2){ Tensor<N+1,D> newT; for(int i=0; i<size;i++){ for(unsigned int j=0;j<D;j++){ newT.components[i*D+j]=components[i]*T2.components[j]; } } return newT; } Tensor<N+1,D> leftprod(const Tensor<1,D> T2){ Tensor<N+1,D> newT; for(unsigned int j=0;j<D;j++){ for(int i=0; i<size;i++){ newT.components[j*size+i]=components[i]*T2.components[j]; } } return newT; } //T^(mu1...mk..mN)T2_(muk) contract kth index, where k member of [1,N] Tensor<N-1,D> contract(const Tensor<1,D> T2, int k){ Tensor<N-1,D> newT; for(int j=0; j<newT.len(); j++){ COM temp; int itemp = pow(D,(N-k)); for (unsigned int i=0; i<D; i++){ int index = D*itemp*floor(j/itemp) + itemp*i +j%(itemp); temp+=components[index]*T2.components[i]*sign(i); } newT.components[j]=temp; } return newT; } std::valarray<COM> components; private: int size; COM sign(unsigned int i){ if(i==0) return 1.; else return -1.; } }; template <unsigned int N, unsigned int D> Tensor<N,D>::Tensor() { size = pow(D,N); components.resize(size); } template <unsigned int N, unsigned int D> Tensor<N,D>::Tensor(COM x) { size = pow(D,N); components.resize(size, x); } template <unsigned int N, unsigned int D> Tensor<N,D>::~Tensor() {} // Tensor Functions: // Tensor<1,4> Sigma(int i, int j, bool hel); // Tensor<2,4> Metric(); // int tensor2listindex(std::array<int,5> indexlist); // int tensor2listindex(std::array<int,3> indexlist); // void perms41(int same4, int diff, std::vector<std::array<int,5>> * perms); // void perms32(int same3, int diff, std::vector<std::array<int,5>> * perms); // void perms311(int same3, int diff1, int diff2, std::vector<std::array<int,5>> * perms); // void perms221(int same2a, int same2b, int diff, std::vector<std::array<int,5>> * perms); // void perms2111(int same2, int diff1,int diff2,int diff3, std::vector<std::array<int,5>> * perms); // void perms21(int same, int diff, std::vector<std::array<int,3>> * perms); // void perms111(int diff1, int diff2, int diff3, std::vector<std::array<int,3>> * perms); Tensor<2,4> Metric(); Tensor<1,4> TCurrent(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2); Tensor<3,4> T3Current(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2); Tensor<5,4> T5Current(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2); Tensor<1,4> Construct1Tensor(CCurrent j); Tensor<1,4> Construct1Tensor(CLHEP::HepLorentzVector p); Tensor<1,4> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol); bool init_sigma_index(); diff --git a/include/HEJ/Weights.hh b/include/HEJ/Weights.hh index 2b0af46..98fb8d7 100644 --- a/include/HEJ/Weights.hh +++ b/include/HEJ/Weights.hh @@ -1,13 +1,13 @@ /** \file * \brief Legacy Header for Weights * \note This Header was moved to "HEJ/Parameters.hh" * \TODO remove in HEJ 2.2.0 * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #warning "HEJ/Weights.hh is deprecated use HEJ/Parameters.hh instead" #pragma once #include "HEJ/Parameters.hh" diff --git a/include/HEJ/YAMLreader.hh b/include/HEJ/YAMLreader.hh index fd9b36a..06cb2f8 100644 --- a/include/HEJ/YAMLreader.hh +++ b/include/HEJ/YAMLreader.hh @@ -1,254 +1,253 @@ /** \file * \brief The file which handles the configuration file parameters * * The configuration files parameters are read and then stored * within this objects. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <string> #include <utility> #include <vector> #include "yaml-cpp/yaml.h" #include "fastjet/JetDefinition.hh" #include "HEJ/config.hh" #include "HEJ/exceptions.hh" #include "HEJ/optional.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/utility.hh" namespace HEJ{ class OutputFile; //! Load configuration from file /** * @param config_file Name of the YAML configuration file * @returns The HEJ 2 configuration */ Config load_config(std::string const & config_file); //! Set option using the corresponding YAML entry /** * @param setting Option variable to be set * @param yaml Root of the YAML configuration * @param names Name of the entry * * If the entry does not exist or has the wrong type or format * an exception is thrown. * * For example * @code * set_from_yaml(foobar, yaml, "foo", "bar") * @endcode * is equivalent to * @code * foobar = yaml["foo"]["bar"].as<decltype(foobar)>() * @endcode * with improved diagnostics on errors. * * @see set_from_yaml_if_defined */ template<typename T, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, YamlNames const & ... names ); //! Set option using the corresponding YAML entry, if present /** * @param setting Option variable to be set * @param yaml Root of the YAML configuration * @param names Name of the entry * * This function works similar to set_from_yaml, but does not * throw any exception if the requested YAML entry does not exist. * * @see set_from_yaml */ template<typename T, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, YamlNames const & ... names ); //! Extract jet parameters from YAML configuration JetParameters get_jet_parameters( YAML::Node const & node, std::string const & entry ); //! Extract Higgs coupling settings from YAML configuration HiggsCouplingSettings get_Higgs_coupling( YAML::Node const & node, std::string const & entry ); //! Extract scale setting parameters from YAML configuration ScaleConfig to_ScaleConfig(YAML::Node const & yaml); //! Extract random number generator settings from YAML configuration RNGConfig to_RNGConfig(YAML::Node const & node, std::string const & entry); //! Check whether all options in configuration are supported /** * @param conf Configuration to be checked * @param supported Tree of supported options * * If conf contains an entry that does not appear in supported * an unknown_option exception is thrown. Sub-entries of "analysis" * (if present) are not checked. * * @see unknown_option */ void assert_all_options_known( YAML::Node const & conf, YAML::Node const & supported ); namespace detail{ void set_from_yaml(fastjet::JetAlgorithm & setting, YAML::Node const & yaml); void set_from_yaml(EventTreatment & setting, YAML::Node const & yaml); void set_from_yaml(ParticleID & setting, YAML::Node const & yaml); void set_from_yaml(OutputFile & setting, YAML::Node const & yaml); inline void set_from_yaml(YAML::Node & setting, YAML::Node const & yaml){ setting = yaml; } template<typename Scalar> void set_from_yaml(Scalar & setting, YAML::Node const & yaml){ assert(yaml); if(!yaml.IsScalar()){ throw invalid_type{"value is not a scalar"}; } try{ setting = yaml.as<Scalar>(); } catch(...){ throw invalid_type{ "value " + yaml.as<std::string>() + " cannot be converted to a " + type_string(setting) }; } } template<typename T> void set_from_yaml(optional<T> & setting, YAML::Node const & yaml){ T tmp; set_from_yaml(tmp, yaml); setting = tmp; } template<typename T> void set_from_yaml(std::vector<T> & setting, YAML::Node const & yaml){ assert(yaml); // special case: treat a single value like a vector with one element if(yaml.IsScalar()){ setting.resize(1); return set_from_yaml(setting.front(), yaml); } if(yaml.IsSequence()){ setting.resize(yaml.size()); for(size_t i = 0; i < setting.size(); ++i){ set_from_yaml(setting[i], yaml[i]); } return; } throw invalid_type{""}; } template<typename T, typename FirstName, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, FirstName const & name, YamlNames && ... names ){ if(!yaml[name]) throw missing_option{""}; set_from_yaml( setting, yaml[name], std::forward<YamlNames>(names)... ); } template<typename T> void set_from_yaml_if_defined(T & setting, YAML::Node const & yaml){ return set_from_yaml(setting, yaml); } template<typename T, typename FirstName, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, FirstName const & name, YamlNames && ... names ){ if(!yaml[name]) return; set_from_yaml_if_defined( setting, yaml[name], std::forward<YamlNames>(names)... ); } } template<typename T, typename... YamlNames> void set_from_yaml( T & setting, YAML::Node const & yaml, YamlNames const & ... names ){ try{ detail::set_from_yaml(setting, yaml, names...); } catch(invalid_type const & ex){ throw invalid_type{ "In option " + join(": ", names...) + ": " + ex.what() }; } catch(missing_option const &){ throw missing_option{ "No entry for mandatory option " + join(": ", names...) }; } catch(std::invalid_argument const & ex){ throw missing_option{ "In option " + join(": ", names...) + ":" " invalid value " + ex.what() }; } } template<typename T, typename... YamlNames> void set_from_yaml_if_defined( T & setting, YAML::Node const & yaml, YamlNames const & ... names ){ try{ detail::set_from_yaml_if_defined(setting, yaml, names...); } catch(invalid_type const & ex){ throw invalid_type{ "In option " + join(": ", names...) + ": " + ex.what() }; } catch(std::invalid_argument const & ex){ throw missing_option{ "In option " + join(": ", names...) + ":" " invalid value " + ex.what() }; } } } namespace YAML { template<> struct convert<HEJ::OutputFile> { static Node encode(HEJ::OutputFile const & outfile); static bool decode(Node const & node, HEJ::OutputFile & out); }; } diff --git a/include/HEJ/config.hh b/include/HEJ/config.hh index 51f973c..c6a002c 100644 --- a/include/HEJ/config.hh +++ b/include/HEJ/config.hh @@ -1,191 +1,190 @@ /** \file * \brief HEJ 2 configuration parameters * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <string> #include "fastjet/JetDefinition.hh" #include "yaml-cpp/yaml.h" #include "HEJ/Constants.hh" #include "HEJ/event_types.hh" #include "HEJ/HiggsCouplingSettings.hh" #include "HEJ/optional.hh" #include "HEJ/output_formats.hh" #include "HEJ/ScaleFunction.hh" namespace HEJ{ //! Jet parameters struct JetParameters{ fastjet::JetDefinition def; /**< Jet Definition */ double min_pt; /**< Minimum Jet Transverse Momentum */ }; //! Settings for scale variation struct ScaleConfig{ //! Base scale choices std::vector<ScaleFunction> base; //! Factors for multiplicative scale variation std::vector<double> factors; //! Maximum ratio between renormalisation and factorisation scale double max_ratio; }; //! Settings for random number generator struct RNGConfig { //! Random number generator name std::string name; //! Optional initial seed optional<std::string> seed; }; /**! Possible treatments for fixed-order input events. * * The program will decide on how to treat an event based on * the value of this enumeration. */ enum class EventTreatment{ reweight, /**< Perform resummation */ keep, /**< Keep the event */ discard, /**< Discard the event */ }; //! Container to store the treatments for various event types using EventTreatMap = std::map<event_type::EventType, EventTreatment>; /**! Input parameters. * * This struct handles stores all configuration parameters * needed in a HEJ 2 run. * * \internal To add a new option: * 1. Add a member to the Config struct. * 2. Inside "src/YAMLreader.cc": * - Add the option name to the "supported" Node in * get_supported_options. * - Initialise the new Config member in to_Config. * The functions set_from_yaml (for mandatory options) and * set_from_yaml_if_defined (non-mandatory) may be helpful. * 3. Add a new entry (with short description) to config.yaml * 4. Update the user documentation in "doc/Sphinx/" */ struct Config { //! Parameters for scale variation ScaleConfig scales; //! Resummation jet properties JetParameters resummation_jets; //! Fixed-order jet properties JetParameters fixed_order_jets; //! Minimum transverse momentum for extremal partons double min_extparton_pt; //! Maximum transverse momentum fraction from soft radiation in extremal jets double max_ext_soft_pt_fraction; //! The regulator lambda for the subtraction terms double regulator_lambda = CLAMBDA; //! Number of resummation configurations to generate per fixed-order event int trials; //! Whether to include the logarithmic correction from \f$\alpha_s\f$ running bool log_correction; //! Event output files names and formats std::vector<OutputFile> output; //! Parameters for random number generation RNGConfig rng; //! Map to decide what to do for different event types EventTreatMap treat; //! Parameters for custom analyses YAML::Node analysis_parameters; //! Settings for effective Higgs-gluon coupling HiggsCouplingSettings Higgs_coupling; }; //! Configuration options for the PhaseSpacePoint class struct PhaseSpacePointConfig { //! Properties of resummation jets JetParameters jet_param; //! Minimum transverse momentum for extremal partons double min_extparton_pt; //! Maximum transverse momentum fraction from soft radiation in extremal jets double max_ext_soft_pt_fraction; }; //! Configuration options for the MatrixElement class struct MatrixElementConfig { MatrixElementConfig() = default; MatrixElementConfig( bool log_correction, HiggsCouplingSettings Higgs_coupling, double regulator_lambda = CLAMBDA ): log_correction(log_correction), Higgs_coupling(Higgs_coupling), regulator_lambda(regulator_lambda) {} //! Whether to include the logarithmic correction from \f$\alpha_s\f$ running bool log_correction; //! Settings for effective Higgs-gluon coupling HiggsCouplingSettings Higgs_coupling; //! The regulator lambda for the subtraction terms double regulator_lambda = CLAMBDA; }; //! Configuration options for the EventReweighter class struct EventReweighterConfig { //! Settings for phase space point generation PhaseSpacePointConfig psp_config; //! Settings for matrix element calculation MatrixElementConfig ME_config; //! Properties of resummation jets JetParameters jet_param; //! Treatment of the various event types EventTreatMap treat; }; /**! Extract PhaseSpacePointConfig from Config * * \internal We do not provide a PhaseSpacePointConfig constructor from Config * so that PhaseSpacePointConfig remains an aggregate. * This faciliates writing client code (e.g. the HEJ fixed-order generator) * that creates a PhaseSpacePointConfig *without* a Config object. * * @see to_MatrixElementConfig, to_EventReweighterConfig */ inline PhaseSpacePointConfig to_PhaseSpacePointConfig(Config const & conf) { return { conf.resummation_jets, conf.min_extparton_pt, conf.max_ext_soft_pt_fraction }; } /**! Extract MatrixElementConfig from Config * * @see to_PhaseSpacePointConfig, to_EventReweighterConfig */ inline MatrixElementConfig to_MatrixElementConfig(Config const & conf) { return {conf.log_correction, conf.Higgs_coupling, conf.regulator_lambda}; } /**! Extract EventReweighterConfig from Config * * @see to_PhaseSpacePointConfig, to_MatrixElementConfig */ inline EventReweighterConfig to_EventReweighterConfig(Config const & conf) { return { to_PhaseSpacePointConfig(conf), to_MatrixElementConfig(conf), conf.resummation_jets, conf.treat }; } } // namespace HEJ diff --git a/include/HEJ/currents.hh b/include/HEJ/currents.hh index fb2ffaf..349518b 100644 --- a/include/HEJ/currents.hh +++ b/include/HEJ/currents.hh @@ -1,1333 +1,1319 @@ -////////////////////////////////////////////////// -////////////////////////////////////////////////// -// This source code is Copyright (2012) of // -// Jeppe R. Andersen and Jennifer M. Smillie // -// and is distributed under the // -// Gnu Public License version 2 // -// http://www.gnu.org/licenses/gpl-2.0.html // -// You are allowed to distribute and alter the // -// source under the conditions of the GPLv2 // -// as long as this copyright notice // -// is unaltered and distributed with the source // -// Any use should comply with the // -// MCNET GUIDELINES // -// for Event Generator Authors and Users // -// as distributed with this source code // -////////////////////////////////////////////////// -////////////////////////////////////////////////// - +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ /** \file * \brief Functions computing the square of current contractions. * * This file contains all the necessary functions to compute the current * contractions for all valid HEJ processes. PJETS, H+JETS and W+JETS along with * some unordered counterparts. * * @TODO add a namespace */ - #pragma once #include <complex> #include <vector> #include <valarray> #include <limits> #include <ostream> #include <CLHEP/Vector/LorentzVector.h> typedef std::complex<double> COM; typedef COM current[4]; typedef CLHEP::HepLorentzVector HLV; //! Square of qQ->qenuQ W+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @returns Square of the current contractions for qQ->qenuQ Scattering * * This returns the square of the current contractions in qQ->qenuQ scattering * with an emission of a W Boson. */ double jMWqQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qbarQ->qbarenuQ W+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @returns Square of the current contractions for qbarQ->qbarenuQ Scattering * * This returns the square of the current contractions in qbarQ->qbarenuQ scattering * with an emission of a W Boson. */ double jMWqbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qQbar->qenuQbar W+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @returns Square of the current contractions for qQbar->qenuQbar Scattering * * This returns the square of the current contractions in qQbar->qenuQbar scattering * with an emission of a W Boson. */ double jMWqQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qbarQbar->qbarenuQbar W+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @returns Square of the current contractions for qbarQbar->qbarenuQbar Scattering * * This returns the square of the current contractions in qbarQbar->qbarenuQbar scattering * with an emission of a W Boson. */ double jMWqbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qg->qenug W+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @returns Square of the current contractions for qg->qenug Scattering * * This returns the square of the current contractions in qg->qenug scattering * with an emission of a W Boson. */ double jMWqg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qbarg->qbarenug W+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @returns Square of the current contractions for qbarg->qbarenug Scattering * * This returns the square of the current contractions in qbarg->qbarenug scattering * with an emission of a W Boson. */ double jMWqbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); // W+Jets Unordered Functions //! qQg Wjets Unordered backwards opposite leg to W /** * @param p1out Momentum of final state quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @param pg Momentum of final state unordered gluon * @returns Square of the current contractions for qQ->qQg Scattering * * This returns the square of the current contractions in qQg->qQg scattering * with an emission of a W Boson. */ double junobMWqQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg); //! qbarQg Wjets Unordered backwards opposite leg to W /** * @param p1out Momentum of final state anti-quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @param pg Momentum of final state unordered gluon * @returns Square of the current contractions for qbarQ->qbarQg Scattering * * This returns the square of the current contractions in qbarQg->qbarQg scattering * with an emission of a W Boson. */ double junobMWqbarQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg); //! qQbarg Wjets Unordered backwards opposite leg to W /** * @param p1out Momentum of final state quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @param pg Momentum of final state unordered gluon * @returns Square of the current contractions for qQbar->qQbarg Scattering * * This returns the square of the current contractions in qQbarg->qQbarg scattering * with an emission of a W Boson. */ double junobMWqQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg); //! qbarQbarg Wjets Unordered backwards opposite leg to W /** * @param p1out Momentum of final state anti-quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @param pg Momentum of final state unordered gluon * @returns Square of the current contractions for qbarQbar->qbarQbarg Scattering * * This returns the square of the current contractions in qbarQbarg->qbarQbarg scattering * with an emission of a W Boson. */ double junobMWqbarQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg); //!Wjets Unordered forwards opposite leg to W /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @returns Square of the current contractions for qQ->gqQ Scattering * * This returns the square of the current contractions in qQg->gqQ scattering * with an emission of a W Boson. */ double junofMWgqQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in); //!Wjets Unordered forwards opposite leg to W /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state anti-quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @returns Square of the current contractions for qbarQ->gqbarQ Scattering * * This returns the square of the current contractions in qbarQg->gqbarQ scattering * with an emission of a W Boson. */ double junofMWgqbarQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in); //!Wjets Unordered forwards opposite leg to W /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @returns Square of the current contractions for qQbar->gqQbar Scattering * * This returns the square of the current contractions in qQbarg->gqQbar scattering * with an emission of a W Boson. */ double junofMWgqQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in); //!Wjets Unordered forwards opposite leg to W /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state anti-quark a * @param pe Momentum of final state electron * @param pnu Momentum of final state Neutrino * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @returns Square of the current contractions for qbarQbar->gqbarQbar Scattering * * This returns the square of the current contractions in qbarQbarg->gqbarQbar scattering * with an emission of a W Boson. */ double junofMWgqbarQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in); //!W+uno same leg /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @returns Square of the current contractions for qQ->qQg Scattering * * This returns the square of the current contractions in gqQ->gqQ scattering * with an emission of a W Boson. */ double jM2WunogqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! @TODO What does this function do? Crossed contribution is Exqqx..? /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @returns Square of the current contractions for qQ->gqQ Scattering * * This returns the square of the current contractions in gqQ->gqQ scattering * with an emission of a W Boson. */ double jM2WunogqQ_crossqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! W+uno same leg. quark anti-quark /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @returns Square of the current contractions for qQbar->gqQbar Scattering * * This returns the square of the current contractions in gqQbar->gqQbar scattering * with an emission of a W Boson. (Unordered Same Leg) */ double jM2WunogqQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! W+uno same leg. quark gluon /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state quark a * @param p2out Momentum of final state gluon b * @param p2in Momentum of intial state gluon b * @returns Square of the current contractions for qg->gqg Scattering * * This returns the square of the current contractions in qg->gqg scattering * with an emission of a W Boson. */ double jM2Wunogqg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! W+uno same leg. anti-quark quark /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state anti-quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state quark b * @param p2in Momentum of intial state quark b * @returns Square of the current contractions for qbarQ->gqbarQ Scattering * * This returns the square of the current contractions in qbarQ->gqbarQ scattering * with an emission of a W Boson. */ double jM2WunogqbarQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! W+uno same leg. anti-quark anti-quark /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state anti-quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state anti-quark b * @param p2in Momentum of intial state anti-quark b * @returns Square of the current contractions for qbarQbar->gqbarQbar Scattering * * This returns the square of the current contractions in gqbarQbar->qbarQbar scattering * with an emission of a W Boson. */ double jM2WunogqbarQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! W+uno same leg. anti-quark gluon /** * @param pg Momentum of final state unordered gluon * @param p1out Momentum of final state anti-quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param p1in Momentum of initial state anti-quark a * @param p2out Momentum of final state gluon b * @param p2in Momentum of intial state gluon b * @returns Square of the current contractions for ->gqbarg Scattering * * This returns the square of the current contractions in qbarg->gqbarg scattering * with an emission of a W Boson. */ double jM2Wunogqbarg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //W+Jets qqxExtremal //! W+Extremal qqx. qxqQ /** * @param pgin Momentum of initial state gluon * @param pqout Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param pqbarout Momentum of final state anti-quark a * @param p2out Momentum of initial state anti-quark b * @param p2in Momentum of final state gluon b * @returns Square of the current contractions for ->qbarqQ Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2WgQtoqbarqQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //W+Jets qqxExtremal //! W+Extremal qqx. qqxQ /** * @param pgin Momentum of initial state gluon * @param pqout Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param pqbarout Momentum of final state anti-quark a * @param p2out Momentum of initial state anti-quark b * @param p2in Momentum of final state gluon b * @returns Square of the current contractions for ->qqbarQ Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2WgQtoqqbarQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //W+Jets qqxExtremal //! W+Extremal qqx. gg->qxqg /** * @param pgin Momentum of initial state gluon * @param pqout Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param pqbarout Momentum of final state anti-quark a * @param p2out Momentum of initial state gluon b * @param p2in Momentum of final state gluon b * @returns Square of the current contractions for gg->qbarqg Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2Wggtoqbarqg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //W+Jets qqxExtremal //! W+Extremal qqx. gg->qqxg /** * @param pgin Momentum of initial state gluon * @param pqout Momentum of final state quark a * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param pqbarout Momentum of final state anti-quark a * @param p2out Momentum of initial state gluon a * @param p2in Momentum of final state gluon b * @returns Square of the current contractions for gg->qqbarg Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2Wggtoqqbarg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //W+Jets qqxExtremal, W emission from opposite leg //! W+Extremal qqx. gg->qqxg. qqx on forwards leg, W emission backwards leg. /** * @param pa Momentum of initial state (anti-)quark * @param pb Momentum of initial state gluon * @param p1 Momentum of final state (anti-)quark (after W emission) * @param p2 Momentum of final state anti-quark * @param p3 Momentum of final state quark * @param plbar Momentum of final state anti-lepton * @param pl Momentum of final state lepton * @param aqlinepa Is opposite extremal leg to qqx a quark or antiquark line * @returns Square of the current contractions for gq->qqbarqW Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated via current contraction of existing currents. * Assumes qqx split from forwards leg, W emission from backwards leg. * Switch input (pa<->pb, p1<->pn) if calculating forwards qqx. */ double jM2WgqtoQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, bool aqlinepa); //! W+Jets qqxCentral. qqx W emission. /** * @param pa Momentum of initial state particle a * @param pb Momentum of initial state particle b * @param pl Momentum of final state lepton * @param plbar Momentum of final state anti-lepton * @param partons Vector of outgoing parton momenta * @param aqlinepa Bool: True= pa is anti-quark * @param aqlinepb Bool: True= pb is anti-quark * @param qqxmarker Bool: Ordering of the qqbar pair produced (qqx vs qxq) * @param nabove Number of lipatov vertices "above" qqbar pair * @param nbelow Number of lipatov vertices "below" qqbar pair * @returns Square of the current contractions for qq>qQQbarWq Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2WqqtoqQQq(HLV pa, HLV pb,HLV pl,HLV plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove); //emission from backwards leg //! W+Jets qqxCentral. W emission from backwards leg. /** * @param ka HLV: Momentum of initial state particle a * @param kb HLV: Momentum of initial state particle b * @param pl HLV: Momentum of final state lepton * @param plbar HLV: Momentum of final state anti-lepton * @param partons Vector(HLV): outgoing parton momenta * @param aqlinepa Bool: True= pa is anti-quark * @param aqlinepb Bool: True= pb is anti-quark * @param qqxmarker Bool: Ordering of the qqbar pair produced (qqx vs qxq) * @param nabove Int: Number of lipatov vertices "above" qqbar pair * @param nbelow Int: Number of lipatov vertices "below" qqbar pair * @param forwards Bool: Swap to emission off front leg TODO:remove so args can be const * @returns Square of the current contractions for qq>qQQbarWq Scattering * * Calculates the square of the current contractions with extremal qqbar pair * production. This is calculated through the use of crossing symmetry. */ double jM2WqqtoqQQqW(HLV ka, HLV kb,HLV pl,HLV plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove, int nbelow, bool forwards); //Doing //! Square of qQ->qQ Pure Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @returns Square of the current contractions for qQ->qQ Scattering * * This returns the square of the current contractions in qQ->qQ Pure Jet Scattering. */ double jM2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qQbar->qQbar Pure Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @returns Square of the current contractions for qQbar->qQbar Scattering * * This returns the square of the current contractions in qQbar->qQbar Pure Jet Scattering. * Note this can be used for qbarQ->qbarQ Scattering by inputting arguments appropriately. */ double jM2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qbarQbar->qbarQbar Pure Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @returns Square of the current contractions for qbarQbar->qbarQbar Scattering * * This returns the square of the current contractions in qbarQbar->qbarQbar Pure Jet Scattering. */ double jM2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qg->qg Pure Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @returns Square of the current contractions for qg->qg Scattering * * This returns the square of the current contractions in qg->qg Pure Jet Scattering. * Note this can be used for gq->gq Scattering by inputting arguments appropriately. */ double jM2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of qbarg->qbarg Pure Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @returns Square of the current contractions for qbarg->qbarg Scattering * * This returns the square of the current contractions in qbarg->qbarg Pure Jet Scattering. * Note this can be used for gqbar->gqbar Scattering by inputting arguments appropriately. */ double jM2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of gg->gg Pure Jets Scattering Current /** * @param p1out Momentum of final state gluon * @param p1in Momentum of initial state gluon * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @returns Square of the current contractions for gg->gg Scattering * * This returns the square of the current contractions in gg->gg Pure Jet Scattering. */ double jM2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in); //! Square of gg->gg Higgs+Jets Scattering Current /** * @param p1out Momentum of final state gluon * @param p1in Momentum of initial state gluon * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for gg->gg Scattering * * This returns the square of the current contractions in gg->gg Higgs+Jet Scattering. * * g~p1 g~p2 * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if g is backward, q1 is forward) */ double MH2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of gq->gq Higgs+Jets Scattering Current with Higgs before Gluon /** * @param p1out Momentum of final state gluon * @param p1in Momentum of initial state gluon * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param pH Momentum of Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contraction * */ double MH2gq_outsideH(CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pH, double mt, bool include_bottom, double mb); //! Square of qg->qg Higgs+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qg->qg Scattering * * This returns the square of the current contractions in qg->qg Higgs+Jet Scattering. * * q~p1 g~p2 (i.e. ALWAYS p1 for quark, p2 for gluon) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if g is backward, q1 is forward) */ double MH2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarg->qbarg Higgs+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarg->qbarg Scattering * * This returns the square of the current contractions in qbarg->qbarg Higgs+Jet Scattering. * * qbar~p1 g~p2 (i.e. ALWAYS p1 for anti-quark, p2 for gluon) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if g is backward, q1 is forward) */ double MH2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qQ->qQ Higgs+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQ->qQ Scattering * * This returns the square of the current contractions in qQ->qQ Higgs+Jet Scattering. * * q~p1 Q~p2 (i.e. ALWAYS p1 for quark, p2 for quark) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if Q is backward, q1 is forward) */ double MH2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qQbar->qQbar Higgs+Jets Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQ->qQ Scattering * * This returns the square of the current contractions in qQbar->qQbar Higgs+Jet Scattering. * * q~p1 Qbar~p2 (i.e. ALWAYS p1 for quark, p2 for anti-quark) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if Qbar is backward, q1 is forward) */ double MH2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarQ->qbarQ Higgs+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQ->qbarQ Scattering * * This returns the square of the current contractions in qbarQ->qbarQ Higgs+Jet Scattering. * * qbar~p1 Q~p2 (i.e. ALWAYS p1 for anti-quark, p2 for quark) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if Q is backward, q1 is forward) */ double MH2qbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarQbar->qbarQbar Higgs+Jets Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param q1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQbar->qbarQbar Scattering * * This returns the square of the current contractions in qbarQbar->qbarQbar Higgs+Jet Scattering. * * qbar~p1 Qbar~p2 (i.e. ALWAYS p1 for anti-quark, p2 for anti-quark) * should be called with q1 meant to be contracted with p2 in first part of vertex * (i.e. if Qbar is backward, q1 is forward) */ double MH2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); // Unordered f //! Square of qQ->gqQ Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQ->gqQ Scattering * * This returns the square of the current contractions in qQ->gqQ Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qQbar->gqQbar Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQbar->gqQbar Scattering * * This returns the square of the current contractions in qQbar->gqQbar Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarQ->gqbarQ Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQ->gqbarQ Scattering * * This returns the square of the current contractions in qbarQ->gqbarQ Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqbarHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarQbar->gqbarQbar Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQbar->gqbarQbar Scattering * * This returns the square of the current contractions in qbarQbar->gqbarQbar Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqbarHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qg->gqg Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qg->gqg Scattering * * This returns the square of the current contractions in qg->gqg Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarg->gqbarg Higgs+Jets Unordered f Scattering Current /** * @param pg Momentum of unordered gluon * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param p2out Momentum of final state gluon * @param p2in Momentum of intial state gluon * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarg->gbarg Scattering * * This returns the square of the current contractions in qbarg->gqbarg Higgs+Jet Scattering. * * This construction is taking rapidity order: pg > p1out >> p2out */ double jM2unogqbarHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //Unordered b //! Square of qbarQ->qbarQg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQ->qbarQg Scattering * * This returns the square of the current contractions in qbarQ->qbarQg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobqbarHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qQ->qQg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQ->qQg Scattering * * This returns the square of the current contractions in qQ->qQg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobqHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qQbar->qQbarg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state quark * @param p1in Momentum of initial state quark * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qQbar->qQbarg Scattering * * This returns the square of the current contractions in qQbar->qQbarg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobqHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of qbarQbar->qbarQbarg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state anti-quark * @param p1in Momentum of initial state anti-quark * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for qbarQbar->qbarQbarg Scattering * * This returns the square of the current contractions in qbarQbar->qbarQbarg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobqbarHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of gQbar->gQbarg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state gluon * @param p1in Momentum of initial state gluon * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state anti-quark * @param p2in Momentum of intial state anti-quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for gQbar->gQbarg Scattering * * This returns the square of the current contractions in gQbar->gQbarg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobgHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); //! Square of gQ->gQg Higgs+Jets Unordered b Scattering Current /** * @param p1out Momentum of final state gluon * @param p1in Momentum of initial state gluon * @param pg Momentum of unordered b gluon * @param p2out Momentum of final state quark * @param p2in Momentum of intial state quark * @param qH1 Momentum of t-channel propagator before Higgs * @param qH2 Momentum of t-channel propagator after Higgs * @param mt Top quark mass * @param include_bottom Specifies whether bottom corrections are included * @param mb Bottom quark mass * @returns Square of the current contractions for gQ->gQg Scattering * * This returns the square of the current contractions in gQ->gQg Higgs+Jet Scattering. * * This construction is taking rapidity order: p1out >> p2out > pg */ double jM2unobgHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool include_bottom, double mb); // impact factors for Higgs + jet //! Implements Eq. (4.22) in hep-ph/0301013 with modifications to incoming plus momenta /** * @param p2 Momentum of Particle 2 * @param p1 Momentum of Particle 1 * @param pH Momentum of Higgs * @returns Value of Eq. (4.22) in Hep-ph/0301013 with modifications * * This gives the impact factor. First it determines first whether this is the case * p1p\sim php>>p3p or the opposite */ double C2gHgm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH); //! Implements Eq. (4.23) in hep-ph/0301013 with modifications to incoming plus momenta /** * @param p2 Momentum of Particle 2 * @param p1 Momentum of Particle 1 * @param pH Momentum of Higgs * @returns Value of Eq. (4.23) in Hep-ph/0301013 * * This gives the impact factor. First it determines first whether this is the case * p1p\sim php>>p3p or the opposite */ double C2gHgp(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH); //! Implements Eq. (4.22) in hep-ph/0301013 /** * @param p2 Momentum of Particle 2 * @param p1 Momentum of Particle 1 * @param pH Momentum of Higgs * @returns Value of Eq. (4.22) in Hep-ph/0301013 * * This gives the impact factor. First it determines first whether this is the case * p1p\sim php>>p3p or the opposite */ double C2qHqm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH); /** \class CCurrent currents.hh "include/HEJ/currents.hh" * \brief This is the a new class structure for currents. */ class CCurrent { public: CCurrent(COM sc0, COM sc1, COM sc2, COM sc3) :c0(sc0),c1(sc1),c2(sc2),c3(sc3) {}; CCurrent(const CLHEP::HepLorentzVector p) { c0=p.e(); c1=p.px(); c2=p.py(); c3=p.pz(); }; CCurrent() {}; CCurrent operator+(const CCurrent& other); CCurrent operator-(const CCurrent& other); CCurrent operator*(const double x); CCurrent operator*(const COM x); CCurrent operator/(const double x); CCurrent operator/(const COM x); friend std::ostream& operator<<(std::ostream& os, const CCurrent& cur); COM dot(CLHEP::HepLorentzVector p1); COM dot(CCurrent p1); COM c0,c1,c2,c3; private: }; /* std::ostream& operator <<(std::ostream& os, const CCurrent& cur); */ CCurrent operator * ( double x, CCurrent& m); CCurrent operator * ( COM x, CCurrent& m); CCurrent operator / ( double x, CCurrent& m); CCurrent operator / ( COM x, CCurrent& m); //! Current <outgoing state | mu | incoming state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ //! @TODO remove [[deprecated("Use joi instead")]] void j (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin,current &cur); //! Current <incoming state | mu | outgoing state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur); //! Current <outgoing state | mu | outgoing state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ void joo(HLV pi, bool heli, HLV pj, bool helj, current &cur); //! Current <outgoing state | mu | incoming state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ void joi(HLV pout, bool helout, HLV pin, bool helin, current &cur); //! Current <outgoing state | mu | incoming state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ //! @TODO remove [[deprecated("Use joi instead")]] CCurrent j (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin); //! Current <outgoing state | mu | incoming state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ CCurrent joi (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin); //! Current <incoming state | mu | outgoing state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ CCurrent jio (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin); //! Current <outgoing state | mu | outgoing state> /** * These functions are a mess. There are many more defined in the source file than declared in the * header - and the arguments are mislabelled in some cases. Need to investigate. */ CCurrent joo (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin); inline COM cdot(const current & j1, const current & j2) { return j1[0]*j2[0]-j1[1]*j2[1]-j1[2]*j2[2]-j1[3]*j2[3]; } inline COM cdot(const HLV & p, const current & j1) { return j1[0]*p.e()-j1[1]*p.x()-j1[2]*p.y()-j1[3]*p.z(); } inline void cmult(const COM & factor, const current & j1, current &cur) { cur[0]=factor*j1[0]; cur[1]=factor*j1[1]; cur[2]=factor*j1[2]; cur[3]=factor*j1[3]; } // WHY!?! inline void cadd(const current & j1, const current & j2, const current & j3, const current & j4, const current & j5, current &sum) { sum[0]=j1[0]+j2[0]+j3[0]+j4[0]+j5[0]; sum[1]=j1[1]+j2[1]+j3[1]+j4[1]+j5[1]; sum[2]=j1[2]+j2[2]+j3[2]+j4[2]+j5[2]; sum[3]=j1[3]+j2[3]+j3[3]+j4[3]+j5[3]; } inline void cadd(const current & j1, const current & j2, const current & j3, const current & j4, current &sum) { sum[0] = j1[0] + j2[0] + j3[0] + j4[0]; sum[1] = j1[1] + j2[1] + j3[1] + j4[1]; sum[2] = j1[2] + j2[2] + j3[2] + j4[2]; sum[3] = j1[3] + j2[3] + j3[3] + j4[3]; } inline void cadd(const current & j1, const current & j2, const current & j3, current &sum) { sum[0]=j1[0]+j2[0]+j3[0]; sum[1]=j1[1]+j2[1]+j3[1]; sum[2]=j1[2]+j2[2]+j3[2]; sum[3]=j1[3]+j2[3]+j3[3]; } inline void cadd(const current & j1, const current & j2, current &sum) { sum[0]=j1[0]+j2[0]; sum[1]=j1[1]+j2[1]; sum[2]=j1[2]+j2[2]; sum[3]=j1[3]+j2[3]; } inline double abs2(const COM & a) { return (a*conj(a)).real(); } inline double vabs2(const CCurrent & cur) { return abs2(cur.c0)-abs2(cur.c1)-abs2(cur.c2)-abs2(cur.c3); } inline double vre(const CCurrent & a, const CCurrent & b) { return real(a.c0*conj(b.c0)-a.c1*conj(b.c1)-a.c2*conj(b.c2)-a.c3*conj(b.c3)); } // @TODO: These are not currents and should be moved elsewhere. double K_g(double p1minus, double paminus); double K_g(CLHEP::HepLorentzVector const & pout, CLHEP::HepLorentzVector const & pin); diff --git a/include/HEJ/event_types.hh b/include/HEJ/event_types.hh index ac85fd6..783942d 100644 --- a/include/HEJ/event_types.hh +++ b/include/HEJ/event_types.hh @@ -1,82 +1,81 @@ /** \file * \brief Define different types of events. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include "HEJ/utility.hh" namespace HEJ{ //! Namespace for event types namespace event_type{ //! Possible event types enum EventType: size_t{ FKL, /**< FKL-type event */ unordered_backward, /**< event with unordered backward emission */ unordered_forward, /**< event with unordered forward emission */ extremal_qqxb, /**< event with a backward extremal qqbar */ extremal_qqxf, /**< event with a forward extremal qqbar */ central_qqx, /**< event with a central qqbar */ nonHEJ, /**< event configuration not covered by HEJ */ no_2_jets, /**< event with less than two jets */ bad_final_state, /**< event with an unsupported final state */ unob = unordered_backward, unof = unordered_forward, qqxexb = extremal_qqxb, qqxexf = extremal_qqxf, qqxmid = central_qqx, first_type = FKL, last_type = bad_final_state }; //! Event type names /** * For example, names[FKL] is the string "FKL" */ static constexpr auto names = make_array( "FKL", "unordered backward", "unordered forward", "extremal qqbar backward", "extremal qqbar forward", "central qqbar", "nonHEJ", "no 2 jets", "bad final state" ); //! Returns True for a HEJ \ref event_type::EventType "EventType" inline bool is_HEJ(EventType type) { switch(type) { case FKL: case unordered_backward: case unordered_forward: case extremal_qqxb: case extremal_qqxf: case central_qqx: return true; default: return false; } } //! Returns True for an unordered \ref event_type::EventType "EventType" inline bool is_uno(EventType type) { return type == unordered_backward || type == unordered_forward; } inline bool is_qqx(EventType type) { return type == extremal_qqxb || type == extremal_qqxf || type == central_qqx; } } } diff --git a/include/HEJ/exceptions.hh b/include/HEJ/exceptions.hh index 8fdeabf..e5c2514 100644 --- a/include/HEJ/exceptions.hh +++ b/include/HEJ/exceptions.hh @@ -1,57 +1,57 @@ /** \file * \brief Custom exception classes * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <stdexcept> namespace HEJ{ //! Exception indicating wrong option type /** * This exception is thrown if a configuration option has * the wrong type (e.g. 'trials' is not set to a number) */ struct invalid_type: std::invalid_argument { explicit invalid_type(std::string const & what): std::invalid_argument{what} {}; explicit invalid_type(char const * what): std::invalid_argument{what} {}; }; //! Exception indicating unknown option /** * This exception is thrown if an unknown configuration option * is set (e.g. the 'trials' setting is misspelt as 'trails') */ struct unknown_option: std::invalid_argument { explicit unknown_option(std::string const & what): std::invalid_argument{what} {}; explicit unknown_option(char const * what): std::invalid_argument{what} {}; }; //! Exception indicating missing option setting /** * This exception is thrown if a mandatory configuration option * (e.g. 'trials') is not set. */ struct missing_option: std::logic_error { explicit missing_option(std::string const & what): std::logic_error{what} {}; explicit missing_option(char const * what): std::logic_error{what} {}; }; //! Exception indicating functionality that has not been implemented yet struct not_implemented: std::logic_error { explicit not_implemented(std::string const & what): std::logic_error{what} {}; explicit not_implemented(char const * what): std::logic_error{what} {}; }; } diff --git a/include/HEJ/get_analysis.hh b/include/HEJ/get_analysis.hh index 8572f44..11e92ec 100644 --- a/include/HEJ/get_analysis.hh +++ b/include/HEJ/get_analysis.hh @@ -1,32 +1,31 @@ /** \file * \brief Contains the get_analysis function * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include "HEJ/Analysis.hh" namespace YAML{ class Node; } namespace HEJ{ //! Load an analysis /** * @param parameters Analysis parameters * @returns A pointer to an Analysis instance * * If parameters["plugin"] exists, an analysis (deriving from the * \ref Analysis class) will be loaded from the library parameters["plugin"]. * Otherwise, if parameters["rivet"] exists, the corresponding RivetAnalysis * will be loaded. If none of these parameters are specified, a pointer to * the default EmptyAnalysis is returned. */ std::unique_ptr<Analysis> get_analysis(YAML::Node const & parameters); } diff --git a/include/HEJ/kinematics.hh b/include/HEJ/kinematics.hh index 3a2b909..cb8aa9c 100644 --- a/include/HEJ/kinematics.hh +++ b/include/HEJ/kinematics.hh @@ -1,25 +1,25 @@ /** \file * \brief Contains function to compute the incoming momentum from outgoing. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <tuple> #include <vector> namespace fastjet{ class PseudoJet; } namespace HEJ{ class Particle; /** \brief Compute the incoming momentum from momentum conservation. */ std::tuple<fastjet::PseudoJet, fastjet::PseudoJet> incoming_momenta( std::vector<Particle> const & outgoing /**< Outgoing particles */ ); } diff --git a/include/HEJ/make_RNG.hh b/include/HEJ/make_RNG.hh index b6ee632..ec7c026 100644 --- a/include/HEJ/make_RNG.hh +++ b/include/HEJ/make_RNG.hh @@ -1,32 +1,32 @@ /** \file * \brief Declares a factory function for random number generators * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <memory> #include <string> #include "HEJ/optional.hh" #include "HEJ/RNG.hh" namespace HEJ { //! Factory function for random number generators /** * @param name Name of the random number generator * @param seed Optional seed * @returns A pointer to an instance of a random number generator * * At present, name should be one of "ranlux64" or "mixmax" (case insensitive). * The interpretation of the seed depends on the random number generator. * For ranlux64, it is the name of a seed file. For mixmax it should be a * string convertible to a long integer. */ std::unique_ptr<HEJ::RNG> make_RNG( std::string const & name, optional<std::string> const & seed ); } diff --git a/include/HEJ/make_writer.hh b/include/HEJ/make_writer.hh index 71a7de5..3511f5a 100644 --- a/include/HEJ/make_writer.hh +++ b/include/HEJ/make_writer.hh @@ -1,37 +1,36 @@ /** \file * \brief Declares a factory function for event writers * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include <string> #include "HEJ/EventWriter.hh" #include "HEJ/output_formats.hh" namespace LHEF{ struct HEPRUP; } namespace HEJ{ //! Factory function for event writers /** * @param format The format of the output file * @param outfile The name of the output file * @param heprup General process information * @returns A pointer to an instance of an EventWriter * for the desired format */ std::unique_ptr<EventWriter> make_format_writer( FileFormat format, std::string const & outfile, LHEF::HEPRUP const & heprup ); } diff --git a/include/HEJ/optional.hh b/include/HEJ/optional.hh index 32be64e..619cf7f 100644 --- a/include/HEJ/optional.hh +++ b/include/HEJ/optional.hh @@ -1,28 +1,28 @@ /** \file * \brief Defines the optional type * * The C++14 standard introduces the std::optional type. * If C++14 is not available, we use the optional type from boost instead. * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #if __cplusplus <= 201402L #include <boost/optional.hpp> #else #include <optional> #endif namespace HEJ{ #if __cplusplus <= 201402L template<typename T> using optional = boost::optional<T>; #else template<typename T> using optional = std::optional<T>; #endif } diff --git a/include/HEJ/output_formats.hh b/include/HEJ/output_formats.hh index 5ee6e51..8d5b005 100644 --- a/include/HEJ/output_formats.hh +++ b/include/HEJ/output_formats.hh @@ -1,38 +1,37 @@ /** \file * \brief Defines formats for output to event files * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <stdexcept> #include <string> namespace HEJ{ //! Supported event file formats enum FileFormat{ Les_Houches, /*!< Les Houches Output */ HepMC /*!< HepMC Output */ }; //! Convert a file format to a string inline std::string to_string(FileFormat f){ switch(f){ case Les_Houches: return "Les Houches"; case HepMC: return "HepMC"; default: throw std::logic_error("unhandled file format"); } } //! Output file specification struct OutputFile{ std::string name; /**< Output File Name */ FileFormat format; /**< Output File Format */ }; } diff --git a/include/HEJ/resummation_jet.hh b/include/HEJ/resummation_jet.hh index 409b5a2..f2f8c31 100644 --- a/include/HEJ/resummation_jet.hh +++ b/include/HEJ/resummation_jet.hh @@ -1,43 +1,43 @@ /** \file * \brief Functions to calculate the kinematics of resummation jets, * i.e. resuffling the jet momenta * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #pragma once #include <vector> namespace fastjet{ struct PseudoJet; } namespace HEJ{ /** * \brief Calculate the resummation jet momenta * @param p_born born Jet Momenta * @param qperp Sum of non-jet Parton Transverse Momenta * @returns Resummation Jet Momenta */ std::vector<fastjet::PseudoJet> resummation_jet_momenta( std::vector<fastjet::PseudoJet> const & p_born, fastjet::PseudoJet const & qperp ); /** * \brief Calculate additional weight from changing the jet momenta * @param p_born born Jet Momenta * @param qperp Sum of non-jet Parton Transverse Momenta * * Computes the Jacobian for changing the original delta functions * expressed in terms of jet momenta to delta functions of the * parton momenta in the resummation phase space */ double resummation_jet_weight( std::vector<fastjet::PseudoJet> const & p_born, fastjet::PseudoJet const & qperp ); } diff --git a/include/HEJ/stream.hh b/include/HEJ/stream.hh index 55ab077..e8aa707 100644 --- a/include/HEJ/stream.hh +++ b/include/HEJ/stream.hh @@ -1,39 +1,38 @@ /** \file * \brief Declares input streams * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <fstream> #include <memory> #include <string> #include <boost/iostreams/filtering_stream.hpp> namespace HEJ{ //! Small wrapper around boost's filtering_istream class istream { using boost_istream = boost::iostreams::filtering_istream; public: //! Constructor /** * @param filename Name of input file */ explicit istream(std::string const & filename); //! Conversion to boost_istream operator boost_istream& () const noexcept { return *stream_; } private: std::ifstream file_; std::unique_ptr<boost_istream> stream_; }; } diff --git a/include/HEJ/utility.hh b/include/HEJ/utility.hh index 9d2d53e..c8583ca 100644 --- a/include/HEJ/utility.hh +++ b/include/HEJ/utility.hh @@ -1,104 +1,103 @@ /** * \file * \brief Contains various utilities * - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #pragma once #include <memory> #include <boost/core/demangle.hpp> #include "fastjet/PseudoJet.hh" namespace HEJ{ //! Create a std::unique_ptr to a T object /** * For non-array types this works like std::make_unique, * which is not available under C++11 */ template<class T, class... Args> std::unique_ptr<T> make_unique(Args&&... a){ return std::unique_ptr<T>{new T{std::forward<Args>(a)...}}; } //! Create an array containing the passed arguments template<typename T, typename... U> constexpr std::array<T, 1 + sizeof...(U)> make_array(T t, U&&... rest){ return {{t, std::forward<U>(rest)...}}; } inline std::string join( std::string const & /* delim */ ){ return ""; } inline std::string join( std::string const & /* delim */, std::string const & str ){ return str; } //! Join strings with a delimiter /** * @param delim Delimiter to be put between consecutive strings * @param first First string * @param second Second string * @param rest Remaining strings */ template<typename... Strings> std::string join( std::string const & delim, std::string const & first, std::string const & second, Strings&&... rest ){ return join(delim, first + delim + second, std::forward<Strings>(rest)...); } //! Return the name of the argument's type template<typename T> std::string type_string(T&&){ return boost::core::demangle(typeid(T).name()); } //! Eliminate compiler warnings for unused variables template<typename... T> constexpr void ignore(T&&...) {} //! Check whether two doubles are closer than ep > 0 to each other inline bool nearby_ep(double a, double b, double ep){ assert(ep > 0); return std::abs(a-b) < ep; } //! Check whether all components of two PseudoJets are closer than ep to each other inline bool nearby_ep( fastjet::PseudoJet const & pa, fastjet::PseudoJet const & pb, double ep ){ assert(ep > 0); for(size_t i = 0; i < 4; ++i){ if(!nearby_ep(pa[i], pb[i], ep)) return false; } return true; } inline bool nearby( fastjet::PseudoJet const & pa, fastjet::PseudoJet const & pb, double const norm = 1. ){ return nearby_ep(pa, pb, 1e-7*norm); } } diff --git a/src/CombinedEventWriter.cc b/src/CombinedEventWriter.cc index 6ea7623..ff99b96 100644 --- a/src/CombinedEventWriter.cc +++ b/src/CombinedEventWriter.cc @@ -1,28 +1,28 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/CombinedEventWriter.hh" #include "HEJ/make_writer.hh" namespace HEJ{ CombinedEventWriter::CombinedEventWriter( std::vector<OutputFile> const & outfiles, LHEF::HEPRUP const & heprup ){ writers_.reserve(outfiles.size()); for(OutputFile const & outfile: outfiles){ writers_.emplace_back( make_format_writer(outfile.format, outfile.name, heprup) ); } } void CombinedEventWriter::write(Event const & ev){ for(auto & writer: writers_) writer->write(ev); } } diff --git a/src/EmptyAnalysis.cc b/src/EmptyAnalysis.cc index bed8f77..39c4037 100644 --- a/src/EmptyAnalysis.cc +++ b/src/EmptyAnalysis.cc @@ -1,68 +1,68 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/EmptyAnalysis.hh" #include <string> #include <vector> #include "yaml-cpp/yaml.h" #include "HEJ/exceptions.hh" namespace HEJ{ namespace{ std::vector<std::string> param_as_strings(YAML::Node const & parameters){ using YAML::NodeType; switch(parameters.Type()){ case NodeType::Null: case NodeType::Undefined: return {}; case NodeType::Scalar: return {parameters.as<std::string>()}; case NodeType::Sequence: { std::vector<std::string> param_strings; for(auto && param: parameters){ param_strings.emplace_back(param.as<std::string>()); } return param_strings; } case NodeType::Map: { std::vector<std::string> param_strings; for(auto && param: parameters){ param_strings.emplace_back(param.first.as<std::string>()); } return param_strings; } default:; } throw std::logic_error{"unreachable"}; } } std::unique_ptr<Analysis> EmptyAnalysis::create( YAML::Node const & parameters ){ const auto param_strings = param_as_strings(parameters); if(! param_strings.empty()){ std::string error{"Unknown analysis parameter(s):"}; for(auto && p: param_strings) error += " " + p; throw unknown_option{error}; } return std::unique_ptr<Analysis>{new EmptyAnalysis{}}; } void EmptyAnalysis::fill(Event const &, Event const &){ // do nothing } bool EmptyAnalysis::pass_cuts(Event const &, Event const &){ return true; } void EmptyAnalysis::finalise(){ // do nothing } } diff --git a/src/EventReader.cc b/src/EventReader.cc index 0067f31..ae4fc9b 100644 --- a/src/EventReader.cc +++ b/src/EventReader.cc @@ -1,19 +1,24 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/EventReader.hh" #include "HEJ/HDF5Reader.hh" #include "HEJ/LesHouchesReader.hh" #include "HEJ/utility.hh" namespace HEJ { std::unique_ptr<EventReader> make_reader(std::string const & filename) { try { return std::make_unique<LesHouchesReader>(filename); } catch(std::runtime_error&) { #if HEJ_BUILD_WITH_HDF5 return std::make_unique<HDF5Reader>(filename); #else throw; #endif } } } diff --git a/src/EventReweighter.cc b/src/EventReweighter.cc index 411bf0c..261807b 100644 --- a/src/EventReweighter.cc +++ b/src/EventReweighter.cc @@ -1,258 +1,275 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/EventReweighter.hh" #include <algorithm> #include <assert.h> #include <limits> #include <math.h> #include <stddef.h> #include <string> #include <unordered_map> #include "fastjet/ClusterSequence.hh" #include "LHEF/LHEF.h" #include "HEJ/Event.hh" #include "HEJ/exceptions.hh" #include "HEJ/Particle.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/PhaseSpacePoint.hh" namespace HEJ{ using EventType = event_type::EventType; namespace { static_assert( std::numeric_limits<double>::has_quiet_NaN, "no quiet NaN for double" ); constexpr double NaN = std::numeric_limits<double>::quiet_NaN(); Event::EventData to_EventData(PhaseSpacePoint const & psp){ Event::EventData result; result.incoming=psp.incoming(); assert(result.incoming.size() == 2); result.outgoing=psp.outgoing(); // technically Event::EventData doesn't have to be sorted, // but PhaseSpacePoint should be anyway assert( std::is_sorted( begin(result.outgoing), end(result.outgoing), rapidity_less{} ) ); assert(result.outgoing.size() >= 2); result.decays = psp.decays(); result.parameters.central = {NaN, NaN, psp.weight()}; return result; } } // namespace anonymous EventReweighter::EventReweighter( LHEF::HEPRUP const & heprup, ScaleGenerator scale_gen, EventReweighterConfig conf, HEJ::RNG & ran ): EventReweighter{ HEJ::Beam{ heprup.EBMUP.first, {{ static_cast<HEJ::ParticleID>(heprup.IDBMUP.first), static_cast<HEJ::ParticleID>(heprup.IDBMUP.second) }} }, heprup.PDFSUP.first, std::move(scale_gen), std::move(conf), ran } { if(heprup.EBMUP.second != E_beam_){ throw std::invalid_argument( "asymmetric beam: " + std::to_string(E_beam_) + " ---> <--- " + std::to_string(heprup.EBMUP.second) ); }; if(heprup.PDFSUP.second != pdf_.id()){ throw std::invalid_argument( "conflicting PDF ids: " + std::to_string(pdf_.id()) + " vs. " + std::to_string(heprup.PDFSUP.second) ); } } EventReweighter::EventReweighter( Beam beam, int pdf_id, ScaleGenerator scale_gen, EventReweighterConfig conf, HEJ::RNG & ran ): param_{std::move(conf)}, E_beam_{beam.E}, pdf_{pdf_id, beam.type.front(), beam.type.back()}, MEt2_{ [this](double mu){ return pdf_.Halphas(mu); }, param_.ME_config }, scale_gen_(std::move(scale_gen)), ran_{ran} {} PDF const & EventReweighter::pdf() const{ return pdf_; } std::vector<Event> EventReweighter::reweight( Event const & input_ev, int num_events ){ auto res_events = gen_res_events(input_ev, num_events); if(res_events.empty()) return {}; for(auto & event: res_events) event = scale_gen_(event); return rescale(input_ev, std::move(res_events)); } std::vector<Event> EventReweighter::gen_res_events( Event const & ev, int phase_space_points ){ assert(ev.variations().empty()); + status_.clear(); switch(param_.treat.at(ev.type())){ - case EventTreatment::discard: return {}; + case EventTreatment::discard: { + status_.emplace_back(StatusCode::discard); + return {}; + } case EventTreatment::keep: - if(! jets_pass_resummation_cuts(ev)) return {}; - else return {ev}; + if(! jets_pass_resummation_cuts(ev)) { + status_.emplace_back(StatusCode::failed_resummation_cuts); + return {}; + } + else { + status_.emplace_back(StatusCode::good); + return {ev}; + } default:; } const double Born_shat = shat(ev); std::vector<Event> resummation_events; + status_.reserve(phase_space_points); for(int psp_number = 0; psp_number < phase_space_points; ++psp_number){ PhaseSpacePoint psp{ev, param_.psp_config, ran_}; - if(psp.weight() == 0.) continue; - if(psp.incoming()[0].E() > E_beam_ || psp.incoming()[1].E() > E_beam_) continue; + status_.emplace_back(psp.status()); + assert(psp.status() != StatusCode::unspecified); + if(psp.status() != StatusCode::good) continue; + assert(psp.weight() != 0.); + if(psp.incoming()[0].E() > E_beam_ || psp.incoming()[1].E() > E_beam_) { + status_.back() = StatusCode::too_much_energy; + continue; + } resummation_events.emplace_back( to_EventData( std::move(psp) ).cluster( param_.jet_param.def, param_.jet_param.min_pt ) ); auto & new_event = resummation_events.back(); if( new_event.type() != ev.type() ) throw std::logic_error{"Resummation Event does not match Born event"}; new_event.generate_colours(ran_); assert(new_event.variations().empty()); new_event.central().mur = ev.central().mur; new_event.central().muf = ev.central().muf; const double resum_shat = shat(new_event); new_event.central().weight *= ev.central().weight*Born_shat*Born_shat/ (phase_space_points*resum_shat*resum_shat); } return resummation_events; } std::vector<Event> EventReweighter::rescale( Event const & Born_ev, std::vector<Event> events ) const{ const double Born_pdf = pdf_factors(Born_ev).central; const double Born_ME = tree_matrix_element(Born_ev); for(auto & cur_event: events){ const auto pdf = pdf_factors(cur_event); assert(pdf.variations.size() == cur_event.variations().size()); const auto ME = matrix_elements(cur_event); assert(ME.variations.size() == cur_event.variations().size()); cur_event.parameters() *= pdf*ME/(Born_pdf*Born_ME); } return events; }; bool EventReweighter::jets_pass_resummation_cuts( Event const & ev ) const{ const auto out_as_PseudoJet = to_PseudoJet(filter_partons(ev.outgoing())); fastjet::ClusterSequence cs{out_as_PseudoJet, param_.jet_param.def}; return cs.inclusive_jets(param_.jet_param.min_pt).size() == ev.jets().size(); } Weights EventReweighter::pdf_factors(Event const & ev) const{ auto const & a = ev.incoming().front(); auto const & b = ev.incoming().back(); const double xa = a.p.e()/E_beam_; const double xb = b.p.e()/E_beam_; Weights result; std::unordered_map<double, double> known_pdf; result.central = pdf_.pdfpt(0,xa,ev.central().muf,a.type)* pdf_.pdfpt(1,xb,ev.central().muf,b.type); known_pdf.emplace(ev.central().muf, result.central); result.variations.reserve(ev.variations().size()); for(auto const & ev_param: ev.variations()){ const double muf = ev_param.muf; auto cur_pdf = known_pdf.find(muf); if(cur_pdf == known_pdf.end()){ cur_pdf = known_pdf.emplace( muf, pdf_.pdfpt(0,xa,muf,a.type)*pdf_.pdfpt(1,xb,muf,b.type) ).first; } result.variations.emplace_back(cur_pdf->second); } assert(result.variations.size() == ev.variations().size()); return result; } Weights EventReweighter::matrix_elements(Event const & ev) const{ assert(param_.treat.count(ev.type()) > 0); if(param_.treat.find(ev.type())->second == EventTreatment::keep){ return fixed_order_scale_ME(ev); } return MEt2_(ev); } double EventReweighter::tree_matrix_element(Event const & ev) const{ assert(ev.variations().empty()); assert(param_.treat.count(ev.type()) > 0); if(param_.treat.find(ev.type())->second == EventTreatment::keep){ return fixed_order_scale_ME(ev).central; } return MEt2_.tree(ev).central; } Weights EventReweighter::fixed_order_scale_ME(Event const & ev) const{ int alpha_s_power = 0; for(auto const & part: ev.outgoing()){ if(is_parton(part)) ++alpha_s_power; else if(part.type == pid::Higgs) { alpha_s_power += 2; } // nothing to do for other uncoloured particles } Weights result; result.central = pow(pdf_.Halphas(ev.central().mur), alpha_s_power); for(auto const & var: ev.variations()){ result.variations.emplace_back( pow(pdf_.Halphas(var.mur), alpha_s_power) ); } return result; } } // namespace HEJ diff --git a/src/HDF5Reader.cc b/src/HDF5Reader.cc index f359e05..50305f0 100644 --- a/src/HDF5Reader.cc +++ b/src/HDF5Reader.cc @@ -1,293 +1,298 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/HDF5Reader.hh" #ifdef HEJ_BUILD_WITH_HDF5 #include <numeric> #include <iterator> #include "highfive/H5File.hpp" namespace HEJ { namespace { // buffer size for reader // each "reading from disk" reads "chunk_size" many event at once constexpr std::size_t chunk_size = 10000; struct ParticleData { std::vector<int> id; std::vector<int> status; std::vector<int> mother1; std::vector<int> mother2; std::vector<int> color1; std::vector<int> color2; std::vector<double> px; std::vector<double> py; std::vector<double> pz; std::vector<double> e; std::vector<double> m; std::vector<double> lifetime; std::vector<double> spin; }; struct EventRecords { std::vector<int> particle_start; std::vector<int> nparticles; std::vector<int> pid; std::vector<int> weight; std::vector<double> scale; std::vector<double> fscale; std::vector<double> rscale; std::vector<double> aqed; std::vector<double> aqcd; ParticleData particles; }; class ConstEventIterator { public: // iterator traits using iterator_category = std::bidirectional_iterator_tag; using value_type = LHEF::HEPEUP; using difference_type = std::ptrdiff_t; using pointer = const LHEF::HEPEUP*; using reference = LHEF::HEPEUP const &; using iterator = ConstEventIterator; friend iterator cbegin(EventRecords const & records) noexcept; friend iterator cend(EventRecords const & records) noexcept; iterator& operator++() { particle_offset_ += records_.get().nparticles[idx_]; ++idx_; return *this; } iterator& operator--() { --idx_; particle_offset_ -= records_.get().nparticles[idx_]; return *this; } iterator operator--(int) { auto res = *this; --(*this); return res; } bool operator==(iterator const & other) const { return idx_ == other.idx_; } bool operator!=(iterator other) const { return !(*this == other); } value_type operator*() const { value_type hepeup{}; auto const & r = records_.get(); hepeup.NUP = r.nparticles[idx_]; hepeup.IDPRUP = r.pid[idx_]; hepeup.XWGTUP = r.weight[idx_]; hepeup.weights.emplace_back(hepeup.XWGTUP, nullptr); hepeup.SCALUP = r.scale[idx_]; hepeup.scales.muf = r.fscale[idx_]; hepeup.scales.mur = r.rscale[idx_]; hepeup.AQEDUP = r.aqed[idx_]; hepeup.AQCDUP = r.aqcd[idx_]; const size_t start = particle_offset_; const size_t end = start + hepeup.NUP; auto const & p = r.particles; hepeup.IDUP = std::vector<long>( begin(p.id)+start, begin(p.id)+end ); hepeup.ISTUP = std::vector<int>( begin(p.status)+start, begin(p.status)+end ); hepeup.VTIMUP = std::vector<double>( begin(p.lifetime)+start, begin(p.lifetime)+end ); hepeup.SPINUP = std::vector<double>( begin(p.spin)+start, begin(p.spin)+end ); hepeup.MOTHUP.resize(hepeup.NUP); hepeup.ICOLUP.resize(hepeup.NUP); hepeup.PUP.resize(hepeup.NUP); for(size_t i = 0; i < hepeup.MOTHUP.size(); ++i) { const size_t idx = start + i; assert(idx < end); hepeup.MOTHUP[i] = std::make_pair(p.mother1[idx], p.mother2[idx]); hepeup.ICOLUP[i] = std::make_pair(p.color1[idx], p.color2[idx]); hepeup.PUP[i] = std::vector<double>{ p.px[idx], p.py[idx], p.pz[idx], p.e[idx], p.m[idx] }; } return hepeup; } private: explicit ConstEventIterator(EventRecords const & records): records_{records} {} std::reference_wrapper<const EventRecords> records_; size_t idx_ = 0; size_t particle_offset_ = 0; }; // end ConstEventIterator ConstEventIterator cbegin(EventRecords const & records) noexcept { return ConstEventIterator{records}; } ConstEventIterator cend(EventRecords const & records) noexcept { auto it =ConstEventIterator{records}; it.idx_ = records.aqcd.size(); // or size of any other records member return it; } } // end anonymous namespace struct HDF5Reader::HDF5ReaderImpl{ HighFive::File file; std::size_t event_idx; std::size_t particle_idx; std::size_t nevents; EventRecords records; ConstEventIterator cur_event; LHEF::HEPRUP heprup; LHEF::HEPEUP hepeup; explicit HDF5ReaderImpl(std::string const & filename): file{filename}, event_idx{0}, particle_idx{0}, nevents{ file.getGroup("event") .getDataSet("nparticles") // or any other dataset .getSpace().getDimensions().front() }, records{}, cur_event{cbegin(records)}, heprup{}, hepeup{} { read_heprup(); read_event_records(chunk_size); } void read_heprup() { const auto init = file.getGroup("init"); init.getDataSet( "PDFgroupA" ).read(heprup.PDFGUP.first); init.getDataSet( "PDFgroupB" ).read(heprup.PDFGUP.second); init.getDataSet( "PDFsetA" ).read(heprup.PDFSUP.first); init.getDataSet( "PDFsetB" ).read(heprup.PDFSUP.second); init.getDataSet( "beamA" ).read(heprup.IDBMUP.first); init.getDataSet( "beamB" ).read(heprup.IDBMUP.second); init.getDataSet( "energyA" ).read(heprup.EBMUP.first); init.getDataSet( "energyB" ).read(heprup.EBMUP.second); init.getDataSet( "numProcesses" ).read(heprup.NPRUP); init.getDataSet( "weightingStrategy" ).read(heprup.IDWTUP); const auto proc_info = file.getGroup("procInfo"); proc_info.getDataSet( "procId" ).read(heprup.LPRUP); proc_info.getDataSet( "xSection" ).read(heprup.XSECUP); proc_info.getDataSet( "error" ).read(heprup.XERRUP); // TODO: is this identification correct? proc_info.getDataSet( "unitWeight" ).read(heprup.XMAXUP); } std::size_t read_event_records(std::size_t count) { count = std::min(count, nevents-event_idx); auto events = file.getGroup("event"); events.getDataSet("nparticles").select({event_idx}, {count}).read(records.nparticles); assert(records.nparticles.size() == count); events.getDataSet("pid").select( {event_idx}, {count} ).read( records.pid ); events.getDataSet("weight").select( {event_idx}, {count} ).read( records.weight ); events.getDataSet("scale").select( {event_idx}, {count} ).read( records.scale ); events.getDataSet("fscale").select( {event_idx}, {count} ).read( records.fscale ); events.getDataSet("rscale").select( {event_idx}, {count} ).read( records.rscale ); events.getDataSet("aqed").select( {event_idx}, {count} ).read( records.aqed ); events.getDataSet("aqcd").select( {event_idx}, {count} ).read( records.aqcd ); const std::size_t particle_count = std::accumulate( begin(records.nparticles), end(records.nparticles), 0 ); auto pdata = file.getGroup("particle"); auto & particles = records.particles; pdata.getDataSet("id").select( {particle_idx}, {particle_count} ).read( particles.id ); pdata.getDataSet("status").select( {particle_idx}, {particle_count} ).read( particles.status ); pdata.getDataSet("mother1").select( {particle_idx}, {particle_count} ).read( particles.mother1 ); pdata.getDataSet("mother2").select( {particle_idx}, {particle_count} ).read( particles.mother2 ); pdata.getDataSet("color1").select( {particle_idx}, {particle_count} ).read( particles.color1 ); pdata.getDataSet("color2").select( {particle_idx}, {particle_count} ).read( particles.color2 ); pdata.getDataSet("px").select( {particle_idx}, {particle_count} ).read( particles.px ); pdata.getDataSet("py").select( {particle_idx}, {particle_count} ).read( particles.py ); pdata.getDataSet("pz").select( {particle_idx}, {particle_count} ).read( particles.pz ); pdata.getDataSet("e").select( {particle_idx}, {particle_count} ).read( particles.e ); pdata.getDataSet("m").select( {particle_idx}, {particle_count} ).read( particles.m ); pdata.getDataSet("lifetime").select( {particle_idx}, {particle_count} ).read( particles.lifetime ); pdata.getDataSet("spin").select( {particle_idx}, {particle_count} ).read( particles.spin ); event_idx += count; particle_idx += particle_count; return count; } }; HDF5Reader::HDF5Reader(std::string const & filename): impl_{ new HDF5Reader::HDF5ReaderImpl{filename}, HDF5Reader::HDF5ReaderImplDeleter{} } {} bool HDF5Reader::read_event() { if(impl_->cur_event == cend(impl_->records)) { // end of active chunk, read new events from file const auto events_read = impl_->read_event_records(chunk_size); impl_->cur_event = cbegin(impl_->records); if(events_read == 0) return false; } impl_->hepeup = *impl_->cur_event; ++impl_->cur_event; return true; } namespace { static const std::string nothing = ""; } std::string const & HDF5Reader::header() const { return nothing; } LHEF::HEPRUP const & HDF5Reader::heprup() const { return impl_->heprup; } LHEF::HEPEUP const & HDF5Reader::hepeup() const { return impl_->hepeup; } } #else // no HDF5 support namespace HEJ { class HDF5Reader::HDF5ReaderImpl{}; HDF5Reader::HDF5Reader(std::string const &){ throw std::invalid_argument{ "Failed to create HDF5 reader: " "HEJ 2 was built without HDF5 support" }; } bool HDF5Reader::read_event() { throw std::logic_error{"unreachable"}; } std::string const & HDF5Reader::header() const { throw std::logic_error{"unreachable"}; } LHEF::HEPRUP const & HDF5Reader::heprup() const { throw std::logic_error{"unreachable"}; } LHEF::HEPEUP const & HDF5Reader::hepeup() const { throw std::logic_error{"unreachable"}; } } #endif namespace HEJ { void HDF5Reader::HDF5ReaderImplDeleter::operator()(HDF5ReaderImpl* p) { delete p; } } diff --git a/src/HepMCInterface.cc b/src/HepMCInterface.cc index f83ece6..a7a1c19 100644 --- a/src/HepMCInterface.cc +++ b/src/HepMCInterface.cc @@ -1,177 +1,177 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/HepMCInterface.hh" #include "HEJ/exceptions.hh" #ifdef HEJ_BUILD_WITH_HepMC_VERSION #include <math.h> #include <utility> #include "HEJ/Event.hh" #include "HEJ/Particle.hh" #include "HepMC/GenCrossSection.h" #include "HepMC/GenEvent.h" #include "HepMC/GenParticle.h" #include "HepMC/GenVertex.h" namespace HEJ{ namespace { HepMC::FourVector to_FourVector(Particle const & sp){ return {sp.px(), sp.py(), sp.pz(), sp.E()}; } constexpr int status_in = 11; constexpr int status_decayed = 2; constexpr int status_out = 1; template<class HepMCClass, typename... Args> auto make_ptr(Args&&... args){ #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 return HepMC::make_shared<HepMCClass>(std::forward<Args>(args)...); #else return new HepMCClass(std::forward<Args>(args)...); #endif } } // namespace anonymous HepMCInterface::HepMCInterface(): event_count_(0.), tot_weight_(0.), tot_weight2_(0.) {} HepMC::GenCrossSection HepMCInterface::cross_section() const { HepMC::GenCrossSection xs; #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 xs.set_cross_section(tot_weight_, sqrt(tot_weight2_), event_count_); /// @TODO add number of attempted events #else // HepMC 2 xs.set_cross_section(tot_weight_, sqrt(tot_weight2_)); #endif return xs; } HepMC::GenEvent HepMCInterface::init_kinematics(Event const & event) { HepMC::GenEvent out_ev{HepMC::Units::GEV, HepMC::Units::MM}; auto vx = make_ptr<HepMC::GenVertex>(); for(auto const & in: event.incoming()){ vx->add_particle_in( make_ptr<HepMC::GenParticle>( to_FourVector(in), static_cast<int>(in.type), status_in ) ); } for(size_t i=0; i < event.outgoing().size(); ++i){ auto const & out = event.outgoing()[i]; auto particle = make_ptr<HepMC::GenParticle>( to_FourVector(out), static_cast<int>(out.type), status_out ); const int status = event.decays().count(i)?status_decayed:status_out; particle->set_status(status); if( status == status_decayed){ auto vx_decay = make_ptr<HepMC::GenVertex>(); vx_decay->add_particle_in(particle); for( auto const & out: event.decays().at(i)){ vx_decay->add_particle_out( make_ptr<HepMC::GenParticle>( to_FourVector(out), static_cast<int>(out.type), status_out ) ); } out_ev.add_vertex(vx_decay); } vx->add_particle_out(particle); } out_ev.add_vertex(vx); return out_ev; } void HepMCInterface::set_central(HepMC::GenEvent & out_ev, Event const & event, ssize_t const weight_index ) { EventParameters event_param; if(weight_index < 0) event_param = event.central(); else if ( (size_t) weight_index < event.variations().size()) event_param = event.variations(weight_index); else throw std::invalid_argument{ "HepMCInterface tried to access a weight outside of the variation range." }; const double wt = event_param.weight; tot_weight_ += wt; tot_weight2_ += wt * wt; if(out_ev.weights().size() == 0){ out_ev.weights().push_back(wt); } else { // central always on first out_ev.weights()[0] = wt; } #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 out_ev.set_cross_section( HepMC::make_shared<HepMC::GenCrossSection>(cross_section()) ); #else // HepMC 2 out_ev.set_cross_section( cross_section() ); out_ev.set_signal_process_id(event.type()+1); // "+1": conistent with lhe out_ev.set_event_scale(event_param.mur); #endif ++event_count_; out_ev.set_event_number(event_count_); /// @TODO add alphaQCD (need function) and alphaQED /// @TODO output pdf (currently not avaiable from event alone) } void HepMCInterface::add_variation(HepMC::GenEvent & out_ev, std::vector<EventParameters> const & varis ) { for(auto const & var: varis){ out_ev.weights().push_back(var.weight); } /// @TODO add name list for weights } HepMC::GenEvent HepMCInterface::operator()(Event const & event, ssize_t const weight_index ) { HepMC::GenEvent out_ev(init_kinematics(event)); set_central(out_ev, event, weight_index); add_variation(out_ev, event.variations()); return out_ev; } } #else // no HepMC => empty class namespace HepMC { class GenEvent {}; class GenCrossSection {}; } namespace HEJ{ HepMCInterface::HepMCInterface(){ throw std::invalid_argument( "Failed to create HepMCInterface: " "HEJ 2 was built without HepMC support" ); } HepMC::GenEvent HepMCInterface::operator()(Event const &, ssize_t) {return HepMC::GenEvent();} HepMC::GenEvent HepMCInterface::init_kinematics(Event const &) {return HepMC::GenEvent();} void HepMCInterface::add_variation(HepMC::GenEvent &, std::vector<EventParameters> const &){} void HepMCInterface::set_central(HepMC::GenEvent &, Event const &, ssize_t) {} HepMC::GenCrossSection HepMCInterface::cross_section() const {return HepMC::GenCrossSection();} } #endif diff --git a/src/HepMCWriter.cc b/src/HepMCWriter.cc index e09c538..c23014b 100644 --- a/src/HepMCWriter.cc +++ b/src/HepMCWriter.cc @@ -1,148 +1,148 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/HepMCWriter.hh" #include <cassert> #include "LHEF/LHEF.h" #ifdef HEJ_BUILD_WITH_HepMC_VERSION #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 #include "HepMC/LHEFAttributes.h" #include "HepMC/WriterAscii.h" #include "HEJ/Version.hh" #else #include "HepMC/IO_GenEvent.h" #endif #include <utility> #include "HepMC/GenParticle.h" #include "HepMC/GenVertex.h" #include "HEJ/Event.hh" #include "HEJ/exceptions.hh" #include "HEJ/HepMCInterface.hh" #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 namespace { void reset_weight_info(LHEF::HEPRUP & heprup){ heprup.IDWTUP = 2; // use placeholders for unknown init block values // we can overwrite them after processing all events heprup.XSECUP = {0.}; heprup.XERRUP = {0.}; heprup.XMAXUP = {0.}; } HepMC::shared_ptr<HepMC::GenRunInfo> init_runinfo(LHEF::HEPRUP && heprup){ reset_weight_info(heprup); HepMC::GenRunInfo runinfo; auto hepr = HepMC::make_shared<HepMC::HEPRUPAttribute>(); hepr->heprup = heprup; runinfo.add_attribute(std::string("HEPRUP"), hepr); for (int i = 0, N = hepr->heprup.generators.size(); i < N; ++i ){ HepMC::GenRunInfo::ToolInfo tool; tool.name = hepr->heprup.generators[i].name; tool.version = hepr->heprup.generators[i].version; tool.description = hepr->heprup.generators[i].contents; runinfo.tools().push_back(tool); } return HepMC::make_shared<HepMC::GenRunInfo>(runinfo); } } // namespace anonymous #endif // HepMC 3 namespace HEJ{ struct HepMCWriter::HepMCWriterImpl{ HepMCInterface hepmc_; HepMCWriterImpl & operator=(HepMCWriterImpl const & other) = delete; HepMCWriterImpl(HepMCWriterImpl const & other) = delete; HepMCWriterImpl & operator=(HepMCWriterImpl && other) = delete; HepMCWriterImpl(HepMCWriterImpl && other) = delete; #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 HepMC::WriterAscii writer_; HepMCWriterImpl( std::string const & file, LHEF::HEPRUP && heprup ): hepmc_(), writer_{file, init_runinfo(std::move(heprup))} {} ~HepMCWriterImpl(){ writer_.close(); } #else // HepMC 2 HepMC::IO_GenEvent writer_; HepMCWriterImpl( std::string const & file, LHEF::HEPRUP && ): hepmc_(), writer_{file} {} #endif void write(Event const & ev){ auto out_ev = hepmc_(ev); #if HEJ_BUILD_WITH_HepMC_VERSION >= 3 writer_.write_event(out_ev); #else // HepMC 2 writer_.write_event(&out_ev); #endif } }; void HepMCWriter::HepMCWriterImplDeleter::operator()(HepMCWriterImpl* p) { delete p; } HepMCWriter::HepMCWriter(std::string const & file, LHEF::HEPRUP heprup): impl_{std::unique_ptr<HepMCWriterImpl, HepMCWriterImplDeleter>{ new HepMCWriterImpl(file, std::move(heprup)) }} {} void HepMCWriter::write(Event const & ev){ impl_->write(ev); } } // namespace HEJ #else // no HepMC namespace HEJ{ class HepMCWriter::HepMCWriterImpl{}; HepMCWriter::HepMCWriter(std::string const &, LHEF::HEPRUP){ throw std::invalid_argument( "Failed to create HepMC writer: " "HEJ 2 was built without HepMC support" ); } void HepMCWriter::write(Event const &){ assert(false); } void HepMCWriter::HepMCWriterImplDeleter::operator()(HepMCWriterImpl* p) { delete p; } } #endif diff --git a/src/JetSplitter.cc b/src/JetSplitter.cc index 9d727db..60003ce 100644 --- a/src/JetSplitter.cc +++ b/src/JetSplitter.cc @@ -1,178 +1,178 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/JetSplitter.hh" #include <array> #include <assert.h> #include <numeric> #include "fastjet/ClusterSequence.hh" #include "fastjet/PseudoJet.hh" #include "HEJ/Constants.hh" #include "HEJ/exceptions.hh" namespace HEJ { namespace{ constexpr double ccut=HEJ::CMINPT; // min parton pt template<class Iterator> bool same_pt_and_rapidity( Iterator begin, Iterator end, fastjet::PseudoJet const & jet ){ constexpr double ep = 1e-2; const fastjet::PseudoJet reconstructed_jet = std::accumulate( begin, end, fastjet::PseudoJet{} ); return (std::abs(reconstructed_jet.pt() - jet.pt()) < ep) && (std::abs(reconstructed_jet.rapidity() - jet.rapidity()) < ep) ; } bool all_in_one_jet( std::vector<fastjet::PseudoJet> const & partons, fastjet::JetDefinition jet_def, double min_jet_pt ){ fastjet::ClusterSequence ev(partons, jet_def); const std::vector<fastjet::PseudoJet> testjet = ev.inclusive_jets(min_jet_pt); return testjet.size() == 1u && testjet[0].constituents().size() == partons.size(); } } using SplitResult = JetSplitter::SplitResult; SplitResult JetSplitter::split( fastjet::PseudoJet const & j2split, int ncons ) const{ if(ncons <= 0) { throw std::invalid_argument{ "number of requested jet constituents less than 1" }; } double swt = 1.; std::vector<fastjet::PseudoJet> jcons; if(ncons == 1){ jcons.emplace_back(j2split); jcons.back().set_user_index(0); return {jcons, swt}; } if(ncons == 2){ return Split2(j2split); } const double R_max = R_factor*R_; assert(R_max < M_PI); double pt_remaining = j2split.pt(); const double phi_jet = j2split.phi(); const double y_jet = j2split.rapidity(); for(int i = 0; i < ncons - 1; ++i){ /** * Generate rapidity and azimuthal angle with a distance * R = sqrt(delta_y^2 + delta_phi^2) < R_max * from the jet centre */ const double R = R_max*ran_.get().flat(); const double theta = 2*M_PI*ran_.get().flat(); const double delta_phi = R*cos(theta); const double delta_y = R*sin(theta); /** * Generate pt such that the total contribution of all partons * along the jet pt axis does not exceed the jet pt */ const double pt_max = pt_remaining/cos(delta_phi); assert(pt_max > 0); if(pt_max < ccut) return {}; // no pt remaining for this parton const double pt = (pt_max - ccut)*ran_.get().flat() + ccut; pt_remaining -= pt*cos(delta_phi); jcons.emplace_back( pt*cos(phi_jet + delta_phi), pt*sin(phi_jet + delta_phi), pt*sinh(y_jet + delta_y), pt*cosh(y_jet + delta_y) ); jcons.back().set_user_index(i); swt *= 2*M_PI*R*R_max*pt*(pt_max - ccut); } const fastjet::PseudoJet p_total = std::accumulate( jcons.begin(), jcons.end(), fastjet::PseudoJet{} ); // Calculate the pt of the last parton const double last_px = j2split.px() - p_total.px(); const double last_py = j2split.py() - p_total.py(); const double last_pt = sqrt(last_px*last_px + last_py*last_py); if(last_pt < ccut) return {}; // Calculate the rapidity of the last parton using the requirement that the // new jet must have the same rapidity as the LO jet. const double exp_2y_jet = (j2split.e() + j2split.pz())/(j2split.e() - j2split.pz()); const double bb = (p_total.e()+p_total.pz()) - exp_2y_jet*(p_total.e()-p_total.pz()); const double lasty = log((-bb+sqrt(bb*bb+4.*exp_2y_jet*last_pt*last_pt))/(2.*last_pt)); jcons.emplace_back( last_px, last_py, last_pt*sinh(lasty), last_pt*cosh(lasty) ); jcons.back().set_user_index(ncons-1); assert(same_pt_and_rapidity(begin(jcons), end(jcons), j2split)); // Test that the last parton is not too far away from the jet centre. if (jcons.back().delta_R(j2split) > R_max) return {}; if(! all_in_one_jet(jcons, jet_def_, min_jet_pt_)) return {}; return {jcons, swt}; } double JetSplitter::sample_distance_2p(double & wt) const{ static constexpr double x_small = 0.1; static constexpr double p_small = 0.4; const double pR = ran_.get().flat(); if(pR < p_small){ wt *= x_small/p_small; return x_small/p_small*pR; } wt *= (1-x_small)/(1-p_small); return (1-x_small)/(1-p_small)*(pR-p_small) + x_small; } SplitResult JetSplitter::Split2(fastjet::PseudoJet const & j2split) const{ static constexpr size_t ncons = 2; std::vector<fastjet::PseudoJet> jcons(ncons); std::array<double, ncons> R, phi, y, pt; double wt = 1; const double theta = 2*M_PI*ran_.get().flat(); // angle in y-phi plane // empiric observation: we are always within the jet radius R[0] = sample_distance_2p(wt)*R_; R[1] = -sample_distance_2p(wt)*R_; for(size_t i = 0; i <= 1; ++i){ phi[i] = j2split.phi() + R[i]*cos(theta); y[i] = j2split.rapidity() + R[i]*sin(theta); } for(size_t i = 0; i <= 1; ++i){ pt[i] = (j2split.py() - tan(phi[1-i])*j2split.px())/ (sin(phi[i]) - tan(phi[1-i])*cos(phi[i])); if(pt[i] < ccut) return {}; jcons[i].reset_PtYPhiM(pt[i], y[i], phi[i]); jcons[i].set_user_index(i); } assert(same_pt_and_rapidity(begin(jcons), end(jcons), j2split)); if(! all_in_one_jet(jcons, jet_def_, min_jet_pt_)) return {}; wt *= 2*M_PI*pt[0]*R[0]*R_*R_; // from transformation of delta(R[1] - ...) to delta(pt[0] - ...) const double dphi0 = phi[0] - j2split.phi(); const double ptJ = j2split.pt(); const double jacobian = cos(theta)*pt[1]*pt[1]/(ptJ*sin(dphi0)); return {jcons, jacobian*wt}; } } diff --git a/src/LesHouchesWriter.cc b/src/LesHouchesWriter.cc index e9c40cc..54d3a12 100644 --- a/src/LesHouchesWriter.cc +++ b/src/LesHouchesWriter.cc @@ -1,95 +1,94 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ - #include <cassert> #include <utility> #include <vector> #include "HEJ/Event.hh" #include "HEJ/event_types.hh" #include "HEJ/LesHouchesWriter.hh" #include "HEJ/utility.hh" namespace HEJ{ namespace{ template<class T, class... Args> std::unique_ptr<T> make_unique(Args&&... a){ return std::unique_ptr<T>{new T{std::forward<Args>(a)...}}; } } LesHouchesWriter::LesHouchesWriter( std::string const & file, LHEF::HEPRUP heprup ): out_{file, std::fstream::in | std::fstream::out | std::fstream::trunc}, writer_{HEJ::make_unique<LHEF::Writer>(out_)} { if(! out_.is_open()){ throw std::ios_base::failure("Failed to open " + file); }; writer_->heprup = std::move(heprup); // lhe Stardard: IDWTUP (negative => weights = +/-) // 1: weighted events, xs = mean(weight), XMAXUP given // 2: weighted events, xs = XSECUP, XMAXUP given // 3: unweighted events, no additional information given // 4: unweighted events, xs = mean(weight), no additional information given writer_->heprup.IDWTUP = 2; // use placeholders for unknown init block values // we can overwrite them after processing all events writer_->heprup.XSECUP = std::vector<double>(event_type::last_type+1, 0.); writer_->heprup.XERRUP = std::vector<double>(event_type::last_type+1, 0.); writer_->heprup.XMAXUP = std::vector<double>(event_type::last_type+1, 0.); write_init(); } void LesHouchesWriter::write(Event const & ev){ assert(writer_ && out_.is_open()); const double wt = ev.central().weight; writer_->hepeup = HEJ::to_HEPEUP(std::move(ev), &heprup()); writer_->writeEvent(); heprup().XSECUP[ev.type()] += wt; heprup().XERRUP[ev.type()] += wt*wt; if(wt > heprup().XMAXUP[ev.type()]){ heprup().XMAXUP[ev.type()] = wt; } } // this function is called after overwritting the Les Houches init block // assert that we have overwritten *exactly* the init block, // i.e. we are at the end of the file or an intact event block is next void assert_next_event_intact(std::istream & out){ (void) out; // suppress compiler warnings if not in debug mode #ifndef NDEBUG std::string line; getline(out, line); assert(out.eof() || line == "<event>"); #endif } void LesHouchesWriter::rewrite_init(){ assert(writer_ && out_.is_open()); // replace placeholder entries const auto pos = out_.tellp(); out_.seekp(0); writer_->init(); assert_next_event_intact(out_); out_.seekp(pos); } LesHouchesWriter::~LesHouchesWriter(){ assert(writer_ && out_.is_open()); for(auto & xs_err: heprup().XERRUP) { xs_err = sqrt(xs_err); } rewrite_init(); } } diff --git a/src/MatrixElement.cc b/src/MatrixElement.cc index 2a7cfbe..5686fd1 100644 --- a/src/MatrixElement.cc +++ b/src/MatrixElement.cc @@ -1,1751 +1,1751 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \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/currents.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_HEJ(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_HEJ(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 qav, CLHEP::HepLorentzVector qbv, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector 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 qav, CLHEP::HepLorentzVector qbv, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2, double lambda ) { double kperp=(qav-qbv).perp(); if (kperp>lambda) return C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2()); else { double Cls=(C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2())); return Cls-4./(kperp*kperp); } } //! Lipatov vertex double C2Lipatov(CLHEP::HepLorentzVector qav, CLHEP::HepLorentzVector qbv, CLHEP::HepLorentzVector pim, CLHEP::HepLorentzVector pip, CLHEP::HepLorentzVector pom, CLHEP::HepLorentzVector pop) // B { 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 qav, CLHEP::HepLorentzVector qbv, CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2, double lambda ) { double kperp=(qav-qbv).perp(); if (kperp>lambda) return C2Lipatov(qav, qbv, pa, pb, p1, p2)/(qav.m2()*qbv.m2()); else { 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 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 jM2gg(pn,pb,p1,pa); } else if (aptype==21&&bptype!=21) { if (bptype > 0) return jM2qg(pn,pb,p1,pa); else return jM2qbarg(pn,pb,p1,pa); } else if (bptype==21&&aptype!=21) { // ----- || ----- if (aptype > 0) return jM2qg(p1,pa,pn,pb); else return jM2qbarg(p1,pa,pn,pb); } else { // they are both quark if (bptype>0) { if (aptype>0) return jM2qQ(pn,pb,p1,pa); else return jM2qQbar(pn,pb,p1,pa); } else { if (aptype>0) return jM2qQbar(p1,pa,pn,pb); else return jM2qbarQbar(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 jMWqg(pn,plbar,pl,pb,p1,pa); else return jMWqbarg(pn,plbar,pl,pb,p1,pa); } else if (bptype==21&&aptype!=21) { // ----- || ----- if (aptype > 0) return jMWqg(p1,plbar,pl,pa,pn,pb); else return jMWqbarg(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 jMWqQ(pn,plbar,pl,pb,p1,pa); else return jMWqQbar(pn,plbar,pl,pb,p1,pa); } else { if (aptype>0) return jMWqbarQ(pn,plbar,pl,pb,p1,pa); else return jMWqbarQbar(pn,plbar,pl,pb,p1,pa); } } else{ // emission off a, (first argument paout) if (aptype > 0) { if (bptype > 0) return jMWqQ(p1,plbar,pl,pa,pn,pb); else return jMWqQbar(p1,plbar,pl,pa,pn,pb); } else { // a is anti-quark if (bptype > 0) return jMWqbarQ(p1,plbar,pl,pa,pn,pb); else return jMWqbarQbar(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 jM2Wunogqg(pg,p1,plbar,pl,pa,pn,pb); else return jM2Wunogqbarg(pg,p1,plbar,pl,pa,pn,pb); } else { // they are both quark if (wc==true) {// emission off b, i.e. b is first current if (bptype>0){ if (aptype>0) return junobMWqQg(pn,plbar,pl,pb,p1,pa,pg); else return junobMWqQbarg(pn,plbar,pl,pb,p1,pa,pg); } else{ if (aptype>0) return junobMWqbarQg(pn,plbar,pl,pb,p1,pa,pg); else return junobMWqbarQbarg(pn,plbar,pl,pb,p1,pa,pg); } } else {// wc == false, emission off a, i.e. a is first current if (aptype > 0) { if (bptype > 0) //qq return jM2WunogqQ(pg,p1,plbar,pl,pa,pn,pb); else //qqbar return jM2WunogqQbar(pg,p1,plbar,pl,pa,pn,pb); } else { // a is anti-quark if (bptype > 0) //qbarq return jM2WunogqbarQ(pg,p1,plbar,pl,pa,pn,pb); else //qbarqbar return jM2WunogqbarQbar(pg,p1,plbar,pl,pa,pn,pb); } } } } /** 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 jM2Wunogqg(pg, pn,plbar, pl, pb, p1, pa); else return jM2Wunogqbarg(pg, pn,plbar, pl, pb, p1, pa); } else { // they are both quark if (wc==true) {// emission off b, i.e. b is first current if (bptype>0){ if (aptype>0) return jM2WunogqQ(pg,pn,plbar,pl,pb,p1,pa); else return jM2WunogqQbar(pg,pn,plbar,pl,pb,p1,pa); } else{ if (aptype>0) return jM2WunogqbarQ(pg,pn,plbar,pl,pb,p1,pa); else return jM2WunogqbarQbar(pg,pn,plbar,pl,pb,p1,pa); } } else {// wc == false, emission off a, i.e. a is first current if (aptype > 0) { if (bptype > 0) //qq return junofMWgqQ(pg,pn,pb,p1,plbar,pl,pa); else //qqbar return junofMWgqQbar(pg,pn,pb,p1,plbar,pl,pa); } else { // a is anti-quark if (bptype > 0) //qbarq return junofMWgqbarQ(pg,pn,pb,p1,plbar,pl,pa); else //qbarqbar return junofMWgqbarQbar(pg,pn,pb,p1,plbar,pl,pa); } } } } /** \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 jM2Wggtoqqbarg(pa, pqbar, plbar, pl, pq, pn,pb)*CFbackward;} else { return jM2Wggtoqbarqg(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!=1){ // W Emitted from backwards qqx if (swapQuarkAntiquark){ return jM2WgQtoqqbarQ(pa, pq, plbar, pl, pqbar, pn, pb)*CFbackward;} else{ return jM2WgQtoqbarqQ(pa, pq, plbar, pl, pqbar, pn, pb)*CFbackward;} } else { // W Must be emitted from forwards leg. if(bptype > 0){ if (swapQuarkAntiquark){ return jM2WgqtoQQqW(pb, pa, pn, pqbar, pq, plbar, pl, false)*CFbackward;} else{ return jM2WgqtoQQqW(pb, pa, pn, pq, pqbar, plbar, pl, false)*CFbackward;} } else { if (swapQuarkAntiquark){ return jM2WgqtoQQqW(pb, pa, pn, pqbar, pq, plbar, pl, true)*CFbackward;} else{ return jM2WgqtoQQqW(pb, pa, pn, pq, pqbar, plbar, pl, true)*CFbackward;} } } } else{ 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 jM2Wggtoqqbarg(pb, pqbar, plbar, pl, pq, p1,pa)*CFforward;} else { return jM2Wggtoqbarqg(pb, pq, plbar, pl, pqbar, p1,pa)*CFforward;} } else if (bptype==21&&aptype!=21) {// b gluon => W emission off a or qqx if (wc==1){ // W Emitted from forwards qqx if (swapQuarkAntiquark){ return jM2WgQtoqbarqQ(pb, pq, plbar,pl, pqbar, p1, pa)*CFforward;} else { return jM2WgQtoqqbarQ(pb, pq, plbar,pl, pqbar, p1, pa)*CFforward;} } // W Must be emitted from backwards leg. if (aptype > 0){ if (swapQuarkAntiquark){ return jM2WgqtoQQqW(pa,pb, p1, pqbar, pq, plbar, pl, false)*CFforward;} else{ return jM2WgqtoQQqW(pa,pb, p1, pq, pqbar, plbar, pl, false)*CFforward;} } else { if (swapQuarkAntiquark){ return jM2WgqtoQQqW(pa,pb, p1, pqbar, pq, plbar, pl, true)*CFforward;} else{ return jM2WgqtoQQqW(pa,pb, p1, pq, pqbar, plbar, pl, true)*CFforward;} } } else{ 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> 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 CFforward = (0.5*(3.-1./3.)*(pb.plus()/(partons[partons.size()-1].plus())+(partons[partons.size()-1].plus())/pb.plus())+1./3.)*3./4.; double CFbackward = (0.5*(3.-1./3.)*(pa.minus()/(partons[0].minus())+(partons[0].minus())/pa.minus())+1./3.)*3./4.; double wt=1.; if (aptype==21) wt*=CFbackward; if (bptype==21) wt*=CFforward; if (aptype <=0 && bptype <=0){ // Both External AntiQuark if (wqq==1){//emission from central qqbar return wt*jM2WqqtoqQQq(pa, pb, pl,plbar, partons,true,true, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*jM2WqqtoqQQqW(pa, pb, pl,plbar, partons, true,true, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*jM2WqqtoqQQqW(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*jM2WqqtoqQQq(pa, pb, pl,plbar, partons, false, true, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*jM2WqqtoqQQqW(pa, pb, pl,plbar, partons,false,true, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*jM2WqqtoqQQqW(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*jM2WqqtoqQQq(pa, pb, pl,plbar, partons, true, false, swapQuarkAntiquark, nabove); } else if (wc==1){//emission from b leg return wt*jM2WqqtoqQQqW(pa, pb, pl,plbar, partons, true, false, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*jM2WqqtoqQQqW(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*jM2WqqtoqQQq(pa, pb, pl, plbar, partons, false, false, swapQuarkAntiquark, nabove);} else if (wc==1){//emission from b leg return wt*jM2WqqtoqQQqW(pa, pb, pl,plbar, partons, false, false, swapQuarkAntiquark, nabove, nbelow, true); } else { // emission from a leg return wt*jM2WqqtoqQQqW(pa, pb, pl,plbar, partons, false, false, swapQuarkAntiquark, nabove, nbelow, false); } } } /** \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 MH2gg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else if (aptype==21&&bptype!=21) { if (bptype > 0) return MH2qg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.; else return MH2qbarg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.; } else if (bptype==21&&aptype!=21) { if (aptype > 0) return MH2qg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.; else return MH2qbarg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.; } else { // they are both quark if (bptype>0) { if (aptype>0) return MH2qQ(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.); else return MH2qQbar(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.); } else { if (aptype>0) return MH2qQbar(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4.*4./(9.*9.); else return MH2qbarQbar(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 forward emission * @param aptype Particle A PDG ID * @param bptype Particle B PDG ID * @param punof Unordered Particle Momentum * @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 with Higgs and unordered forward emission */ double ME_Higgs_current_unof( int aptype, int bptype, CLHEP::HepLorentzVector const & punof, 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) { if (bptype > 0) return jM2unogqHg(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unogqbarHg(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); } else { // they are both quark if (bptype>0) { if (aptype>0) return jM2unogqHQ(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unogqHQbar(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); } else { if (aptype>0) return jM2unogqbarHQ(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unogqbarHQbar(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb); } } 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 punob 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 */ double ME_Higgs_current_unob( int aptype, int bptype, CLHEP::HepLorentzVector const & pn, CLHEP::HepLorentzVector const & pb, CLHEP::HepLorentzVector const & punob, 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 jM2unobgHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unobgHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb); } else { // they are both quark if (aptype>0) { if (bptype>0) return jM2unobqHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unobqbarHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb); } else { if (bptype>0) return jM2unobqHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb); else return jM2unobqbarHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,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_HEJ(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; } 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"); } 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]); auto begin_ladder = begin(partons) + 1; auto end_ladder = end(partons) - 1; bool wc = true; auto q0 = pa - p1; if (aptype!=partons[0].type) { //leg a emits w wc = false; 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]); auto begin_ladder = begin(partons) + 2; auto end_ladder = end(partons) - 1; bool wc = true; auto q0 = pa - p1 -pg; if (aptype!=partons[1].type) { //leg a emits w wc = false; 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]); auto begin_ladder = begin(partons) + 1; auto end_ladder = end(partons) - 2; bool wc = true; auto q0 = pa - p1; if (aptype!=partons[0].type) { //leg a emits w wc = false; 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]); auto begin_ladder = begin(partons) + 2; auto end_ladder = end(partons) - 1; bool wc = true; auto q0 = pa - pq - pqbar; if (partons[1].type!=partons[0].type) { //leg a emits w wc = false; 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]); auto begin_ladder = begin(partons) + 1; auto end_ladder = end(partons) - 2; bool wc = true; auto q0 = pa - p1; if (aptype!=partons[0].type) { //leg a emits w wc = false; 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; } auto begin_ladder = begin(partons) + 1; auto end_ladder_1 = (backmidquark); auto begin_ladder_2 = (backmidquark+2); auto end_ladder = end(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 currents.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 p1out, CLHEP::HepLorentzVector p1in, ParticleID type2, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector 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*MH2gq_outsideH( 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 ); } 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 = C_A*C_A/2.*ME_Higgs_current_unob( // 1/2 = "K_uno" incoming[0].type, incoming[1].type, pn, pb, to_HepLorentzVector(partons.front()), p1, pa, 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 = C_A*C_A/2.*ME_Higgs_current_unof( // 1/2 = "K_uno" incoming[0].type, incoming[1].type, to_HepLorentzVector(partons.back()), pn, pb, p1, pa, qH, qH - pH, 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; } double MatrixElement::tree_param_partons( double alpha_s, double mur, std::vector<Particle> const & partons ) const{ const double gs2 = 4.*M_PI*alpha_s; double wt = std::pow(gs2, partons.size()); if(param_.log_correction){ // use alpha_s(q_perp), evolved to mur assert(partons.size() >= 2); for(size_t i = 1; i < partons.size()-1; ++i){ wt *= 1. + alpha_s/(2.*M_PI)*beta0*log(mur/partons[i].p.perp()); } } return wt; } 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_HEJ(ev.type())); const auto & out = ev.outgoing(); const double alpha_s = alpha_s_(mur); const double AWZH_coupling = get_AWZH_coupling(ev, alpha_s); if(ev.type() == event_type::unob || ev.type() == event_type::qqxexb){ return AWZH_coupling*4.*M_PI*alpha_s*tree_param_partons( alpha_s, mur, filter_partons({begin(out) + 1, end(out)}) ); } if(ev.type() == event_type::unof || ev.type() == event_type::qqxexf){ return AWZH_coupling*4.*M_PI*alpha_s*tree_param_partons( alpha_s, mur, filter_partons({begin(out), end(out) - 1}) ); } return AWZH_coupling*tree_param_partons(alpha_s, mur, filter_partons(out)); } } // namespace HEJ diff --git a/src/PDF.cc b/src/PDF.cc index 3a82e18..0792a99 100644 --- a/src/PDF.cc +++ b/src/PDF.cc @@ -1,112 +1,112 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/PDF.hh" #include <iostream> #include <stdexcept> #include <string> namespace HEJ{ namespace{ int to_beam(ParticleID id){ if(std::abs(id) == pid::proton){ return (id > 0)?1:-1; } throw std::invalid_argument( "unknown beam type: " + std::to_string(id) ); } } #if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 PDF::PDF(int id, ParticleID beam1, ParticleID beam2): pdf{LHAPDF::mkPDF(id)}, beamtype{{to_beam(beam1), to_beam(beam2)}} {} double PDF::pdfpt(size_t beam_idx, double x, double q, ParticleID id) const{ if(!(inRangeQ(q) && inRangeX(x))) return 0.; if(id == pid::gluon){ return pdf->xfxQ(21,x,q); } else if(abs(id) < 7){ return pdf->xfxQ(id*beamtype[beam_idx],x,q); } else { std::cerr << "particle type unknown: "<< id << std::endl; return 0.0; } } double PDF::Halphas(double q) const{ double as = pdf->alphasQ(q); if (std::isnan(as) || as > 0.5) { as = 0.5; } return as; } int PDF::id() const{ return pdf->lhapdfID(); }; bool PDF::inRangeQ(double q) const{ return pdf->inRangeQ(q); } bool PDF::inRangeX(double x) const{ return pdf->inRangeX(x); } #else /* LHAPDF version unknown or older than 6 */ PDF::PDF(std::string LHAPDFName, int LHAPDFsubset, ParticleID beam1, ParticleID beam2): beamtype{{to_beam(beam1_type), to_beam(beam2_type)}} { LHAPDF::initPDFSet(LHAPDFName, LHAPDF::LHGRID, LHAPDFsubset); } double PDF::pdfpt(size_t beam_idx, double x, double q, ParticleID id) const{ if(!(inRangeQ(q) && inRangeX(x))) return 0.; if (id == pid::gluon){ return LHAPDF::xfx(x,q,0); } else if (abs(id) < 7){ return LHAPDF::xfx(x,q,id*beamtype[beam_idx]); } else { std::cerr << "particle type unknown: "<< id <<std::endl; return 0.0; } } double PDF::Halphas(double q) const{ double as = LHAPDF::alphasPDF(q); if (isnan(as) || as > 0.5) as = 0.5; return as; } bool PDF::inRangeQ(double q) const{ // here we assume that all members actually have the same range! static constexpr int member = 0; return (LHAPDF::getQ2min(member) < q*q) && (q*q < LHAPDF::getQ2max(member)); } bool PDF::inRangeX(double x) const{ // here we assume that all members actually have the same range! static constexpr int member = 0; return (LHAPDF::getXmin(member) < x) && (x < LHAPDF::getXmax(member)); } #endif } diff --git a/src/PDG_codes.cc b/src/PDG_codes.cc index 2d1b02e..c4a8aff 100644 --- a/src/PDG_codes.cc +++ b/src/PDG_codes.cc @@ -1,93 +1,93 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/PDG_codes.hh" #include <map> #include "HEJ/exceptions.hh" namespace HEJ{ ParticleID to_ParticleID(std::string const & name){ using namespace HEJ::pid; static const std::map<std::string, ParticleID> known = { {"d", d}, {"down", down}, {"1",static_cast<ParticleID>(1)}, {"u", u}, {"up", up}, {"2",static_cast<ParticleID>(2)}, {"s", s}, {"strange", strange}, {"3",static_cast<ParticleID>(3)}, {"c", c}, {"charm", charm}, {"4",static_cast<ParticleID>(4)}, {"b", b}, {"bottom", bottom}, {"5",static_cast<ParticleID>(5)}, {"t", t}, {"top", top}, {"6",static_cast<ParticleID>(6)}, {"e", e}, {"electron", electron}, {"e-", e}, {"11",static_cast<ParticleID>(11)}, {"nu_e", nu_e}, {"electron_neutrino", electron_neutrino}, {"12",static_cast<ParticleID>(12)}, {"mu", mu}, {"muon", muon}, {"mu-", mu}, {"13",static_cast<ParticleID>(13)}, {"nu_mu", nu_mu}, {"muon_neutrino", muon_neutrino}, {"14",static_cast<ParticleID>(14)}, {"tau", tau}, {"tau-", tau}, {"15",static_cast<ParticleID>(15)}, {"nu_tau", nu_tau}, {"tau_neutrino", tau_neutrino}, {"16",static_cast<ParticleID>(16)}, {"d_bar", d_bar}, {"antidown", antidown}, {"-1",static_cast<ParticleID>(-1)}, {"u_bar", u_bar}, {"antiup", antiup}, {"-2",static_cast<ParticleID>(-2)}, {"s_bar", s_bar}, {"antistrange", antistrange}, {"-3",static_cast<ParticleID>(-3)}, {"c_bar", c_bar}, {"anticharm", anticharm}, {"-4",static_cast<ParticleID>(-4)}, {"b_bar", b_bar}, {"antibottom", antibottom}, {"-5",static_cast<ParticleID>(-5)}, {"t_bar", t_bar}, {"antitop", antitop}, {"-6",static_cast<ParticleID>(-6)}, {"e_bar", e_bar}, {"antielectron", antielectron}, {"positron", positron}, {"e+", e_bar}, {"-11",static_cast<ParticleID>(-11)}, {"nu_e_bar", nu_e_bar}, {"electron-antineutrino", electron_antineutrino}, {"-12",static_cast<ParticleID>(-12)}, {"mu_bar", mu_bar}, {"mu+", mu_bar}, {"antimuon", antimuon}, {"-13",static_cast<ParticleID>(-13)}, {"nu_mu_bar", nu_mu_bar}, {"muon-antineutrino", muon_antineutrino}, {"-14",static_cast<ParticleID>(-14)}, {"tau_bar", tau_bar}, {"tau+", tau_bar}, {"antitau", antitau}, {"-15",static_cast<ParticleID>(-15)}, {"nu_tau_bar", nu_tau_bar}, {"tau-antineutrino", tau_antineutrino}, {"-16",static_cast<ParticleID>(-16)}, {"gluon", gluon}, {"g", g}, {"21",static_cast<ParticleID>(21)}, {"photon", photon}, {"gamma", gamma}, {"22",static_cast<ParticleID>(22)}, {"Z", Z}, {"23",static_cast<ParticleID>(23)}, {"Wp", Wp}, {"W+", Wp}, {"24",static_cast<ParticleID>(24)}, {"Wm", Wm}, {"W-", Wm}, {"-24",static_cast<ParticleID>(-24)}, {"h", h}, {"H", h}, {"Higgs", Higgs}, {"higgs", higgs}, {"25",static_cast<ParticleID>(25)}, {"p", p}, {"proton", proton}, {"p_bar", p_bar}, {"2212",static_cast<ParticleID>(2212)} }; const auto res = known.find(name); if(res == known.end()){ throw std::invalid_argument("Unknown particle " + name); } return res->second; } std::string name(ParticleID id) { using namespace HEJ::pid; switch (id) { case down: return "down"; case up: return "up"; case strange: return "strange"; case charm: return "charm"; case bottom: return "bottom"; case top: return "top"; case electron: return "electron"; case muon: return "muon"; case tau: return "tau"; case electron_neutrino: return "electron-neutrino"; case muon_neutrino: return "muon-neutrino"; case tau_neutrino: return "tau-neutrino"; case antidown: return "antidown"; case antiup: return "antiup"; case antistrange: return "antistrange"; case anticharm: return "anticharm"; case antibottom: return "antibottom"; case antitop: return "antitop"; case positron: return "positron"; case antimuon: return "antimuon"; case antitau: return "antitau"; case electron_antineutrino: return "electron-antineutrino"; case muon_antineutrino: return "muon-antineutrino"; case tau_antineutrino: return "tau-antineutrino"; case gluon: return "gluon"; case photon: return "photon"; case Z: return "Z"; case Wp: return "W+"; case Wm: return "W-"; case Higgs: return "Higgs"; case proton: return "proton"; case antiproton: return "antiproton"; } throw std::logic_error{"unreachable"}; } } diff --git a/src/PhaseSpacePoint.cc b/src/PhaseSpacePoint.cc index 7660d65..5d0c983 100644 --- a/src/PhaseSpacePoint.cc +++ b/src/PhaseSpacePoint.cc @@ -1,683 +1,694 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/PhaseSpacePoint.hh" #include <algorithm> #include <assert.h> #include <numeric> #include <random> #include "fastjet/ClusterSequence.hh" #include "HEJ/Constants.hh" #include "HEJ/Event.hh" #include "HEJ/JetSplitter.hh" #include "HEJ/kinematics.hh" #include "HEJ/resummation_jet.hh" #include "HEJ/utility.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/event_types.hh" namespace HEJ{ namespace { constexpr int max_jet_user_idx = PhaseSpacePoint::ng_max; bool is_nonjet_parton(fastjet::PseudoJet const & parton){ assert(parton.user_index() != -1); return parton.user_index() > max_jet_user_idx; } bool is_jet_parton(fastjet::PseudoJet const & parton){ assert(parton.user_index() != -1); return parton.user_index() <= max_jet_user_idx; } // user indices for partons with extremal rapidity constexpr int qqxb_idx = -7; constexpr int qqxf_idx = -6; constexpr int unob_idx = -5; constexpr int unof_idx = -4; constexpr int backward_FKL_idx = -3; constexpr int forward_FKL_idx = -2; } namespace { double estimate_ng_mean(std::vector<fastjet::PseudoJet> const & Born_jets){ const double delta_y = Born_jets.back().rapidity() - Born_jets.front().rapidity(); assert(delta_y > 0); // Formula derived from fit in arXiv:1805.04446 (see Fig. 2) return 0.975052*delta_y; } } std::vector<fastjet::PseudoJet> PhaseSpacePoint::cluster_jets( std::vector<fastjet::PseudoJet> const & partons ) const{ fastjet::ClusterSequence cs(partons, param_.jet_param.def); return sorted_by_rapidity(cs.inclusive_jets(param_.jet_param.min_pt)); } bool PhaseSpacePoint::pass_resummation_cuts( std::vector<fastjet::PseudoJet> const & jets ) const{ return cluster_jets(jets).size() == jets.size(); } int PhaseSpacePoint::sample_ng(std::vector<fastjet::PseudoJet> const & Born_jets){ const double ng_mean = estimate_ng_mean(Born_jets); std::poisson_distribution<int> dist(ng_mean); const int ng = dist(ran_.get()); assert(ng >= 0); assert(ng < ng_max); weight_ *= std::tgamma(ng + 1)*std::exp(ng_mean)*std::pow(ng_mean, -ng); return ng; } void PhaseSpacePoint::copy_AWZH_boson_from(Event const & event){ auto const & from = event.outgoing(); const auto AWZH_boson = std::find_if( begin(from), end(from), [](Particle const & p){ return is_AWZH_boson(p); } ); if(AWZH_boson == end(from)) return; auto insertion_point = std::lower_bound( begin(outgoing_), end(outgoing_), *AWZH_boson, rapidity_less{} ); outgoing_.insert(insertion_point, *AWZH_boson); // copy decay products const int idx = std::distance(begin(from), AWZH_boson); assert(idx >= 0); const auto decay_it = event.decays().find(idx); if(decay_it != end(event.decays())){ const int new_idx = std::distance(begin(outgoing_), insertion_point); assert(new_idx >= 0); assert(outgoing_[new_idx].type == AWZH_boson->type); decays_.emplace(new_idx, decay_it->second); } assert(std::is_sorted(begin(outgoing_), end(outgoing_), rapidity_less{})); } namespace { template<class ConstIterator, class Iterator> void label_extremal_qqx( ConstIterator born_begin, ConstIterator born_end, Iterator first_out ){ // find born quarks const auto firstquark = std::find_if( born_begin, born_end-1, [](Particle const & s){ return (is_anyquark(s)); } ); assert(firstquark != born_end-1); const auto secondquark = std::find_if( firstquark+1, born_end, [](Particle const & s){ return (is_anyquark(s)); } ); assert(secondquark != born_end); assert( ( is_quark(*firstquark) && is_antiquark(*secondquark) ) || ( is_antiquark(*firstquark) && is_quark(*secondquark) )); assert(first_out->type == ParticleID::gluon); assert((first_out+1)->type == ParticleID::gluon); // copy type from born first_out->type = firstquark->type; (first_out+1)->type = secondquark->type; } } void PhaseSpacePoint::label_qqx(Event const & event){ assert(std::is_sorted(begin(outgoing_), end(outgoing_), rapidity_less{})); assert(filter_partons(outgoing_).size() == outgoing_.size()); if(qqxb_){ label_extremal_qqx( event.outgoing().cbegin(), event.outgoing().cend(), outgoing_.begin() ); return; } if(qqxf_){ // same as qqxb with reversed order label_extremal_qqx( event.outgoing().crbegin(), event.outgoing().crend(), outgoing_.rbegin() ); return; } // central qqx std::vector<Particle> const born_parton{filter_partons(event.outgoing())}; // find born quarks (ignore extremal partons) auto const firstquark = std::find_if( born_parton.cbegin()+1, born_parton.cend()-2, [](Particle const & s){ return (is_anyquark(s)); } ); auto const secondquark = firstquark+1; assert(firstquark != born_parton.cend()-2); assert( ( is_quark(*firstquark) && is_antiquark(*secondquark) ) || ( is_antiquark(*firstquark) && is_quark(*secondquark) )); // find jets at FO corresponding to the quarks // technically this isn't necessary for LO std::vector<int> const born_indices{ event.particle_jet_indices(event.jets()) }; int const firstjet_idx = born_indices[ std::distance(born_parton.cbegin(), firstquark) ]; assert(firstjet_idx>0); assert(born_indices[ std::distance(born_parton.cbegin(), firstquark) ] == firstjet_idx); assert( born_indices[ std::distance(born_parton.cbegin(), secondquark) ] == firstjet_idx+1); // find corresponding jets after resummation fastjet::ClusterSequence cs{to_PseudoJet(outgoing_), param_.jet_param.def}; auto const jets = fastjet::sorted_by_rapidity( cs.inclusive_jets( param_.jet_param.min_pt )); std::vector<int> const resum_indices{ cs.particle_jet_indices({jets}) }; #ifndef NDEBUG // assert that jets are where we expect them to be auto const firstjet = event.jets().cbegin() + firstjet_idx; assert(nearby_ep( firstjet->rapidity(), jets[firstjet_idx].rapidity(), 1e-2) ); assert(nearby_ep( (firstjet+1)->rapidity(), jets[firstjet_idx+1].rapidity(), 1e-2) ); #endif // find last partons in first (central) jet size_t idx_out = 0; for(size_t i=resum_indices.size()-2; i>0; --i) if(resum_indices[i] == firstjet_idx){ idx_out = i; break; } assert(idx_out != 0); // check that no additional emission between jets //! @TODO don't even generate such configurations if(resum_indices[idx_out+1] != resum_indices[idx_out]+1){ weight_=0.; return; } outgoing_[idx_out].type = firstquark->type; outgoing_[idx_out+1].type = (firstquark+1)->type; } PhaseSpacePoint::PhaseSpacePoint( Event const & ev, PhaseSpacePointConfig conf, HEJ::RNG & ran ): unob_{ev.type() == event_type::unob}, unof_{ev.type() == event_type::unof}, qqxb_{ev.type() == event_type::qqxexb}, qqxf_{ev.type() == event_type::qqxexf}, qqxmid_{ev.type() == event_type::qqxmid}, param_{std::move(conf)}, - ran_{ran} + ran_{ran}, + status_{unspecified} { weight_ = 1; const auto & Born_jets = ev.jets(); const int ng = sample_ng(Born_jets); weight_ /= std::tgamma(ng + 1); const int ng_jets = sample_ng_jets(ng, Born_jets); std::vector<fastjet::PseudoJet> out_partons = gen_non_jet( ng - ng_jets, CMINPT, param_.jet_param.min_pt ); const auto qperp = std::accumulate( begin(out_partons), end(out_partons), fastjet::PseudoJet{} ); const auto jets = reshuffle(Born_jets, qperp); - if(weight_ == 0.) return; + if(weight_ == 0.) { + status_ = failed_reshuffle; + return; + } if(! pass_resummation_cuts(jets)){ - weight_ = 0.; - return; + status_ = failed_resummation_cuts; + weight_ = 0.; + return; } std::vector<fastjet::PseudoJet> jet_partons = split(jets, ng_jets); - if(weight_ == 0.) return; + if(weight_ == 0.) { + status_ = StatusCode::failed_split; + return; + } rescale_rapidities( out_partons, most_backward_FKL(jet_partons).rapidity(), most_forward_FKL(jet_partons).rapidity() ); if(! cluster_jets(out_partons).empty()){ weight_ = 0.; + status_ = StatusCode::empty_jets; return; } std::sort(begin(out_partons), end(out_partons), rapidity_less{}); assert( std::is_sorted(begin(jet_partons), end(jet_partons), rapidity_less{}) ); const auto first_jet_parton = out_partons.insert( end(out_partons), begin(jet_partons), end(jet_partons) ); std::inplace_merge( begin(out_partons), first_jet_parton, end(out_partons), rapidity_less{} ); if(! jets_ok(Born_jets, out_partons)){ weight_ = 0.; + status_ = StatusCode::wrong_jets; return; } weight_ *= phase_space_normalisation(Born_jets.size(), out_partons.size()); outgoing_.reserve(out_partons.size() + 1); // one slot for possible A, W, Z, H for(auto & p: out_partons){ outgoing_.emplace_back(Particle{pid::gluon, std::move(p), {}}); } const auto WEmit = std::find_if( begin(ev.outgoing()), end(ev.outgoing()), [](Particle const & s){ return abs(s.type) == pid::Wp; } ); if (WEmit != end(ev.outgoing())){ if(!qqxb_) outgoing_[unob_].type = filter_partons(ev.outgoing())[unob_].type; if(!qqxf_) outgoing_.rbegin()[unof_].type = filter_partons(ev.outgoing()).rbegin()[unof_].type; } else{ most_backward_FKL(outgoing_).type = ev.incoming().front().type; most_forward_FKL(outgoing_).type = ev.incoming().back().type; } if(qqxmid_||qqxb_||qqxf_){ label_qqx(ev); if(weight_ == 0.) return; //!< @TODO optimise s.t. this is not possible } if(! jets_ok(Born_jets, out_partons)){ weight_ = 0.; return; } copy_AWZH_boson_from(ev); assert(!outgoing_.empty()); reconstruct_incoming(ev.incoming()); + status_ = StatusCode::good; } std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_non_jet( int count, double ptmin, double ptmax ){ // heuristic parameters for pt sampling const double ptpar = 1.3 + count/5.; const double temp1 = atan((ptmax - ptmin)/ptpar); std::vector<fastjet::PseudoJet> partons(count); for(size_t i = 0; i < (size_t) count; ++i){ const double r1 = ran_.get().flat(); const double pt = ptmin + ptpar*tan(r1*temp1); const double temp2 = cos(r1*temp1); const double phi = 2*M_PI*ran_.get().flat(); weight_ *= 2.0*M_PI*pt*ptpar*temp1/(temp2*temp2); // we don't know the allowed rapidity span yet, // set a random value to be rescaled later on const double y = ran_.get().flat(); partons[i].reset_PtYPhiM(pt, y, phi); // Set user index higher than any jet-parton index // in order to assert that these are not inside jets partons[i].set_user_index(i + 1 + ng_max); assert(ptmin-1e-5 <= partons[i].pt() && partons[i].pt() <= ptmax+1e-5); } assert(std::all_of(partons.cbegin(), partons.cend(), is_nonjet_parton)); return partons; } void PhaseSpacePoint::rescale_rapidities( std::vector<fastjet::PseudoJet> & partons, double ymin, double ymax ){ constexpr double ep = 1e-7; for(auto & parton: partons){ assert(0 <= parton.rapidity() && parton.rapidity() <= 1); const double dy = ymax - ymin - 2*ep; const double y = ymin + ep + dy*parton.rapidity(); parton.reset_momentum_PtYPhiM(parton.pt(), y, parton.phi()); weight_ *= dy; assert(ymin <= parton.rapidity() && parton.rapidity() <= ymax); } } namespace { template<typename T, typename... Rest> auto min(T const & a, T const & b, Rest&&... r) { using std::min; return min(a, min(b, std::forward<Rest>(r)...)); } } double PhaseSpacePoint::probability_in_jet( std::vector<fastjet::PseudoJet> const & Born_jets ) const{ assert(std::is_sorted(begin(Born_jets), end(Born_jets), rapidity_less{})); assert(Born_jets.size() >= 2); const double dy = Born_jets.back().rapidity() - Born_jets.front().rapidity(); const double R = param_.jet_param.def.R(); const int njets = Born_jets.size(); const double p_J_y_large = (njets-1)*R*R/(2.*dy); const double p_J_y0 = njets*R/M_PI; return min(p_J_y_large, p_J_y0, 1.); } int PhaseSpacePoint::sample_ng_jets( int ng, std::vector<fastjet::PseudoJet> const & Born_jets ){ const double p_J = probability_in_jet(Born_jets); std::binomial_distribution<> bin_dist(ng, p_J); const int ng_J = bin_dist(ran_.get()); weight_ *= std::pow(p_J, -ng_J)*std::pow(1 - p_J, ng_J - ng); return ng_J; } std::vector<fastjet::PseudoJet> PhaseSpacePoint::reshuffle( std::vector<fastjet::PseudoJet> const & Born_jets, fastjet::PseudoJet const & q ){ if(q == fastjet::PseudoJet{0, 0, 0, 0}) return Born_jets; const auto jets = resummation_jet_momenta(Born_jets, q); if(jets.empty()){ weight_ = 0; return {}; } // additional Jacobian to ensure Born integration over delta gives 1 weight_ *= resummation_jet_weight(Born_jets, q); return jets; } std::vector<int> PhaseSpacePoint::distribute_jet_partons( int ng_jets, std::vector<fastjet::PseudoJet> const & jets ){ size_t first_valid_jet = 0; size_t num_valid_jets = jets.size(); const double R_eff = 5./3.*param_.jet_param.def.R(); // if there is an unordered jet too far away from the FKL jets // then extra gluon constituents of the unordered jet would // violate the FKL rapidity ordering if((unob_||qqxb_) && jets[0].delta_R(jets[1]) > R_eff){ ++first_valid_jet; --num_valid_jets; } else if((unof_||qqxf_) && jets[jets.size()-1].delta_R(jets[jets.size()-2]) > R_eff){ --num_valid_jets; } std::vector<int> np(jets.size(), 1); for(int i = 0; i < ng_jets; ++i){ ++np[first_valid_jet + ran_.get().flat() * num_valid_jets]; } weight_ *= std::pow(num_valid_jets, ng_jets); return np; } #ifndef NDEBUG namespace{ bool tagged_FKL_backward( std::vector<fastjet::PseudoJet> const & jet_partons ){ return std::find_if( begin(jet_partons), end(jet_partons), [](fastjet::PseudoJet const & p){ return p.user_index() == backward_FKL_idx; } ) != end(jet_partons); } bool tagged_FKL_forward( std::vector<fastjet::PseudoJet> const & jet_partons ){ // the most forward FKL parton is most likely near the end of jet_partons; // start search from there return std::find_if( jet_partons.rbegin(), jet_partons.rend(), [](fastjet::PseudoJet const & p){ return p.user_index() == forward_FKL_idx; } ) != jet_partons.rend(); } bool tagged_FKL_extremal( std::vector<fastjet::PseudoJet> const & jet_partons ){ return tagged_FKL_backward(jet_partons) && tagged_FKL_forward(jet_partons); } } // namespace anonymous #endif std::vector<fastjet::PseudoJet> PhaseSpacePoint::split( std::vector<fastjet::PseudoJet> const & jets, int ng_jets ){ return split(jets, distribute_jet_partons(ng_jets, jets)); } bool PhaseSpacePoint::pass_extremal_cuts( fastjet::PseudoJet const & ext_parton, fastjet::PseudoJet const & jet ) const{ if(ext_parton.pt() < param_.min_extparton_pt) return false; return (ext_parton - jet).pt()/jet.pt() < param_.max_ext_soft_pt_fraction; } std::vector<fastjet::PseudoJet> PhaseSpacePoint::split( std::vector<fastjet::PseudoJet> const & jets, std::vector<int> const & np ){ assert(! jets.empty()); assert(jets.size() == np.size()); assert(pass_resummation_cuts(jets)); const size_t most_backward_FKL_idx = 0 + unob_ + qqxb_; const size_t most_forward_FKL_idx = jets.size() - 1 - unof_ - qqxf_; const auto & jet = param_.jet_param; const JetSplitter jet_splitter{jet.def, jet.min_pt, ran_}; std::vector<fastjet::PseudoJet> jet_partons; // randomly distribute jet gluons among jets for(size_t i = 0; i < jets.size(); ++i){ auto split_res = jet_splitter.split(jets[i], np[i]); weight_ *= split_res.weight; if(weight_ == 0) return {}; assert( std::all_of( begin(split_res.constituents), end(split_res.constituents), is_jet_parton ) ); const auto first_new_parton = jet_partons.insert( end(jet_partons), begin(split_res.constituents), end(split_res.constituents) ); // mark uno and extremal FKL emissions here so we can check // their position once all emissions are generated auto extremal = end(jet_partons); if (i == most_backward_FKL_idx){ //FKL backward emission extremal = std::min_element( first_new_parton, end(jet_partons), rapidity_less{} ); extremal->set_user_index(backward_FKL_idx); } else if(((unob_ || qqxb_) && i == 0)){ // unordered/qqxb extremal = std::min_element( first_new_parton, end(jet_partons), rapidity_less{} ); extremal->set_user_index((unob_)?unob_idx:qqxb_idx); } else if (i == most_forward_FKL_idx){ extremal = std::max_element( first_new_parton, end(jet_partons), rapidity_less{} ); extremal->set_user_index(forward_FKL_idx); } else if(((unof_ || qqxf_) && i == jets.size() - 1)){ // unordered/qqxf extremal = std::max_element( first_new_parton, end(jet_partons), rapidity_less{} ); extremal->set_user_index((unof_)?unof_idx:qqxf_idx); } if( extremal != end(jet_partons) && !pass_extremal_cuts(*extremal, jets[i]) ){ weight_ = 0; return {}; } } assert(tagged_FKL_extremal(jet_partons)); std::sort(begin(jet_partons), end(jet_partons), rapidity_less{}); if( !extremal_ok(jet_partons) || !split_preserved_jets(jets, jet_partons) ){ weight_ = 0.; return {}; } return jet_partons; } bool PhaseSpacePoint::extremal_ok( std::vector<fastjet::PseudoJet> const & partons ) const{ assert(std::is_sorted(begin(partons), end(partons), rapidity_less{})); if(unob_ && partons.front().user_index() != unob_idx) return false; if(unof_ && partons.back().user_index() != unof_idx) return false; if(qqxb_ && partons.front().user_index() != qqxb_idx) return false; if(qqxf_ && partons.back().user_index() != qqxf_idx) return false; return most_backward_FKL(partons).user_index() == backward_FKL_idx && most_forward_FKL(partons).user_index() == forward_FKL_idx; } bool PhaseSpacePoint::split_preserved_jets( std::vector<fastjet::PseudoJet> const & jets, std::vector<fastjet::PseudoJet> const & jet_partons ) const{ assert(std::is_sorted(begin(jets), end(jets), rapidity_less{})); const auto split_jets = cluster_jets(jet_partons); // this can happen if two overlapping jets // are both split into more than one parton if(split_jets.size() != jets.size()) return false; for(size_t i = 0; i < split_jets.size(); ++i){ // this can happen if there are two overlapping jets // and a parton is assigned to the "wrong" jet if(!nearby_ep(jets[i].rapidity(), split_jets[i].rapidity(), 1e-2)){ return false; } } return true; } template<class Particle> Particle const & PhaseSpacePoint::most_backward_FKL( std::vector<Particle> const & partons ) const{ return partons[0 + unob_ + qqxb_]; } template<class Particle> Particle const & PhaseSpacePoint::most_forward_FKL( std::vector<Particle> const & partons ) const{ const size_t idx = partons.size() - 1 - unof_ - qqxf_; assert(idx < partons.size()); return partons[idx]; } template<class Particle> Particle & PhaseSpacePoint::most_backward_FKL( std::vector<Particle> & partons ) const{ return partons[0 + unob_ + qqxb_]; } template<class Particle> Particle & PhaseSpacePoint::most_forward_FKL( std::vector<Particle> & partons ) const{ const size_t idx = partons.size() - 1 - unof_ - qqxf_; assert(idx < partons.size()); return partons[idx]; } namespace { bool contains_idx( fastjet::PseudoJet const & jet, fastjet::PseudoJet const & parton ){ auto const & constituents = jet.constituents(); const int idx = parton.user_index(); return std::find_if( begin(constituents), end(constituents), [idx](fastjet::PseudoJet const & con){return con.user_index() == idx;} ) != end(constituents); } } bool PhaseSpacePoint::jets_ok( std::vector<fastjet::PseudoJet> const & Born_jets, std::vector<fastjet::PseudoJet> const & partons ) const{ fastjet::ClusterSequence cs(partons, param_.jet_param.def); const auto jets = sorted_by_rapidity(cs.inclusive_jets(param_.jet_param.min_pt)); if(jets.size() != Born_jets.size()) return false; int in_jet = 0; for(size_t i = 0; i < jets.size(); ++i){ assert(jets[i].has_constituents()); for(auto && parton: jets[i].constituents()){ if(is_nonjet_parton(parton)) return false; } in_jet += jets[i].constituents().size(); } const int expect_in_jet = std::count_if( partons.cbegin(), partons.cend(), is_jet_parton ); if(in_jet != expect_in_jet) return false; // note that PseudoJet::contains does not work here if(! ( contains_idx(most_backward_FKL(jets), most_backward_FKL(partons)) && contains_idx(most_forward_FKL(jets), most_forward_FKL(partons)) )) return false; if(unob_ && !contains_idx(jets.front(), partons.front())) return false; if(unof_ && !contains_idx(jets.back(), partons.back())) return false; for(size_t i = 0; i < jets.size(); ++i){ assert(nearby_ep(jets[i].rapidity(), Born_jets[i].rapidity(), 1e-2)); } return true; } void PhaseSpacePoint::reconstruct_incoming( std::array<Particle, 2> const & Born_incoming ){ std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_); for(size_t i = 0; i < incoming_.size(); ++i){ incoming_[i].type = Born_incoming[i].type; } assert(momentum_conserved()); } double PhaseSpacePoint::phase_space_normalisation( int num_Born_jets, int num_out_partons ) const{ return pow(16*pow(M_PI,3), num_Born_jets - num_out_partons); } bool PhaseSpacePoint::momentum_conserved() const{ fastjet::PseudoJet diff; for(auto const & in: incoming()) diff += in.p; const double norm = diff.E(); for(auto const & out: outgoing()) diff -= out.p; return nearby(diff, fastjet::PseudoJet{}, norm); } } //namespace HEJ diff --git a/src/Ranlux64.cc b/src/Ranlux64.cc index c870864..ea67bb6 100644 --- a/src/Ranlux64.cc +++ b/src/Ranlux64.cc @@ -1,61 +1,61 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/Ranlux64.hh" #include <cstdio> namespace HEJ { namespace { //! create Ranlux64Engine with state read from the given file CLHEP::Ranlux64Engine make_Ranlux64Engine(std::string const & seed_file) { CLHEP::Ranlux64Engine result; result.restoreStatus(seed_file.c_str()); return result; } CLHEP::Ranlux64Engine make_Ranlux64Engine() { /* * some (all?) of the Ranlux64Engine constructors leave fields * uninitialised, invoking undefined behaviour. This can be * circumvented by restoring the state from a file */ static const std::string state = "9876\n" "0.91280703978419097666\n" "0.41606065829518357191\n" "0.99156342622341142601\n" "0.030922955274050423213\n" "0.16206278421638486975\n" "0.76151768001958330956\n" "0.43765760066092695979\n" "0.42904698253748563275\n" "0.11476317525663759511\n" "0.026620053590963976831\n" "0.65953715764414511114\n" "0.30136722624439826745\n" "3.5527136788005009294e-15 4\n" "1 202\n"; const std::string file = std::tmpnam(nullptr); { std::ofstream out{file}; out << state; } auto result = make_Ranlux64Engine(file); std::remove(file.c_str()); return result; } } Ranlux64::Ranlux64(): ran_{make_Ranlux64Engine()} {} Ranlux64::Ranlux64(std::string const & seed_file): ran_{make_Ranlux64Engine(seed_file)} {} double Ranlux64::flat() { return ran_.flat(); } } diff --git a/src/RivetAnalysis.cc b/src/RivetAnalysis.cc index 7db9b8b..cb07fd9 100644 --- a/src/RivetAnalysis.cc +++ b/src/RivetAnalysis.cc @@ -1,143 +1,143 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/RivetAnalysis.hh" #ifdef HEJ_BUILD_WITH_RIVET #include <ostream> #include <stddef.h> #include "yaml-cpp/yaml.h" #include "Rivet/AnalysisHandler.hh" #include "HepMC/GenEvent.h" #include "HEJ/Event.hh" #include "HEJ/exceptions.hh" #endif namespace HEJ{ std::unique_ptr<Analysis> RivetAnalysis::create(YAML::Node const & config){ return std::unique_ptr<Analysis>{new RivetAnalysis{config}}; } } #ifdef HEJ_BUILD_WITH_RIVET namespace HEJ { RivetAnalysis::RivetAnalysis(YAML::Node const & config): output_name_{config["output"].as<std::string>()}, first_event_(true) { // read in analyses const auto & name_node = config["rivet"]; switch(name_node.Type()){ case YAML::NodeType::Scalar: analyses_names_.push_back(name_node.as<std::string>()); break; case YAML::NodeType::Sequence: for(YAML::const_iterator it = name_node.begin(); it != name_node.end(); ++it){ analyses_names_.push_back(it->as<std::string>()); } break; default: throw std::invalid_argument{ "No Analysis was provided to rivet. " "Either give an analysis or deactivate rivet." }; } } namespace { void replace( std::string & str, char to_replace, std::string const & replacement ) { for( auto pos = str.find(to_replace); pos != str.npos; pos = str.find(to_replace, pos) ) { str.replace(pos, 1, replacement); pos += replacement.size(); } } // remove "special" characters from scale name // so that we can more easily use it as part of a file name std::string sanitise_scalename(std::string scalename) { replace(scalename, '/', "_over_"); replace(scalename, '*', "_times_"); return scalename; } } void RivetAnalysis::init(Event const & event){ rivet_runs_.push_back( {std::make_unique<Rivet::AnalysisHandler>(), "", HepMCInterface()} ); rivet_runs_.back().handler->addAnalyses(analyses_names_); if( !event.variations().empty() ){ rivet_runs_.reserve(event.variations().size()+1); for(auto const & vari : event.variations()){ std::ostringstream name; name << ".Scale" << sanitise_scalename(vari.description->scale_name) << "_MuR" << vari.description->mur_factor << "_MuF" << vari.description->muf_factor; rivet_runs_.push_back( {std::make_unique<Rivet::AnalysisHandler>(), name.str(), HepMCInterface()} ); rivet_runs_.back().handler->addAnalyses(analyses_names_); } } } void RivetAnalysis::fill(Event const & event, Event const &){ if(first_event_){ first_event_=false; init(event); } HepMC::GenEvent hepmc_kin(rivet_runs_[0].hepmc.init_kinematics(event)); for(size_t i = 0; i < rivet_runs_.size(); ++i){ auto & run = rivet_runs_[i]; run.hepmc.set_central(hepmc_kin, event, i-1); // -1: first = central run.handler->analyze(hepmc_kin); } } void RivetAnalysis::finalise(){ for(auto const & run: rivet_runs_){ run.handler->finalize(); run.handler->writeData(output_name_+run.name+std::string(".yoda")); } } } // namespace HEJ #else // no rivet => create empty analysis namespace Rivet { class AnalysisHandler {}; } namespace HEJ { RivetAnalysis::RivetAnalysis(YAML::Node const &) { throw std::invalid_argument( "Failed to create RivetAnalysis: " "HEJ 2 was built without rivet support" ); } void RivetAnalysis::init(Event const &){} void RivetAnalysis::fill(Event const &, Event const &){} void RivetAnalysis::finalise(){} } // namespace HEJ #endif diff --git a/src/ScaleFunction.cc b/src/ScaleFunction.cc index 5fc7d7e..04eb410 100644 --- a/src/ScaleFunction.cc +++ b/src/ScaleFunction.cc @@ -1,171 +1,171 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/ScaleFunction.hh" #include <cassert> #include "HEJ/Event.hh" #include "HEJ/exceptions.hh" namespace HEJ{ double H_T(Event const & ev){ double result = 0.; for(size_t i = 0; i < ev.outgoing().size(); ++i){ auto const decay_products = ev.decays().find(i); if(decay_products == end(ev.decays())){ result += ev.outgoing()[i].perp(); } else{ for(auto const & particle: decay_products->second){ result += particle.perp(); } } } return result; } double max_jet_pt(Event const & ev) { return sorted_by_pt(ev.jets()).front().pt(); } double jet_invariant_mass(Event const & ev) { fastjet::PseudoJet sum; for(const auto & jet: ev.jets()) sum+=jet; return sum.m(); } double m_j1j2(Event const & ev) { const auto jets = sorted_by_pt(ev.jets()); assert(jets.size() >= 2); return (jets[0] + jets[1]).m(); } ScaleFunction operator*(double factor, ScaleFunction base_scale) { base_scale.name_.insert(0, std::to_string(factor) + '*'); auto new_fun = [factor,fun{std::move(base_scale.fun_)}](HEJ::Event const & ev) { return factor*fun(ev); }; base_scale.fun_ = std::move(new_fun); return base_scale; } ScaleFunction operator*(ScaleFunction factor, ScaleFunction base_scale) { base_scale.name_.insert(0, factor.name_ + '*'); auto new_fun = [fun1{std::move(factor.fun_)}, fun2{std::move(base_scale.fun_)}, name{base_scale.name_}] (HEJ::Event const & ev) { return fun1(ev)*fun2(ev); }; base_scale.fun_ = std::move(new_fun); return base_scale; } ScaleFunction operator/(ScaleFunction base_scale, double denom) { base_scale.name_.append('/' + std::to_string(denom)); auto new_fun = [denom,fun{std::move(base_scale.fun_)}](HEJ::Event const & ev) { return fun(ev)/denom; }; base_scale.fun_ = std::move(new_fun); return base_scale; } ScaleFunction operator/(ScaleFunction base_scale, ScaleFunction denom) { base_scale.name_.append('/' + denom.name_); auto new_fun = [fun2{std::move(denom.fun_)}, fun1{std::move(base_scale.fun_)}] (HEJ::Event const & ev) { return fun1(ev)/fun2(ev); }; base_scale.fun_ = std::move(new_fun); return base_scale; } // TODO: significant logic duplication with operator() void ScaleGenerator::gen_descriptions() { if(scales_.empty()) { throw std::logic_error{"Need at least one scale"}; } descriptions_.emplace_back( std::make_shared<ParameterDescription>(scales_.front().name(), 1., 1.) ); for(auto & base_scale: scales_){ const auto base_name = base_scale.name(); descriptions_.emplace_back( std::make_shared<ParameterDescription>(base_name, 1., 1.) ); //multiplicative scale variation for(double mur_factor: scale_factors_){ for(double muf_factor: scale_factors_){ if(muf_factor == 1. && mur_factor == 1.) continue; if( mur_factor/muf_factor < 1/max_scale_ratio_ || mur_factor/muf_factor > max_scale_ratio_ ) continue; descriptions_.emplace_back( std::make_shared<ParameterDescription>( base_name, mur_factor, muf_factor ) ); } } } } Event ScaleGenerator::operator()(Event ev) const { if(! ev.variations().empty()) { throw std::invalid_argument{"Input event already has scale variation"}; } assert(!scales_.empty()); assert(!descriptions_.empty()); size_t descr_idx = 0; const double mu_central = (scales_.front())(ev); ev.central().mur = mu_central; ev.central().muf = mu_central; assert(descr_idx < descriptions_.size()); assert(descriptions_[descr_idx]); ev.central().description = descriptions_[descr_idx++]; // check if we are doing scale variation at all if(scales_.size() == 1 && scale_factors_.empty()) return ev; for(auto & base_scale: scales_){ const double mu_base = base_scale(ev); assert(descr_idx < descriptions_.size()); assert(descriptions_[descr_idx]); ev.variations().emplace_back( EventParameters{ mu_base, mu_base, ev.central().weight, descriptions_[descr_idx++] } ); //multiplicative scale variation for(double mur_factor: scale_factors_){ const double mur = mu_base*mur_factor; for(double muf_factor: scale_factors_){ if(muf_factor == 1. && mur_factor == 1.) continue; const double muf = mu_base*muf_factor; if( mur/muf < 1/max_scale_ratio_ || mur/muf > max_scale_ratio_ ) continue; assert(descr_idx < descriptions_.size()); assert(descriptions_[descr_idx]); ev.variations().emplace_back( EventParameters{ mur, muf, ev.central().weight, descriptions_[descr_idx++] } ); } } }; return ev; } } diff --git a/src/Tensor.cc b/src/Tensor.cc index 0fba3bb..af7e882 100644 --- a/src/Tensor.cc +++ b/src/Tensor.cc @@ -1,790 +1,795 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/currents.hh" #include "HEJ/Tensor.hh" #include <array> #include <iostream> namespace{ // Tensor Template definitions short int sigma_index5[1024]; short int sigma_index3[64]; std::valarray<COM> permfactor5; std::valarray<COM> permfactor3; short int helfactor5[2][1024]; short int helfactor3[2][64]; // 2D sigma matrices const COM sigma0[2][2] = { {1.,0.}, {0., 1.} }; const COM sigma1[2][2] = { {0.,1.}, {1., 0.} }; const COM sigma2[2][2] = { {0,-1.*COM(0,1)}, {1.*COM(0,1), 0.} }; const COM sigma3[2][2] = { {1.,0.}, {0., -1.} }; Tensor<1,4> Sigma(int i, int j, bool hel){ Tensor<1,4> newT; if(hel){ newT.components[0]=sigma0[i][j]; newT.components[1]=sigma1[i][j]; newT.components[2]=sigma2[i][j]; newT.components[3]=sigma3[i][j]; } else { newT.components[0]= sigma0[i][j]; newT.components[1]=-sigma1[i][j]; newT.components[2]=-sigma2[i][j]; newT.components[3]=-sigma3[i][j]; } return newT; } // map from a list of 5 tensor lorentz indices onto a single index 0<=i<1024 // in 4 dimensional spacetime int tensor2listindex(std::array<int,5> indexlist){ int mu=indexlist[0]; int nu=indexlist[1]; int sigma=indexlist[2]; int tau=indexlist[3]; int rho=indexlist[4]; int myindex; myindex = 256*mu+64*nu+16*sigma+4*tau+rho; if(myindex<0||myindex>1023){ std::cerr<<"bad index in tensor2listindex "<<std::endl; return 1024; } return myindex; } // map from a list of 3 tensor lorentz indices onto a single index 0<=i<64 in // 4 dimensional spacetime int tensor2listindex(std::array<int,3> indexlist){ int mu=indexlist[0]; int nu=indexlist[1]; int sigma=indexlist[2]; int myindex; myindex = 16*mu+4*nu+sigma; if(myindex<0||myindex>64){ std::cerr<<"bad index in tensor2listindex "<<std::endl; return 64; } return myindex; } // generate all unique perms of vectors {a,a,a,a,b}, return in perms // set_permfactor is a bool which encodes the anticommutation relations of the // sigma matrices namely if we have sigma0, set_permfactor= false because it // commutes with all others otherwise we need to assign a minus sign to odd // permutations, set in permfactor // note, inital perm is always even void perms41(int same4, int diff, std::vector<std::array<int,5>> & perms){ bool set_permfactor(true); if(same4==0||diff==0) set_permfactor=false; for(int diffpos=0;diffpos<5;diffpos++){ std::array<int,5> tempvec={same4,same4,same4,same4,same4}; tempvec[diffpos]=diff; perms.push_back(tempvec); if(set_permfactor){ if(diffpos%2==1) permfactor5[tensor2listindex(tempvec)]=-1.; } } } // generate all unique perms of vectors {a,a,a,b,b}, return in perms // note, inital perm is always even void perms32(int same3, int diff, std::vector<std::array<int,5>> & perms){ bool set_permfactor(true); if(same3==0||diff==0) set_permfactor=false; for(int diffpos1=0;diffpos1<5;diffpos1++){ for(int diffpos2=diffpos1+1;diffpos2<5;diffpos2++){ std::array<int,5> tempvec={same3,same3,same3,same3,same3}; tempvec[diffpos1]=diff; tempvec[diffpos2]=diff; perms.push_back(tempvec); if(set_permfactor){ if((diffpos2-diffpos1)%2==0) permfactor5[tensor2listindex(tempvec)]=-1.; } } } } // generate all unique perms of vectors {a,a,a,b,c}, return in perms // we have two bools since there are three distinct type of sigma matrices to // permute, so need to test if the 3xrepeated = sigma0 or if one of the // singles is sigma0 // if diff1/diff2 are distinct, flipping them results in a change of perm, // otherwise it'll be symmetric under flip -> encode this in set_permfactor2 // as long as diff2!=0 can ensure inital perm is even // if diff2=0 then it is not possible to ensure inital perm even -> encode in // bool signflip void perms311(int same3, int diff1, int diff2, std::vector<std::array<int,5>> & perms ){ bool set_permfactor2(true); bool same0(false); bool diff0(false); bool signflip(false); // if true, inital perm is odd if(same3==0) // is the repeated matrix sigma0? same0 = true; else if(diff2==0){ // is one of the single matrices sigma0 diff0=true; if((diff1%3-same3)!=-1) signflip=true; } else if(diff1==0){ std::cerr<<"Note, only first and last argument may be zero"<<std::endl; return; } // possible outcomes: tt, ft, tf for(int diffpos1=0;diffpos1<5;diffpos1++){ for(int diffpos2=diffpos1+1;diffpos2<5;diffpos2++){ std::array<int,5> tempvec={same3,same3,same3,same3,same3}; tempvec[diffpos1]=diff1; tempvec[diffpos2]=diff2; perms.push_back(tempvec); if(!same0 && !diff0){ // full antisymmetric under exchange of same3,diff1,diff2 if((diffpos2-diffpos1)%2==0){ permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm // if this perm is odd, swapping diff1<->diff2 automatically even set_permfactor2=false; } else { permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm // if this perm is even, swapping diff1<->diff2 automatically odd set_permfactor2=true; } } else if(diff0){// one of the single matrices is sigma0 if(signflip){ // initial config is odd! if(diffpos1%2==1){ permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm // initally symmetric under diff1<->diff2 => // if this perm is even, automatically even for first diffpos2 set_permfactor2=false; } else { permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm // initally symmetric under diff1<->diff2 => // if this perm is odd, automatically odd for first diffpos2 set_permfactor2=true; } } else {// diff0=true, initial config is even if(diffpos1%2==1){ permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd perm // initally symmetric under diff1<->diff2 => // if this perm is odd, automatically odd for first diffpos2 set_permfactor2=true; } else { permfactor5[tensor2listindex(tempvec)]=COM(0,1); // even perm // initally symmetric under diff1<->diff2 => // if this perm is even, automatically even for first diffpos2 set_permfactor2=false; } } if((diffpos2-diffpos1-1)%2==1) set_permfactor2=!set_permfactor2; // change to account for diffpos2 } else if(same0){ // the repeated matrix is sigma0 // => only relative positions of diff1, diff2 matter. // always even before flip because diff1pos<diff2pos permfactor5[tensor2listindex(tempvec)]=COM(0,1); // if this perm is odd, swapping diff1<->diff2 automatically odd set_permfactor2=true; } tempvec[diffpos1]=diff2; tempvec[diffpos2]=diff1; perms.push_back(tempvec); if(set_permfactor2) permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); else permfactor5[tensor2listindex(tempvec)]=COM(0,1); } } } // end perms311 // generate all unique perms of vectors {a,a,b,b,c}, return in perms void perms221(int same2a, int same2b, int diff, std::vector<std::array<int,5>> & perms ){ bool set_permfactor1(true); bool set_permfactor2(true); if(same2b==0){ std::cerr<<"second entry in perms221() shouldn't be zero" <<std::endl; return; } else if(same2a==0) set_permfactor1=false; else if(diff==0) set_permfactor2=false; for(int samepos=0;samepos<5;samepos++){ int permcount = 0; for(int samepos2=samepos+1;samepos2<5;samepos2++){ for(int diffpos=0;diffpos<5;diffpos++){ if(diffpos==samepos||diffpos==samepos2) continue; std::array<int,5> tempvec={same2a,same2a,same2a,same2a,same2a}; tempvec[samepos]=same2b; tempvec[samepos2]=same2b; tempvec[diffpos]=diff; perms.push_back(tempvec); if(set_permfactor1){ if(set_permfactor2){// full anti-symmetry if(permcount%2==1) permfactor5[tensor2listindex(tempvec)]=-1.; } else { // diff is sigma0 if( ((samepos2-samepos-1)%3>0) && (abs(abs(samepos2-diffpos)-abs(samepos-diffpos))%3>0) ) permfactor5[tensor2listindex(tempvec)]=-1.; } } else { // same2a is sigma0 if((diffpos>samepos) && (diffpos<samepos2)) permfactor5[tensor2listindex(tempvec)]=-1.; } permcount++; } } } } // generate all unique perms of vectors {a,a,b,b,c}, return in perms // there must be a sigma zero if we have 4 different matrices in string // bool is true if sigma0 is the repeated matrix void perms2111(int same2, int diff1,int diff2,int diff3, std::vector<std::array<int,5>> & perms ){ bool twozero(false); if(same2==0) twozero=true; else if (diff1!=0){ std::cerr<<"One of first or second argurments must be a zero"<<std::endl; return; } else if(diff2==0|| diff3==0){ std::cerr<<"Only first and second arguments may be a zero."<<std::endl; return; } int permcount = 0; for(int diffpos1=0;diffpos1<5;diffpos1++){ for(int diffpos2=0;diffpos2<5;diffpos2++){ if(diffpos2==diffpos1) continue; for(int diffpos3=0;diffpos3<5;diffpos3++){ if(diffpos3==diffpos2||diffpos3==diffpos1) continue; std::array<int,5> tempvec={same2,same2,same2,same2,same2}; tempvec[diffpos1]=diff1; tempvec[diffpos2]=diff2; tempvec[diffpos3]=diff3; perms.push_back(tempvec); if(twozero){// don't care about exact positions of singles, just order if(diffpos2>diffpos3 && diffpos3>diffpos1) permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd else if(diffpos1>diffpos2 && diffpos2>diffpos3) permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd else if(diffpos3>diffpos1 && diffpos1>diffpos2) permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1);// odd else permfactor5[tensor2listindex(tempvec)]=COM(0,1);// evwn } else { if(permcount%2==1) permfactor5[tensor2listindex(tempvec)]=-1.*COM(0,1); else permfactor5[tensor2listindex(tempvec)]=COM(0,1); } permcount++; } } } } void perms21(int same, int diff, std::vector<std::array<int,3>> & perms){ bool set_permfactor(true); if(same==0||diff==0) set_permfactor=false; for(int diffpos=0; diffpos<3;diffpos++){ std::array<int,3> tempvec={same,same,same}; tempvec[diffpos]=diff; perms.push_back(tempvec); if(set_permfactor && diffpos==1) permfactor3[tensor2listindex(tempvec)]=-1.; } } void perms111(int diff1, int diff2, int diff3, std::vector<std::array<int,3>> & perms ){ bool sig_zero(false); if(diff1==0) sig_zero=true; else if(diff2==0||diff3==0){ std::cerr<<"Only first argument may be a zero."<<std::endl; return; } int permcount=0; for(int pos1=0;pos1<3;pos1++){ for(int pos2=pos1+1;pos2<3;pos2++){ std::array<int,3> tempvec={diff1,diff1,diff1}; tempvec[pos1]=diff2; tempvec[pos2]=diff3; perms.push_back(tempvec); if(sig_zero){ permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even } else if(permcount%2==1){ permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd } else { permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even } tempvec[pos1]=diff3; tempvec[pos2]=diff2; perms.push_back(tempvec); if(sig_zero){ permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd } else if(permcount%2==1){ permfactor3[tensor2listindex(tempvec)]=1.*COM(0,1); // even } else { permfactor3[tensor2listindex(tempvec)]=-1.*COM(0,1); // odd } permcount++; } } } void SpinorO(CLHEP::HepLorentzVector p, bool hel, COM *sp){ // sp is pointer to COM sp[2] COM pplus = p.e() +p.z(); COM pminus = p.e() -p.z(); COM sqpp= sqrt(pplus); COM sqpm= sqrt(pminus); COM pperp = p.x() + COM(0,1)*p.y(); // if hel=+ if(hel){ sp[0] = sqpp; sp[1] = sqpm*pperp/abs(pperp); } else { sp[0] = sqpm*conj(pperp)/abs(pperp); sp[1] = -sqpp; } } void SpinorIp(COM sqpp, bool hel, COM *sp){ // if hel=+ if(hel){ sp[0] = sqpp; sp[1] = 0.; } else { sp[0] = 0.; sp[1] = -sqpp; } } void SpinorIm(COM sqpm, bool hel, COM *sp){ // if hel=+ if(hel){ sp[0] = 0; sp[1] = -sqpm; } else { sp[0] = -sqpm; sp[1] = 0.; } } void Spinor(CLHEP::HepLorentzVector p, bool hel, COM *sp){ COM pplus = p.e() +p.z(); COM pminus = p.e() -p.z(); // If incoming along +ve z if (pminus==0.){ COM sqpp= sqrt(pplus); SpinorIp(sqpp,hel,sp); } // If incoming along -ve z else if(pplus==0.){ COM sqpm= sqrt(pminus); SpinorIm(sqpm,hel,sp); } // Outgoing else { SpinorO(p,hel,sp); } } } // anonymous namespace Tensor<2,4> Metric(){ Tensor<2,4> g(0.); g.Set(0,0, 1.); g.Set(1,1, -1.); g.Set(2,2, -1.); g.Set(3,3, -1.); return g; } // <1|mu|2> Tensor<1,4> TCurrent(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2 ){ COM sp1[2]; COM sp2[2]; Tensor<1,4> newT(0.); CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 }; CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 }; if(h1!=h2){ return newT; } Spinor(p1new, h1, sp1); Spinor(p2new, h2, sp2); for(int i=0;i<2;i++){ for(int j=0; j<2; j++){ newT+=(Sigma(i,j,h2)*sp2[j])*conj(sp1[i]); } } return newT; } // <1|mu nu sigma|2> Tensor<3,4> T3Current(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2 ){ COM sp1[2]; COM sp2[2]; Tensor<3,4> newT(0.); CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 }; CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 }; if(h1!=h2){ return newT; } Spinor(p1new, h1, sp1); Spinor(p2new, h2, sp2); COM current[4]; for(int i=0; i<2;i++){ for(int j=0; j<2;j++){ current[0]+=conj(sp1[i])*sigma0[i][j]*sp2[j]; current[1]+=conj(sp1[i])*sigma1[i][j]*sp2[j]; current[2]+=conj(sp1[i])*sigma2[i][j]*sp2[j]; current[3]+=conj(sp1[i])*sigma3[i][j]*sp2[j]; } } for( int itensor=0; itensor<newT.len(); itensor++ ){ double hfact = double( helfactor3[h2][itensor] ); newT.components[itensor] = current[sigma_index3[itensor]] * hfact * permfactor3[itensor]; } return newT; } // <1|mu nu sigma tau rho|2> Tensor<5,4> T5Current(CLHEP::HepLorentzVector p1, bool h1, CLHEP::HepLorentzVector p2, bool h2 ){ COM sp1[2]; COM sp2[2]; Tensor<5,4> newT(0.); CLHEP::HepLorentzVector p1new{ p1.e()<0?-p1:p1 }; CLHEP::HepLorentzVector p2new{ p2.e()<0?-p2:p2 }; if(h1!=h2){ return newT; } Spinor(p1new, h1, sp1); Spinor(p2new, h2, sp2); COM current[4]; for(int i=0; i<2;i++){ for(int j=0; j<2;j++){ current[0]+=conj(sp1[i])*sigma0[i][j]*sp2[j]; current[1]+=conj(sp1[i])*sigma1[i][j]*sp2[j]; current[2]+=conj(sp1[i])*sigma2[i][j]*sp2[j]; current[3]+=conj(sp1[i])*sigma3[i][j]*sp2[j]; } } for(int itensor=0;itensor<newT.len();itensor++){ double hfact = double(helfactor5[h2][itensor]); newT.components[itensor] = current[sigma_index5[itensor]] * hfact * permfactor5[itensor]; } return newT; } Tensor<1,4> Construct1Tensor(CCurrent j){ Tensor<1,4> newT; newT.components={j.c0,j.c1,j.c2,j.c3}; return newT; } Tensor<1,4> Construct1Tensor(CLHEP::HepLorentzVector p){ Tensor<1,4> newT; newT.components={p.e(),p.x(),p.y(),p.z()}; return newT; } Tensor<1,4> eps(CLHEP::HepLorentzVector k, CLHEP::HepLorentzVector ref, bool pol){ Tensor<1,4> polvec; COM spk[2]; COM spr[2]; COM denom; CLHEP::HepLorentzVector knew{ k.e()<0?-k:k }; Spinor(knew, pol, spk); Spinor(ref, !pol, spr); denom = pow(-1.,pol)*sqrt(2)*(conj(spr[0])*spk[0] + conj(spr[1])*spk[1]); polvec = TCurrent(ref,!pol,knew,!pol)/denom; return polvec; } // slow function! - but only need to evaluate once. bool init_sigma_index(){ // initialize permfactor(3) to list of ones (change to minus one for each odd // permutation and multiply by i for all permutations in perms2111, perms311, // perms111) permfactor5.resize(1024,1.); permfactor3.resize(64,1.); // first set sigma_index (5) std::vector<std::array<int,5>> sigma0indices; std::vector<std::array<int,5>> sigma1indices; std::vector<std::array<int,5>> sigma2indices; std::vector<std::array<int,5>> sigma3indices; // need to generate all possible permuations of {i,j,k,l,m} // where each index can be {0,1,2,3,4} // 1024 possibilities // perms with 5 same sigma0indices.push_back({0,0,0,0,0}); sigma1indices.push_back({1,1,1,1,1}); sigma2indices.push_back({2,2,2,2,2}); sigma3indices.push_back({3,3,3,3,3}); // perms with 4 same perms41(1,0,sigma0indices); perms41(2,0,sigma0indices); perms41(3,0,sigma0indices); perms41(0,1,sigma1indices); perms41(2,1,sigma1indices); perms41(3,1,sigma1indices); perms41(0,2,sigma2indices); perms41(1,2,sigma2indices); perms41(3,2,sigma2indices); perms41(0,3,sigma3indices); perms41(1,3,sigma3indices); perms41(2,3,sigma3indices); // perms with 3 same, 2 same perms32(0,1,sigma0indices); perms32(0,2,sigma0indices); perms32(0,3,sigma0indices); perms32(1,0,sigma1indices); perms32(1,2,sigma1indices); perms32(1,3,sigma1indices); perms32(2,0,sigma2indices); perms32(2,1,sigma2indices); perms32(2,3,sigma2indices); perms32(3,0,sigma3indices); perms32(3,1,sigma3indices); perms32(3,2,sigma3indices); // perms with 3 same, 2 different perms311(1,2,3,sigma0indices); perms311(2,3,1,sigma0indices); perms311(3,1,2,sigma0indices); perms311(0,2,3,sigma1indices); perms311(2,3,0,sigma1indices); perms311(3,2,0,sigma1indices); perms311(0,3,1,sigma2indices); perms311(1,3,0,sigma2indices); perms311(3,1,0,sigma2indices); perms311(0,1,2,sigma3indices); perms311(1,2,0,sigma3indices); perms311(2,1,0,sigma3indices); perms221(1,2,0,sigma0indices); perms221(1,3,0,sigma0indices); perms221(2,3,0,sigma0indices); perms221(0,2,1,sigma1indices); perms221(0,3,1,sigma1indices); perms221(2,3,1,sigma1indices); perms221(0,1,2,sigma2indices); perms221(0,3,2,sigma2indices); perms221(1,3,2,sigma2indices); perms221(0,1,3,sigma3indices); perms221(0,2,3,sigma3indices); perms221(1,2,3,sigma3indices); perms2111(0,1,2,3,sigma0indices); perms2111(1,0,2,3,sigma1indices); perms2111(2,0,3,1,sigma2indices); perms2111(3,0,1,2,sigma3indices); if(sigma0indices.size()!=256){ std::cerr<<"sigma_index not set: "; std::cerr<<"sigma0indices has "<< sigma0indices.size() << " components" << std::endl; return false; } else if(sigma1indices.size()!=256){ std::cerr<<"sigma_index not set: "; std::cerr<<"sigma1indices has "<< sigma0indices.size() << " components" << std::endl; return false; } else if(sigma2indices.size()!=256){ std::cerr<<"sigma_index not set: "; std::cerr<<"sigma2indices has "<< sigma0indices.size() << " components" << std::endl; return false; } else if(sigma3indices.size()!=256){ std::cerr<<"sigma_index not set: "; std::cerr<<"sigma3indices has "<< sigma0indices.size() << " components" << std::endl; return false; } for(int i=0;i<256;i++){ // map each unique set of tensor indices to its position in a list int index0 = tensor2listindex(sigma0indices.at(i)); int index1 = tensor2listindex(sigma1indices.at(i)); int index2 = tensor2listindex(sigma2indices.at(i)); int index3 = tensor2listindex(sigma3indices.at(i)); sigma_index5[index0]=0; sigma_index5[index1]=1; sigma_index5[index2]=2; sigma_index5[index3]=3; short int sign[4]={1,-1,-1,-1}; // plus->true->1 helfactor5[1][index0] = sign[sigma0indices.at(i)[1]] * sign[sigma0indices.at(i)[3]]; helfactor5[1][index1] = sign[sigma1indices.at(i)[1]] * sign[sigma1indices.at(i)[3]]; helfactor5[1][index2] = sign[sigma2indices.at(i)[1]] * sign[sigma2indices.at(i)[3]]; helfactor5[1][index3] = sign[sigma3indices.at(i)[1]] * sign[sigma3indices.at(i)[3]]; // minus->false->0 helfactor5[0][index0] = sign[sigma0indices.at(i)[0]] * sign[sigma0indices.at(i)[2]] * sign[sigma0indices.at(i)[4]]; helfactor5[0][index1] = sign[sigma1indices.at(i)[0]] * sign[sigma1indices.at(i)[2]] * sign[sigma1indices.at(i)[4]]; helfactor5[0][index2] = sign[sigma2indices.at(i)[0]] * sign[sigma2indices.at(i)[2]] * sign[sigma2indices.at(i)[4]]; helfactor5[0][index3] = sign[sigma3indices.at(i)[0]] * sign[sigma3indices.at(i)[2]] * sign[sigma3indices.at(i)[4]]; } // now set sigma_index3 std::vector<std::array<int,3>> sigma0indices3; std::vector<std::array<int,3>> sigma1indices3; std::vector<std::array<int,3>> sigma2indices3; std::vector<std::array<int,3>> sigma3indices3; // perms with 3 same sigma0indices3.push_back({0,0,0}); sigma1indices3.push_back({1,1,1}); sigma2indices3.push_back({2,2,2}); sigma3indices3.push_back({3,3,3}); // 2 same perms21(1,0,sigma0indices3); perms21(2,0,sigma0indices3); perms21(3,0,sigma0indices3); perms21(0,1,sigma1indices3); perms21(2,1,sigma1indices3); perms21(3,1,sigma1indices3); perms21(0,2,sigma2indices3); perms21(1,2,sigma2indices3); perms21(3,2,sigma2indices3); perms21(0,3,sigma3indices3); perms21(1,3,sigma3indices3); perms21(2,3,sigma3indices3); // none same perms111(1,2,3,sigma0indices3); perms111(0,2,3,sigma1indices3); perms111(0,3,1,sigma2indices3); perms111(0,1,2,sigma3indices3); if(sigma0indices3.size()!=16){ std::cerr<<"sigma_index3 not set: "; std::cerr<<"sigma0indices3 has "<< sigma0indices3.size() << " components" << std::endl; return false; } else if(sigma1indices3.size()!=16){ std::cerr<<"sigma_index3 not set: "; std::cerr<<"sigma1indices3 has "<< sigma0indices3.size() << " components" << std::endl; return false; } else if(sigma2indices3.size()!=16){ std::cerr<<"sigma_index3 not set: "; std::cerr<<"sigma2indices3 has "<< sigma0indices3.size() << " components" << std::endl; return false; } else if(sigma3indices3.size()!=16){ std::cerr<<"sigma_index3 not set: "; std::cerr<<"sigma3indices3 has "<< sigma0indices3.size() << " components" << std::endl; return false; } for(int i=0;i<16;i++){ int index0 = tensor2listindex(sigma0indices3.at(i)); int index1 = tensor2listindex(sigma1indices3.at(i)); int index2 = tensor2listindex(sigma2indices3.at(i)); int index3 = tensor2listindex(sigma3indices3.at(i)); sigma_index3[index0]=0; sigma_index3[index1]=1; sigma_index3[index2]=2; sigma_index3[index3]=3; short int sign[4]={1,-1,-1,-1}; // plus->true->1 helfactor3[1][index0] = sign[sigma0indices3.at(i)[1]]; helfactor3[1][index1] = sign[sigma1indices3.at(i)[1]]; helfactor3[1][index2] = sign[sigma2indices3.at(i)[1]]; helfactor3[1][index3] = sign[sigma3indices3.at(i)[1]]; // minus->false->0 helfactor3[0][index0] = sign[sigma0indices3.at(i)[0]] * sign[sigma0indices3.at(i)[2]]; helfactor3[0][index1] = sign[sigma1indices3.at(i)[0]] * sign[sigma1indices3.at(i)[2]]; helfactor3[0][index2] = sign[sigma2indices3.at(i)[0]] * sign[sigma2indices3.at(i)[2]]; helfactor3[0][index3] = sign[sigma3indices3.at(i)[0]] * sign[sigma3indices3.at(i)[2]]; } return true; } // end init_sigma_index diff --git a/src/Wjets.cc b/src/Wjets.cc index cf5ae44..ddd3d38 100644 --- a/src/Wjets.cc +++ b/src/Wjets.cc @@ -1,2067 +1,2072 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/currents.hh" #include "HEJ/utility.hh" #include "HEJ/Tensor.hh" #include "HEJ/Constants.hh" #include <array> #include <iostream> namespace { // Helper Functions // FKL W Helper Functions void jW (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin, current cur) { // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5) // Need to swap e and nu for events with W- --> e- nubar! if (helin==helout && hele==helnu) { CLHEP::HepLorentzVector qa=pout+pe+pnu; CLHEP::HepLorentzVector qb=pin-pe-pnu; double ta(qa.m2()),tb(qb.m2()); current t65,vout,vin,temp2,temp3,temp5; joo(pnu,helnu,pe,hele,t65); vout[0]=pout.e(); vout[1]=pout.x(); vout[2]=pout.y(); vout[3]=pout.z(); vin[0]=pin.e(); vin[1]=pin.x(); vin[2]=pin.y(); vin[3]=pin.z(); COM brac615=cdot(t65,vout); COM brac645=cdot(t65,vin); // prod1565 and prod6465 are zero for Ws (not Zs)!! // noalias(temp)=prod(trans(CurrentOutOut(pout,helout,pnu,helout)),metric); joo(pout,helout,pnu,helout,temp2); // noalias(temp2)=prod(temp,ctemp); COM prod1665=cdot(temp2,t65); // noalias(temp)=prod(trans(Current(pe,helin,pin,helin)),metric); // noalias(temp2)=prod(temp,ctemp); joi(pe,helin,pin,helin,temp3); COM prod5465=cdot(temp3,t65); // noalias(temp)=prod(trans(Current(pnu,helin,pin,helin)),metric); // noalias(temp2)=prod(temp,ctemp); joo(pout,helout,pe,helout,temp2); joi(pnu,helnu,pin,helin,temp3); joi(pout,helout,pin,helin,temp5); current term1,term2,term3,sum; cmult(2.*brac615/ta+2.*brac645/tb,temp5,term1); cmult(prod1665/ta,temp3,term2); cmult(-prod5465/tb,temp2,term3); // cur=((2.*brac615*Current(pout,helout,pin,helin)+prod1565*Current(pe,helin,pin,helin)+prod1665*Current(pnu,helin,pin,helin))/ta + (2.*brac645*Current(pout,helout,pin,helin)-prod5465*CurrentOutOut(pout,helout,pe,helout)-prod6465*CurrentOutOut(pout,helout,pnu,helout))/tb); // cur=((2.*brac615*temp5+prod1565*temp3+prod1665*temp4)/ta + (2.*brac645*temp5-prod5465*temp1-prod6465*temp2)/tb); cadd(term1,term2,term3,sum); // std::cout<<"sum: ("<<sum[0]<<","<<sum[1]<<","<<sum[2]<<","<<sum[3]<<")\n"; cur[0]=sum[0]; cur[1]=sum[1]; cur[2]=sum[2]; cur[3]=sum[3]; } } void jWbar (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin, current cur) { // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5) // Need to swap e and nu for events with W- --> e- nubar! if (helin==helout && hele==helnu) { CLHEP::HepLorentzVector qa=pout+pe+pnu; CLHEP::HepLorentzVector qb=pin-pe-pnu; double ta(qa.m2()),tb(qb.m2()); current t65,vout,vin,temp2,temp3,temp5; joo(pnu,helnu,pe,hele,t65); vout[0]=pout.e(); vout[1]=pout.x(); vout[2]=pout.y(); vout[3]=pout.z(); vin[0]=pin.e(); vin[1]=pin.x(); vin[2]=pin.y(); vin[3]=pin.z(); COM brac615=cdot(t65,vout); COM brac645=cdot(t65,vin); // prod1565 and prod6465 are zero for Ws (not Zs)!! joo(pe,helout,pout,helout,temp2); // temp2 is <5|alpha|1> COM prod5165=cdot(temp2,t65); jio(pin,helin,pnu,helin,temp3); // temp3 is <4|alpha|6> COM prod4665=cdot(temp3,t65); joo(pnu,helout,pout,helout,temp2); // temp2 is now <6|mu|1> jio(pin,helin,pe,helin,temp3); // temp3 is now <4|mu|5> jio(pin,helin,pout,helout,temp5); // temp5 is <4|mu|1> current term1,term2,term3,sum; cmult(-2.*brac615/ta-2.*brac645/tb,temp5,term1); cmult(-prod5165/ta,temp3,term2); cmult(prod4665/tb,temp2,term3); // cur=((2.*brac615*Current(pout,helout,pin,helin)+prod1565*Current(pe,helin,pin,helin)+prod1665*Current(pnu,helin,pin,helin))/ta + (2.*brac645*Current(pout,helout,pin,helin)-prod5465*CurrentOutOut(pout,helout,pe,helout)-prod6465*CurrentOutOut(pout,helout,pnu,helout))/tb); // cur=((2.*brac615*temp5+prod1565*temp3+prod1665*temp4)/ta + (2.*brac645*temp5-prod5465*temp1-prod6465*temp2)/tb); cadd(term1,term2,term3,sum); // std::cout<<"term1: ("<<temp5[0]<<" "<<temp5[1]<<" "<<temp5[2]<<" "<<temp5[3]<<")"<<std::endl; // std::cout<<"sum: ("<<sum[0]<<","<<sum[1]<<","<<sum[2]<<","<<sum[3]<<")\n"; cur[0]=sum[0]; cur[1]=sum[1]; cur[2]=sum[2]; cur[3]=sum[3]; } } double WProp (const CLHEP::HepLorentzVector & plbar, const CLHEP::HepLorentzVector & pl){ COM propW = COM(0.,-1.)/((pl+plbar).m2() -HEJ::MW*HEJ::MW + COM(0.,1.)*HEJ::MW*HEJ::GammaW); double PropFactor=(propW*conj(propW)).real(); return PropFactor; } CCurrent jW (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin) { COM cur[4]; cur[0]=0.; cur[1]=0.; cur[2]=0.; cur[3]=0.; CCurrent sum(0.,0.,0.,0.); // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5) // Need to swap e and nu for events with W- --> e- nubar! if (helin==helout && hele==helnu) { CLHEP::HepLorentzVector qa=pout+pe+pnu; CLHEP::HepLorentzVector qb=pin-pe-pnu; double ta(qa.m2()),tb(qb.m2()); CCurrent temp2,temp3,temp5; CCurrent t65 = joo(pnu,helnu,pe,hele); CCurrent vout(pout.e(),pout.x(),pout.y(),pout.z()); CCurrent vin(pin.e(),pin.x(),pin.y(),pin.z()); COM brac615=t65.dot(vout); COM brac645=t65.dot(vin); // prod1565 and prod6465 are zero for Ws (not Zs)!! temp2 = joo(pout,helout,pnu,helout); COM prod1665=temp2.dot(t65); temp3 = joi(pe,helin,pin,helin); COM prod5465=temp3.dot(t65); temp2=joo(pout,helout,pe,helout); temp3=joi(pnu,helnu,pin,helin); temp5=joi(pout,helout,pin,helin); CCurrent term1,term2,term3; term1=(2.*brac615/ta+2.*brac645/tb)*temp5; term2=(prod1665/ta)*temp3; term3=(-prod5465/tb)*temp2; sum=term1+term2+term3; } return sum; } CCurrent jWbar (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pe, bool hele, CLHEP::HepLorentzVector pnu, bool helnu, CLHEP::HepLorentzVector pin, bool helin) { COM cur[4]; cur[0]=0.; cur[1]=0.; cur[2]=0.; cur[3]=0.; CCurrent sum(0.,0.,0.,0.); // NOTA BENE: Conventions for W+ --> e+ nu, so that nu is lepton(6), e is anti-lepton(5) // Need to swap e and nu for events with W- --> e- nubar! if (helin==helout && hele==helnu) { CLHEP::HepLorentzVector qa=pout+pe+pnu; CLHEP::HepLorentzVector qb=pin-pe-pnu; double ta(qa.m2()),tb(qb.m2()); CCurrent temp2,temp3,temp5; CCurrent t65 = joo(pnu,helnu,pe,hele); CCurrent vout(pout.e(),pout.x(),pout.y(),pout.z()); CCurrent vin(pin.e(),pin.x(),pin.y(),pin.z()); COM brac615=t65.dot(vout); COM brac645=t65.dot(vin); // prod1565 and prod6465 are zero for Ws (not Zs)!! temp2 = joo(pe,helout,pout,helout); // temp2 is <5|alpha|1> COM prod5165=temp2.dot(t65); temp3 = jio(pin,helin,pnu,helin); // temp3 is <4|alpha|6> COM prod4665=temp3.dot(t65); temp2=joo(pnu,helout,pout,helout); // temp2 is now <6|mu|1> temp3=jio(pin,helin,pe,helin); // temp3 is now <4|mu|5> temp5=jio(pin,helin,pout,helout); // temp5 is <4|mu|1> CCurrent term1,term2,term3; term1 =(-2.*brac615/ta-2.*brac645/tb)*temp5; term2 =(-prod5165/ta)*temp3; term3 =(prod4665/tb)*temp2; sum = term1 + term2 + term3; } return sum; } // Extremal quark current with W emission. Using Tensor class rather than CCurrent Tensor <1,4> jW(HLV pin, HLV pout, HLV plbar, HLV pl, bool aqline){ // Build the external quark line W Emmision Tensor<1,4> ABCurr = TCurrent(pl, false, plbar, false); Tensor<1,4> Tp4W = Construct1Tensor((pout+pl+plbar));//p4+pw Tensor<1,4> TpbW = Construct1Tensor((pin-pl-plbar));//pb-pw Tensor<3,4> J4bBlank; if (aqline){ J4bBlank = T3Current(pin,false,pout,false); } else{ J4bBlank = T3Current(pout,false,pin,false); } double t4AB = (pout+pl+plbar).m2(); double tbAB = (pin-pl-plbar).m2(); Tensor<2,4> J4b1 = (J4bBlank.contract(Tp4W,2))/t4AB; Tensor<2,4> J4b2 = (J4bBlank.contract(TpbW,2))/tbAB; Tensor<2,4> T4bmMom(0.); if (aqline){ for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ T4bmMom.Set(mu,nu, (J4b1.at(nu,mu) + J4b2.at(mu,nu))*(COM(0,-1))); } } } else{ for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ T4bmMom.Set(nu,mu, (J4b1.at(nu,mu) + J4b2.at(mu,nu))*(COM(0,1))); } } } Tensor<1,4> T4bm = T4bmMom.contract(ABCurr,1); return T4bm; } // Relevant W+Jets Unordered Contribution Helper Functions // W+Jets Uno double jM2Wuno(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector plbar, CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pa, bool h1, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector pb, bool h2, bool pol) { static bool is_sigma_index_set(false); if(!is_sigma_index_set){ //std::cout<<"Setting sigma_index...." << std::endl; if(init_sigma_index()) is_sigma_index_set = true; else return 0.; } CLHEP::HepLorentzVector pW = pl+plbar; CLHEP::HepLorentzVector q1g=pa-pW-p1-pg; CLHEP::HepLorentzVector q1 = pa-p1-pW; CLHEP::HepLorentzVector q2 = p2-pb; const double taW = (pa-pW).m2(); const double taW1 = (pa-pW-p1).m2(); const double tb2 = (pb-p2).m2(); const double tb2g = (pb-p2-pg).m2(); const double s1W = (p1+pW).m2(); const double s1gW = (p1+pW+pg).m2(); const double s1g = (p1+pg).m2(); const double tag = (pa-pg).m2(); const double taWg = (pa-pW-pg).m2(); //use p1 as ref vec in pol tensor Tensor<1,4> epsg = eps(pg,p2,pol); Tensor<1,4> epsW = TCurrent(pl,false,plbar,false); Tensor<1,4> j2b = TCurrent(p2,h2,pb,h2); Tensor<1,4> Tq1q2 = Construct1Tensor((q1+q2)/taW1 + (pb/pb.dot(pg) + p2/p2.dot(pg)) * tb2/(2*tb2g)); Tensor<1,4> Tq1g = Construct1Tensor((-pg-q1))/taW1; Tensor<1,4> Tq2g = Construct1Tensor((pg-q2)); Tensor<1,4> TqaW = Construct1Tensor((pa-pW));//pa-pw Tensor<1,4> Tqag = Construct1Tensor((pa-pg)); Tensor<1,4> TqaWg = Construct1Tensor((pa-pg-pW)); Tensor<1,4> Tp1g = Construct1Tensor((p1+pg)); Tensor<1,4> Tp1W = Construct1Tensor((p1+pW));//p1+pw Tensor<1,4> Tp1gW = Construct1Tensor((p1+pg+pW));//p1+pw+pg Tensor<2,4> g=Metric(); Tensor<3,4> J31a = T3Current(p1, h1, pa, h1); Tensor<2,4> J2_qaW =J31a.contract(TqaW/taW, 2); Tensor<2,4> J2_p1W =J31a.contract(Tp1W/s1W, 2); Tensor<3,4> L1a =J2_qaW.leftprod(Tq1q2); Tensor<3,4> L1b =J2_p1W.leftprod(Tq1q2); Tensor<3,4> L2a = J2_qaW.leftprod(Tq1g); Tensor<3,4> L2b = J2_p1W.leftprod(Tq1g); Tensor<3,4> L3 = (g.rightprod(J2_qaW.contract(Tq2g,1)+J2_p1W.contract(Tq2g,2)))/taW1; Tensor<3,4> L(0.); Tensor<5,4> J51a = T5Current(p1, h1, pa, h1); Tensor<4,4> J_qaW = J51a.contract(TqaW,4); Tensor<4,4> J_qag = J51a.contract(Tqag,4); Tensor<4,4> J_p1gW = J51a.contract(Tp1gW,4); Tensor<3,4> U1a = J_qaW.contract(Tp1g,2); Tensor<3,4> U1b = J_p1gW.contract(Tp1g,2); Tensor<3,4> U1c = J_p1gW.contract(Tp1W,2); Tensor<3,4> U1(0.); Tensor<3,4> U2a = J_qaW.contract(TqaWg,2); Tensor<3,4> U2b = J_qag.contract(TqaWg,2); Tensor<3,4> U2c = J_qag.contract(Tp1W,2); Tensor<3,4> U2(0.); for(int nu=0; nu<4;nu++){ for(int mu=0;mu<4;mu++){ for(int rho=0;rho<4;rho++){ L.Set(nu, mu, rho, L1a.at(nu,mu,rho) + L1b.at(nu,rho,mu) + L2a.at(mu,nu,rho) + L2b.at(mu,rho,nu) + L3.at(mu,nu,rho)); U1.Set(nu, mu, rho, U1a.at(nu, mu, rho) / (s1g*taW) + U1b.at(nu,rho,mu) / (s1g*s1gW) + U1c.at(rho,nu,mu) / (s1W*s1gW)); U2.Set(nu,mu,rho,U2a.at(mu,nu,rho) / (taWg*taW) + U2b.at(mu,rho,nu) / (taWg*tag) + U2c.at(rho,mu,nu) / (s1W*tag)); } } } COM X = ((((U1-L).contract(epsW,3)).contract(j2b,2)).contract(epsg,1)).at(0); COM Y = ((((U2+L).contract(epsW,3)).contract(j2b,2)).contract(epsg,1)).at(0); double amp = HEJ::C_A*HEJ::C_F*HEJ::C_F/2.*(norm(X)+norm(Y)) - HEJ::C_F/2.*(X*conj(Y)).real(); double t1 = q1g.m2(); double t2 = q2.m2(); double WPropfact = WProp(plbar, pl); //Divide by WProp amp*=WPropfact; //Divide by t-channels amp/=(t1*t2); //Average over initial states amp/=(4.*HEJ::C_A*HEJ::C_A); return amp; } // Relevant Wqqx Helper Functions. //g->qxqlxl (Calculates gluon to qqx Current. See JV_\mu in WSubleading Notes) Tensor <1,4> gtqqxW(CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar){ double s2AB=(pl+plbar+pq).m2(); double s3AB=(pl+plbar+pqbar).m2(); Tensor<1,4> Tpq = Construct1Tensor(pq); Tensor<1,4> Tpqbar = Construct1Tensor(pqbar); Tensor<1,4> TAB = Construct1Tensor(pl+plbar); // Define llx current. Tensor<1,4> ABCur = TCurrent(pl, false, plbar, false); //blank 3 Gamma Current Tensor<3,4> JV23 = T3Current(pq,false,pqbar,false); // Components of g->qqW before W Contraction Tensor<2,4> JV1 = JV23.contract((Tpq + TAB),2)/(s2AB); Tensor<2,4> JV2 = JV23.contract((Tpqbar + TAB),2)/(s3AB); // g->qqW Current. Note Minus between terms due to momentum flow. // Also note: (-I)^2 from W vert. (I) from Quark prop. Tensor<1,4> JVCur = (JV1.contract(ABCur,1) - JV2.contract(ABCur,2))*COM(0.,-1.); return JVCur; } // Helper Functions Calculate the Crossed Contribution Tensor <2,4> MCrossW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){ // Useful propagator factors double s2AB=(pl+plbar+pq).m2(); double s3AB=(pl+plbar+pqbar).m2(); CLHEP::HepLorentzVector q1, q3; q1=pa; for(int i=0; i<nabove+1;i++){ q1=q1-partons.at(i); } q3 = q1 - pq - pqbar - pl - plbar; double tcro1=(q3+pq).m2(); double tcro2=(q1-pqbar).m2(); Tensor<1,4> Tp1 = Construct1Tensor(p1); Tensor<1,4> Tp4 = Construct1Tensor(p4); Tensor<1,4> Tpa = Construct1Tensor(pa); Tensor<1,4> Tpb = Construct1Tensor(pb); Tensor<1,4> Tpq = Construct1Tensor(pq); Tensor<1,4> Tpqbar = Construct1Tensor(pqbar); Tensor<1,4> TAB = Construct1Tensor(pl+plbar); Tensor<1,4> Tq1 = Construct1Tensor(q1); Tensor<1,4> Tq3 = Construct1Tensor(q3); Tensor<2,4> g=Metric(); // Define llx current. Tensor<1,4> ABCur = TCurrent(pl, false, plbar,false); //Blank 5 gamma Current Tensor<5,4> J523 = T5Current(pq,false,pqbar,false); // 4 gamma currents (with 1 contraction already). Tensor<4,4> J_q3q = J523.contract((Tq3+Tpq),2); Tensor<4,4> J_2AB = J523.contract((Tpq+TAB),2); // Components of Crossed Vertex Contribution Tensor<3,4> Xcro1 = J_q3q.contract((Tpqbar + TAB),3); Tensor<3,4> Xcro2 = J_q3q.contract((Tq1-Tpqbar),3); Tensor<3,4> Xcro3 = J_2AB.contract((Tq1-Tpqbar),3); // Term Denominators Taken Care of at this stage Tensor<2,4> Xcro1Cont = Xcro1.contract(ABCur,3)/(tcro1*s3AB); Tensor<2,4> Xcro2Cont = Xcro2.contract(ABCur,2)/(tcro1*tcro2); Tensor<2,4> Xcro3Cont = Xcro3.contract(ABCur,1)/(s2AB*tcro2); //Initialise the Crossed Vertex Object Tensor<2,4> Xcro(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xcro.Set(mu,nu, -(-Xcro1Cont.at(nu,mu)+Xcro2Cont.at(nu,mu)+Xcro3Cont.at(nu,mu))); } } return Xcro; } // Helper Functions Calculate the Uncrossed Contribution Tensor <2,4> MUncrossW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){ double s2AB=(pl+plbar+pq).m2(); double s3AB=(pl+plbar+pqbar).m2(); CLHEP::HepLorentzVector q1, q3; q1=pa; for(int i=0; i<nabove+1;i++){ q1=q1-partons.at(i); } q3 = q1 - pl - plbar - pq - pqbar; double tunc1 = (q1-pq).m2(); double tunc2 = (q3+pqbar).m2(); Tensor<1,4> Tp1 = Construct1Tensor(p1); Tensor<1,4> Tp4 = Construct1Tensor(p4); Tensor<1,4> Tpa = Construct1Tensor(pa); Tensor<1,4> Tpb = Construct1Tensor(pb); Tensor<1,4> Tpq = Construct1Tensor(pq); Tensor<1,4> Tpqbar = Construct1Tensor(pqbar); Tensor<1,4> TAB = Construct1Tensor(pl+plbar); Tensor<1,4> Tq1 = Construct1Tensor(q1); Tensor<1,4> Tq3 = Construct1Tensor(q3); Tensor<2,4> g=Metric(); // Define llx current. Tensor<1,4> ABCur = TCurrent(pl, false, plbar, false); //Blank 5 gamma Current Tensor<5,4> J523 = T5Current(pq,false,pqbar,false); // 4 gamma currents (with 1 contraction already). Tensor<4,4> J_2AB = J523.contract((Tpq+TAB),2); Tensor<4,4> J_q1q = J523.contract((Tq1-Tpq),2); // 2 Contractions taken care of. Tensor<3,4> Xunc1 = J_2AB.contract((Tq3+Tpqbar),3); Tensor<3,4> Xunc2 = J_q1q.contract((Tq3+Tpqbar),3); Tensor<3,4> Xunc3 = J_q1q.contract((Tpqbar+TAB),3); // Term Denominators Taken Care of at this stage Tensor<2,4> Xunc1Cont = Xunc1.contract(ABCur,1)/(s2AB*tunc2); Tensor<2,4> Xunc2Cont = Xunc2.contract(ABCur,2)/(tunc1*tunc2); Tensor<2,4> Xunc3Cont = Xunc3.contract(ABCur,3)/(tunc1*s3AB); //Initialise the Uncrossed Vertex Object Tensor<2,4> Xunc(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xunc.Set(mu,nu,-(- Xunc1Cont.at(mu,nu)+Xunc2Cont.at(mu,nu) +Xunc3Cont.at(mu,nu))); } } return Xunc; } // Helper Functions Calculate the g->qqxW (Eikonal) Contributions Tensor <2,4> MSymW(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, int nabove){ double sa2=(pa+pq).m2(); double s12=(p1+pq).m2(); double sa3=(pa+pqbar).m2(); double s13=(p1+pqbar).m2(); double saA=(pa+pl).m2(); double s1A=(p1+pl).m2(); double saB=(pa+plbar).m2(); double s1B=(p1+plbar).m2(); double sb2=(pb+pq).m2(); double s42=(p4+pq).m2(); double sb3=(pb+pqbar).m2(); double s43=(p4+pqbar).m2(); double sbA=(pb+pl).m2(); double s4A=(p4+pl).m2(); double sbB=(pb+plbar).m2(); double s4B=(p4+plbar).m2(); double s23AB=(pl+plbar+pq+pqbar).m2(); CLHEP::HepLorentzVector q1,q3; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } q3=q1-pq-pqbar-plbar-pl; double t1 = (q1).m2(); double t3 = (q3).m2(); //Define Tensors to be used Tensor<1,4> Tp1 = Construct1Tensor(p1); Tensor<1,4> Tp4 = Construct1Tensor(p4); Tensor<1,4> Tpa = Construct1Tensor(pa); Tensor<1,4> Tpb = Construct1Tensor(pb); Tensor<1,4> Tpq = Construct1Tensor(pq); Tensor<1,4> Tpqbar = Construct1Tensor(pqbar); Tensor<1,4> TAB = Construct1Tensor(pl+plbar); Tensor<1,4> Tq1 = Construct1Tensor(q1); Tensor<1,4> Tq3 = Construct1Tensor(q3); Tensor<2,4> g=Metric(); // g->qqW Current (Factors of sqrt2 dealt with in this function.) Tensor<1,4> JV = gtqqxW(pq,pqbar,pl,plbar); // 1a gluon emisson Contribution Tensor<3,4> X1a = g.rightprod(Tp1*(t1/(s12+s13+s1A+s1B)) + Tpa*(t1/(sa2+sa3+saA+saB))); Tensor<2,4> X1aCont = X1a.contract(JV,3); //4b gluon emission Contribution Tensor<3,4> X4b = g.rightprod(Tp4*(t3/(s42+s43+s4A+s4B)) + Tpb*(t3/(sb2+sb3+sbA+sbB))); Tensor<2,4> X4bCont = X4b.contract(JV,3); //Set up each term of 3G diagram. Tensor<3,4> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar+TAB); Tensor<3,4> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar-TAB); Tensor<3,4> X3g3 = g.leftprod((Tq1+Tq3)); // Note the contraction of indices changes term by term Tensor<2,4> X3g1Cont = X3g1.contract(JV,3); Tensor<2,4> X3g2Cont = X3g2.contract(JV,2); Tensor<2,4> X3g3Cont = X3g3.contract(JV,1); // XSym is an amalgamation of x1a, X4b and X3g. Makes sense from a colour factor point of view. Tensor<2,4>Xsym(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xsym.Set(mu,nu, (X3g1Cont.at(nu,mu) + X3g2Cont.at(mu,nu) - X3g3Cont.at(nu,mu)) + (X1aCont.at(mu,nu) - X4bCont.at(mu,nu)) ); } } return Xsym/s23AB; } Tensor <2,4> MCross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){ CLHEP::HepLorentzVector q1; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } double t2=(q1-pqbar).m2(); Tensor<1,4> Tq1 = Construct1Tensor(q1-pqbar); //Blank 3 gamma Current Tensor<3,4> J323 = T3Current(pq,hq,pqbar,hq); // 2 gamma current (with 1 contraction already). Tensor<2,4> XCroCont = J323.contract((Tq1),2)/(t2); //Initialise the Crossed Vertex Tensor<2,4> Xcro(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xcro.Set(mu,nu, (XCroCont.at(nu,mu))); } } return Xcro; } // Helper Functions Calculate the Uncrossed Contribution Tensor <2,4> MUncross(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){ CLHEP::HepLorentzVector q1; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } double t2 = (q1-pq).m2(); Tensor<1,4> Tq1 = Construct1Tensor(q1-pq); //Blank 3 gamma Current Tensor<3,4> J323 = T3Current(pq,hq,pqbar,hq); // 2 gamma currents (with 1 contraction already). Tensor<2,4> XUncCont = J323.contract((Tq1),2)/t2; //Initialise the Uncrossed Vertex Tensor<2,4> Xunc(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xunc.Set(mu,nu,-(XUncCont.at(mu,nu))); } } return Xunc; } // Helper Functions Calculate the Eikonal Contributions Tensor <2,4> MSym(CLHEP::HepLorentzVector pa,CLHEP::HepLorentzVector p1,CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector p4, CLHEP::HepLorentzVector pq,CLHEP::HepLorentzVector pqbar, std::vector<HLV> partons, bool hq, int nabove){ CLHEP::HepLorentzVector q1, q3; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } q3 = q1-pq-pqbar; double t1 = (q1).m2(); double t3 = (q3).m2(); double s23 = (pq+pqbar).m2(); double sa2 = (pa+pq).m2(); double sa3 = (pa+pqbar).m2(); double s12 = (p1+pq).m2(); double s13 = (p1+pqbar).m2(); double sb2 = (pb+pq).m2(); double sb3 = (pb+pqbar).m2(); double s42 = (p4+pq).m2(); double s43 = (p4+pqbar).m2(); //Define Tensors to be used Tensor<1,4> Tp1 = Construct1Tensor(p1); Tensor<1,4> Tp4 = Construct1Tensor(p4); Tensor<1,4> Tpa = Construct1Tensor(pa); Tensor<1,4> Tpb = Construct1Tensor(pb); Tensor<1,4> Tpq = Construct1Tensor(pq); Tensor<1,4> Tpqbar = Construct1Tensor(pqbar); Tensor<1,4> Tq1 = Construct1Tensor(q1); Tensor<1,4> Tq3 = Construct1Tensor(q3); Tensor<2,4> g=Metric(); Tensor<1,4> qqxCur = TCurrent(pq, hq, pqbar, hq); // // 1a gluon emisson Contribution Tensor<3,4> X1a = g.rightprod(Tp1*(t1/(s12+s13))+Tpa*(t1/(sa2+sa3))); Tensor<2,4> X1aCont = X1a.contract(qqxCur,3); // //4b gluon emission Contribution Tensor<3,4> X4b = g.rightprod(Tp4*(t3/(s42+s43)) + Tpb*(t3/(sb2+sb3))); Tensor<2,4> X4bCont = X4b.contract(qqxCur,3); // New Formulation Corresponding to New Analytics Tensor<3,4> X3g1 = g.leftprod(Tq1+Tpq+Tpqbar); Tensor<3,4> X3g2 = g.leftprod(Tq3-Tpq-Tpqbar); Tensor<3,4> X3g3 = g.leftprod((Tq1+Tq3)); // Note the contraction of indices changes term by term Tensor<2,4> X3g1Cont = X3g1.contract(qqxCur,3); Tensor<2,4> X3g2Cont = X3g2.contract(qqxCur,2); Tensor<2,4> X3g3Cont = X3g3.contract(qqxCur,1); Tensor<2,4>Xsym(0.); for(int mu=0; mu<4;mu++){ for(int nu=0;nu<4;nu++){ Xsym.Set(mu, nu, COM(0,1) * ( (X3g1Cont.at(nu,mu) + X3g2Cont.at(mu,nu) - X3g3Cont.at(nu,mu)) + (X1aCont.at(mu,nu) - X4bCont.at(mu,nu)) ) ); } } return Xsym/s23; } } // Anonymous Namespace helper functions // W+Jets FKL Contributions double jMWqQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { current mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf^2 return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } double jMWqQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { current mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m); jio(p2in,true,p2out,true,mj2p); jio(p2in,false,p2out,false,mj2m); COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf^2 return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } double jMWqbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { current mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf^2 return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } double jMWqbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { current mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m); jio(p2in,true,p2out,true,mj2p); jio(p2in,false,p2out,false,mj2m); COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf^2 return HEJ::C_F*HEJ::C_F*WPropfact*(a2Mmp+a2Mmm)/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } double jMWqg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qg->qenug scattering // p1: quark // p2: gluon { CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj2p,mj2m; jW(p1out,false,pe,false,pnu,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); // mj1m.mj2p COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); const double K = K_g(p2out, p2in); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double sst = K/HEJ::C_A*(a2Mmp+a2Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf*Ca=4 return HEJ::C_F*HEJ::C_A*WPropfact*sst/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } double jMWqbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qg->qenug scattering // p1: quark // p2: gluon { CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj2p,mj2m; jWbar(p1out,false,pe,false,pnu,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); // mj1m.mj2p COM Mmp=cdot(mj1m,mj2p); // mj1m.mj2m COM Mmm=cdot(mj1m,mj2m); const double K = K_g(p2out, p2in); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double sst = K/HEJ::C_A*(a2Mmp+a2Mmm); double WPropfact = WProp(pe, pnu); // Division by colour and Helicity average (Nc2-1)(4) // Multiply by Cf*Ca=4 return HEJ::C_F*HEJ::C_A*WPropfact*sst/(q1.m2()*q2.m2()*(HEJ::N_C*HEJ::N_C - 1)*4); } // W+Jets Unordered Contributions //qQ->qQWg_unob double junobMWqQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); CLHEP::HepLorentzVector q3=-(p2in-p2out); mj1m=jW(p1out,false,pe,false,pnu,false,p1in,false); mj2p=joi(p2out,true,p2in,true); mj2m=joi(p2out,false,p2in,false); // Dot products of these which occur again and again COM MWmp=mj1m.dot(mj2p); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(p2out,true,pg,true); j2gm=joo(p2out,false,pg,false); jgbp=joi(pg,true,p2in,true); jgbm=joi(pg,false,p2in,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2(); U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2(); double amm,amp; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp); double ampsq=-(amm+amp); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*q1.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qQbar->qQbarWg_unob double junobMWqQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); CLHEP::HepLorentzVector q3=-(p2in-p2out); mj1m=jW(p1out,false,pe,false,pnu,false,p1in,false); mj2p=jio(p2in,true,p2out,true); mj2m=jio(p2in,false,p2out,false); // Dot products of these which occur again and again COM MWmp=mj1m.dot(mj2p); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(pg,true,p2out,true); j2gm=joo(pg,false,p2out,false); jgbp=jio(p2in,true,pg,true); jgbm=jio(p2in,false,pg,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2(); U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2(); double amm,amp; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp); double ampsq=-(amm+amp); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*q1.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qbarQ->qbarQWg_unob double junobMWqbarQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); CLHEP::HepLorentzVector q3=-(p2in-p2out); mj1m=jWbar(p1out,false,pe,false,pnu,false,p1in,false); mj2p=joi(p2out,true,p2in,true); mj2m=joi(p2out,false,p2in,false); // Dot products of these which occur again and again COM MWmp=mj1m.dot(mj2p); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(p2out,true,pg,true); j2gm=joo(p2out,false,pg,false); jgbp=joi(pg,true,p2in,true); jgbm=joi(pg,false,p2in,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2(); U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2(); double amm,amp; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp); double ampsq=-(amm+amp); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*q1.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qbarQbar->qbarQbarWg_unob double junobMWqbarQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pg) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj1m,mj2p,mj2m; CLHEP::HepLorentzVector q1=p1in-p1out-pe-pnu; CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); CLHEP::HepLorentzVector q3=-(p2in-p2out); mj1m=jWbar(p1out,false,pe,false,pnu,false,p1in,false); mj2p=jio(p2in,true,p2out,true); mj2m=jio(p2in,false,p2out,false); // Dot products of these which occur again and again COM MWmp=mj1m.dot(mj2p); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(pg,true,p2out,true); j2gm=joo(pg,false,p2out,false); jgbp=jio(p2in,true,pg,true); jgbm=jio(p2in,false,pg,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); Lmm=((-1.)*qsum*(MWmm) + (-2.*mj1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MWmp) + (-2.*mj1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mj1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MWmp/2.))/q3.m2(); U1mm=(jgbm.dot(mj1m)*j2gm+2.*p2o*MWmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mj1m)*j2gp+2.*p2o*MWmp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj1m)*jgbm+2.*p2i*MWmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mj1m)*jgbp+2.*p2i*MWmp)/(p2in-pg).m2(); double amm,amp; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); amp=HEJ::C_F*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mp+U2mp); double ampsq=-(amm+amp); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*q1.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //////////////////////////////////////////////////////////////////// //qQ->qQWg_unof double junofMWgqQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj2m,mj1p,mj1m; CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector qg=p1in-p1out-pg; CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu); mj2m=jW(p2out,false,pe,false,pnu,false,p2in,false); mj1p=joi(p1out,true,p1in,true); mj1m=joi(p1out,false,p1in,false); // Dot products of these which occur again and again COM MWpm=mj1p.dot(mj2m); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(p1out,true,pg,true); j2gm=joo(p1out,false,pg,false); jgap=joi(pg,true,p1in,true); jgam=joi(pg,false,p1in,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2(); Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2(); U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2(); U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2(); double amm,apm; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm); double ampsq=-(apm+amm); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*qg.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qQbar->qQbarWg_unof double junofMWgqQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj2m,mj1p,mj1m; CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector qg=p1in-p1out-pg; CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu); mj2m=jWbar(p2out,false,pe,false,pnu,false,p2in,false); mj1p=joi(p1out,true,p1in,true); mj1m=joi(p1out,false,p1in,false); // Dot products of these which occur again and again COM MWpm=mj1p.dot(mj2m); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(p1out,true,pg,true); j2gm=joo(p1out,false,pg,false); jgap=joi(pg,true,p1in,true); jgam=joi(pg,false,p1in,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2(); Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2(); U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2(); U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2(); double amm,apm; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm); double ampsq=-(apm+amm); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*qg.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qbarQ->qbarQWg_unof double junofMWgqbarQ (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj2m,mj1p,mj1m; CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector qg=p1in-p1out-pg; CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu); mj2m=jW(p2out,false,pe,false,pnu,false,p2in,false); mj1p=jio(p1in,true,p1out,true); mj1m=jio(p1in,false,p1out,false); // Dot products of these which occur again and again COM MWpm=mj1p.dot(mj2m); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(pg,true,p1out,true); j2gm=joo(pg,false,p1out,false); jgap=jio(p1in,true,pg,true); jgam=jio(p1in,false,pg,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2(); Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2(); U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2(); U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2(); double amm,apm; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm); double ampsq=-(apm+amm); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*qg.m2(); ampsq/=th; ampsq/=16.; return ampsq; } //qbarQbar->qbarQbarWg_unof double junofMWgqbarQbar (CLHEP::HepLorentzVector pg,CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector pe, CLHEP::HepLorentzVector pnu, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qQ->qenuQ scattering // p1: quark (with W emittance) // p2: Quark { CCurrent mj2m,mj1p,mj1m; CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector qg=p1in-p1out-pg; CLHEP::HepLorentzVector q2=-(p2in-p2out-pe-pnu); mj2m=jWbar(p2out,false,pe,false,pnu,false,p2in,false); mj1p=jio(p1in,true,p1out,true); mj1m=jio(p1in,false,p1out,false); // Dot products of these which occur again and again COM MWpm=mj1p.dot(mj2m); // And now for the Higgs ones COM MWmm=mj1m.dot(mj2m); CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(pg,true,p1out,true); j2gm=joo(pg,false,p1out,false); jgap=jio(p1in,true,pg,true); jgam=jio(p1in,false,pg,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MWmm) + (-2.*mj2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWmm/2.))/q1.m2(); Lpm=(qsum*(MWpm) + (-2.*mj2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mj2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MWpm/2.))/q1.m2(); U1mm=(jgam.dot(mj2m)*j2gm+2.*p1o*MWmm)/(p1out+pg).m2(); U1pm=(jgap.dot(mj2m)*j2gp+2.*p1o*MWpm)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mj2m)*jgam+2.*p1i*MWmm)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mj2m)*jgap+2.*p1i*MWpm)/(p1in-pg).m2(); double amm,apm; amm=HEJ::C_F*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1mm+U2mm); apm=HEJ::C_F*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*HEJ::C_F*HEJ::C_F/3.*vabs2(U1pm+U2pm); double ampsq=-(apm+amm); //Divide by WProp double WPropfact = WProp(pe, pnu); ampsq*=WPropfact; // Now add the t-channels double th=q2.m2()*qg.m2(); ampsq/=th; ampsq/=16.; return ampsq; } ///TODO make this comment more visible /// Naming scheme jM2-Wuno-g-({q/qbar}{Q/Qbar/g}) ///TODO Spit naming for more complicated functions? /// e.g. jM2WqqtoqQQq -> jM2_Wqq_to_qQQq double jM2WunogqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; return ME2; } //same as function above but actually obtaining the antiquark line by crossing symmetry, where p1out and p1in are expected to be negative. //should give same result as jM2WunogqbarQ below (verified) double jM2WunogqQ_crossqQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; return ME2; } double jM2WunogqQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; return ME2; } double jM2Wunogqg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; double ratio; // p2-/pb- in the notes if (p2in.pz()>0.) // if the gluon is the positive ratio=p2out.plus()/p2in.plus(); else // the gluon is the negative ratio=p2out.minus()/p2in.minus(); double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F; ME2*=cam; return ME2; } double jM2WunogqbarQ(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; return ME2; } double jM2WunogqbarQbar(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; return ME2; } double jM2Wunogqbarg(CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,true); ME2mpm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,true,false); ME2mmp = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,true); ME2mmm = jM2Wuno(pg, p1out,plbar,pl,p1in,true,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; double ratio; // p2-/pb- in the notes if (p2in.pz()>0.) // if the gluon is the positive ratio=p2out.plus()/p2in.plus(); else // the gluon is the negative ratio=p2out.minus()/p2in.minus(); double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F; ME2*=cam; return ME2; } // W+Jets qqxExtremal // W+Jets qqxExtremal Currents - wqq emission double jM2WgQtoqbarqQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; //Correct colour averaging ME2*=(3.0/8.0); return ME2; } double jM2WgQtoqqbarQ(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in){ //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,true); ME2mpm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,false); ME2mmp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,true); ME2mmm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; //Correct colour averaging ME2*=(3.0/8.0); return ME2; } double jM2Wggtoqbarqg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqbarout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,true); ME2mpm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,true,false); ME2mmp = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,true); ME2mmm = jM2Wuno(-pgin, pqout,plbar,pl,-pqbarout,false,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; double ratio; // p2-/pb- in the notes if (p2in.pz()>0.) // if the gluon is the positive ratio=p2out.plus()/p2in.plus(); else // the gluon is the negative ratio=p2out.minus()/p2in.minus(); double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F; ME2*=cam; //Correct colour averaging ME2*=(3.0/8.0); return ME2; } double jM2Wggtoqqbarg(CLHEP::HepLorentzVector pgin, CLHEP::HepLorentzVector pqbarout,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector pqout, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in){ //COM temp; double ME2mpp=0.; double ME2mpm=0.; double ME2mmp=0.; double ME2mmm=0.; double ME2; ME2mpp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,true); ME2mpm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,true,false); ME2mmp = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,true); ME2mmm = jM2Wuno(-pgin, pqbarout,plbar,pl,-pqout,true,p2out,p2in,false,false); //Helicity sum ME2 = ME2mpp + ME2mpm + ME2mmp + ME2mmm; double ratio; // p2-/pb- in the notes if (p2in.pz()>0.) // if the gluon is the positive ratio=p2out.plus()/p2in.plus(); else // the gluon is the negative ratio=p2out.minus()/p2in.minus(); double cam = ( (HEJ::C_A - 1/HEJ::C_A)*(ratio + 1./ratio)/2. + 1/HEJ::C_A)/HEJ::C_F; ME2*=cam; //Correct colour averaging ME2*=(3.0/8.0); return ME2; } namespace { //Function to calculate Term 1 in Equation 3.23 in James Cockburn's Thesis. Tensor<1,4> qggm1(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){ double t1 = (p3-pb)*(p3-pb); Tensor<1,4> Tp3 = Construct1Tensor((p3));//p3 Tensor<1,4> Tpb = Construct1Tensor((pb));//pb // Gauge choice in polarisation tensor. (see JC's Thesis) Tensor<1,4> epsg = eps(pb, refmom, helg); Tensor<3,4> qqCurBlank = T3Current(p2,hel2,p3,hel2); Tensor<2,4> qqCur = qqCurBlank.contract(Tp3-Tpb,2); Tensor<1,4> gqqCur = qqCur.contract(epsg,2)/t1; return gqqCur*(-1); } //Function to calculate Term 2 in Equation 3.23 in James Cockburn's Thesis. Tensor<1,4> qggm2(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){ double t1 = (p2-pb)*(p2-pb); Tensor<1,4> Tp2 = Construct1Tensor((p2));//p2 Tensor<1,4> Tpb = Construct1Tensor((pb));//pb // Gauge choice in polarisation tensor. (see JC's Thesis) Tensor<1,4> epsg = eps(pb,refmom, helg); Tensor<3,4> qqCurBlank = T3Current(p2,hel2,p3,hel2); Tensor<2,4> qqCur = qqCurBlank.contract(Tp2-Tpb,2); Tensor<1,4> gqqCur = qqCur.contract(epsg,1)/t1; return gqqCur; } //Function to calculate Term 3 in Equation 3.23 in James Cockburn's Thesis. Tensor<1,4> qggm3(CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3, bool hel2, bool helg, CLHEP::HepLorentzVector refmom){ double s23 = (p2+p3)*(p2+p3); Tensor<1,4> Tp2 = Construct1Tensor((p2));//p2 Tensor<1,4> Tp3 = Construct1Tensor((p3));//p3 Tensor<1,4> Tpb = Construct1Tensor((pb));//pb // Gauge choice in polarisation tensor. (see JC's Thesis) Tensor<1,4> epsg = eps(pb, refmom, helg); Tensor<2,4> g=Metric(); Tensor<3,4> qqCurBlank1 = g.leftprod(Tp2+Tp3)/s23; Tensor<3,4> qqCurBlank2 = g.leftprod(Tpb)/s23; Tensor<1,4> Cur23 = TCurrent(p2,hel2, p3,hel2); Tensor<2,4> qqCur1 = qqCurBlank1.contract(Cur23,3); Tensor<2,4> qqCur2 = qqCurBlank2.contract(Cur23,3); Tensor<2,4> qqCur3 = qqCurBlank2.contract(Cur23,1); Tensor<1,4> gqqCur = (qqCur1.contract(epsg,1) - qqCur2.contract(epsg,2) + qqCur3.contract(epsg,1))*2*COM(0,1); return gqqCur; } } // no wqq emission double jM2WgqtoQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p3,CLHEP::HepLorentzVector plbar,CLHEP::HepLorentzVector pl, bool aqlinepa){ static bool is_sigma_index_set(false); if(!is_sigma_index_set){ if(init_sigma_index()) is_sigma_index_set = true; else return 0.;} // 2 independent helicity choices (complex conjugation related). Tensor<1,4> TMmmm1 = qggm1(pb,p2,p3,false,false, pa); Tensor<1,4> TMmmm2 = qggm2(pb,p2,p3,false,false, pa); Tensor<1,4> TMmmm3 = qggm3(pb,p2,p3,false,false, pa); Tensor<1,4> TMpmm1 = qggm1(pb,p2,p3,false,true, pa); Tensor<1,4> TMpmm2 = qggm2(pb,p2,p3,false,true, pa); Tensor<1,4> TMpmm3 = qggm3(pb,p2,p3,false,true, pa); // Build the external quark line W Emmision Tensor<1,4> cur1a = jW(pa,p1,plbar,pl, aqlinepa); //Contract with the qqxCurrent. COM Mmmm1 = TMmmm1.contract(cur1a,1).at(0); COM Mmmm2 = TMmmm2.contract(cur1a,1).at(0); COM Mmmm3 = TMmmm3.contract(cur1a,1).at(0); COM Mpmm1 = TMpmm1.contract(cur1a,1).at(0); COM Mpmm2 = TMpmm2.contract(cur1a,1).at(0); COM Mpmm3 = TMpmm3.contract(cur1a,1).at(0); //Colour factors: COM cm1m1,cm2m2,cm3m3,cm1m2,cm1m3,cm2m3; cm1m1=8./3.; cm2m2=8./3.; cm3m3=6.; cm1m2 =-1./3.; cm1m3 = -3.*COM(0.,1.); cm2m3 = 3.*COM(0.,1.); //Sqaure and sum for each helicity config: double Mmmm = real(cm1m1*pow(abs(Mmmm1),2)+cm2m2*pow(abs(Mmmm2),2)+cm3m3*pow(abs(Mmmm3),2)+2.*real(cm1m2*Mmmm1*conj(Mmmm2))+2.*real(cm1m3*Mmmm1*conj(Mmmm3))+2.*real(cm2m3*Mmmm2*conj(Mmmm3))); double Mpmm = real(cm1m1*pow(abs(Mpmm1),2)+cm2m2*pow(abs(Mpmm2),2)+cm3m3*pow(abs(Mpmm3),2)+2.*real(cm1m2*Mpmm1*conj(Mpmm2))+2.*real(cm1m3*Mpmm1*conj(Mpmm3))+2.*real(cm2m3*Mpmm2*conj(Mpmm3))); // Divide by WProp double WPropfact = WProp(plbar, pl); return (2*WPropfact*(Mmmm+Mpmm)/24./4.)/(pa-p1-pl-plbar).m2()/(p2+p3-pb).m2(); } // W+Jets qqxCentral double jM2WqqtoqQQq(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector pl, CLHEP::HepLorentzVector plbar, std::vector<HLV> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove) { static bool is_sigma_index_set(false); if(!is_sigma_index_set){ if(init_sigma_index()) is_sigma_index_set = true; else return 0.;} HLV pq, pqbar, p1, p4; if (qqxmarker){ pqbar = partons[nabove+1]; pq = partons[nabove+2];} else{ pq = partons[nabove+1]; pqbar = partons[nabove+2];} p1 = partons.front(); p4 = partons.back(); Tensor<1,4> T1am, T4bm, T1ap, T4bp; if(!(aqlinepa)){ T1ap = TCurrent(p1, true, pa, true); T1am = TCurrent(p1, false, pa, false);} else if(aqlinepa){ T1ap = TCurrent(pa, true, p1, true); T1am = TCurrent(pa, false, p1, false);} if(!(aqlinepb)){ T4bp = TCurrent(p4, true, pb, true); T4bm = TCurrent(p4, false, pb, false);} else if(aqlinepb){ T4bp = TCurrent(pb, true, p4, true); T4bm = TCurrent(pb, false, p4, false);} // Calculate the 3 separate contributions to the effective vertex Tensor<2,4> Xunc = MUncrossW(pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove); Tensor<2,4> Xcro = MCrossW( pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove); Tensor<2,4> Xsym = MSymW( pa, p1, pb, p4, pq, pqbar, pl, plbar, partons, nabove); // 4 Different Helicity Choices (Differs from Pure Jet Case, where there is also the choice in qqbar helicity. // (- - hel choice) COM M_mmUnc = (((Xunc).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mmCro = (((Xcro).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mmSym = (((Xsym).contract(T1am,1)).contract(T4bm,1)).at(0); // (- + hel choice) COM M_mpUnc = (((Xunc).contract(T1am,1)).contract(T4bp,1)).at(0); COM M_mpCro = (((Xcro).contract(T1am,1)).contract(T4bp,1)).at(0); COM M_mpSym = (((Xsym).contract(T1am,1)).contract(T4bp,1)).at(0); // (+ - hel choice) COM M_pmUnc = (((Xunc).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_pmCro = (((Xcro).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_pmSym = (((Xsym).contract(T1ap,1)).contract(T4bm,1)).at(0); // (+ + hel choice) COM M_ppUnc = (((Xunc).contract(T1ap,1)).contract(T4bp,1)).at(0); COM M_ppCro = (((Xcro).contract(T1ap,1)).contract(T4bp,1)).at(0); COM M_ppSym = (((Xsym).contract(T1ap,1)).contract(T4bp,1)).at(0); //Colour factors: COM cmsms,cmumu,cmcmc,cmsmu,cmsmc,cmumc; cmsms=3.; cmumu=4./3.; cmcmc=4./3.; cmsmu =3./2.*COM(0.,1.); cmsmc = -3./2.*COM(0.,1.); cmumc = -1./6.; // Work Out Interference in each case of helicity: double amp_mm = real(cmsms*pow(abs(M_mmSym),2) +cmumu*pow(abs(M_mmUnc),2) +cmcmc*pow(abs(M_mmCro),2) +2.*real(cmsmu*M_mmSym*conj(M_mmUnc)) +2.*real(cmsmc*M_mmSym*conj(M_mmCro)) +2.*real(cmumc*M_mmUnc*conj(M_mmCro))); double amp_mp = real(cmsms*pow(abs(M_mpSym),2) +cmumu*pow(abs(M_mpUnc),2) +cmcmc*pow(abs(M_mpCro),2) +2.*real(cmsmu*M_mpSym*conj(M_mpUnc)) +2.*real(cmsmc*M_mpSym*conj(M_mpCro)) +2.*real(cmumc*M_mpUnc*conj(M_mpCro))); double amp_pm = real(cmsms*pow(abs(M_pmSym),2) +cmumu*pow(abs(M_pmUnc),2) +cmcmc*pow(abs(M_pmCro),2) +2.*real(cmsmu*M_pmSym*conj(M_pmUnc)) +2.*real(cmsmc*M_pmSym*conj(M_pmCro)) +2.*real(cmumc*M_pmUnc*conj(M_pmCro))); double amp_pp = real(cmsms*pow(abs(M_ppSym),2) +cmumu*pow(abs(M_ppUnc),2) +cmcmc*pow(abs(M_ppCro),2) +2.*real(cmsmu*M_ppSym*conj(M_ppUnc)) +2.*real(cmsmc*M_ppSym*conj(M_ppCro)) +2.*real(cmumc*M_ppUnc*conj(M_ppCro))); double amp=((amp_mm+amp_mp+amp_pm+amp_pp)/(9.*4.)); CLHEP::HepLorentzVector q1,q3; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } q3 = q1 - pq - pqbar - pl - plbar; double t1 = (q1).m2(); double t3 = (q3).m2(); //Divide by t-channels amp/=(t1*t1*t3*t3); //Divide by WProp double WPropfact = WProp(plbar, pl); amp*=WPropfact; return amp; } // no wqq emission double jM2WqqtoqQQqW(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb,CLHEP::HepLorentzVector pl,CLHEP::HepLorentzVector plbar, std::vector<CLHEP::HepLorentzVector> partons, bool aqlinepa, bool aqlinepb, bool qqxmarker, int nabove, int nbelow, bool forwards){ static bool is_sigma_index_set(false); if(!is_sigma_index_set){ if(init_sigma_index()) is_sigma_index_set = true; else return 0.; } if (!forwards){ //If Emission from Leg a instead, flip process. HLV dummymom = pa; bool dummybool= aqlinepa; int dummyint = nabove; pa = pb; pb = dummymom; std::reverse(partons.begin(),partons.end()); qqxmarker = !(qqxmarker); aqlinepa = aqlinepb; aqlinepb = dummybool; nabove = nbelow; nbelow = dummyint; } HLV pq, pqbar, p1,p4; if (qqxmarker){ pqbar = partons[nabove+1]; pq = partons[nabove+2];} else{ pq = partons[nabove+1]; pqbar = partons[nabove+2];} p1 = partons.front(); p4 = partons.back(); Tensor<1,4> T1am(0.), T1ap(0.); if(!(aqlinepa)){ T1ap = TCurrent(p1, true, pa, true); T1am = TCurrent(p1, false, pa, false);} else if(aqlinepa){ T1ap = TCurrent(pa, true, p1, true); T1am = TCurrent(pa, false, p1, false);} Tensor <1,4> T4bm = jW(pb, p4, plbar, pl, aqlinepb); // Calculate the 3 separate contributions to the effective vertex Tensor<2,4> Xunc_m = MUncross(pa, pq, pqbar,partons, false, nabove); Tensor<2,4> Xcro_m = MCross( pa, pq, pqbar,partons, false, nabove); Tensor<2,4> Xsym_m = MSym( pa, p1, pb, p4, pq, pqbar, partons, false, nabove); Tensor<2,4> Xunc_p = MUncross(pa, pq, pqbar,partons, true, nabove); Tensor<2,4> Xcro_p = MCross( pa, pq, pqbar,partons, true, nabove); Tensor<2,4> Xsym_p = MSym( pa, p1, pb, p4, pq, pqbar, partons, true, nabove); // (- - hel choice) COM M_mmUnc = (((Xunc_m).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mmCro = (((Xcro_m).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mmSym = (((Xsym_m).contract(T1am,1)).contract(T4bm,1)).at(0); // (- + hel choice) COM M_mpUnc = (((Xunc_p).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mpCro = (((Xcro_p).contract(T1am,1)).contract(T4bm,1)).at(0); COM M_mpSym = (((Xsym_p).contract(T1am,1)).contract(T4bm,1)).at(0); // (+ - hel choice) COM M_pmUnc = (((Xunc_m).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_pmCro = (((Xcro_m).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_pmSym = (((Xsym_m).contract(T1ap,1)).contract(T4bm,1)).at(0); // (+ + hel choice) COM M_ppUnc = (((Xunc_p).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_ppCro = (((Xcro_p).contract(T1ap,1)).contract(T4bm,1)).at(0); COM M_ppSym = (((Xsym_p).contract(T1ap,1)).contract(T4bm,1)).at(0); //Colour factors: COM cmsms,cmumu,cmcmc,cmsmu,cmsmc,cmumc; cmsms=3.; cmumu=4./3.; cmcmc=4./3.; cmsmu =3./2.*COM(0.,1.); cmsmc = -3./2.*COM(0.,1.); cmumc = -1./6.; // Work Out Interference in each case of helicity: double amp_mm = real(cmsms*pow(abs(M_mmSym),2) +cmumu*pow(abs(M_mmUnc),2) +cmcmc*pow(abs(M_mmCro),2) +2.*real(cmsmu*M_mmSym*conj(M_mmUnc)) +2.*real(cmsmc*M_mmSym*conj(M_mmCro)) +2.*real(cmumc*M_mmUnc*conj(M_mmCro))); double amp_mp = real(cmsms*pow(abs(M_mpSym),2) +cmumu*pow(abs(M_mpUnc),2) +cmcmc*pow(abs(M_mpCro),2) +2.*real(cmsmu*M_mpSym*conj(M_mpUnc)) +2.*real(cmsmc*M_mpSym*conj(M_mpCro)) +2.*real(cmumc*M_mpUnc*conj(M_mpCro))); double amp_pm = real(cmsms*pow(abs(M_pmSym),2) +cmumu*pow(abs(M_pmUnc),2) +cmcmc*pow(abs(M_pmCro),2) +2.*real(cmsmu*M_pmSym*conj(M_pmUnc)) +2.*real(cmsmc*M_pmSym*conj(M_pmCro)) +2.*real(cmumc*M_pmUnc*conj(M_pmCro))); double amp_pp = real(cmsms*pow(abs(M_ppSym),2) +cmumu*pow(abs(M_ppUnc),2) +cmcmc*pow(abs(M_ppCro),2) +2.*real(cmsmu*M_ppSym*conj(M_ppUnc)) +2.*real(cmsmc*M_ppSym*conj(M_ppCro)) +2.*real(cmumc*M_ppUnc*conj(M_ppCro))); double amp=((amp_mm+amp_mp+amp_pm+amp_pp)/(9.*4.)); CLHEP::HepLorentzVector q1,q3; q1=pa; for(int i=0;i<nabove+1;i++){ q1-=partons.at(i); } q3 = q1 - pq - pqbar; double t1 = (q1).m2(); double t3 = (q3).m2(); //Divide by t-channels amp/=(t1*t1*t3*t3); //Divide by WProp double WPropfact = WProp(plbar, pl); amp*=WPropfact; return amp; } diff --git a/src/YAMLreader.cc b/src/YAMLreader.cc index 1d51bd4..d19c1f8 100644 --- a/src/YAMLreader.cc +++ b/src/YAMLreader.cc @@ -1,475 +1,475 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/YAMLreader.hh" #include <algorithm> #include <iostream> #include <limits> #include <map> #include <string> #include <unordered_map> #include <vector> #include <dlfcn.h> #include "HEJ/ScaleFunction.hh" #include "HEJ/event_types.hh" #include "HEJ/output_formats.hh" #include "HEJ/Constants.hh" namespace HEJ{ class Event; 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 = { "trials", "min extparton pt", "max ext soft pt fraction", "FKL", "unordered", "qqx", "non-HEJ", "scales", "scale factors", "max scale ratio", "import scales", "log correction", "event output", "analysis", "regulator parameter" }; // add subnodes to "supported" - the assigned value is irrelevant for(auto && opt: opts) supported[opt] = ""; for(auto && jet_opt: {"min pt", "algorithm", "R"}){ supported["resummation jets"][jet_opt] = ""; supported["fixed order jets"][jet_opt] = ""; } for(auto && opt: {"mt", "use impact factors", "include bottom", "mb"}){ supported["Higgs coupling"][opt] = ""; } for(auto && opt: {"name", "seed"}){ supported["random generator"][opt] = ""; } return supported; }(); return supported; } fastjet::JetAlgorithm to_JetAlgorithm(std::string const & algo){ using namespace fastjet; static const std::map<std::string, fastjet::JetAlgorithm> known = { {"kt", kt_algorithm}, {"cambridge", cambridge_algorithm}, {"antikt", antikt_algorithm}, {"cambridge for passive", cambridge_for_passive_algorithm}, {"plugin", plugin_algorithm} }; const auto res = known.find(algo); if(res == known.end()){ throw std::invalid_argument("Unknown jet algorithm " + algo); } return res->second; } EventTreatment to_EventTreatment(std::string const & name){ static const std::map<std::string, EventTreatment> known = { {"reweight", EventTreatment::reweight}, {"keep", EventTreatment::keep}, {"discard", EventTreatment::discard} }; const auto res = known.find(name); if(res == known.end()){ throw std::invalid_argument("Unknown event treatment " + name); } return res->second; } } // namespace anonymous namespace detail{ void set_from_yaml(fastjet::JetAlgorithm & setting, YAML::Node const & yaml){ setting = to_JetAlgorithm(yaml.as<std::string>()); } void set_from_yaml(EventTreatment & setting, YAML::Node const & yaml){ setting = to_EventTreatment(yaml.as<std::string>()); } void set_from_yaml(ParticleID & setting, YAML::Node const & yaml){ setting = to_ParticleID(yaml.as<std::string>()); } } // namespace detail JetParameters get_jet_parameters( YAML::Node const & node, std::string const & entry ){ assert(node); JetParameters result; fastjet::JetAlgorithm jet_algo = fastjet::antikt_algorithm; double R; set_from_yaml_if_defined(jet_algo, node, entry, "algorithm"); set_from_yaml(R, node, entry, "R"); result.def = fastjet::JetDefinition{jet_algo, R}; set_from_yaml(result.min_pt, node, entry, "min pt"); return result; } RNGConfig to_RNGConfig( YAML::Node const & node, std::string const & entry ){ assert(node); RNGConfig result; set_from_yaml(result.name, node, entry, "name"); set_from_yaml_if_defined(result.seed, node, entry, "seed"); return result; } HiggsCouplingSettings get_Higgs_coupling( YAML::Node const & node, std::string const & entry ){ assert(node); static constexpr double mt_max = 2e4; #ifndef HEJ_BUILD_WITH_QCDLOOP if(node[entry]){ throw std::invalid_argument{ "Higgs coupling settings require building HEJ 2 " "with QCDloop support" }; } #endif HiggsCouplingSettings settings; set_from_yaml_if_defined(settings.mt, node, entry, "mt"); set_from_yaml_if_defined(settings.mb, node, entry, "mb"); set_from_yaml_if_defined(settings.include_bottom, node, entry, "include bottom"); set_from_yaml_if_defined(settings.use_impact_factors, node, entry, "use impact factors"); if(settings.use_impact_factors){ if(settings.mt != std::numeric_limits<double>::infinity()){ throw std::invalid_argument{ "Conflicting settings: " "impact factors may only be used in the infinite top mass limit" }; } } else{ // huge values of the top mass are numerically unstable settings.mt = std::min(settings.mt, mt_max); } return settings; } FileFormat to_FileFormat(std::string const & name){ static const std::map<std::string, FileFormat> known = { {"Les Houches", FileFormat::Les_Houches}, {"HepMC", FileFormat::HepMC} }; const auto res = known.find(name); if(res == known.end()){ throw std::invalid_argument("Unknown file format " + name); } return res->second; } std::string extract_suffix(std::string const & filename){ size_t separator = filename.rfind('.'); if(separator == filename.npos) return {}; return filename.substr(separator + 1); } FileFormat format_from_suffix(std::string const & filename){ const std::string suffix = extract_suffix(filename); if(suffix == "lhe") return FileFormat::Les_Houches; if(suffix == "hepmc") return FileFormat::HepMC; throw std::invalid_argument{ "Can't determine format for output file " + filename }; } void assert_all_options_known( YAML::Node const & conf, YAML::Node const & supported ){ if(!conf.IsMap()) return; if(!supported.IsMap()) throw invalid_type{"must not have sub-entries"}; for(auto const & entry: conf){ const auto name = entry.first.as<std::string>(); if(! supported[name]) throw unknown_option{name}; /* check sub-options, e.g. 'resummation jets: min pt' * we don't check analysis sub-options * those depend on the analysis being used and should be checked there * similar for "import scales" */ if(name != "analysis" && name != "import scales"){ try{ assert_all_options_known(conf[name], supported[name]); } catch(unknown_option const & ex){ throw unknown_option{name + ": " + ex.what()}; } catch(invalid_type const & ex){ throw invalid_type{name + ": " + ex.what()}; } } } } } // namespace HEJ namespace YAML { Node convert<HEJ::OutputFile>::encode(HEJ::OutputFile const & outfile) { Node node; node[to_string(outfile.format)] = outfile.name; return node; }; bool convert<HEJ::OutputFile>::decode(Node const & node, HEJ::OutputFile & out) { switch(node.Type()){ case NodeType::Map: { YAML::const_iterator it = node.begin(); out.format = HEJ::to_FileFormat(it->first.as<std::string>()); out.name = it->second.as<std::string>(); return true; } case NodeType::Scalar: out.name = node.as<std::string>(); out.format = HEJ::format_from_suffix(out.name); return true; default: return false; } } } // namespace YAML namespace HEJ{ namespace detail{ void set_from_yaml(OutputFile & setting, YAML::Node const & yaml){ setting = yaml.as<OutputFile>(); } } namespace{ void update_fixed_order_jet_parameters( JetParameters & fixed_order_jets, YAML::Node const & yaml ){ if(!yaml["fixed order jets"]) return; set_from_yaml_if_defined( fixed_order_jets.min_pt, yaml, "fixed order jets", "min pt" ); fastjet::JetAlgorithm algo = fixed_order_jets.def.jet_algorithm(); set_from_yaml_if_defined(algo, yaml, "fixed order jets", "algorithm"); double R = fixed_order_jets.def.R(); set_from_yaml_if_defined(R, yaml, "fixed order jets", "R"); fixed_order_jets.def = fastjet::JetDefinition{algo, R}; } // like std::stod, but throw if not the whole string can be converted double to_double(std::string const & str){ std::size_t pos; const double result = std::stod(str, &pos); if(pos < str.size()){ throw std::invalid_argument(str + " is not a valid double value"); } return result; } using EventScale = double (*)(Event const &); void import_scale_functions( std::string const & file, std::vector<std::string> const & scale_names, std::unordered_map<std::string, EventScale> & known ) { auto handle = dlopen(file.c_str(), RTLD_NOW); char * error = dlerror(); if(error != nullptr) throw std::runtime_error{error}; for(auto const & scale: scale_names) { void * sym = dlsym(handle, scale.c_str()); error = dlerror(); if(error != nullptr) throw std::runtime_error{error}; known.emplace(scale, reinterpret_cast<EventScale>(sym)); } } auto get_scale_map( YAML::Node const & yaml ) { std::unordered_map<std::string, EventScale> scale_map; scale_map.emplace("H_T", H_T); scale_map.emplace("max jet pperp", max_jet_pt); scale_map.emplace("jet invariant mass", jet_invariant_mass); scale_map.emplace("m_j1j2", m_j1j2); if(yaml["import scales"]) { if(! yaml["import scales"].IsMap()) { throw invalid_type{"Entry 'import scales' is not a map"}; } for(auto const & import: yaml["import scales"]) { const auto file = import.first.as<std::string>(); const auto scale_names = import.second.IsSequence() ?import.second.as<std::vector<std::string>>() :std::vector<std::string>{import.second.as<std::string>()}; import_scale_functions(file, scale_names, scale_map); } } return scale_map; } // simple (as in non-composite) scale functions /** * An example for a simple scale function would be H_T, * H_T/2 is then composite (take H_T and then divide by 2) */ ScaleFunction parse_simple_ScaleFunction( std::string const & scale_fun, std::unordered_map<std::string, EventScale> const & known ) { assert( scale_fun.empty() || (!std::isspace(scale_fun.front()) && !std::isspace(scale_fun.back())) ); const auto it = known.find(scale_fun); if(it != end(known)) return {it->first, it->second}; try{ const double scale = to_double(scale_fun); return {scale_fun, FixedScale{scale}}; } catch(std::invalid_argument const &){} throw std::invalid_argument{"Unknown scale choice: " + scale_fun}; } std::string trim_front(std::string const & str){ const auto new_begin = std::find_if( begin(str), end(str), [](char c){ return ! std::isspace(c); } ); return std::string(new_begin, end(str)); } std::string trim_back(std::string str){ size_t pos = str.size() - 1; // use guaranteed wrap-around behaviour to check whether we have // traversed the whole string for(; pos < str.size() && std::isspace(str[pos]); --pos) {} str.resize(pos + 1); // note that pos + 1 can be 0 return str; } ScaleFunction parse_ScaleFunction( std::string const & scale_fun, std::unordered_map<std::string, EventScale> const & known ){ assert( scale_fun.empty() || (!std::isspace(scale_fun.front()) && !std::isspace(scale_fun.back())) ); // parse from right to left => a/b/c gives (a/b)/c const size_t delim = scale_fun.find_last_of("*/"); if(delim == scale_fun.npos){ return parse_simple_ScaleFunction(scale_fun, known); } const std::string first = trim_back(std::string{scale_fun, 0, delim}); const std::string second = trim_front(std::string{scale_fun, delim+1}); if(scale_fun[delim] == '/'){ return parse_ScaleFunction(first, known) / parse_ScaleFunction(second, known); } else{ assert(scale_fun[delim] == '*'); return parse_ScaleFunction(first, known) * parse_ScaleFunction(second, known); } } EventTreatMap get_event_treatment( YAML::Node const & yaml ){ using namespace event_type; EventTreatMap treat { {no_2_jets, EventTreatment::discard}, {bad_final_state, EventTreatment::discard}, {FKL, EventTreatment::reweight}, {unob, EventTreatment::keep}, {unof, EventTreatment::keep}, {qqxexb, EventTreatment::keep}, {qqxexf, EventTreatment::keep}, {qqxmid, EventTreatment::keep}, {nonHEJ, EventTreatment::keep} }; set_from_yaml(treat.at(FKL), yaml, "FKL"); set_from_yaml(treat.at(unob), yaml, "unordered"); treat.at(unof) = treat.at(unob); set_from_yaml(treat.at(qqxexb), yaml, "qqx"); set_from_yaml(treat.at(qqxexf), yaml, "qqx"); set_from_yaml(treat.at(qqxmid), yaml, "qqx"); set_from_yaml(treat.at(nonHEJ), yaml, "non-HEJ"); if(treat[nonHEJ] == EventTreatment::reweight){ throw std::invalid_argument{"Cannot reweight non-HEJ events"}; } return treat; } Config to_Config(YAML::Node const & yaml){ try{ assert_all_options_known(yaml, get_supported_options()); } catch(unknown_option const & ex){ throw unknown_option{std::string{"Unknown option '"} + ex.what() + "'"}; } Config config; config.resummation_jets = get_jet_parameters(yaml, "resummation jets"); config.fixed_order_jets = config.resummation_jets; update_fixed_order_jet_parameters(config.fixed_order_jets, yaml); set_from_yaml(config.min_extparton_pt, yaml, "min extparton pt"); // Sets the standard value, then changes this if defined config.regulator_lambda=CLAMBDA; set_from_yaml_if_defined(config.regulator_lambda, yaml, "regulator parameter"); config.max_ext_soft_pt_fraction = std::numeric_limits<double>::infinity(); set_from_yaml_if_defined( config.max_ext_soft_pt_fraction, yaml, "max ext soft pt fraction" ); set_from_yaml(config.trials, yaml, "trials"); set_from_yaml(config.log_correction, yaml, "log correction"); config.treat = get_event_treatment(yaml); set_from_yaml_if_defined(config.output, yaml, "event output"); config.rng = to_RNGConfig(yaml, "random generator"); set_from_yaml_if_defined(config.analysis_parameters, yaml, "analysis"); config.scales = to_ScaleConfig(yaml); config.Higgs_coupling = get_Higgs_coupling(yaml, "Higgs coupling"); return config; } } // namespace anonymous ScaleConfig to_ScaleConfig(YAML::Node const & yaml){ ScaleConfig config; auto scale_funs = get_scale_map(yaml); std::vector<std::string> scales; set_from_yaml(scales, yaml, "scales"); config.base.reserve(scales.size()); std::transform( begin(scales), end(scales), std::back_inserter(config.base), [scale_funs](auto const & entry){ return parse_ScaleFunction(entry, scale_funs); } ); set_from_yaml_if_defined(config.factors, yaml, "scale factors"); config.max_ratio = std::numeric_limits<double>::infinity(); set_from_yaml_if_defined(config.max_ratio, yaml, "max scale ratio"); return config; } 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; } } } // namespace HEJ diff --git a/src/bin/HEJ.cc b/src/bin/HEJ.cc index 0338a92..ed90104 100644 --- a/src/bin/HEJ.cc +++ b/src/bin/HEJ.cc @@ -1,191 +1,211 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include <array> #include <chrono> #include <iostream> #include <limits> #include <memory> #include <numeric> #include "yaml-cpp/yaml.h" #include "fastjet/ClusterSequence.hh" #include "HEJ/CombinedEventWriter.hh" #include "HEJ/config.hh" #include "HEJ/CrossSectionAccumulator.hh" #include "HEJ/Event.hh" #include "HEJ/EventReader.hh" #include "HEJ/EventReweighter.hh" #include "HEJ/get_analysis.hh" #include "HEJ/make_RNG.hh" #include "HEJ/ProgressBar.hh" #include "HEJ/stream.hh" #include "HEJ/Version.hh" #include "HEJ/YAMLreader.hh" int event_number(std::string const & record){ size_t start = record.rfind("Number of Events"); start = record.find_first_of("123456789", start); if(start == std::string::npos) { throw std::invalid_argument("no event number record found"); } const size_t end = record.find_first_not_of("0123456789", start); return std::stoi(record.substr(start, end - start)); } HEJ::Config load_config(char const * filename){ try{ return HEJ::load_config(filename); } catch(std::exception const & exc){ std::cerr << "Error: " << exc.what() << '\n'; std::exit(EXIT_FAILURE); } } std::unique_ptr<HEJ::Analysis> get_analysis( YAML::Node const & parameters ){ try{ return HEJ::get_analysis(parameters); } catch(std::exception const & exc){ std::cerr << "Failed to load analysis: " << exc.what() << '\n'; std::exit(EXIT_FAILURE); } } // unique_ptr is a workaround: // HEJ::optional is a better fit, but gives spurious errors with g++ 7.3.0 std::unique_ptr<HEJ::ProgressBar<double>> make_progress_bar( std::vector<double> const & xs ) { if(xs.empty()) return {}; const double Born_xs = std::accumulate(begin(xs), end(xs), 0.); return std::make_unique<HEJ::ProgressBar<double>>(std::cout, Born_xs); } std::string time_to_string(const time_t time){ char s[30]; struct tm * p = localtime(&time); strftime(s, 30, "%a %b %d %Y %H:%M:%S", p); return s; } int main(int argn, char** argv) { using clock = std::chrono::system_clock; if (argn < 3) { std::cerr << "\n# Usage:\n."<< argv[0] <<" config_file input_file\n\n"; return EXIT_FAILURE; } const auto start_time = clock::now(); { std::cout << "Starting " << HEJ::Version::package_name_full() << ", revision " << HEJ::Version::revision() << " (" << time_to_string(clock::to_time_t(start_time)) << ")" << std::endl; } fastjet::ClusterSequence::print_banner(); // read configuration const HEJ::Config config = load_config(argv[1]); auto reader = HEJ::make_reader(argv[2]); assert(reader); std::unique_ptr<HEJ::Analysis> analysis = get_analysis( config.analysis_parameters ); assert(analysis != nullptr); auto heprup = reader->heprup(); heprup.generators.emplace_back(LHEF::XMLTag{}); heprup.generators.back().name = HEJ::Version::package_name(); heprup.generators.back().version = HEJ::Version::String(); HEJ::CombinedEventWriter writer{config.output, std::move(heprup)}; double global_reweight = 1.; int max_events = std::numeric_limits<int>::max(); if(argn > 3){ max_events = std::stoi(argv[3]); const int input_events = event_number(reader->header()); global_reweight = input_events/static_cast<double>(max_events); std::cout << "Processing " << max_events << " out of " << input_events << " events\n"; } HEJ::ScaleGenerator scale_gen{ config.scales.base, config.scales.factors, config.scales.max_ratio }; auto ran = HEJ::make_RNG(config.rng.name, config.rng.seed); assert(ran != nullptr); HEJ::EventReweighter hej{ reader->heprup(), std::move(scale_gen), to_EventReweighterConfig(config), *ran }; + // status infos & eye candy int nevent = 0; std::array<int, HEJ::event_type::last_type + 1> nevent_type{0}, nfailed_type{0}; auto progress = make_progress_bar(reader->heprup().XSECUP); HEJ::CrossSectionAccumulator xs; - // Loop over the events in the inputfile + std::map<HEJ::StatusCode, int> status_counter; + size_t total_trials = 0; + + // Loop over the events in the input file while(reader->read_event()){ // reweight events so that the total cross section is conserved auto hepeup = reader->hepeup(); hepeup.setWeight(0, global_reweight * hepeup.weight()); if(nevent == max_events) break; ++nevent; HEJ::Event::EventData event_data{hepeup}; event_data.reconstruct_intermediate(); // calculate HEJ weight HEJ::Event FO_event{ std::move(event_data).cluster( config.fixed_order_jets.def, config.fixed_order_jets.min_pt ) }; auto resummed_events = hej.reweight(FO_event, config.trials); + for(auto const & s: hej.status()) + ++status_counter[s]; + total_trials+=hej.status().size(); ++nevent_type[FO_event.type()]; if(resummed_events.empty()) ++nfailed_type[FO_event.type()]; for(auto const & ev: resummed_events){ //TODO: move pass_cuts to after phase space point generation if(analysis->pass_cuts(ev, FO_event)){ analysis->fill(ev, FO_event); writer.write(ev); xs.fill(ev); } } if(progress) progress->increment(FO_event.central().weight); } // main event loop std::cout << '\n'; analysis->finalise(); using namespace HEJ::event_type; std::cout<< "Events processed: " << nevent << '\n'; for(size_t ev_type = first_type; ev_type <= last_type; ++ev_type){ std::cout << '\t' << names[ev_type] << ": " << nevent_type[ev_type] << ", failed to reconstruct " << nfailed_type[ev_type] << '\n'; } std::cout << '\n' << xs << '\n'; + std::cout << "Generation statistic: " + << status_counter[HEJ::StatusCode::good] << "/" << total_trials + << " trials successful.\n"; + for(auto && entry: status_counter){ + const double fraction = static_cast<double>(entry.second)/total_trials; + const int percent = std::round(100*fraction); + std::cout << std::left << std::setw(16) << (to_string(entry.first) + ":") + << " ["; + for(int i = 0; i < percent/2; ++i) std::cout << '#'; + for(int i = percent/2; i < 50; ++i) std::cout << ' '; + std::cout << "] " << percent << "%\n"; + } + std::chrono::duration<double> run_time = (clock::now() - start_time); - std::cout << "Finished " << HEJ::Version::package_name() << " at " + std::cout << "\nFinished " << HEJ::Version::package_name() << " at " << time_to_string(clock::to_time_t(clock::now())) << "\n=> Runtime: " << run_time.count() << " sec (" << nevent/run_time.count() << " Events/sec).\n"; } diff --git a/src/currents.cc b/src/currents.cc index de692eb..26542a9 100644 --- a/src/currents.cc +++ b/src/currents.cc @@ -1,3210 +1,3198 @@ -////////////////////////////////////////////////// -////////////////////////////////////////////////// -// This source code is Copyright (2012) of // -// Jeppe R. Andersen and Jennifer M. Smillie // -// and is distributed under the // -// Gnu Public License version 2 // -// http://www.gnu.org/licenses/gpl-2.0.html // -// You are allowed to distribute and alter the // -// source under the conditions of the GPLv2 // -// as long as this copyright notice // -// is unaltered and distributed with the source // -// Any use should comply with the // -// MCNET GUIDELINES // -// for Event Generator Authors and Users // -// as distributed with this source code // -////////////////////////////////////////////////// -////////////////////////////////////////////////// +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/currents.hh" #include <iostream> #include <limits> #include <utility> #include <vector> #ifdef HEJ_BUILD_WITH_QCDLOOP #include "qcdloop/qcdloop.h" #endif #include "HEJ/Constants.hh" #include "HEJ/exceptions.hh" #include "HEJ/PDG_codes.hh" const COM looprwfactor = (COM(0.,1.)*M_PI*M_PI)/pow((2.*M_PI),4); constexpr double infinity = std::numeric_limits<double>::infinity(); namespace { // Loop integrals #ifdef HEJ_BUILD_WITH_QCDLOOP COM B0DD(CLHEP::HepLorentzVector q, double mq) { static std::vector<std::complex<double>> result(3); static auto ql_B0 = [](){ ql::Bubble<std::complex<double>,double,double> ql_B0; ql_B0.setCacheSize(100); return ql_B0; }(); static std::vector<double> masses(2); static std::vector<double> momenta(1); for(auto & m: masses) m = mq*mq; momenta.front() = q.m2(); ql_B0.integral(result, 1, masses, momenta); return result[0]; } COM C0DD(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq) { static std::vector<std::complex<double>> result(3); static auto ql_C0 = [](){ ql::Triangle<std::complex<double>,double,double> ql_C0; ql_C0.setCacheSize(100); return ql_C0; }(); static std::vector<double> masses(3); static std::vector<double> momenta(3); for(auto & m: masses) m = mq*mq; momenta[0] = q1.m2(); momenta[1] = q2.m2(); momenta[2] = (q1+q2).m2(); ql_C0.integral(result, 1, masses, momenta); return result[0]; } COM D0DD(CLHEP::HepLorentzVector q1,CLHEP::HepLorentzVector q2, CLHEP::HepLorentzVector q3, double mq) { static std::vector<std::complex<double>> result(3); static auto ql_D0 = [](){ ql::Box<std::complex<double>,double,double> ql_D0; ql_D0.setCacheSize(100); return ql_D0; }(); static std::vector<double> masses(4); static std::vector<double> momenta(6); for(auto & m: masses) m = mq*mq; momenta[0] = q1.m2(); momenta[1] = q2.m2(); momenta[2] = q3.m2(); momenta[3] = (q1+q2+q3).m2(); momenta[4] = (q1+q2).m2(); momenta[5] = (q2+q3).m2(); ql_D0.integral(result, 1, masses, momenta); return result[0]; } COM A1(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt) // As given in Eq. (B.2) of VDD { double q12,q22,Q2; CLHEP::HepLorentzVector Q; double Delta3,mt2; COM ans(COM(0.,0.)); q12=q1.m2(); q22=q2.m2(); Q=-q1-q2; // Define all momenta ingoing as in appendix of VDD Q2=Q.m2(); Delta3=q12*q12+q22*q22+Q2*Q2-2*q12*q22-2*q12*Q2-2*q22*Q2; if (mt < 0.) std::cerr<<"Problem in A1! mt = "<<mt<<std::endl; mt2=mt*mt; ans=looprwfactor*COM(0,-1)*C0DD(q1,q2,mt)*( 4.*mt2/Delta3*(Q2-q12-q22) -1.-4.*q12*q22/Delta3-12.*q12*q22*Q2/Delta3/Delta3*(q12+q22-Q2) ) - looprwfactor*COM(0,-1)*( B0DD(q2,mt)-B0DD(Q,mt) ) * ( 2.*q22/Delta3+12.*q12*q22/Delta3/Delta3*(q22-q12+Q2) ) - looprwfactor*COM(0,-1)*( B0DD(q1,mt)-B0DD(Q,mt) ) * ( 2.*q12/Delta3+12.*q12*q22/Delta3/Delta3*(q12-q22+Q2) ) - 2./Delta3/16/M_PI/M_PI*(q12+q22-Q2); return ans; } COM A2(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt) // As given in Eq. (B.2) of VDD, but with high energy limit // of invariants taken. { double q12,q22,Q2; CLHEP::HepLorentzVector Q; double Delta3,mt2; COM ans(COM(0.,0.)); if (mt < 0.) std::cerr<<"Problem in A2! mt = "<<mt<<std::endl; mt2=mt*mt; q12=q1.m2(); q22=q2.m2(); Q=-q1-q2; // Define all momenta ingoing as in appendix of VDD Q2=Q.m2(); Delta3=q12*q12+q22*q22+Q2*Q2-2*q12*q22-2*q12*Q2-2*q22*Q2; ans=looprwfactor*COM(0,-1)*C0DD(q1,q2,mt)*( 2.*mt2+1./2.*(q12+q22-Q2) +2.*q12*q22*Q2/Delta3 ) +looprwfactor*COM(0,-1)*(B0DD(q2,mt)-B0DD(Q,mt)) *q22*(q22-q12-Q2)/Delta3 +looprwfactor*COM(0,-1)*(B0DD(q1,mt)-B0DD(Q,mt)) *q12*(q12-q22-Q2)/Delta3+1./16/M_PI/M_PI; return ans; } #else // no QCDloop COM A1(CLHEP::HepLorentzVector, CLHEP::HepLorentzVector, double) { throw std::logic_error{"A1 called without QCDloop support"}; } COM A2(CLHEP::HepLorentzVector, CLHEP::HepLorentzVector, double) { throw std::logic_error{"A2 called without QCDloop support"}; } #endif void to_current(const CLHEP::HepLorentzVector & q, current & ret){ ret[0]=q.e(); ret[1]=q.x(); ret[2]=q.y(); ret[3]=q.z(); } constexpr double C_A = 3.; constexpr double C_F = 4./3.; // using ParticleID = HEJ::pid::ParticleID; } // namespace anonymous // Colour acceleration multiplier for gluons see eq. (7) in arXiv:0910.5113 // @TODO: this is not a current and should be moved somewhere else double K_g(double p1minus, double paminus) { return 1./2.*(p1minus/paminus + paminus/p1minus)*(HEJ::C_A - 1./HEJ::C_A) + 1./HEJ::C_A; } double K_g( CLHEP::HepLorentzVector const & pout, CLHEP::HepLorentzVector const & pin ) { if(pin.z() > 0) return K_g(pout.plus(), pin.plus()); return K_g(pout.minus(), pin.minus()); } CCurrent CCurrent::operator+(const CCurrent& other) { COM result_c0=c0 + other.c0; COM result_c1=c1 + other.c1; COM result_c2=c2 + other.c2; COM result_c3=c3 + other.c3; return CCurrent(result_c0,result_c1,result_c2,result_c3); } CCurrent CCurrent::operator-(const CCurrent& other) { COM result_c0=c0 - other.c0; COM result_c1=c1 - other.c1; COM result_c2=c2 - other.c2; COM result_c3=c3 - other.c3; return CCurrent(result_c0,result_c1,result_c2,result_c3); } CCurrent CCurrent::operator*(const double x) { COM result_c0=x*CCurrent::c0; COM result_c1=x*CCurrent::c1; COM result_c2=x*CCurrent::c2; COM result_c3=x*CCurrent::c3; return CCurrent(result_c0,result_c1,result_c2,result_c3); } CCurrent CCurrent::operator/(const double x) { COM result_c0=CCurrent::c0/x; COM result_c1=CCurrent::c1/x; COM result_c2=CCurrent::c2/x; COM result_c3=CCurrent::c3/x; return CCurrent(result_c0,result_c1,result_c2,result_c3); } CCurrent CCurrent::operator*(const COM x) { COM result_c0=x*CCurrent::c0; COM result_c1=x*CCurrent::c1; COM result_c2=x*CCurrent::c2; COM result_c3=x*CCurrent::c3; return CCurrent(result_c0,result_c1,result_c2,result_c3); } CCurrent CCurrent::operator/(const COM x) { COM result_c0=(CCurrent::c0)/x; COM result_c1=(CCurrent::c1)/x; COM result_c2=(CCurrent::c2)/x; COM result_c3=(CCurrent::c3)/x; return CCurrent(result_c0,result_c1,result_c2,result_c3); } std::ostream& operator <<(std::ostream& os, const CCurrent& cur) { os << "("<<cur.c0<< " ; "<<cur.c1<<" , "<<cur.c2<<" , "<<cur.c3<<")"; return os; } CCurrent operator * ( double x, CCurrent& m) { return m*x; } CCurrent operator * ( COM x, CCurrent& m) { return m*x; } CCurrent operator / ( double x, CCurrent& m) { return m/x; } CCurrent operator / ( COM x, CCurrent& m) { return m/x; } COM CCurrent::dot(CLHEP::HepLorentzVector p1) { // Current goes (E,px,py,pz) // std::cout<<"current = ("<<c0<<","<<c1<<","<<c2<<","<<c3<<")\n"; // Vector goes (px,py,pz,E) // std::cout<<"vector = ("<<p1[0]<<","<<p1[1]<<","<<p1[2]<<","<<p1[3]<<")\n"; return p1[3]*c0-p1[0]*c1-p1[1]*c2-p1[2]*c3; } COM CCurrent::dot(CCurrent p1) { return p1.c0*c0-p1.c1*c1-p1.c2*c2-p1.c3*c3; } //Current Functions // Current for <outgoing state | mu | incoming state> /// @TODO always use this instead of "j" /// @TODO isn't this jio with flipt helicities? void joi(HLV pout, bool helout, HLV pin, bool helin, current &cur) { cur[0]=0.; cur[1]=0.; cur[2]=0.; cur[3]=0.; const double sqpop = sqrt(pout.plus()); const double sqpom = sqrt(pout.minus()); const COM poperp = pout.x() + COM(0, 1) * pout.y(); if (helout != helin) { throw std::invalid_argument{"Non-matching helicities"}; } else if (helout == false) { // negative helicity if (pin.plus() > pin.minus()) { // if forward const double sqpip = sqrt(pin.plus()); cur[0] = sqpop * sqpip; cur[1] = sqpom * sqpip * poperp / abs(poperp); cur[2] = -COM(0,1) * cur[1]; cur[3] = cur[0]; } else { // if backward const double sqpim = sqrt(pin.minus()); cur[0] = -sqpom * sqpim * poperp / abs(poperp); cur[1] = -sqpim * sqpop; cur[2] = COM(0,1) * cur[1]; cur[3] = -cur[0]; } } else { // positive helicity if (pin.plus() > pin.minus()) { // if forward const double sqpip = sqrt(pin.plus()); cur[0] = sqpop * sqpip; cur[1] = sqpom * sqpip * conj(poperp) / abs(poperp); cur[2] = COM(0,1) * cur[1]; cur[3] = cur[0]; } else { // if backward const double sqpim = sqrt(pin.minus()); cur[0] = -sqpom * sqpim * conj(poperp) / abs(poperp); cur[1] = -sqpim * sqpop; cur[2] = -COM(0,1) * cur[1]; cur[3] = -cur[0]; } } } CCurrent joi (HLV pout, bool helout, HLV pin, bool helin) { current cur; joi(pout, helout, pin, helin, cur); return CCurrent(cur[0],cur[1],cur[2],cur[3]); } /// @TODO remove this void j (HLV pout, bool helout, HLV pin, bool helin,current &cur) { joi(pout, helout, pin, helin, cur); } /// @TODO remove this CCurrent j (HLV pout, bool helout, HLV pin, bool helin) { return joi(pout, helout, pin, helin); } // Current for <incoming state | mu | outgoing state> void jio(HLV pin, bool helin, HLV pout, bool helout, current &cur) { cur[0] = 0.0; cur[1] = 0.0; cur[2] = 0.0; cur[3] = 0.0; const double sqpop = sqrt(pout.plus()); const double sqpom = sqrt(pout.minus()); const COM poperp = pout.x() + COM(0, 1) * pout.y(); if (helout != helin) { throw std::invalid_argument{"Non-matching helicities"}; } else if (helout == false) { // negative helicity if (pin.plus() > pin.minus()) { // if forward const double sqpip = sqrt(pin.plus()); cur[0] = sqpop * sqpip; cur[1] = sqpom * sqpip * conj(poperp) / abs(poperp); cur[2] = COM(0,1) * cur[1]; cur[3] = cur[0]; } else { // if backward const double sqpim = sqrt(pin.minus()); cur[0] = -sqpom * sqpim * conj(poperp) / abs(poperp); cur[1] = -sqpim * sqpop; cur[2] = -COM(0,1) * cur[1]; cur[3] = -cur[0]; } } else { // positive helicity if (pin.plus() > pin.minus()) { // if forward const double sqpip = sqrt(pin.plus()); cur[0] = sqpop * sqpip; cur[1] = sqpom * sqpip * poperp / abs(poperp); cur[2] = -COM(0,1) * cur[1]; cur[3] = cur[0]; } else { // if backward const double sqpim = sqrt(pin.minus()); cur[0] = -sqpom * sqpim * poperp / abs(poperp); cur[1] = -sqpim * sqpop; cur[2] = COM(0,1) * cur[1]; cur[3] = -cur[0]; } } } CCurrent jio (HLV pin, bool helin, HLV pout, bool helout) { current cur; jio(pin, helin, pout, helout, cur); return CCurrent(cur[0],cur[1],cur[2],cur[3]); } // Current for <outgoing state | mu | outgoing state> void joo(HLV pi, bool heli, HLV pj, bool helj, current &cur) { // Zero our current cur[0] = 0.0; cur[1] = 0.0; cur[2] = 0.0; cur[3] = 0.0; if (heli!=helj) { throw std::invalid_argument{"Non-matching helicities"}; } else if ( heli == true ) { // If positive helicity swap momenta std::swap(pi,pj); } const double sqpjp = sqrt(pj.plus()); const double sqpjm = sqrt(pj.minus()); const double sqpip = sqrt(pi.plus()); const double sqpim = sqrt(pi.minus()); const COM piperp = pi.x() + COM(0,1) * pi.y(); const COM pjperp = pj.x() + COM(0,1) * pj.y(); const COM phasei = piperp / abs(piperp); const COM phasej = pjperp / abs(pjperp); cur[0] = sqpim * sqpjm * phasei * conj(phasej) + sqpip * sqpjp; cur[1] = sqpim * sqpjp * phasei + sqpip * sqpjm * conj(phasej); cur[2] = -COM(0, 1) * (sqpim * sqpjp * phasei - sqpip * sqpjm * conj(phasej)); cur[3] = -sqpim * sqpjm * phasei * conj(phasej) + sqpip * sqpjp; } CCurrent joo (HLV pi, bool heli, HLV pj, bool helj) { current cur; joo(pi, heli, pj, helj, cur); return CCurrent(cur[0],cur[1],cur[2],cur[3]); } namespace { /// @TODO unused function // double jM2 (CLHEP::HepLorentzVector p1out, bool hel1out, CLHEP::HepLorentzVector p1in, bool hel1in, CLHEP::HepLorentzVector p2out, bool hel2out, CLHEP::HepLorentzVector p2in, bool hel2in) // { // CLHEP::HepLorentzVector q1=p1in-p1out; // CLHEP::HepLorentzVector q2=-(p2in-p2out); // current C1,C2; // j (p1out,hel1out,p1in,hel1in, C1); // j (p2out,hel2out,p2in,hel2in, C2); // std::cout << "# From Currents, C1 : ("<<C1[0]<<","<<C1[1]<<","<<C1[2]<<","<<C1[3]<<"\n"; // std::cout << "# From Currents, C2 : ("<<C2[0]<<","<<C2[1]<<","<<C2[2]<<","<<C2[3]<<"\n"; // COM M=cdot(C1,C2); // return (M*conj(M)).real()/(q1.m2()*q2.m2()); // } } // namespace anonymous double jM2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { // std::cerr<<"Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; current mj1m,mj1p,mj2m,mj2p; joi(p1out,true,p1in,true,mj1p); joi(p1out,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); double sst=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm); // Multiply by Cf^2 return HEJ::C_F*HEJ::C_F*(sst)/(q1.m2()*q2.m2()); } double jM2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; joi(p1out,true,p1in,true,mj1p); joi(p1out,false,p1in,false,mj1m); jio(p2in,true,p2out,true,mj2p); jio(p2in,false,p2out,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); double sumsq=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm); // Multiply by Cf^2 return C_F*C_F*(sumsq)/(q1.m2()*q2.m2()); } double jM2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) { CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; jio(p1in,true,p1out,true,mj1p); jio(p1in,false,p1out,false,mj1m); jio(p2in,true,p2out,true,mj2p); jio(p2in,false,p2out,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); double sumsq=abs2(Mmm)+abs2(Mmp)+abs2(Mpp)+abs2(Mpm); // Multiply by Cf^2 return C_F*C_F*(sumsq)/(q1.m2()*q2.m2()); } double jM2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qg scattering // p1: quark // p2: gluon { CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; joi(p1out,true,p1in,true,mj1p); joi(p1out,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); const double K = K_g(p2out, p2in); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double a2Mpp=abs2(Mpp); double a2Mpm=abs2(Mpm); double sst = K/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm); // Cf*Ca=4 return C_F*C_A*sst/(q1.m2()*q2.m2()); } double jM2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for qg scattering // p1: quark // p2: gluon { CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; jio(p1in,true,p1out,true,mj1p); jio(p1in,false,p1out,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); const double K = K_g(p2out, p2in); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double a2Mpp=abs2(Mpp); double a2Mpm=abs2(Mpm); double sst = K/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm); // Cf*Ca=4 return C_F*C_A*sst/(q1.m2()*q2.m2()); } double jM2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in) // Calculates the square of the current contractions for gg scattering // p1: gluon // p2: gluon { CLHEP::HepLorentzVector q1=p1in-p1out; CLHEP::HepLorentzVector q2=-(p2in-p2out); current mj1m,mj1p,mj2m,mj2p; joi(p1out,true,p1in,true,mj1p); joi(p1out,false,p1in,false,mj1m); joi(p2out,true,p2in,true,mj2p); joi(p2out,false,p2in,false,mj2m); COM Mmp=cdot(mj1m,mj2p); COM Mmm=cdot(mj1m,mj2m); COM Mpp=cdot(mj1p,mj2p); COM Mpm=cdot(mj1p,mj2m); const double K_g1 = K_g(p1out, p1in); const double K_g2 = K_g(p2out, p2in); // sum of spinor strings ||^2 double a2Mmp=abs2(Mmp); double a2Mmm=abs2(Mmm); double a2Mpp=abs2(Mpp); double a2Mpm=abs2(Mpm); double sst = K_g1/C_A*K_g2/C_A*(a2Mpp+a2Mpm+a2Mmp+a2Mmm); // Ca*Ca=9 return C_A*C_A*sst/(q1.m2()*q2.m2()); } namespace { /** * @brief Higgs vertex contracted with current @param C1 and @param C2 */ COM cHdot(const current & C1, const current & C2, const current & q1, const current & q2, double mt, bool incBot, double mb) { if (mt == infinity) { return (cdot(C1,C2)*cdot(q1,q2)-cdot(C1,q2)*cdot(C2,q1))/(6*M_PI*HEJ::vev); } else { CLHEP::HepLorentzVector vq1,vq2; vq1.set(q1[1].real(),q1[2].real(),q1[3].real(),q1[0].real()); vq2.set(q2[1].real(),q2[2].real(),q2[3].real(),q2[0].real()); // first minus sign obtained because of q1-difference to VDD // std::cout<<"A1 : " << A1(-vq1,vq2)<<std::endl; // std::cout<<"A2 : " << A2(-vq1,vq2)<<std::endl; if(!(incBot)) // Factor is because 4 mt^2 g^2/HEJ::vev A1 -> 16 pi mt^2/HEJ::vev alphas, // and we divide by a factor 4 at the amp sqaured level later // which I absorb here (i.e. I divide by 2) /// @TODO move factor 1/2 from S to |ME|^2 => consistent with general notation return 8.*M_PI*mt*mt/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mt)-cdot(C1,C2)*A2(-vq1,vq2,mt)); else return 8.*M_PI*mt*mt/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mt)-cdot(C1,C2)*A2(-vq1,vq2,mt)) + 8.*M_PI*mb*mb/HEJ::vev*(-cdot(C1,q2)*cdot(C2,q1)*A1(-vq1,vq2,mb)-cdot(C1,C2)*A2(-vq1,vq2,mb)); } } } // namespace anonymous double MH2qQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { // CLHEP::HepLorentzVector q1=p1in-p1out; // CLHEP::HepLorentzVector q2=-(p2in-p2out); current j1p,j1m,j2p,j2m, q1v, q2v; joi (p1out,true,p1in,true,j1p); joi (p1out,false,p1in,false,j1m); joi (p2out,true,p2in,true,j2p); joi (p2out,false,p2in,false,j2m); to_current(q1, q1v); to_current(q2, q2v); COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm); // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2qQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { // CLHEP::HepLorentzVector q1=p1in-p1out; // CLHEP::HepLorentzVector q2=-(p2in-p2out); current j1p,j1m,j2p,j2m,q1v,q2v; joi (p1out,true,p1in,true,j1p); joi (p1out,false,p1in,false,j1m); jio (p2in,true,p2out,true,j2p); jio (p2in,false,p2out,false,j2m); to_current(q1, q1v); to_current(q2, q2v); COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm); // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2qbarQ (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { // CLHEP::HepLorentzVector q1=p1in-p1out; // CLHEP::HepLorentzVector q2=-(p2in-p2out); current j1p,j1m,j2p,j2m,q1v,q2v; jio (p1in,true,p1out,true,j1p); jio (p1in,false,p1out,false,j1m); joi (p2out,true,p2in,true,j2p); joi (p2out,false,p2in,false,j2m); to_current(q1, q1v); to_current(q2, q2v); COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm); // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2qbarQbar (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { // CLHEP::HepLorentzVector q1=p1in-p1out; // CLHEP::HepLorentzVector q2=-(p2in-p2out); current j1p,j1m,j2p,j2m,q1v,q2v; jio (p1in,true,p1out,true,j1p); jio (p1in,false,p1out,false,j1m); jio (p2in,true,p2out,true,j2p); jio (p2in,false,p2out,false,j2m); to_current(q1, q1v); to_current(q2, q2v); COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); double sst=abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm); // return (4./3.)*(4./3.)*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2qg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) // q~p1 g~p2 (i.e. ALWAYS p1 for quark, p2 for gluon) // should be called with q1 meant to be contracted with p2 in first part of vertex // (i.e. if g is backward, q1 is forward) { current j1p,j1m,j2p,j2m,q1v,q2v; joi (p1out,true,p1in,true,j1p); joi (p1out,false,p1in,false,j1m); joi (p2out,true,p2in,true,j2p); joi (p2out,false,p2in,false,j2m); to_current(q1, q1v); to_current(q2, q2v); // First, calculate the non-flipping amplitudes: COM Mpp=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); COM Mpm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); COM Mmp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); COM Mmm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); //cout << "Bits in MH2qg: " << Mpp << " " << Mpm << " " << Mmp << " " << Mmm << endl; const double K = K_g(p2out, p2in); double sst=K/C_A*(abs2(Mmp)+abs2(Mmm)+abs2(Mpp)+abs2(Mpm)); // Cf*Ca=4 // return 4.*sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return sst/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2qbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) // qbar~p1 g~p2 (i.e. ALWAYS p1 for anti-quark, p2 for gluon) // should be called with q1 meant to be contracted with p2 in first part of vertex // (i.e. if g is backward, q1 is forward) { current j1p,j1m,j2p,j2m,q1v,q2v; jio (p1in,true,p1out,true,j1p); jio (p1in,false,p1out,false,j1m); joi (p2out,true,p2in,true,j2p); joi (p2out,false,p2in,false,j2m); to_current(q1, q1v); to_current(q2, q2v); // First, calculate the non-flipping amplitudes: COM amp,amm,apm,app; app=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); apm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); amp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); amm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); double MH2sum = abs2(app)+abs2(amm)+abs2(apm)+abs2(amp); const double K = K_g(p2out, p2in); MH2sum*=K/C_A; // Cf*Ca=4 // return 4.*MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } double MH2gg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) // g~p1 g~p2 // should be called with q1 meant to be contracted with p2 in first part of vertex // (i.e. if g is backward, q1 is forward) { current j1p,j1m,j2p,j2m,q1v,q2v; joi (p1out,true,p1in,true,j1p); joi (p1out,false,p1in,false,j1m); joi (p2out,true,p2in,true,j2p); joi (p2out,false,p2in,false,j2m); to_current(q1, q1v); to_current(q2, q2v); // First, calculate the non-flipping amplitudes: COM amp,amm,apm,app; app=cHdot(j1p,j2p,q1v,q2v,mt, incBot, mb); apm=cHdot(j1p,j2m,q1v,q2v,mt, incBot, mb); amp=cHdot(j1m,j2p,q1v,q2v,mt, incBot, mb); amm=cHdot(j1m,j2m,q1v,q2v,mt, incBot, mb); double MH2sum = abs2(app)+abs2(amm)+abs2(apm)+abs2(amp); const double K_g1 = K_g(p1out, p1in); const double K_g2 = K_g(p2out, p2in); MH2sum*=K_g1/C_A*K_g2/C_A; // Ca*Ca=9 // return 9.*MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); return MH2sum/((p1in-p1out).m2()*(p2in-p2out).m2()*q1.m2()*q2.m2()); } // // Z's stuff // void jZ(HLV pin, HLV pout, HLV pem, HLV pep, bool HelPartons, bool HelLeptons, current cur) { // // Init current to zero // cur[0] = 0.0; // cur[1] = 0.0; // cur[2] = 0.0; // cur[3] = 0.0; // // Temporary variables // COM temp; // current Term_1, Term_2, Term_3, Term_4, J_temp, TempCur1, TempCur2; // // Momentum of virtual gluons aroun weak boson emission site // HLV qa = pout + pep + pem; // HLV qb = pin - pep - pem; // double ta = qa.m2(); // double tb = qb.m2(); // // Out-Out currents: // current Em_Ep, Out_Em, Out_Ep; // // Other currents: // current Out_In, Em_In, Ep_In; // joi(pout, HelPartons, pin, HelPartons, Out_In); // joi(pem, HelLeptons, pin, HelPartons, Em_In); // joi(pep, HelLeptons, pin, HelPartons, Ep_In); // joo(pem, HelLeptons, pep, HelLeptons, Em_Ep); // joo(pout, HelPartons, pem, HelLeptons, Out_Em); // joo(pout, HelPartons, pep, HelLeptons, Out_Ep); // if (HelLeptons == HelPartons) { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, Out_In, Term_1); // temp = cdot(Out_Em, Em_Ep); // cmult(temp / ta , Em_In, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, Out_In, Term_3); // temp = -cdot(Ep_In, Em_Ep); // cmult(temp / tb, Out_Ep, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // else { // if (HelPartons == true) { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, Out_In, Term_1); // joo(pout, true, pep, true, TempCur1); // joi(pep, true, pin, true, TempCur2); // temp = cdot(TempCur1, Em_Ep); // cmult(temp / ta , TempCur2, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, Out_In, Term_3); // joo(pout, true, pem, true, TempCur1); // joi(pem, true, pin, true, TempCur2); // temp = -cdot(TempCur2, Em_Ep); // cmult(temp / tb, TempCur1, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // else { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, Out_In, Term_1); // joo(pout, false, pep, false, TempCur1); // joi(pep, false, pin, false, TempCur2); // temp = cdot(TempCur1, Em_Ep); // cmult(temp / ta, TempCur2, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, Out_In, Term_3); // joo(pout, false, pem, false, TempCur1); // joi(pem, false, pin, false, TempCur2); // temp = -cdot(TempCur2, Em_Ep); // cmult(temp / tb, TempCur1, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // } // } // void jZbar(HLV pin, HLV pout, HLV pem, HLV pep, bool HelPartons, bool HelLeptons, current cur) { // // Init current to zero // cur[0] = 0.0; // cur[1] = 0.0; // cur[2] = 0.0; // cur[3] = 0.0; // // Temporary variables // COM temp; // current Term_1, Term_2, Term_3, Term_4, J_temp, TempCur1, TempCur2; // // Transfered 4-momenta // HLV qa = pout + pep + pem; // HLV qb = pin - pep - pem; // // The square of the transfered 4-momenta // double ta = qa.m2(); // double tb = qb.m2(); // // Out-Out currents: // current Em_Ep, Em_Out, Ep_Out; // // In-Out currents: // current In_Out, In_Em, In_Ep; // // Safe to use the currents since helicity structure is ok // if (HelPartons == HelLeptons) { // jio(pin, HelPartons, pout, HelPartons, In_Out); // joo(pem, HelLeptons, pep, HelLeptons, Em_Ep); // jio(pin, HelPartons, pem, HelLeptons, In_Em); // jio(pin, HelPartons, pep, HelLeptons, In_Ep); // joo(pem, HelLeptons, pout, HelPartons, Em_Out); // joo(pep, HelLeptons, pout, HelPartons, Ep_Out); // } // else { // jio(pin, HelPartons, pout, HelPartons, In_Out); // joo(pem, HelLeptons, pep, HelLeptons, Em_Ep); // In_Em[0] = 0.0; // In_Em[1] = 0.0; // In_Em[2] = 0.0; // In_Em[3] = 0.0; // In_Ep[0] = 0.0; // In_Ep[1] = 0.0; // In_Ep[2] = 0.0; // In_Ep[3] = 0.0; // Em_Out[0] = 0.0; // Em_Out[1] = 0.0; // Em_Out[2] = 0.0; // Em_Out[3] = 0.0; // Ep_Out[0] = 0.0; // Ep_Out[1] = 0.0; // Ep_Out[2] = 0.0; // Ep_Out[3] = 0.0; // } // if (HelLeptons == HelPartons) { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, In_Out, Term_1); // temp = cdot(Ep_Out, Em_Ep); // cmult(temp / ta, In_Ep, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, In_Out, Term_3); // temp = - cdot(In_Em, Em_Ep); // cmult(temp / tb, Em_Out, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // else { // if (HelPartons == true) { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, In_Out, Term_1); // joo(pem, true, pout, true, TempCur1); // jio(pin, true, pem, true, TempCur2); // temp = cdot(TempCur1, Em_Ep); // cmult(temp / ta , TempCur2, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, In_Out, Term_3); // joo(pep, true, pout, true, TempCur1); // jio(pin, true, pep, true, TempCur2); // temp = - cdot(TempCur2, Em_Ep); // cmult(temp / tb, TempCur1, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // else { // temp = 2.0 * cdot(pout, Em_Ep); // cmult(temp / ta, In_Out, Term_1); // joo(pem, false, pout, false, TempCur1); // jio(pin, false, pem, false, TempCur2); // temp = cdot(TempCur1, Em_Ep); // cmult(temp / ta , TempCur2, Term_2); // temp = 2.0 * cdot(pin, Em_Ep); // cmult(temp / tb, In_Out, Term_3); // joo(pep, false, pout, false, TempCur1); // jio(pin, false, pep, false, TempCur2); // temp = - cdot(TempCur2, Em_Ep); // cmult(temp / tb, TempCur1, Term_4); // cadd(Term_1, Term_2, Term_3, Term_4, J_temp); // cur[0] = J_temp[0]; // cur[1] = J_temp[1]; // cur[2] = J_temp[2]; // cur[3] = J_temp[3]; // } // } // } // // Progagators // COM PZ(double s) { // double MZ, GammaZ; // MZ = 9.118800e+01; // Mass of the mediating gauge boson // GammaZ = 2.441404e+00; // Z peak width // // Return Z Prop value // return 1.0 / (s - MZ * MZ + COM(0.0, 1.0) * GammaZ * MZ); // } // COM PG(double s) { // return 1.0 / s; // } // // Non-gluonic with pa emitting // std::vector <double> jMZqQ (HLV pa, HLV pb, HLV p1, HLV p2, HLV pep, HLV pem, std::vector <double> VProducts, std::vector < std::vector <double> > Virtuals, int aptype, int bptype, bool UseVirtuals, bool BottomLineEmit) { // std::vector <double> ScaledWeights; // double Sum; // // Propagator factors // COM PZs = PZ((pep + pem).m2()); // COM PGs = PG((pep + pem).m2()); // // Emitting current initialisation // current j1pptop, j1pmtop; // Emission from top line // current j1ppbot, j1pmbot; // Emission from bottom line // // Non-emitting current initialisation // current j2ptop, j2mtop; // Emission from top line // current j2pbot, j2mbot; // Emission from bottom line // // Currents for top emission // // Upper current calculations // // if a is a quark // if (aptype > 0) { // jZ(pa, p1, pem, pep, true, true, j1pptop); // jZ(pa, p1, pem, pep, true, false, j1pmtop); // } // // if a is an antiquark // else { // jZbar(pa, p1, pem, pep, true, true, j1pptop); // jZbar(pa, p1, pem, pep, true, false, j1pmtop); // } // // Lower current calculations // // if b is a quark // if (bptype > 0) { // joi(p2, true, pb, true, j2ptop); // joi(p2, false, pb, false, j2mtop); // } // // if b is an antiquark // else { // jio(pb, true, p2, true, j2ptop); // jio(pb, false, p2, false, j2mtop); // } // // Currents for bottom emission // // Lower current calculations // if (bptype > 0) { // jZ(pb, p2, pem, pep, true, true, j1ppbot); // jZ(pb, p2, pem, pep, true, false, j1pmbot); // } // else { // jZbar(pb, p2, pem, pep, true, true, j1ppbot); // jZbar(pb, p2, pem, pep, true, false, j1pmbot); // } // // Upper current calculations // if (aptype > 0) { // joi(p1, true, pa, true, j2pbot); // joi(p1, false, pa, false, j2mbot); // } // else { // jio(pa, true, p1, true, j2pbot); // jio(pa, false, p1, false, j2mbot); // } // COM Coeff[2][8]; // if (!Interference) { // double ZCharge_a_P = Zq(aptype, true); // double ZCharge_a_M = Zq(aptype, false); // double ZCharge_b_P = Zq(bptype, true); // double ZCharge_b_M = Zq(bptype, false); // if (BottomLineEmit) { // // Emission from top-line quark (pa/p1 line) // Coeff[0][0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2ptop); // Coeff[0][1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2mtop); // Coeff[0][2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2ptop); // Coeff[0][3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2mtop); // Coeff[0][4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop)); // Coeff[0][5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop)); // Coeff[0][6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop)); // Coeff[0][7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop)); // } // else { // // Emission from bottom-line quark (pb/p2 line) // Coeff[1][0] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1ppbot, j2pbot); // Coeff[1][7] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1ppbot, j2mbot); // Coeff[1][2] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1pmbot, j2pbot); // Coeff[1][5] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1pmbot, j2mbot); // Coeff[1][4] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2pbot)); // Coeff[1][3] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2mbot)); // Coeff[1][6] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2pbot)); // Coeff[1][1] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2mbot)); // } // } // // Else calculate all the possiblities // else { // double ZCharge_a_P = Zq(aptype, true); // double ZCharge_a_M = Zq(aptype, false); // double ZCharge_b_P = Zq(bptype, true); // double ZCharge_b_M = Zq(bptype, false); // // Emission from top-line quark (pa/p1 line) // Coeff[0][0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2ptop); // Coeff[0][1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2mtop); // Coeff[0][2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2ptop); // Coeff[0][3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2mtop); // Coeff[0][4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop)); // Coeff[0][5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop)); // Coeff[0][6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop)); // Coeff[0][7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop)); // // Emission from bottom-line quark (pb/p2 line) // Coeff[1][0] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1ppbot, j2pbot); // Coeff[1][7] = (ZCharge_b_P * Zep * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1ppbot, j2mbot); // Coeff[1][2] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1pmbot, j2pbot); // Coeff[1][5] = (ZCharge_b_P * Zem * PZs * RWeak + Gq(bptype) * PGs) * cdot(j1pmbot, j2mbot); // Coeff[1][4] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2pbot)); // Coeff[1][3] = (ZCharge_b_M * Zem * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1ppbot, j2mbot)); // Coeff[1][6] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2pbot)); // Coeff[1][1] = (ZCharge_b_M * Zep * PZs * RWeak + Gq(bptype) * PGs) * conj(cdot(j1pmbot, j2mbot)); // } // // Find the numbers of scales // int ScaleCount; // #if calcscaleunc // ScaleCount = 20; // #else // ScaleCount = 1; // #endif // // For each scale... // for (int j = 0; j < ScaleCount; j++) { // Sum = 0.0; // // If we want to compare back to the W's code only emit from one quark and only couple to left handed particles // // virtuals arent here since they are calculated and included in weight() call. // if (!Interference) { // if (BottomLineEmit) for (int i = 0; i < 8; i++) Sum += abs2(Coeff[1][i]) * VProducts.at(1); // else for (int i = 0; i < 8; i++) Sum += abs2(Coeff[0][i]) * VProducts.at(0); // } // // Else work out the full interference // else { // // For the full calculation... // if (UseVirtuals) { // for (int i = 0; i < 8; i++) { // Sum += abs2(Coeff[0][i]) * VProducts.at(0) * Virtuals.at(j).at(0) // + abs2(Coeff[1][i]) * VProducts.at(1) * Virtuals.at(j).at(1) // + 2.0 * real(Coeff[0][i] * conj(Coeff[1][i])) * VProducts.at(2) * Virtuals.at(j).at(2); // } // } // // For the tree level calculation... // else { // for (int i = 0; i < 8; i++) { // Sum += abs2(Coeff[0][i]) * VProducts.at(0) // + abs2(Coeff[1][i]) * VProducts.at(1) // + 2.0 * real(Coeff[0][i] * conj(Coeff[1][i])) * VProducts.at(2); // } // } // } // // Add this to the vector to be returned with the other factors of C_A and the helicity sum/average factors. // ScaledWeights.push_back(Sum / 18.0); // } // // Return all the scale values // return ScaledWeights; // } // // Semi-gluonic with pa emitting // std::vector <double> jMZqg (HLV pa, HLV pb, HLV p1, HLV p2, HLV pep, HLV pem, std::vector <double> VProducts, std::vector < std::vector <double> > Virtuals, int aptype, int bptype, bool UseVirtuals, bool BottomLineEmit) { // COM Coeff[8]; // double Sum; // std::vector <double> ScaledWeights; // COM PZs = PZ((pep + pem).m2()); // COM PGs = PG((pep + pem).m2()); // // Emitting current initialisation - Emission from top line // current j1pptop, j1pmtop; // // Non-emitting current initialisation - Emission from top line // current j2ptop, j2mtop; // // Currents for top emission // // Upper current calculations // if (aptype > 0) { // jZ (pa, p1, pem, pep, true, true, j1pptop); // jZ (pa, p1, pem, pep, true, false, j1pmtop); // } // else { // jZbar(pa, p1, pem, pep, true, true, j1pptop); // jZbar(pa, p1, pem, pep, true, false, j1pmtop); // } // // Lower current calculations // joi(p2, true, pb, true, j2ptop); // joi(p2, false, pb, false, j2mtop); // // Calculate all the possiblities // double ZCharge_a_P = Zq(aptype, true); // double ZCharge_a_M = Zq(aptype, false); // // Emission from top-line quark (pa/p1 line) // Coeff[0] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2ptop); // Coeff[1] = (ZCharge_a_P * Zep * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pptop, j2mtop); // Coeff[2] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2ptop); // Coeff[3] = (ZCharge_a_P * Zem * PZs * RWeak + Gq(aptype) * PGs) * cdot(j1pmtop, j2mtop); // Coeff[4] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2ptop)); // Coeff[5] = (ZCharge_a_M * Zem * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pptop, j2mtop)); // Coeff[6] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2ptop)); // Coeff[7] = (ZCharge_a_M * Zep * PZs * RWeak + Gq(aptype) * PGs) * conj(cdot(j1pmtop, j2mtop)); // // Calculate gluon colour accelerated factor // double CAMFactor, z; // // If b is a forward moving gluon define z (C.F. multiple jets papers) // if (pb.pz() > 0) z = p2.plus() / pb.plus(); // else z = p2.minus() / pb.minus(); // CAMFactor = (1.0 - 1.0 / 9.0) / 2.0 * (z + 1.0 / z) + 1.0 / 9.0; // // Find the numbers of scales // int ScaleCount; // #if calcscaleunc // ScaleCount = 20; // #else // ScaleCount = 1; // #endif // // For each scale... // for (int j = 0; j < ScaleCount; j++) { // Sum = 0.0; // // If we dont want the interference // if (!Interference) for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0); // // Else work out the full interference // else { // if (UseVirtuals) { // for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0) * Virtuals.at(j).at(0); // } // else { // for (int i = 0; i < 8; i++) Sum += abs2(Coeff[i]) * VProducts.at(0); // } // } // // Add this to the vector to be returned with the other factors of C_A, the colour accelerated factor and the helicity sum/average factors.: (4/3)*3/32 // ScaledWeights.push_back(CAMFactor * Sum / 8.0); // } // return ScaledWeights; // } // // Electroweak Charge Functions // double Zq (int PID, bool Helcitiy) { // double temp; // // Positive Spin // if (Helcitiy == true) { // if (PID == 1 || PID == 3 || PID == 5) temp = (+ 1.0 * stw2 / 3.0) / ctw; // if (PID == 2 || PID == 4) temp = (- 2.0 * stw2 / 3.0) / ctw; // if (PID == -1 || PID == -3 || PID == -5) temp = (- 1.0 * stw2 / 3.0) / ctw; // if (PID == -2 || PID == -4) temp = (+ 2.0 * stw2 / 3.0) / ctw; // // If electron or positron // if (PID == 7 || PID == -7) temp = Zep; // } // // Negative Spin // else { // if (PID == 1 || PID == 3 || PID == 5) temp = (-0.5 + 1.0 * stw2 / 3.0) / ctw; // if (PID == 2 || PID == 4) temp = ( 0.5 - 2.0 * stw2 / 3.0) / ctw; // if (PID == -1 || PID == -3 || PID == -5) temp = ( 0.5 - 1.0 * stw2 / 3.0) / ctw; // if (PID == -2 || PID == -4) temp = (-0.5 + 2.0 * stw2 / 3.0) / ctw; // // If electron or positron // if (PID == 7 || PID == -7) temp = Zem; // } // return temp; // } // double Gq (int PID) { // if (!VirtualPhoton) return 0.0; // if (PID == -1) return 1.0 * ee / 3.0; // if (PID == -2) return -2.0 * ee / 3.0; // if (PID == -3) return 1.0 * ee / 3.0; // if (PID == -4) return -2.0 * ee / 3.0; // if (PID == -5) return 1.0 * ee / 3.0; // if (PID == 1) return -1.0 * ee / 3.0; // if (PID == 2) return 2.0 * ee / 3.0; // if (PID == 3) return -1.0 * ee / 3.0; // if (PID == 4) return 2.0 * ee / 3.0; // if (PID == 5) return -1.0 * ee / 3.0; // std::cout << "ERROR! No Electroweak Charge Found at line " << __LINE__ << "..." << std::endl; // return 0.0; // } namespace { //@{ /// @brief Higgs vertex contracted with one current CCurrent jH (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { CCurrent j2 = joi(pout,helout,pin,helin); CCurrent jq2(q2.e(),q2.px(),q2.py(),q2.pz()); if(mt == infinity) return ((q1.dot(q2))*j2 - j2.dot(q1)*jq2)/(3*M_PI*HEJ::vev); else { if(incBot) return (-16.*M_PI*mb*mb/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j2*A2(-q1,q2,mb)) + (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt)); else return (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt)); } } CCurrent jioH (CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { CCurrent j2 = jio(pin,helin,pout,helout); CCurrent jq2(q2.e(),q2.px(),q2.py(),q2.pz()); if(mt == infinity) return ((q1.dot(q2))*j2 - j2.dot(q1)*jq2)/(3*M_PI*HEJ::vev); else { if(incBot) return (-16.*M_PI*mb*mb/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j2*A2(-q1,q2,mb)) + (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt)); else return (-16.*M_PI*mt*mt/HEJ::vev*j2.dot(q1)*jq2*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j2*A2(-q1,q2,mt)); } } CCurrent jHtop (CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { CCurrent j1 = joi(pout,helout,pin,helin); CCurrent jq1(q1.e(),q1.px(),q1.py(),q1.pz()); if(mt == infinity) return ((q1.dot(q2))*j1 - j1.dot(q2)*jq1)/(3*M_PI*HEJ::vev); else { if(incBot) return (-16.*M_PI*mb*mb/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j1*A2(-q1,q2,mb)) + (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt)); else return (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt)); } } CCurrent jioHtop (CLHEP::HepLorentzVector pin, bool helin, CLHEP::HepLorentzVector pout, bool helout, CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mt, bool incBot, double mb) { CCurrent j1 = jio(pin,helin,pout,helout); CCurrent jq1(q1.e(),q1.px(),q1.py(),q1.pz()); if(mt == infinity) return ((q1.dot(q2))*j1 - j1.dot(q2)*jq1)/(3*M_PI*HEJ::vev); else { if(incBot) return (-16.*M_PI*mb*mb/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mb)-16.*M_PI*mb*mb/HEJ::vev*j1*A2(-q1,q2,mb)) + (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt)); else return (-16.*M_PI*mt*mt/HEJ::vev*j1.dot(q2)*jq1*A1(-q1,q2,mt)-16.*M_PI*mt*mt/HEJ::vev*j1*A2(-q1,q2,mt)); } } //@} } // namespace anonymous double jM2unogqHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=joi(p1out,true,p1in,true); mj1m=joi(p1out,false,p1in,false); mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb); mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // std::cout<< p1out.rapidity() << " " << p2out.rapidity()<< " " << qH1 << " " << qH2 << "\n" <<MHmm << " " << MHmp << " " << MHpm << " " << MHpp << std::endl; // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(p1out,true,pg,true); j2gm=joo(p1out,false,pg,false); jgap=joi(pg,true,p1in,true); jgam=joi(pg,false,p1in,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; ampsq*=HEJ::C_F*HEJ::C_F/HEJ::C_A/HEJ::C_A; // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unogqbarHQ (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=jio(p1in,true,p1out,true); mj1m=jio(p1in,false,p1out,false); mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb); mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(pg,true,p1out,true); j2gm=joo(pg,false,p1out,false); jgap=jio(p1in,true,pg,true); jgam=jio(p1in,false,pg,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unogqHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=joi(p1out,true,p1in,true); mj1m=joi(p1out,false,p1in,false); mjH2p=jioH(p2in,true,p2out,true,qH1,qH2, mt, incBot, mb); mjH2m=jioH(p2in,false,p2out,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(p1out,true,pg,true); j2gm=joo(p1out,false,pg,false); jgap=joi(pg,true,p1in,true); jgam=joi(pg,false,p1in,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unogqbarHQbar (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=jio(p1in,true,p1out,true); mj1m=jio(p1in,false,p1out,false); mjH2p=jioH(p2in,true,p2out,true,qH1,qH2, mt, incBot, mb); mjH2m=jioH(p2in,false,p2out,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(pg,true,p1out,true); j2gm=joo(pg,false,p1out,false); jgap=jio(p1in,true,pg,true); jgam=jio(p1in,false,pg,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; //Higgs coupling is included in Hjets.C ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. return ampsq; } double jM2unogqHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=joi(p1out,true,p1in,true); mj1m=joi(p1out,false,p1in,false); mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb); mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(p1out,true,pg,true); j2gm=joo(p1out,false,pg,false); jgap=joi(pg,true,p1in,true); jgam=joi(pg,false,p1in,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; ampsq*=4./9.*4./9.; // Factor of (Cf/Ca) for each quark to match MH2qQ. // here we need 2 to match with the normalization // gq is 9./4. times the qQ //Higgs coupling is included in Hjets.C const double K = K_g(p2out, p2in); return ampsq*K/C_A*9./4.; //ca/cf = 9/4 } double jM2unogqbarHg (CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // This construction is taking rapidity order: pg > p1out >> p2out // std::cerr<<"This Uno Current: "<<p1out<<" "<<p1in<<" "<<p2out<<" "<<p2in<<" "<<pg<<std::endl; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out); // Bottom End CLHEP::HepLorentzVector qg=p1in-p1out-pg; // Extra bit post-gluon CCurrent mj1m,mj1p,mj2m,mj2p,mjH2m,mjH2p; mj1p=jio(p1in,true,p1out,true); mj1m=jio(p1in,false,p1out,false); mjH2p=jH(p2out,true,p2in,true,qH1,qH2, mt, incBot, mb); mjH2m=jH(p2out,false,p2in,false,qH1,qH2, mt, incBot, mb); // Dot products of these which occur again and again COM MHmp=mj1m.dot(mjH2p); // And now for the Higgs ones COM MHmm=mj1m.dot(mjH2m); COM MHpp=mj1p.dot(mjH2p); COM MHpm=mj1p.dot(mjH2m); // Currents with pg CCurrent jgam,jgap,j2gm,j2gp; j2gp=joo(pg,true,p1out,true); j2gm=joo(pg,false,p1out,false); jgap=jio(p1in,true,pg,true); jgam=jio(p1in,false,pg,false); CCurrent qsum(q1+qg); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p2o(p2out),p2i(p2in); CCurrent p1o(p1out); CCurrent p1i(p1in); Lmm=(qsum*(MHmm) + (-2.*mjH2m.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmm/2.))/q1.m2(); Lmp=(qsum*(MHmp) + (-2.*mjH2p.dot(pg))*mj1m+2.*mj1m.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHmp/2.))/q1.m2(); Lpm=(qsum*(MHpm) + (-2.*mjH2m.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2m+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpm/2.))/q1.m2(); Lpp=(qsum*(MHpp) + (-2.*mjH2p.dot(pg))*mj1p+2.*mj1p.dot(pg)*mjH2p+(p2o/pg.dot(p2out) + p2i/pg.dot(p2in))*(qg.m2()*MHpp/2.))/q1.m2(); U1mm=(jgam.dot(mjH2m)*j2gm+2.*p1o*MHmm)/(p1out+pg).m2(); U1mp=(jgam.dot(mjH2p)*j2gm+2.*p1o*MHmp)/(p1out+pg).m2(); U1pm=(jgap.dot(mjH2m)*j2gp+2.*p1o*MHpm)/(p1out+pg).m2(); U1pp=(jgap.dot(mjH2p)*j2gp+2.*p1o*MHpp)/(p1out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH2m)*jgam+2.*p1i*MHmm)/(p1in-pg).m2(); U2mp=((-1.)*j2gm.dot(mjH2p)*jgam+2.*p1i*MHmp)/(p1in-pg).m2(); U2pm=((-1.)*j2gp.dot(mjH2m)*jgap+2.*p1i*MHpm)/(p1in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH2p)*jgap+2.*p1i*MHpp)/(p1in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q2.m2()*qH2.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH1.m2()*qg.m2(); ampsq/=th; ampsq/=16.; ampsq*=4./9.*4./9.; // Factor of (Cf/Ca) for each quark to match MH2qQ. // here we need 2 to match with the normalization // gq is 9./4. times the qQ //Higgs coupling is included in Hjets.C const double K = K_g(p2out, p2in); return ampsq*K/C_F; } double jM2unobqHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // std::cout << "####################\n"; // std::cout << "# p1in : "<<p1in<< " "<<p1in.plus()<<" "<<p1in.minus()<<std::endl; // std::cout << "# p2in : "<<p2in<< " "<<p2in.plus()<<" "<<p2in.minus()<<std::endl; // std::cout << "# p1out : "<<p1out<< " "<<p1out.rapidity()<<std::endl; // std::cout << "# (qH1-qH2) : "<<(qH1-qH2)<< " "<<(qH1-qH2).rapidity()<<std::endl; // std::cout << "# pg : "<<pg<< " "<<pg.rapidity()<<std::endl; // std::cout << "# p2out : "<<p2out<< " "<<p2out.rapidity()<<std::endl; // std::cout << "####################\n"; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2, mt, incBot, mb); mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2, mt, incBot, mb); mj2p=joi(p2out,true,p2in,true); mj2m=joi(p2out,false,p2in,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(p2out,true,pg,true); j2gm=joo(p2out,false,pg,false); jgbp=joi(pg,true,p2in,true); jgbm=joi(pg,false,p2in,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m + (p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p +(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); // 1/3. = 1/C_A ? double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs const double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=HEJ::C_F*HEJ::C_F/(HEJ::C_A*HEJ::C_A); // Factor of (Cf/Ca) for each quark to match MH2qQ. return ampsq; } double jM2unobqbarHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jioHtop(p1in,true,p1out,true,qH1,qH2, mt, incBot, mb); mjH1m=jioHtop(p1in,false,p1out,false,qH1,qH2, mt, incBot, mb); mj2p=joi(p2out,true,p2in,true); mj2m=joi(p2out,false,p2in,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(p2out,true,pg,true); j2gm=joo(p2out,false,pg,false); jgbp=joi(pg,true,p2in,true); jgbm=joi(pg,false,p2in,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unobqHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb); mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb); mj2p=jio(p2in,true,p2out,true); mj2m=jio(p2in,false,p2out,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(pg,true,p2out,true); j2gm=joo(pg,false,p2out,false); jgbp=jio(p2in,true,pg,true); jgbm=jio(p2in,false,pg,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unobqbarHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jioHtop(p1in,true,p1out,true,qH1,qH2,mt, incBot, mb); mjH1m=jioHtop(p1in,false,p1out,false,qH1,qH2,mt, incBot, mb); mj2p=jio(p2in,true,p2out,true); mj2m=jio(p2in,false,p2out,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(pg,true,p2out,true); j2gm=joo(pg,false,p2out,false); jgbp=jio(p2in,true,pg,true); jgbm=jio(p2in,false,pg,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=4.*4./(9.*9.); // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C return ampsq; } double jM2unobgHQg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { // std::cout << "####################\n"; // std::cout << "# p1in : "<<p1in<< " "<<p1in.plus()<<" "<<p1in.minus()<<std::endl; // std::cout << "# p2in : "<<p2in<< " "<<p2in.plus()<<" "<<p2in.minus()<<std::endl; // std::cout << "# p1out : "<<p1out<< " "<<p1out.rapidity()<<std::endl; // std::cout << "# (qH1-qH2) : "<<(qH1-qH2)<< " "<<(qH1-qH2).rapidity()<<std::endl; // std::cout << "# pg : "<<pg<< " "<<pg.rapidity()<<std::endl; // std::cout << "# p2out : "<<p2out<< " "<<p2out.rapidity()<<std::endl; // std::cout << "####################\n"; CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb); mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb); mj2p=joi(p2out,true,p2in,true); mj2m=joi(p2out,false,p2in,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(p2out,true,pg,true); j2gm=joo(p2out,false,pg,false); jgbp=joi(pg,true,p2in,true); jgbm=joi(pg,false,p2in,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=4./9.*4./9.; // Factor of (Cf/Ca) for each quark to match MH2qQ. // need twice to match the normalization //Higgs coupling is included in Hjets.C const double K = K_g(p1out, p1in); return ampsq*K/C_F; } double jM2unobgHQbarg (CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector pg, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector qH1, CLHEP::HepLorentzVector qH2, double mt, bool incBot, double mb) { CLHEP::HepLorentzVector q1=p1in-p1out; // Top End CLHEP::HepLorentzVector q2=-(p2in-p2out-pg); // Extra bit pre-gluon CLHEP::HepLorentzVector q3=-(p2in-p2out); // Bottom End // std::cerr<<"Current: "<<q1.m2()<<" "<<q2.m2()<<std::endl; CCurrent mjH1m,mjH1p,mj2m,mj2p; mjH1p=jHtop(p1out,true,p1in,true,qH1,qH2,mt, incBot, mb); mjH1m=jHtop(p1out,false,p1in,false,qH1,qH2,mt, incBot, mb); mj2p=jio(p2in,true,p2out,true); mj2m=jio(p2in,false,p2out,false); // Dot products of these which occur again and again COM MHmp=mjH1m.dot(mj2p); // And now for the Higgs ones COM MHmm=mjH1m.dot(mj2m); COM MHpp=mjH1p.dot(mj2p); COM MHpm=mjH1p.dot(mj2m); // Currents with pg CCurrent jgbm,jgbp,j2gm,j2gp; j2gp=joo(pg,true,p2out,true); j2gm=joo(pg,false,p2out,false); jgbp=jio(p2in,true,pg,true); jgbm=jio(p2in,false,pg,false); CCurrent qsum(q2+q3); CCurrent Lmp,Lmm,Lpp,Lpm,U1mp,U1mm,U1pp,U1pm,U2mp,U2mm,U2pp,U2pm,p1o(p1out),p1i(p1in); CCurrent p2o(p2out); CCurrent p2i(p2in); CCurrent pplus((p1in+p1out)/2.); CCurrent pminus((p2in+p2out)/2.); // COM test=pminus.dot(p1in); Lmm=((-1.)*qsum*(MHmm) + (-2.*mjH1m.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmm/2.))/q3.m2(); Lmp=((-1.)*qsum*(MHmp) + (-2.*mjH1m.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1m+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHmp/2.))/q3.m2(); Lpm=((-1.)*qsum*(MHpm) + (-2.*mjH1p.dot(pg))*mj2m+2.*mj2m.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpm/2.))/q3.m2(); Lpp=((-1.)*qsum*(MHpp) + (-2.*mjH1p.dot(pg))*mj2p+2.*mj2p.dot(pg)*mjH1p+(p1o/pg.dot(p1out) + p1i/pg.dot(p1in))*(q2.m2()*MHpp/2.))/q3.m2(); U1mm=(jgbm.dot(mjH1m)*j2gm+2.*p2o*MHmm)/(p2out+pg).m2(); U1mp=(jgbp.dot(mjH1m)*j2gp+2.*p2o*MHmp)/(p2out+pg).m2(); U1pm=(jgbm.dot(mjH1p)*j2gm+2.*p2o*MHpm)/(p2out+pg).m2(); U1pp=(jgbp.dot(mjH1p)*j2gp+2.*p2o*MHpp)/(p2out+pg).m2(); U2mm=((-1.)*j2gm.dot(mjH1m)*jgbm+2.*p2i*MHmm)/(p2in-pg).m2(); U2mp=((-1.)*j2gp.dot(mjH1m)*jgbp+2.*p2i*MHmp)/(p2in-pg).m2(); U2pm=((-1.)*j2gm.dot(mjH1p)*jgbm+2.*p2i*MHpm)/(p2in-pg).m2(); U2pp=((-1.)*j2gp.dot(mjH1p)*jgbp+2.*p2i*MHpp)/(p2in-pg).m2(); const double cf=HEJ::C_F; double amm,amp,apm,app; amm=cf*(2.*vre(Lmm-U1mm,Lmm+U2mm))+2.*cf*cf/3.*vabs2(U1mm+U2mm); amp=cf*(2.*vre(Lmp-U1mp,Lmp+U2mp))+2.*cf*cf/3.*vabs2(U1mp+U2mp); apm=cf*(2.*vre(Lpm-U1pm,Lpm+U2pm))+2.*cf*cf/3.*vabs2(U1pm+U2pm); app=cf*(2.*vre(Lpp-U1pp,Lpp+U2pp))+2.*cf*cf/3.*vabs2(U1pp+U2pp); double ampsq=-(amm+amp+apm+app)/(q1.m2()*qH1.m2()); // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) > 1.0000001) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // if ((vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm))/(2*vre(Lmm-U1mm,Lmm+U2mm)) < 0.9999999) // std::cout << " Big Problem!! " << vabs2(Lmm-U1mm+U2mm)+vabs2(Lmm)-vabs2(U1mm)-vabs2(U2mm) << " " << 2*vre(Lmm-U1mm,Lmm+U2mm) << std::endl; // Now add the t-channels for the Higgs double th=qH2.m2()*q2.m2(); ampsq/=th; ampsq/=16.; ampsq*=4./9.*4./9.; // Factor of (Cf/Ca) for each quark to match MH2qQ. //Higgs coupling is included in Hjets.C const double K = K_g(p1out, p1in); return ampsq*K/C_F; //ca/cf = 9/4 } // Begin finite mass stuff #ifdef HEJ_BUILD_WITH_QCDLOOP namespace { // All the stuff needed for the box functions in qg->qgH now... //COM E1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM E1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2=-(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor*(-s12*D0DD(k2, k1, q2, mq)*(1 - 8.*mq*mq/s12 + S2/(2.*s12) + S2*(s12 - 8.*mq*mq)*(s34 + S1)/(2.*s12*Delta) + 2.*(s34 + S1)*(s34 + S1)/Delta + S2*pow((s34 + S1),3)/Delta/Delta) - ((s12 + S2)*C0DD(k2, k1 + q2, mq) - s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) - S1*C0DD(k1, q2, mq))*(S2*(s12 - 4.*mq*mq)/(2.*s12*Delta) + 2.*(s34 + S1)/Delta + S2*pow((s34 + S1),2)/Delta/Delta) + (C0DD(k1, q2, mq) - C0DD(k1 + k2, q2, mq))*(1. - 4.*mq*mq/s12) - C0DD(k1 + k2, q2, mq)*2.*s34/ S1 - (B0DD(k1 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2.*s34*(s34 + S1)/(S1*Delta) + (B0DD(q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*(2.*s34*(s34 + S1)*(S1 - S2)/(Delta*Sigma) + 2.*s34*(s34 + S1)/(S1*Delta)) + (B0DD(k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*2.*(s34 + S1)*(2.*s12*s34 - S2*(S1 + S2))/(Delta*Sigma)); } //COM F1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM F1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor*(-S2*D0DD(k1, k2, q2, mq)*(0.5 - (s12 - 8.*mq*mq)*(s34 + S2)/(2.*Delta) - s12*pow((s34 + S2),3)/Delta/Delta) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) - s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) - S2*C0DD(k2, q2, mq))*(S2*(s12 - 4.*mq*mq)/(2.*s12*Delta) + S2*pow((s34 + S2),2)/Delta/Delta) - (C0DD(k1 + k2, q2, mq) - C0DD(k1, k2 + q2, mq))*(1. - 4.*mq*mq/s12) - C0DD(k1, k2 + q2, mq) + (B0DD(k2 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2.*pow((s34 + S2),2)/((s12 + S1)*Delta) - (B0DD( q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*2.*s34*(s34 + S2)*(S2 - S1)/(Delta*Sigma) + (B0DD( k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*2.*(s34 + S2)*(2.*s12*s34 - S2*(S1 + S2))/(Delta*Sigma)); } //COM G1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM G1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; return looprwfactor*(S2*D0DD(k1, q2, k2, mq)*(Delta/s12/s12 - 4.*mq*mq/s12) - S2*((s12 + S1)*C0DD(k1, k2 + q2, mq) - S1*C0DD(k1, q2, mq))*(1./ s12/s12 - (s12 - 4.*mq*mq)/(2.*s12*Delta)) - S2*((s12 + S2)*C0DD(k1 + q2, k2, mq) - S2*C0DD(k2, q2, mq))*(1./ s12/s12 + (s12 - 4.*mq*mq)/(2.*s12*Delta)) - C0DD(k1, q2, mq) - (C0DD(k1, k2 + q2, mq) - C0DD(k1, q2, mq))*4.*mq*mq/ s12 + (B0DD(k1 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2./ s12 + (B0DD(k1 + q2, mq) - B0DD(q2, mq))*2.*s34/(s12*S1) + (B0DD(k2 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2.*(s34 + S2)/(s12*(s12 + S1))); } //COM E4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM E4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor* (-s12*D0DD(k2, k1, q2, mq)*(0.5 - (S1 - 8.*mq*mq)*(s34 + S1)/(2.*Delta) - s12*pow((s34 + S1),3)/Delta/Delta) + ((s12 + S2)*C0DD(k2, k1 + q2, mq) - s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) - S1*C0DD(k1, q2, mq))*((S1 - 4.*mq*mq)/(2.*Delta) + s12*pow((s34 + S1),2)/Delta/Delta) - C0DD(k1 + k2, q2, mq) + (B0DD(k1 + q2, mq) - B0DD(k1 + k2 + q2, mq))*(2.*s34/Delta + 2.*s12*(s34 + S1)/((s12 + S2)*Delta)) - (B0DD( q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*((2.*s34*(2.*s12*s34 - S2*(S1 + S2) + s12*(S1 - S2)))/(Delta*Sigma)) + (B0DD(k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*((2.*s12*(2.*s12*s34 - S1*(S1 + S2) + s34*(S2 - S1)))/(Delta*Sigma))); } //COM F4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM F4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor* (-s12*D0DD(k1, k2, q2, mq)*(0.5 + (S1 - 8.*mq*mq)*(s34 + S2)/(2.*Delta) + s12*pow((s34 + S2),3)/Delta/Delta) - ((s12 + S1)*C0DD(k1, k2 + q2, mq) - s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) - S2*C0DD(k2, q2, mq))*((S1 - 4.*mq*mq)/(2.*Delta) + s12*pow((s34 + S2),2)/Delta/Delta) - C0DD(k1 + k2, q2, mq) - (B0DD(k2 + q2, mq) - B0DD(k1 + k2 + q2, mq))*2.*(s34 + S2)/Delta + (B0DD(q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*2.*s34*(2.*s12*s34 - S1*(S1 + S2) + s12*(S2 - S1))/(Delta*Sigma) - (B0DD(k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*(2.*s12*(2.*s12*s34 - S2*(S1 + S2) + s34*(S1 - S2))/(Delta*Sigma))); } //COM G4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM G4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; return looprwfactor* (-D0DD(k1, q2, k2, mq)*(Delta/s12 + (s12 + S1)/2. - 4.*mq*mq) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) - S1*C0DD(k1, q2, mq))*(1./ s12 - (S1 - 4.*mq*mq)/(2.*Delta)) + ((s12 + S2)*C0DD( k1 + q2, k2, mq) - S2*C0DD(k2, q2, mq))*(1./ s12 + (S1 - 4.*mq*mq)/(2.*Delta)) + (B0DD( k1 + k2 + q2, mq) - B0DD(k1 + q2, mq))*2./(s12 + S2)); } //COM E10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM E10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor*(-s12*D0DD(k2, k1, q2, mq)*((s34 + S1)/Delta + 12.*mq*mq*S1*(s34 + S1)/Delta/Delta - 4.*s12*S1*pow((s34 + S1),3)/Delta/Delta/Delta) - ((s12 + S2)*C0DD(k2, k1 + q2, mq) - s12*C0DD(k1, k2, mq) + (S1 - S2)*C0DD(k1 + k2, q2, mq) - S1*C0DD(k1, q2, mq))*(1./Delta + 4.*mq*mq*S1/Delta/Delta - 4.*s12*S1*pow((s34 + S1),2)/Delta/Delta/Delta) + C0DD(k1 + k2, q2, mq)*(4.*s12*s34*(S1 - S2)/(Delta*Sigma) - 4.*(s12 - 2.*mq*mq)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma)) + (B0DD(k1 + q2, mq) - B0DD(k1 + k2 + q2, mq))*(4.*(s34 + S1)/((s12 + S2)*Delta) + 8.*S1*(s34 + S1)/Delta/Delta) + (B0DD(q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*(12.*s34*(2.*s12 + S1 + S2)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma*Sigma) - 4.*s34*(4.*s12 + 3.*S1 + S2)/(Delta*Sigma) + 8.*s12*s34*(s34*(s12 + S2) - S1*(s34 + S1))/(Delta*Delta*Sigma)) + (B0DD(k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*(12.*s12*(2.*s34 + S1 + S2)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma*Sigma) + 8.*s12*S1*(s34*(s12 + S2) - S1*(s34 + S1))/(Delta*Delta*Sigma))) + (COM(0.,1.)/(4.*M_PI*M_PI))*((2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma)); } //COM F10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM F10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, Sigma, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; Sigma = 4.*s12*s34 - pow(S1+S2,2); return looprwfactor* (s12*D0DD(k1, k2, q2, mq)*((s34 + S2)/Delta - 4.*mq*mq/Delta + 12.*mq*mq*s34*(s12 + S1)/Delta/Delta - 4.*s12*pow((s34 + S2),2)/Delta/Delta - 4.*s12*S1*pow((s34 + S2),3)/Delta/Delta/Delta) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) - s12*C0DD(k1, k2, mq) - (S1 - S2)*C0DD(k1 + k2, q2, mq) - S2*C0DD(k2, q2, mq))*(1./Delta + 4.*mq*mq*S1/Delta/Delta - 4.*s12*(s34 + S2)/Delta/Delta - 4.*s12*S1*pow((s34 + S2),2)/Delta/Delta/Delta) - C0DD(k1 + k2, q2, mq)*(4.*s12*s34/(S2*Delta) + 4.*s12*s34*(S2 - S1)/(Delta*Sigma) + 4.*(s12 - 2.*mq*mq)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma)) - (B0DD( k2 + q2, mq) - B0DD(k1 + k2 + q2, mq))*(4.*s34/(S2*Delta) + 8.*s34*(s12 + S1)/Delta/Delta) - (B0DD(q2, mq) - B0DD(k1 + k2 + q2, mq) + s12*C0DD(k1 + k2, q2, mq))*(-12*s34*(2*s12 + S1 + S2)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma*Sigma) - 4.*s12*s34*s34/(S2*Delta*Delta) + 4.*s34*S1/(Delta*Sigma) - 4.*s34*(s12*s34*(2.*s12 + S2) - S1*S1*(2.*s12 + S1))/(Delta*Delta*Sigma)) - (B0DD(k1 + k2, mq) - B0DD(k1 + k2 + q2, mq) - (s34 + S1 + S2)*C0DD(k1 + k2, q2, mq))*(-12.*s12*(2.*s34 + S1 + S2)*(2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma*Sigma) + 8.*s12*(2.*s34 + S1)/(Delta*Sigma) - 8.*s12*s34*(2.*s12*s34 - S1*(S1 + S2) + s12*(S2 - S1))/(Delta*Delta*Sigma))) + (COM(0.,1.)/(4.*M_PI*M_PI))*((2.*s12*s34 - S1*(S1 + S2))/(Delta*Sigma)); } //COM G10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM G10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //CLHEP::HepLorentzVector q2=k3+k4; CLHEP::HepLorentzVector q2 = -(k1+k2+kh); double Delta, S1, S2, s12, s34; S1 = 2.*k1.dot(q2); S2 = 2.*k2.dot(q2); s12 = 2.*k1.dot(k2); //s34 = 2.*k3.dot(k4); s34 = q2.m2(); Delta = s12*s34 - S1*S2; return looprwfactor* (-D0DD(k1, q2, k2, mq)*(1. + 4.*S1*mq*mq/Delta) + ((s12 + S1)*C0DD(k1, k2 + q2, mq) - S1*C0DD(k1, q2, mq))*(1./Delta + 4.*S1*mq*mq/Delta/Delta) - ((s12 + S2)*C0DD(k1 + q2, k2, mq) - S2*C0DD(k2, q2, mq))*(1./Delta + 4.*S1*mq*mq/Delta/Delta) + (B0DD(k1 + k2 + q2, mq) - B0DD(k1 + q2, mq))*4.*(s34 + S1)/(Delta*(s12 + S2)) + (B0DD(q2, mq) - B0DD(k2 + q2, mq))*4.*s34/(Delta*S2)); } //COM H1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H1(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return E1(k1,k2,k3,k4,mq)+F1(k1,k2,k3,k4,mq)+G1(k1,k2,k3,k4,mq); return E1(k1,k2,kh,mq)+F1(k1,k2,kh,mq)+G1(k1,k2,kh,mq); } //COM H4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H4(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return E4(k1,k2,k3,k4,mq)+F4(k1,k2,k3,k4,mq)+G4(k1,k2,k3,k4,mq); return E4(k1,k2,kh,mq)+F4(k1,k2,kh,mq)+G4(k1,k2,kh,mq); } //COM H10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H10(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return E10(k1,k2,k3,k4,mq)+F10(k1,k2,k3,k4,mq)+G10(k1,k2,k3,k4,mq); return E10(k1,k2,kh,mq)+F10(k1,k2,kh,mq)+G10(k1,k2,kh,mq); } //COM H2(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H2(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return -1.*H1(k2,k1,k3,k4,mq); return -1.*H1(k2,k1,kh,mq); } //COM H5(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H5(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return -1.*H4(k2,k1,k3,k4,mq); return -1.*H4(k2,k1,kh,mq); } //COM H12(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector k3, CLHEP::HepLorentzVector k4, double mq) COM H12(CLHEP::HepLorentzVector k1, CLHEP::HepLorentzVector k2, CLHEP::HepLorentzVector kh, double mq) { //return -1.*H10(k2,k1,k3,k4,mq); return -1.*H10(k2,k1,kh,mq); } // FL and FT functions COM FL(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq) { CLHEP::HepLorentzVector Q = q1 + q2; double detQ2 = q1.m2()*q2.m2() - q1.dot(q2)*q1.dot(q2); return -1./(2.*detQ2)*((2.- 3.*q1.m2()*q2.dot(Q)/detQ2)*(B0DD(q1, mq) - B0DD(Q, mq)) + (2. - 3.*q2.m2()*q1.dot(Q)/detQ2)*(B0DD(q2, mq) - B0DD(Q, mq)) - (4.*mq*mq + q1.m2() + q2.m2() + Q.m2() - 3.*q1.m2()*q2.m2()*Q.m2()/detQ2)*C0DD( q1, q2, mq) - 2.); } COM FT(CLHEP::HepLorentzVector q1, CLHEP::HepLorentzVector q2, double mq) { CLHEP::HepLorentzVector Q = q1 + q2; double detQ2 = q1.m2()*q2.m2() - q1.dot(q2)*q1.dot(q2); return -1./(2.*detQ2)*(Q.m2()*(B0DD(q1, mq) + B0DD(q2, mq) - 2.*B0DD(Q, mq) - 2.*q1.dot(q2)*C0DD(q1, q2, mq)) + (q1.m2() - q2.m2()) *(B0DD(q1, mq) - B0DD(q2, mq))) - q1.dot(q2)*FL(q1, q2, mq); } CLHEP::HepLorentzVector ParityFlip(CLHEP::HepLorentzVector p) { CLHEP::HepLorentzVector flippedVector; flippedVector.setE(p.e()); flippedVector.setX(-p.x()); flippedVector.setY(-p.y()); flippedVector.setZ(-p.z()); return flippedVector; } /// @brief HC amp for qg->qgH with finite top (i.e. j^{++}_H) void g_gH_HC(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH, double mq, current &retAns) { current cura1,pacur,p1cur,pHcur,conjeps1,conjepsH1,epsa,epsHa,epsHapart1, epsHapart2,conjepsH1part1,conjepsH1part2; COM ang1a,sqa1; const double F = 4.*mq*mq/HEJ::vev; // Easier to have the whole thing as current object so I can use cdot functionality. // Means I need to write pa,p1 as current objects to_current(pa, pacur); to_current(p1,p1cur); to_current(pH,pHcur); bool gluonforward = true; if(pa.z() < 0) gluonforward = false; //HEJ gauge jio(pa,false,p1,false,cura1); if(gluonforward){ // sqrt(2pa_-/p1_-)*p1_perp/abs(p1_perp) ang1a = sqrt(pa.plus()*p1.minus())*(p1.x()+COM(0.,1.)*p1.y())/p1.perp(); // sqrt(2pa_-/p1_-)*p1_perp*/abs(p1_perp) sqa1 = sqrt(pa.plus()*p1.minus())*(p1.x()-COM(0.,1.)*p1.y())/p1.perp(); } else { ang1a = sqrt(pa.minus()*p1.plus()); sqa1 = sqrt(pa.minus()*p1.plus()); } const double prop = (pa-p1-pH).m2(); cmult(-1./sqrt(2)/ang1a,cura1,conjeps1); cmult(1./sqrt(2)/sqa1,cura1,epsa); const COM Fta = FT(-pa,pa-pH,mq)/(pa-pH).m2(); const COM Ft1 = FT(-p1-pH,p1,mq)/(p1+pH).m2(); const COM h4 = H4(p1,-pa,pH,mq); const COM h5 = H5(p1,-pa,pH,mq); const COM h10 = H10(p1,-pa,pH,mq); const COM h12 = H12(p1,-pa,pH,mq); cmult(Fta*pa.dot(pH), epsa, epsHapart1); cmult(-1.*Fta*cdot(pHcur,epsa), pacur, epsHapart2); cmult(Ft1*cdot(pHcur,conjeps1), p1cur, conjepsH1part1); cmult(-Ft1*p1.dot(pH), conjeps1, conjepsH1part2); cadd(epsHapart1, epsHapart2, epsHa); cadd(conjepsH1part1, conjepsH1part2, conjepsH1); const COM aH1 = cdot(pHcur, cura1); current T1,T2,T3,T4,T5,T6,T7,T8,T9,T10; if(gluonforward){ cmult(sqrt(2.)*sqrt(p1.plus()/pa.plus())*prop/sqa1, conjepsH1, T1); cmult(-sqrt(2.)*sqrt(pa.plus()/p1.plus())*prop/ang1a, epsHa, T2); } else{ cmult(-sqrt(2.)*sqrt(p1.minus()/pa.minus()) *((p1.x()-COM(0.,1.)*p1.y())/p1.perp())*prop/sqa1, conjepsH1, T1); cmult(sqrt(2.)*sqrt(pa.minus()/p1.minus()) *((p1.x()-COM(0.,1.)*p1.y())/p1.perp())*prop/ang1a, epsHa, T2); } cmult(sqrt(2.)/ang1a*aH1, epsHa, T3); cmult(sqrt(2.)/sqa1*aH1, conjepsH1, T4); cmult(-sqrt(2.)*Fta*pa.dot(p1)*aH1/sqa1, conjeps1, T5); cmult(-sqrt(2.)*Ft1*pa.dot(p1)*aH1/ang1a, epsa, T6); cmult(-aH1/sqrt(2.)/sqa1*h4*8.*COM(0.,1.)*M_PI*M_PI, conjeps1, T7); cmult(aH1/sqrt(2.)/ang1a*h5*8.*COM(0.,1.)*M_PI*M_PI, epsa, T8); cmult(aH1*aH1/2./ang1a/sqa1*h10*8.*COM(0.,1.)*M_PI*M_PI, pacur, T9); cmult(-aH1*aH1/2./ang1a/sqa1*h12*8.*COM(0.,1.)*M_PI*M_PI, p1cur, T10); current ans; for(int i=0;i<4;i++) { ans[i] = T1[i]+T2[i]+T3[i]+T4[i]+T5[i]+T6[i]+T7[i]+T8[i]+T9[i]+T10[i]; } retAns[0] = F/prop*ans[0]; retAns[1] = F/prop*ans[1]; retAns[2] = F/prop*ans[2]; retAns[3] = F/prop*ans[3]; } /// @brief HNC amp for qg->qgH with finite top (i.e. j^{+-}_H) void g_gH_HNC(CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH, double mq, current &retAns) { const double F = 4.*mq*mq/HEJ::vev; COM ang1a,sqa1; current conjepsH1,epsHa,p1cur,pacur,pHcur,conjeps1,epsa,paplusp1cur, p1minuspacur,cur1a,cura1,epsHapart1,epsHapart2,conjepsH1part1, conjepsH1part2; // Find here if pa, meaning the gluon, is forward or backward bool gluonforward = true; if(pa.z() < 0) gluonforward = false; jio(pa,true,p1,true,cura1); joi(p1,true,pa,true,cur1a); to_current(pa,pacur); to_current(p1,p1cur); to_current(pH,pHcur); to_current(pa+p1,paplusp1cur); to_current(p1-pa,p1minuspacur); const COM aH1 = cdot(pHcur,cura1); const COM oneHa = std::conj(aH1); // = cdot(pHcur,cur1a) if(gluonforward){ // sqrt(2pa_-/p1_-)*p1_perp/abs(p1_perp) ang1a = sqrt(pa.plus()*p1.minus())*(p1.x()+COM(0.,1.)*p1.y())/p1.perp(); // sqrt(2pa_-/p1_-)*p1_perp*/abs(p1_perp) sqa1 = sqrt(pa.plus()*p1.minus())*(p1.x()-COM(0.,1.)*p1.y())/p1.perp(); } else { ang1a = sqrt(pa.minus()*p1.plus()); sqa1 = sqrt(pa.minus()*p1.plus()); } const double prop = (pa-p1-pH).m2(); cmult(1./sqrt(2)/sqa1, cur1a, epsa); cmult(-1./sqrt(2)/sqa1, cura1, conjeps1); const COM phase = cdot(conjeps1, epsa); const COM Fta = FT(-pa,pa-pH,mq)/(pa-pH).m2(); const COM Ft1 = FT(-p1-pH,p1,mq)/(p1+pH).m2(); const COM Falpha = FT(p1-pa,pa-p1-pH,mq); const COM Fbeta = FL(p1-pa,pa-p1-pH,mq); const COM h1 = H1(p1,-pa, pH, mq); const COM h2 = H2(p1,-pa, pH, mq); const COM h4 = H4(p1,-pa, pH, mq); const COM h5 = H5(p1,-pa, pH, mq); const COM h10 = H10(p1,-pa, pH, mq); const COM h12 = H12(p1,-pa, pH, mq); cmult(Fta*pa.dot(pH), epsa, epsHapart1); cmult(-1.*Fta*cdot(pHcur,epsa), pacur, epsHapart2); cmult(Ft1*cdot(pHcur,conjeps1), p1cur, conjepsH1part1); cmult(-Ft1*p1.dot(pH), conjeps1, conjepsH1part2); cadd(epsHapart1, epsHapart2, epsHa); cadd(conjepsH1part1, conjepsH1part2, conjepsH1); current T1,T2,T3,T4,T5a,T5b,T6,T7,T8a,T8b,T9,T10,T11a, T11b,T12a,T12b,T13; if(gluonforward){ cmult(sqrt(2.)*sqrt(p1.plus()/pa.plus())*prop/sqa1, conjepsH1, T1); cmult(-sqrt(2.)*sqrt(pa.plus()/p1.plus())*prop/sqa1, epsHa, T2); } else{ cmult(-sqrt(2.)*sqrt(p1.minus()/pa.minus())*((p1.x()-COM(0.,1.)*p1.y())/p1.perp()) *prop/sqa1, conjepsH1, T1); cmult(sqrt(2.)*sqrt(pa.minus()/p1.minus())*((p1.x()+COM(0.,1.)*p1.y())/p1.perp()) *prop/sqa1, epsHa, T2); } const COM boxdiagFact = 8.*COM(0.,1.)*M_PI*M_PI; cmult(aH1*sqrt(2.)/sqa1, epsHa, T3); cmult(oneHa*sqrt(2.)/sqa1, conjepsH1, T4); cmult(-2.*phase*Fta*pa.dot(pH), p1cur, T5a); cmult(2.*phase*Ft1*p1.dot(pH), pacur, T5b); cmult(-sqrt(2.)*Fta*p1.dot(pa)*oneHa/sqa1, conjeps1, T6); cmult(-sqrt(2.)*Ft1*pa.dot(p1)*aH1/sqa1, epsa, T7); cmult(-boxdiagFact*phase*h2, pacur, T8a); cmult(boxdiagFact*phase*h1, p1cur, T8b); cmult(boxdiagFact*aH1/sqrt(2.)/sqa1*h5, epsa, T9); cmult(-boxdiagFact*oneHa/sqrt(2.)/sqa1*h4, conjeps1, T10); cmult(boxdiagFact*aH1*oneHa/2./sqa1/sqa1*h10, pacur, T11a); cmult(-boxdiagFact*aH1*oneHa/2./sqa1/sqa1*h12, p1cur, T11b); cmult(-phase/(pa-p1).m2()*Falpha*(p1-pa).dot(pa-p1-pH), paplusp1cur, T12a); cmult(phase/(pa-p1).m2()*Falpha*(pa+p1).dot(pa-p1-pH), p1minuspacur, T12b); cmult(-phase*Fbeta*(pa-p1-pH).m2(), paplusp1cur, T13); current ans; for(int i=0;i<4;i++) { ans[i] = T1[i]+T2[i]+T3[i]+T4[i]+T5a[i]+T5b[i]+T6[i]+T7[i]+T8a[i]+T8b[i]+T9[i]+T10[i]+T11a[i]+T11b[i]+T12a[i]+T12b[i]+T13[i]; } retAns[0] = F/prop*ans[0]; retAns[1] = F/prop*ans[1]; retAns[2] = F/prop*ans[2]; retAns[3] = F/prop*ans[3]; } } // namespace anonymous // JDC - new amplitude with Higgs emitted close to gluon with full mt effects. Keep usual HEJ-style function call double MH2gq_outsideH(CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in, CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in, CLHEP::HepLorentzVector pH, double mq, bool includeBottom, double mq2) { current cur2bplus,cur2bminus, cur2bplusFlip, cur2bminusFlip; current retAns,retAnsb; joi(p2out,true,p2in,true,cur2bplus); joi(p2out,false,p2in,false,cur2bminus); joi(ParityFlip(p2out),true,ParityFlip(p2in),true,cur2bplusFlip); joi(ParityFlip(p2out),false,ParityFlip(p2in),false,cur2bminusFlip); COM app1,app2,apm1,apm2; COM app3, app4, apm3, apm4; if(!includeBottom) { g_gH_HC(p1in,p1out,pH,mq,retAns); app1=cdot(retAns,cur2bplus); app2=cdot(retAns,cur2bminus); g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns); app3=cdot(retAns,cur2bplusFlip); app4=cdot(retAns,cur2bminusFlip); // And non-conserving bits g_gH_HNC(p1in,p1out,pH,mq,retAns); apm1=cdot(retAns,cur2bplus); apm2=cdot(retAns,cur2bminus); g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns); apm3=cdot(retAns,cur2bplusFlip); apm4=cdot(retAns,cur2bminusFlip); } else { g_gH_HC(p1in,p1out,pH,mq,retAns); g_gH_HC(p1in,p1out,pH,mq2,retAnsb); app1=cdot(retAns,cur2bplus) + cdot(retAnsb,cur2bplus); app2=cdot(retAns,cur2bminus) + cdot(retAnsb,cur2bminus); g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns); g_gH_HC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq2,retAnsb); app3=cdot(retAns,cur2bplusFlip) + cdot(retAnsb,cur2bplusFlip); app4=cdot(retAns,cur2bminusFlip) + cdot(retAnsb,cur2bminusFlip); // And non-conserving bits g_gH_HNC(p1in,p1out,pH,mq,retAns); g_gH_HNC(p1in,p1out,pH,mq2,retAnsb); apm1=cdot(retAns,cur2bplus) + cdot(retAnsb,cur2bplus); apm2=cdot(retAns,cur2bminus) + cdot(retAnsb,cur2bminus); g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq,retAns); g_gH_HNC(ParityFlip(p1in),ParityFlip(p1out),ParityFlip(pH),mq2,retAnsb); apm3=cdot(retAns,cur2bplusFlip) + cdot(retAnsb,cur2bplusFlip); apm4=cdot(retAns,cur2bminusFlip) + cdot(retAnsb,cur2bminusFlip); } return abs2(app1) + abs2(app2) + abs2(app3) + abs2(app4) + abs2(apm1) + abs2(apm2) + abs2(apm3) + abs2(apm4); } #endif // HEJ_BUILD_WITH_QCDLOOP double C2gHgm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH) { static double A=1./(3.*M_PI*HEJ::vev); // Implements Eq. (4.22) in hep-ph/0301013 with modifications to incoming plus momenta double s12,p1p,p2p; COM p1perp,p3perp,phperp; // Determine first whether this is the case p1p\sim php>>p3p og the opposite s12=p1.invariantMass2(-p2); if (p2.pz()>0.) { // case considered in hep-ph/0301013 p1p=p1.plus(); p2p=p2.plus(); } else { // opposite case p1p=p1.minus(); p2p=p2.minus(); } p1perp=p1.px()+COM(0,1)*p1.py(); phperp=pH.px()+COM(0,1)*pH.py(); p3perp=-(p1perp+phperp); COM temp=COM(0,1)*A/(2.*s12)*(p2p/p1p*conj(p1perp)*p3perp+p1p/p2p*p1perp*conj(p3perp)); temp=temp*conj(temp); return temp.real(); } double C2gHgp(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH) { static double A=1./(3.*M_PI*HEJ::vev); // Implements Eq. (4.23) in hep-ph/0301013 double s12,php,p1p,phm; COM p1perp,p3perp,phperp; // Determine first whether this is the case p1p\sim php>>p3p or the opposite s12=p1.invariantMass2(-p2); if (p2.pz()>0.) { // case considered in hep-ph/0301013 php=pH.plus(); phm=pH.minus(); p1p=p1.plus(); } else { // opposite case php=pH.minus(); phm=pH.plus(); p1p=p1.minus(); } p1perp=p1.px()+COM(0,1)*p1.py(); phperp=pH.px()+COM(0,1)*pH.py(); p3perp=-(p1perp+phperp); COM temp=-COM(0,1)*A/(2.*s12)*( conj(p1perp*p3perp)*pow(php/p1p,2)/(1.+php/p1p) +s12*(pow(conj(phperp),2)/(pow(abs(phperp),2)+p1p*phm) -pow(conj(p3perp) +(1.+php/p1p)*conj(p1perp),2)/((1.+php/p1p)*(pH.m2()+2.*p1.dot(pH)))) ); temp=temp*conj(temp); return temp.real(); } double C2qHqm(CLHEP::HepLorentzVector p2, CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector pH) { static double A=1./(3.*M_PI*HEJ::vev); // Implements Eq. (4.22) in hep-ph/0301013 double s12,p2p,p1p; COM p1perp,p3perp,phperp; // Determine first whether this is the case p1p\sim php>>p3p or the opposite s12=p1.invariantMass2(-p2); if (p2.pz()>0.) { // case considered in hep-ph/0301013 p2p=p2.plus(); p1p=p1.plus(); } else { // opposite case p2p=p2.minus(); p1p=p1.minus(); } p1perp=p1.px()+COM(0,1)*p1.py(); phperp=pH.px()+COM(0,1)*pH.py(); p3perp=-(p1perp+phperp); COM temp=A/(2.*s12)*( sqrt(p2p/p1p)*p3perp*conj(p1perp) +sqrt(p1p/p2p)*p1perp*conj(p3perp) ); temp=temp*conj(temp); return temp.real(); } diff --git a/src/get_analysis.cc b/src/get_analysis.cc index dfcc5d5..14ee951 100644 --- a/src/get_analysis.cc +++ b/src/get_analysis.cc @@ -1,38 +1,38 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/get_analysis.hh" #include <dlfcn.h> #include <string> #include "yaml-cpp/yaml.h" #include "HEJ/EmptyAnalysis.hh" #include "HEJ/RivetAnalysis.hh" namespace HEJ{ std::unique_ptr<Analysis> get_analysis(YAML::Node const & parameters){ if(!parameters["plugin"]){ if(parameters["rivet"]) return RivetAnalysis::create(parameters); return EmptyAnalysis::create(parameters); } using AnalysisMaker = std::unique_ptr<Analysis> (*)(YAML::Node); const auto plugin_name = parameters["plugin"].as<std::string>(); auto handle = dlopen(plugin_name.c_str(), RTLD_NOW); char * error = dlerror(); if(error != nullptr) throw std::runtime_error(error); void * sym = dlsym(handle, "make_analysis"); error = dlerror(); if(error != nullptr) throw std::runtime_error(error); auto make_analysis = reinterpret_cast<AnalysisMaker>(sym); return make_analysis(parameters); } } diff --git a/src/kinematics.cc b/src/kinematics.cc index a878155..ce88056 100644 --- a/src/kinematics.cc +++ b/src/kinematics.cc @@ -1,27 +1,27 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/kinematics.hh" #include "fastjet/PseudoJet.hh" #include "HEJ/Particle.hh" namespace HEJ{ //reconstruct incoming momenta from momentum conservation std::tuple<fastjet::PseudoJet, fastjet::PseudoJet> incoming_momenta( std::vector<Particle> const & outgoing ){ double xa(0.), xb(0.); for(auto const & out: outgoing){ xa += out.p.e() - out.p.pz(); xb += out.p.e() + out.p.pz(); } return std::tuple<fastjet::PseudoJet, fastjet::PseudoJet>{ {0,0,-xa/2.,xa/2.}, {0,0,xb/2.,xb/2.} }; } } diff --git a/src/make_RNG.cc b/src/make_RNG.cc index b1a3661..d96c67f 100644 --- a/src/make_RNG.cc +++ b/src/make_RNG.cc @@ -1,35 +1,35 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/make_RNG.hh" #include <algorithm> #include <locale> #include "HEJ/exceptions.hh" #include "HEJ/Mixmax.hh" #include "HEJ/Ranlux64.hh" namespace HEJ { std::unique_ptr<HEJ::RNG> make_RNG( std::string const & name, optional<std::string> const & seed ) { std::string lname; std::transform( begin(name), end(name), std::back_inserter(lname), [](char c) { return std::tolower(c, std::locale()); } ); if(lname == "mixmax") { if(seed) return std::make_unique<Mixmax>(std::stol(*seed)); return std::make_unique<Mixmax>(); } if(lname == "ranlux64") { if(seed) return std::make_unique<Ranlux64>(*seed); return std::make_unique<Ranlux64>(); } throw std::invalid_argument{"Unknown random number generator: " + name}; } } diff --git a/src/make_writer.cc b/src/make_writer.cc index 0e15d61..5a7efaf 100644 --- a/src/make_writer.cc +++ b/src/make_writer.cc @@ -1,31 +1,31 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/make_writer.hh" #include "HEJ/exceptions.hh" #include "HEJ/HepMCWriter.hh" #include "HEJ/LesHouchesWriter.hh" namespace HEJ{ std::unique_ptr<EventWriter> make_format_writer( FileFormat format, std::string const & outfile, LHEF::HEPRUP const & heprup ){ switch(format){ case Les_Houches: return std::unique_ptr<EventWriter>{ new LesHouchesWriter{outfile, heprup} }; case HepMC: return std::unique_ptr<EventWriter>{ new HepMCWriter{outfile, heprup} }; default: throw std::logic_error("unhandled file format"); } } } diff --git a/src/resummation_jet.cc b/src/resummation_jet.cc index 0c41dbe..28cec70 100644 --- a/src/resummation_jet.cc +++ b/src/resummation_jet.cc @@ -1,113 +1,113 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/resummation_jet.hh" #include <assert.h> #include <math.h> #include <stdio.h> #include <boost/numeric/ublas/lu.hpp> #include <boost/numeric/ublas/matrix.hpp> #include "fastjet/PseudoJet.hh" #include "HEJ/utility.hh" namespace HEJ{ std::vector<fastjet::PseudoJet> resummation_jet_momenta( std::vector<fastjet::PseudoJet> const & p_born, fastjet::PseudoJet const & qperp ) { // for "new" reshuffling p^B = p + qperp*|p^B|/P^B double Pperp_born = 0.; for(auto const & p: p_born) Pperp_born += p.perp(); std::vector<fastjet::PseudoJet> p_res; p_res.reserve(p_born.size()); for(auto & pB: p_born) { const double px = pB.px() - qperp.px()*pB.perp()/Pperp_born; const double py = pB.py() - qperp.py()*pB.perp()/Pperp_born; const double pperp = sqrt(px*px + py*py); // keep the rapidities fixed const double pz = pperp*sinh(pB.rapidity()); const double E = pperp*cosh(pB.rapidity()); p_res.emplace_back(px, py, pz, E); assert( HEJ::nearby_ep( p_res.back().rapidity(), pB.rapidity(), 1e-5 ) ); } return p_res; } namespace{ enum coordinates : size_t { x1, x2 }; namespace ublas = boost::numeric::ublas; template<class Matrix> double det(ublas::matrix_expression<Matrix> const& m) { ublas::permutation_matrix<size_t> pivots{m().size1()}; Matrix mLu{m()}; const auto is_singular = lu_factorize(mLu, pivots); if(is_singular) return 0.; double det = 1.0; for (std::size_t i = 0; i < pivots.size(); ++i){ if (pivots(i) != i) det = -det; det *= mLu(i,i); } return det; } using ublas::matrix; } double resummation_jet_weight( std::vector<fastjet::PseudoJet> const & p_born, fastjet::PseudoJet const & qperp ) { static constexpr int num_coordinates = 2; auto Jacobian = matrix<double>{ num_coordinates*p_born.size(), num_coordinates*p_born.size() }; double P_perp = 0.; for(auto const & J: p_born) P_perp += J.perp(); for(size_t l = 0; l < p_born.size(); ++l){ const double Jl_perp = p_born[l].perp(); for(size_t lp = 0; lp < p_born.size(); ++lp){ const int delta_l = l == lp; const double Jlp_perp = p_born[lp].perp(); for(size_t x = x1; x <= x2; ++x){ for(size_t xp = x1; xp <= x2; ++xp){ const int delta_x = x == xp; Jacobian(2*l + x, 2*lp + xp) = + delta_l*delta_x - qperp[x]*p_born[lp][xp]/(P_perp*Jlp_perp)*( + delta_l - Jl_perp/P_perp ); } } } } return det(Jacobian); } } diff --git a/src/stream.cc b/src/stream.cc index d856096..c4843eb 100644 --- a/src/stream.cc +++ b/src/stream.cc @@ -1,32 +1,32 @@ /** - * \authors Jeppe Andersen, Tuomas Hapola, Marian Heil, Andreas Maier, Jennifer Smillie + * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019 * \copyright GPLv2 or later */ #include "HEJ/stream.hh" #include <boost/iostreams/filter/gzip.hpp> namespace HEJ{ namespace{ bool is_gzip(std::ifstream & file){ static constexpr char magic_bytes[] = {'\x1f', '\x8b'}; if(file.peek() != magic_bytes[0]) return false; file.get(); const char second = file.peek(); file.unget(); return second == magic_bytes[1]; } } istream::istream(std::string const & filename): file_{filename, std::ios_base::in | std::ios_base::binary}, stream_{new boost_istream()} { if(is_gzip(file_)){ stream_->push(boost::iostreams::gzip_decompressor{}); } stream_->push(file_); } } diff --git a/t/check_hepmc.cc b/t/check_hepmc.cc index 066f510..f6b7620 100644 --- a/t/check_hepmc.cc +++ b/t/check_hepmc.cc @@ -1,21 +1,26 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include <stdexcept> #include "HepMC/ReaderAscii.h" static constexpr double ep = 1e-3; int main(int argn, char** argv) { if(argn != 2){ std::cerr << "Usage: check_hepmc hepmc_file\n"; return EXIT_FAILURE; } HepMC::ReaderAscii input{argv[1]}; if(input.failed()) throw std::runtime_error{"failed to open HepMC file"}; while(true){ HepMC::GenEvent ev{}; if ( !input.read_event(ev) || ev.event_number() == 0 ) break; if(input.failed()) throw std::runtime_error{"failed to read HepMC event"}; } } diff --git a/t/check_lhe.cc b/t/check_lhe.cc index 0823d48..dd60ee7 100644 --- a/t/check_lhe.cc +++ b/t/check_lhe.cc @@ -1,29 +1,34 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include "HEJ/stream.hh" #include "LHEF/LHEF.h" static constexpr double ep = 1e-3; int main(int argn, char** argv) { if(argn != 2){ std::cerr << "Usage: check_lhe lhe_file\n"; return EXIT_FAILURE; } HEJ::istream in{argv[1]}; LHEF::Reader reader{in}; std::vector<double> xsec_ref(reader.heprup.NPRUP, 0.); while(reader.readEvent()){ xsec_ref[reader.hepeup.IDPRUP-1] += reader.hepeup.weight(); } for(size_t i = 0; i < xsec_ref.size(); ++i){ std::cout << xsec_ref[i] << '\t' << reader.heprup.XSECUP[i] << '\n'; if(std::abs(xsec_ref[i]/reader.heprup.XSECUP[i] - 1) > ep){ std::cerr << "Cross sections deviate substantially"; return EXIT_FAILURE; } } } diff --git a/t/check_res.cc b/t/check_res.cc index 26ce3c1..e9374c0 100644 --- a/t/check_res.cc +++ b/t/check_res.cc @@ -1,136 +1,141 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include "LHEF/LHEF.h" #include "HEJ/Event.hh" #include "HEJ/EventReweighter.hh" #include "HEJ/Mixmax.hh" #include "HEJ/stream.hh" #define ASSERT(x) if(!(x)) { \ std::cerr << "Assertion '" #x "' failed.\n"; \ return EXIT_FAILURE; \ } namespace{ const fastjet::JetDefinition jet_def{fastjet::kt_algorithm, 0.4}; const fastjet::JetDefinition Born_jet_def{jet_def}; constexpr double Born_jetptmin = 30; constexpr double extpartonptmin = 30; constexpr double max_ext_soft_pt_fraction = std::numeric_limits<double>::infinity(); constexpr double jetptmin = 35; constexpr bool log_corr = false; using EventTreatment = HEJ::EventTreatment; using namespace HEJ::event_type; HEJ::EventTreatMap treat{ {no_2_jets, EventTreatment::discard}, {bad_final_state, EventTreatment::discard}, {nonHEJ, EventTreatment::discard}, {unof, EventTreatment::discard}, {unob, EventTreatment::discard}, {qqxexb, EventTreatment::discard}, {qqxexf, EventTreatment::discard}, {qqxmid, EventTreatment::discard}, {FKL, EventTreatment::reweight} }; /// true if colour is allowed for particle bool correct_colour(HEJ::Particle const & part){ if(HEJ::is_AWZH_boson(part) && !part.colour) return true; if(!part.colour) return false; int const colour = part.colour->first; int const anti_colour = part.colour->second; if(part.type == HEJ::ParticleID::gluon) return colour != anti_colour && colour > 0 && anti_colour > 0; if(HEJ::is_quark(part)) return anti_colour == 0 && colour > 0; return colour == 0 && anti_colour > 0; } bool correct_colour(HEJ::Event const & ev){ if(!HEJ::event_type::is_HEJ(ev.type())) return true; for(auto const & part: ev.incoming()){ if(!correct_colour(part)) return false; } for(auto const & part: ev.outgoing()){ if(!correct_colour(part)) return false; } return true; } }; int main(int argn, char** argv) { if(argn == 5 && std::string(argv[4]) == "uno"){ --argn; treat[unof] = EventTreatment::reweight; treat[unob] = EventTreatment::reweight; treat[FKL] = EventTreatment::discard; } if(argn != 4){ std::cerr << "Usage: check_res eventfile xsection tolerance [uno]"; return EXIT_FAILURE; } const double xsec_ref = std::stod(argv[2]); const double tolerance = std::stod(argv[3]); HEJ::istream in{argv[1]}; LHEF::Reader reader{in}; HEJ::PhaseSpacePointConfig psp_conf; psp_conf.jet_param = HEJ::JetParameters{jet_def, jetptmin}; psp_conf.min_extparton_pt = extpartonptmin; psp_conf.max_ext_soft_pt_fraction = max_ext_soft_pt_fraction; HEJ::MatrixElementConfig ME_conf; ME_conf.log_correction = log_corr; ME_conf.Higgs_coupling = HEJ::HiggsCouplingSettings{}; HEJ::EventReweighterConfig conf; conf.psp_config = std::move(psp_conf); conf.ME_config = std::move(ME_conf); conf.jet_param = psp_conf.jet_param; conf.treat = treat; reader.readEvent(); const bool has_Higgs = std::find( begin(reader.hepeup.IDUP), end(reader.hepeup.IDUP), 25 ) != end(reader.hepeup.IDUP); const double mu = has_Higgs?125.:91.188; HEJ::ScaleGenerator scale_gen{ {{std::to_string(mu), HEJ::FixedScale{mu}}}, {}, 1. }; HEJ::Mixmax ran{}; HEJ::EventReweighter hej{reader.heprup, std::move(scale_gen), conf, ran}; double xsec = 0.; double xsec_err = 0.; do{ auto ev_data = HEJ::Event::EventData{reader.hepeup}; ev_data.reconstruct_intermediate(); HEJ::Event ev{ ev_data.cluster( Born_jet_def, Born_jetptmin ) }; auto resummed_events = hej.reweight(ev, 100); for(auto const & ev: resummed_events) { ASSERT(correct_colour(ev)); xsec += ev.central().weight; xsec_err += ev.central().weight*ev.central().weight; } } while(reader.readEvent()); xsec_err = std::sqrt(xsec_err); const double significance = std::abs(xsec - xsec_ref) / std::sqrt( xsec_err*xsec_err + tolerance*tolerance ); std::cout << xsec_ref << " +/- " << tolerance << " ~ " << xsec << " +- " << xsec_err << " => " << significance << " sigma\n"; if(significance > 3.){ std::cerr << "Cross section is off by over 3 sigma!\n"; return EXIT_FAILURE; } } diff --git a/t/scales.cc b/t/scales.cc index 64ca2c4..220ad1c 100644 --- a/t/scales.cc +++ b/t/scales.cc @@ -1,8 +1,13 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "HEJ/Event.hh" extern "C" __attribute__((visibility("default"))) double softest_jet_pt(HEJ::Event const & ev){ const auto softest_jet = sorted_by_pt(ev.jets()).back(); return softest_jet.perp(); } diff --git a/t/test_ME_generic.cc b/t/test_ME_generic.cc index 7ad3f45..d59e3e0 100644 --- a/t/test_ME_generic.cc +++ b/t/test_ME_generic.cc @@ -1,132 +1,140 @@ +/** + * \brief Generic tester for the ME for a given set of PSP + * + * \note reference weights and PSP (as LHE file) have to be given as + * _individual_ files + * + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ -// Generic tester for the ME for a given set of PSP -// reference weights and PSP (as LHE file) have to be given as _individual_ files #include <fstream> #include <random> #include <algorithm> #include "LHEF/LHEF.h" #include "HEJ/MatrixElement.hh" #include "HEJ/Event.hh" #include "HEJ/YAMLreader.hh" #include "HEJ/stream.hh" constexpr double alpha_s = 0.118; constexpr double ep = 1e-5; void shuffle_particles(HEJ::Event::EventData & ev) { static std::mt19937_64 ran{0}; std::shuffle(begin(ev.incoming), end(ev.incoming), ran); std::shuffle(begin(ev.outgoing), end(ev.outgoing), ran); } void dump(HEJ::Event const & ev){ { LHEF::Writer writer{std::cout}; std::cout << std::setprecision(6); writer.hepeup = to_HEPEUP(std::move(ev), nullptr); writer.writeEvent(); } std::cout << "Rapidity ordering:\n"; for(const auto & part: ev.outgoing()){ std::cout << std::setw(2) << part.type << ": "<< std::setw(7) << part.rapidity() << std::endl; } } enum MEComponent {tree, virt}; MEComponent guess_component(std::string const & data_file) { if(data_file.find("virt") != data_file.npos) return MEComponent::virt; return MEComponent::tree; } int main(int argn, char** argv){ if(argn != 4 && argn != 5){ std::cerr << "\n# Usage:\n."<< argv[0] <<" config.yml ME_weights input_file.lhe\n\n"; return EXIT_FAILURE; } bool OUTPUT_MODE = false; if(argn == 5 && std::string("OUTPUT")==std::string(argv[4])) OUTPUT_MODE = true; const HEJ::Config config = HEJ::load_config(argv[1]); std::fstream wgt_file; if ( OUTPUT_MODE ) { std::cout << "_______________________USING OUTPUT MODE!_______________________" << std::endl; wgt_file.open(argv[2], std::fstream::out); wgt_file.precision(10); } else { wgt_file.open(argv[2], std::fstream::in); } HEJ::istream in{argv[3]}; LHEF::Reader reader{in}; const auto component = guess_component(argv[2]); HEJ::MatrixElement ME{ [](double){ return alpha_s; }, HEJ::to_MatrixElementConfig(config) }; double max_ratio = 0.; size_t idx_max_ratio = 0; HEJ::Event ev_max_ratio(HEJ::Event::EventData{}.cluster( config.resummation_jets.def,0 ) ); double av_ratio = 0; size_t i = 0; while(reader.readEvent()){ ++i; HEJ::Event::EventData data{reader.hepeup}; shuffle_particles(data); HEJ::Event event{ data.cluster( config.resummation_jets.def, config.resummation_jets.min_pt ) }; const double our_ME = (component == MEComponent::tree)? ME.tree(event).central: ME.virtual_corrections(event).central ; if ( OUTPUT_MODE ) { wgt_file << our_ME << std::endl; } else { std::string line; if(!std::getline(wgt_file,line)) break; const double ref_ME = std::stod(line); const double diff = std::abs(our_ME/ref_ME-1.); av_ratio+=diff; if( diff > max_ratio ) { max_ratio = diff; idx_max_ratio = i; ev_max_ratio = event; } if( diff > ep ){ size_t precision(std::cout.precision()); std::cout.precision(16); std::cout<< "Large difference in PSP " << i << "\nis: "<<our_ME << " should: " << ref_ME << " => difference: " << diff << std::endl; std::cout.precision(precision); dump(event); return EXIT_FAILURE; } } } wgt_file.close(); if ( !OUTPUT_MODE ) { size_t precision(std::cout.precision()); std::cout.precision(16); std::cout << "Avg ratio after " << i << " PSP: " << av_ratio/i << std::endl; std::cout << "maximal ratio at " << idx_max_ratio << ": " << max_ratio << std::endl; std::cout.precision(precision); } return EXIT_SUCCESS; } diff --git a/t/test_classify.cc b/t/test_classify.cc index 13081e3..34276ac 100644 --- a/t/test_classify.cc +++ b/t/test_classify.cc @@ -1,62 +1,67 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <random> #include <algorithm> #include "LHEF/LHEF.h" #include "HEJ/stream.hh" #include "HEJ/event_types.hh" #include "HEJ/Event.hh" namespace{ constexpr double min_jet_pt = 30.; const fastjet::JetDefinition jet_def{fastjet::kt_algorithm, 0.4}; using namespace HEJ::event_type; static const std::vector<EventType> results{ unob,FKL,FKL,FKL,FKL,FKL,FKL,unob,FKL,unob,FKL,FKL,FKL,unof,FKL,unob,FKL, FKL,unob,unob,FKL,FKL,unob,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,unof, FKL,FKL,unof,FKL,FKL,FKL,FKL,FKL,unof,FKL,FKL,FKL,unof,FKL,FKL,unob,unof, FKL,unof,FKL,unob,FKL,FKL,unob,FKL,unob,unof,unob,unof,FKL,FKL,FKL,FKL,FKL, FKL,FKL,FKL,FKL,FKL,FKL,FKL,unob,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,unob,FKL, FKL,FKL,FKL,unof,FKL,unob,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,unob,FKL, FKL,FKL,FKL,FKL,unob,FKL,unob,unob,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,FKL,unof,unob,FKL }; void shuffle_particles(HEJ::Event::EventData & ev) { static std::mt19937_64 ran{0}; std::shuffle(begin(ev.incoming), end(ev.incoming), ran); std::shuffle(begin(ev.outgoing), end(ev.outgoing), ran); } } int main(int argn, char** argv) { if(argn != 2){ std::cerr << "Usage: test_classify eventfile"; return EXIT_FAILURE; } HEJ::istream in{argv[1]}; LHEF::Reader reader{in}; LHEF::Writer writer{std::cerr}; writer.heprup = reader.heprup; for(auto const & expected: results){ reader.readEvent(); HEJ::Event::EventData data{reader.hepeup}; shuffle_particles(data); const HEJ::Event ev{ data.cluster( jet_def, min_jet_pt ) }; if(ev.type() != expected){ using HEJ::event_type::names; writer.hepeup = reader.hepeup; std::cerr << "wrong classification of event:\n"; writer.writeEvent(); std::cerr << "classified as " << names[ev.type()] << ", is " << names[expected] << '\n'; return EXIT_FAILURE; } } } diff --git a/t/test_colours.cc b/t/test_colours.cc index d2c29e6..6f0fea1 100644 --- a/t/test_colours.cc +++ b/t/test_colours.cc @@ -1,221 +1,226 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <random> #include <stdexcept> #include <utility> #include "HEJ/Event.hh" #include "HEJ/RNG.hh" #define ASSERT(x) if(!(x)) { \ throw std::logic_error("Assertion '" #x "' failed."); \ } /// biased RNG to connect always to colour class dum_rnd: public HEJ::DefaultRNG { public: dum_rnd() = default; double flat() override { return 0.; }; }; void shuffle_particles(HEJ::Event::EventData & ev) { static std::mt19937_64 ran{0}; std::shuffle(begin(ev.incoming), end(ev.incoming), ran); std::shuffle(begin(ev.outgoing), end(ev.outgoing), ran); } void dump_event(HEJ::Event const & ev){ for(auto const & in: ev.incoming()){ std::cerr << "in type=" << in.type << ", colour={" << (*in.colour).first << ", " << (*in.colour).second << "}\n"; } for(auto const & out: ev.outgoing()){ std::cerr << "out type=" << out.type << ", colour={"; if(out.colour) std::cerr << (*out.colour).first << ", " << (*out.colour).second; else std::cerr << "non, non"; std::cerr << "}\n"; } } /// true if colour is allowed for particle bool correct_colour(HEJ::Particle const & part){ if(HEJ::is_AWZH_boson(part) && !part.colour) return true; if(!part.colour) return false; int const colour = part.colour->first; int const anti_colour = part.colour->second; if(part.type == HEJ::ParticleID::gluon) return colour != anti_colour && colour > 0 && anti_colour > 0; if(HEJ::is_quark(part)) return anti_colour == 0 && colour > 0; return colour == 0 && anti_colour > 0; } bool correct_colour(HEJ::Event const & ev){ for(auto const & part: ev.incoming()){ if(!correct_colour(part)) return false; } for(auto const & part: ev.outgoing()){ if(!correct_colour(part)) return false; } return true; } bool match_expected( HEJ::Event const & ev, std::vector<HEJ::Colour> const & expected ){ ASSERT(ev.outgoing().size()+2==expected.size()); for(size_t i=0; i<ev.incoming().size(); ++i){ ASSERT(ev.incoming()[i].colour); if( *ev.incoming()[i].colour != expected[i]) return false; } for(size_t i=2; i<ev.outgoing().size()+2; ++i){ if( ev.outgoing()[i-2].colour ){ if( *ev.outgoing()[i-2].colour != expected[i] ) return false; } else if( expected[i].first != 0 || expected[i].second != 0) return false; } return true; } void check_event( HEJ::Event::EventData unc_ev, std::vector<HEJ::Colour> const & expected_colours ){ shuffle_particles(unc_ev); // make sure incoming order doesn't matter HEJ::Event ev{unc_ev.cluster( fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 30.) }; ASSERT(HEJ::event_type::is_HEJ(ev.type())); dum_rnd rng; ASSERT(ev.generate_colours(rng)); if(!correct_colour(ev)){ std::cerr << "Found illegal colours for event\n"; dump_event(ev); throw std::invalid_argument("Illegal colour set"); } if(!match_expected(ev, expected_colours)){ std::cerr << "Colours didn't match expectation. Found\n"; dump_event(ev); std::cerr << "but expected\n"; for(auto const & col: expected_colours){ std::cerr << "colour={" << col.first << ", " << col.second << "}\n"; } throw std::logic_error("Colours did not match expectation"); } } int main() { HEJ::Event::EventData ev; std::vector<HEJ::Colour> expected_colours(7); /// pure gluon ev.incoming[0] = { HEJ::ParticleID::gluon, { 0, 0,-427, 427}, {}}; ev.incoming[1] = { HEJ::ParticleID::gluon, { 0, 0, 851, 851}, {}}; ev.outgoing.push_back({ HEJ::ParticleID::gluon, { 196, 124, -82, 246}, {}}); ev.outgoing.push_back({ HEJ::ParticleID::gluon, {-167,-184, 16, 249}, {}}); ev.outgoing.push_back({ HEJ::ParticleID::higgs, { 197, 180, 168, 339}, {}}); ev.outgoing.push_back({ HEJ::ParticleID::gluon, {-190, -57, 126, 235}, {}}); ev.outgoing.push_back({ HEJ::ParticleID::gluon, { -36, -63, 196, 209}, {}}); expected_colours[0] = {502, 501}; expected_colours[1] = {509, 502}; expected_colours[2] = {503, 501}; expected_colours[3] = {505, 503}; expected_colours[4] = { 0, 0}; expected_colours[5] = {507, 505}; expected_colours[6] = {509, 507}; check_event(ev, expected_colours); /// last g to Qx (=> gQx -> g ... Qx) ev.incoming[1].type = HEJ::ParticleID::d_bar; ev.outgoing[4].type = HEJ::ParticleID::d_bar; // => only end changes expected_colours[1].first = 0; expected_colours[6].first = 0; check_event(ev, expected_colours); { // don't overwrite auto new_expected = expected_colours; auto new_ev = ev; /// uno forward (=> gQx -> g ... Qx g) std::swap(new_ev.outgoing[3].type, new_ev.outgoing[4].type); // => uno quarks eats colour and gluon connects to anti-colour new_expected[5] = {0, expected_colours[3].first}; new_expected[6] = {expected_colours[0].first, expected_colours[0].first+2}; new_expected[1].second += 2; // one more anti-colour in line check_event(new_ev, new_expected); } /// swap Qx <-> Q (=> gQ -> g ... Q) ev.incoming[1].type = HEJ::ParticleID::d; ev.outgoing[4].type = HEJ::ParticleID::d; // => swap: colour<->anti && inital<->final std::swap(expected_colours[1], expected_colours[6]); std::swap(expected_colours[1].first, expected_colours[1].second); std::swap(expected_colours[6].first, expected_colours[6].second); check_event(ev, expected_colours); /// first g to qx (=> qxQ -> qx ... Q) ev.incoming[0].type = HEJ::ParticleID::u_bar; ev.outgoing[0].type = HEJ::ParticleID::u_bar; expected_colours[0] = { 0, 501}; // => shift anti-colour index one up expected_colours[1].first -= 2; expected_colours[5] = expected_colours[3]; expected_colours[3] = expected_colours[2]; expected_colours[2] = { 0, 502}; check_event(ev, expected_colours); { // don't overwrite auto new_expected = expected_colours; auto new_ev = ev; /// uno backward (=> qxQ -> g qx ... Q) std::swap(new_ev.outgoing[0].type, new_ev.outgoing[1].type); // => uno gluon connects to quark colour new_expected[3] = expected_colours[2]; new_expected[2] = {expected_colours[0].second+2, expected_colours[0].second}; check_event(new_ev, new_expected); /// swap qx <-> q (=> qQ -> g q ... Q) new_ev.incoming[0].type = HEJ::ParticleID::u; new_ev.outgoing[1].type = HEJ::ParticleID::u; // => swap: colour<->anti && inital<->final std::swap(new_expected[0], new_expected[3]); std::swap(new_expected[0].first, new_expected[0].second); std::swap(new_expected[3].first, new_expected[3].second); // => & connect first gluon with remaining anti-colour new_expected[2] = {new_expected[0].first, new_expected[0].first+2}; // shift colour line one down new_expected[1].first-=2; new_expected[5].first-=2; new_expected[5].second-=2; // shift anti-colour line one up new_expected[6].first+=2; check_event(new_ev, new_expected); } { // don't overwrite auto new_expected = expected_colours; auto new_ev = ev; /// uno forward (=> qxQ -> qx ... Q g) std::swap(new_ev.outgoing[3].type, new_ev.outgoing[4].type); // => uno gluon connects to remaining colour new_expected[5] = expected_colours[6]; new_expected[6] = {expected_colours[3].first+2, expected_colours[3].first}; check_event(new_ev, new_expected); } /// @TODO add qqx test when implemented (it should work) return EXIT_SUCCESS; } diff --git a/t/test_descriptions.cc b/t/test_descriptions.cc index 30c66a6..2d3c9d2 100644 --- a/t/test_descriptions.cc +++ b/t/test_descriptions.cc @@ -1,62 +1,67 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include <cstddef> #include "HEJ/Event.hh" #include "HEJ/EventReweighter.hh" #include "HEJ/ScaleFunction.hh" #define ASSERT(x) if(!(x)) { \ std::cerr << "Assertion '" #x "' failed.\n"; \ return EXIT_FAILURE; \ } int main() { constexpr double mu = 125.; HEJ::ScaleFunction fun{"125", HEJ::FixedScale{mu}}; ASSERT(fun.name() == "125"); HEJ::ScaleGenerator scale_gen{ {std::move(fun)}, {0.5, 1, 2.}, 2.1 }; HEJ::Event::EventData tmp; tmp.outgoing.push_back( {HEJ::ParticleID::gluon, fastjet::PtYPhiM(50., -1., 0.3, 0.), {}} ); tmp.outgoing.push_back( {HEJ::ParticleID::gluon, fastjet::PtYPhiM(30., 1., -0.3, 0.), {}} ); HEJ::Event ev{ tmp.cluster( fastjet::JetDefinition{fastjet::kt_algorithm, 0.4}, 20. ) }; auto rescaled = scale_gen(std::move(ev)); ASSERT(rescaled.central().description->scale_name == "125"); for(auto const & var: rescaled.variations()) { ASSERT(var.description->scale_name == "125"); } ASSERT(rescaled.central().description->mur_factor == 1.); ASSERT(rescaled.central().description->muf_factor == 1.); ASSERT(rescaled.variations(0).description->mur_factor == 1.); ASSERT(rescaled.variations(0).description->muf_factor == 1.); ASSERT(rescaled.variations(1).description->mur_factor == 0.5); ASSERT(rescaled.variations(1).description->muf_factor == 0.5); ASSERT(rescaled.variations(2).description->mur_factor == 0.5); ASSERT(rescaled.variations(2).description->muf_factor == 1.); ASSERT(rescaled.variations(3).description->mur_factor == 1.); ASSERT(rescaled.variations(3).description->muf_factor == 0.5); ASSERT(rescaled.variations(4).description->mur_factor == 1.); ASSERT(rescaled.variations(4).description->muf_factor == 2.); ASSERT(rescaled.variations(5).description->mur_factor == 2.); ASSERT(rescaled.variations(5).description->muf_factor == 1.); ASSERT(rescaled.variations(6).description->mur_factor == 2.); ASSERT(rescaled.variations(6).description->muf_factor == 2.); } diff --git a/t/test_hdf5.cc b/t/test_hdf5.cc index 8b14d31..08f7c10 100644 --- a/t/test_hdf5.cc +++ b/t/test_hdf5.cc @@ -1,40 +1,45 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include "HEJ/EventReader.hh" int main(int argc, char** argv) { if(argc != 2) { std::cerr << "Usage: " << argv[0] << " file.hdf5\n"; return EXIT_FAILURE; } auto reader = HEJ::make_reader(argv[1]); if( reader->heprup().EBMUP != std::make_pair(7000., 7000.) || reader->heprup().PDFSUP != std::make_pair(13000, 13000) ) { std::cerr << "Read incorrect init parameters\n"; return EXIT_FAILURE; } int nevent = 0; while(reader->read_event()) { ++nevent; if(reader->hepeup().NUP != 13) { std::cerr << "Read wrong number of particles: " << reader->hepeup().NUP << " != 13 in event " << nevent; return EXIT_FAILURE; } for(size_t i = 0; i < 2; ++i) { for(size_t j = 0; j < 2; ++j) { if(reader->hepeup().PUP[i][j] != 0) { std::cerr << "Non-vanishing transverse momentum in incoming particle" " in event " << nevent; return EXIT_FAILURE; } } } } if(nevent != 51200) { std::cerr << "Wrong number of events " << nevent << " != 51200\n"; return EXIT_FAILURE; } } diff --git a/t/test_parameters.cc b/t/test_parameters.cc index 2261167..796a4c7 100644 --- a/t/test_parameters.cc +++ b/t/test_parameters.cc @@ -1,71 +1,76 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <iostream> #include <stdexcept> #include "HEJ/Parameters.hh" #define ASSERT(x) if(!(x)) { \ throw std::logic_error("Assertion '" #x "' failed."); \ } namespace { bool same_description( HEJ::EventParameters const & par1, HEJ::EventParameters const & par2 ){ if( par1.mur!=par2.mur || par1.muf!=par2.muf ) return false; auto const & des1 = par1.description; auto const & des2 = par2.description; if(bool(des1) != bool(des2)) return false; // only one set if(!des1) return true; // both not set return (des1->mur_factor == des2->mur_factor) && (des1->muf_factor == des2->muf_factor) && (des1->scale_name == des2->scale_name); } void same_description( HEJ::Parameters<HEJ::EventParameters> const & par1, HEJ::Parameters<HEJ::EventParameters> const & par2 ){ ASSERT(same_description(par1.central, par2.central)); ASSERT(par1.variations.size() == par2.variations.size()); for(size_t i=0; i<par1.variations.size(); ++i) ASSERT( same_description(par1.variations[i], par2.variations[i]) ); } } int main() { HEJ::Parameters<HEJ::EventParameters> ev_param; ev_param.central = HEJ::EventParameters{ 1,1,1.1, std::make_shared<HEJ::ParameterDescription>("a", 1.,1.) }; ev_param.variations.emplace_back( HEJ::EventParameters{ 2,2,2.2, std::make_shared<HEJ::ParameterDescription>("b", 2.,2.) }); ev_param.variations.emplace_back( HEJ::EventParameters{ 3,3,3.3, std::make_shared<HEJ::ParameterDescription>("c", 3.,3.) }); HEJ::Weights weights; weights.central = 4.4; weights.variations.push_back(5.5); weights.variations.push_back(6.6); HEJ::Parameters<HEJ::EventParameters> mult_param; mult_param = ev_param*weights; same_description(ev_param, mult_param); ASSERT(mult_param.central.weight == ev_param.central.weight*weights.central); for(size_t i=0; i<weights.variations.size(); ++i) ASSERT(mult_param.variations[i].weight == ev_param.variations[i].weight*weights.variations[i]); HEJ::Parameters<HEJ::EventParameters> div_param; div_param = ev_param/weights; same_description(ev_param, div_param); ASSERT(div_param.central.weight == ev_param.central.weight/weights.central); for(size_t i=0; i<weights.variations.size(); ++i) ASSERT(div_param.variations[i].weight == ev_param.variations[i].weight/weights.variations[i]); return EXIT_SUCCESS; } diff --git a/t/test_psp.cc b/t/test_psp.cc index 87355c6..da35994 100644 --- a/t/test_psp.cc +++ b/t/test_psp.cc @@ -1,65 +1,70 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include "LHEF/LHEF.h" #include "HEJ/stream.hh" #include "HEJ/config.hh" #include "HEJ/event_types.hh" #include "HEJ/Event.hh" #include "HEJ/PhaseSpacePoint.hh" #include "HEJ/Ranlux64.hh" namespace{ constexpr int max_trials = 100; constexpr double extpartonptmin = 45.; constexpr double max_ext_soft_pt_fraction = std::numeric_limits<double>::infinity(); const fastjet::JetDefinition jet_def{fastjet::kt_algorithm, 0.4}; constexpr double min_jet_pt = 50; }; int main(int argn, char** argv) { if(argn != 2){ std::cerr << "Usage: " << argv[0] << " eventfile"; return EXIT_FAILURE; } HEJ::istream in{argv[1]}; LHEF::Reader reader{in}; LHEF::Writer writer{std::cerr}; writer.heprup = reader.heprup; HEJ::PhaseSpacePointConfig conf; conf.jet_param = HEJ::JetParameters{jet_def, min_jet_pt}; conf.min_extparton_pt = extpartonptmin; conf.max_ext_soft_pt_fraction = max_ext_soft_pt_fraction; HEJ::Ranlux64 ran{}; while(reader.readEvent()){ const HEJ::Event ev{ HEJ::Event::EventData{reader.hepeup}( jet_def, min_jet_pt ) }; for(int trial = 0; trial < max_trials; ++trial){ HEJ::PhaseSpacePoint psp{ev, conf, ran}; if(psp.weight() != 0){ HEJ::Event::EventData tmp_ev; tmp_ev.incoming = psp.incoming(); tmp_ev.outgoing = psp.outgoing(); tmp_ev.parameters.central = {0,0,0}; HEJ::Event out_ev{ tmp_ev(jet_def, min_jet_pt) }; if(out_ev.type() != ev.type()){ using HEJ::event_type::names; std::cerr << "Wrong class of phase space point:\n" "original event of class " << names[ev.type()] << ":\n"; writer.hepeup = reader.hepeup; writer.writeEvent(); std::cerr << "Phase space point of class " << names[out_ev.type()] << ":\n"; writer.hepeup = to_HEPEUP(out_ev, &writer.heprup); writer.writeEvent(); return EXIT_FAILURE; } } } } } diff --git a/t/test_scale_arithmetics.cc b/t/test_scale_arithmetics.cc index b640726..ff27844 100644 --- a/t/test_scale_arithmetics.cc +++ b/t/test_scale_arithmetics.cc @@ -1,99 +1,100 @@ - -// Generic tester for the ME for a given set of PSP -// reference weights and PSP (as LHE file) have to be given as _individual_ files - +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <fstream> #include <random> #include <algorithm> #include "LHEF/LHEF.h" #include "HEJ/EventReweighter.hh" #include "HEJ/make_RNG.hh" #include "HEJ/Event.hh" #include "HEJ/YAMLreader.hh" #include "HEJ/stream.hh" constexpr double alpha_s = 0.118; constexpr double ep = 1e-13; void dump(HEJ::Event const & ev){ { LHEF::Writer writer{std::cout}; std::cout << std::setprecision(6); writer.hepeup = to_HEPEUP(std::move(ev), nullptr); writer.writeEvent(); } std::cout << "Rapidity ordering:\n"; for(const auto & part: ev.outgoing()){ std::cout << std::setw(2) << part.type << ": "<< std::setw(7) << part.rapidity() << std::endl; } } void shuffle_particles(HEJ::Event::EventData & ev) { static std::mt19937_64 ran{0}; std::shuffle(begin(ev.incoming), end(ev.incoming), ran); std::shuffle(begin(ev.outgoing), end(ev.outgoing), ran); } int main(int argn, char** argv){ if(argn != 3){ std::cerr << "\n# Usage:\n."<< argv[0] <<" config.yml input_file.lhe\n\n"; return EXIT_FAILURE; } HEJ::Config config = HEJ::load_config(argv[1]); config.scales = HEJ::to_ScaleConfig( YAML::Load("scales: [H_T, 1 * H_T, 2/2 * H_T, 2*H_T/2, H_T/2*2, H_T/2/2*4, H_T*H_T/H_T]") ); HEJ::istream in{argv[2]}; LHEF::Reader reader{in}; auto ran = HEJ::make_RNG(config.rng.name, config.rng.seed); HEJ::ScaleGenerator scale_gen{ config.scales.base, config.scales.factors, config.scales.max_ratio }; HEJ::EventReweighter resum{ reader.heprup, std::move(scale_gen), to_EventReweighterConfig(config), *ran }; size_t i = 0; while(reader.readEvent()){ ++i; HEJ::Event::EventData data{reader.hepeup}; shuffle_particles(data); HEJ::Event event{ data.cluster( config.resummation_jets.def, config.resummation_jets.min_pt ) }; auto resummed = resum.reweight(event, config.trials); for(auto && ev: resummed) { for(auto &&var: ev.variations()) { if(std::abs(var.muf - ev.central().muf) > ep) { std::cerr << std::setprecision(15) << "unequal scales: " << var.muf << " != " << ev.central().muf << '\n' << "in resummed event:\n"; dump(ev); std::cerr << "\noriginal event:\n"; dump(event); return EXIT_FAILURE; } } } } } diff --git a/t/test_scale_import.cc b/t/test_scale_import.cc index 0b3fd88..36b72e9 100644 --- a/t/test_scale_import.cc +++ b/t/test_scale_import.cc @@ -1,29 +1,34 @@ +/** + * \authors The HEJ collaboration (see AUTHORS for details) + * \date 2019 + * \copyright GPLv2 or later + */ #include <stdexcept> #include <iostream> #include "HEJ/YAMLreader.hh" #include "HEJ/Event.hh" int main(int argc, char** argv) { constexpr double ep = 1e-7; if (argc != 2) { throw std::logic_error{"wrong number of args"}; } const HEJ::Config config = HEJ::load_config(argv[1]); HEJ::Event::EventData tmp; tmp.outgoing.push_back( {HEJ::ParticleID::gluon, fastjet::PtYPhiM(50., -1., 0.3, 0.), {}} ); tmp.outgoing.push_back( {HEJ::ParticleID::gluon, fastjet::PtYPhiM(30., 1., -0.3, 0.), {}} ); HEJ::Event ev{ tmp(fastjet::JetDefinition{fastjet::kt_algorithm, 0.4}, 20.) }; const double softest_pt = config.scales.base[0](ev); if(std::abs(softest_pt-30.) > ep){ throw std::logic_error{"wrong softest pt"}; } }