Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F7877698
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
101 KB
Subscribers
None
View Options
diff --git a/include/HEJ/event_types.hh b/include/HEJ/event_types.hh
index 849b29a..77d2ffc 100644
--- a/include/HEJ/event_types.hh
+++ b/include/HEJ/event_types.hh
@@ -1,106 +1,106 @@
/** \file
* \brief Define different types of events.
*
* \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{
- FixedOrder=0, /**< event configuration not covered by All Order resummation */
+ non_resummable=0, /**< event configuration not covered by All Order resummation */
bad_final_state=1, /**< event with an unsupported final state */
no_2_jets=2, /**< event with less than two jets */
FKL=4, /**< FKL-type event */
unordered_backward=8, /**< event with unordered backward emission */
unordered_forward=16, /**< event with unordered forward emission */
extremal_qqxb=32, /**< event with a backward extremal qqbar */
extremal_qqxf=64, /**< event with a forward extremal qqbar */
central_qqx=128, /**< event with a central qqbar */
unob = unordered_backward,
unof = unordered_forward,
qqxexb = extremal_qqxb,
qqxexf = extremal_qqxf,
qqxmid = central_qqx,
- first_type = FixedOrder,
+ first_type = non_resummable,
last_type = central_qqx
};
//! Event type names
/**
* For example, name(FKL) is the string "FKL"
*/
inline std::string name(EventType type) {
switch(type) {
case FKL:
return "FKL";
case unordered_backward:
return "unordered backward";
case unordered_forward:
return "unordered forward";
case extremal_qqxb:
return "extremal qqbar backward";
case extremal_qqxf:
return "extremal qqbar forward";
case central_qqx:
return "central qqbar";
- case FixedOrder:
- return "FixedOrder";
+ case non_resummable:
+ return "non-resummable";
case no_2_jets:
return "no 2 jets";
case bad_final_state:
return "bad final state";
default:
throw std::logic_error{"Unreachable"};
}
};
//! 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;
}
//! Returns True for an extremal_qqx \ref event_type::EventType "EventType"
inline
bool is_ex_qqx(EventType type) {
return type == extremal_qqxb || type == extremal_qqxf;
}
//! Returns True for an central_qqx \ref event_type::EventType "EventType"
inline
bool is_mid_qqx(EventType type) {
return type == central_qqx;
}
//! Returns True for any qqx event \ref event_type::EventType "EventType"
inline
bool is_qqx(EventType type) {
return is_ex_qqx(type) || is_mid_qqx(type);
}
} // namespace event_type
} // namespace HEJ
diff --git a/src/Event.cc b/src/Event.cc
index 7166357..985b0e4 100644
--- a/src/Event.cc
+++ b/src/Event.cc
@@ -1,785 +1,785 @@
/**
* \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;
}
/**
* \brief function which determines if type change is consistent with Wp emission.
* @param in incoming Particle id
* @param out outgoing Particle id
* @param qqx Current both incoming/both outgoing?
*
* \see is_Wm_Change
*/
bool is_Wp_Change(ParticleID in, ParticleID out, bool qqx){
if(!qqx && (in==-1 || in== 2 || in==-3 || in== 4)) return out== (in-1);
if( qqx && (in== 1 || in==-2 || in== 3 || in==-4)) return out==-(in+1);
return false;
}
/**
* \brief function which determines if type change is consistent with Wm emission.
* @param in incoming Particle id
* @param out outgoing Particle id
* @param qqx Current both incoming/both outgoing?
*
* Ensures that change type of quark line is possible by a flavour changing
* Wm emission. Allows checking of qqx currents also.
*/
bool is_Wm_Change(ParticleID in, ParticleID out, bool qqx){
if(!qqx && (in== 1 || in==-2 || in== 3 || in==-4)) return out== (in+1);
if( qqx && (in==-1 || in== 2 || in==-3 || in== 4)) return out==-(in-1);
return false;
}
/**
* \brief checks if particle type remains same from incoming to outgoing
* @param in incoming Particle
* @param out outgoing Particle
* @param qqx Current both incoming/outgoing?
*/
bool no_flavour_change(ParticleID in, ParticleID out, bool qqx){
const int qqxCurrent = qqx?-1:1;
if(abs(in)<=6 || in==pid::gluon) return (in==out*qqxCurrent);
else return false;
}
bool has_2_jets(Event const & event){
return event.jets().size() >= 2;
}
/**
* \brief check if we have a valid Impact factor
* @param in incoming Particle
* @param out outgoing Particle
* @param qqx Current both incoming/outgoing?
* @param qqx returns +1 if Wp, -1 if Wm, else 0
*/
bool is_valid_impact_factor(
ParticleID in, ParticleID out, bool qqx, int & W_change
){
if( no_flavour_change(in, out, qqx) ){
return true;
}
if( is_Wp_Change(in, out, qqx) ) {
W_change+=1;
return true;
}
if( is_Wm_Change(in, out, qqx) ) {
W_change-=1;
return true;
}
return false;
}
//! Returns all possible classifications from the impact factors
// the beginning points are changed s.t. after the the classification they
// point to the beginning of the (potential) FKL chain
// sets W_change: + if Wp change
// 0 if no change
// - if Wm change
// This function can be used with forward & backwards iterators
template<class OutIterator, class IndexIterator>
size_t possible_impact_factors(
ParticleID incoming_id, // incoming
OutIterator & begin_out, OutIterator const & end_out, // outgoing
IndexIterator & begin_idx, // jet indices
int & W_change, std::vector<Particle> const & boson,
bool const backward // backward?
){
using event_type::EventType;
assert(boson.size() < 2);
// keep track of all states that we don't test
size_t not_tested = EventType::qqxmid;
if(backward)
not_tested |= EventType::unof | EventType::qqxexf;
else
not_tested |= EventType::unob | EventType::qqxexb;
// Is this LL current?
if( is_valid_impact_factor(incoming_id, begin_out->type, false, W_change) ){
++begin_out;
++begin_idx;
return not_tested | EventType::FKL;
}
// or NLL current?
// -> needs two partons in two different jets
if( std::distance(begin_out, end_out)>=2
&& *begin_idx>=0 && *(begin_idx+1)>=0 && *begin_idx!=*(begin_idx+1)
){
// Is this unordered emisson?
if( incoming_id!=pid::gluon && begin_out->type==pid::gluon ){
if( is_valid_impact_factor(
incoming_id, (begin_out+1)->type, false, W_change )
){
// veto Higgs inside uno
assert((begin_out+1)<end_out);
if( !boson.empty() && boson.front().type == ParticleID::h
){
if( (backward && boson.front().rapidity() < (begin_out+1)->rapidity())
||(!backward && boson.front().rapidity() > (begin_out+1)->rapidity()))
- return EventType::FixedOrder;
+ return EventType::non_resummable;
}
begin_out+=2;
begin_idx+=2;
return not_tested | (backward?EventType::unob:EventType::unof);
}
}
// Is this QQbar?
else if( incoming_id==pid::gluon ){
if( is_valid_impact_factor(
begin_out->type, (begin_out+1)->type, true, W_change )
){
// veto Higgs inside qqx
assert((begin_out+1)<end_out);
if( !boson.empty() && boson.front().type == ParticleID::h
){
if( (backward && boson.front().rapidity() < (begin_out+1)->rapidity())
||(!backward && boson.front().rapidity() > (begin_out+1)->rapidity()))
- return EventType::FixedOrder;
+ return EventType::non_resummable;
}
begin_out+=2;
begin_idx+=2;
return not_tested | (backward?EventType::qqxexb:EventType::qqxexf);
}
}
}
- return EventType::FixedOrder;
+ return EventType::non_resummable;
}
//! Returns all possible classifications from central emissions
// the beginning points are changed s.t. after the the classification they
// point to the end of the emission chain
// sets W_change: + if Wp change
// 0 if no change
// - if Wm change
template<class OutIterator, class IndexIterator>
size_t possible_central(
OutIterator & begin_out, OutIterator const & end_out,
IndexIterator & begin_idx,
int & W_change, std::vector<Particle> const & boson
){
using event_type::EventType;
assert(boson.size() < 2);
// if we already passed the central chain,
// then it is not a valid all-order state
- if(std::distance(begin_out, end_out) < 0) return EventType::FixedOrder;
+ if(std::distance(begin_out, end_out) < 0) return EventType::non_resummable;
// keep track of all states that we don't test
size_t possible = EventType::unob | EventType::unof
| EventType::qqxexb | EventType::qqxexf;
// Find the first non-gluon/non-FKL
while( (begin_out->type==pid::gluon) && (begin_out<end_out) ){
++begin_out;
++begin_idx;
}
// end of chain -> FKL
if( begin_out==end_out ){
return possible | EventType::FKL;
}
// is this a qqbar-pair?
// needs two partons in two separate jets
if( is_valid_impact_factor(
begin_out->type, (begin_out+1)->type, true, W_change )
&& *begin_idx>=0 && *(begin_idx+1)>=0 && *begin_idx!=*(begin_idx+1)
){
// veto Higgs inside qqx
if( !boson.empty() && boson.front().type == ParticleID::h
&& boson.front().rapidity() > begin_out->rapidity()
&& boson.front().rapidity() < (begin_out+1)->rapidity()
){
- return EventType::FixedOrder;
+ return EventType::non_resummable;
}
begin_out+=2;
begin_idx+=2;
// remaining chain should be pure gluon/FKL
for(; begin_out<end_out; ++begin_out){
- if(begin_out->type != pid::gluon) return EventType::FixedOrder;
+ if(begin_out->type != pid::gluon) return EventType::non_resummable;
++begin_idx;
}
return possible | EventType::qqxmid;
}
- return EventType::FixedOrder;
+ return EventType::non_resummable;
}
/**
* \brief Checks for all event types
* @param ev Event
* @returns Event Type
*
*/
event_type::EventType classify(Event const & ev){
using event_type::EventType;
if(! has_2_jets(ev))
return EventType::no_2_jets;
// currently we can't handle multiple boson states in the ME. So they are
// considered "bad_final_state" even though the "classify" could work with
// them.
if(! final_state_ok(ev.outgoing()))
return EventType::bad_final_state;
// initialise variables
auto const & in = ev.incoming();
auto const & out = filter_partons(ev.outgoing());
auto indices{ev.particle_jet_indices({ev.jets()})};
assert(std::distance(begin(in), end(in)) == 2);
assert(out.size() >= 2);
assert(std::distance(begin(out), end(out)) >= 2);
assert(std::is_sorted(begin(out), end(out), rapidity_less{}));
auto const boson{ filter_AWZH_bosons(ev.outgoing()) };
// we only allow one boson through final_state_ok
assert(boson.size()<=1);
// keep track of potential W couplings, at the end the sum should be 0
int remaining_Wp = 0;
int remaining_Wm = 0;
if(!boson.empty() && abs(boson.front().type) == ParticleID::Wp ){
if(boson.front().type>0) ++remaining_Wp;
else ++remaining_Wm;
}
int W_change = 0;
// range for current checks
auto begin_out{out.cbegin()};
auto end_out{out.crbegin()};
auto begin_idx{indices.cbegin()};
auto end_idx{indices.crbegin()};
size_t final_type = ~(EventType::no_2_jets | EventType::bad_final_state);
// check forward impact factor
final_type &= possible_impact_factors(
in.front().type,
begin_out, end_out.base(), begin_idx,
W_change, boson, true );
assert(std::distance(begin_out, end_out.base())
== std::distance(begin_idx, end_idx.base()));
if(W_change>0) remaining_Wp-=W_change;
else if(W_change<0) remaining_Wm+=W_change;
W_change = 0;
// check backward impact factor
final_type &= possible_impact_factors(
in.back().type,
end_out, std::make_reverse_iterator(begin_out), end_idx,
W_change, boson, false );
assert(std::distance(begin_out, end_out.base())
== std::distance(begin_idx, end_idx.base()));
if(W_change>0) remaining_Wp-=W_change;
else if(W_change<0) remaining_Wm+=W_change;
W_change = 0;
// check central emissions
final_type &= possible_central(
begin_out, end_out.base(), begin_idx, W_change, boson );
assert(std::distance(begin_out, end_out.base())
== std::distance(begin_idx, end_idx.base()));
if(W_change>0) remaining_Wp-=W_change;
else if(W_change<0) remaining_Wm+=W_change;
// Check whether the right number of Ws are present
- if( remaining_Wp != 0 || remaining_Wm != 0 ) return EventType::FixedOrder;
+ if( remaining_Wp != 0 || remaining_Wm != 0 ) return EventType::non_resummable;
// result has to be unique
- if( (final_type & (final_type-1)) != 0) return EventType::FixedOrder;
+ if( (final_type & (final_type-1)) != 0) return EventType::non_resummable;
return static_cast<EventType>(final_type);
}
//@}
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.2.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());
}
}
namespace {
Particle reconstruct_boson(std::vector<Particle> const & leptons) {
Particle decayed_boson;
decayed_boson.p = leptons[0].p + leptons[1].p;
const int pidsum = leptons[0].type + leptons[1].type;
if(pidsum == +1) {
assert(is_antilepton(leptons[0]));
if(is_antineutrino(leptons[0])) {
throw not_implemented{"lepton-flavour violating final state"};
}
assert(is_neutrino(leptons[1]));
// charged antilepton + neutrino means we had a W+
decayed_boson.type = pid::Wp;
}
else if(pidsum == -1) {
assert(is_antilepton(leptons[0]));
if(is_neutrino(leptons[1])) {
throw not_implemented{"lepton-flavour violating final state"};
}
assert(is_antineutrino(leptons[0]));
// charged lepton + antineutrino means we had a W-
decayed_boson.type = pid::Wm;
}
else {
throw not_implemented{
"final state with leptons "
+ name(leptons[0].type)
+ " and "
+ name(leptons[1].type)
};
}
return decayed_boson;
}
}
void Event::EventData::reconstruct_intermediate() {
const auto begin_leptons = std::partition(
begin(outgoing), end(outgoing),
[](Particle const & p) {return !is_anylepton(p);}
);
if(begin_leptons == end(outgoing)) return;
assert(is_anylepton(*begin_leptons));
std::vector<Particle> leptons(begin_leptons, end(outgoing));
outgoing.erase(begin_leptons, end(outgoing));
if(leptons.size() != 2) {
throw not_implemented{"Final states with one or more than two leptons"};
}
std::sort(
begin(leptons), end(leptons),
[](Particle const & p0, Particle const & p1) {
return p0.type < p1.type;
}
);
outgoing.emplace_back(reconstruct_boson(leptons));
decays.emplace(outgoing.size()-1, std::move(leptons));
}
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;
}
Event::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}
{
jets_ = sorted_by_rapidity(cs_.inclusive_jets(min_jet_pt_));
}
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
Event::ConstPartonIterator Event::begin_partons() const {
return cbegin_partons();
};
Event::ConstPartonIterator Event::cbegin_partons() const {
return boost::make_filter_iterator(
static_cast<bool (*)(Particle const &)>(is_parton),
cbegin(outgoing()),
cend(outgoing())
);
};
Event::ConstPartonIterator Event::end_partons() const {
return cend_partons();
};
Event::ConstPartonIterator Event::cend_partons() const {
return boost::make_filter_iterator(
static_cast<bool (*)(Particle const &)>(is_parton),
cend(outgoing()),
cend(outgoing())
);
};
namespace {
void print_momentum(std::ostream & os, fastjet::PseudoJet const & part){
const std::streamsize orig_prec = os.precision();
os <<std::scientific<<std::setprecision(6) << "["
<<std::setw(13)<<std::right<< part.px() << ", "
<<std::setw(13)<<std::right<< part.py() << ", "
<<std::setw(13)<<std::right<< part.pz() << ", "
<<std::setw(13)<<std::right<< part.E() << "]"<< std::fixed;
os.precision(orig_prec);
}
}
std::ostream& operator<<(std::ostream & os, Event const & ev){
const std::streamsize orig_prec = os.precision();
os <<std::setprecision(4)<<std::fixed;
std::cout << "########## " << event_type::name(ev.type()) << " ##########" << std::endl;
std::cout << "Incoming particles:\n";
for(auto const & in: ev.incoming()){
std::cout <<std::setw(3)<< in.type << ": ";
print_momentum(os, in.p);
std::cout << std::endl;
}
std::cout << "\nOutgoing particles: " << ev.outgoing().size() << "\n";
for(auto const & out: ev.outgoing()){
std::cout <<std::setw(3)<< out.type << ": ";
print_momentum(os, out.p);
std::cout << " => rapidity="
<<std::setw(7)<<std::right<< out.rapidity() << std::endl;
}
std::cout << "\nForming Jets: " << ev.jets().size() << "\n";
for(auto const & jet: ev.jets()){
print_momentum(os, jet);
std::cout << " => rapidity="
<<std::setw(7)<<std::right<< jet.rapidity() << std::endl;
}
if(ev.decays().size() > 0 ){
std::cout << "\nDecays: " << ev.decays().size() << "\n";
for(auto const & decay: ev.decays()){
std::cout <<std::setw(3)<< ev.outgoing()[decay.first].type
<< " (" << decay.first << ") to:\n";
for(auto const & out: decay.second){
std::cout <<" "<<std::setw(3)<< out.type << ": ";
print_momentum(os, out.p);
std::cout << " => rapidity="
<<std::setw(7)<<std::right<< out.rapidity() << std::endl;
}
}
}
os << std::defaultfloat;
os.precision(orig_prec);
return os;
}
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(); // event type
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/YAMLreader.cc b/src/YAMLreader.cc
index 6a0f524..59b5332 100644
--- a/src/YAMLreader.cc
+++ b/src/YAMLreader.cc
@@ -1,474 +1,474 @@
/**
* \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", "extremal qqx", "central qqx", "non-resummable",
"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},
- {FixedOrder, EventTreatment::keep}
+ {non_resummable, 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, "extremal qqx");
set_from_yaml(treat.at(qqxexf), yaml, "extremal qqx");
set_from_yaml(treat.at(qqxmid), yaml, "central qqx");
- set_from_yaml(treat.at(FixedOrder), yaml, "non-resummable");
- if(treat[FixedOrder] == EventTreatment::reweight){
+ set_from_yaml(treat.at(non_resummable), yaml, "non-resummable");
+ if(treat[non_resummable] == EventTreatment::reweight){
throw std::invalid_argument{"Cannot reweight Fixed Order 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 = 0.1;
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/t/check_res.cc b/t/check_res.cc
index a8a2546..f67d0a8 100644
--- a/t/check_res.cc
+++ b/t/check_res.cc
@@ -1,165 +1,165 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include <iostream>
#include <math.h>
#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 = 0.1;
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},
- {FixedOrder, EventTreatment::discard},
+ {non_resummable, 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]) == "unof"){
--argn;
treat[unof] = EventTreatment::reweight;
treat[unob] = EventTreatment::discard;
treat[FKL] = EventTreatment::discard;
}
if(argn == 5 && std::string(argv[4]) == "unob"){
--argn;
treat[unof] = EventTreatment::discard;
treat[unob] = EventTreatment::reweight;
treat[FKL] = EventTreatment::discard;
}
else if(argn == 5 && std::string(argv[4]) == "splitf"){
--argn;
treat[qqxexb] = EventTreatment::discard;
treat[qqxexf] = EventTreatment::reweight;
treat[FKL] = EventTreatment::discard;
}
else if(argn == 5 && std::string(argv[4]) == "splitb"){
--argn;
treat[qqxexb] = EventTreatment::reweight;
treat[qqxexf] = EventTreatment::discard;
treat[FKL] = EventTreatment::discard;
}
else if(argn == 5 && std::string(argv[4]) == "qqxmid"){
--argn;
treat[qqxmid] = EventTreatment::reweight;
treat[FKL] = EventTreatment::discard;
}
if(argn != 4){
std::cerr << "Usage: check_res eventfile xsection tolerance [uno]";
return EXIT_FAILURE;
}
const double xsec_ref = std::stod(argv[2]);
const double tolerance = std::stod(argv[3]);
HEJ::istream in{argv[1]};
LHEF::Reader reader{in};
HEJ::PhaseSpacePointConfig psp_conf;
psp_conf.jet_param = HEJ::JetParameters{jet_def, jetptmin};
psp_conf.min_extparton_pt = extpartonptmin;
psp_conf.max_ext_soft_pt_fraction = max_ext_soft_pt_fraction;
HEJ::MatrixElementConfig ME_conf;
ME_conf.log_correction = log_corr;
ME_conf.Higgs_coupling = HEJ::HiggsCouplingSettings{};
HEJ::EventReweighterConfig conf;
conf.psp_config = std::move(psp_conf);
conf.ME_config = std::move(ME_conf);
conf.jet_param = psp_conf.jet_param;
conf.treat = treat;
reader.readEvent();
const bool has_Higgs = std::find(
begin(reader.hepeup.IDUP),
end(reader.hepeup.IDUP),
25
) != end(reader.hepeup.IDUP);
const double mu = has_Higgs?125.:91.188;
HEJ::ScaleGenerator scale_gen{
{{std::to_string(mu), HEJ::FixedScale{mu}}}, {}, 1.
};
HEJ::Mixmax ran{};
HEJ::EventReweighter hej{reader.heprup, std::move(scale_gen), conf, ran};
double xsec = 0.;
double xsec_err = 0.;
do{
auto ev_data = HEJ::Event::EventData{reader.hepeup};
ev_data.reconstruct_intermediate();
HEJ::Event ev{
ev_data.cluster(
Born_jet_def, Born_jetptmin
)
};
auto resummed_events = hej.reweight(ev, 100);
for(auto const & ev: resummed_events) {
ASSERT(correct_colour(ev));
ASSERT(isfinite(ev.central().weight));
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/test_classify.cc b/t/test_classify.cc
index 34d568f..8b1dafd 100644
--- a/t/test_classify.cc
+++ b/t/test_classify.cc
@@ -1,835 +1,835 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include <iostream>
#include <random>
#include "HEJ/Event.hh"
#include "HEJ/exceptions.hh"
#define ASSERT(x) if(!(x)) { \
throw std::logic_error("Assertion '" #x "' failed."); \
}
namespace {
const fastjet::JetDefinition jet_def{fastjet::JetAlgorithm::antikt_algorithm, 0.4};
const double min_jet_pt{30.};
const std::array<std::string, 6> all_quarks{"-4","-1","1","2","3","4"};
const std::array<std::string, 7> all_partons{"g","-2","-1","1","2","3","4"};
const std::array<std::string, 3> all_bosons{"h", "Wp", "Wm"};
static std::mt19937_64 ran{0};
void shuffle_particles(HEJ::Event::EventData & ev) {
std::shuffle(begin(ev.incoming), end(ev.incoming), ran);
std::shuffle(begin(ev.outgoing), end(ev.outgoing), ran);
}
// if pos_boson = -1 (or not implemented) -> no boson
// njet==7 is special: has less jets, i.e. multiple parton in one jet,
// pos_boson < 0 to select process (see list for details)
HEJ::Event::EventData get_process(int const njet, int const pos_boson){
HEJ::Event::EventData ev;
if(njet == 2){
switch(pos_boson){
case 0:
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 198, 33, -170, 291}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-154, 68, 44, 174}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -44, -101, 88, 141}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -322, 322}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 284, 284}, {}};
return ev;
case 1:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -6, 82, -159, 179}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 195, -106, 74, 265}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-189, 24, 108, 219}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -320, 320}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 343, 343}, {}};
return ev;
case 2:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -80, -80, -140, 180}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -60, -32, 0, 68}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 140, 112, 177, 281}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -246, 246}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 283, 283}, {}};
return ev;
default:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -72, 24, 18, 78}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 72, -24, 74, 106}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -46, 46}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 138, 138}, {}};
return ev;
}
}
if(njet == 3){
switch(pos_boson){
case 0:
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 152, -117, -88, 245}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-146, 62, -11, 159}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 126, -72, 96, 174}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-132, 127, 144, 233}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -335, 335}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 476, 476}, {}};
return ev;
case 1:
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-191, 188, -128, 297}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 199, 72, -76, 257}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 184, -172, -8, 252}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-192, -88, 54, 218}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -591, 591}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 433, 433}, {}};
return ev;
case 2:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -42, 18, -49, 67}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, -54, -28, 62}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 99, 32, -16, 163}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -45, 4, 72, 85}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -199, 199}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 178, 178}, {}};
return ev;
case 3:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -65, -32, -76, 105}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -22, 31, -34, 51}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, -67, -36, 77}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 99, 68, -4, 173}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -278, 278}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 128, 128}, {}};
return ev;
default:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -90, -135, 30, 165}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-108, 198, 76, 238}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 198, -63, 126, 243}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -207, 207}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 439, 439}, {}};
return ev;
}
}
if(njet == 4){
switch(pos_boson){
case 0:
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 199, 72, -76, 257}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-200, -155, -64, 261}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 198, 194, 57, 283}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 1, 32, 8, 33}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-198, -143, 186, 307}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -515, 515}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 626, 626}, {}};
return ev;
case 1:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 198, 61, -162, 263}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 199, 72, -76, 257}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-200, 135, 144, 281}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-198, -186, 171, 321}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 1, -82, 122, 147}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -535, 535}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 734, 734}, {}};
return ev;
case 2:
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-180, -27, -164, 245}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-108, 78, -36, 138}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 196, -189, 68, 307}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-107, 136, 76, 189}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 199, 2, 178, 267}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -512, 512}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 634, 634}, {}};
return ev;
case 3:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, -30, -84, 90}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -72, 22, -96, 122}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 0, -51, 85}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 64, 72, -81, 177}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -64, 84, 116}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -409, 409}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 181, 181}, {}};
return ev;
case 4:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -72, -49, -72, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, 0, -36, 60}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 54, -36, 66}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, -77, -56, 117}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 64, 72, -81, 177}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -407, 407}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 126, 126}, {}};
return ev;
default:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 248, -56, -122, 282}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 249, 30, -10, 251}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-249, -18, 26, 251}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-248, 44, 199, 321}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -506, 506}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 599, 599}, {}};
return ev;
}
}
if(njet == 6){
switch(pos_boson){
case 0:
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 349, 330, -94, 505}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-315, -300, 0, 435}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 347, 306, 18, 463}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-249, -342, 162, 453}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 345, 312, 284, 545}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-324, -126, 292, 454}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-153, -180, 304, 385}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -1137, 1137}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 2103, 2103}, {}};
return ev;
case 1:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 242, 241, -182, 387}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 243, 238, -190, 409}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-218, -215, -74, 315}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-224, -224, 112, 336}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 241, 182, 154, 339}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -53, -234, 126, 271}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-231, 12, 156, 279}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -1117, 1117}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 1219, 1219}, {}};
return ev;
case 2:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 151, 102, -42, 187}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -86, -46, -17, 99}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 152, 153, 0, 249}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -60, -135, 64, 161}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 150, 123, 110, 223}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-154, -49, 98, 189}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-153, -148, 144, 257}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -504, 504}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 861, 861}, {}};
return ev;
case 3:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 198, 197, -66, 287}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-198, -189, -54, 279}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-200, -64, 2, 210}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 199, 158, 6, 283}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-199, -184, 172, 321}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 196, 168, 177, 313}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 4, -86, 92, 126}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -745, 745}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 1074, 1074}, {}};
return ev;
case 4:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 151, 102, -42, 187}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -86, -133, -14, 159}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-154, -104, -8, 186}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -60, 11, 0, 61}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 152, 153, 0, 249}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 150, 125, 90, 215}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-153, -154, 126, 251}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -578, 578}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 730, 730}, {}};
return ev;
case 5:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -90, -94, 131}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 82, -74, 111}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -80, -64, 105}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -25, -36, 65}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -16, 101}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 68, 92, -18, 170}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -78, 54, 95}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -513, 513}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 265, 265}, {}};
return ev;
case 6:
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 198, 197, -66, 287}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 4, -84, -18, 86}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-198, -60, -36, 210}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 196, -78, -36, 214}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-200, 45, 0, 205}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-199, -178, 2, 267}, {}});
ev.outgoing.push_back({HEJ::ParticleID::higgs, { 199, 158, 6, 283}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -850, 850}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 702, 702}, {}};
return ev;
default:
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-350, -112, -280, 462}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 347, 266, -322, 543}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-349, -314, -38, 471}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 349, 348, 12, 493}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, {-342, -54, 23, 347}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 345, -134, 138, 395}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -1589, 1589}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 1122, 1122}, {}};
return ev;
}
}
if(njet == 7){
switch(pos_boson){
case -1: // jet idx: -1 0 1 2 3 4 5
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, -18, -42, 47}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, 26, -18, 35}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, -24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -54, -6, 59}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -44, 8, 45}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -96, 44, 116}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, 88, 133}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -249, 249}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 299, 299}, {}};
return ev;
case -2: // jet idx: 0 1 2 3 4 -1 -1
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -80, -64, 105}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -84, -12, 85}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, 88, 133}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -24, 62, 82}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, -18, 42, 47}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, 20, 60, 65}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -215, 215}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 415, 415}, {}};
return ev;
case -3: // jet idx: 0 0 1 2 3 4 5
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -86, -70, 111}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -52, -36, 65}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -44, 109}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -60, 5, 77}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 92, 8, 93}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -80, 64, 105}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -361, 361}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 312, 312}, {}};
return ev;
case -4: // jet idx: 0 1 2 3 4 5 5
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -40, -56, 69}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -88, 133}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -84, -72, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 92, 8, 93}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -58, 30, 67}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -96, 96, 144}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -395, 395}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 337, 337}, {}};
return ev;
case -5: // jet idx: 0 1 -1 -1 2 3 4
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -64, -80, 105}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -16, 101}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, 20, 0, 25}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, -10, 2, 15}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -72, 54, 102}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -60, 48, 77}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -253, 253}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 285, 285}, {}};
return ev;
case -6: // jet idx: 0 0 0 1 2 2 3
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -60, -48, 77}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -52, -36, 65}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -96, -58, 122}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, -24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -16, 101}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 92, 8, 93}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -70, 14, 75}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -403, 403}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 243, 243}, {}};
return ev;
case -7: // jet idx: 0 1 1 2 2 3 4
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -46, -46, 69}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -90, -70, 115}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -78, -54, 95}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 88, -28, 93}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, -16, 101}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -60, 5, 77}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -424, 424}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 239, 239}, {}};
return ev;
case -8: // jet idx: 0 1 2 2 2 3 4
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 23, -84, -84, 121}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -11, 92, -8, 93}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -15, -36, 0, 39}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -5, -62, 10, 63}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -48, -96, 19, 109}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { 68, 87, 24, 113}, {}});
ev.outgoing.push_back({HEJ::ParticleID::gluon, { -12, 99, 88, 133}, {}});
ev.incoming[0] = {HEJ::ParticleID::gluon, { 0, 0, -311, 311}, {}};
ev.incoming[1] = {HEJ::ParticleID::gluon, { 0, 0, 360, 360}, {}};
return ev;
}
}
throw HEJ::unknown_option{"unkown process"};
}
bool couple_quark(std::string const & boson, std::string & quark){
if(abs(HEJ::to_ParticleID(boson)) == HEJ::ParticleID::Wp){
auto qflav{ HEJ::to_ParticleID(quark) };
if(!HEJ::is_anyquark(qflav)) return false;
const int W_charge = HEJ::to_ParticleID(boson)>0?1:-1;
if(W_charge*qflav < 0 && !(abs(qflav)%2)) return false; // not anti-down
if(W_charge*qflav > 0 && (abs(qflav)%2)) return false; // not up
quark=std::to_string(qflav-W_charge);
}
return true;
}
// create event corresponding from given Configuration
// overwrite_boson to force a specific boson position, indepentent from input
// (useful for njet == 7)
HEJ::Event parse_configuration(
std::array<std::string,2> const & in, std::vector<std::string> const & out,
int const overwrite_boson = 0
){
auto boson = std::find_if(out.cbegin(), out.cend(),
[](std::string id){ return !HEJ::is_parton(HEJ::to_ParticleID(id)); });
int const pos_boson = (overwrite_boson!=0)?overwrite_boson:
((boson == out.cend())?-1:std::distance(out.cbegin(), boson));
size_t njets = out.size();
if(boson != out.cend()) --njets;
HEJ::Event::EventData ev{get_process(njets, pos_boson)};
ASSERT((pos_boson<0) || (ev.outgoing[pos_boson].type == HEJ::ParticleID::higgs));
for(size_t i=0; i<out.size(); ++i){
ev.outgoing[i].type = HEJ::to_ParticleID(out[i]);
}
for(size_t i=0; i<in.size(); ++i){
ev.incoming[i].type = HEJ::to_ParticleID(in[i]);
}
shuffle_particles(ev);
return ev.cluster(jet_def, min_jet_pt);
}
bool match_expectation( HEJ::event_type::EventType expected,
std::array<std::string,2> const & in, std::vector<std::string> const & out,
int const overwrite_boson = 0
){
HEJ::Event ev{parse_configuration(in,out,overwrite_boson)};
if(ev.type() != expected){
std::cerr << "Expected type " << HEJ::event_type::name(expected)
<< " but found " << HEJ::event_type::name(ev.type()) << "\n" << ev;
auto jet_idx{ ev.particle_jet_indices(ev.jets()) };
std::cout << "Particle Jet indices: ";
for(int const i: jet_idx)
std::cout << i << " ";
std::cout << std::endl;
return false;
}
return true;
}
bool check_fkl(){
using namespace HEJ;
for(std::string const & first: all_partons) // all quark flavours
for(std::string const & last: all_partons){
for(int njet=2; njet<=6; ++njet){ // all multiplicities
if(njet==5) continue;
std::array<std::string,2> base_in{first,last};
std::vector<std::string> base_out(njet, "g");
base_out.front() = first;
base_out.back() = last;
if(!match_expectation(event_type::FKL, base_in, base_out))
return false;
for(auto const & boson: all_bosons) // any boson
for(int pos=0; pos<=njet; ++pos){ // at any position
auto in{base_in};
auto out{base_out};
// change quark flavours for W
int couple_idx{ std::uniform_int_distribution<int>{0,1}(ran) };
if(!couple_quark(boson, couple_idx?out.back():out.front()))
continue;
out.insert(out.begin()+pos, boson);
if(!match_expectation(event_type::FKL, in, out))
return false;
}
}
for(int i=-1; i>-9;--i){ // jet setup doesn't matter for FKL
std::array<std::string,2> base_in{first,last};
std::vector<std::string> base_out(7, "g");
base_out.front() = first;
base_out.back() = last;
if(!match_expectation(event_type::FKL, base_in, base_out, i))
return false;
}
}
return true;
}
bool check_uno(){
using namespace HEJ;
auto const b{ event_type::unob };
auto const f{ event_type::unof };
for(std::string const & uno: all_quarks) // all quark flavours
for(std::string const & fkl: all_partons){
for(int njet=3; njet<=6; ++njet){ // all multiplicities >2
if(njet==5) continue;
for(int i=0; i<2; ++i){ // forward & backwards
std::array<std::string,2> base_in;
std::vector<std::string> base_out(njet, "g");
const int uno_pos = i?1:(njet-2);
const int fkl_pos = i?(njet-1):0;
base_in[i?0:1] = uno;
base_in[i?1:0] = fkl;
base_out[uno_pos] = uno;
base_out[fkl_pos] = fkl;
auto expectation{ i?b:f };
if( !match_expectation(expectation, base_in, base_out) )
return false;
for(auto const & boson: all_bosons){ // any boson
// at any position (higgs only inside FKL chain)
int start = 0;
int end = njet;
if(to_ParticleID(boson) == pid::higgs){
start = i?(uno_pos+1):fkl_pos;
end = i?(fkl_pos+1):uno_pos;
}
for(int pos=start; pos<=end; ++pos){
auto in{base_in};
auto out{base_out};
// change quark flavours for W
bool couple_idx{ std::uniform_int_distribution<int>{0,1}(ran) };
if(!couple_quark(boson, couple_idx?out[fkl_pos]:out[uno_pos]))
continue;
out.insert(out.begin()+pos, boson);
if(!match_expectation(expectation, in, out))
return false;
}
}
}
}
// test allowed jet configurations
if(!(match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -1)
&& match_expectation(b,{uno,fkl},{"g",uno,"g","g","g","g",fkl}, -2)
&& match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -3)
&& match_expectation(b,{uno,fkl},{"g",uno,"g","g","g","g",fkl}, -4)
&& match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -5)
&& match_expectation(b,{uno,fkl},{"g",uno,"g","g","g","g",fkl}, -5)
&& match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -6)
&& match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -7)
&& match_expectation(b,{uno,fkl},{"g",uno,"g","g","g","g",fkl}, -7)
&& match_expectation(f,{fkl,uno},{fkl,"g","g","g","g",uno,"g"}, -8)
&& match_expectation(b,{uno,fkl},{"g",uno,"g","g","g","g",fkl}, -8)
))
return false;
}
return true;
}
bool check_extremal_qqx(){
using namespace HEJ;
auto const b{ event_type::qqxexb };
auto const f{ event_type::qqxexf };
for(std::string const & qqx: all_quarks) // all quark flavours
for(std::string const & fkl: all_partons){
std::string const qqx2{ std::to_string(HEJ::to_ParticleID(qqx)*-1) };
for(int njet=3; njet<=6; ++njet){ // all multiplicities >2
if(njet==5) continue;
for(int i=0; i<2; ++i){ // forward & backwards
std::array<std::string,2> base_in;
std::vector<std::string> base_out(njet, "g");
const int qqx_pos = i?0:(njet-2);
const int fkl_pos = i?(njet-1):0;
base_in[i?0:1] = "g";
base_in[i?1:0] = fkl;
base_out[fkl_pos] = fkl;
base_out[qqx_pos] = qqx;
base_out[qqx_pos+1] = qqx2;
auto expectation{ i?b:f };
if( !match_expectation(expectation, base_in, base_out) )
return false;
for(auto const & boson: all_bosons){ // any boson
// at any position (higgs only inside FKL chain)
int start = 0;
int end = njet;
if(to_ParticleID(boson) == pid::higgs){
start = i?(qqx_pos+2):fkl_pos;
end = i?(fkl_pos+1):qqx_pos;
}
for(int pos=start; pos<=end; ++pos){
auto in{base_in};
auto out{base_out};
// change quark flavours for W
bool couple_idx{ std::uniform_int_distribution<int>{0,1}(ran) };
if(couple_idx || !couple_quark(boson, out[fkl_pos]) ){
// (randomly) try couple to FKL, else fall-back to qqx
if(!couple_quark(boson, out[qqx_pos]))
couple_quark(boson, out[qqx_pos+1]);
}
out.insert(out.begin()+pos, boson);
if(!match_expectation(expectation, in, out))
return false;
}
}
}
}
// test allowed jet configurations
if(!(match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -1)
&& match_expectation(b,{"g",fkl},{qqx,qqx2,"g","g","g","g",fkl}, -2)
&& match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -3)
&& match_expectation(b,{"g",fkl},{qqx,qqx2,"g","g","g","g",fkl}, -4)
&& match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -5)
&& match_expectation(b,{"g",fkl},{qqx,qqx2,"g","g","g","g",fkl}, -5)
&& match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -6)
&& match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -7)
&& match_expectation(b,{"g",fkl},{qqx,qqx2,"g","g","g","g",fkl}, -7)
&& match_expectation(f,{fkl,"g"},{fkl,"g","g","g","g",qqx,qqx2}, -8)
&& match_expectation(b,{"g",fkl},{qqx,qqx2,"g","g","g","g",fkl}, -8)
))
return false;
}
return true;
}
bool check_central_qqx(){
using namespace HEJ;
auto const t{ event_type::qqxmid };
for(std::string const & qqx: all_quarks) // all quark flavours
for(std::string const & fkl1: all_partons)
for(std::string const & fkl2: all_partons){
std::string const qqx2{ std::to_string(HEJ::to_ParticleID(qqx)*-1) };
for(int njet=4; njet<=6; ++njet){ // all multiplicities >3
if(njet==5) continue;
for(int qqx_pos=1; qqx_pos<njet-2; ++qqx_pos){ // any qqx position
std::array<std::string,2> base_in;
std::vector<std::string> base_out(njet, "g");
base_in[0] = fkl1;
base_in[1] = fkl2;
base_out.front() = fkl1;
base_out.back() = fkl2;
base_out[qqx_pos] = qqx;
base_out[qqx_pos+1] = qqx2;
if( !match_expectation(t, base_in, base_out) )
return false;
for(auto const & boson: all_bosons) // any boson
for(int pos=0; pos<=njet; ++pos){ // at any position
if( to_ParticleID(boson) == pid::higgs
&& (pos==qqx_pos || pos==qqx_pos+1) )
continue;
auto in{base_in};
auto out{base_out};
// change quark flavours for W
int couple_idx{ std::uniform_int_distribution<int>{0,2}(ran) };
// (randomly) try couple to FKL, else fall-back to qqx
if( couple_idx == 0 && couple_quark(boson, out.front()) ){}
else if( couple_idx == 1 && couple_quark(boson, out.back()) ){}
else {
if(!couple_quark(boson, out[qqx_pos]))
couple_quark(boson, out[qqx_pos+1]);
}
out.insert(out.begin()+pos, boson);
if(!match_expectation(t, in, out))
return false;
}
}
}
// test allowed jet configurations (non exhaustive collection)
if(!(match_expectation(t,{fkl1,fkl2},{fkl1,qqx,qqx2,"g","g","g",fkl2}, -1)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g",qqx,qqx2,"g",fkl2}, -2)
&& match_expectation(t,{fkl1,fkl2},{fkl1,qqx,qqx2,"g","g","g",fkl2}, -3)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g",qqx,qqx2,"g","g",fkl2}, -3)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g","g",qqx,qqx2,fkl2}, -4)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g",qqx,qqx2,"g",fkl2}, -4)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g","g",qqx,qqx2,fkl2}, -5)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g",qqx,qqx2,"g","g",fkl2}, -6)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g",qqx,qqx2,"g",fkl2}, -6)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g",qqx,qqx2,"g","g",fkl2}, -7)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g","g",qqx,qqx2,fkl2}, -7)
&& match_expectation(t,{fkl1,fkl2},{fkl1,qqx,qqx2,"g","g","g",fkl2}, -8)
&& match_expectation(t,{fkl1,fkl2},{fkl1,"g","g","g",qqx,qqx2,fkl2}, -8)
))
return false;
}
return true;
}
// this checks a (non excessive) list of Non-HEJ states
bool check_non_resummable(){
- auto type{ HEJ::event_type::FixedOrder};
+ auto type{ HEJ::event_type::non_resummable};
return
// 2j - crossing lines
match_expectation(type, {"g","2"}, {"2","g"})
&& match_expectation(type, {"-1","g"}, {"g","-1"})
&& match_expectation(type, {"1","-1"}, {"-1","1"})
&& match_expectation(type, {"g","2"}, {"2","g","h"})
&& match_expectation(type, {"1","2"}, {"2","h","1"})
&& match_expectation(type, {"1","-1"}, {"h","-1","1"})
&& match_expectation(type, {"g","2"}, {"Wp","1","g"})
&& match_expectation(type, {"1","-1"}, {"-2","Wp","1"})
&& match_expectation(type, {"4","g"}, {"g","3","Wp"})
&& match_expectation(type, {"1","-2"}, {"-1","Wm","1"})
&& match_expectation(type, {"g","3"}, {"4","g","Wm"})
&& match_expectation(type, {"1","3"}, {"Wm","4","1"})
// 2j - qqx
&& match_expectation(type, {"g","g"}, {"1","-1"})
&& match_expectation(type, {"g","g"}, {"-2","2","h"})
&& match_expectation(type, {"g","g"}, {"-4","Wp","3"})
&& match_expectation(type, {"g","g"}, {"Wm","-1","2"})
// 3j - crossing lines
&& match_expectation(type, {"g","4"}, {"4","g","g"})
&& match_expectation(type, {"-1","g"}, {"g","g","-1"})
&& match_expectation(type, {"1","3"}, {"3","g","1"})
&& match_expectation(type, {"-2","2"}, {"2","g","-2","h"})
&& match_expectation(type, {"-3","g"}, {"g","g","Wp","-4"})
&& match_expectation(type, {"1","-2"}, {"Wm","-1","g","1"})
&& match_expectation(type, {"-1","g"}, {"1","-1","-1"})
// higgs inside uno
&& match_expectation(type, {"-1","g"}, {"g","h","-1","g"})
&& match_expectation(type, {"-1","1"}, {"g","h","-1","1"})
&& match_expectation(type, {"g","2"}, {"g","2","h","g"})
&& match_expectation(type, {"-1","1"}, {"-1","1","h","g"})
// higgs outside uno
&& match_expectation(type, {"-1","g"}, {"h","g","-1","g"})
&& match_expectation(type, {"-1","1"}, {"-1","1","g","h"})
// higgs inside qqx
&& match_expectation(type, {"g","g"}, {"-1","h","1","g","g"})
&& match_expectation(type, {"g","g"}, {"g","-1","h","1","g"})
&& match_expectation(type, {"g","g"}, {"g","g","2","h","-2"})
// higgs outside qqx
&& match_expectation(type, {"g","g"}, {"h","-1","1","g","g"})
&& match_expectation(type, {"g","g"}, {"g","g","2","-2","h"})
// 4j - two uno
&& match_expectation(type, {"-2","2"}, {"g","-2","2","g"})
&& match_expectation(type, {"1","3"}, {"g","1","h","3","g"})
&& match_expectation(type, {"1","2"}, {"g","1","3","Wp","g"})
&& match_expectation(type, {"1","-2"}, {"g","Wm","1","-1","g"})
// 4j - two gluon outside
&& match_expectation(type, {"g","4"}, {"g","4","g","g"})
&& match_expectation(type, {"1","3"}, {"1","3","h","g","g"})
&& match_expectation(type, {"1","2"}, {"1","3","g","Wp","g"})
&& match_expectation(type, {"1","-2"}, {"1","Wm","-1","g","g"})
&& match_expectation(type, {"-1","g"}, {"g","g","-1","g"})
&& match_expectation(type, {"1","3"}, {"g","g","1","3","h"})
&& match_expectation(type, {"1","2"}, {"g","g","1","Wp","3"})
&& match_expectation(type, {"1","-2"}, {"Wm","g","g","1","-1"})
// 4j - ggx+uno
&& match_expectation(type, {"g","4"}, {"1","-1","4","g"})
&& match_expectation(type, {"2","g"}, {"g","2","-3","3"})
&& match_expectation(type, {"g","4"}, {"1","-1","h","4","g"})
&& match_expectation(type, {"2","g"}, {"g","2","-3","3","h"})
&& match_expectation(type, {"g","4"}, {"Wp","1","-1","3","g"})
&& match_expectation(type, {"2","g"}, {"g","2","-4","Wp","3"})
&& match_expectation(type, {"g","4"}, {"2","Wm","-1","4","g"})
&& match_expectation(type, {"2","g"}, {"g","2","Wp","-3","4"})
// 3j - crossing+uno
&& match_expectation(type, {"1","4"}, {"g","4","1"})
&& match_expectation(type, {"1","4"}, {"4","1","g"})
&& match_expectation(type, {"1","4"}, {"g","h","4","1"})
&& match_expectation(type, {"-1","-3"},{"Wm","g","-4","-1"})
&& match_expectation(type, {"1","4"}, {"3","1","Wp","g"})
&& match_expectation(type, {"1","4"}, {"3","1","g","h"})
// 3j - crossing+qqx
&& match_expectation(type, {"1","g"}, {"-1","1","g","1"})
&& match_expectation(type, {"1","g"}, {"-1","1","1","g"})
&& match_expectation(type, {"g","1"}, {"1","g","1","-1"})
&& match_expectation(type, {"g","1"}, {"g","1","1","-1"})
&& match_expectation(type, {"1","g"}, {"2","-2","g","1"})
&& match_expectation(type, {"1","g"}, {"2","-2","1","g"})
&& match_expectation(type, {"g","1"}, {"1","g","-2","2"})
&& match_expectation(type, {"g","1"}, {"g","1","-2","2"})
&& match_expectation(type, {"1","g"}, {"-1","1","h","g","1"})
&& match_expectation(type, {"1","g"}, {"-1","h","1","1","g"})
&& match_expectation(type, {"g","1"}, {"1","g","1","h","-1"})
&& match_expectation(type, {"g","1"}, {"h","g","1","1","-1"})
&& match_expectation(type, {"1","g"}, {"2","-2","1","g","h"})
&& match_expectation(type, {"g","1"}, {"g","h","1","-2","2"})
&& match_expectation(type, {"1","g"}, {"Wp","3","-4","g","1"})
&& match_expectation(type, {"3","g"}, {"-2","Wm","1","3","g"})
&& match_expectation(type, {"g","1"}, {"1","g","Wm","-3","4"})
&& match_expectation(type, {"g","-3"}, {"g","-3","-1","Wp","2"})
// 4j- gluon in qqx
&& match_expectation(type, {"g","1"}, {"1","g","-1","1"})
&& match_expectation(type, {"1","g"}, {"1","-1","g","1"})
&& match_expectation(type, {"g","1"}, {"1","g","Wm","-2","1"})
&& match_expectation(type, {"2","g"}, {"2","-2","g","Wp","1"})
&& match_expectation(type, {"g","g"}, {"Wp","3","g","-4","g"})
&& match_expectation(type, {"1","g"}, {"1","h","-1","g","1"})
// 6j - two qqx
&& match_expectation(type, {"g","g"}, {"1","-1","g","g","1","-1"})
&& match_expectation(type, {"g","g"}, {"1","-1","g","1","-1","g"})
&& match_expectation(type, {"g","g"}, {"g","1","-1","g","1","-1"})
&& match_expectation(type, {"g","g"}, {"g","1","-1","1","-1","g"})
&& match_expectation(type, {"g","g"}, {"g","1","1","-1","-1","g"})
&& match_expectation(type, {"g","g"}, {"h","1","-1","g","g","1","-1"})
&& match_expectation(type, {"g","g"}, {"1","Wp","-2","g","1","-1","g"})
&& match_expectation(type, {"g","g"}, {"g","1","Wp","-1","g","1","-2"})
&& match_expectation(type, {"g","g"}, {"g","1","-1","Wm","2","-1","g"})
&& match_expectation(type, {"g","g"}, {"g","1","2","-1","Wm","-1","g"})
// random stuff (can be non-physical)
&& match_expectation(type, {"g","g"}, {"1","-2","2","-1"}) // != 2 qqx
&& match_expectation(type, {"g","g"}, {"1","-2","2","g"}) // could be qqx
&& match_expectation(type, {"e+","e-"},{"1","-1"}) // bad initial state
&& match_expectation(type, {"1","e-"}, {"g","1","Wm"}) // bad initial state
&& match_expectation(type, {"h","g"}, {"g","g"}) // bad initial state
&& match_expectation(type, {"-1","g"}, {"-1","1","1"}) // bad qqx
&& match_expectation(type, {"-1","g"}, {"1","1","-1"}) // crossing in bad qqx
&& match_expectation(type, {"-1","g"}, {"-2","1","1","Wp"}) // bad qqx
&& match_expectation(type, {"1","2"}, {"1","-1","g","g","g","2"}) // bad qqx
&& match_expectation(type, {"1","2"}, {"1","-1","-2","g","g","2"}) // gluon in bad qqx
&& match_expectation(type, {"g","g"}, {"-1","2","g","g"}) // wrong back qqx
&& match_expectation(type, {"g","g"}, {"g","g","2","1"}) // wrong forward qqx
&& match_expectation(type, {"g","g"}, {"g","-2","1","g"}) // wrong central qqx
;
}
// Events failing the jet requirements, e.g. qqx inside one jet
//! @FIXME they are currently allowed
bool check_illegal_jets(){
- auto type{ HEJ::event_type::FixedOrder};
+ auto type{ HEJ::event_type::non_resummable};
return true
// uno backward not in jet
&& match_expectation(type, {"1","g"}, {"g","1","g","g","g","g","g"}, -1)
// & also legal uno on other side
&& match_expectation(type, {"1","1"}, {"g","1","g","g","g","1","g"}, -1)
// qqx backward not in jet
&& match_expectation(type, {"g","2"}, {"-1","1","g","g","g","g","2"}, -1)
// uno forward not in jet
&& match_expectation(type, {"3","3"}, {"3","g","g","g","g","3","g"}, -2)
// qqx backward not in jet
&& match_expectation(type, {"g","g"}, {"g","g","g","g","g","-2","2"}, -2)
// uno backward in same jet
&& match_expectation(type, {"1","g"}, {"g","1","g","g","g","g","g"}, -3)
// & also legal uno on other side
&& match_expectation(type, {"1","1"}, {"g","1","g","g","g","1","g"}, -3)
// qqx backward in same jet
&& match_expectation(type, {"g","2"}, {"-4","4","g","g","g","g","2"}, -3)
// uno forward in same jet
&& match_expectation(type, {"3","2"}, {"3","g","g","g","g","2","g"}, -4)
// qqx backward in same jet
&& match_expectation(type, {"g","g"}, {"g","g","g","g","g","-2","2"}, -4)
// central qqx not in jet
&& match_expectation(type, {"1","2"}, {"1","g","-1","1","g","g","2"}, -5)
// central qqx in same jet
&& match_expectation(type, {"1","2"}, {"1","-1","1","g","g","g","2"}, -6)
// central qqx in same jet
&& match_expectation(type, {"1","2"}, {"1","g","g","g","2","-2","2"}, -6)
// central qqx in same jet
&& match_expectation(type, {"1","2"}, {"1","-1","1","g","g","g","2"}, -7)
// central qqx in same jet
&& match_expectation(type, {"1","2"}, {"1","g","g","3","-3","g","2"}, -7)
// central qqx in same jet
&& match_expectation(type, {"g","3"}, {"g","g","-2","2","g","g","3"}, -8)
// central qqx in same jet
&& match_expectation(type, {"g","-2"}, {"g","g","g","2","-2","g","-2"}, -8)
;
}
// Two boson states, that are currently not implemented
bool check_bad_FS(){
auto type{ HEJ::event_type::bad_final_state};
return
match_expectation(type, {"g","g"}, {"g","h","h","g"})
&& match_expectation(type, {"g","g"}, {"h","g","h","g"})
&& match_expectation(type, {"g","-1"}, {"g","h","Wp","-2"})
&& match_expectation(type, {"-3","-1"},{"-4","g","Wp","Wp","-2"})
&& match_expectation(type, {"-4","-1"},{"-3","Wp","g","Wm","-2"})
&& match_expectation(type, {"-4","-1"},{"g","-3","Wp","Wm","-2"})
;
}
}
int main() {
// tests for "no false negatives"
// i.e. all HEJ-configurations get classified correctly
if(!check_fkl()) return EXIT_FAILURE;
if(!check_uno()) return EXIT_FAILURE;
if(!check_extremal_qqx()) return EXIT_FAILURE;
if(!check_central_qqx()) return EXIT_FAILURE;
// test for "no false positive"
// i.e. non-resummable gives non-resummable
if(!check_non_resummable()) return EXIT_FAILURE;
if(!check_illegal_jets()) return EXIT_FAILURE;
if(!check_bad_FS()) return EXIT_FAILURE;
//! @TODO missing:
//! checks for partons sharing a jet
return EXIT_SUCCESS;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Nov 19, 4:15 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3795312
Default Alt Text
(101 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment