Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F7879132
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
37 KB
Subscribers
None
View Options
diff --git a/src/Event.cc b/src/Event.cc
index 9a7561d..2bc52a3 100644
--- a/src/Event.cc
+++ b/src/Event.cc
@@ -1,946 +1,946 @@
/**
* \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>
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 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;
}
#if oldcode
/**
* \brief Checks whether event is unordered.
* @returns Is Event Unordered (default back, reverse input for forwards)
*
* - 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
* - Checks currents at both ends of FKL chain logical to process.
*/
template<class InIterator, class OutIterator, class JetIterator, class IndIterator>
bool is_unordered(
InIterator begin_in, InIterator end_in,
OutIterator begin_out, OutIterator end_out,
JetIterator begin_jets, JetIterator end_jets,
IndIterator begin_indices
){
if(std::distance(begin_out, (end_out)) < 3) return false;
if(std::distance(begin_jets, (end_jets)) < 3) return false;
if((begin_in[0]).type == pid::gluon) return false;
if(((begin_out)->type)==pid::Higgs) return false;
int bosonBegin = (is_AWZ_boson(begin_out->type))?1:0;
int bosonSecond = (is_AWZ_boson((begin_out+bosonBegin+1)->type))?1+bosonBegin:bosonBegin;
if((begin_out+bosonBegin)->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.
if(((begin_out+1)->type)==pid::Higgs) return false;
if(!is_FKL({begin_in[0], (end_in-1)[0]}, {(begin_out+bosonSecond+1), end_out})) return false;
// check that the unordered gluon forms an extra jet
if(!(begin_indices[0] >= 0 && (begin_indices+1)[0] == -1)) return false;
const auto W = std::find_if(
begin_out, end_out,
[](Particle const & s){ return abs(s.type) == pid::Wp; }
);
- int BosonEnd = (HEJ::is_AWZH_boson((end_out-1)->type))?1:0;
+ int BosonEnd = (is_AWZH_boson((end_out-1)->type))?1:0;
if (W != end_out){
// Must have a valid W Current
return ((no_flavour_change(begin_in->type, (begin_out+bosonSecond+1)->type, false)
&& is_W_Current((end_in-1)->type, (end_out-1-BosonEnd)->type, W->type, false))
||( is_W_Current(begin_in->type, (begin_out+bosonSecond+1)->type, W->type, false)
&& no_flavour_change((end_in-1)->type, (end_out-1-BosonEnd)->type, false)));
}
return ( no_flavour_change(begin_in->type, (begin_out+bosonSecond+1)->type, false)
&& no_flavour_change((end_in-1)->type, (end_out-1-BosonEnd)->type, false));
}
#endif
#if oldcode
/**
* \brief Checks for an extremal qqx (forwards, reverse input for back)
* @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 remaining chain is pure gluon
* 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.
* Checks other current logically consistent (with/out W emission.)
*/
template<class InIterator, class OutIterator, class JetIterator, class IndIterator>
bool is_Ex_qqx(
InIterator begin_in, InIterator end_in,
OutIterator begin_out, OutIterator end_out,
JetIterator begin_jets, JetIterator end_jets,
IndIterator back_qqx_indice, IndIterator forward_qqx_indice
){
int fkl_start=is_AWZ_boson(begin_out->type);
int fkl_end=0;
int qBosonqx=0;
if(std::distance(begin_out, (end_out)) < 3) return false;
if(std::distance(begin_jets, (end_jets)) < 3) return false;
if((end_in-1)->type != pid::gluon) return false;
if((end_out-1)->type == pid::Higgs || begin_out->type == pid::Higgs
|| (end_out-2)->type == pid::Higgs) return false;
if(is_AWZ_boson((end_out-1)->type)){ // if extremal AWZ
++fkl_end;
if (is_quark((end_out-2)->type)){ //if second quark
if (!(is_antiquark((end_out-3)->type))) return false;// third must be anti-quark
}
else if (is_antiquark((end_out-2)->type)){ //if second anti-quark
if (!(is_quark((end_out-3)->type))) return false;// third must be quark
}
else return false;
}
else if (is_quark((end_out-1)->type)){ //if extremal quark
if(is_AWZ_boson((end_out-2)->type)){ // if second AWZ
++qBosonqx;
if (!(is_antiquark((end_out-3)->type))) return false;// third must be anti-quark
}
else if (!(is_antiquark((end_out-2)->type))) return false;// second must be anti-quark
}
else if (is_antiquark((end_out-1)->type)){ //if extremal anti-quark
if(is_AWZ_boson((end_out-2)->type)){ // if second AWZ
++qBosonqx;
if (!(is_quark((end_out-3)->type))) return false;// third must be quark
}
else if (!(is_quark((end_out-2)->type))) return false;// second must be quark
}
else return false;
// no other quark emission (first doesn't matter)
if(std::any_of(
begin_out+1+fkl_start, end_out-3-fkl_end-qBosonqx,
[](Particle const & p){ return is_anyquark(p); })
) return false;
// Ensure qqbar pair are in jets
if((back_qqx_indice)[0] != 0 || (forward_qqx_indice)[1] != 0){
return false;
}
const auto W = std::find_if(
begin_out, end_out,
[](Particle const & s){ return abs(s.type) == pid::Wp; }
);
if (W != end_out){
// Must have a valid W Current
return ((no_flavour_change(begin_in->type, (begin_out+fkl_start)->type, false)
&& is_W_Current((end_out-1-fkl_end)->type, (end_out-2-fkl_end-qBosonqx)->type, W->type, true))
||( is_W_Current(begin_in->type, (begin_out+fkl_start)->type, W->type, false)
&& no_flavour_change((end_out-1-fkl_end)->type, (end_out-2-fkl_end-qBosonqx)->type, true)));
}
return ( no_flavour_change(begin_in->type, (begin_out+fkl_start)->type, false)
&& no_flavour_change((end_out-1-fkl_end)->type, (end_out-2-fkl_end-qBosonqx)->type, true));
}
#endif
#if oldcode
/**
* \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)
* Check that other partons are only gluons in chain
* 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;
const auto WEmit = std::find_if(
begin(out), end(out),
[](Particle const & s){ return abs(s.type) == pid::Wp; }
);
const auto & jets = ev.jets();
const auto indices = ev.particle_jet_indices({jets});
auto const out_partons = filter_partons(out);
- HEJ::ParticleID backQuark = HEJ::pid::gluon;
- HEJ::ParticleID forwardQuark = HEJ::pid::gluon;
+ ParticleID backQuark = pid::gluon;
+ ParticleID forwardQuark = pid::gluon;
// search for qqx pair
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])))
){
// no quarks before qqx (beside first)
if(std::any_of(
out_partons.cbegin()+1, out_partons.cbegin()+i,
[](Particle const & p){ return is_anyquark(p); })
) return false;
// no quarks after qqx (beside last)
if(std::any_of(
out_partons.cbegin()+i+2, out_partons.cend()-1,
[](Particle const & p){ return is_anyquark(p); })
) return false;
// should be in seperate jets
if (indices[i+1] == indices[i]+1 && indices[i] != -1){
backQuark = out_partons[i].type;
forwardQuark = out_partons[i+1].type;
break;}
}
}
if (backQuark == forwardQuark) return false;
if (WEmit != end(out)){
//One W Current Must Exist.
if ( is_W_Current(in.back().type,out.rbegin()[end_FKL].type, WEmit->type, false)
&& no_flavour_change(backQuark, forwardQuark, true)
&& no_flavour_change(in.front().type,out[start_FKL].type, false)){
//Backwards Current is W, Nothing to do
}
else if ( no_flavour_change(in.back().type,out.rbegin()[end_FKL].type, false)
&& no_flavour_change(backQuark, forwardQuark, true)
&& is_W_Current(in.front().type,out[start_FKL].type, WEmit->type, false)){
//Forwards Current is W, Nothing to do
}
else if ( !( no_flavour_change(in.back().type,out.rbegin()[end_FKL].type, false)
&& is_W_Current(backQuark, forwardQuark, WEmit->type, true)
&& no_flavour_change(in.front().type,out[start_FKL].type, false))){
//No W-coupled fermion line, with W present.
return false;
}
}
else{
//Can only be Pure Currents.
return ( no_flavour_change(in.back().type,out.rbegin()[end_FKL].type, false)
&& no_flavour_change(backQuark, forwardQuark, true)
&& no_flavour_change(in.front().type,out[start_FKL].type, false));
}
return true;
}
#endif
//! check if we have a valid Impact factor
- bool is_Valid_IF(HEJ::ParticleID in, HEJ::ParticleID out, bool qqx,
+ bool is_Valid_IF(ParticleID in, ParticleID out, bool qqx,
bool &PureIF, bool &WpIF, bool &WmIF
){
if (no_flavour_change(in, out, qqx)) PureIF=true;
else if (is_Wp_Change(in, out, qqx)) WpIF=true;
else if (is_Wm_Change(in, out, qqx)) WmIF=true;
else return false;
return true;
}
/**
* \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;
bool IFfuno(false),IFfgqq(false), IFfLL(false),
IFbuno(false), IFbgqq(false), IFbLL(false);
bool IFfunoWp(false),IFfgqqWp(false), IFfLLWp(false),
IFbunoWp(false), IFbgqqWp(false), IFbLLWp(false);
bool IFfunoWm(false),IFfgqqWm(false), IFfLLWm(false),
IFbunoWm(false), IFbgqqWm(false), IFbLLWm(false);
bool Midqqbar(false), MidqqbarWp(false), MidqqbarWm(false);
// now check event parton by parton
// check first the impact factors at either end, and loop over the middle partons
auto const & in = ev.incoming();
auto const & out = filter_partons(ev.outgoing());
auto outN=out.size();
assert(std::distance(begin(in), end(in)) == 2);
assert(outN >= 2);
assert(std::distance(begin(out), end(out)) >= 2);
assert(std::is_sorted(begin(out), end(out), rapidity_less{}));
double ymid1(-10.),ymid2(-10.);
auto thispartonN = out.begin();
// Is this backwards LL current?
if(is_Valid_IF(in.front().type, thispartonN->type,
false, IFbLL, IFbLLWp, IFbLLWm)){
++thispartonN;
}
else if (outN>=3) {
if ((in.front().type!=pid::gluon)&&thispartonN->type==pid::gluon) {
// Is this backwards unordered emisson?
if(is_Valid_IF(in.front().type, (thispartonN+1)->type,
false, IFbuno, IFbunoWp, IFbunoWm)){
thispartonN+=2;
}
}
else if (in.front().type==pid::gluon) {
// Is this backwards QQbar?
if(is_Valid_IF((thispartonN)->type, (thispartonN+1)->type,
true, IFbgqq, IFbgqqWp, IFbgqqWm)){
thispartonN+=2;
}
}
}
// if we reached this far and thisparton==begin(out)
// then it is not a valid all-order state
if (thispartonN==begin(out)) return EventType::FixedOrder;
// else check forward particles.
// Need to ensure the same particles don't count for both sub-leading
// impact factors
auto thispartonfN = (out.end()-1);
// Is this a forward LL current?
if(is_Valid_IF(in.back().type, thispartonfN->type,
false, IFfLL, IFfLLWp, IFfLLWm)){
--thispartonfN;
}
else if (outN>=3&&(thispartonfN-1!=(thispartonN-1))) { // if the prevparton is not
// the last parton included in backward IF
// Possibility of unordered gluon emission or gluon splitting
// unless we already used up all the partons
if ((in.back().type!=pid::gluon)&&thispartonfN->type==pid::gluon) {
// Is this forwards Uno?
if(is_Valid_IF(in.back().type, (thispartonfN-1)->type,
false, IFfuno, IFfunoWp, IFfunoWm)){
thispartonfN-=2;
}
}
else if (in.back().type==pid::gluon) {
// Is this forwards QQbar?
if(is_Valid_IF((thispartonfN)->type, (thispartonfN-1)->type,
true, IFfgqq, IFfgqqWp, IFfgqqWm)){
thispartonfN-=2;
}
}
} //impact factors done
// if we reached this far and thispartonf==end(out),
// then it is not a valid all-order state
if (thispartonfN==end(out)-1) return EventType::FixedOrder;
// Now check the remaining middle partons
// the first (in rapidity) parton in the forward impact factor
// allow only one qqbar(+Wp/Wm) insertion
while (((thispartonN)->type==pid::gluon)&&(thispartonN!=(thispartonfN+1))) {
++thispartonN;
}
if (thispartonN!=(thispartonfN+1)) {
// is this a qqbar-pair?
if(is_Valid_IF(thispartonN->type, (thispartonN+1)->type,
true, Midqqbar, MidqqbarWp, MidqqbarWm)){
ymid1=thispartonN->p.rapidity();
ymid2=(thispartonN+1)->p.rapidity();
thispartonN+=2;
}
//continue checking
while ((thispartonN->type==pid::gluon)&&(thispartonN!=(thispartonfN+1))) {
++thispartonN;
}
}
// are we at the end of the partons? if not, this is not resummable
if (thispartonN!=(thispartonfN+1)) return EventType::FixedOrder;
// Checks using the non-partonic momenta
auto const boson=filter_AWZH_bosons(ev.outgoing());
int WpN(0),WmN(0),HN(0),ZN(0);
if(boson.size()>0){ // if some bosons were found
// count number of W+, W-, H, Z/gamma
for (auto bitr=boson.begin(); bitr!=boson.end(); ++bitr) {
if (bitr->type==24) ++WpN;
else if (bitr->type==-24) ++WmN;
else if (bitr->type==25) ++HN;
else if (bitr->type==23) ++ZN;
}
}
// veto Higgs+uno/split with Higgs rapidity inside qqx or uno
// veto Higgs between central qqbar pair
if (HN==1) {
for (auto bitr=boson.begin(); bitr!=boson.end(); ++bitr) {
if (bitr->type==25) {
const double yH=bitr->p.rapidity();
if (IFbuno||IFbgqq) {
// check if the Higgs is in the FKL chain for forward uno
if ((yH<out.at(1).p.rapidity()))
return EventType::FixedOrder;
} if (IFfuno||IFfgqq) {
// check if the Higgs is in the FKL chain for backward uno
if ((yH>out.at(outN-2).p.rapidity()))
return EventType::FixedOrder;
} if (Midqqbar) {
if ((ymid1<yH)&&(yH<ymid2))
return EventType::FixedOrder;
}
}
}
}
// Check whether the right number of Ws are present
// count the numbers of Wp Wm required by the identification of partons in the events
int NWpR=IFbLLWp+IFfLLWp+MidqqbarWp+IFbunoWp+IFfunoWp+IFbgqqWp+IFfgqqWp;
int NWmR=IFbLLWm+IFfLLWm+MidqqbarWm+IFbunoWm+IFfunoWm+IFbgqqWm+IFfgqqWm;
if (NWpR!=WpN) return EventType::FixedOrder;
if (NWmR!=WmN) return EventType::FixedOrder;
if (WmN>1||WpN>1||HN>1||ZN>1) return EventType::FixedOrder;
// return the event type
if (!(Midqqbar||MidqqbarWm||MidqqbarWp)) { // if there are no mid qqbar
if ((IFbLL||IFbLLWm||IFbLLWp)&&IFfLL) return EventType::FKL;
if ((IFfLLWm||IFfLLWp)&&IFbLL) return EventType::FKL;
if ((IFbuno||IFbunoWm||IFbunoWp)&&IFfLL) return EventType::unordered_backward;
if ((IFbuno)&&(IFfLLWp||IFfLLWm)) return EventType::unordered_backward;
if ((IFfuno||IFfunoWm||IFfunoWp)&&IFbLL) return EventType::unordered_forward;
if ((IFfuno)&&(IFbLLWp||IFbLLWm)) return EventType::unordered_forward;
if ((IFbgqq||IFbgqqWp||IFbgqqWm)&&IFfLL) return EventType::extremal_qqxb;
if ((IFbgqq)&&(IFfLLWp||IFfLLWm)) return EventType::extremal_qqxb;
if ((IFfgqq||IFfgqqWp||IFfgqqWm)&&IFbLL) return EventType::extremal_qqxf;
if ((IFfgqq)&&(IFbLLWp||IFbLLWm)) return EventType::extremal_qqxf;
} else { // there is a middle qqbar pair
if (IFbLL)
if (IFfLL||IFfLLWp||IFfLLWm) return EventType::central_qqx;
if (IFfLL)
if (IFbLL||IFbLLWp||IFbLLWm) return EventType::central_qqx;
}
return EventType::FixedOrder;
} // classify
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) {
- HEJ::Particle decayed_boson;
+ 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 HEJ::not_implemented{"lepton-flavour violating final state"};
+ throw not_implemented{"lepton-flavour violating final state"};
}
assert(is_neutrino(leptons[1]));
// charged antilepton + neutrino means we had a W+
- decayed_boson.type = HEJ::pid::Wp;
+ decayed_boson.type = pid::Wp;
}
else if(pidsum == -1) {
assert(is_antilepton(leptons[0]));
if(is_neutrino(leptons[1])) {
- throw HEJ::not_implemented{"lepton-flavour violating final state"};
+ throw not_implemented{"lepton-flavour violating final state"};
}
assert(is_antineutrino(leptons[0]));
// charged lepton + antineutrino means we had a W-
- decayed_boson.type = HEJ::pid::Wm;
+ decayed_boson.type = pid::Wm;
}
else {
- throw HEJ::not_implemented{
+ throw not_implemented{
"final state with leptons "
- + HEJ::name(leptons[0].type)
+ + name(leptons[0].type)
+ " and "
- + HEJ::name(leptons[1].type)
+ + name(leptons[1].type)
};
}
return decayed_boson;
}
}
- void HEJ::Event::EventData::reconstruct_intermediate() {
+ void Event::EventData::reconstruct_intermediate() {
const auto begin_leptons = std::partition(
begin(outgoing), end(outgoing),
- [](HEJ::Particle const & p) {return !HEJ::is_anylepton(p);}
+ [](Particle const & p) {return !is_anylepton(p);}
);
if(begin_leptons == end(outgoing)) return;
assert(is_anylepton(*begin_leptons));
- std::vector<HEJ::Particle> leptons(begin_leptons, end(outgoing));
+ std::vector<Particle> leptons(begin_leptons, end(outgoing));
outgoing.erase(begin_leptons, end(outgoing));
if(leptons.size() != 2) {
- throw HEJ::not_implemented{"Final states with one or more than two leptons"};
+ throw not_implemented{"Final states with one or more than two leptons"};
}
std::sort(
begin(leptons), end(leptons),
- [](HEJ::Particle const & p0, HEJ::Particle const & p1) {
+ [](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
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;
}
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;
result.IDPRUP = event.type(); // event type
// the following entries are pretty much meaningless
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;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Nov 19, 7:38 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3789774
Default Alt Text
(37 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment