Page MenuHomeHEPForge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
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 d2234b4..720b71e 100644
--- a/FixedOrderGen/include/PhaseSpacePoint.hh
+++ b/FixedOrderGen/include/PhaseSpacePoint.hh
@@ -1,216 +1,219 @@
-/** \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
);
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 64bb955..45756da 100644
--- a/FixedOrderGen/include/Process.hh
+++ b/FixedOrderGen/include/Process.hh
@@ -1,15 +1,20 @@
+/**
+ * \authors The HEJ collaboration (see AUTHORS for details)
+ * \date 2019
+ * \copyright GPLv2 or later
+ */
#pragma once
#include <array>
#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;
};
}
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 4543185..951dd56 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,654 +1,659 @@
+/**
+ * \authors The HEJ collaboration (see AUTHORS for details)
+ * \date 2019
+ * \copyright GPLv2 or later
+ */
#include "PhaseSpacePoint.hh"
#include <algorithm>
#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};
}
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);
outgoing_.reserve(nout);
// generate parton momenta
const bool is_pure_jets = !proc.boson;
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 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 = std::upper_bound(
begin(outgoing_),end(outgoing_),boson,rapidity_less{}
);
outgoing_.insert(pos, 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;
}
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 9e0b3b5..bb68da5 100644
--- a/FixedOrderGen/src/config.cc
+++ b/FixedOrderGen/src/config.cc
@@ -1,359 +1,364 @@
+/**
+ * \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;
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', 'W+', 'W-', 'Z', 'H'"
};
}
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(!HEJ::is_AWZH_boson(pid)){
throw invalid_outgoing(particles[i]);
}
if(result.boson){
throw std::invalid_argument{
"More than one outgoing boson is not supported"
};
}
result.boson = pid;
}
}
if(result.njets < 2){
throw std::invalid_argument{
"Process has to include at least two jets ('j')"
};
}
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/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 9be4d9f..8274bf1 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(10)
<< " " << std::left << std::setw(20)
<< "Cross section: " << xs.total().value
<< " +- " << std::sqrt(xs.total().error) << " (pb)\n";
for(auto const & xs_type: xs) {
os
<< " " << std::left << std::setw(20)
<< (HEJ::event_type::names[xs_type.first] + std::string(": "))
<< xs_type.second.value << " +- "
<< std::sqrt(xs_type.second.error) << " (pb)\n";
}
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 71b5503..54a574d 100644
--- a/include/HEJ/Event.hh
+++ b/include/HEJ/Event.hh
@@ -1,275 +1,274 @@
/** \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.3.0
[[deprecated("UnclusteredEvent will be replaced by EventData")]]
Event(
UnclusteredEvent const & ev,
fastjet::JetDefinition const & jet_def, double min_jet_pt
);
//! The jets formed by the outgoing partons
std::vector<fastjet::PseudoJet> jets() const;
//! 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_;
}
//! 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
): incoming_{std::move(incoming)},
outgoing_{std::move(outgoing)},
decays_{std::move(decays)},
parameters_{std::move(parameters)},
cs_{ to_PseudoJet( filter_partons(outgoing_) ), jet_def },
min_jet_pt_{min_jet_pt}
{};
std::array<Particle, 2> incoming_;
std::vector<Particle> outgoing_;
std::unordered_map<size_t, std::vector<Particle>> decays_;
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();
std::array<Particle, 2> incoming;
std::vector<Particle> outgoing;
std::unordered_map<size_t, std::vector<Particle>> decays;
Parameters<EventParameters> parameters;
}; // end class EventData
//! 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.3.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..fae8b53 100644
--- a/include/HEJ/EventReweighter.hh
+++ b/include/HEJ/EventReweighter.hh
@@ -1,190 +1,190 @@
/** \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/PDF.hh"
#include "HEJ/PDG_codes.hh"
#include "HEJ/RNG.hh"
#include "HEJ/ScaleFunction.hh"
#include "HEJ/Parameters.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
);
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_;
};
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 7138456..13bc75e 100644
--- a/include/HEJ/HDF5Reader.hh
+++ b/include/HEJ/HDF5Reader.hh
@@ -1,44 +1,44 @@
/** \file
* \brief Header file for reading events in the HDF5 event 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 "HEJ/EventReader.hh"
namespace HEJ{
//! 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 8c01bb6..982172a 100644
--- a/include/HEJ/LesHouchesReader.hh
+++ b/include/HEJ/LesHouchesReader.hh
@@ -1,52 +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 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 cf3ca3a..5a3b0a8 100644
--- a/include/HEJ/PDG_codes.hh
+++ b/include/HEJ/PDG_codes.hh
@@ -1,143 +1,142 @@
/** \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 */
u_bar = -u, /*!< Anti-Up quark */
s_bar = -s, /*!< Anti-Strange Quark */
c_bar = -c, /*!< Anti-Charm Quark */
b_bar = -b, /*!< Anti-Bottom Quark */
t_bar = -t, /*!< Anti-Top Quark */
e_bar = -e, /*!< Positron */
positron = e_bar, /*!< Positron */
nu_e_bar = -nu_e, /*!< Anti-Electron Neutrino */
mu_bar = -mu, /*!< Anti-Muon */
nu_mu_bar = -nu_mu, /*!< Anti-Muon Neutrino */
tau_bar = -tau, /*!< Anti-Tau */
nu_tau_bar = -nu_tau, /*!< Anti-Tau 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 */
};
}
using ParticleID = pid::ParticleID;
//! Convert a particle name to the corresponding PDG particle ID
ParticleID to_ParticleID(std::string const & name);
/**
* \brief Function to determine if particle is a parton
* @param p PDG ID of particle
* @returns true if the particle is a parton, false otherwise
*/
inline
constexpr bool is_parton(ParticleID p){
return p == pid::gluon || std::abs(p) <= pid::top;
}
/**
* \brief Function to determine if particle is a quark
* @param id PDG ID of particle
* @returns true if the particle is a qaurk, false otherwise
*/
inline
constexpr bool is_quark(ParticleID id){
return (id >= pid::down && id <= pid::top);
}
/**
* \brief Function to determine if particle is a 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 a (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 a 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 a 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);
}
}
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 c6f321c..a2aa613 100644
--- a/include/HEJ/Particle.hh
+++ b/include/HEJ/Particle.hh
@@ -1,148 +1,147 @@
/**
* \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);
}
//! 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 634c239..2f18172 100644
--- a/include/HEJ/PhaseSpacePoint.hh
+++ b/include/HEJ/PhaseSpacePoint.hh
@@ -1,164 +1,163 @@
/** \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"
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_;
}
static constexpr int ng_max = 1000; //< maximum number of extra gluons
private:
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;
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_;
};
}
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/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 1c1016f..801f97f 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.3.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/Event.cc b/src/Event.cc
index 6c63a59..d366a8c 100644
--- a/src/Event.cc
+++ b/src/Event.cc
@@ -1,787 +1,787 @@
/**
- * \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/Event.hh"
#include <algorithm>
#include <assert.h>
#include <numeric>
#include <utility>
#include "LHEF/LHEF.h"
#include "fastjet/JetDefinition.hh"
#include "HEJ/Constants.hh"
#include "HEJ/exceptions.hh"
#include "HEJ/PDG_codes.hh"
namespace HEJ{
namespace{
constexpr int status_in = -1;
constexpr int status_decayed = 2;
constexpr int status_out = 1;
/// @name helper functions to determine event type
//@{
/**
* \brief check if final state valid for HEJ
*
* check if there is at most one photon, W, H, Z in the final state
* and all the rest are quarks or gluons
*/
bool final_state_ok(std::vector<Particle> const & outgoing){
bool has_AWZH_boson = false;
for(auto const & out: outgoing){
if(is_AWZH_boson(out.type)){
if(has_AWZH_boson) return false;
has_AWZH_boson = true;
}
else if(! is_parton(out.type)) return false;
}
return true;
}
template<class Iterator>
Iterator remove_AWZH(Iterator begin, Iterator end){
return std::remove_if(
begin, end, [](Particle const & p){return is_AWZH_boson(p);}
);
}
template<class Iterator>
bool valid_outgoing(Iterator begin, Iterator end){
return std::distance(begin, end) >= 2
&& std::is_sorted(begin, end, rapidity_less{})
&& std::count_if(
begin, end, [](Particle const & s){return is_AWZH_boson(s);}
) < 2;
}
/**
* \brief function which determines if type change is consistent with W emission.
* @param in incoming Particle
* @param out outgoing Particle
*
* Ensures that change type of quark line is possible by a flavour changing
* W emission.
*/
bool is_W_Current(ParticleID in, ParticleID out){
if((in==1 && out==2)||(in==2 && out==1)){
return true;
}
else if((in==-1 && out==-2)||(in==-2 && out==-1)){
return true;
}
else if((in==3 && out==4)||(in==4 && out==3)){
return true;
}
else if((in==-3 && out==-4)||(in==-4 && out==-3)){
return true;
}
else{
return false;
}
}
/**
* \brief checks if particle type remains same from incoming to outgoing
* @param in incoming Particle
* @param out outgoing Particle
*/
bool is_Pure_Current(ParticleID in, ParticleID out){
if(abs(in)<=6 || in==21) return (in==out);
else return false;
}
// @note that this changes the outgoing range!
template<class ConstIterator, class Iterator>
bool is_FKL(
ConstIterator begin_incoming, ConstIterator end_incoming,
Iterator begin_outgoing, Iterator end_outgoing
){
assert(std::distance(begin_incoming, end_incoming) == 2);
assert(std::distance(begin_outgoing, end_outgoing) >= 2);
// One photon, W, H, Z in the final state is allowed.
// Remove it for remaining tests,
end_outgoing = remove_AWZH(begin_outgoing, end_outgoing);
if(std::all_of(
begin_outgoing + 1, end_outgoing - 1,
[](Particle const & p){ return p.type == pid::gluon; })
){
// Test if this is a standard FKL configuration.
if (is_Pure_Current(begin_incoming->type, begin_outgoing->type)
&& is_Pure_Current((end_incoming-1)->type, (end_outgoing-1)->type)){
return true;
}
}
return false;
}
template<class ConstIterator, class Iterator>
bool is_W_FKL(
ConstIterator begin_incoming, ConstIterator end_incoming,
Iterator begin_outgoing, Iterator end_outgoing
){
assert(std::distance(begin_incoming, end_incoming) == 2);
assert(std::distance(begin_outgoing, end_outgoing) >= 2);
// One photon, W, H, Z in the final state is allowed.
// Remove it for remaining tests,
end_outgoing = remove_AWZH(begin_outgoing, end_outgoing);
if(std::all_of(
begin_outgoing + 1, end_outgoing - 1,
[](Particle const & p){ return p.type == pid::gluon; })
){
// Test if this is a standard FKL configuration.
if(is_W_Current(begin_incoming->type, begin_outgoing->type)
&& is_Pure_Current((end_incoming-1)->type, (end_outgoing-1)->type)){
return true;
}
else if(is_Pure_Current(begin_incoming->type, begin_outgoing->type)
&& is_W_Current((end_incoming-1)->type, (end_outgoing-1)->type)){
return true;
}
}
return false;
}
bool is_FKL(
std::array<Particle, 2> const & incoming,
std::vector<Particle> outgoing
){
assert(std::is_sorted(begin(incoming), end(incoming), pz_less{}));
assert(valid_outgoing(begin(outgoing), end(outgoing)));
const auto WEmit = std::find_if(
begin(outgoing), end(outgoing),
[](Particle const & s){ return abs(s.type) == pid::Wp; }
);
if (WEmit != end(outgoing) && abs(WEmit->type) == pid::Wp){
return is_W_FKL(
begin(incoming), end(incoming),
begin(outgoing), end(outgoing)
);
}
else{
return is_FKL(
begin(incoming), end(incoming),
begin(outgoing), end(outgoing)
);
}
}
bool has_2_jets(Event const & event){
return event.jets().size() >= 2;
}
/**
* \brief Checks whether event is unordered backwards
* @param ev Event
* @returns Is Event Unordered Backwards
*
* - Checks there is more than 3 constuents in the final state
* - Checks there is more than 3 jets
* - Checks the most backwards parton is a gluon
* - Checks the most forwards jet is not a gluon
* - Checks the rest of the event is FKL
* - Checks the second most backwards is not a different boson
* - Checks the unordered gluon actually forms a jet
*/
bool is_unordered_backward(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.front().type == pid::gluon) return false;
if(out.front().type != pid::gluon) return false;
// When skipping the unordered emission
// the remainder should be a regular FKL event,
// except that the (new) first outgoing particle must not be a A,W,Z,H.
const auto FKL_begin = next(begin(out));
if(is_AWZH_boson(*FKL_begin)) return false;
if(!is_FKL(in, {FKL_begin, end(out)})) return false;
// check that the unordered gluon forms an extra jet
const auto jets = sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets.front()});
return indices[0] >= 0 && indices[1] == -1;
}
/**
* \brief Checks for a forward unordered gluon emission
* @param ev Event
* @returns Is the event a forward unordered emission
*
* \see is_unordered_backward
*/
bool is_unordered_forward(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.back().type == pid::gluon) return false;
if(out.back().type != pid::gluon) return false;
// When skipping the unordered emission
// the remainder should be a regular FKL event,
// except that the (new) last outgoing particle must not be a A,W,Z,H.
const auto FKL_end = prev(end(out));
if(is_AWZH_boson(*prev(FKL_end))) return false;
if(!is_FKL(in, {begin(out), FKL_end})) return false;
// check that the unordered gluon forms an extra jet
const auto jets = sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets.back()});
return indices.back() >= 0 && indices[indices.size()-2] == -1;
}
/**
* \brief Checks for a forward extremal qqx
* @param ev Event
* @returns Is the event a forward extremal qqx event
*
* Checks there is 3 or more than 3 constituents in the final state
* Checks there is 3 or more than 3 jets
* Checks most forwards incoming is gluon
* Checks most extremal particle is not a Higgs (either direction)
* Checks the second most forwards particle is not Higgs boson
* Checks the most forwards parton is a either quark or anti-quark.
* Checks the second most forwards parton is anti-quark or quark.
* Checks the qqbar pair form 2 separate jets.
*/
bool is_Ex_qqxf(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
int fkl_end=2;
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.back().type != pid::gluon) return false;
if(out.back().type == pid::Higgs || out.front().type == pid::Higgs
|| out.rbegin()[1].type == pid::Higgs) return false;
// if extremal AWZ
if(is_AWZ_boson(out.back())){ // if extremal AWZ
fkl_end++;
if (is_quark(out.rbegin()[1])){ //if second quark
if (!(is_antiquark(out.rbegin()[2]))) return false;// third must be anti-quark
}
else if (is_antiquark(out.rbegin()[1])){ //if second anti-quark
if (!(is_quark(out.rbegin()[2]))) return false;// third must be quark
}
else return false;
}
else if (is_quark(out.rbegin()[0])){ //if extremal quark
if(is_AWZ_boson(out.rbegin()[1])){ // if second AWZ
fkl_end++;
if (!(is_antiquark(out.rbegin()[2]))) return false;// third must be anti-quark
}
else if (!(is_antiquark(out.rbegin()[1]))) return false;// second must be anti-quark
}
else if (is_antiquark(out.rbegin()[0])){ //if extremal anti-quark
if(is_AWZ_boson(out.rbegin()[1])){ // if second AWZ
fkl_end++;
if (!(is_quark(out.rbegin()[2]))) return false;// third must be quark
}
else if (!(is_quark(out.rbegin()[1]))) return false;// second must be quark
}
else return false;
// When skipping the qqbar
// New last outgoing particle must not be a Higgs
if (out.rbegin()[fkl_end].type == pid::Higgs) return false;
const auto jets = fastjet::sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets});
// Ensure qqbar pair are in separate jets
if(indices[indices.size()-2] != indices[indices.size()-1]-1) return false;
// Opposite current should be logical to process
if (is_AWZ_boson(out.front().type)){
return (is_Pure_Current(in.front().type, out[1].type)
|| is_W_Current(in.front().type,out[1].type));
}
else
return (is_Pure_Current(in.front().type, out[0].type)
|| is_W_Current(in.front().type,out[0].type));
}
/**
* \brief Checks for a backward extremal qqx
* @param ev Event
* @returns Is the event a backward extremal qqx event
*
* Checks there is 3 or more than 3 constituents in the final state
* Checks there is 3 or more than 3 jets
* Checks most backwards incoming is gluon
* Checks most extremal particle is not a Higgs (either direction) y
* Checks the second most backwards particle is not Higgs boson y
* Checks the most backwards parton is a either quark or anti-quark. y
* Checks the second most backwards parton is anti-quark or quark. y
* Checks the qqbar pair form 2 separate jets.
*/
bool is_Ex_qqxb(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
int fkl_start=2;
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.front().type != pid::gluon) return false;
if(out.back().type == pid::Higgs || out.front().type == pid::Higgs
|| out[1].type == pid::Higgs) return false;
if(is_AWZ_boson(out.front())){ // if extremal AWZ
fkl_start++;
if (is_quark(out[1])){ //if second quark
if (!(is_antiquark(out[2]))) return false;// third must be anti-quark
}
else if (is_antiquark(out[1])){ //if second anti-quark
if (!(is_quark(out[2]))) return false;// third must be quark
}
else return false;
}
else if (is_quark(out[0])){ // if extremal quark
if(is_AWZ_boson(out[1])){ // if second AWZ
fkl_start++;
if (!(is_antiquark(out[2]))) return false;// third must be anti-quark
}
else if (!(is_antiquark(out[1]))) return false;// second must be anti-quark
}
else if (is_antiquark(out[0])){ //if extremal anti-quark
if(is_AWZ_boson(out[1])){ // if second AWZ
fkl_start++;
if (!(is_quark(out[2]))) return false;// third must be quark
}
else if (!(is_quark(out[1]))) return false;// second must be quark
}
else return false;
// When skipping the qqbar
// New last outgoing particle must not be a Higgs.
if (out[fkl_start].type == pid::Higgs) return false;
const auto jets = fastjet::sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets});
// Ensure qqbar pair form separate jets.
if(indices[0] != indices[1]-1) return false;
// Other current should be logical to process
if (is_AWZ_boson(out.back())){
return (is_Pure_Current(in.back().type, out.rbegin()[1].type)
|| is_W_Current(in.back().type,out.rbegin()[1].type));
}
else
return (is_Pure_Current(in.back().type, out.rbegin()[0].type)
|| is_W_Current(in.back().type, out.rbegin()[0].type));
}
/**
* \brief Checks for a central qqx
* @param ev Event
* @returns Is the event a central extremal qqx event
*
* Checks there is 4 or more than 4 constuents in the final state
* Checks there is 4 or more than 4 jets
* Checks most extremal particle is not a Higgs (either direction) y
* Checks for a central quark in the outgoing states
* Checks for adjacent anti-quark parton. (allowing for AWZ boson emission between)
* Checks external currents are logically sound.
*/
bool is_Mid_qqx(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
if(out.size() < 4) return false;
if(ev.jets().size() < 4) return false;
if(out.back().type == pid::Higgs || out.front().type == pid::Higgs)
return false;
size_t start_FKL=0;
size_t end_FKL=0;
if (is_AWZ_boson(out.back())){
end_FKL++;
}
if (is_AWZ_boson(out.front())){
start_FKL++;
}
if ((is_Pure_Current(in.back().type,out.rbegin()[end_FKL].type)
&& is_Pure_Current(in.front().type,out[start_FKL].type))){
//nothing to do
}
else if (is_W_Current(in.back().type,out.rbegin()[end_FKL].type)
&& is_Pure_Current(in.front().type,out[start_FKL].type)){
//nothing to do
}
else if (!(is_Pure_Current(in.back().type,out.rbegin()[end_FKL].type)
&& is_W_Current(in.front().type,out[start_FKL].type))){
return false;
}
const auto jets = fastjet::sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets});
auto const out_partons = filter_partons(out);
for (size_t i = 1; i<out_partons.size()-2; i++){
if ((is_quark(out_partons[i]) && (is_antiquark(out_partons[i+1])))
|| (is_antiquark(out_partons[i]) && (is_quark(out_partons[i+1])))){
return (indices[i+1] == indices[i]+1 && indices[i] != -1);
}
}
return false;
}
using event_type::EventType;
EventType classify(Event const & ev){
if(! final_state_ok(ev.outgoing()))
return EventType::bad_final_state;
if(! has_2_jets(ev))
return EventType::no_2_jets;
if(is_FKL(ev.incoming(), ev.outgoing()))
return EventType::FKL;
if(is_unordered_backward(ev))
return EventType::unordered_backward;
if(is_unordered_forward(ev))
return EventType::unordered_forward;
if(is_Ex_qqxb(ev))
return EventType::extremal_qqxb;
if(is_Ex_qqxf(ev))
return EventType::extremal_qqxf;
if(is_Mid_qqx(ev))
return EventType::central_qqx;
return EventType::nonHEJ;
}
//@}
Particle extract_particle(LHEF::HEPEUP const & hepeup, int i){
const ParticleID id = static_cast<ParticleID>(hepeup.IDUP[i]);
const fastjet::PseudoJet momentum{
hepeup.PUP[i][0], hepeup.PUP[i][1],
hepeup.PUP[i][2], hepeup.PUP[i][3]
};
if(is_parton(id))
return Particle{ id, std::move(momentum), hepeup.ICOLUP[i] };
return Particle{ id, std::move(momentum), {} };
}
bool is_decay_product(std::pair<int, int> const & mothers){
if(mothers.first == 0) return false;
return mothers.second == 0 || mothers.first == mothers.second;
}
} // namespace anonymous
Event::EventData::EventData(LHEF::HEPEUP const & hepeup){
parameters.central = EventParameters{
hepeup.scales.mur, hepeup.scales.muf, hepeup.weight()
};
size_t in_idx = 0;
for (int i = 0; i < hepeup.NUP; ++i) {
// skip decay products
// we will add them later on, but we have to ensure that
// the decayed particle is added before
if(is_decay_product(hepeup.MOTHUP[i])) continue;
auto particle = extract_particle(hepeup, i);
// needed to identify mother particles for decay products
particle.p.set_user_index(i+1);
if(hepeup.ISTUP[i] == status_in){
if(in_idx > incoming.size()) {
throw std::invalid_argument{
"Event has too many incoming particles"
};
}
incoming[in_idx++] = std::move(particle);
}
else outgoing.emplace_back(std::move(particle));
}
// add decay products
for (int i = 0; i < hepeup.NUP; ++i) {
if(!is_decay_product(hepeup.MOTHUP[i])) continue;
const int mother_id = hepeup.MOTHUP[i].first;
const auto mother = std::find_if(
begin(outgoing), end(outgoing),
[mother_id](Particle const & particle){
return particle.p.user_index() == mother_id;
}
);
if(mother == end(outgoing)){
throw std::invalid_argument{"invalid decay product parent"};
}
const int mother_idx = std::distance(begin(outgoing), mother);
assert(mother_idx >= 0);
decays[mother_idx].emplace_back(extract_particle(hepeup, i));
}
}
Event::Event(
UnclusteredEvent const & ev,
fastjet::JetDefinition const & jet_def, double const min_jet_pt
):
Event( Event::EventData{
ev.incoming, ev.outgoing, ev.decays,
Parameters<EventParameters>{ev.central, ev.variations}
}.cluster(jet_def, min_jet_pt) )
{}
//! @TODO remove in HEJ 2.3.0
UnclusteredEvent::UnclusteredEvent(LHEF::HEPEUP const & hepeup){
Event::EventData const evData{hepeup};
incoming = evData.incoming;
outgoing = evData.outgoing;
decays = evData.decays;
central = evData.parameters.central;
variations = evData.parameters.variations;
}
void Event::EventData::sort(){
// sort particles
std::sort(
begin(incoming), end(incoming),
[](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
);
auto old_outgoing = std::move(outgoing);
std::vector<size_t> idx(old_outgoing.size());
std::iota(idx.begin(), idx.end(), 0);
std::sort(idx.begin(), idx.end(), [&old_outgoing](size_t i, size_t j){
return old_outgoing[i].rapidity() < old_outgoing[j].rapidity();
});
outgoing.clear();
outgoing.reserve(old_outgoing.size());
for(size_t i: idx) {
outgoing.emplace_back(std::move(old_outgoing[i]));
}
// find decays again
if(!decays.empty()){
auto old_decays = std::move(decays);
decays.clear();
for(size_t i=0; i<idx.size(); ++i) {
auto decay = old_decays.find(idx[i]);
if(decay != old_decays.end())
decays.emplace(i, std::move(decay->second));
}
assert(old_decays.size() == decays.size());
}
}
Event Event::EventData::cluster(
fastjet::JetDefinition const & jet_def, double const min_jet_pt
){
sort();
Event ev{ std::move(incoming), std::move(outgoing), std::move(decays),
std::move(parameters),
jet_def, min_jet_pt
};
assert(std::is_sorted(begin(ev.outgoing_), end(ev.outgoing_),
rapidity_less{}));
ev.type_ = classify(ev);
return ev;
}
namespace {
void connect_incoming(Particle & in, int & colour, int & anti_colour){
in.colour = std::make_pair(anti_colour, colour);
// gluon
if(in.type == pid::gluon)
return;
if(in.type > 0){
// quark
assert(is_quark(in));
in.colour->second = 0;
colour*=-1;
return;
}
// anti-quark
assert(is_antiquark(in));
in.colour->first = 0;
anti_colour*=-1;
return;
}
}
bool Event::generate_colours(RNG & ran){
// generate only for HEJ events
if(!event_type::is_HEJ(type()))
return false;
assert(std::is_sorted(
begin(outgoing()), end(outgoing()), rapidity_less{}));
assert(incoming()[0].pz() < incoming()[1].pz());
// positive (anti-)colour -> can connect
// negative (anti-)colour -> not available/used up by (anti-)quark
int colour = COLOUR_OFFSET;
int anti_colour = colour+1;
// initialise first
connect_incoming(incoming_[0], colour, anti_colour);
for(auto & part: outgoing_){
assert(colour>0 || anti_colour>0);
if(part.type == ParticleID::gluon){
// gluon
if(colour>0 && anti_colour>0){
// on g line => connect to colour OR anti-colour (random)
if(ran.flat() < 0.5){
part.colour = std::make_pair(colour+2,colour);
colour+=2;
} else {
part.colour = std::make_pair(anti_colour, anti_colour+2);
anti_colour+=2;
}
} else if(colour > 0){
// on q line => connect to available colour
part.colour = std::make_pair(colour+2, colour);
colour+=2;
} else {
assert(colour<0 && anti_colour>0);
// on qx line => connect to available anti-colour
part.colour = std::make_pair(anti_colour, anti_colour+2);
anti_colour+=2;
}
} else if(is_quark(part)) {
// quark
assert(anti_colour>0);
if(colour>0){
// on g line => connect and remove anti-colour
part.colour = std::make_pair(anti_colour, 0);
anti_colour+=2;
anti_colour*=-1;
} else {
// on qx line => new colour
colour*=-1;
part.colour = std::make_pair(colour, 0);
}
} else if(is_antiquark(part)) {
// anti-quark
assert(colour>0);
if(anti_colour>0){
// on g line => connect and remove colour
part.colour = std::make_pair(0, colour);
colour+=2;
colour*=-1;
} else {
// on q line => new anti-colour
anti_colour*=-1;
part.colour = std::make_pair(0, anti_colour);
}
}
// else not a parton
}
// Connect last
connect_incoming(incoming_[1], anti_colour, colour);
return true;
} // generate_colours
std::vector<fastjet::PseudoJet> Event::jets() const{
return cs_.inclusive_jets(min_jet_pt_);
}
double shat(Event const & ev){
return (ev.incoming()[0].p + ev.incoming()[1].p).m2();
}
LHEF::HEPEUP to_HEPEUP(Event const & event, LHEF::HEPRUP * heprup){
LHEF::HEPEUP result;
result.heprup = heprup;
result.weights = {{event.central().weight, nullptr}};
for(auto const & var: event.variations()){
result.weights.emplace_back(var.weight, nullptr);
}
size_t num_particles = event.incoming().size() + event.outgoing().size();
for(auto const & decay: event.decays()) num_particles += decay.second.size();
result.NUP = num_particles;
// the following entries are pretty much meaningless
result.IDPRUP = event.type()+1; // event ID
result.AQEDUP = 1./128.; // alpha_EW
//result.AQCDUP = 0.118 // alpha_QCD
// end meaningless part
result.XWGTUP = event.central().weight;
result.SCALUP = event.central().muf;
result.scales.muf = event.central().muf;
result.scales.mur = event.central().mur;
result.scales.SCALUP = event.central().muf;
result.pdfinfo.p1 = event.incoming().front().type;
result.pdfinfo.p2 = event.incoming().back().type;
result.pdfinfo.scale = event.central().muf;
result.IDUP.reserve(num_particles); // PID
result.ISTUP.reserve(num_particles); // status (in, out, decay)
result.PUP.reserve(num_particles); // momentum
result.MOTHUP.reserve(num_particles); // index mother particle
result.ICOLUP.reserve(num_particles); // colour
// incoming
for(Particle const & in: event.incoming()){
result.IDUP.emplace_back(in.type);
result.ISTUP.emplace_back(status_in);
result.PUP.push_back({in.p[0], in.p[1], in.p[2], in.p[3], in.p.m()});
result.MOTHUP.emplace_back(0, 0);
assert(in.colour);
result.ICOLUP.emplace_back(*in.colour);
}
// outgoing
for(size_t i = 0; i < event.outgoing().size(); ++i){
Particle const & out = event.outgoing()[i];
result.IDUP.emplace_back(out.type);
const int status = event.decays().count(i)?status_decayed:status_out;
result.ISTUP.emplace_back(status);
result.PUP.push_back({out.p[0], out.p[1], out.p[2], out.p[3], out.p.m()});
result.MOTHUP.emplace_back(1, 2);
if(out.colour)
result.ICOLUP.emplace_back(*out.colour);
else{
assert(is_AWZH_boson(out));
result.ICOLUP.emplace_back(std::make_pair(0,0));
}
}
// decays
for(auto const & decay: event.decays()){
for(auto const out: decay.second){
result.IDUP.emplace_back(out.type);
result.ISTUP.emplace_back(status_out);
result.PUP.push_back({out.p[0], out.p[1], out.p[2], out.p[3], out.p.m()});
const size_t mother_idx = 1 + event.incoming().size() + decay.first;
result.MOTHUP.emplace_back(mother_idx, mother_idx);
result.ICOLUP.emplace_back(0,0);
}
}
assert(result.ICOLUP.size() == num_particles);
static constexpr double unknown_spin = 9.; //per Les Houches accord
result.VTIMUP = std::vector<double>(num_particles, unknown_spin);
result.SPINUP = result.VTIMUP;
return result;
}
}
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 693a847..7461ddc 100644
--- a/src/EventReweighter.cc
+++ b/src/EventReweighter.cc
@@ -1,257 +1,257 @@
/**
- * \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());
switch(param_.treat.at(ev.type())){
case EventTreatment::discard: return {};
case EventTreatment::keep:
if(! jets_pass_resummation_cuts(ev)) return {};
else return {ev};
default:;
}
const double Born_shat = shat(ev);
std::vector<Event> resummation_events;
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;
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();
assert(new_event.type() == ev.type());
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 e453c57..8cc5bbd 100644
--- a/src/PDG_codes.cc
+++ b/src/PDG_codes.cc
@@ -1,54 +1,54 @@
/**
- * \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}, {"-1",static_cast<ParticleID>(-1)},
{"u_bar", u_bar}, {"-2",static_cast<ParticleID>(-2)},
{"s_bar", s_bar}, {"-3",static_cast<ParticleID>(-3)},
{"c_bar", c_bar}, {"-4",static_cast<ParticleID>(-4)},
{"b_bar", b_bar}, {"-5",static_cast<ParticleID>(-5)},
{"t_bar", t_bar}, {"-6",static_cast<ParticleID>(-6)},
{"e_bar", e_bar}, {"positron", positron}, {"e+", e_bar}, {"-11",static_cast<ParticleID>(-11)},
{"nu_e_bar", nu_e_bar}, {"-12",static_cast<ParticleID>(-12)},
{"mu_bar", mu_bar}, {"mu+", mu_bar}, {"-13",static_cast<ParticleID>(-13)},
{"nu_mu_bar", nu_mu_bar}, {"-14",static_cast<ParticleID>(-14)},
{"tau_bar", tau_bar}, {"tau+", tau_bar}, {"-15",static_cast<ParticleID>(-15)},
{"nu_tau_bar", nu_tau_bar}, {"-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;
}
}
diff --git a/src/PhaseSpacePoint.cc b/src/PhaseSpacePoint.cc
index c7fa77f..1a901fc 100644
--- a/src/PhaseSpacePoint.cc
+++ b/src/PhaseSpacePoint.cc
@@ -1,623 +1,623 @@
/**
- * \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 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{}));
}
//! \brief relabels qqx-pair with its PDG IDs.
//*@param ev Born Event
//
// This function will label the qqx pair in a qqx event back to
// their original types from the input event.
void PhaseSpacePoint::label_qqx(Event const & event){
auto const & bornout = event.outgoing();
const auto backquark = std::find_if(
begin(bornout) + 1 - ((qqxb_)?1:0), end(bornout) - 1 + ((qqxf_)?1:0) ,
[](Particle const & s){ return (is_anyquark(s.type)); }
);
if(backquark == end(bornout) || (backquark+1)->type==pid::gluon) weight_= 0;
auto quark1type = backquark->type;
auto quark2type = (backquark+1)->type;
if(is_AWZ_boson((backquark+1)->type)) quark2type = (backquark+2)->type;
if( !((is_quark(quark1type) && is_antiquark(quark2type))
&& !(is_quark(quark2type) && is_antiquark(quark1type)))
){
weight_=0;
}
auto partons = to_PseudoJet(filter_partons(outgoing_));
fastjet::ClusterSequence cs(partons, event.jet_def());
const auto jets = fastjet::sorted_by_rapidity(cs.inclusive_jets(event.min_jet_pt()));
const auto indices = cs.particle_jet_indices({jets});
assert(partons.size() == indices.size());
int qpart=-1;
// Find Parton in res event closest to most backward qqx jet in born
for (size_t i=0; i<indices.size(); i++) {
if( (indices[i] != -1) && (indices[i]==indices[i+1]-1)
&& nearby_ep(backquark->rapidity(), partons[i].rapidity(), 0.1)){
qpart=i;
outgoing_.at(qpart).type = quark1type;
outgoing_.at(qpart+1).type = quark2type;
break;
}
}
if(qpart==-1) weight_=0;
assert(std::is_sorted(begin(outgoing_), end(outgoing_), rapidity_less{}));
}
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}
{
weight_ = 1;
const auto Born_jets = sorted_by_rapidity(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(! pass_resummation_cuts(jets)){
weight_ = 0.;
return;
}
std::vector<fastjet::PseudoJet> jet_partons = split(jets, ng_jets);
if(weight_ == 0.) 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.;
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.;
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);
}
copy_AWZH_boson_from(ev);
assert(!outgoing_.empty());
reconstruct_incoming(ev.incoming());
}
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 = sorted_by_rapidity(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 d799cc4..cc91d60 100644
--- a/src/bin/HEJ.cc
+++ b/src/bin/HEJ.cc
@@ -1,188 +1,188 @@
/**
- * \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
};
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
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;
// calculate HEJ weight
HEJ::Event FO_event{
HEJ::Event::EventData{hepeup}(
config.fixed_order_jets.def, config.fixed_order_jets.min_pt
)
};
auto resummed_events = hej.reweight(FO_event, config.trials);
++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::chrono::duration<double> run_time = (clock::now() - start_time);
std::cout << "Finished " << 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 88fdd47..fab2b8f 100644
--- a/t/check_res.cc
+++ b/t/check_res.cc
@@ -1,134 +1,139 @@
+/**
+ * \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{
HEJ::Event ev{
HEJ::Event::EventData{reader.hepeup}.cluster(
Born_jet_def, Born_jetptmin
)
};
auto resummed_events = hej.reweight(ev, 20);
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"};
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jan 20, 11:35 PM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4233208
Default Alt Text
(739 KB)

Event Timeline