Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F7879397
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Subscribers
None
View Options
diff --git a/src/Event.cc b/src/Event.cc
index 716a7ee..223ed5a 100644
--- a/src/Event.cc
+++ b/src/Event.cc
@@ -1,775 +1,773 @@
/**
* \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"
#define NPRINT 0
namespace HEJ{
namespace{
constexpr int status_in = -1;
constexpr int status_decayed = 2;
constexpr int status_out = 1;
/// @name helper functions to determine event type
//@{
/**
* \brief check if final state valid for HEJ
*
* check if there is at most one photon, W, H, Z in the final state
* and all the rest are quarks or gluons
*/
bool final_state_ok(std::vector<Particle> const & outgoing){
bool has_AWZH_boson = false;
for(auto const & out: outgoing){
if(is_AWZH_boson(out.type)){
if(has_AWZH_boson) return false;
has_AWZH_boson = true;
}
else if(! is_parton(out.type)) return false;
}
return true;
}
template<class Iterator>
Iterator remove_AWZH(Iterator begin, Iterator end){
return std::remove_if(
begin, end, [](Particle const & p){return is_AWZH_boson(p);}
);
}
template<class Iterator>
bool valid_outgoing(Iterator begin, Iterator end){
return std::distance(begin, end) >= 2
&& std::is_sorted(begin, end, rapidity_less{})
&& std::count_if(
begin, end, [](Particle const & s){return is_AWZH_boson(s);}
) < 2;
}
/**
* \brief function which determines if type change is consistent with Wp emission.
* @param in incoming Particle id
* @param out outgoing Particle id
* @param qqx Current both incoming/both outgoing?
*
* \see is_Wm_Current
*/
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;
}
// @note that this changes the outgoing range!
template<class ConstIterator, class Iterator>
bool is_FKL(
ConstIterator begin_incoming, ConstIterator end_incoming,
Iterator begin_outgoing, Iterator end_outgoing
){
assert(std::distance(begin_incoming, end_incoming) == 2);
assert(std::distance(begin_outgoing, end_outgoing) >= 2);
// One photon, W, H, Z in the final state is allowed.
// Remove it for remaining tests,
end_outgoing = remove_AWZH(begin_outgoing, end_outgoing);
if(std::all_of(
begin_outgoing + 1, end_outgoing - 1,
[](Particle const & p){ return p.type == pid::gluon; })
){
// Test if this is a standard FKL configuration.
if ( no_flavour_change(begin_incoming->type, begin_outgoing->type, false)
&& no_flavour_change((end_incoming-1)->type, (end_outgoing-1)->type, false)){
return true;
}
}
return false;
}
template<class ConstIterator, class Iterator>
bool is_W_FKL(
ConstIterator begin_incoming, ConstIterator end_incoming,
Iterator begin_outgoing, Iterator end_outgoing, ParticleID W
){
assert(std::distance(begin_incoming, end_incoming) == 2);
assert(std::distance(begin_outgoing, end_outgoing) >= 2);
// One photon, W, H, Z in the final state is allowed.
// Remove it for remaining tests,
end_outgoing = remove_AWZH(begin_outgoing, end_outgoing);
if(std::all_of(
begin_outgoing + 1, end_outgoing - 1,
[](Particle const & p){ return p.type == pid::gluon; })
){
// Test if this is a standard FKL configuration.
if( is_W_Current(begin_incoming->type, begin_outgoing->type, W, false)
&& no_flavour_change((end_incoming-1)->type, (end_outgoing-1)->type, false)){
return true;
}
else if( no_flavour_change(begin_incoming->type, begin_outgoing->type, false)
&& is_W_Current((end_incoming-1)->type, (end_outgoing-1)->type, W, false)){
return true;
}
}
return false;
}
bool has_2_jets(Event const & event){
return event.jets().size() >= 2;
}
- namespace{
- bool is_Valid_IF(HEJ::ParticleID in, HEJ::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;
- }
+ bool is_Valid_IF(HEJ::ParticleID in, HEJ::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;
}
- using event_type::EventType;
/**
* \brief Checks for all event types
* @param ev Event
* @returns Event Type
*
*/
- EventType classify(Event const & ev){
+ 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;
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"};
}
assert(is_neutrino(leptons[1]));
// charged antilepton + neutrino means we had a W+
decayed_boson.type = HEJ::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"};
}
assert(is_antineutrino(leptons[0]));
// charged lepton + antineutrino means we had a W-
decayed_boson.type = HEJ::pid::Wm;
}
else {
throw HEJ::not_implemented{
"final state with leptons "
+ HEJ::name(leptons[0].type)
+ " and "
+ HEJ::name(leptons[1].type)
};
}
return decayed_boson;
}
}
void HEJ::Event::EventData::reconstruct_intermediate() {
const auto begin_leptons = std::partition(
begin(outgoing), end(outgoing),
[](HEJ::Particle const & p) {return !HEJ::is_anylepton(p);}
);
if(begin_leptons == end(outgoing)) return;
assert(is_anylepton(*begin_leptons));
std::vector<HEJ::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"};
}
std::sort(
begin(leptons), end(leptons),
[](HEJ::Particle const & p0, HEJ::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, 8:14 PM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3789376
Default Alt Text
(28 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment