Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F8724077
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Subscribers
None
View Options
diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc
index 9e6e9b9..affdc09 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,670 +1,669 @@
#include "PhaseSpacePoint.hh"
#include <random>
#include <algorithm>
#include "RHEJ/Constants.hh"
#include "RHEJ/kinematics.hh"
#include "RHEJ/utility.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),
[](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::Particle const & p1, RHEJ::Particle const & p2
){
return is_parton(p1)
&& p1.type != pid::gluon
&& p2.type == pid::gluon;
}
size_t count_gluons(std::vector<Particle>::const_iterator first,
std::vector<Particle>::const_iterator last){
return std::count_if(first, last, [](Particle const & p)
{return p.type == pid::gluon;});
}
/** assumes FKL configurations between first and last,
* else there can be a quark in a non-extreme position
* e.g. uno configuration gqg would pass
*/
bool can_change_to_qqx(
std::vector<Particle>::const_iterator first,
std::vector<Particle>::const_iterator last){
return 1 < count_gluons(first,last);
}
bool is_AWZ_proccess(Process const & proc){
return proc.boson && is_AWZ_boson(*proc.boson);
}
}
void PhaseSpacePoint::maybe_turn_to_subl(
double chance,
Process const & proc,
RHEJ::RNG & ran
){
if(proc.njets <= 2) return;
assert(outgoing_.size() >= 2);
// decide what kind of subleading process is allowed
bool allow_uno = false;
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]
);
allow_uno = can_be_uno_backward || can_be_uno_forward;
bool allow_qqx = false;
if(is_AWZ_proccess(proc)) {
allow_qqx = can_change_to_qqx(outgoing_.cbegin(), outgoing_.cend());
if(incoming_[0].type == pid::gluon && incoming_[1].type == pid::gluon) {
/// enforce qqx for initial gg
allow_uno = false;
chance = 1.;
}
}
if(!allow_uno && !allow_qqx) return;
if(ran.flat() < chance){
weight_ /= chance;
if(allow_uno && !allow_qqx){
turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran);
} else if (!allow_uno && allow_qqx) {
std::cout << "only qqx" << std::endl;
turn_to_qqx(ran);
} else {
assert( allow_uno && allow_qqx);
std::cout << "both qqx and uno" << std::endl;
if(ran.flat() < 0.5) turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran);
else turn_to_qqx(ran);
weight_ *= 2.;
}
} else weight_ /= 1 - chance;
}
void PhaseSpacePoint::turn_to_uno(
const bool can_be_uno_backward, const bool can_be_uno_forward,
RHEJ::RNG & ran
){
if(!can_be_uno_backward && !can_be_uno_forward) return;
const size_t nout = outgoing_.size();
if(can_be_uno_backward && can_be_uno_forward){
if(ran.flat() < 0.5){
std::swap(outgoing_[0].type, outgoing_[1].type);
} else {
std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
}
weight_ *= 2.;
} else if(can_be_uno_backward){
std::swap(outgoing_[0].type, outgoing_[1].type);
} else {
assert(can_be_uno_forward);
std::swap(outgoing_[nout-1].type, outgoing_[nout-2].type);
}
}
void PhaseSpacePoint::turn_to_qqx(RHEJ::RNG & ran){
/// find first and last gluon in FKL chain
auto first = std::find_if(outgoing_.begin(), outgoing_.end(),
[](Particle const & p){return p.type == pid::gluon;});
auto last = std::find_if(first, outgoing_.end(),
[](Particle const & p){return is_quark(p) || is_antiquark(p);});
const size_t ng = count_gluons(first,last);
if(ng < 2)
throw std::logic_error("not enough gluons to create qqx");
// select flavour of quark
const double r1 = 2.*ran.flat()-1.;
weight_ *= n_f*2;
int flavour = pid::down;
for (double sum = 1./n_f; sum < std::abs(r1); sum += 1./n_f)
++flavour;
flavour*=r1<0.?-1:1;
// select gluon for switch
first += floor((ng-1) * ran.flat());
auto next = std::find_if(first+1, last,
[](Particle const & p){return p.type == pid::gluon;});
assert(next != outgoing_.end());
weight_ *= (ng-1);
first->type = ParticleID(flavour);
next->type = ParticleID(-flavour);
}
template<class ParticleMomenta>
fastjet::PseudoJet PhaseSpacePoint::gen_last_momentum(
ParticleMomenta const & other_momenta,
const double mass_square, const double y
) const {
std::array<double,2> pt{0.,0.};
for (auto const & p: other_momenta) {
pt[0]-= p.px();
pt[1]-= p.py();
}
const double mperp = sqrt(pt[0]*pt[0]+pt[1]*pt[1]+mass_square);
const double pz=mperp*sinh(y);
const double E=mperp*cosh(y);
return {pt[0], pt[1], pz, E};
}
PhaseSpacePoint::PhaseSpacePoint(
Process const & proc,
JetParameters const & jet_param,
RHEJ::PDF & pdf, double E_beam,
double subl_chance,
HiggsProperties const & h,
RHEJ::RNG & ran
)
{
assert(proc.njets >= 2);
status_ = good;
weight_ = 1;
const int nout = proc.njets + (proc.boson?1:0);
outgoing_.reserve(nout);
// generate parton momenta
const bool is_pure_jets = !proc.boson;
auto partons = gen_LO_partons(
proc.njets, is_pure_jets, jet_param, E_beam, ran
);
// pre fill flavour with gluons
for(auto&& p_out: partons) {
outgoing_.emplace_back(Particle{pid::gluon, std::move(p_out)});
}
if(status_ != good) return;
if(proc.boson){
switch (*proc.boson) {
case pid::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)
);
}
break;
}
case pid::Wp:{
/// @TODO implement, currently this is just a relabel Higgs
///@{
std::cout << "Emission of Wp not implemented yet.\nThis is just a place holder" << std::endl;
auto Hparticle=gen_boson(pid::Wp, 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)
);
}
///@}
break;
}
case pid::Wm:{
/// @TODO implement, currently this is just a relabel Higgs
///@{
std::cout << "Emission of Wm not implemented yet.\nThis is just a place holder" << std::endl;
auto Hparticle=gen_boson(pid::Wm, 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)
);
}
///@}
break;
}
case pid::photon:
case pid::Z:
default:
throw std::logic_error("Emission of boson of unsupported type");
}
}
// normalisation of momentum-conserving delta function
weight_ *= pow(2*M_PI, 4);
reconstruct_incoming(proc, pdf, E_beam, jet_param.min_pt, ran);
if(status_ != good) return;
// set outgoing states
most_backward_FKL(outgoing_).type = incoming_[0].type;
most_forward_FKL(outgoing_).type = incoming_[1].type;
maybe_turn_to_subl(subl_chance, proc, ran);
if(proc.boson) couple_boson(*proc.boson, ran);
#ifndef NDEBUG
if(is_AWZ_proccess(proc)){
// check that W has a quark to couple to
auto const partons = filter_partons(outgoing_);
- /// @TODO extend assert to also check flavour? Maybe easier in separate cmake test
assert(partons.front().type != pid::gluon
|| partons.back().type != pid::gluon // extremal quark
|| ( (partons.size() > 3 ) // or central qqx
&& ( 1<std::count_if(partons.cbegin()+1, partons.cend()-1,
[](Particle const & p) {return p.type != pid::gluon;})
))
);
}
#endif
}
double PhaseSpacePoint::gen_hard_pt(
int np , double ptmin, double ptmax, double y,
RHEJ::RNG & ran
) {
// heuristic parameters for pt sampling
const double ptpar = ptmin + np/5.;
const double arg_small_y = atan((ptmax - ptmin)/ptpar);
const double y_cut = 3.;
const double r1 = ran.flat();
if(y < y_cut){
const double pt = ptmin + ptpar*tan(r1*arg_small_y);
const double temp = cos(r1*arg_small_y);
weight_ *= pt*ptpar*arg_small_y/(temp*temp);
return pt;
}
const double ptpar2 = ptpar/(1 + 5*(y-y_cut));
const double temp = 1. - std::exp((ptmin-ptmax)/ptpar2);
const double pt = ptmin - ptpar2*std::log(1-r1*temp);
weight_ *= pt*ptpar2*temp/(1-r1*temp);
return pt;
}
double PhaseSpacePoint::gen_soft_pt(int np, double max_pt, RHEJ::RNG & ran) {
constexpr double ptpar = 4.;
const double r = ran.flat();
const double pt = max_pt + ptpar/np*std::log(r);
weight_ *= pt*ptpar/(np*r);
return pt;
}
double PhaseSpacePoint::gen_parton_pt(
int count, JetParameters const & jet_param, double max_pt, double y,
RHEJ::RNG & ran
) {
constexpr double p_small_pt = 0.02;
if(! jet_param.peak_pt) {
return gen_hard_pt(count, jet_param.min_pt, max_pt, y, ran);
}
const double r = ran.flat();
if(r > p_small_pt) {
weight_ /= 1. - p_small_pt;
return gen_hard_pt(count, *jet_param.peak_pt, max_pt, y, ran);
}
weight_ /= p_small_pt;
const double pt = gen_soft_pt(count, *jet_param.peak_pt, ran);
if(pt < jet_param.min_pt) {
weight_=0.0;
status_ = not_enough_jets;
return jet_param.min_pt;
}
return pt;
}
std::vector<fastjet::PseudoJet> PhaseSpacePoint::gen_LO_partons(
int np, bool is_pure_jets,
JetParameters const & jet_param,
double max_pt,
RHEJ::RNG & ran
){
if (np<2) throw std::invalid_argument{"Not enough partons in gen_LO_partons"};
weight_ /= pow(16.*pow(M_PI,3),np);
weight_ /= std::tgamma(np+1); //remove rapidity ordering
std::vector<fastjet::PseudoJet> partons;
partons.reserve(np);
for(int i = 0; i < np; ++i){
const double y = -jet_param.max_y + 2*jet_param.max_y*ran.flat();
weight_ *= 2*jet_param.max_y;
const bool is_last_parton = i+1 == np;
if(is_pure_jets && is_last_parton) {
constexpr double parton_mass_sq = 0.;
partons.emplace_back(gen_last_momentum(partons, parton_mass_sq, y));
break;
}
const double phi = 2*M_PI*ran.flat();
weight_ *= 2.0*M_PI;
const double pt = gen_parton_pt(np, jet_param, max_pt, y, ran);
if(weight_ == 0.0) return {};
partons.emplace_back(fastjet::PtYPhiM(pt, y, phi));
assert(jet_param.min_pt <= partons[i].pt());
assert(partons[i].pt() <= max_pt+1e-5);
}
// Need to check that at LO, the number of jets = number of partons;
fastjet::ClusterSequence cs(partons, jet_param.def);
auto cluster_jets=cs.inclusive_jets(jet_param.min_pt);
if (cluster_jets.size()!=unsigned(np)){
weight_=0.0;
status_ = not_enough_jets;
return {};
}
std::sort(begin(partons), end(partons), rapidity_less{});
return partons;
}
Particle PhaseSpacePoint::gen_boson(
RHEJ::ParticleID bosonid, double mass, double width,
RHEJ::RNG & ran
){
// Usual phase space measure
weight_ /= 16.*pow(M_PI, 3);
// Generate a y Gaussian distributed around 0
// TODO: magic number only for Higgs
const double y = random_normal(1.6, ran);
const double r1 = ran.flat();
const double sH = mass*(
mass + width*tan(M_PI/2.*r1 + (r1-1.)*atan(mass/width))
);
auto p = gen_last_momentum(outgoing_, sH, y);
return Particle{bosonid, std::move(p)};
}
Particle const & PhaseSpacePoint::most_backward_FKL(
std::vector<Particle> const & partons
) const{
if(!RHEJ::is_parton(partons[0])) return partons[1];
return partons[0];
}
Particle const & PhaseSpacePoint::most_forward_FKL(
std::vector<Particle> const & partons
) const{
const size_t last_idx = partons.size() - 1;
if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
return partons[last_idx];
}
Particle & PhaseSpacePoint::most_backward_FKL(
std::vector<Particle> & partons
) const{
if(!RHEJ::is_parton(partons[0])) return partons[1];
return partons[0];
}
Particle & PhaseSpacePoint::most_forward_FKL(
std::vector<Particle> & partons
) const{
const size_t last_idx = partons.size() - 1;
if(!RHEJ::is_parton(partons[last_idx])) return partons[last_idx-1];
return partons[last_idx];
}
namespace {
/// partons are ordered: even = anti, 0 = gluon
ParticleID index_to_pid(size_t i){
if(!i) return pid::gluon;
return static_cast<ParticleID>(i%2?(i+1)/2:-i/2);
}
/// decides which "index" (see index_to_pid) are allowed for process
std::bitset<11> switch_allowed(Process const & proc){
std::bitset<11> allowed = ~0;
allowed[0] = 0; // no gluon
if(abs(*proc.boson) == pid::Wp){
// special case W+2j:
// Wp: anti-down or up-type quark -> 1001100110(0) = 1228
// Wm: down or anti-up-type quark -> 0110011001(0) = 818
allowed &= (*proc.boson)>0?1228:818;
}
return allowed;
}
}
void PhaseSpacePoint::reconstruct_incoming(
Process const & proc,
RHEJ::PDF & pdf, double E_beam,
double uf,
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
*/
auto const & ids = proc.incoming;
std::array<std::bitset<11>,2> allowed_partons{~0,~0};
// special case A/W/Z+2j: needs one quark initially
if(proc.njets == 2 && is_AWZ_proccess(proc)){
// @TODO optimise: do not allow dd initial for Wp, also for 3j
if(ids[0] != pid::gluon && ids[1] != pid::gluon){
// both can be quarks => force one to be a gluon
weight_*=2.;
allowed_partons[ran.flat() < 0.5] = switch_allowed(proc);
} else if(ids[0] == pid::gluon) {
if(ids[1] == pid::gluon) {
throw RHEJ::not_implemented{
"W+2 jet process requires at least one initial quark"
};
}
// first gluon -> second has to be quark
allowed_partons[1] = switch_allowed(proc);
} else {
// second gluon -> first has to be quark
allowed_partons[0] = switch_allowed(proc);
}
}
for(size_t i = 0; i < 2; ++i){
if(ids[i] == pid::proton || ids[i] == pid::p_bar){
incoming_[i].type =
generate_incoming_id(i, i?xb:xa, uf, pdf, allowed_partons[i], ran);
} else {
incoming_[i].type = ids[i];
}
}
assert(momentum_conserved(1e-7));
}
RHEJ::ParticleID PhaseSpacePoint::generate_incoming_id(
size_t const beam_idx, double const x, double const uf,
RHEJ::PDF & pdf, std::bitset<11> allowed_partons, RHEJ::RNG & ran
){
std::array<double,11> pdf_wt;
pdf_wt[0] = allowed_partons[0]?fabs(pdf.pdfpt(beam_idx,x,uf,pid::gluon)):0.;
double pdftot = pdf_wt[0];
for(size_t i = 1; i < pdf_wt.size(); ++i){
pdf_wt[i] = allowed_partons[i]?4./9.*fabs(pdf.pdfpt(beam_idx,x,uf,index_to_pid(i))):0;
pdftot += pdf_wt[i];
}
const double r1 = pdftot * ran.flat();
double sum = 0;
for(size_t i=0; i < pdf_wt.size(); ++i){
if (r1 < (sum+=pdf_wt[i])){
weight_*= pdftot/pdf_wt[i];
return index_to_pid(i);
}
}
std::cerr << "Error in choosing incoming parton: "<<x<<" "<<uf<<" "
<<sum<<" "<<pdftot<<" "<<r1<<std::endl;
throw std::logic_error{"Failed to choose parton flavour"};
}
namespace {
bool is_up_type(Particle const & part){
return RHEJ::is_anyquark(part) && !(abs(part.type)%2);
}
bool is_down_type(Particle const & part){
return RHEJ::is_anyquark(part) && abs(part.type)%2;
}
}
void PhaseSpacePoint::couple_boson(
RHEJ::ParticleID const boson, RHEJ::RNG & ran
){
if(abs(boson) != pid::Wp) return; // only matters for W
// find all possible quarks
const int sign_W = boson>0?1:-1;
std::vector<Particle*> allowed_parts;
for(auto & part: outgoing_){
// Wp -> up OR anti-down, Wm -> anti-up OR down
if ( (sign_W*part.type > 0 && is_up_type(part))
|| (sign_W*part.type < 0 && is_down_type(part)) )
allowed_parts.push_back(&part);
}
if(!allowed_parts.size()){
/// @TODO do not allow such states in the generation
status_=wrong_final_state;
return;
}
// select one and flip it
size_t idx = 0;
if(allowed_parts.size() > 1){
/// @TODO more efficient sampling
idx = floor(ran.flat()*allowed_parts.size());
weight_ *= allowed_parts.size();
}
allowed_parts[idx]->type =
static_cast<ParticleID>( allowed_parts[idx]->type - sign_W );
}
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<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<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/W_2j_classify.cc b/FixedOrderGen/t/W_2j_classify.cc
index d65b954..9e7c2d8 100644
--- a/FixedOrderGen/t/W_2j_classify.cc
+++ b/FixedOrderGen/t/W_2j_classify.cc
@@ -1,105 +1,114 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include "PhaseSpacePoint.hh"
#include "Process.hh"
#include "JetParameters.hh"
#include "HiggsProperties.hh"
#include "RHEJ/Mixmax.hh"
#include "RHEJ/PDF.hh"
#include "RHEJ/utility.hh"
using namespace HEJFOG;
using namespace RHEJ;
namespace {
void print_event(PhaseSpacePoint const & psp){
std::cerr << "Process:\n"
<< psp.incoming()[0].type << " + "<< psp.incoming()[1].type << " -> ";
for(auto const & out: psp.outgoing()){
std::cerr << out.type << " ";
}
std::cerr << "\n";
}
void bail_out(PhaseSpacePoint const & psp, std::string msg){
print_event(psp);
throw std::logic_error{msg};
}
bool is_up_type(Particle const & part){
return RHEJ::is_anyquark(part) && !(abs(part.type)%2);
}
bool is_down_type(Particle const & part){
return RHEJ::is_anyquark(part) && abs(part.type)%2;
}
}
int main(){
constexpr size_t n_psp_base = 1337;
const JetParameters jet_para{
fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 20,5,30};
PDF pdf(11000, pid::proton, pid::proton);
constexpr double E_cms = 13000.;
constexpr double subl_change = 0.5;
const HiggsProperties higgs_para{125., 0.001,
{Decay{{pid::photon, pid::photon},1.}}};
RHEJ::Mixmax ran{};
// W2j
const Process proc {{pid::proton,pid::proton}, 2, pid::Wp};
size_t n_psp = n_psp_base;
size_t t_fail = 0;
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf, E_cms, subl_change, higgs_para, ran};
if(psp.status()==good){
bool found_quark = false;
bool found_anti = false;
- auto out_partons = filter_partons(psp.outgoing());
+ std::vector<Particle> out_partons;
+ std::vector<Particle> Wp;
+ for(auto const & p: psp.outgoing()){
+ if(p.type == pid::Wp) Wp.push_back(p);
+ else if(is_parton(p)) out_partons.push_back(p);
+ else bail_out(psp, "Found particle with is not Wp or parton");
+ }
+ if(Wp.size() != 1 || out_partons.size() != 2){
+ bail_out(psp, "Found wrong number of outgoing partons");
+ }
for(size_t j=0; j<2; ++j){
auto const & in = psp.incoming()[j];
auto const & out = out_partons[j];
if(is_quark(in) || is_antiquark(in)) {
found_quark = true;
if(in.type != out.type) { // switch in quark type -> Wp couples to it
if(found_anti){ // already found qq for coupling to W
bail_out(psp, "Found second up/down pair");
}
found_anti = true;
if( is_up_type(in)) { // "up" in
// -> only allowed u -> Wp + d
if(in.type < 0 || is_up_type(out) || out.type < 0){
// not in "q" or out "up" or out "qx" -> bail out
bail_out(psp, "u -/> Wp + d");
}
} else { // "down" in
// -> only allowed dx -> Wp + ux
if(in.type > 0 || is_down_type(out) || out.type > 0){
// not in "qx" or out "down" or out "q" -> bail out
bail_out(psp, "dx -/> Wp + ux");
}
}
}
}
}
if(!found_quark) {
bail_out(psp, "Found no initial quarks");
} else if(!found_anti){
bail_out(psp, "Found no up/down pair");
}
} else { // bad process -> try again
++n_psp;
if(psp.status()==wrong_final_state) ++t_fail;
}
}
// @TODO test final state for 3j
std::cout << "All processes passed.\nTook " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
std::cout << "Failed for wrong final state " << t_fail
<< " (" << 100.*t_fail/(n_psp-n_psp_base) << " % of fails)" << std::endl;
return EXIT_SUCCESS;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Jan 20, 10:26 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4242647
Default Alt Text
(26 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment