Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F8723734
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
174 KB
Subscribers
None
View Options
diff --git a/FixedOrderGen/include/PhaseSpacePoint.hh b/FixedOrderGen/include/PhaseSpacePoint.hh
index d579a56..a090e92 100644
--- a/FixedOrderGen/include/PhaseSpacePoint.hh
+++ b/FixedOrderGen/include/PhaseSpacePoint.hh
@@ -1,149 +1,149 @@
/** \file PhaseSpacePoint.hh
* \brief Contains the PhaseSpacePoint Class
*/
#pragma once
#include <vector>
#include "fastjet/JetDefinition.hh"
#include "RHEJ/utility.hh"
#include "RHEJ/Event.hh"
#include "RHEJ/PDG_codes.hh"
#include "RHEJ/PDF.hh"
#include "RHEJ/RNG.hh"
#include "Status.hh"
#include "HiggsProperties.hh"
namespace HEJFOG{
class Process;
- using RHEJ::Sparticle;
+ using RHEJ::Particle;
//! A point in resummation phase space
class PhaseSpacePoint{
public:
//! Default PhaseSpacePoint Constructor
PhaseSpacePoint() = default;
//! PhaseSpacePoint Constructor
/**
* @param proc The process to generate
* @param jet_def The Jet Definition Used
* @param jetptmin Minimum Jet Transverse Momentum
* @param rapmax Maximum parton rapidity
* @param pdf The pdf set (used for sampling)
* @param uno_chance Chance to turn a potentially unordered
* emission into an actual one
*
* Initially, only FKL phase space points are generated. If the most
* extremal emission in any direction is a quark or anti-quark and the
* next emission is a gluon, uno_chance is the chance to turn this into
* an unordered emission event by swapping the two flavours. At most one
* unordered emission will be generated in this way.
*/
PhaseSpacePoint(
Process const & proc,
fastjet::JetDefinition jet_def,double jetptmin, double rapmax,
RHEJ::PDF & pdf, double E_beam,
double uno_chance,
HiggsProperties const & higgs_properties,
RHEJ::RNG & ran
);
//! Get Weight Function
/**
* @returns Weight of Event
*/
double weight() const{
return weight_;
}
Status status() const{
return status_;
}
//! Get Incoming Function
/**
* @returns Incoming Particles
*/
- std::array<Sparticle, 2> const & incoming() const{
+ std::array<Particle, 2> const & incoming() const{
return incoming_;
}
//! Get Outgoing Function
/**
* @returns Outgoing Particles
*/
- std::vector<Sparticle> const & outgoing() const{
+ std::vector<Particle> const & outgoing() const{
return outgoing_;
}
- std::unordered_map<int, std::vector<Sparticle>> const & decays() const{
+ std::unordered_map<int, std::vector<Particle>> const & decays() const{
return decays_;
}
private:
std::vector<fastjet::PseudoJet> gen_LO_partons(
int count, double ptmin, double ptmax, double rapmax,
RHEJ::RNG & ran
);
- Sparticle gen_boson(
+ Particle gen_boson(
RHEJ::ParticleID bosonid, double mass, double width,
RHEJ::RNG & ran
);
bool jets_ok(
std::vector<fastjet::PseudoJet> const & Born_jets,
std::vector<fastjet::PseudoJet> const & partons
) const;
void reconstruct_incoming(
std::array<RHEJ::ParticleID, 2> const & ids,
RHEJ::PDF & pdf, double E_beam,
RHEJ::RNG & ran
);
RHEJ::ParticleID generate_incoming_id(
double x, double uf, RHEJ::PDF & pdf,
RHEJ::RNG & ran
);
bool momentum_conserved(double ep) const;
- RHEJ::Sparticle const & most_backward_FKL(
- std::vector<RHEJ::Sparticle> const & partons
+ RHEJ::Particle const & most_backward_FKL(
+ std::vector<RHEJ::Particle> const & partons
) const;
- RHEJ::Sparticle const & most_forward_FKL(
- std::vector<RHEJ::Sparticle> const & partons
+ RHEJ::Particle const & most_forward_FKL(
+ std::vector<RHEJ::Particle> const & partons
) const;
- RHEJ::Sparticle & most_backward_FKL(std::vector<RHEJ::Sparticle> & partons) const;
- RHEJ::Sparticle & most_forward_FKL(std::vector<RHEJ::Sparticle> & partons) const;
+ RHEJ::Particle & most_backward_FKL(std::vector<RHEJ::Particle> & partons) const;
+ RHEJ::Particle & most_forward_FKL(std::vector<RHEJ::Particle> & partons) const;
bool extremal_FKL_ok(
std::vector<fastjet::PseudoJet> const & partons
) const;
double random_normal(double stddev, RHEJ::RNG & ran);
void maybe_turn_to_uno(double chance, RHEJ::RNG & ran);
- std::vector<Sparticle> decay_boson(
- RHEJ::Sparticle const & parent,
+ std::vector<Particle> decay_boson(
+ RHEJ::Particle const & parent,
std::vector<Decay> const & decays,
RHEJ::RNG & ran
);
Decay select_decay_channel(
std::vector<Decay> const & decays,
RHEJ::RNG & ran
);
double weight_;
Status status_;
double jetptmin_;
fastjet::JetDefinition jet_def_;
- std::array<Sparticle, 2> incoming_;
- std::vector<Sparticle> outgoing_;
+ std::array<Particle, 2> incoming_;
+ std::vector<Particle> outgoing_;
//! Particle decays in the format {outgoing index, decay products}
- std::unordered_map<int, std::vector<Sparticle>> decays_;
+ std::unordered_map<int, std::vector<Particle>> decays_;
};
RHEJ::UnclusteredEvent to_UnclusteredEvent(PhaseSpacePoint const & psp);
}
diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc
index ad19a47..6080e6b 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,420 +1,420 @@
#include "PhaseSpacePoint.hh"
#include <random>
#include "RHEJ/kinematics.hh"
#include "RHEJ/utility.hh"
#include "RHEJ/debug.hh"
#include "RHEJ/exceptions.hh"
#include "Process.hh"
#include <CLHEP/Random/Randomize.h>
#include <CLHEP/Random/RanluxEngine.h>
using namespace RHEJ;
namespace HEJFOG{
static_assert(
std::numeric_limits<double>::has_quiet_NaN,
"no quiet NaN for double"
);
constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
RHEJ::UnclusteredEvent to_UnclusteredEvent(PhaseSpacePoint const & psp){
RHEJ::UnclusteredEvent result;
result.incoming = psp.incoming();
std::sort(
begin(result.incoming), end(result.incoming),
- [](Sparticle o1, Sparticle o2){return o1.p.pz()<o2.p.pz();}
+ [](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
);
assert(result.incoming.size() == 2);
result.outgoing = psp.outgoing();
assert(
std::is_sorted(
begin(result.outgoing), end(result.outgoing),
RHEJ::rapidity_less{}
)
);
assert(result.outgoing.size() >= 2);
result.decays = psp.decays();
result.central.mur = NaN;
result.central.muf = NaN;
result.central.weight = psp.weight();
return result;
}
namespace{
bool can_swap_to_uno(
- RHEJ::Sparticle const & p1, RHEJ::Sparticle const & p2
+ RHEJ::Particle const & p1, RHEJ::Particle const & p2
){
return is_parton(p1)
&& p1.type != RHEJ::pid::gluon
&& p2.type == RHEJ::pid::gluon;
}
}
void PhaseSpacePoint::maybe_turn_to_uno(
double chance,
RHEJ::RNG & ran
){
assert(outgoing_.size() >= 2);
const size_t nout = outgoing_.size();
const bool can_be_uno_backward = can_swap_to_uno(
outgoing_[0], outgoing_[1]
);
const bool can_be_uno_forward = can_swap_to_uno(
outgoing_[nout-1], outgoing_[nout-2]
);
if(!can_be_uno_backward && !can_be_uno_forward) return;
if(ran.flat() < chance){
weight_ /= chance;
if(can_be_uno_backward && can_be_uno_forward){
if(ran.flat() < 0.5){
std::swap(outgoing_[0].type, outgoing_[1].type);
}
else{
std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
}
weight_ *= 2.;
}
else if(can_be_uno_backward){
std::swap(outgoing_[0].type, outgoing_[1].type);
}
else{
assert(can_be_uno_forward);
std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
}
}
else weight_ /= 1 - chance;
}
PhaseSpacePoint::PhaseSpacePoint(
Process const & proc,
fastjet::JetDefinition jet_def,double jetptmin, double rapmax,
RHEJ::PDF & pdf, double E_beam,
double uno_chance,
HiggsProperties const & h,
RHEJ::RNG & ran
):
jetptmin_{jetptmin},
jet_def_{jet_def}
{
assert(proc.njets >= 2);
const int nout = proc.njets + (proc.boson?1:0);
status_ = good;
weight_ = 1;
weight_ /= std::tgamma(nout);
outgoing_.reserve(nout);
for(auto&& p_out: gen_LO_partons(proc.njets, jetptmin_, E_beam, rapmax, ran)){
- outgoing_.emplace_back(Sparticle{pid::gluon, std::move(p_out)});
+ outgoing_.emplace_back(Particle{pid::gluon, std::move(p_out)});
}
if(status_ != good) return;
if(proc.boson && *proc.boson == pid::Higgs){
// The Higgs
auto Hparticle=gen_boson(pid::higgs, h.mass, h.width, ran);
auto pos=std::upper_bound(
begin(outgoing_),end(outgoing_),Hparticle,rapidity_less{}
);
outgoing_.insert(pos, Hparticle);
if(! h.decays.empty()){
const int boson_idx = std::distance(begin(outgoing_), pos);
decays_.emplace(
boson_idx,
decay_boson(outgoing_[boson_idx], h.decays, ran)
);
}
}
reconstruct_incoming(proc.incoming, pdf, E_beam, ran);
if(status_ != good) return;
// set outgoing states
most_backward_FKL(outgoing_).type = incoming_[0].type;
most_forward_FKL(outgoing_).type = incoming_[1].type;
if(proc.njets > 2) maybe_turn_to_uno(uno_chance, ran);
}
std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_LO_partons(
int np , double ptmin, double ptmax, double rapmax,
RHEJ::RNG & ran
){
if (np<2) throw std::invalid_argument{"Not enough partons in gen_LO_partons"};
// heuristic parameters for pt sampling
const double ptpar = ptmin + np/5.;
const double arg_small_y = atan((ptmax - ptmin)/ptpar);
const double y_cut = 3.;
weight_ /= pow(16.*pow(M_PI,3),np-2);
std::vector<fastjet::PseudoJet> partons;
partons.reserve(np);
for(int i = 0; i < np; ++i){
const double y = -rapmax + 2*rapmax*ran.flat();
weight_ *= 2*rapmax;
const double phi = 2*M_PI*ran.flat();
weight_ *= 2.0*M_PI;
double pt;
const double r1 = ran.flat();
if(y < y_cut){
pt = ptmin + ptpar*tan(r1*arg_small_y);
const double temp = cos(r1*arg_small_y);
weight_ *= pt*ptpar*arg_small_y/(temp*temp);
}
else{
const double ptpar2 = ptpar/(1 + 5*(y-y_cut));
const double temp = 1. - std::exp((ptmin-ptmax)/ptpar2);
pt = ptmin - ptpar2*std::log(1-r1*temp);
weight_ *= pt*ptpar2*temp/(1-r1*temp);
}
partons.emplace_back(fastjet::PtYPhiM(pt, y, phi));
assert(ptmin-1e-5 <= partons[i].pt() && partons[i].pt() <= ptmax+1e-5);
}
// Need to check that at LO, the number of jets = number of partons;
fastjet::ClusterSequence cs(partons, jet_def_);
auto cluster_jets=cs.inclusive_jets(jetptmin_);
if (cluster_jets.size()!=unsigned(np)){
weight_=0.0;
status_ = not_enough_jets;
return {};
}
std::sort(begin(partons), end(partons), rapidity_less{});
return partons;
}
- Sparticle PhaseSpacePoint::gen_boson(
+ Particle PhaseSpacePoint::gen_boson(
RHEJ::ParticleID bosonid, double mass, double width,
RHEJ::RNG & ran
){
std::array<double,2> ptrans{0.,0.};
for (auto const & parton:outgoing_) {
ptrans[0]-=parton.px();
ptrans[1]-=parton.py();
}
// The Higgs:
// Generate a y Gaussian distributed around 0
const double y = random_normal(1.6, ran);
const double r1 = ran.flat();
const double sH = mass*(
mass + width*tan(M_PI/2.*r1 + (r1-1.)*atan(mass/width))
);
const double mHperp=sqrt(ptrans[0]*ptrans[0]+ptrans[1]*ptrans[1]+sH);
const double pz=mHperp*sinh(y);
const double E=mHperp*cosh(y);
- return Sparticle{bosonid,fastjet::PseudoJet{ptrans[0],ptrans[1],pz,E}};
+ return Particle{bosonid,fastjet::PseudoJet{ptrans[0],ptrans[1],pz,E}};
}
- Sparticle const & PhaseSpacePoint::most_backward_FKL(
- std::vector<Sparticle> const & partons
+ Particle const & PhaseSpacePoint::most_backward_FKL(
+ std::vector<Particle> const & partons
) const{
if(!RHEJ::is_parton(partons[0])) return partons[1];
return partons[0];
}
- Sparticle const & PhaseSpacePoint::most_forward_FKL(
- std::vector<Sparticle> const & partons
+ Particle const & PhaseSpacePoint::most_forward_FKL(
+ std::vector<Particle> const & partons
) const{
const size_t last_idx = partons.size() - 1;
if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
return partons[last_idx];
}
- Sparticle & PhaseSpacePoint::most_backward_FKL(
- std::vector<Sparticle> & partons
+ Particle & PhaseSpacePoint::most_backward_FKL(
+ std::vector<Particle> & partons
) const{
if(!RHEJ::is_parton(partons[0])) return partons[1];
return partons[0];
}
- Sparticle & PhaseSpacePoint::most_forward_FKL(
- std::vector<Sparticle> & partons
+ Particle & PhaseSpacePoint::most_forward_FKL(
+ std::vector<Particle> & partons
) const{
const size_t last_idx = partons.size() - 1;
if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
return partons[last_idx];
}
void PhaseSpacePoint::reconstruct_incoming(
std::array<RHEJ::ParticleID, 2> const & ids,
RHEJ::PDF & pdf, double E_beam,
RHEJ::RNG & ran
){
std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_);
// calculate xa, xb
const double sqrts=2*E_beam;
const double xa=(incoming_[0].p.e()-incoming_[0].p.pz())/sqrts;
const double xb=(incoming_[1].p.e()+incoming_[1].p.pz())/sqrts;
// abort if phase space point is outside of collider energy reach
if (xa>1. || xb>1.){
weight_=0;
status_ = too_much_energy;
return;
}
// pick pdfs
/** TODO:
* ufa, ufb don't correspond to our final scale choice.
* The reversed HEJ scale generators currently expect a full event as input,
* so fixing this is not completely trivial
*/
if(ids[0] == pid::proton || ids[0] == pid::p_bar){
const double ufa=jetptmin_;
incoming_[0].type = generate_incoming_id(xa, ufa, pdf, ran);
}
else {
incoming_[0].type = ids[0];
}
if(ids[1] == pid::proton || ids[1] == pid::p_bar){
const double ufb=jetptmin_;
incoming_[1].type = generate_incoming_id(xb, ufb, pdf, ran);
}
else {
incoming_[1].type = ids[1];
}
assert(momentum_conserved(1e-7));
}
RHEJ::ParticleID PhaseSpacePoint::generate_incoming_id(
double x, double uf, RHEJ::PDF & pdf,
RHEJ::RNG & ran
){
const double pdfg=fabs(pdf.pdfpt(0,x,uf,pid::gluon));
const double pdfu=fabs(pdf.pdfpt(0,x,uf,pid::up));
const double pdfd=fabs(pdf.pdfpt(0,x,uf,pid::down));
const double pdfux=fabs(pdf.pdfpt(0,x,uf,pid::u_bar));
const double pdfdx=fabs(pdf.pdfpt(0,x,uf,pid::d_bar));
const double pdfc=fabs(pdf.pdfpt(0,x,uf,pid::charm));
const double pdfs=fabs(pdf.pdfpt(0,x,uf,pid::strange));
const double pdfsx=fabs(pdf.pdfpt(0,x,uf,pid::s_bar));
const double pdfb=fabs(pdf.pdfpt(0,x,uf,pid::b));
const double pdftot=pdfg+4.0/9.0*(pdfu + pdfd + pdfux + pdfdx +pdfs +pdfsx + 2.0*(pdfc +pdfb ));
const double r1=pdftot*ran.flat();
double sum;
if (r1<(sum=pdfg)) {
weight_*=pdftot/pdfg;
return pid::gluon;
}
if (r1<(sum+=(4./9.)*pdfu)) {
weight_*=pdftot/((4./9.)*pdfu);
return pid::up;
}
else if (r1<(sum+=(4./9.)*pdfd)) {
weight_*=pdftot/((4./9.)*pdfd);
return pid::down;
}
else if (r1<(sum+=(4./9.)*pdfux)) {
weight_*=pdftot/((4./9.)*pdfux);
return pid::u_bar;
}
else if (r1<(sum+=(4./9.)*pdfdx)) {
weight_*=pdftot/((4./9.)*pdfdx);
return pid::d_bar;
}
else if (r1<(sum+=(4./9.)*pdfc)) {
weight_*=pdftot/((4./9.)*pdfc);
return pid::c;
}
else if (r1<(sum+=(4./9.)*pdfc)){
weight_*=pdftot/((4./9.)*pdfc);
return pid::c_bar;
}
else if (r1<(sum+=(4./9.)*pdfs)) {
weight_*=pdftot/((4./9.)*pdfs);
return pid::s;
}
else if (r1<(sum+=(4./9.)*pdfsx)) {
weight_*=pdftot/((4./9.)*pdfsx);
return pid::s_bar;
}
else if (r1<(sum+=(4./9.)*pdfb)) {
weight_*=pdftot/((4./9.)*pdfb);
return pid::b;
}
else if (r1<=(sum+=(4./9.)*pdfb)) {
weight_*=pdftot/((4./9.)*pdfb);
return pid::b_bar;
}
std::cout << "Error in choosing incoming parton: "<<x<<" "<<uf<<" "<<sum<<" "<<pdftot<<" "<<r1;
std::cout << " "<<pdfg+4./9.*(pdfu+pdfux+pdfd+pdfdx+pdfs+pdfsx+2.*(pdfc+pdfb))<<std::endl;
throw std::logic_error{"Failed to choose parton flavour"};
}
double PhaseSpacePoint::random_normal(
double stddev,
RHEJ::RNG & ran
){
const double r1 = ran.flat();
const double r2 = ran.flat();
const double lninvr1 = -log(r1);
const double result = stddev*sqrt(2.*lninvr1)*cos(2.*M_PI*r2);
weight_ *= exp(result*result/(2*stddev*stddev))*sqrt(2.*M_PI)*stddev;
return result;
}
bool PhaseSpacePoint::momentum_conserved(double ep) const{
fastjet::PseudoJet diff;
for(auto const & in: incoming()) diff += in.p;
for(auto const & out: outgoing()) diff -= out.p;
return nearby_ep(diff, fastjet::PseudoJet{}, ep);
}
Decay PhaseSpacePoint::select_decay_channel(
std::vector<Decay> const & decays,
RHEJ::RNG & ran
){
double br_total = 0.;
for(auto const & decay: decays) br_total += decay.branching_ratio;
// adjust weight
// this is given by (channel branching ratio)/(chance to pick channel)
// where (chance to pick channel) =
// (channel branching ratio)/(total branching ratio)
weight_ *= br_total;
const double r1 = br_total*ran.flat();
double br_sum = 0.;
for(auto const & decay: decays){
br_sum += decay.branching_ratio;
if(r1 < br_sum) return decay;
}
throw std::logic_error{"unreachable"};
}
- std::vector<Sparticle> PhaseSpacePoint::decay_boson(
- RHEJ::Sparticle const & parent,
+ std::vector<Particle> PhaseSpacePoint::decay_boson(
+ RHEJ::Particle const & parent,
std::vector<Decay> const & decays,
RHEJ::RNG & ran
){
const auto channel = select_decay_channel(decays, ran);
if(channel.products.size() != 2){
throw RHEJ::not_implemented{
"only decays into two particles are implemented"
};
}
- std::vector<Sparticle> decay_products(channel.products.size());
+ std::vector<Particle> decay_products(channel.products.size());
for(size_t i = 0; i < channel.products.size(); ++i){
decay_products[i].type = channel.products[i];
}
// choose polar and azimuth angle in parent rest frame
const double E = parent.m()/2;
const double theta = 2.*M_PI*ran.flat();
const double cos_phi = 2.*ran.flat()-1.;
const double sin_phi = sqrt(1. - cos_phi*cos_phi); // Know 0 < phi < pi
const double px = E*cos(theta)*sin_phi;
const double py = E*sin(theta)*sin_phi;
const double pz = E*cos_phi;
decay_products[0].p.reset(px, py, pz, E);
decay_products[1].p.reset(-px, -py, -pz, E);
for(auto & particle: decay_products) particle.p.boost(parent.p);
return decay_products;
}
}
diff --git a/FixedOrderGen/t/h_2j.cc b/FixedOrderGen/t/h_2j.cc
index 0fb5c8c..2f7d9c3 100644
--- a/FixedOrderGen/t/h_2j.cc
+++ b/FixedOrderGen/t/h_2j.cc
@@ -1,64 +1,64 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "RHEJ/Ranlux64.hh"
#include "RHEJ/PDF.hh"
#include "RHEJ/MatrixElement.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 2.0304; //calculated with "old" HEJ svn r3364
auto config = load_config("config_h_2j.yml");
RHEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
RHEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.unordered_fraction,
config.Higgs_properties,
config.Higgs_coupling,
ran
};
double xs = 0., xs_err = 0.;
for (int trials = 0; trials < config.events; ++trials){
auto ev = generator.gen_event();
if(generator.status() != good) continue;
ev.central().weight *= invGeV2_to_pb;
ev.central().weight /= config.events;
const auto the_Higgs = std::find_if(
begin(ev.outgoing()), end(ev.outgoing()),
- [](RHEJ::Sparticle const & p){ return p.type == RHEJ::ParticleID::h; }
+ [](RHEJ::Particle const & p){ return p.type == RHEJ::ParticleID::h; }
);
assert(the_Higgs != end(ev.outgoing()));
if(std::abs(the_Higgs->rapidity()) > 5.) continue;
xs += ev.central().weight;
xs_err += ev.central().weight*ev.central().weight;
}
xs_err = std::sqrt(xs_err);
std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n';
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.01*xs);
}
diff --git a/FixedOrderGen/t/h_2j_decay.cc b/FixedOrderGen/t/h_2j_decay.cc
index 3b2180d..688c1e4 100644
--- a/FixedOrderGen/t/h_2j_decay.cc
+++ b/FixedOrderGen/t/h_2j_decay.cc
@@ -1,82 +1,82 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "RHEJ/Ranlux64.hh"
#include "RHEJ/PDF.hh"
#include "RHEJ/MatrixElement.hh"
#include "RHEJ/debug.hh"
using namespace HEJFOG;
bool pass_dR_cut(
std::vector<fastjet::PseudoJet> const & jets,
- std::vector<RHEJ::Sparticle> const & photons
+ std::vector<RHEJ::Particle> const & photons
){
constexpr double delta_R_min = 0.7;
for(auto const & jet: jets){
for(auto const & photon: photons){
if(jet.delta_R(photon.p) < delta_R_min) return false;
}
}
return true;
}
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 0.00425287; //calculated with "old" HEJ svn r3364
auto config = load_config("config_h_2j_decay.yml");
RHEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
RHEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.unordered_fraction,
config.Higgs_properties,
config.Higgs_coupling,
ran
};
double xs = 0., xs_err = 0.;
for (int trials = 0; trials < config.events; ++trials){
auto ev = generator.gen_event();
if(generator.status() != good) continue;
assert(ev.decays().size() == 1);
const auto decay = begin(ev.decays());
assert(ev.outgoing().size() > static_cast<size_t>(decay->first));
const auto & the_Higgs = ev.outgoing()[decay->first];
assert(the_Higgs.type == RHEJ::pid::Higgs);
assert(decay->second.size() == 2);
auto const & gamma = decay->second;
assert(gamma[0].type == RHEJ::pid::photon);
assert(gamma[1].type == RHEJ::pid::photon);
assert(nearby_ep(gamma[0].p + gamma[1].p, the_Higgs.p, 1e-6));
if(!pass_dR_cut(ev.jets(), gamma)) continue;
ev.central().weight *= invGeV2_to_pb;
ev.central().weight /= config.events;
xs += ev.central().weight;
xs_err += ev.central().weight*ev.central().weight;
}
xs_err = std::sqrt(xs_err);
std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n';
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.012*xs);
}
diff --git a/FixedOrderGen/t/h_3j.cc b/FixedOrderGen/t/h_3j.cc
index c8ba972..d24d3d9 100644
--- a/FixedOrderGen/t/h_3j.cc
+++ b/FixedOrderGen/t/h_3j.cc
@@ -1,65 +1,65 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "RHEJ/Ranlux64.hh"
#include "RHEJ/PDF.hh"
#include "RHEJ/MatrixElement.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 1.0888; //calculated with "old" HEJ svn r3364
auto config = load_config("config_h_2j.yml");
config.process.njets = 3;
RHEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
RHEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.unordered_fraction,
config.Higgs_properties,
config.Higgs_coupling,
ran
};
double xs = 0., xs_err = 0.;
for (int trials = 0; trials < config.events; ++trials){
auto ev = generator.gen_event();
if(generator.status() != good) continue;
ev.central().weight *= invGeV2_to_pb;
ev.central().weight /= config.events;
const auto the_Higgs = std::find_if(
begin(ev.outgoing()), end(ev.outgoing()),
- [](RHEJ::Sparticle const & p){ return p.type == RHEJ::ParticleID::h; }
+ [](RHEJ::Particle const & p){ return p.type == RHEJ::ParticleID::h; }
);
assert(the_Higgs != end(ev.outgoing()));
if(std::abs(the_Higgs->rapidity()) > 5.) continue;
xs += ev.central().weight;
xs_err += ev.central().weight*ev.central().weight;
}
xs_err = std::sqrt(xs_err);
std::cout << xs_ref << " ~ " << xs << " +- " << xs_err << '\n';
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.02*xs);
}
diff --git a/analysis-plugins/include/ROOTReader_impl.hh b/analysis-plugins/include/ROOTReader_impl.hh
index 5ac1fc6..c161d09 100644
--- a/analysis-plugins/include/ROOTReader_impl.hh
+++ b/analysis-plugins/include/ROOTReader_impl.hh
@@ -1,270 +1,270 @@
#pragma once
#include "ROOTReader.hh"
#include "TTree.h"
#include "RHEJ/kinematics.hh"
#include "RHEJ/debug.hh"
inline
-std::ostream & operator<<(std::ostream & o, RHEJ::Sparticle const & s){
+std::ostream & operator<<(std::ostream & o, RHEJ::Particle const & s){
return o << '{' << s.type << ", " << s.p << '}';
}
inline
std::ostream & operator<<(std::ostream & o, RHEJ::EventParameters const & p){
return o << '{' << p.mur << ", " << p.muf << ", " << p.weight << '}';
}
inline
std::ostream & operator<<(std::ostream & o, RHEJ::UnclusteredEvent const & ev){
o << "incoming:\n";
for(auto && p: ev.incoming) o << " " << p << '\n';
o << "outgoing:\n";
for(auto && p: ev.outgoing) o << " " << p << '\n';
o << "central parameters: ";
return o << ev.central << '\n';
if(! ev.variations.empty()){
o << "variation parameters: {" << ev.variations.front();
for(auto it = begin(ev.variations) + 1; it != end(ev.variations); ++it){
o << ", " << (*it);
}
o << "}\n";
}
return o;
}
namespace RHEJ_analyses{
using const_iterator = ROOTReader::const_iterator;
inline
ROOTReader::ROOTReader(TTree * events):
events_{events}
{
}
inline
const_iterator ROOTReader::begin() const{
const_iterator it{events_};
it.idx_ = 0;
return it;
}
inline
const_iterator ROOTReader::end() const{
const_iterator it{events_};
it.idx_ = events_->GetEntries();
return it;
}
using difference_type = EventIterator::difference_type;
using value_type = EventIterator::value_type;
using pointer = EventIterator::pointer;
using reference = EventIterator::reference;
inline
EventIterator::EventIterator(EventIterator const & other):
idx_{other.idx_},
events_{other.events_}
{
reset_branches();
}
inline
EventIterator::EventIterator(EventIterator && other):
idx_{std::move(other.idx_)},
events_{std::move(other.events_)}
{
reset_branches();
}
inline
EventIterator & EventIterator::operator=(EventIterator const & other){
idx_ = other.idx_;
events_ = other.events_;
reset_branches();
return *this;
}
inline
EventIterator & EventIterator::operator=(EventIterator && other){
idx_ = std::move(other.idx_);
events_ = std::move(other.events_);
reset_branches();
return *this;
}
inline
EventIterator::EventIterator(TTree * events):
events_{events}
{
reset_branches();
}
inline
void EventIterator::reset_branches() const{
events_->SetBranchAddress("id", &entry_.id);
events_->SetBranchAddress("nparticle", &entry_.n_out);
events_->SetBranchAddress("weight", &entry_.weight);
events_->SetBranchAddress("id1", &entry_.PDG_id_in1);
events_->SetBranchAddress("id2", &entry_.PDG_id_in2);
events_->SetBranchAddress("fac_scale", &entry_.muf);
events_->SetBranchAddress("ren_scale", &entry_.mur);
events_->SetBranchAddress("nuwgt", &entry_.n_weights);
events_->SetBranchAddress("jet_algo", &entry_.jet_algo);
events_->SetBranchAddress("R", &entry_.R);
events_->SetBranchAddress("min_jet_pt", &entry_.min_jet_pt);
}
inline
reference EventIterator::operator*() const{
// first read number of particles and weights
events_->FindBranch("nparticle")->GetEntry(idx_);
events_->FindBranch("nuwgt")->GetEntry(idx_);
entry_.px.resize(entry_.n_out);
entry_.py.resize(entry_.n_out);
entry_.pz.resize(entry_.n_out);
entry_.E.resize(entry_.n_out);
entry_.PDG_id.resize(entry_.n_out);
entry_.weights.resize(entry_.n_weights);
events_->SetBranchAddress("px", entry_.px.data());
events_->SetBranchAddress("py", entry_.py.data());
events_->SetBranchAddress("pz", entry_.pz.data());
events_->SetBranchAddress("E", entry_.E.data());
events_->SetBranchAddress("kf", entry_.PDG_id.data());
events_->SetBranchAddress("usr_wgts", entry_.weights.data());
// second read to get the whole event
events_->GetEntry(idx_);
auto ev = to_UnclusteredEvent(entry_);
fastjet::JetDefinition jet_def{
static_cast<fastjet::JetAlgorithm>(entry_.jet_algo), entry_.R
};
ev_ = Event{std::move(ev), std::move(jet_def), entry_.min_jet_pt};
return ev_;
}
inline
RHEJ::UnclusteredEvent EventIterator::to_UnclusteredEvent(
EventIterator::BranchEntry const & event_entry
) const{
RHEJ::UnclusteredEvent ev;
ev.outgoing.resize(event_entry.n_out);
for(size_t i = 0; i < (size_t) event_entry.n_out; ++i){
ev.outgoing[i].p = {
event_entry.px[i], event_entry.py[i],
event_entry.pz[i], event_entry.E[i]
};
ev.outgoing[i].type = static_cast<RHEJ::ParticleID>(event_entry.PDG_id[i]);
}
std::tie(ev.incoming[0].p, ev.incoming[1].p) =
RHEJ::incoming_momenta(ev.outgoing);
ev.incoming[0].type = static_cast<RHEJ::ParticleID>(event_entry.PDG_id_in1);
ev.incoming[1].type = static_cast<RHEJ::ParticleID>(event_entry.PDG_id_in2);
ev.central = {event_entry.mur, event_entry.muf, event_entry.weight};
ev.variations.resize(event_entry.n_weights);
for(size_t i = 0; i < (size_t) event_entry.n_weights; ++i){
ev.variations[i].weight = event_entry.weights[i];
}
return ev;
}
inline
EventIterator & EventIterator::operator++(){
++idx_;
return *this;
}
inline
EventIterator EventIterator::operator++(int){
EventIterator res = *this;
++idx_;
return res;
}
inline
EventIterator & EventIterator::operator--(){
--idx_;
return *this;
}
inline
EventIterator EventIterator::operator--(int){
EventIterator res = *this;
--idx_;
return res;
}
inline
EventIterator & EventIterator::operator+=(difference_type n){
idx_ += n;
return *this;
}
inline
EventIterator & EventIterator::operator-=(difference_type n){
idx_ -= n;
return *this;
}
inline
reference EventIterator::operator[](difference_type n) const{
return *(*this + n);
}
inline
bool operator==(EventIterator const & a, EventIterator const & b){
return a.events_==b.events_ && a.idx_==b.idx_;
}
inline
bool operator!=(EventIterator const & a, EventIterator const & b){
return !(a==b);
}
inline
bool operator<(EventIterator const & a, EventIterator const & b){
return a.idx_ < b.idx_;
}
inline
bool operator<=(EventIterator const & a, EventIterator const & b){
return a==b || a<b;
}
inline
bool operator>(EventIterator const & a, EventIterator const & b){
return !(a<=b);
}
inline
bool operator>=(EventIterator const & a, EventIterator const & b){
return !(a<b);
}
inline
EventIterator operator+(EventIterator const & a, difference_type n){
EventIterator res = a;
return res += n;
}
inline
EventIterator operator+(difference_type n, EventIterator const & a){
return a + n;
}
inline
EventIterator operator-(EventIterator const & a, difference_type n){
return a + (-n);
}
inline
difference_type operator-(
EventIterator const & a, EventIterator const & b
){
return a.idx_ - b.idx_;
}
}
diff --git a/analysis-plugins/include/StandardAnalysis_decl.hh b/analysis-plugins/include/StandardAnalysis_decl.hh
index 9c2bac6..bf62a71 100644
--- a/analysis-plugins/include/StandardAnalysis_decl.hh
+++ b/analysis-plugins/include/StandardAnalysis_decl.hh
@@ -1,146 +1,146 @@
#pragma once
#include <array>
#include <map>
#include "fastjet/JetDefinition.hh"
#include "fastjet/PseudoJet.hh"
#include "fastjet/ClusterSequence.hh"
#include "RHEJ/Analysis.hh"
#include "RHEJ/Event.hh"
#include "Histogram.hh"
class TFile;
namespace YAML{
class Node;
}
namespace RHEJ_analyses{
using RHEJ::Event;
namespace detail{
struct AbsWtLess{
bool operator()(Event const & a, Event const & b){
return std::abs(a.central().weight) < std::abs(b.central().weight);
}
};
}
class StandardAnalysis: public RHEJ::DynamicAnalysis{
public:
using histogram_type = Histogram;
// macro definition to avoid repetition of histogram names
#define RHEJ_HISTOGRAMS(F) F(total), F(np), F(njets),F(pt1), F(pt2), F(pth1), F(pth2), F(qt), F(ya), F(yb), F(ydif), F(yEW), F(ptEW), F(wt), F(wtwt)
#define RHEJ_AS_ENUM(VAR) VAR
#define RHEJ_AS_STRING(VAR) #VAR
enum Id{
RHEJ_HISTOGRAMS(RHEJ_AS_ENUM),
first_histogram = np,
last_histogram = wtwt,
first_histpack = np,
last_histpack = ptEW
};
static constexpr auto hist_names = RHEJ::make_array(
RHEJ_HISTOGRAMS(RHEJ_AS_STRING)
);
#undef RHEJ_HISTOGRAMS
#undef RHEJ_AS_ENUM
#undef RHEJ_AS_STRING
StandardAnalysis(YAML::Node const &);
explicit StandardAnalysis(std::string const & filename);
StandardAnalysis(StandardAnalysis const & other);
StandardAnalysis(StandardAnalysis && other);
StandardAnalysis & operator=(StandardAnalysis const & other);
StandardAnalysis & operator=(StandardAnalysis && other);
void fill(Event const & e, Event const &) override;
bool pass_cuts(Event const &, Event const &) override{
return true;
};
std::vector<std::string> histogram_names() const override;
std::vector<Parameter> parameters() const override;
void draw_histogram(
std::string const & name, std::string const & filename
) const override;
bool update_parameter(std::string const & name, double value) override;
void finalise() override;
static std::unique_ptr<Analysis> create(YAML::Node const &);
static std::unique_ptr<DynamicAnalysis> create(
std::string const & filename
);
private:
void store();
void restore(std::string const & filename);
void write_settings(TFile & out);
void write_histograms(TFile & out);
void write_events(TFile & out);
void read_settings(TFile & in);
void read_histograms(TFile & in);
void read_events(TFile & in);
struct hist_pack{
histogram_type h, hwt, hN;
hist_pack() = default;
hist_pack(
const char * title, const std::string & id,
int numbins, double min, double max
);
void fill(double val, double wt);
void write() const;
int nbins() const;
};
struct KinInfo{
- std::vector<RHEJ::Sparticle> out;
+ std::vector<RHEJ::Particle> out;
std::vector<fastjet::PseudoJet> jets_y;
std::vector<fastjet::PseudoJet> jets_pt;
fastjet::PseudoJet q;
};
struct EventHists{
EventHists();
explicit EventHists(std::string const & id);
void fill(KinInfo const & i, double weight);
void write() const;
std::array<hist_pack, last_histpack + 1> hist_;
histogram_type hist_wt_, hist_wtwt_;
};
void restore_histograms(
std::map<std::string, histogram_type> && hists
);
void update_hist_by_name();
void add_to_hist_by_name(EventHists const & hist);
void add_to_hist_by_name(hist_pack const & pack);
void reset();
EventHists central_;
std::vector<EventHists> hist_;
double log_wt_cut_;
std::string output_;
std::set<Event, detail::AbsWtLess> bad_events_;
using Hist_ref = std::reference_wrapper<const histogram_type>;
std::map<std::string, Hist_ref> hist_by_name_;
EventHists orig_central_;
std::vector<EventHists> orig_hist_;
double orig_log_wt_cut_;
};
}
diff --git a/analysis-plugins/include/StandardAnalysis_impl.hh b/analysis-plugins/include/StandardAnalysis_impl.hh
index 619df5b..4674ee2 100644
--- a/analysis-plugins/include/StandardAnalysis_impl.hh
+++ b/analysis-plugins/include/StandardAnalysis_impl.hh
@@ -1,525 +1,525 @@
#pragma once
#include <iostream>
#include <numeric>
#include "StandardAnalysis.hh"
#include "ROOTWriter.hh"
#include "ROOTReader.hh"
#include "TDirectory.h"
#include "TKey.h"
#include "TCanvas.h"
#include "TImage.h"
#include "TFile.h"
#include "yaml-cpp/yaml.h"
namespace RHEJ_analyses{
namespace detail{
inline
bool disable_TH1_reference(){
TH1::AddDirectory(kFALSE);
std::cout << "Disabled central ROOT histogram references\n";
return true;
};
}
using histogram = StandardAnalysis::histogram_type;
inline
StandardAnalysis::hist_pack::hist_pack(
const char * title, const std::string & id,
int numbins, double min, double max
):
h((title + id).c_str(), title, numbins, min, max),
hwt(
(title + ("wt2" + id)).c_str(),
(title + std::string("wt2")).c_str(),
numbins, min, max
),
hN(
(title + ("N" + id)).c_str(),
(title + std::string("N")).c_str(),
numbins, min, max
)
{
static const bool TH1_reference_disabled = detail::disable_TH1_reference();
(void) TH1_reference_disabled; // avoid compiler warnings
h.sumw2();
}
inline
void StandardAnalysis::hist_pack::write() const{
h.write();
hwt.write();
hN.write();
}
inline
int StandardAnalysis::hist_pack::nbins() const{
return h.nbins();
}
inline
void StandardAnalysis::hist_pack::fill(double val, double wt){
const int binnumber = h.x_axis()->FindBin(val);
const double binwidth = h.x_axis()->GetBinWidth(binnumber);
h.fill(val, wt/binwidth);
hwt.fill(val, wt*wt/binwidth);
hN.fill(val, 1);
}
inline
StandardAnalysis::EventHists::EventHists():
EventHists{""} {}
StandardAnalysis::EventHists::EventHists(std::string const & id){
#define NEWHIST(X,UUID,BINS,MIN,MAX) hist_[X] = hist_pack{#X, UUID, BINS, MIN, MAX};
NEWHIST(total,id,1,-.5,.5);
NEWHIST(np,id,35,-.5,34.5);
NEWHIST(njets,id,7,.5,7.5);
NEWHIST(pt1,id,100,0.,1000.);
NEWHIST(pt2,id,100,0.,1000.);
NEWHIST(pth1,id,100,0.,1000.);
NEWHIST(pth2,id,100,0.,1000.);
NEWHIST(qt,id,100,0.,99.);
NEWHIST(ya,id,40,-5.,5.);
NEWHIST(yb,id,40,-5.,5.);
NEWHIST(ydif,id,32,0.,8.);
NEWHIST(yEW,id,40,-5.,5.);
NEWHIST(ptEW,id,20,0.,200.);
#undef NEWHIST
hist_wt_ = histogram{("wt" + id).c_str(),"wt",800,-30.,50.};
hist_wtwt_ = histogram{("wtwt" + id).c_str(),"wtwt",800,-30.,50.};
}
inline
void StandardAnalysis::EventHists::fill(KinInfo const & i, double weight){
const double ymin = i.jets_y.front().rapidity();
const double ymax = i.jets_y.back().rapidity();
assert(ymax > ymin);
const auto EW_boson = std::find_if(
begin(i.out), end(i.out),
- [](RHEJ::Sparticle const & s){ return is_AWZH_boson(s); }
+ [](RHEJ::Particle const & s){ return is_AWZH_boson(s); }
);
const size_t npartons = (EW_boson==end(i.out))?
i.out.size():
i.out.size()-1
;
hist_[total].fill(0., weight);
hist_[np].fill(npartons, weight);
for(size_t jets = 2; jets <= i.jets_y.size(); ++jets){
hist_[njets].fill(jets, weight);
}
hist_[pt1].fill(i.jets_y.front().perp(), weight);
hist_[pt2].fill(i.jets_y.back().perp(), weight);
hist_[pth1].fill(i.jets_pt.front().perp(), weight);
hist_[pth2].fill(i.jets_pt[1].perp(), weight);
hist_[qt].fill(i.q.perp(), weight);
hist_[ya].fill(ymin, weight);
hist_[yb].fill(ymax, weight);
hist_[ydif].fill(ymax - ymin, weight);
if(EW_boson!=end(i.out)){
hist_[yEW].fill(EW_boson->rapidity(), weight);
hist_[ptEW].fill(EW_boson->perp(), weight);
}
const double awt = std::abs(weight);
hist_wt_.fill(std::log(awt), 1);
hist_wtwt_.fill(std::log(awt), awt);
}
inline
void StandardAnalysis::EventHists::write() const{
for(auto hist: hist_){
hist.write();
}
hist_wt_.write();
hist_wtwt_.write();
}
namespace detail{
inline
double get_log_wt_cut(YAML::Node const & cut){
return cut?
cut.as<double>():
std::numeric_limits<double>::infinity();
}
}
inline
StandardAnalysis::StandardAnalysis(YAML::Node const & parameters):
log_wt_cut_{detail::get_log_wt_cut(parameters["log wt cut"])},
output_{parameters["output"].as<std::string>()}
{}
inline
StandardAnalysis::StandardAnalysis(
std::string const & filename
){
restore(filename);
}
inline
void StandardAnalysis::finalise(){
if(!output_.empty()) store();
}
inline
StandardAnalysis::StandardAnalysis(StandardAnalysis const & other){
*this = other;
}
inline
StandardAnalysis::StandardAnalysis(StandardAnalysis && other){
*this = std::move(other);
}
inline
StandardAnalysis & StandardAnalysis::operator=(StandardAnalysis const & other){
if(this == &other) return *this;
central_ = other.central_;
hist_ = other.hist_;
log_wt_cut_ = other.log_wt_cut_;
output_ = other.output_;
bad_events_ = other.bad_events_;
orig_central_ = other.orig_central_;
orig_hist_ = other.orig_hist_;
orig_log_wt_cut_ = other.orig_log_wt_cut_;
update_hist_by_name();
return *this;
}
StandardAnalysis & StandardAnalysis::operator=(StandardAnalysis && other){
if(this == &other) return *this;
central_ = std::move(other.central_);
hist_ = std::move(other.hist_);
log_wt_cut_ = std::move(other.log_wt_cut_);
output_ = std::move(other.output_);
bad_events_ = std::move(other.bad_events_);
orig_central_ = std::move(other.orig_central_);
orig_hist_ = std::move(other.orig_hist_);
orig_log_wt_cut_ = std::move(other.orig_log_wt_cut_);
update_hist_by_name();
return *this;
}
inline
std::vector<std::string> StandardAnalysis::histogram_names() const{
std::vector<std::string> result;
for(auto const & entry: hist_by_name_) result.emplace_back(entry.first);
return result;
};
inline
std::vector<RHEJ::DynamicAnalysis::Parameter> StandardAnalysis::parameters() const{
double min = log_wt_cut_;
double max = log_wt_cut_;
if(! bad_events_.empty()){
min = std::min(min, std::log(std::abs(begin(bad_events_)->central().weight)));
max = std::max(max, std::log(std::abs(bad_events_.rbegin()->central().weight)));
}
return {RHEJ::DynamicAnalysis::Parameter{"log wt cut", log_wt_cut_, min, max}};
}
inline
void StandardAnalysis::draw_histogram(
std::string const & name, std::string const & filename
) const{
const auto hist = hist_by_name_.find(name);
if(hist == end(hist_by_name_)){
throw std::invalid_argument{
"histogram with title "+ name + " does not exist"
};
}
TCanvas c;
hist->second.get().draw();
const auto img = std::unique_ptr<TImage>{TImage::Create()};
img->FromPad(&c);
img->WriteImage(filename.c_str(), TImage::EImageFileTypes::kPng);
}
inline
bool StandardAnalysis::update_parameter(std::string const & name, double value){
if(name != "log wt cut"){
throw std::invalid_argument{"invalid parameter " + name};
}
Event search_event;
search_event.central().weight = std::exp(log_wt_cut_);
const auto old_end = bad_events_.lower_bound(search_event);
search_event.central().weight = std::exp(value);
const auto new_end = bad_events_.lower_bound(search_event);
if(new_end == old_end){
log_wt_cut_ = value;
return false; // no update required
}
if(value < log_wt_cut_){
// we would have to remove events from histograms
// instead, reset and add all events again
reset();
update_parameter(name, value);
return true;
}
log_wt_cut_ = value;
for(auto it = old_end; it != new_end; ++it) fill(*it, *it);
return true;
}
inline
void StandardAnalysis::fill(Event const & ev, Event const & /* FO_event */){
if(std::log(std::abs(ev.central().weight)) > log_wt_cut_){
bad_events_.emplace(ev);
return;
}
const std::vector<fastjet::PseudoJet> partons =
to_PseudoJet(filter_partons(ev.outgoing()));
auto jets_y = sorted_by_rapidity(ev.jets());
auto q =
std::accumulate(partons.begin(), partons.end(), fastjet::PseudoJet{})
- std::accumulate(jets_y.begin(), jets_y.end(), fastjet::PseudoJet{})
;
const KinInfo info = {
ev.outgoing(),
std::move(jets_y),
sorted_by_pt(ev.jets()),
std::move(q)
};
assert(info.jets_y.size() == info.jets_pt.size());
assert(info.jets_y.size() >= 2);
central_.fill(info, ev.central().weight);
if(hist_.empty()){
hist_.reserve(ev.variations().size());
for(size_t i = 0; i < ev.variations().size(); ++i){
hist_.emplace_back('_' + std::to_string(i));
}
}
if(hist_.size() != ev.variations().size()){
throw std::invalid_argument(
"number of weights " + std::to_string(ev.variations().size())
+ " does not match number of histograms "
+ std::to_string(hist_.size())
);
}
for(size_t i = 0; i < ev.variations().size(); ++i){
hist_[i].fill(info, ev.variations(i).weight);
}
}
inline
void StandardAnalysis::write_settings(TFile &){
TTree settings{"settings", "settings"};
settings.Branch("log_wt_cut", &log_wt_cut_, "wtwt_cut/D");
settings.Fill();
settings.Write();
}
inline
void StandardAnalysis::read_settings(TFile & in){
auto tree = static_cast<TTree*>(in.Get("settings"));
if(tree == nullptr){
throw std::runtime_error("no TTree with name \"settings\"");
}
tree->SetBranchAddress("log_wt_cut", &log_wt_cut_);
if(tree->GetEntries() != 1){
throw std::runtime_error("wrong number of entries in \"settings\"");
}
tree->GetEntry(0);
}
inline
void StandardAnalysis::write_histograms(TFile & out){
const auto dir = out.mkdir("histograms");
assert(dir != nullptr);
dir->cd();
central_.write();
for(auto const & hist: hist_) hist.write();
out.cd();
}
inline
void StandardAnalysis::write_events(TFile &){
ROOTWriter writer{"events"};
for(auto && event: bad_events_) writer.write(event);
}
namespace detail{
struct weight_less{
bool operator()(Event const & a, Event const & b){
return a.central().weight < b.central().weight;
}
bool operator()(Event const & ev, double wt){
return ev.central().weight < wt;
}
bool operator()(double wt, RHEJ::Event const & ev){
return wt < ev.central().weight;
}
};
}
inline
void StandardAnalysis::read_events(TFile & in){
assert(in.IsOpen());
auto event_tree = static_cast<TTree*>(in.Get("events"));
if(event_tree == nullptr){
throw std::runtime_error("no TTree with name \"events\"");
}
ROOTReader event_reader{event_tree};
bad_events_ = std::set<Event, detail::AbsWtLess>(
std::begin(event_reader), std::end(event_reader)
);
}
inline
void StandardAnalysis::store(){
TFile out{output_.c_str(), "RECREATE"};
write_settings(out);
write_histograms(out);
write_events(out);
}
inline
void StandardAnalysis::restore(std::string const & filename){
TFile in{filename.c_str()};
read_settings(in);
read_histograms(in);
read_events(in);
orig_central_ = central_;
orig_hist_ = hist_;
orig_log_wt_cut_ = log_wt_cut_;
}
namespace detail{
using histogram_type = StandardAnalysis::histogram_type;
inline
size_t num_hist_indices(
std::map<std::string, Histogram> const & hists,
std::string const & name
){
size_t result = 0;
while(hists.find(name + "_" + std::to_string(result)) != hists.end()){
++result;
}
return result;
}
inline
std::map<std::string, histogram_type> read_hist_map(TDirectory & in){
TIter keys = in.GetListOfKeys();
TKey* key;
std::map<std::string, histogram_type> hists;
while( (key = static_cast<TKey*>(keys())) ){
auto new_hist = dynamic_cast<TH1D*>(key->ReadObj());
if(! new_hist){
throw std::runtime_error("Encountered unexpected object in ROOT file");
}
hists.emplace(new_hist->GetName(), histogram_type{new_hist});
}
return hists;
}
}
inline
void StandardAnalysis::read_histograms(TFile & in){
const auto dir = in.GetDirectory("histograms");
if(dir == nullptr){
throw std::runtime_error{"no directory \"histograms\""};
}
restore_histograms(detail::read_hist_map(*dir));
update_hist_by_name();
}
inline
void StandardAnalysis::restore_histograms(
std::map<std::string, histogram_type> && hists
){
hist_.resize(detail::num_hist_indices(hists, hist_names[first_histogram]));
for(size_t id = first_histogram; id <= last_histpack; ++id){
central_.hist_[id].h = std::move(hists[hist_names[id]]);
for(size_t i = 0; i < hist_.size(); ++i){
const std::string name = hist_names[id] + ("_" + std::to_string(i));
hist_[i].hist_[id].h = std::move(hists[name]);
}
std::string name = hist_names[id] + std::string{"wt2"};
central_.hist_[id].hwt = std::move(hists[name]);
for(size_t i = 0; i < hist_.size(); ++i){
const std::string name = hist_names[id] + ("wt2_" + std::to_string(i));
hist_[i].hist_[id].hwt = std::move(hists[name]);
}
name = hist_names[id] + std::string{"N"};
central_.hist_[id].hN = std::move(hists[name]);
for(size_t i = 0; i < hist_.size(); ++i){
const std::string name = hist_names[id] + ("N_" + std::to_string(i));
hist_[i].hist_[id].hN = std::move(hists[name]);
}
}
central_.hist_wt_ = std::move(hists["wt"]);
central_.hist_wtwt_ = std::move(hists["wtwt"]);
for(size_t i = 0; i < hist_.size(); ++i){
std::string name = "wt_" + std::to_string(i);
hist_[i].hist_wt_ = std::move(hists[name]);
name = "wtwt_" + std::to_string(i);
hist_[i].hist_wtwt_ = std::move(hists[name]);
}
}
inline
void StandardAnalysis::update_hist_by_name(){
hist_by_name_.clear();
add_to_hist_by_name(central_);
for(auto const & hist: hist_) add_to_hist_by_name(hist);
}
inline
void StandardAnalysis::add_to_hist_by_name(EventHists const & hist){
for(auto const & h: hist.hist_) add_to_hist_by_name(h);
hist_by_name_.emplace(hist.hist_wt_.title(), Hist_ref{hist.hist_wt_});
hist_by_name_.emplace(hist.hist_wtwt_.title(), Hist_ref{hist.hist_wtwt_});
}
inline
void StandardAnalysis::add_to_hist_by_name(hist_pack const & pack){
hist_by_name_.emplace(pack.h.title(), Hist_ref{pack.h});
hist_by_name_.emplace(pack.hwt.title(), Hist_ref{pack.hwt});
hist_by_name_.emplace(pack.hN.title(), Hist_ref{pack.hN});
}
inline
std::unique_ptr<RHEJ::Analysis> StandardAnalysis::create(
YAML::Node const & parameters
){
return std::unique_ptr<Analysis>{new StandardAnalysis{parameters}};
}
inline
std::unique_ptr<RHEJ::DynamicAnalysis> StandardAnalysis::create(
std::string const & filename
){
return std::unique_ptr<RHEJ::DynamicAnalysis>{
new StandardAnalysis{filename}
};
}
inline
void StandardAnalysis::reset(){
central_ = orig_central_;
hist_ = orig_hist_;
log_wt_cut_ = orig_log_wt_cut_;
update_hist_by_name();
}
constexpr
decltype(StandardAnalysis::hist_names) StandardAnalysis::hist_names;
}
diff --git a/include/RHEJ/Event.hh b/include/RHEJ/Event.hh
index 77dd373..b79ab89 100644
--- a/include/RHEJ/Event.hh
+++ b/include/RHEJ/Event.hh
@@ -1,136 +1,136 @@
/** \file Event.hh
* \brief Details the parameters of an Event.
*
* Contains the EventParameters struct and the Event struct. Also
* contains the ClusteredEvent class.
*/
#pragma once
#include <string>
#include <unordered_map>
#include "RHEJ/utility.hh"
#include "RHEJ/event_types.hh"
#include "LHEF/LHEF.h"
#include "fastjet/JetDefinition.hh"
#include "fastjet/ClusterSequence.hh"
namespace RHEJ{
/** \struct EventParameters Event.hh "include/RHEJ/Event.hh"
* \brief A struct containing the parameters of an event
*/
struct EventParameters{
double mur; /**< Value of the Renormalisation Scale */
double muf; /**< Value of the Factorisation Scale */
double weight; /**< Event Weight */
};
/** \struct UnclusteredEvent Event.hh "include/RHEJ/Event.hh"
* \brief Event Struct which contains Particle Content.
*/
struct UnclusteredEvent{
//! Default Constructor
UnclusteredEvent() = default;
//! Constructor from LesHouches event information
UnclusteredEvent(LHEF::HEPEUP const & hepeup);
- std::array<Sparticle, 2> incoming; /**< Incoming Particles */
- std::vector<Sparticle> outgoing; /**< Outgoing Particles */
+ std::array<Particle, 2> incoming; /**< Incoming Particles */
+ std::vector<Particle> outgoing; /**< Outgoing Particles */
//! Particle decays in the format {outgoing index, decay products}
- std::unordered_map<int, std::vector<Sparticle>> decays;
+ std::unordered_map<int, std::vector<Particle>> decays;
//! Central parameter (e.g. scale) choice
EventParameters central;
std::vector<EventParameters> variations; /**< For parameter variation */
};
/** \class Event Event.hh "include/RHEJ/Event.hh"
* \brief Class for Events
*
* This is the default reversed HEJ event class.
* It contains kinematic information including jet clustering,
* parameter (e.g. scale) settings and the event weight.
*/
class Event{
public:
//! Default Event Constructor
Event() = default;
//! Event Constructor adding jet clustering to an unclustered event
Event(
UnclusteredEvent ev,
fastjet::JetDefinition const & jet_def, double min_jet_pt
);
std::vector<fastjet::PseudoJet> jets() const;
UnclusteredEvent const & unclustered() const {
return ev_;
}
EventParameters const & central() const{
return ev_.central;
}
EventParameters & central(){
return ev_.central;
}
- std::array<Sparticle, 2> const & incoming() const{
+ std::array<Particle, 2> const & incoming() const{
return ev_.incoming;
}
- std::vector<Sparticle> const & outgoing() const{
+ std::vector<Particle> const & outgoing() const{
return ev_.outgoing;
}
- std::unordered_map<int, std::vector<Sparticle>> const & decays() const{
+ std::unordered_map<int, std::vector<Particle>> const & decays() const{
return ev_.decays;
}
std::vector<EventParameters> const & variations() const{
return ev_.variations;
}
std::vector<EventParameters> & variations(){
return ev_.variations;
}
EventParameters const & variations(size_t i) const{
return ev_.variations[i];
}
EventParameters & variations(size_t i){
return ev_.variations[i];
}
std::vector<int> particle_jet_indices(
std::vector<fastjet::PseudoJet> const & jets
) const{
return cs_.particle_jet_indices(jets);
}
fastjet::JetDefinition const & jet_def() const{
return cs_.jet_def();
}
double min_jet_pt() const{
return min_jet_pt_;
}
event_type::EventType type() const{
return type_;
}
private:
UnclusteredEvent ev_;
fastjet::ClusterSequence cs_;
double min_jet_pt_;
event_type::EventType type_;
};
double shat(Event const & ev);
LHEF::HEPEUP to_HEPEUP(Event const & event, LHEF::HEPRUP *);
}
diff --git a/include/RHEJ/MatrixElement.hh b/include/RHEJ/MatrixElement.hh
index 20302f4..41b4f6f 100644
--- a/include/RHEJ/MatrixElement.hh
+++ b/include/RHEJ/MatrixElement.hh
@@ -1,216 +1,216 @@
/** \file MatrixElement.hh
* \brief The header file which contains the MatrixElement Class
*
* This contains the MatrixElement Class which contains many functions
* used to calculate many different MatrixElements and their components.
*/
#pragma once
#include <functional>
#include "RHEJ/config.hh"
#include "RHEJ/utility.hh"
#include "RHEJ/HiggsCouplingSettings.hh"
#include "CLHEP/Vector/LorentzVector.h"
namespace RHEJ{
/** \class MatrixElement MatrixElement.hh "include/RHEJ/MatrixElement.hh
* \brief MatrixElement class. Functions for obtaining various ME and components.
*/
class MatrixElement{
public:
/** \brief MatrixElement Constructor
* @param alpha_s Function taking the renormalisation scale
* and returning the strong coupling constant
* @param conf General matrix element settings
*/
MatrixElement(
std::function<double (double)> alpha_s,
MatrixElementConfig conf
);
/**
* \brief regulated HEJ matrix element
* @param mur Value of the renormalisation scale
* @param incoming Incoming particles
* @param partons Outgoing particles
* @param check_momenta Special treatment for partons inside extremal jets
* @returns The HEJ matrix element including virtual corrections
*
* cf. eq. (22) in \ref Andersen:2011hs
* Incoming particles should be ordered by ascending z momentum.
* Outgoing particles should be ordered by ascending rapidity.
*
* \internal Relation to standard HEJ Met2: MatrixElement = Met2*shat^2/(pdfta*pdftb)
*/
double operator()(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
//! HEJ tree-level matrix element
/**
* @param mur Value of the renormalisation scale
* @param incoming Incoming particles
* @param outgoing Outgoing particles
* @param check_momenta Special treatment for partons inside extremal jets
* @returns The HEJ matrix element without virtual corrections
*
* cf. eq. (22) in \ref Andersen:2011hs
* Incoming particles should be ordered by ascending z momentum.
* Outgoing particles should be ordered by ascending rapidity.
*/
double tree(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
//! HEJ tree-level matrix element - parametric part
/**
* @param mur Value of the renormalisation scale
* @param outgoing Outgoing particles
* @returns The parametric part of the tree matrix element
*
* cf. eq. (22) in \ref Andersen:2011hs
*
* The tree level matrix element factorises into a parametric part
* which depends on the theory parameters (alpha_s and scale)
* and a kinematic part comprising the dependence on the particle momenta
* and colour factors. This function returns the former.
*/
double tree_param(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
) const;
//! HEJ tree-level matrix element - kinematic part
/**
* @param incoming Incoming particles
* @param partons Outgoing particles
* @param check_momenta Special treatment for partons inside extremal jets
* @returns The kinematic part of the tree matrix element
*
* cf. eq. (22) in \ref Andersen:2011hs
* Incoming particles should be ordered by ascending z momentum.
* Outgoing particles should be ordered by ascending rapidity.
*
* The tree level matrix element factorises into a parametric part
* which depends on the theory parameters (alpha_s and scale)
* and a kinematic part comprising the dependence on the particle momenta
* and colour factors. This function returns the latter.
*/
double tree_kin(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
/**
* \brief Calculates the Virtual Corrections
* @param mur Value of the renormalisation scale
* @param in Incoming particles
* @param out Outgoing particles
* @returns The Virtual Corrections of the Matrix Element
*
* Incoming particles should be ordered by ascending z momentum.
* Outgoing particles should be ordered by ascending rapidity.
*
* The all order virtual corrections to LL in the MRK limit is
* given by replacing 1/t in the scattering amplitude according to the
* lipatov ansatz.
*
* cf. second-to-last line of eq. (22) in \ref Andersen:2011hs
* note that indices are off by one, i.e. out[0].p corresponds to p_1
*/
double virtual_corrections(
double mur,
- std::array<Sparticle, 2> const & in,
- std::vector<Sparticle> const & out
+ std::array<Particle, 2> const & in,
+ std::vector<Particle> const & out
) const;
private:
/**
* \brief cf. last line of eq. (22) in \ref Andersen:2011hs
* @param mur Value of Renormalisation Scale
* @param q_j ???
* @param lambda ???
*/
double omega0(
double alpha_s, double mur,
fastjet::PseudoJet const & q_j, double lambda
) const;
double tree_kin_jets(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> partons,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> partons,
bool check_momenta
) const;
double tree_kin_Higgs(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
double tree_kin_Higgs_first(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
double tree_kin_Higgs_last(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
/**
* \brief Higgs inbetween extremal partons.
*
* Note that in the case of unordered emission, the Higgs is *always*
* treated as if in between the extremal (FKL) partons, even if its
* rapidity is outside the extremal parton rapidities
*/
double tree_kin_Higgs_between(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const;
double tree_param_partons(
double alpha_s, double mur,
- std::vector<Sparticle> const & partons
+ std::vector<Particle> const & partons
) const;
std::vector<int> in_extremal_jet_indices(
std::vector<fastjet::PseudoJet> const & partons
) const;
- std::vector<Sparticle> tag_extremal_jet_partons(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> out_partons, bool check_momenta
+ std::vector<Particle> tag_extremal_jet_partons(
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> out_partons, bool check_momenta
) const;
double MH2_forwardH(
RHEJ::ParticleID id,
CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
CLHEP::HepLorentzVector pH,
double t1, double t2
) const;
std::function<double (double)> alpha_s_;
MatrixElementConfig param_;
};
}
diff --git a/include/RHEJ/PhaseSpacePoint.hh b/include/RHEJ/PhaseSpacePoint.hh
index c91f9f6..f317304 100644
--- a/include/RHEJ/PhaseSpacePoint.hh
+++ b/include/RHEJ/PhaseSpacePoint.hh
@@ -1,156 +1,156 @@
/** \file PhaseSpacePoint.hh
* \brief Contains the PhaseSpacePoint Class
*/
#pragma once
#include <vector>
#include "RHEJ/utility.hh"
#include "RHEJ/config.hh"
#include "RHEJ/Event.hh"
#include "RHEJ/Splitter.hh"
#include "RHEJ/RNG.hh"
namespace RHEJ{
//! A point in resummation phase space
class PhaseSpacePoint{
public:
//! Default PhaseSpacePoint Constructor
PhaseSpacePoint() = default;
//! PhaseSpacePoint Constructor
/**
* @param ev Clustered Jet Event
* @param conf Configuration parameters
*/
PhaseSpacePoint(
Event const & ev,
PhaseSpacePointConfig conf,
RHEJ::RNG & ran
);
//! Get Weight Function
/**
* @returns Weight of Event
*/
double weight() const{
return weight_;
}
//! Get Incoming Function
/**
* @returns Incoming Particles
*/
- std::array<Sparticle, 2> const & incoming() const{
+ std::array<Particle, 2> const & incoming() const{
return incoming_;
}
//! Get Outgoing Function
/**
* @returns Outgoing Particles
*/
- std::vector<Sparticle> const & outgoing() const{
+ std::vector<Particle> const & outgoing() const{
return outgoing_;
}
- std::unordered_map<int, std::vector<Sparticle>> const & decays() const{
+ std::unordered_map<int, std::vector<Particle>> const & decays() const{
return decays_;
}
static constexpr int ng_max = 1000; //< maximum number of extra gluons
static void reset_ranlux(std::string const & init_file);
static void reset_ranlux(char const * init_file);
private:
std::vector<fastjet::PseudoJet> cluster_jets(
std::vector<fastjet::PseudoJet> const & partons
) const;
bool pass_resummation_cuts(
std::vector<fastjet::PseudoJet> const & jets
) const;
bool pass_extremal_cuts(
fastjet::PseudoJet const & ext_parton,
fastjet::PseudoJet const & jet
) const;
int sample_ng(std::vector<fastjet::PseudoJet> const & Born_jets);
int sample_ng_jets(int ng, std::vector<fastjet::PseudoJet> const & Born_jets);
double probability_in_jet(
std::vector<fastjet::PseudoJet> const & Born_jets
) const;
std::vector<fastjet::PseudoJet> gen_non_jet(
int ng_non_jet,
double ptmin, double ptmax
);
void rescale_rapidities(
std::vector<fastjet::PseudoJet> & partons,
double ymin, double ymax
);
std::vector<fastjet::PseudoJet> reshuffle(
std::vector<fastjet::PseudoJet> const & Born_jets,
fastjet::PseudoJet const & q
);
bool jets_ok(
std::vector<fastjet::PseudoJet> const & Born_jets,
std::vector<fastjet::PseudoJet> const & partons
) const;
- void reconstruct_incoming(std::array<Sparticle, 2> const & Born_incoming);
+ void reconstruct_incoming(std::array<Particle, 2> const & Born_incoming);
double phase_space_normalisation(
int num_Born_jets,
int num_res_partons
) const;
std::vector<fastjet::PseudoJet> split(
std::vector<fastjet::PseudoJet> const & jets, int ng_jets
);
std::vector<int> distribute_jet_partons(
int ng_jets, std::vector<fastjet::PseudoJet> const & jets
);
std::vector<fastjet::PseudoJet> split(
std::vector<fastjet::PseudoJet> const & jets,
std::vector<int> const & np_in_jet
);
bool split_preserved_jets(
std::vector<fastjet::PseudoJet> const & jets,
std::vector<fastjet::PseudoJet> const & jet_partons
) const;
template<class Particle>
Particle const & most_backward_FKL(
std::vector<Particle> const & partons
) const;
template<class Particle>
Particle const & most_forward_FKL(
std::vector<Particle> const & partons
) const;
template<class Particle>
Particle & most_backward_FKL(std::vector<Particle> & partons) const;
template<class Particle>
Particle & most_forward_FKL(std::vector<Particle> & partons) const;
bool extremal_ok(
std::vector<fastjet::PseudoJet> const & partons
) const;
void copy_AWZH_boson_from(Event const & event);
bool momentum_conserved() const;
bool unob_, unof_;
double weight_;
PhaseSpacePointConfig param_;
- std::array<Sparticle, 2> incoming_;
- std::vector<Sparticle> outgoing_;
+ std::array<Particle, 2> incoming_;
+ std::vector<Particle> outgoing_;
//! Particle decays in the format {outgoing index, decay products}
- std::unordered_map<int, std::vector<Sparticle>> decays_;
+ std::unordered_map<int, std::vector<Particle>> decays_;
std::reference_wrapper<RHEJ::RNG> ran_;
HejSplit splitter_;
};
}
diff --git a/include/RHEJ/kinematics.hh b/include/RHEJ/kinematics.hh
index e882fde..a8e86c0 100644
--- a/include/RHEJ/kinematics.hh
+++ b/include/RHEJ/kinematics.hh
@@ -1,21 +1,21 @@
/** \file kinematics.hh
* \brief Contains function to compute the incoming momentum from outgoing.
*/
#pragma once
#include <tuple>
#include <vector>
namespace fastjet{
class PseudoJet;
}
namespace RHEJ{
- class Sparticle;
+ class Particle;
/** \brief incoming_momenta function to compute the incoming momentum from momentum conservation.
*/
std::tuple<fastjet::PseudoJet, fastjet::PseudoJet> incoming_momenta(
- std::vector<Sparticle> const & outgoing /**< Outgoing particles */
+ std::vector<Particle> const & outgoing /**< Outgoing particles */
);
}
diff --git a/include/RHEJ/uno.hh b/include/RHEJ/uno.hh
index 80637ee..f90d23c 100644
--- a/include/RHEJ/uno.hh
+++ b/include/RHEJ/uno.hh
@@ -1,74 +1,74 @@
/** \file uno.hh
* \brief Some boolean functions for determining if event is unordered.
*/
#pragma once
#include "RHEJ/utility.hh"
#include "RHEJ/PDG_codes.hh"
namespace RHEJ{
//! Unordered Classification Front Leg
/**
* @param incoming Incoming Particles
* @param outgoing Outgoing Particles
* @returns 0 or 1 depending if classifed as unob_gluon event
*
* This is a test applied to the most forwards (in terms of rapidity) jet.
* If the initial state leg is not a gluon, and the final state leg corresponding
* to that is a gluon then the even is deemed to be an unob_gluon event.
* This assumes that the event being tested is an FKL event wih at most
* one unordered emission.
*/
inline
bool has_unob_gluon(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
){
return incoming.front().type != pid::gluon
&& outgoing.front().type == pid::gluon;
}
//! Unordered Classification Back Leg
/**
* @param incoming Incoming Particles
* @param outgoing Outgoing Particles
* @returns 0 or 1 depending if classifed as unof_gluon event
*
* This is a test applied to the most backwards (in terms of rapidity) jet.
* If the initial state leg is not a gluon, and the final state leg corresponding
* to that is a gluon then the even is deemed to be an unob_gluon event.
* This assumes that the event being tested is an FKL event wih at most
* one unordered emission.
*/
inline
bool has_unof_gluon(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
){
return incoming.back().type != pid::gluon
&& outgoing.back().type == pid::gluon;
}
//! Unordered Classification
/**
* @param incoming Incoming Particles
* @param outgoing Outgoing Particles
* @returns 0 or 1 depending if classifed as unordered event
*
* This combined the functions has_unob_gluon and has_unof_gluon to see either leg
* has an unordered emission.
* This assumes that the event being tested is an FKL event wih at most
* one unordered emission.
*/
inline
bool has_uno_gluon(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
){
return
has_unob_gluon(incoming, outgoing) || has_unof_gluon(incoming, outgoing);
}
}
diff --git a/include/RHEJ/utility.hh b/include/RHEJ/utility.hh
index 412ffdb..33ae3c1 100644
--- a/include/RHEJ/utility.hh
+++ b/include/RHEJ/utility.hh
@@ -1,145 +1,145 @@
/**
* \file utility.hh
* Author: Tuomas Hapola
- * \brief Contains the struct Sparticle which contains particle information and parameters.
+ * \brief Contains the struct Particle which contains particle information and parameters.
*
* Also contains some functions which are useful for comparison on particles parameters.
*/
#pragma once
#include <algorithm>
#include <boost/core/demangle.hpp>
// FastJet Includes
#include "fastjet/PseudoJet.hh"
#include "fastjet/ClusterSequence.hh"
#include "RHEJ/PDG_codes.hh"
namespace RHEJ{
- /** \struct Sparticle utility.hh "include/RHEJ/utility.hh"
+ /** \struct Particle utility.hh "include/RHEJ/utility.hh"
* \brief The struct which contains all the parameters of a particle.
*
* Constituted by PiD and PseudoJet Objects.
*/
- struct Sparticle {
+ struct Particle {
ParticleID type;
fastjet::PseudoJet p;
//! get rapidity function
double rapidity() const{
return p.rapidity();
}
//! get perp function
double perp() const{
return p.perp();
}
//! get Px function
double px() const{
return p.px();
}
//! get Py function
double py() const{
return p.py();
}
//! Get Pz function
double pz() const{
return p.pz();
}
//! Get P0 function
double E() const{
return p.E();
}
//! Get particle mass
double m() const{
return p.m();
}
};
/** \struct rapidity_less utility.hh "include/RHEJ/utility.hh
* \brief A struct which allows quick comparison of two different jets rapidities.
*/
struct rapidity_less{
template<class FourVector>
bool operator()(FourVector const & p1, FourVector const & p2){
return p1.rapidity() < p2.rapidity();
}
};
/** \struct pz_less utility.hh "include/RHEJ/utility.hh
* \brief A struct which allows quick comparison of Pz between two jets.
*/
struct pz_less{
template<class FourVector>
bool operator()(FourVector const & p1, FourVector const & p2){
return p1.pz() < p2.pz();
}
};
inline
std::vector<fastjet::PseudoJet> to_PseudoJet(
- std::vector<Sparticle> const & v
+ std::vector<Particle> const & v
){
std::vector<fastjet::PseudoJet> result;
for(auto && sp: v) result.emplace_back(sp.p);
return result;
}
inline
- bool is_parton(Sparticle const & p){
+ bool is_parton(Particle const & p){
return is_parton(p.type);
}
- inline bool is_AWZH_boson(Sparticle const & particle){
+ inline bool is_AWZH_boson(Particle const & particle){
return is_AWZH_boson(particle.type);
}
inline
- std::vector<Sparticle> filter_partons(
- std::vector<Sparticle> const & v
+ std::vector<Particle> filter_partons(
+ std::vector<Particle> const & v
){
- std::vector<Sparticle> result;
+ std::vector<Particle> result;
result.reserve(v.size());
std::copy_if(
begin(v), end(v), std::back_inserter(result),
- [](Sparticle const & p){ return is_parton(p); }
+ [](Particle const & p){ return is_parton(p); }
);
return result;
}
template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... a){
return std::unique_ptr<T>{new T{std::forward<Args>(a)...}};
}
template<typename T, typename... U>
constexpr
std::array<T, 1 + sizeof...(U)> make_array(T t, U&&... rest){
return {{t, std::forward<U>(rest)...}};
}
inline
std::string join(
std::string const & /* delim */, std::string const & str
){
return str;
}
template<typename... Strings>
std::string join(
std::string const & delim,
std::string const & first, std::string const & second,
Strings&&... rest
){
return join(delim, first + delim + second, std::forward<Strings>(rest)...);
}
template<typename T>
std::string type_string(T&&){
return boost::core::demangle(typeid(T).name());
}
}
diff --git a/src/Event.cc b/src/Event.cc
index 0886a63..0995f25 100644
--- a/src/Event.cc
+++ b/src/Event.cc
@@ -1,343 +1,343 @@
#include "RHEJ/Event.hh"
#include "RHEJ/debug.hh"
namespace RHEJ{
namespace{
constexpr int status_in = -1;
constexpr int status_decayed = 2;
constexpr int status_out = 1;
// helper functions to determine event type
// 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<Sparticle> const & outgoing){
+ 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, [](Sparticle const & p){return is_AWZH_boson(p);}
+ 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, [](Sparticle const & s){return is_AWZH_boson(s);}
+ begin, end, [](Particle const & s){return is_AWZH_boson(s);}
) < 2;
}
// 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);
// Test if this is a standard FKL configuration.
return
(begin_incoming->type == begin_outgoing->type)
&& ((end_incoming-1)->type == (end_outgoing-1)->type)
&& std::all_of(
begin_outgoing + 1, end_outgoing - 1,
- [](Sparticle const & p){ return p.type == pid::gluon; }
+ [](Particle const & p){ return p.type == pid::gluon; }
);
}
bool is_FKL(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> outgoing
){
assert(std::is_sorted(begin(incoming), end(incoming), pz_less{}));
assert(valid_outgoing(begin(outgoing), end(outgoing)));
return is_FKL(
begin(incoming), end(incoming),
begin(outgoing), end(outgoing)
);
}
bool has_2_jets(Event const & event){
return event.jets().size() >= 2;
}
/**
* \brief Checks whether event is unordered backwards
* @param ev Event
* @returns Is Event Unordered Backwards
*
* Checks there is more than 3 constuents in the final state
* Checks there is more than 3 jets
* Checks the most backwards parton is a gluon
* Checks the most forwards jet is not a gluon
* Checks the rest of the event is FKL
* Checks the second most backwards is not a different boson
* Checks the unordered gluon actually forms a jet
*/
bool is_unordered_backward(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.front().type == pid::gluon) return false;
if(out.front().type != pid::gluon) return false;
// When skipping the unordered emission
// the remainder should be a regular FKL event,
// except that the (new) first outgoing particle must not be a A,W,Z,H.
const auto FKL_begin = next(begin(out));
if(is_AWZH_boson(*FKL_begin)) return false;
if(!is_FKL(in, {FKL_begin, end(out)})) return false;
// check that the unordered gluon forms an extra jet
const auto jets = sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets.front()});
return indices[0] >= 0 && indices[1] == -1;
}
/**
* \brief Checks for a forward unordered gluon emission
* @param ev Event
* @returns Is the event a forward unordered emission
*
* \see is_unordered_backward
*/
bool is_unordered_forward(Event const & ev){
auto const & in = ev.incoming();
auto const & out = ev.outgoing();
assert(std::is_sorted(begin(in), end(in), pz_less{}));
assert(valid_outgoing(begin(out), end(out)));
if(out.size() < 3) return false;
if(ev.jets().size() < 3) return false;
if(in.back().type == pid::gluon) return false;
if(out.back().type != pid::gluon) return false;
// When skipping the unordered emission
// the remainder should be a regular FKL event,
// except that the (new) last outgoing particle must not be a A,W,Z,H.
const auto FKL_end = prev(end(out));
if(is_AWZH_boson(*prev(FKL_end))) return false;
if(!is_FKL(in, {begin(out), FKL_end})) return false;
// check that the unordered gluon forms an extra jet
const auto jets = sorted_by_rapidity(ev.jets());
const auto indices = ev.particle_jet_indices({jets.back()});
return indices.back() >= 0 && indices[indices.size()-2] == -1;
}
using event_type::EventType;
EventType classify(Event const & ev){
if(! final_state_ok(ev.outgoing())) return EventType::bad_final_state;
if(! has_2_jets(ev)) return EventType::no_2_jets;
if(is_FKL(ev.incoming(), ev.outgoing())) return EventType::FKL;
if(is_unordered_backward(ev)){
return EventType::unordered_backward;
}
if(is_unordered_forward(ev)){
return EventType::unordered_forward;
}
return EventType::nonHEJ;
}
- Sparticle extract_particle(LHEF::HEPEUP const & hepeup, int i){
- return Sparticle{
+ Particle extract_particle(LHEF::HEPEUP const & hepeup, int i){
+ return Particle{
static_cast<ParticleID>(hepeup.IDUP[i]),
fastjet::PseudoJet{
hepeup.PUP[i][0], hepeup.PUP[i][1],
hepeup.PUP[i][2], hepeup.PUP[i][3]
}
};
}
bool is_decay_product(std::pair<int, int> const & mothers){
if(mothers.first == 0) return false;
return mothers.second == 0 || mothers.first == mothers.second;
}
}
UnclusteredEvent::UnclusteredEvent(LHEF::HEPEUP const & hepeup):
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));
}
std::sort(
begin(incoming), end(incoming),
- [](Sparticle o1, Sparticle o2){return o1.p.pz()<o2.p.pz();}
+ [](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
);
std::sort(begin(outgoing), end(outgoing), rapidity_less{});
// 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](Sparticle const & particle){
+ [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 ev,
fastjet::JetDefinition const & jet_def, double min_jet_pt
):
ev_{std::move(ev)},
cs_{to_PseudoJet(filter_partons(ev_.outgoing)), jet_def},
min_jet_pt_{min_jet_pt}
{
type_ = classify(*this);
}
std::vector<fastjet::PseudoJet> Event::jets() const{
return cs_.inclusive_jets(min_jet_pt_);
}
/**
* \brief Returns the invarient mass of the event
* @param ev Event
* @returns s hat
*
* Makes use of the FastJet PseudoJet function m2().
* Applies this function to the sum of the incoming partons.
*/
double shat(Event const & ev){
return (ev.incoming()[0].p + ev.incoming()[1].p).m2();
}
namespace{
// colour flow according to Les Houches standard
// TODO: stub
std::vector<std::pair<int, int>> colour_flow(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
){
std::vector<std::pair<int, int>> result(
incoming.size() + outgoing.size()
);
for(auto & col: result){
col = std::make_pair(-1, -1);
}
return result;
}
}
LHEF::HEPEUP to_HEPEUP(Event const & event, LHEF::HEPRUP * heprup){
LHEF::HEPEUP result;
result.heprup = heprup;
result.weights = {{event.central().weight, nullptr}};
for(auto const & var: event.variations()){
result.weights.emplace_back(var.weight, nullptr);
}
size_t num_particles = event.incoming().size() + event.outgoing().size();
for(auto const & decay: event.decays()) num_particles += decay.second.size();
result.NUP = num_particles;
// the following entries are pretty much meaningless
result.IDPRUP = event.type()+1; // event ID
result.AQEDUP = 1./128.; // alpha_EW
//result.AQCDUP = 0.118 // alpha_QCD
// end meaningless part
result.XWGTUP = event.central().weight;
result.SCALUP = event.central().muf;
result.scales.muf = event.central().muf;
result.scales.mur = event.central().mur;
result.scales.SCALUP = event.central().muf;
result.pdfinfo.p1 = event.incoming().front().type;
result.pdfinfo.p2 = event.incoming().back().type;
result.pdfinfo.scale = event.central().muf;
- for(Sparticle const & in: event.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);
}
for(size_t i = 0; i < event.outgoing().size(); ++i){
- Sparticle const & out = event.outgoing()[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);
}
result.ICOLUP = colour_flow(
event.incoming(), filter_partons(event.outgoing())
);
if(result.ICOLUP.size() < num_particles){
const size_t AWZH_boson_idx = std::find_if(
begin(event.outgoing()), end(event.outgoing()),
- [](Sparticle const & s){ return is_AWZH_boson(s); }
+ [](Particle const & s){ return is_AWZH_boson(s); }
) - begin(event.outgoing()) + event.incoming().size();
assert(AWZH_boson_idx <= result.ICOLUP.size());
result.ICOLUP.insert(
begin(result.ICOLUP) + AWZH_boson_idx,
std::make_pair(0,0)
);
}
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 int 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/EventReweighter.cc b/src/EventReweighter.cc
index c988b49..34c8d34 100644
--- a/src/EventReweighter.cc
+++ b/src/EventReweighter.cc
@@ -1,281 +1,281 @@
#include "RHEJ/EventReweighter.hh"
#include <string>
#include <unordered_map>
#include "RHEJ/PhaseSpacePoint.hh"
#include "RHEJ/PDG_codes.hh"
#include "RHEJ/debug.hh"
namespace RHEJ{
using EventType = event_type::EventType;
namespace {
static_assert(
std::numeric_limits<double>::has_quiet_NaN,
"no quiet NaN for double"
);
constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
UnclusteredEvent to_UnclusteredEvent(PhaseSpacePoint const & psp){
UnclusteredEvent result;
result.incoming = psp.incoming();
std::sort(
begin(result.incoming), end(result.incoming),
- [](Sparticle o1, Sparticle o2){return o1.p.pz()<o2.p.pz();}
+ [](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
);
assert(result.incoming.size() == 2);
result.outgoing = psp.outgoing();
assert(
std::is_sorted(
begin(result.outgoing), end(result.outgoing),
rapidity_less{}
)
);
assert(result.outgoing.size() >= 2);
result.decays = psp.decays();
result.central.mur = NaN;
result.central.muf = NaN;
result.central.weight = psp.weight();
return result;
}
} // namespace anonymous
EventReweighter::EventReweighter(
LHEF::HEPRUP const & heprup,
ScaleGenerator scale_gen,
EventReweighterConfig conf,
RHEJ::RNG & ran
):
EventReweighter{
RHEJ::Beam{
heprup.EBMUP.first,
{{
static_cast<RHEJ::ParticleID>(heprup.IDBMUP.first),
static_cast<RHEJ::ParticleID>(heprup.IDBMUP.second)
}}
},
heprup.PDFSUP.first,
std::move(scale_gen),
std::move(conf),
ran
}
{
if(heprup.EBMUP.second != E_beam_){
throw std::invalid_argument(
"asymmetric beam: " + std::to_string(E_beam_)
+ " ---> <--- " + std::to_string(heprup.EBMUP.second)
);
};
if(heprup.PDFSUP.second != pdf_.id()){
throw std::invalid_argument(
"conflicting PDF ids: " + std::to_string(pdf_.id())
+ " vs. " + std::to_string(heprup.PDFSUP.second)
);
}
}
EventReweighter::EventReweighter(
Beam beam,
int pdf_id,
ScaleGenerator scale_gen,
EventReweighterConfig conf,
RHEJ::RNG & ran
):
param_{std::move(conf)},
E_beam_{beam.E},
pdf_{pdf_id, beam.type.front(), beam.type.back()},
MEt2_{
[this](double mu){ return pdf_.Halphas(mu); },
param_.ME_config
},
scale_gen_(std::move(scale_gen)),
ran_{ran}
{}
PDF const & EventReweighter::pdf() const{
return pdf_;
}
std::vector<Event> EventReweighter::reweight(
Event const & input_ev, int num_events
){
auto res_events = gen_res_events(input_ev, num_events);
if(res_events.empty()) return {};
for(auto & event: res_events) event = scale_gen_(event);
return rescale(input_ev, std::move(res_events));
}
/**
* \brief main generation/reweighting function:
* generate phase space points and divide out Born factors
*/
std::vector<Event> EventReweighter::gen_res_events(
Event const & ev,
int phase_space_points
){
assert(ev.variations().empty());
switch(param_.treat.at(ev.type())){
case EventTreatment::discard: return {};
case EventTreatment::keep:
if(! jets_pass_resummation_cuts(ev)) return {};
else return {ev};
default:;
}
const double Born_shat = shat(ev);
std::vector<Event> resummation_events;
for(int psp_number = 0; psp_number < phase_space_points; ++psp_number){
PhaseSpacePoint psp{ev, param_.psp_config, ran_};
if(psp.weight() == 0.) continue;
if(psp.incoming()[0].E() > E_beam_ || psp.incoming()[1].E() > E_beam_) continue;
resummation_events.emplace_back(
to_UnclusteredEvent(std::move(psp)),
param_.jet_param.def, param_.jet_param.min_pt
);
auto & new_event = resummation_events.back();
assert(new_event.variations().empty());
new_event.central().mur = ev.central().mur;
new_event.central().muf = ev.central().muf;
const double resum_shat = shat(new_event);
new_event.central().weight *= ev.central().weight*Born_shat*Born_shat/
(phase_space_points*resum_shat*resum_shat);
}
return resummation_events;
}
std::vector<Event> EventReweighter::rescale(
Event const & Born_ev,
std::vector<Event> events
) const{
const double Born_pdf = pdf_factors(Born_ev).central;
const double Born_ME = tree_matrix_element(Born_ev);
for(auto & cur_event: events){
const auto pdf = pdf_factors(cur_event);
assert(pdf.variations.size() == cur_event.variations().size());
const auto ME = matrix_elements(cur_event);
assert(ME.variations.size() == cur_event.variations().size());
cur_event.central().weight *= pdf.central*ME.central/(Born_pdf*Born_ME);
for(size_t i = 0; i < cur_event.variations().size(); ++i){
cur_event.variations(i).weight *=
pdf.variations[i]*ME.variations[i]/(Born_pdf*Born_ME);
}
}
return events;
};
bool EventReweighter::jets_pass_resummation_cuts(
Event const & ev
) const{
const auto out_as_PseudoJet = to_PseudoJet(filter_partons(ev.outgoing()));
fastjet::ClusterSequence cs{out_as_PseudoJet, param_.jet_param.def};
return cs.inclusive_jets(param_.jet_param.min_pt).size() == ev.jets().size();
}
EventReweighter::EventFactors
EventReweighter::pdf_factors(Event const & ev) const{
auto const & a = ev.incoming().front();
auto const & b = ev.incoming().back();
const double xa = a.p.e()/E_beam_;
const double xb = b.p.e()/E_beam_;
EventFactors result;
std::unordered_map<double, double> known_pdf;
result.central =
pdf_.pdfpt(0,xa,ev.central().muf,a.type)*
pdf_.pdfpt(1,xb,ev.central().muf,b.type);
known_pdf.emplace(ev.central().muf, result.central);
result.variations.reserve(ev.variations().size());
for(auto const & ev_param: ev.variations()){
const double muf = ev_param.muf;
auto cur_pdf = known_pdf.find(muf);
if(cur_pdf == known_pdf.end()){
cur_pdf = known_pdf.emplace(
muf,
pdf_.pdfpt(0,xa,muf,a.type)*pdf_.pdfpt(1,xb,muf,b.type)
).first;
}
result.variations.emplace_back(cur_pdf->second);
}
assert(result.variations.size() == ev.variations().size());
return result;
}
EventReweighter::EventFactors
EventReweighter::matrix_elements(Event const & ev) const{
assert(param_.treat.count(ev.type()) > 0);
if(param_.treat.find(ev.type())->second == EventTreatment::keep){
return fixed_order_scale_ME(ev);
}
// precompute overall kinematic factor
const double ME_kin = MEt2_.tree_kin(ev.incoming(), ev.outgoing(), true);
EventFactors result;
std::unordered_map<double, double> known_ME;
result.central = MEt2_(
ev.central().mur,
ev.incoming(), ev.outgoing(),
true
);
known_ME.emplace(ev.central().mur, result.central);
result.variations.reserve(ev.variations().size());
for(auto const & param: ev.variations()){
const double mur = param.mur;
auto cur_ME = known_ME.find(mur);
if(cur_ME == known_ME.end()){
const double ME = MEt2_.tree_param(
mur, ev.incoming(), ev.outgoing()
)*ME_kin*MEt2_.virtual_corrections(
mur, ev.incoming(), ev.outgoing()
);
cur_ME = known_ME.emplace(mur, ME).first;
}
result.variations.emplace_back(cur_ME->second);
}
assert(result.variations.size() == ev.variations().size());
return result;
}
double EventReweighter::tree_matrix_element(Event const & ev) const{
assert(ev.variations().empty());
assert(param_.treat.count(ev.type()) > 0);
if(param_.treat.find(ev.type())->second == EventTreatment::keep){
return fixed_order_scale_ME(ev).central;
}
return MEt2_.tree(
ev.central().mur,
ev.incoming(), ev.outgoing(),
false
);
}
EventReweighter::EventFactors
EventReweighter::fixed_order_scale_ME(Event const & ev) const{
const int alpha_s_power = std::count_if(
begin(ev.outgoing()), end(ev.outgoing()),
- [](Sparticle const & p){ return is_parton(p); }
+ [](Particle const & p){ return is_parton(p); }
);
EventFactors result;
result.central = pow(pdf_.Halphas(ev.central().mur), alpha_s_power);
for(auto const & var: ev.variations()){
result.variations.emplace_back(
pow(pdf_.Halphas(var.mur), alpha_s_power)
);
}
return result;
}
}
diff --git a/src/HepMCInterface.cc b/src/HepMCInterface.cc
index 1650922..7160ef3 100644
--- a/src/HepMCInterface.cc
+++ b/src/HepMCInterface.cc
@@ -1,144 +1,144 @@
#include "RHEJ/HepMCInterface.hh"
#include <cassert>
#ifdef RHEJ_BUILD_WITH_HepMC_VERSION
#include "RHEJ/Event.hh"
#include "HepMC/GenEvent.h"
#include "HepMC/GenVertex.h"
#include "HepMC/GenParticle.h"
#include "HepMC/GenCrossSection.h"
#include "LHEF/LHEF.h"
namespace RHEJ{
namespace {
- HepMC::FourVector to_FourVector(Sparticle const & sp){
+ HepMC::FourVector to_FourVector(Particle const & sp){
return {sp.px(), sp.py(), sp.pz(), sp.E()};
}
constexpr int status_in = -1;
constexpr int status_decayed = 3;
constexpr int status_out = 1;
template<class HepMCClass, typename... Args>
auto make_ptr(Args&&... args){
#if RHEJ_BUILD_WITH_HepMC_VERSION >= 3
return HepMC::make_shared<HepMCClass>(std::forward<Args>(args)...);
#else
return new HepMCClass(std::forward<Args>(args)...);
#endif
}
} // namespace anonymous
HepMCInterface::HepMCInterface():
event_count_(0.), tot_weight_(0.), tot_weight2_(0.)
{}
void HepMCInterface::add_weight(double const wt){
++event_count_;
tot_weight_ += wt;
tot_weight2_ += wt * wt;
}
HepMC::GenCrossSection HepMCInterface::cross_section() const {
HepMC::GenCrossSection xs;
#if RHEJ_BUILD_WITH_HepMC_VERSION >= 3
xs.set_cross_section(tot_weight_, sqrt(tot_weight2_), event_count_);
/// @TODO add number of attempted events
#else // HepMC 2
xs.set_cross_section(tot_weight_, sqrt(tot_weight2_));
#endif
return xs;
}
HepMC::GenEvent HepMCInterface::operator()(Event const & event, size_t const weight_index){
HepMC::GenEvent out_ev{HepMC::Units::GEV, HepMC::Units::MM};
auto vx = make_ptr<HepMC::GenVertex>();
for(auto const & in: event.incoming()){
vx->add_particle_in(
make_ptr<HepMC::GenParticle>(
to_FourVector(in), static_cast<int>(in.type), status_in
)
);
}
for(int i=0; i< (int) event.outgoing().size(); ++i){
auto const & out = event.outgoing()[i];
auto particle = make_ptr<HepMC::GenParticle>(
to_FourVector(out), static_cast<int>(out.type), status_out
);
const int status = event.decays().count(i)?status_decayed:status_out;
particle->set_status(status);
if( status == status_decayed){
auto vx_decay = make_ptr<HepMC::GenVertex>();
vx_decay->add_particle_in(particle);
for( auto const & out: event.decays().at(i)){
vx_decay->add_particle_out(
make_ptr<HepMC::GenParticle>(
to_FourVector(out), static_cast<int>(out.type), status_out
)
);
}
out_ev.add_vertex(vx_decay);
}
vx->add_particle_out(particle);
}
out_ev.add_vertex(vx);
// weights
EventParameters central_parameters;
if(event.variations().size() == 0){
central_parameters = event.central();
}
else{
central_parameters = event.variations(weight_index);
}
out_ev.weights().push_back(central_parameters.weight);
for(auto const & var: event.variations()){
out_ev.weights().push_back(var.weight);
}
/// @TODO add name list for weights
// cross section
add_weight(central_parameters.weight);
#if RHEJ_BUILD_WITH_HepMC_VERSION >= 3
out_ev.set_cross_section(
HepMC::make_shared<HepMC::GenCrossSection>(cross_section()) );
#else // HepMC 2
out_ev.set_cross_section( cross_section() );
out_ev.set_signal_process_id(event.type()+1); // "+1": conistent with lhe
out_ev.set_event_scale(central_parameters.mur);
#endif
out_ev.set_event_number(event_count_);
/// @TODO add alphaQCD (need function) and alphaQED
/// @TODO output pdf (currently not avaiable from event alone)
return out_ev;
}
}
#else // no HepMC => empty class
namespace HepMC {
class GenEvent {};
class GenCrossSection {};
}
namespace RHEJ{
HepMCInterface::HepMCInterface(){
throw std::invalid_argument(
"Failed to create HepMCInterface: "
"Reversed HEJ was built without HepMC support"
);
}
HepMC::GenEvent HepMCInterface::operator()(Event const &, size_t)
{return HepMC::GenEvent();}
void HepMCInterface::add_weight(double) {}
HepMC::GenCrossSection HepMCInterface::cross_section() const
{return HepMC::GenCrossSection();}
}
#endif
diff --git a/src/MatrixElement.cc b/src/MatrixElement.cc
index 3ebc3d8..a67bbc3 100644
--- a/src/MatrixElement.cc
+++ b/src/MatrixElement.cc
@@ -1,761 +1,761 @@
#include "RHEJ/MatrixElement.hh"
#include <CLHEP/Random/Randomize.h>
#include <CLHEP/Random/RanluxEngine.h>
#include "RHEJ/Constants.hh"
#include "RHEJ/currents.hh"
#include "RHEJ/PDG_codes.hh"
#include "RHEJ/uno.hh"
#include "RHEJ/debug.hh"
namespace RHEJ{
//cf. last line of eq. (22) in \ref Andersen:2011hs
double MatrixElement::omega0(
double alpha_s, double mur,
fastjet::PseudoJet const & q_j, double lambda
) const {
const double result = - alpha_s*N_C/M_PI*log(q_j.perp2()/(lambda*lambda));
if(! param_.log_correction) return result;
// use alpha_s(sqrt(q_j*lambda)), evolved to mur
return (
1. + alpha_s/(4.*M_PI)*beta0*log(mur*mur/(q_j.perp()*lambda))
)*result;
}
double MatrixElement::virtual_corrections(
double mur,
- std::array<Sparticle, 2> const & in,
- std::vector<Sparticle> const & out
+ std::array<Particle, 2> const & in,
+ std::vector<Particle> const & out
) const{
fastjet::PseudoJet const & pa = in.front().p;
#ifndef NDEBUG
fastjet::PseudoJet const & pb = in.back().p;
double const norm = (in.front().p + in.back().p).E();
#endif
assert(std::is_sorted(out.begin(), out.end(), rapidity_less{}));
assert(out.size() >= 2);
assert(pa.pz() < pb.pz());
fastjet::PseudoJet q = pa - out[0].p;
size_t first_idx = 0;
size_t last_idx = out.size() - 1;
// if there is a Higgs or unordered gluon outside the extremal partons
// then it is not part of the FKL ladder and does not contribute
// to the virtual corrections
if(out.front().type == pid::Higgs || has_unob_gluon(in, out)){
q -= out[1].p;
++first_idx;
}
if(out.back().type == pid::Higgs || has_unof_gluon(in, out)){
--last_idx;
}
double exponent = 0;
const double alpha_s = alpha_s_(mur);
for(size_t j = first_idx; j < last_idx; ++j){
exponent += omega0(alpha_s, mur, q, CLAMBDA)*(
out[j+1].rapidity() - out[j].rapidity()
);
q -= out[j+1].p;
}
assert(
nearby(q, -1*pb, norm)
|| out.back().type == pid::Higgs
|| has_unof_gluon(in, out)
);
return exp(exponent);
}
} // namespace RHEJ
namespace {
//! Lipatov vertex for partons emitted into extremal jets
double C2Lipatov(CLHEP::HepLorentzVector qav, CLHEP::HepLorentzVector qbv,
CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2)
{
CLHEP::HepLorentzVector temptrans=-(qav+qbv);
CLHEP::HepLorentzVector p5=qav-qbv;
CLHEP::HepLorentzVector CL=temptrans
+ p1*(qav.m2()/p5.dot(p1) + 2.*p5.dot(p2)/p1.dot(p2))
- p2*(qbv.m2()/p5.dot(p2) + 2.*p5.dot(p1)/p1.dot(p2));
// cout << "#Fadin qa : "<<qav<<endl;
// cout << "#Fadin qb : "<<qbv<<endl;
// cout << "#Fadin p1 : "<<p1<<endl;
// cout << "#Fadin p2 : "<<p2<<endl;
// cout << "#Fadin p5 : "<<p5<<endl;
// cout << "#Fadin Gauge Check : "<< CL.dot(p5)<<endl;
// cout << "#Fadin C2L : "<< -CL.dot(CL)<<" "<<-CL.dot(CL)/(qav.m2()*qbv.m2())/(4./p5.perp2())<<endl;
// TODO can this dead test go?
// if (-CL.dot(CL)<0.)
// if (fabs(CL.dot(p5))>fabs(CL.dot(CL))) // not sufficient!
// return 0.;
// else
return -CL.dot(CL);
}
//! Lipatov vertex with soft subtraction for partons emitted into extremal jets
double C2Lipatovots(CLHEP::HepLorentzVector qav, CLHEP::HepLorentzVector qbv,
CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2)
{
double kperp=(qav-qbv).perp();
if (kperp>RHEJ::CLAMBDA)
return C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2());
else {
double Cls=(C2Lipatov(qav, qbv, p1, p2)/(qav.m2()*qbv.m2()));
return Cls-4./(kperp*kperp);
}
}
//! Lipatov vertex
double C2Lipatov(CLHEP::HepLorentzVector qav, CLHEP::HepLorentzVector qbv,
CLHEP::HepLorentzVector pim, CLHEP::HepLorentzVector pip,
CLHEP::HepLorentzVector pom, CLHEP::HepLorentzVector pop) // B
{
CLHEP::HepLorentzVector temptrans=-(qav+qbv);
CLHEP::HepLorentzVector p5=qav-qbv;
CLHEP::HepLorentzVector CL=temptrans
+ qav.m2()*(1./p5.dot(pip)*pip + 1./p5.dot(pop)*pop)/2.
- qbv.m2()*(1./p5.dot(pim)*pim + 1./p5.dot(pom)*pom)/2.
+ ( pip*(p5.dot(pim)/pip.dot(pim) + p5.dot(pom)/pip.dot(pom))
+ pop*(p5.dot(pim)/pop.dot(pim) + p5.dot(pom)/pop.dot(pom))
- pim*(p5.dot(pip)/pip.dot(pim) + p5.dot(pop)/pop.dot(pim))
- pom*(p5.dot(pip)/pip.dot(pom) + p5.dot(pop)/pop.dot(pom)) )/2.;
return -CL.dot(CL);
}
//! Lipatov vertex with soft subtraction
double C2Lipatovots(CLHEP::HepLorentzVector qav, CLHEP::HepLorentzVector qbv,
CLHEP::HepLorentzVector pa, CLHEP::HepLorentzVector pb,
CLHEP::HepLorentzVector p1, CLHEP::HepLorentzVector p2)
{
double kperp=(qav-qbv).perp();
if (kperp>RHEJ::CLAMBDA)
return C2Lipatov(qav, qbv, pa, pb, p1, p2)/(qav.m2()*qbv.m2());
else {
double Cls=(C2Lipatov(qav, qbv, pa, pb, p1, p2)/(qav.m2()*qbv.m2()));
double temp=Cls-4./(kperp*kperp);
return temp;
}
}
/** Matrix element squared for tree-level current-current scattering
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @returns ME Squared for Tree-Level Current-Current Scattering
*/
double ME_current(
int aptype, int bptype,
CLHEP::HepLorentzVector const & pn,
CLHEP::HepLorentzVector const & pb,
CLHEP::HepLorentzVector const & p1,
CLHEP::HepLorentzVector const & pa
){
if (aptype==21&&bptype==21) {
return jM2gg(pn,pb,p1,pa);
} else if (aptype==21&&bptype!=21) {
if (bptype > 0)
return jM2qg(pn,pb,p1,pa);
else
return jM2qbarg(pn,pb,p1,pa);
}
else if (bptype==21&&aptype!=21) { // ----- || -----
if (aptype > 0)
return jM2qg(p1,pa,pn,pb);
else
return jM2qbarg(p1,pa,pn,pb);
}
else { // they are both quark
if (bptype>0) {
if (aptype>0)
return jM2qQ(pn,pb,p1,pa);
else
return jM2qQbar(pn,pb,p1,pa);
}
else {
if (aptype>0)
return jM2qQbar(p1,pa,pn,pb);
else
return jM2qbarQbar(pn,pb,p1,pa);
}
}
throw std::logic_error("unknown particle types");
}
/** \brief Matrix element squared for tree-level current-current scattering with Higgs
* @param aptype Particle a PDG ID
* @param bptype Particle b PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param qH t-channel momentum before Higgs
* @param qHp1 t-channel momentum after Higgs
* @returns ME Squared for Tree-Level Current-Current Scattering with Higgs
*/
double ME_Higgs_current(
int aptype, int bptype,
CLHEP::HepLorentzVector const & pn,
CLHEP::HepLorentzVector const & pb,
CLHEP::HepLorentzVector const & p1,
CLHEP::HepLorentzVector const & pa,
CLHEP::HepLorentzVector const & qH, // t-channel momentum before Higgs
CLHEP::HepLorentzVector const & qHp1, // t-channel momentum after Higgs
double mt, bool include_bottom, double mb
){
if (aptype==21&&bptype==21) // gg initial state
return MH2gg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else if (aptype==21&&bptype!=21) {
if (bptype > 0)
return MH2qg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.;
else
return MH2qbarg(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4./9.;
}
else if (bptype==21&&aptype!=21) {
if (aptype > 0)
return MH2qg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.;
else
return MH2qbarg(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4./9.;
}
else { // they are both quark
if (bptype>0) {
if (aptype>0)
return MH2qQ(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.);
else
return MH2qQbar(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.);
}
else {
if (aptype>0)
return MH2qQbar(p1,pa,pn,pb,-qH,-qHp1,mt,include_bottom,mb)*4.*4./(9.*9.);
else
return MH2qbarQbar(pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb)*4.*4./(9.*9.);
}
}
throw std::logic_error("unknown particle types");
}
/** \brief Current matrix element squared with Higgs and unordered forward emission
* @param aptype Particle A PDG ID
* @param bptype Particle B PDG ID
* @param punof Unordered Particle Momentum
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param qH t-channel momentum before Higgs
* @param qHp1 t-channel momentum after Higgs
* @returns ME Squared with Higgs and unordered forward emission
*/
double ME_Higgs_current_unof(
int aptype, int bptype,
CLHEP::HepLorentzVector const & punof,
CLHEP::HepLorentzVector const & pn,
CLHEP::HepLorentzVector const & pb,
CLHEP::HepLorentzVector const & p1,
CLHEP::HepLorentzVector const & pa,
CLHEP::HepLorentzVector const & qH, // t-channel momentum before Higgs
CLHEP::HepLorentzVector const & qHp1, // t-channel momentum after Higgs
double mt, bool include_bottom, double mb
){
if (aptype==21&&bptype!=21) {
if (bptype > 0)
return jM2unogqHg(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unogqbarHg(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
else { // they are both quark
if (bptype>0) {
if (aptype>0)
return jM2unogqHQ(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unogqHQbar(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
else {
if (aptype>0)
return jM2unogqbarHQ(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unogqbarHQbar(punof,pn,pb,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
}
throw std::logic_error("unknown particle types");
}
/** \brief Current matrix element squared with Higgs and unordered backward emission
* @param aptype Particle A PDG ID
* @param bptype Particle B PDG ID
* @param pn Particle n Momentum
* @param pb Particle b Momentum
* @param punob Unordered back Particle Momentum
* @param p1 Particle 1 Momentum
* @param pa Particle a Momentum
* @param qH t-channel momentum before Higgs
* @param qHp1 t-channel momentum after Higgs
* @returns ME Squared with Higgs and unordered backward emission
*/
double ME_Higgs_current_unob(
int aptype, int bptype,
CLHEP::HepLorentzVector const & pn,
CLHEP::HepLorentzVector const & pb,
CLHEP::HepLorentzVector const & punob,
CLHEP::HepLorentzVector const & p1,
CLHEP::HepLorentzVector const & pa,
CLHEP::HepLorentzVector const & qH, // t-channel momentum before Higgs
CLHEP::HepLorentzVector const & qHp1, // t-channel momentum after Higgs
double mt, bool include_bottom, double mb
){
if (bptype==21&&aptype!=21) {
if (aptype > 0)
return jM2unobgHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unobgHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
else { // they are both quark
if (aptype>0) {
if (bptype>0)
return jM2unobqHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unobqbarHQg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
else {
if (bptype>0)
return jM2unobqHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
else
return jM2unobqbarHQbarg(pn,pb,punob,p1,pa,-qHp1,-qH,mt,include_bottom,mb);
}
}
throw std::logic_error("unknown particle types");
}
- CLHEP::HepLorentzVector to_HepLorentzVector(RHEJ::Sparticle const & particle){
+ CLHEP::HepLorentzVector to_HepLorentzVector(RHEJ::Particle const & particle){
return {particle.p.px(), particle.p.py(), particle.p.pz(), particle.p.E()};
}
} // namespace anonymous
namespace RHEJ{
MatrixElement::MatrixElement(
std::function<double (double)> alpha_s,
MatrixElementConfig conf
):
alpha_s_{std::move(alpha_s)},
param_{std::move(conf)}
{}
double MatrixElement::operator()(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
return tree(
mur,
incoming, outgoing,
check_momenta
)*virtual_corrections(
mur,
incoming, outgoing
);
}
double MatrixElement::tree_kin(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
assert(
std::is_sorted(
incoming.begin(), incoming.end(),
- [](Sparticle o1, Sparticle o2){return o1.p.pz()<o2.p.pz();}
+ [](Particle o1, Particle o2){return o1.p.pz()<o2.p.pz();}
)
);
assert(std::is_sorted(outgoing.begin(), outgoing.end(), rapidity_less{}));
auto AWZH_boson = std::find_if(
begin(outgoing), end(outgoing),
- [](Sparticle const & p){return is_AWZH_boson(p);}
+ [](Particle const & p){return is_AWZH_boson(p);}
);
if(AWZH_boson == end(outgoing)){
return tree_kin_jets(incoming, outgoing, check_momenta);
}
switch(AWZH_boson->type){
case pid::Higgs: {
static constexpr double mH = 125.;
const double alpha_s_mH = alpha_s_(mH);
return alpha_s_mH*alpha_s_mH/(256.*pow(M_PI, 5))*tree_kin_Higgs(
incoming, outgoing, check_momenta
);
}
// TODO
case pid::Wp:
case pid::Wm:
case pid::photon:
case pid::Z:
default:
throw std::logic_error("Emission of boson of unsupported type");
}
}
namespace{
constexpr int extremal_jet_idx = 1;
constexpr int no_extremal_jet_idx = 0;
- bool treat_as_extremal(Sparticle const & parton){
+ bool treat_as_extremal(Particle const & parton){
return parton.p.user_index() == extremal_jet_idx;
}
template<class InputIterator>
double FKL_ladder_weight(
InputIterator begin_gluon, InputIterator end_gluon,
CLHEP::HepLorentzVector const & q0,
CLHEP::HepLorentzVector const & pa, CLHEP::HepLorentzVector const & pb,
CLHEP::HepLorentzVector const & p1, CLHEP::HepLorentzVector const & pn
){
double wt = 1;
auto qi = q0;
for(auto gluon_it = begin_gluon; gluon_it != end_gluon; ++gluon_it){
assert(gluon_it->type == pid::gluon);
const auto g = to_HepLorentzVector(*gluon_it);
const auto qip1 = qi - g;
if(treat_as_extremal(*gluon_it)){
wt *= C2Lipatovots(qip1, qi, pa, pb)*C_A;
} else{
wt *= C2Lipatovots(qip1, qi, pa, pb, p1, pn)*C_A;
}
qi = qip1;
}
return wt;
}
} // namespace anonymous
- std::vector<Sparticle> MatrixElement::tag_extremal_jet_partons(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> out_partons, bool check_momenta
+ std::vector<Particle> MatrixElement::tag_extremal_jet_partons(
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> out_partons, bool check_momenta
) const{
if(!check_momenta){
for(auto & parton: out_partons){
parton.p.set_user_index(no_extremal_jet_idx);
}
return out_partons;
}
fastjet::ClusterSequence cs(to_PseudoJet(out_partons), param_.jet_param.def);
const auto jets = sorted_by_rapidity(cs.inclusive_jets(param_.jet_param.min_pt));
assert(jets.size() >= 2);
auto most_backward = begin(jets);
auto most_forward = end(jets) - 1;
// skip jets caused by unordered emission
if(has_unob_gluon(incoming, out_partons)){
assert(jets.size() >= 3);
++most_backward;
}
else if(has_unof_gluon(incoming, out_partons)){
assert(jets.size() >= 3);
--most_forward;
}
const auto extremal_jet_indices = cs.particle_jet_indices(
{*most_backward, *most_forward}
);
assert(extremal_jet_indices.size() == out_partons.size());
for(size_t i = 0; i < out_partons.size(); ++i){
assert(RHEJ::is_parton(out_partons[i]));
const int idx = (extremal_jet_indices[i]>=0)?
extremal_jet_idx:
no_extremal_jet_idx;
out_partons[i].p.set_user_index(idx);
}
return out_partons;
}
double MatrixElement::tree_kin_jets(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> partons,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> partons,
bool check_momenta
) const {
partons = tag_extremal_jet_partons(incoming, partons, check_momenta);
if(has_unob_gluon(incoming, partons) || has_unof_gluon(incoming, partons)){
throw std::logic_error("unordered emission not implemented for pure jets");
}
const auto pa = to_HepLorentzVector(incoming[0]);
const auto pb = to_HepLorentzVector(incoming[1]);
const auto p1 = to_HepLorentzVector(partons.front());
const auto pn = to_HepLorentzVector(partons.back());
return ME_current(
incoming[0].type, incoming[1].type,
pn, pb, p1, pa
)/(4*(N_C*N_C - 1))*FKL_ladder_weight(
begin(partons) + 1, end(partons) - 1,
pa - p1, pa, pb, p1, pn
);
}
double MatrixElement::tree_kin_Higgs(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
if(has_uno_gluon(incoming, outgoing)){
return tree_kin_Higgs_between(incoming, outgoing, check_momenta);
}
if(outgoing.front().type == pid::Higgs){
return tree_kin_Higgs_first(incoming, outgoing, check_momenta);
}
if(outgoing.back().type == pid::Higgs){
return tree_kin_Higgs_last(incoming, outgoing, check_momenta);
}
return tree_kin_Higgs_between(incoming, outgoing, check_momenta);
}
double MatrixElement::MH2_forwardH(
RHEJ::ParticleID id,
CLHEP::HepLorentzVector p1out, CLHEP::HepLorentzVector p1in,
CLHEP::HepLorentzVector p2out, CLHEP::HepLorentzVector p2in,
CLHEP::HepLorentzVector pH,
double t1, double t2
) const{
ignore(p2out, p2in);
const double shat = p1in.invariantMass2(p2in);
assert(RHEJ::is_parton(id));
if(id != RHEJ::pid::gluon){
return 9./2.*shat*shat*C2qHqm(p1in,p1out,pH)/(t1*t2);
}
// gluon case
#ifdef RHEJ_BUILD_WITH_QCDLOOP
if(!param_.Higgs_coupling.use_impact_factors){
return C_A/C_F*1./(16*M_PI*M_PI)*t1/t2*MH2gq_outsideH(
p1out, p1in, p2out, p2in, pH,
param_.Higgs_coupling.mt, param_.Higgs_coupling.include_bottom,
param_.Higgs_coupling.mb
);
}
#endif
return 9./2.*shat*shat*(
C2gHgp(p1in,p1out,pH) + C2gHgm(p1in,p1out,pH)
)/(t1*t2);
}
double MatrixElement::tree_kin_Higgs_first(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
assert(outgoing.front().type == pid::Higgs);
const auto pH = to_HepLorentzVector(outgoing.front());
const auto partons = tag_extremal_jet_partons(
incoming,
- std::vector<Sparticle>(begin(outgoing) + 1, end(outgoing)),
+ std::vector<Particle>(begin(outgoing) + 1, end(outgoing)),
check_momenta
);
const auto pa = to_HepLorentzVector(incoming[0]);
const auto pb = to_HepLorentzVector(incoming[1]);
const auto p1 = to_HepLorentzVector(partons.front());
const auto pn = to_HepLorentzVector(partons.back());
const auto q0 = pa - p1 - pH;
const double t1 = q0.m2();
const double t2 = (pn - pb).m2();
double wt = MH2_forwardH(
incoming[0].type, p1, pa, pn, pb, pH,
t1, t2
)*FKL_ladder_weight(
begin(partons) + 1, end(partons) - 1,
q0, pa, pb, p1, pn
);
for(auto const & inc: incoming){
if(inc.type != pid::gluon) wt *= C_F/C_A;
}
return wt;
}
double MatrixElement::tree_kin_Higgs_last(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
assert(outgoing.back().type == pid::Higgs);
const auto pH = to_HepLorentzVector(outgoing.back());
const auto partons = tag_extremal_jet_partons(
incoming,
- std::vector<Sparticle>(begin(outgoing), end(outgoing) - 1),
+ std::vector<Particle>(begin(outgoing), end(outgoing) - 1),
check_momenta
);
const auto pa = to_HepLorentzVector(incoming[0]);
const auto pb = to_HepLorentzVector(incoming[1]);
auto p1 = to_HepLorentzVector(partons.front());
const auto pn = to_HepLorentzVector(partons.back());
auto q0 = pa - p1;
const double t1 = q0.m2();
const double t2 = (pn + pH - pb).m2();
double wt = MH2_forwardH(
incoming[1].type, pn, pb, p1, pa, pH,
t2, t1
)*FKL_ladder_weight(
begin(partons) + 1, end(partons) - 1,
q0, pa, pb, p1, pn
);
for(auto const & inc: incoming){
if(inc.type != pid::gluon) wt *= C_F/C_A;
}
return wt;
}
double MatrixElement::tree_kin_Higgs_between(
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
const auto the_Higgs = std::find_if(
begin(outgoing), end(outgoing),
- [](Sparticle const & s){ return s.type == pid::Higgs; }
+ [](Particle const & s){ return s.type == pid::Higgs; }
);
assert(the_Higgs != end(outgoing));
const auto pH = to_HepLorentzVector(*the_Higgs);
- std::vector<Sparticle> partons(begin(outgoing), the_Higgs);
+ std::vector<Particle> partons(begin(outgoing), the_Higgs);
partons.insert(end(partons), the_Higgs + 1, end(outgoing));
partons = tag_extremal_jet_partons(incoming, partons, check_momenta);
const auto pa = to_HepLorentzVector(incoming[0]);
const auto pb = to_HepLorentzVector(incoming[1]);
auto p1 = to_HepLorentzVector(
partons[has_unob_gluon(incoming, outgoing)?1:0]
);
auto pn = to_HepLorentzVector(
partons[partons.size() - (has_unof_gluon(incoming, outgoing)?2:1)]
);
auto first_after_Higgs = begin(partons) + (the_Higgs-begin(outgoing));
assert(
(first_after_Higgs == end(partons) && has_unob_gluon(incoming, outgoing))
|| first_after_Higgs->rapidity() >= the_Higgs->rapidity()
);
assert(
(first_after_Higgs == begin(partons) && has_unof_gluon(incoming, outgoing))
|| (first_after_Higgs-1)->rapidity() <= the_Higgs->rapidity()
);
// always treat the Higgs as if it were in between the extremal FKL partons
if(first_after_Higgs == begin(partons)) ++first_after_Higgs;
else if(first_after_Higgs == end(partons)) --first_after_Higgs;
// t-channel momentum before Higgs
auto qH = pa;
for(auto parton_it = begin(partons); parton_it != first_after_Higgs; ++parton_it){
qH -= to_HepLorentzVector(*parton_it);
}
auto q0 = pa - p1;
auto begin_ladder = begin(partons) + 1;
auto end_ladder = end(partons) - 1;
double current_factor;
if(has_unob_gluon(incoming, outgoing)){
current_factor = 9./2.*ME_Higgs_current_unob(
incoming[0].type, incoming[1].type,
pn, pb, to_HepLorentzVector(partons.front()), p1, pa, qH, qH - pH,
param_.Higgs_coupling.mt,
param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb
);
const auto p_unob = to_HepLorentzVector(partons.front());
q0 -= p_unob;
p1 += p_unob;
++begin_ladder;
}
else if(has_unof_gluon(incoming, outgoing)){
current_factor = 9./2.*ME_Higgs_current_unof(
incoming[0].type, incoming[1].type,
to_HepLorentzVector(partons.back()), pn, pb, p1, pa, qH, qH - pH,
param_.Higgs_coupling.mt,
param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb
);
pn += to_HepLorentzVector(partons.back());
--end_ladder;
}
else{
current_factor = ME_Higgs_current(
incoming[0].type, incoming[1].type,
pn, pb, p1, pa, qH, qH - pH,
param_.Higgs_coupling.mt,
param_.Higgs_coupling.include_bottom, param_.Higgs_coupling.mb
);
}
const double ladder_factor = FKL_ladder_weight(
begin_ladder, first_after_Higgs,
q0, pa, pb, p1, pn
)*FKL_ladder_weight(
first_after_Higgs, end_ladder,
qH - pH, pa, pb, p1, pn
);
return current_factor*9./8.*ladder_factor;
}
double MatrixElement::tree_param_partons(
double alpha_s, double mur,
- std::vector<Sparticle> const & partons
+ std::vector<Particle> const & partons
) const{
const double gs2 = 4.*M_PI*alpha_s;
double wt = std::pow(gs2, partons.size());
if(param_.log_correction){
// use alpha_s(q_perp), evolved to mur
assert(partons.size() >= 2);
for(size_t i = 1; i < partons.size()-1; ++i){
wt *= 1 + alpha_s/(2*M_PI)*beta0*log(mur/partons[i].p.perp());
}
}
return wt;
}
double MatrixElement::tree_param(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing
) const{
const double alpha_s = alpha_s_(mur);
if(has_unob_gluon(incoming, outgoing)){
return 4*M_PI*alpha_s*tree_param_partons(
alpha_s, mur, filter_partons({begin(outgoing) + 1, end(outgoing)})
);
}
if(has_unof_gluon(incoming, outgoing)){
return 4*M_PI*alpha_s*tree_param_partons(
alpha_s, mur, filter_partons({begin(outgoing), end(outgoing) - 1})
);
}
return tree_param_partons(alpha_s, mur, filter_partons(outgoing));
}
double MatrixElement::tree(
double mur,
- std::array<Sparticle, 2> const & incoming,
- std::vector<Sparticle> const & outgoing,
+ std::array<Particle, 2> const & incoming,
+ std::vector<Particle> const & outgoing,
bool check_momenta
) const {
return tree_param(mur, incoming, outgoing)*tree_kin(
incoming, outgoing, check_momenta
);
}
} // namespace RHEJ
diff --git a/src/PhaseSpacePoint.cc b/src/PhaseSpacePoint.cc
index c191825..5067a0b 100644
--- a/src/PhaseSpacePoint.cc
+++ b/src/PhaseSpacePoint.cc
@@ -1,535 +1,535 @@
#include "RHEJ/PhaseSpacePoint.hh"
#include <random>
#include <CLHEP/Random/Randomize.h>
#include <CLHEP/Random/RanluxEngine.h>
#include "RHEJ/Constants.hh"
#include "RHEJ/resummation_jet_momenta.hh"
#include "RHEJ/Jacobian.hh"
#include "RHEJ/uno.hh"
#include "RHEJ/debug.hh"
#include "RHEJ/kinematics.hh"
namespace RHEJ{
namespace {
constexpr int max_jet_user_idx = PhaseSpacePoint::ng_max;
bool is_nonjet_parton(fastjet::PseudoJet const & parton){
assert(parton.user_index() != -1);
return parton.user_index() > max_jet_user_idx;
}
bool is_jet_parton(fastjet::PseudoJet const & parton){
assert(parton.user_index() != -1);
return parton.user_index() <= max_jet_user_idx;
}
// user indices for partons with extremal rapidity
constexpr int unob_idx = -5;
constexpr int unof_idx = -4;
constexpr int backward_FKL_idx = -3;
constexpr int forward_FKL_idx = -2;
}
namespace {
double estimate_ng_mean(std::vector<fastjet::PseudoJet> const & Born_jets){
const double delta_y =
Born_jets.back().rapidity() - Born_jets.front().rapidity();
assert(delta_y > 0);
// Formula derived from fit in reversed HEJ intro paper
return 0.975052*delta_y;
}
}
std::vector<fastjet::PseudoJet> PhaseSpacePoint::cluster_jets(
std::vector<fastjet::PseudoJet> const & partons
) const{
fastjet::ClusterSequence cs(partons, param_.jet_param.def);
return cs.inclusive_jets(param_.jet_param.min_pt);
}
bool PhaseSpacePoint::pass_resummation_cuts(
std::vector<fastjet::PseudoJet> const & jets
) const{
return cluster_jets(jets).size() == jets.size();
}
int PhaseSpacePoint::sample_ng(std::vector<fastjet::PseudoJet> const & Born_jets){
const double ng_mean = estimate_ng_mean(Born_jets);
std::poisson_distribution<int> dist(ng_mean);
const int ng = dist(ran_.get());
assert(ng >= 0);
assert(ng < ng_max);
weight_ *= std::tgamma(ng + 1)*std::exp(ng_mean)*std::pow(ng_mean, -ng);
return ng;
}
void PhaseSpacePoint::copy_AWZH_boson_from(Event const & event){
auto const & from = event.outgoing();
const auto AWZH_boson = std::find_if(
begin(from), end(from),
- [](Sparticle const & p){ return is_AWZH_boson(p); }
+ [](Particle const & p){ return is_AWZH_boson(p); }
);
if(AWZH_boson == end(from)) return;
auto insertion_point = std::lower_bound(
begin(outgoing_), end(outgoing_), *AWZH_boson, rapidity_less{}
);
outgoing_.insert(insertion_point, *AWZH_boson);
// copy decay products
const int idx = std::distance(begin(from), AWZH_boson);
const auto decay_it = event.decays().find(idx);
if(decay_it != end(event.decays())){
const int new_idx = std::distance(begin(outgoing_), insertion_point);
assert(outgoing_[new_idx].type == AWZH_boson->type);
decays_.emplace(new_idx, decay_it->second);
}
assert(std::is_sorted(begin(outgoing_), end(outgoing_), rapidity_less{}));
}
PhaseSpacePoint::PhaseSpacePoint(
Event const & ev, PhaseSpacePointConfig conf, RHEJ::RNG & ran
):
unob_{has_unob_gluon(ev.incoming(), ev.outgoing())},
unof_{!unob_ && has_unof_gluon(ev.incoming(), ev.outgoing())},
param_{std::move(conf)},
ran_{ran},
splitter_{param_.jet_param.def.R(), param_.jet_param.def, param_.jet_param.min_pt, ran}
{
weight_ = 1;
const auto Born_jets = sorted_by_rapidity(ev.jets());
const int ng = sample_ng(Born_jets);
weight_ /= std::tgamma(ng + 1);
const int ng_jets = sample_ng_jets(ng, Born_jets);
std::vector<fastjet::PseudoJet> out_partons = gen_non_jet(
ng - ng_jets, CMINPT, param_.jet_param.min_pt
);
{
const auto qperp = std::accumulate(
begin(out_partons), end(out_partons),
fastjet::PseudoJet{}
);
const auto jets = reshuffle(Born_jets, qperp);
if(weight_ == 0.) return;
if(! pass_resummation_cuts(jets)){
weight_ = 0.;
return;
}
std::vector<fastjet::PseudoJet> jet_partons = split(jets, ng_jets);
if(weight_ == 0.) return;
rescale_rapidities(
out_partons,
most_backward_FKL(jet_partons).rapidity(),
most_forward_FKL(jet_partons).rapidity()
);
if(! cluster_jets(out_partons).empty()){
weight_ = 0.;
return;
}
std::sort(begin(out_partons), end(out_partons), rapidity_less{});
assert(
std::is_sorted(begin(jet_partons), end(jet_partons), rapidity_less{})
);
const auto first_jet_parton = out_partons.insert(
end(out_partons), begin(jet_partons), end(jet_partons)
);
std::inplace_merge(
begin(out_partons), first_jet_parton, end(out_partons), rapidity_less{}
);
}
if(! jets_ok(Born_jets, out_partons)){
weight_ = 0.;
return;
}
weight_ *= phase_space_normalisation(Born_jets.size(), out_partons.size());
outgoing_.reserve(out_partons.size() + 1); // one slot for possible A, W, Z, H
for(auto & p: out_partons){
- outgoing_.emplace_back(Sparticle{pid::gluon, std::move(p)});
+ outgoing_.emplace_back(Particle{pid::gluon, std::move(p)});
}
most_backward_FKL(outgoing_).type = ev.incoming().front().type;
most_forward_FKL(outgoing_).type = ev.incoming().back().type;
copy_AWZH_boson_from(ev);
assert(!outgoing_.empty());
reconstruct_incoming(ev.incoming());
}
std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_non_jet(
int count, double ptmin, double ptmax
){
// heuristic parameters for pt sampling
const double ptpar = 1.3 + count/5.;
const double temp1 = atan((ptmax - ptmin)/ptpar);
std::vector<fastjet::PseudoJet> partons(count);
for(size_t i = 0; i < (size_t) count; ++i){
const double r1 = ran_.get().flat();
const double pt = ptmin + ptpar*tan(r1*temp1);
const double temp2 = cos(r1*temp1);
const double phi = 2*M_PI*ran_.get().flat();
weight_ *= 2.0*M_PI*pt*ptpar*temp1/(temp2*temp2);
// we don't know the allowed rapidity span yet,
// set a random value to be rescaled later on
const double y = ran_.get().flat();
partons[i].reset_PtYPhiM(pt, y, phi);
// Set user index higher than any jet-parton index
// in order to assert that these are not inside jets
partons[i].set_user_index(i + 1 + ng_max);
assert(ptmin-1e-5 <= partons[i].pt() && partons[i].pt() <= ptmax+1e-5);
}
assert(std::all_of(partons.cbegin(), partons.cend(), is_nonjet_parton));
return partons;
}
void PhaseSpacePoint::rescale_rapidities(
std::vector<fastjet::PseudoJet> & partons,
double ymin, double ymax
){
constexpr double ep = 1e-7;
for(auto & parton: partons){
assert(0 <= parton.rapidity() && parton.rapidity() <= 1);
const double dy = ymax - ymin - 2*ep;
const double y = ymin + ep + dy*parton.rapidity();
parton.reset_momentum_PtYPhiM(parton.pt(), y, parton.phi());
weight_ *= dy;
assert(ymin <= parton.rapidity() && parton.rapidity() <= ymax);
}
}
namespace {
template<typename T, typename... Rest>
auto min(T const & a, T const & b, Rest&&... r) {
using std::min;
return min(a, min(b, std::forward<Rest>(r)...));
}
}
double PhaseSpacePoint::probability_in_jet(
std::vector<fastjet::PseudoJet> const & Born_jets
) const{
assert(std::is_sorted(begin(Born_jets), end(Born_jets), rapidity_less{}));
assert(Born_jets.size() >= 2);
const double dy =
Born_jets.back().rapidity() - Born_jets.front().rapidity();
const double R = param_.jet_param.def.R();
const int njets = Born_jets.size();
const double p_J_y_large = (njets-1)*R*R/(2.*dy);
const double p_J_y0 = njets*R/M_PI;
return min(p_J_y_large, p_J_y0, 1.);
}
int PhaseSpacePoint::sample_ng_jets(
int ng, std::vector<fastjet::PseudoJet> const & Born_jets
){
const double p_J = probability_in_jet(Born_jets);
std::binomial_distribution<> bin_dist(ng, p_J);
const int ng_J = bin_dist(ran_.get());
weight_ *= std::pow(p_J, -ng_J)*std::pow(1 - p_J, ng_J - ng);
return ng_J;
}
std::vector<fastjet::PseudoJet>
PhaseSpacePoint::reshuffle(
std::vector<fastjet::PseudoJet> const & Born_jets,
fastjet::PseudoJet const & q
){
if(q == fastjet::PseudoJet{0, 0, 0, 0}) return Born_jets;
std::vector<fastjet::PseudoJet> jets = resummation_jet_momenta(Born_jets, q);
if(jets.empty()){
weight_ = 0;
return {};
}
// transform delta functions to integration over resummation momenta
weight_ /= Jacobian(jets, q);
return jets;
}
std::vector<int> PhaseSpacePoint::distribute_jet_partons(
int ng_jets, std::vector<fastjet::PseudoJet> const & jets
){
size_t first_valid_jet = 0;
size_t num_valid_jets = jets.size();
const double R_eff = 5./3.*param_.jet_param.def.R();
// if there is an unordered jet too far away from the FKL jets
// then extra gluon constituents of the unordered jet would
// violate the FKL rapidity ordering
if(unob_ && jets[0].delta_R(jets[1]) > R_eff){
++first_valid_jet;
--num_valid_jets;
}
else if(unof_ && jets[jets.size()-1].delta_R(jets[jets.size()-2]) > R_eff){
--num_valid_jets;
}
std::vector<int> np(jets.size(), 1);
for(int i = 0; i < ng_jets; ++i){
++np[first_valid_jet + ran_.get().flat() * num_valid_jets];
}
weight_ *= std::pow(num_valid_jets, ng_jets);
return np;
}
#ifndef NDEBUG
namespace{
bool tagged_FKL_backward(
std::vector<fastjet::PseudoJet> const & jet_partons
){
return std::find_if(
begin(jet_partons), end(jet_partons),
[](fastjet::PseudoJet const & p){
return p.user_index() == backward_FKL_idx;
}
) != end(jet_partons);
}
bool tagged_FKL_forward(
std::vector<fastjet::PseudoJet> const & jet_partons
){
// the most forward FKL parton is most likely near the end of jet_partons;
// start search from there
return std::find_if(
jet_partons.rbegin(), jet_partons.rend(),
[](fastjet::PseudoJet const & p){
return p.user_index() == forward_FKL_idx;
}
) != jet_partons.rend();
}
bool tagged_FKL_extremal(
std::vector<fastjet::PseudoJet> const & jet_partons
){
return tagged_FKL_backward(jet_partons) && tagged_FKL_forward(jet_partons);
}
} // namespace anonymous
#endif
std::vector<fastjet::PseudoJet> PhaseSpacePoint::split(
std::vector<fastjet::PseudoJet> const & jets,
int ng_jets
){
return split(jets, distribute_jet_partons(ng_jets, jets));
}
bool PhaseSpacePoint::pass_extremal_cuts(
fastjet::PseudoJet const & ext_parton,
fastjet::PseudoJet const & jet
) const{
if(ext_parton.pt() < param_.min_extparton_pt) return false;
return (ext_parton - jet).pt()/jet.pt() < param_.max_ext_soft_pt_fraction;
}
std::vector<fastjet::PseudoJet> PhaseSpacePoint::split(
std::vector<fastjet::PseudoJet> const & jets,
std::vector<int> const & np
){
assert(! jets.empty());
assert(jets.size() == np.size());
assert(pass_resummation_cuts(jets));
const size_t most_backward_FKL_idx = 0 + unob_;
const size_t most_forward_FKL_idx = jets.size() - 1 - unof_;
std::vector<fastjet::PseudoJet> jet_partons;
// randomly distribute jet gluons among jets
for(size_t i = 0; i < jets.size(); ++i){
weight_ *= splitter_.Split(jets[i], np[i]);
if(weight_ == 0) return {};
assert(
std::all_of(
begin(splitter_.get_jcons()), end(splitter_.get_jcons()),
is_jet_parton
)
);
const auto first_new_parton = jet_partons.insert(
end(jet_partons),
begin(splitter_.get_jcons()), end(splitter_.get_jcons())
);
// mark uno and extremal FKL emissions here so we can check
// their position once all emissions are generated
auto extremal = end(jet_partons);
if((unob_ && i == 0) || i == most_backward_FKL_idx){
// unordered or FKL backward emission
extremal = std::min_element(
first_new_parton, end(jet_partons), rapidity_less{}
);
extremal->set_user_index(
(i == most_backward_FKL_idx)?backward_FKL_idx:unob_idx
);
}
else if((unof_ && i == jets.size() - 1) || i == most_forward_FKL_idx){
// unordered or FKL forward emission
extremal = std::max_element(
first_new_parton, end(jet_partons), rapidity_less{}
);
extremal->set_user_index(
(i == most_forward_FKL_idx)?forward_FKL_idx:unof_idx
);
}
if(
extremal != end(jet_partons)
&& !pass_extremal_cuts(*extremal, jets[i])
){
weight_ = 0;
return {};
}
}
assert(tagged_FKL_extremal(jet_partons));
std::sort(begin(jet_partons), end(jet_partons), rapidity_less{});
if(
!extremal_ok(jet_partons)
|| !split_preserved_jets(jets, jet_partons)
){
weight_ = 0.;
return {};
}
return jet_partons;
}
bool PhaseSpacePoint::extremal_ok(
std::vector<fastjet::PseudoJet> const & partons
) const{
assert(std::is_sorted(begin(partons), end(partons), rapidity_less{}));
if(unob_ && partons.front().user_index() != unob_idx) return false;
if(unof_ && partons.back().user_index() != unof_idx) return false;
return
most_backward_FKL(partons).user_index() == backward_FKL_idx
&& most_forward_FKL(partons).user_index() == forward_FKL_idx;
}
bool PhaseSpacePoint::split_preserved_jets(
std::vector<fastjet::PseudoJet> const & jets,
std::vector<fastjet::PseudoJet> const & jet_partons
) const{
assert(std::is_sorted(begin(jets), end(jets), rapidity_less{}));
const auto split_jets = sorted_by_rapidity(cluster_jets(jet_partons));
// this can happen if two overlapping jets
// are both split into more than one parton
if(split_jets.size() != jets.size()) return false;
for(size_t i = 0; i < split_jets.size(); ++i){
// this can happen if there are two overlapping jets
// and a parton is assigned to the "wrong" jet
if(!nearby_ep(jets[i].rapidity(), split_jets[i].rapidity(), 1e-2)){
return false;
}
}
return true;
}
template<class Particle>
Particle const & PhaseSpacePoint::most_backward_FKL(
std::vector<Particle> const & partons
) const{
return partons[0 + unob_];
}
template<class Particle>
Particle const & PhaseSpacePoint::most_forward_FKL(
std::vector<Particle> const & partons
) const{
const size_t idx = partons.size() - 1 - unof_;
assert(idx < partons.size());
return partons[idx];
}
template<class Particle>
Particle & PhaseSpacePoint::most_backward_FKL(
std::vector<Particle> & partons
) const{
return partons[0 + unob_];
}
template<class Particle>
Particle & PhaseSpacePoint::most_forward_FKL(
std::vector<Particle> & partons
) const{
const size_t idx = partons.size() - 1 - unof_;
assert(idx < partons.size());
return partons[idx];
}
namespace {
bool contains_idx(
fastjet::PseudoJet const & jet, fastjet::PseudoJet const & parton
){
auto const & constituents = jet.constituents();
const int idx = parton.user_index();
return std::find_if(
begin(constituents), end(constituents),
[idx](fastjet::PseudoJet const & con){return con.user_index() == idx;}
) != end(constituents);
}
}
/**
* final jet test:
* - number of jets must match Born kinematics
* - no partons designated as nonjet may end up inside jets
* - all other outgoing partons *must* end up inside jets
* - the extremal (in rapidity) partons must be inside the extremal jets
* - rapidities must be the same (by construction)
*/
bool PhaseSpacePoint::jets_ok(
std::vector<fastjet::PseudoJet> const & Born_jets,
std::vector<fastjet::PseudoJet> const & partons
) const{
fastjet::ClusterSequence cs(partons, param_.jet_param.def);
const auto jets = sorted_by_rapidity(cs.inclusive_jets(param_.jet_param.min_pt));
if(jets.size() != Born_jets.size()) return false;
int in_jet = 0;
for(size_t i = 0; i < jets.size(); ++i){
assert(jets[i].has_constituents());
for(auto && parton: jets[i].constituents()){
if(is_nonjet_parton(parton)) return false;
}
in_jet += jets[i].constituents().size();
}
const int expect_in_jet = std::count_if(
partons.cbegin(), partons.cend(), is_jet_parton
);
if(in_jet != expect_in_jet) return false;
// note that PseudoJet::contains does not work here
if(! (
contains_idx(most_backward_FKL(jets), most_backward_FKL(partons))
&& contains_idx(most_forward_FKL(jets), most_forward_FKL(partons))
)) return false;
if(unob_ && !contains_idx(jets.front(), partons.front())) return false;
if(unof_ && !contains_idx(jets.back(), partons.back())) return false;
for(size_t i = 0; i < jets.size(); ++i){
assert(nearby_ep(jets[i].rapidity(), Born_jets[i].rapidity(), 1e-2));
}
return true;
}
void PhaseSpacePoint::reconstruct_incoming(
- std::array<Sparticle, 2> const & Born_incoming
+ std::array<Particle, 2> const & Born_incoming
){
std::tie(incoming_[0].p, incoming_[1].p) = incoming_momenta(outgoing_);
for(size_t i = 0; i < incoming_.size(); ++i){
incoming_[i].type = Born_incoming[i].type;
}
assert(momentum_conserved());
}
double PhaseSpacePoint::phase_space_normalisation(
int num_Born_jets, int num_out_partons
) const{
return pow(16*pow(M_PI,3), num_Born_jets - num_out_partons);
}
bool PhaseSpacePoint::momentum_conserved() const{
fastjet::PseudoJet diff;
for(auto const & in: incoming()) diff += in.p;
const double norm = diff.E();
for(auto const & out: outgoing()) diff -= out.p;
return nearby(diff, fastjet::PseudoJet{}, norm);
}
} //namespace RHEJ
diff --git a/src/kinematics.cc b/src/kinematics.cc
index 74b0b69..689b071 100644
--- a/src/kinematics.cc
+++ b/src/kinematics.cc
@@ -1,22 +1,22 @@
#include "RHEJ/kinematics.hh"
#include "fastjet/PseudoJet.hh"
#include "RHEJ/utility.hh"
namespace RHEJ{
//reconstruct incoming momenta from momentum conservation
std::tuple<fastjet::PseudoJet, fastjet::PseudoJet> incoming_momenta(
- std::vector<Sparticle> const & outgoing
+ std::vector<Particle> const & outgoing
){
double xa(0.), xb(0.);
for(auto const & out: outgoing){
xa += out.p.e() - out.p.pz();
xb += out.p.e() + out.p.pz();
}
return std::tuple<fastjet::PseudoJet, fastjet::PseudoJet>{
{0,0,-xa/2.,xa/2.},
{0,0,xb/2.,xb/2.}
};
}
}
diff --git a/t/test_ME_h_3j.cc b/t/test_ME_h_3j.cc
index ab3a28d..fe7bc17 100644
--- a/t/test_ME_h_3j.cc
+++ b/t/test_ME_h_3j.cc
@@ -1,99 +1,99 @@
#include "LHEF/LHEF.h"
#include "RHEJ/config.hh"
#include "RHEJ/MatrixElement.hh"
#include "RHEJ/Event.hh"
struct Event{
- std::array<RHEJ::Sparticle, 2> incoming;
- std::vector<RHEJ::Sparticle> outgoing;
+ std::array<RHEJ::Particle, 2> incoming;
+ std::vector<RHEJ::Particle> outgoing;
Event(
- RHEJ::Sparticle in1, RHEJ::Sparticle in2,
- std::initializer_list<RHEJ::Sparticle> out
+ RHEJ::Particle in1, RHEJ::Particle in2,
+ std::initializer_list<RHEJ::Particle> out
):
incoming{std::move(in1), std::move(in2)},
outgoing{out}
{}
};
constexpr
RHEJ::pid::ParticleID PDG(int id){
return static_cast<RHEJ::pid::ParticleID>(id);
}
constexpr double alpha_s = 0.113559;
constexpr double mu = 125.;
constexpr double R = 0.4;
constexpr double min_jet_pt = 50.;
constexpr auto jet_def = fastjet::antikt_algorithm;
constexpr double ep = 1e-4;
void dump(Event const & ev){
LHEF::Writer writer{std::cerr};
std::cerr << std::setprecision(15);
RHEJ::UnclusteredEvent tmp;
tmp.incoming = ev.incoming;
tmp.outgoing = ev.outgoing;
tmp.central = {mu, mu, 0.};
RHEJ::Event out_ev{std::move(tmp), {jet_def, R}, min_jet_pt};
writer.hepeup = to_HEPEUP(std::move(out_ev), nullptr);
writer.writeEvent();
}
int main(){
std::vector<Event> events = {
/*
* reference matrix elements obtained from traditional HEJ (svn r3355)
* weights correspond to shat2*wt/(pdfPtr->pdfta*pdfPtr->pdftb)
* at the end of MEt2 in HJets.cxx
*/
#include "ME_test_events.dat"
};
const std::vector<double> ref_weights{
1.20840366448943e-08,3.41482815561959e-18,4.09113550770465e-12,4.62704699562129e-15,4.48439126356004e-15,1.87972263060254e-12,1.44306589954128e-14,9.10660553817556e-13,6.78185181417658e-13,2.2313219279205e-14,5.04225136522914e-10,1.15445795400542e-13,4.25305992011228e-15,6.34464495221583e-11,8.1504882635896e-09,8.13050604628519e-10,1.16718768515638e-12,2.10641257506331e-08,6.62448031524987e-23,4.3319311109536e-07,1.20944494921349e-15,5.92539274973405e-05,4.4796169513938e-17,1.49273221119393e-15,2.43311569643869e-18,2.402863950606e-12,1.0620402696538e-11,5.35907540952987e-14,1.23031328706173e-12,2.79984692016006e-15,9.15681008462036e-19,6.82192590709917e-19,7.89237067022333e-13,1.86125787460036e-14,6.46979689455398e-07,3.04911830916725e-15,8.13163686285418e-15,1.53766124466997e-14,8.32276518653951e-14,8.88400099785712e-11,8.91102728936822e-06,1.80107644544759e-15,2.10582866365414e-09,3.10947796493188e-17,3.91243813845236e-15,3.26654480787734e-17,9.5447871679842e-14,2.59793669360488e-15,4.96134344054012e-13,5.81162371703576e-14,1.111167877034e-09,2.79109572058797e-16,4.46160513513727e-16,6.75218397576417e-15,2.68260561114305e-11,4.28989454505788e-16,5.8329868340234e-16,2.2024897389957e-09,2.57397955688743e-15,2.44654345522128e-14,2.30866752912176e-14,1.41827747056589e-07,1.08893147410797e-14,4.03382910318587e-11,3.1389869623674e-10,3.90505557430021e-13,1.08295237971538e-12,7.454591488958e-15,7.54483306433453e-14,1.02908259302562e-15,5.63531574394432e-14,6.30249429292698e-11,4.53762691808614e-13,1.89024041595359e-16,6.8158270448436e-15,1.14399844221906e-12,8.90256332512462e-11,6.06548092223796e-17,9.98362270779565e-12,4.59859716748231e-15,2.15099414771066e-10,2.11591109618363e-13,4.9742178019335e-09,1.33845681137089e-10,2.71186491627684e-16,8.86739836718398e-13,1.8249669781697e-14,1.92215499935624e-13,5.63538105112205e-14,4.14171568963499e-12,2.2717979957039e-15,5.55611156772101e-15,1.28364738716082e-16,5.3851134765245e-12,1.24211103260246e-08,4.83232530709888e-17,0.000521569751168655,1.6806219324588e-15,6.59977348355555e-11,9.1627970683281e-14,2.76820118228537e-12,4.0198982918336e-11,1.48426883756103e-18,1.40114232815435e-18,1.7965991343524e-11,7.6977628175923e-10,4.62196685302415e-14,2.69246069544232e-08,1.51516950568948e-13,6.99496684443045e-13,5.18573546306991e-16,0.0434630460883225,1.9837330600509e-23,2.67017601462925e-12,9.8878856049861e-16,8.72580364190897e-11,9.78094461016429e-06,8.71781003862465e-17,1.1559862791241e-08,4.84083438123941e-11,0.0139742563571754,1.99847601444777e-13,3.04915596353023e-17,5.93151845056274e-16,2.17435618150856e-14,5.33225221812805e-08,3.87773807827851e-14,4.50810202343348e-08,1.21607462589437e-08,3.1594598104258e-13,3.28656273761685e-16,2.50210924939855e-21,2.38126296013289e-13,1.25433376653286e-11,2.14322725557091e-14,1.49146107213853e-09,1.242585653879e-15,3.55954759815053e-17,3.58323190858796e-10,4.51037144634267e-14,7.55931651143187e-09,5.37698824199559e-14,7.38868781004529e-14,1.69357650230295e-11,5.80639629823124e-10,7.4837350747944e-17,6.96956083393151e-16,1.81834207579059e-10,2.82540028744915e-12,4.0395726561383e-13,1.79694539029015e-12,1.31041890677814e-16,1.30438189219159e-07,1.43221371664219e-10,9.114047729275e-16,7.34577355123687e-09,3.22593068239571e-15,4.15681922353836e-15,3.36408379142654e-16,1.44480854726148e-11,1.01363611458694e-13,1.00219358430676e-12,0.00338137229726986,4.29548017717404e-15,2.60395354258443e-14,4.1476296627427e-14,1.06855911096978e-13,8.22439039784712e-11,2.73629652512136e-10,5.15659349602634e-11,1.01584718933351e-13,6.94380398977803e-16,2.18931000347143e-18,3.07933496617785e-09,1.66390942837878e-16,3.52525907142114e-13,3.78080647432571e-14,1.17556440172277e-12,6.59751630435329e-17,1.21755902521401e-08,2.55450721249666e-11,1.53256550428156e-14,1.08380893991568e-12,4.16098986326189e-13,2.90205083341855e-14,5.511460594056e-18,1.57699398911427e-16,7.00104401760928e-13,3.58046798793545e-12,2.01229361268661e-12,3.73614518690553e-07,2.14710426845508e-14,3.70105600162546e-13,7.98071394035332e-15,7.37834963791502e-16,1.60529982053429e-09,1.08256973923745e-12,1.0334353499219e-13,9.49543099778791e-11,1.9115591364306e-12,4.0448657562838e-16,8.71422438179998e-15,1.25631778664749e-16,3.14479096095934e-19,2.64428535684163e-16,1.12107615349188e-11,1.23625298812219e-13,4.01428912903254e-13,2.70797308155832e-11,6.56279497820654e-09,7.13734059806893e-16,0.000782868291989126,3.76614026148548e-16,1.26257000484765e-13,9.58631950869197e-13,8.31708875806124e-11,2.34133301418612e-13,9.56863619261736e-14,4.64712032868663e-12,2.86185199150703e-12,1.33576465609689e-11,1.10079981208014e-15,1.0127254462106e-12,1.1462054990501e-12,6.6945137657857e-11,5.58956247731427e-17,9.55921087729154e-12,2.34217482968982e-13,9.06915368555449e-19,5.71005344841003e-15,7.30755001164554e-09,6.21879071656432e-07,3.18226338142145e-17,7.85187718829052e-15,1.12784019414768e-13,1.26620458266236e-12,3.69177699852588e-14,5.15075992359208e-08,4.92072565553936e-15,1.85781482577606e-18,4.45444190278706e-16,1.26266755594178e-13,2.4288203970545e-16,3.05176309462854e-13,1.10490541122231e-16,8.47749453725764e-16,5.15877353528789e-11,5.24254149207253e-17,1.91355494316452e-10,5.00556344079427e-17,2.17154626918891e-15,8.84358943960976e-15,3.61414423657153e-11,4.82735747825927e-09,1.29064865560832e-13,8.42127739585314e-10,3.92906216459766e-16,6.04446459041361e-17,5.89524177334148e-12,5.46194519536606e-19,1.34088171433487e-11,5.52860041827642e-15,1.75477788501097e-15,1.73667838135065e-16,1.65397026290053e-13,1.12185521855334e-09,6.08386662697057e-17,4.59141650497559e-07,1.5209325219688e-11,2.23037744763897e-13,2.01952877105987e-13,6.8597135743949e-17,1.21998302502671e-11,3.21171910404898e-17,5.26021980482437e-15,7.19705632175135e-19,1.20963419308456e-09,6.88528237531901e-13,1.98848279147693e-11,4.01262000581642e-12,5.20247739003617e-13,1.30428205622828e-14,4.11298291694491e-13,5.52043003142038e-10,1.23093415613032e-16,7.36616975809533e-17,3.45364902177034e-16,4.34985181424009e-08,5.38804276057675e-14,9.48300760869968e-13,1.22337104642822e-09,8.35787040119371e-14,1.55423397182344e-15,1.42203125672685e-13,3.18903277676011e-13,3.88652741986258e-15,7.04896809011702e-18,1.32646740227354e-21,7.99231856556843e-13,5.95802234870006e-09,1.65149306543534e-12,1.33064116256099e-11,1.56832702886549e-12,1.10299934631458e-08,3.67898989067657e-16,7.84682358054423e-17,2.57971628718788e-09,8.33182695406546e-17,1.18568992167241e-10,1.84355449893326e-12,2.55066898328171e-13,2.83673294248314e-14,1.78606190612042e-12,3.58348766614931e-12,4.59943073492537e-16,9.51522624162865e-13,8.0286195911246e-14,1.36695977212813e-16,2.66996900743536e-13,1.18874419459462e-15,4.20697505402443e-07,1.44157427471053e-12,3.88352207261609e-12,1.10352682706254e-15,9.16382540998255e-16,1.6918487768822e-14,6.27001020277801e-13,1.19982339734628e-15,2.08524585760556e-15,3.98635216491517e-11,2.29164410091261e-16,6.59993812570474e-14,9.09720299660866e-19,1.00791143935241e-13,3.48282488442434e-15,3.82462701684145e-11,1.82912920125976e-14,2.35934504263123e-12,3.07876467756239e-11,3.01958860729077e-05,1.34442938440306e-12,1.98172170171169e-11,2.54803366934403e-14,4.63525528427102e-13,1.98623090357032e-11,1.17532063246858e-12,1.62645374532443e-16,2.23093836031326e-11,5.23718977936426e-13,6.30254161980384e-15,5.64457070654369e-16,5.8598582297477e-15,1.54121478101166e-11,2.54757492800786e-11,7.24784320481052e-13,7.10590291356503e-11,1.90012029508776e-12,5.38421849395334e-05,9.2027530054952e-13,0.00802523961864568,1.69971085315301e-12,4.17128853468654e-15,2.58531014487319e-15,6.72871249369096e-12,3.68392430578061e-16,1.56192266889718e-14,8.09758960836169e-16,1.33670176619002e-07,3.40402526854793e-10,7.14029639915786e-15,1.15907463202726e-14
};
const std::vector<double> ref_virt{
0.000407437434887122,0.0616303680115081,0.0619338272462471,0.00113600815259533,0.0611805205486735,0.000565698082480416,0.516976611025519,0.0361140019339901,0.00145895360905874,0.134071980986426,0.000248975936203567,0.199294625870235,0.24358305091454,4.74361172738652e-05,5.89666196640687e-05,0.00531027816302915,0.000200243383490462,0.0805261711344379,0.00120027603203917,0.00201705178179895,0.339181495419129,0.000229863490455131,0.0523929260778993,0.000263057002724373,0.00244241108460007,0.0261467924657004,5.9657372131903e-05,0.200512468910312,0.00810099141722299,0.013973033333956,0.0108154079325531,0.158574821336736,0.00070998197888614,0.000498608284914822,3.73054997210496e-05,0.0589374030166269,0.00230622721548646,0.0339477696166811,0.000912463632412847,0.000736710687806361,0.00409015383244036,0.245951477936874,0.0837392661445892,0.222078993106222,0.00532590926455614,0.625630979237125,0.0496003388518398,0.10116468200925,0.0661786669164834,0.0210544045965245,0.0244625178289293,0.0146510511459362,0.101257018174142,0.00316763508016474,0.00143243489499069,0.333592621341247,0.00370907687545401,0.00213872056006003,0.01900030889465,0.167144065343861,2.6100961817368e-05,4.91550277446228e-05,0.0166499896061438,0.00011398434602661,0.000359768751250008,0.00225147558163185,0.0317147645964709,0.0842595514695342,0.35407612826878,0.00010526694382132,0.0430608610020923,3.5715013356257e-05,0.000838215519554185,0.00192018265054966,0.0713712284182796,0.000485232329561933,0.00152471141515176,0.000311862603200811,0.166619420201183,0.0199021050517686,1.41779057397457e-05,0.0017318628596011,0.00053760812759845,0.0686125677803084,0.0532620439395034,0.00166666380089786,0.0113533421860016,0.000109349820296255,0.0115667016173654,0.00173679164546385,0.0256607191277514,0.00120155627964714,0.0111815333349668,0.00349052851306921,0.00531735228893806,0.00152975285273546,4.66037248418355e-05,0.0425850611539657,0.00117697776465851,1.23387751381228e-05,0.0038237470220905,0.0905644410585002,0.02820127090728,0.00024367136851271,0.147636957219027,0.000593136877076053,0.0618471045067722,9.07687985864349e-06,0.000158960279301719,0.0887358461047651,0.0332353914977947,7.4341716367417e-06,0.000892008177580303,0.000741022113249675,0.00237741099974918,0.00354813689304541,0.00074173961384706,0.00467141577324516,0.00842296482521057,0.00821661392007147,4.83792120557372e-05,0.00425252516494632,0.000432204419963046,0.00586736518573752,0.000956530707046858,0.000236851602228008,0.0892427215701044,1.38830962250345e-05,0.0080267826500828,0.284615916615109,0.000228095910528196,0.000135342214864163,7.55341699407512e-06,0.000571884401074523,0.0101768016413147,0.0171951107578717,0.00189669876455143,0.00394930354845142,0.00328294862282636,0.00123193340562429,0.00331783483858544,0.00319051646342221,0.00155129659005506,8.87358953340508e-05,0.27623170363077,0.000223827470760779,0.0568015505265356,0.000286151801691539,0.0193226057191209,0.00123755083758374,0.000465248541258071,0.0760142560624272,0.00112490607994365,0.000144842352216183,0.197405681090406,0.00129883979140284,0.0930965339402953,0.0010308437485118,0.670013359364299,0.00432667098624779,0.0454915871138651,0.00251703872973342,0.00423441033466031,0.000345157767746845,0.00161415356368555,0.00416069958683314,0.00164939718639514,0.0111406419016027,0.00655421252542946,0.00851532238518754,0.00348709627275328,0.496059905302338,0.0371917367183897,0.000211531938236732,0.000258942974591912,0.17759337052515,0.00418622722335427,0.166120697713642,0.00360502919950296,0.000407414278464457,0.0360738279541873,0.0288893174873495,0.00047259015965458,1.56547248986137e-05,0.834956154090444,0.00732703650642937,0.00474657800944094,0.00273096554923287,0.257207154892208,0.00469808491585188,0.000270576144489275,0.000136075839471612,0.097205919234904,0.000607126031374257,0.000136619984636834,0.000160087925098193,0.0073858227644151,0.538982397271589,0.00336284303209108,0.00152656630103797,0.367113302445716,7.48038626150403e-05,2.60037367946894e-05,4.68016275421979e-05,0.000158257654442151,0.000139074963089943,0.000665698879408135,0.000343142682314476,0.0686327476602143,0.000242720484154181,0.0343708294206813,0.00114889968298977,0.0586454267607763,0.0681515891243611,0.00825429790468652,0.023992046337532,0.0176721744671367,0.000118812692493978,0.152442537631382,0.017153140472422,0.0064172004743378,3.15311961394686e-05,0.0176719977165195,0.00523267370956132,0.00696013339412051,0.0283129688131134,0.000387153677372906,0.00691199037138631,0.000146275451696295,0.701230156661611,0.000192846626056869,0.000164329434653947,0.00161262788918379,0.138649850457724,0.0298984433917698,0.0318122273046375,3.04827880239274e-05,0.000447390422746664,0.00113026494701542,0.00113285595566244,2.89098339981399e-05,0.00113856357833898,0.0539144571449436,0.0708152617112735,0.000146823107858066,0.0226524231026193,0.00337461891944858,0.000951319767163979,0.00173528759879105,0.027553837556441,0.000644790987241654,0.00202675597720372,0.0904812026317863,0.000121859990107361,0.0778263959001868,0.0078676495423855,0.00106041104696191,0.0460181415526085,0.111418229601818,0.00485578450515022,0.000301615731939099,0.0991074788208953,0.000545043001929007,0.00699096247420379,0.203553031240112,0.00129391506623192,0.0163036481873179,9.84784360850182e-06,0.0011930992876943,0.000233138513444116,0.00327134762224621,0.00934510369593952,0.0257690022271133,0.0586620958023085,0.0044269686967688,0.00458204111385776,0.000575173870997244,0.0196091953126155,0.0172446254918132,0.0023874923763825,0.00203444177442346,0.00590189106361814,0.160798676736245,0.000218465854877618,0.0449130791723244,0.0221907455403962,0.00577930006864582,4.68129848124974e-05,4.39088532565896e-05,0.0957291068496414,0.000222196152405895,0.00244492299475677,0.0649283175892222,0.00246575641284538,0.00395895850035338,0.452609135498808,2.18247701431579e-05,0.000103691495491759,0.0300254483476907,0.000997825085990438,0.00120168803041095,0.000488310402876861,5.02375648302248e-05,0.0889218155230037,0.886196353445691,0.537472442381394,0.000989158503397272,0.00585452117968649,0.000166646041974894,0.0559913557856292,0.271624614149917,1.9604193016588e-05,0.00400455993655262,0.000719953658022318,0.00769221521719457,0.0122222590022294,0.00869539856191144,0.00665334452394116,0.00269456106141176,0.0203144580365219,1.06269256412071e-05,0.00266305904353431,0.000866750257077464,0.0118678506617259,0.00774140571086026,0.472668086097713,0.00449314655439557,0.000363054262255041,0.000123958362353204,0.0593128481039698,6.49758497533422e-05,0.0147733538718899,0.000181422709422017,0.124358363237549,0.0149418567595413,0.000496790567694211,0.00319609174497007,0.171371757877329,0.000132314177013318,0.000118421517677613,0.0384411149022143,0.0560023977555578,0.000545951922843868,0.00923849055867683,7.42750022847054e-05,0.0034657141222543,0.0814951536826408,0.000247436489650107,0.00279135741337402,0.128217103654628,0.000239656955359697,0.0286081920788208,0.0264861644616376,0.000700223039958121,0.000224261722502375,0.206999869456071,0.0245477336638465,0.00020080171595025,0.000534370708560753,0.00114853261836608,0.0140588914482069,0.0491695416950957,0.0219392429988939,0.000187573794241001,2.76073824918907e-05,0.0177905351398601,0.0227102533101537,0.0156338659659345,0.0045130866637909,0.0118789100672146,0.0684121072806861
};
RHEJ::MatrixElementConfig config;
config.jet_param.def = fastjet::JetDefinition(jet_def, R);
config.jet_param.min_pt = min_jet_pt;
config.log_correction = false;
config.Higgs_coupling = RHEJ::HiggsCouplingSettings{};
RHEJ::MatrixElement ME{
[](double){ return alpha_s; },
config
};
assert(events.size() == ref_weights.size());
for(size_t i = 0; i < events.size(); ++i){
std::sort(
begin(events[i].outgoing), end(events[i].outgoing),
RHEJ::rapidity_less{}
);
const double our_ME = ME.tree(
mu, events[i].incoming, events[i].outgoing, true
);
const double deviation = our_ME/ref_weights[i] - 1.;
if(std::abs(deviation) > ep){
std::cerr
<< "Matrix element deviates by factor of " << 1+deviation << ":\n"
"Is " << our_ME << ", should be " << ref_weights[i] << "\n"
"Event:\n";
dump(events[i]);
return EXIT_FAILURE;
}
const double our_virt = ME.virtual_corrections(
mu, events[i].incoming, events[i].outgoing
);
const double virt_deviation = our_virt/ref_virt[i] - 1.;
if(std::abs(virt_deviation) > ep){
std::cerr
<< "Virtual corrections deviate by factor of " << 1+virt_deviation << ":\n"
"Is " << our_virt << ", should be " << ref_virt[i] << "\n"
"Event:\n";
dump(events[i]);
return EXIT_FAILURE;
}
}
}
diff --git a/t/test_ME_hjets_mt174.cc b/t/test_ME_hjets_mt174.cc
index 45591c1..fe1cb0c 100644
--- a/t/test_ME_hjets_mt174.cc
+++ b/t/test_ME_hjets_mt174.cc
@@ -1,90 +1,90 @@
#include "LHEF/LHEF.h"
#include "RHEJ/MatrixElement.hh"
#include "RHEJ/Event.hh"
struct Event{
double weight;
- std::array<RHEJ::Sparticle, 2> incoming;
- std::vector<RHEJ::Sparticle> outgoing;
+ std::array<RHEJ::Particle, 2> incoming;
+ std::vector<RHEJ::Particle> outgoing;
Event(
double wt,
- RHEJ::Sparticle in1, RHEJ::Sparticle in2,
- std::initializer_list<RHEJ::Sparticle> out
+ RHEJ::Particle in1, RHEJ::Particle in2,
+ std::initializer_list<RHEJ::Particle> out
):
weight{wt},
incoming{std::move(in1), std::move(in2)},
outgoing{out}
{}
};
constexpr
RHEJ::pid::ParticleID PDG(int id){
return static_cast<RHEJ::pid::ParticleID>(id);
}
constexpr double alpha_s = 0.112654;
constexpr double mu = 125.;
constexpr double R = 0.4;
constexpr double min_jet_pt = 35.;
constexpr auto jet_def = fastjet::antikt_algorithm;
constexpr double ep = 1e-4;
constexpr double alpha_s_mH_RHEJ = 0.113559;
void dump(Event const & ev){
LHEF::Writer writer{std::cerr};
std::cerr << std::setprecision(15);
RHEJ::UnclusteredEvent tmp;
tmp.incoming = ev.incoming;
tmp.outgoing = ev.outgoing;
tmp.central = {mu, mu, 0.};
RHEJ::Event out_ev{std::move(tmp), {jet_def, R}, min_jet_pt};
writer.hepeup = to_HEPEUP(std::move(out_ev), nullptr);
writer.writeEvent();
}
int main(){
std::vector<Event> events = {
/*
* reference matrix elements obtained from traditional HEJ (svn r3355)
* weights correspond to shat2*wt/(pdfPtr->pdfta*pdfPtr->pdftb)
* at the end of MEt2 in HJets.cxx
*/
#include "ME_hjets_mt174.dat"
};
RHEJ::MatrixElementConfig config;
config.jet_param.def = fastjet::JetDefinition(jet_def, R);
config.jet_param.min_pt = min_jet_pt;
config.log_correction = false;
RHEJ::HiggsCouplingSettings settings;
settings.mt = 174.;
settings.use_impact_factors = false;
settings.mb = 5.;
settings.include_bottom = true;
config.Higgs_coupling = settings;
RHEJ::MatrixElement ME{
[](double){ return alpha_s; },
config
};
for(size_t i = 0; i < events.size(); ++i){
std::sort(
begin(events[i].outgoing), end(events[i].outgoing),
RHEJ::rapidity_less{}
);
const double our_ME = ME.tree(
mu, events[i].incoming, events[i].outgoing, true
);
const double deviation = our_ME/events[i].weight - 1.;
if(std::abs(deviation) > ep){
std::cerr
<< "Matrix element deviates by factor of " << 1+deviation << ":\n"
"Is " << our_ME << ", should be " << events[i].weight << "\n"
"Event:\n";
dump(events[i]);
return EXIT_FAILURE;
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Jan 20, 9:14 PM (22 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4238215
Default Alt Text
(174 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment