Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F9501449
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
105 KB
Subscribers
None
View Options
diff --git a/FixedOrderGen/configFO.yml b/FixedOrderGen/configFO.yml
index aea3393..6b9bfb7 100644
--- a/FixedOrderGen/configFO.yml
+++ b/FixedOrderGen/configFO.yml
@@ -1,79 +1,84 @@
## number of generated events
events: 200
jets:
min pt: 20
peak pt: 30
algorithm: antikt
R: 0.4
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 230000
process: p p => h 4j
## fraction of events with two extremal emissions in one direction
## that contain an subleading emission e.g. unordered emission
subleading fraction: 0.00
## Allow different subleading configurations
## By default all implemented processes are allowed.
#
# subleading channels:
# - unordered
# - qqx
scales: max jet pperp
event output:
- HEJFO.lhe
# - HEJFO_events.hepmc
+# Vacuum expectation value
+vev: 246.2196508
+
particle properties:
Higgs:
mass: 125
width: 0.004165
- decays: {into: [photon, photon], branching ratio: 0.0023568762400521404}
- Wp:
- mass: 80.385
- width: 2.085
- decays: {into: [e+, nu_e], branching ratio: 1}
- Wm:
+ W:
mass: 80.385
width: 2.085
- decays: {into: [e-, nu_e_bar]} # equivalent to "branching ratio: 1"
+ Z:
+ mass: 91.187
+ width: 2.495
random generator:
name: mixmax
# seed: 1
+decays:
+ Higgs: {into: [photon, photon], branching ratio: 0.0023568762400521404}
+ Wp: {into: [e+, nu_e], branching ratio: 1}
+ Wm: {into: [e-, nu_e_bar]} # equivalent to "branching ratio: 1"
+
## unweighting parameters
## remove to obtain weighted events
# unweight:
# sample size: 200 # should be similar to "events:", but not more than ~10000
# max deviation: 0
## to use a rivet analysis
#
# analysis:
# rivet: MC_XS # rivet analysis name
# output: HEJ # name of the yoda files, ".yoda" and scale suffix will be added
#
## to use a custom analysis
#
# analysis:
# plugin: /path/to/libmyanalysis.so
# my analysis parameter: some value
## parameters for Higgs-gluon couplings
## this requires compilation with qcdloop
#
# Higgs coupling:
# use impact factors: false
# mt: 174
# include bottom: true
# mb: 4.7
diff --git a/FixedOrderGen/include/Decay.hh b/FixedOrderGen/include/Decay.hh
index 05d9c75..f6d3ec8 100644
--- a/FixedOrderGen/include/Decay.hh
+++ b/FixedOrderGen/include/Decay.hh
@@ -1,16 +1,27 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#pragma once
-#include "HEJ/PDG_codes.hh"
+#include <unordered_map>
#include <vector>
+#include "HEJ/PDG_codes.hh"
+
namespace HEJFOG{
struct Decay{
std::vector<HEJ::ParticleID> products;
double branching_ratio;
};
+ #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6)
+ // gcc version < 6 explicitly needs hash function for enum
+ // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
+ using ParticlesDecayMap
+ = std::unordered_map<HEJ::ParticleID, std::vector<Decay>, std::hash<int>>;
+ #else
+ using ParticlesDecayMap
+ = std::unordered_map<HEJ::ParticleID, std::vector<Decay>>;
+ #endif
}
diff --git a/FixedOrderGen/include/EventGenerator.hh b/FixedOrderGen/include/EventGenerator.hh
index 896f0f6..c696c72 100644
--- a/FixedOrderGen/include/EventGenerator.hh
+++ b/FixedOrderGen/include/EventGenerator.hh
@@ -1,62 +1,65 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#pragma once
#include "HEJ/MatrixElement.hh"
#include "HEJ/optional.hh"
#include "HEJ/PDF.hh"
#include "HEJ/RNG.hh"
#include "Beam.hh"
+#include "Decay.hh"
#include "JetParameters.hh"
-#include "ParticleProperties.hh"
#include "Process.hh"
#include "Status.hh"
namespace HEJ{
class Event;
class HiggsCouplingSettings;
class ScaleGenerator;
+ class EWConstants;
}
//! Namespace for HEJ Fixed Order Generator
namespace HEJFOG{
class EventGenerator{
public:
EventGenerator(
Process process,
Beam beam,
HEJ::ScaleGenerator scale_gen,
JetParameters jets,
int pdf_id,
double subl_change,
unsigned int subl_channels,
- ParticlesPropMap particles_properties,
+ ParticlesDecayMap particles_decays,
HEJ::HiggsCouplingSettings Higgs_coupling,
+ HEJ::EWConstants ew_parameters,
HEJ::RNG & ran
);
HEJ::optional<HEJ::Event> gen_event();
Status status() const {
return status_;
}
private:
HEJ::PDF pdf_;
HEJ::MatrixElement ME_;
HEJ::ScaleGenerator scale_gen_;
Process process_;
JetParameters jets_;
Beam beam_;
Status status_;
double subl_change_;
unsigned int subl_channels_;
- ParticlesPropMap particles_properties_;
+ ParticlesDecayMap particles_decays_;
+ HEJ::EWConstants ew_parameters_;
std::reference_wrapper<HEJ::RNG> ran_;
};
}
diff --git a/FixedOrderGen/include/ParticleProperties.hh b/FixedOrderGen/include/ParticleProperties.hh
deleted file mode 100644
index 70c74b8..0000000
--- a/FixedOrderGen/include/ParticleProperties.hh
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * \authors The HEJ collaboration (see AUTHORS for details)
- * \date 2019
- * \copyright GPLv2 or later
- */
-#pragma once
-
-#include <vector>
-#include <unordered_map>
-
-#include "HEJ/EWConstants.hh"
-
-#include "Decay.hh"
-
-namespace HEJFOG{
- //! @TODO this is redundant we should be able to just call EWConstants
- struct ParticleProperties: public HEJ::ParticleProperties{
- std::vector<Decay> decays;
- ParticleProperties() = default;
- ParticleProperties(double mass_, double width_, std::vector<Decay> decays_):
- HEJ::ParticleProperties{mass_, width_}, decays{decays_}{}
- };
- #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 6)
- // gcc version < 6 explicitly needs hash function for enum
- // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
- using ParticlesPropMap
- = std::unordered_map<HEJ::ParticleID, ParticleProperties, std::hash<int>>;
- #else
- using ParticlesPropMap
- = std::unordered_map<HEJ::ParticleID, ParticleProperties>;
- #endif
-}
diff --git a/FixedOrderGen/include/PhaseSpacePoint.hh b/FixedOrderGen/include/PhaseSpacePoint.hh
index 3fc11b9..0764045 100644
--- a/FixedOrderGen/include/PhaseSpacePoint.hh
+++ b/FixedOrderGen/include/PhaseSpacePoint.hh
@@ -1,225 +1,230 @@
/** \file PhaseSpacePoint.hh
* \brief Contains the PhaseSpacePoint Class
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#pragma once
#include <bitset>
#include <vector>
#include "HEJ/Event.hh"
#include "HEJ/Particle.hh"
#include "HEJ/PDF.hh"
#include "HEJ/PDG_codes.hh"
#include "HEJ/RNG.hh"
#include "JetParameters.hh"
-#include "ParticleProperties.hh"
+#include "Decay.hh"
#include "Status.hh"
+namespace HEJ{
+ class EWConstants;
+}
+
namespace HEJFOG{
class Process;
using HEJ::Particle;
//! A point in resummation phase space
class PhaseSpacePoint{
public:
//! Default PhaseSpacePoint Constructor
- PhaseSpacePoint() = default;
+ PhaseSpacePoint() = delete;
//! PhaseSpacePoint Constructor
/**
* @param proc The process to generate
* @param jet_properties Jet defintion & cuts
* @param pdf The pdf set (used for sampling)
* @param E_beam Energie of the beam
* @param subl_chance Chance to turn a potentially unordered
* emission into an actual one
* @param subl_channels Possible subleading channels.
* see HEJFOG::Subleading
* @param particle_properties Properties of producted boson
*
* Initially, only FKL phase space points are generated. subl_chance gives
* the change of turning one emissions into a subleading configuration,
* i.e. either unordered or central quark/anti-quark pair. Unordered
* emissions require that the most extremal emission in any direction is
* a quark or anti-quark and the next emission is a gluon. Quark/anti-quark
* pairs are only generated for W processes. At most one subleading
* emission will be generated in this way.
*/
PhaseSpacePoint(
Process const & proc,
JetParameters const & jet_properties,
HEJ::PDF & pdf, double E_beam,
double subl_chance,
unsigned int subl_channels,
- ParticlesPropMap const & particles_properties,
+ ParticlesDecayMap const & particles_decays,
+ HEJ::EWConstants const & ew_parameters,
HEJ::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<Particle, 2> const & incoming() const{
return incoming_;
}
//! Get Outgoing Function
/**
* @returns Outgoing Particles
*/
std::vector<Particle> const & outgoing() const{
return outgoing_;
}
std::unordered_map<size_t, std::vector<Particle>> const & decays() const{
return decays_;
}
private:
/**
* @internal
* @brief Generate LO parton momentum
*
* @param count Number of partons to generate
* @param is_pure_jets If true ensures momentum conservation in x and y
* @param jet_param Jet properties to fulfil
* @param max_pt max allowed pt for a parton (typically E_CMS)
* @param ran Random Number Generator
*
* @returns Momentum of partons
*
* Ensures that each parton is in its own jet.
* Generation is independent of parton flavour. Output is sorted in rapidity.
*/
std::vector<fastjet::PseudoJet> gen_LO_partons(
int count, bool is_pure_jets,
JetParameters const & jet_param,
double max_pt,
HEJ::RNG & ran
);
Particle gen_boson(
HEJ::ParticleID bosonid, double mass, double width,
HEJ::RNG & ran
);
template<class ParticleMomenta>
fastjet::PseudoJet gen_last_momentum(
ParticleMomenta const & other_momenta,
double mass_square, double y
) const;
bool jets_ok(
std::vector<fastjet::PseudoJet> const & Born_jets,
std::vector<fastjet::PseudoJet> const & partons
) const;
/**
* @internal
* @brief Generate incoming partons according to the PDF
*
* @param uf Scale used in the PDF
*/
void reconstruct_incoming(
Process const & proc, unsigned int subl_channels,
HEJ::PDF & pdf, double E_beam,
double uf,
HEJ::RNG & ran
);
/**
* @internal
* @brief Returns list of all allowed initial states partons
*/
std::array<std::bitset<11>,2> filter_partons(
Process const & proc, unsigned int const subl_channels,
HEJ::RNG & ran
);
HEJ::ParticleID generate_incoming_id(
size_t beam_idx, double x, double uf, HEJ::PDF & pdf,
std::bitset<11> allowed_partons, HEJ::RNG & ran
);
bool momentum_conserved(double ep) const;
HEJ::Particle const & most_backward_FKL(
std::vector<HEJ::Particle> const & partons
) const;
HEJ::Particle const & most_forward_FKL(
std::vector<HEJ::Particle> const & partons
) const;
HEJ::Particle & most_backward_FKL(std::vector<HEJ::Particle> & partons) const;
HEJ::Particle & most_forward_FKL(std::vector<HEJ::Particle> & partons) const;
bool extremal_FKL_ok(
std::vector<fastjet::PseudoJet> const & partons
) const;
double random_normal(double stddev, HEJ::RNG & ran);
/**
* @internal
* @brief Turns a FKL configuration into a subleading one
*
* @param chance Change to switch to subleading configuration
* @param channels Allowed channels for subleading process
* @param proc Process to decide which subleading
* configurations are allowed
*
* With a chance of "chance" the FKL configuration is either turned into
* a unordered configuration or, for A/W/Z bosons, a configuration with
* a central quark/anti-quark pair.
*/
void maybe_turn_to_subl(double chance, unsigned int channels,
Process const & proc, HEJ::RNG & ran);
void turn_to_uno(bool can_be_uno_backward, bool can_be_uno_forward, HEJ::RNG & ran);
void turn_to_qqx(bool allow_strange, HEJ::RNG & ran);
//! decay where we select the decay channel
std::vector<Particle> decay_boson(
HEJ::Particle const & parent,
std::vector<Decay> const & decays,
HEJ::RNG & ran
);
//! generate decay products of a boson
std::vector<Particle> decay_boson(
HEJ::Particle const & parent,
std::vector<HEJ::ParticleID> const & decays,
HEJ::RNG & ran
);
/// @brief setup outgoing partons to ensure correct coupling to boson
void couple_boson(HEJ::ParticleID boson, HEJ::RNG & ran);
Decay select_decay_channel(
std::vector<Decay> const & decays,
HEJ::RNG & ran
);
double gen_hard_pt(
int np, double ptmin, double ptmax, double y,
HEJ::RNG & ran
);
double gen_soft_pt(int np, double ptmax, HEJ::RNG & ran);
double gen_parton_pt(
int count, JetParameters const & jet_param, double ptmax, double y,
HEJ::RNG & ran
);
double weight_;
Status status_;
std::array<Particle, 2> incoming_;
std::vector<Particle> outgoing_;
//! Particle decays in the format {outgoing index, decay products}
std::unordered_map<size_t, std::vector<Particle>> decays_;
};
HEJ::Event::EventData to_EventData(PhaseSpacePoint const & psp);
}
diff --git a/FixedOrderGen/include/config.hh b/FixedOrderGen/include/config.hh
index c104f5e..06a2487 100644
--- a/FixedOrderGen/include/config.hh
+++ b/FixedOrderGen/include/config.hh
@@ -1,44 +1,45 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#pragma once
#include "yaml-cpp/yaml.h"
#include "HEJ/HiggsCouplingSettings.hh"
#include "HEJ/optional.hh"
#include "HEJ/config.hh"
#include "HEJ/output_formats.hh"
#include "HEJ/exceptions.hh"
+#include "HEJ/EWConstants.hh"
-#include "Process.hh"
-#include "JetParameters.hh"
#include "Beam.hh"
-#include "ParticleProperties.hh"
+#include "Decay.hh"
+#include "JetParameters.hh"
+#include "Process.hh"
#include "UnweightSettings.hh"
namespace HEJFOG{
struct Config{
- //! @FIXME add EWConstants
Process process;
int events;
JetParameters jets;
Beam beam;
int pdf_id;
double subleading_fraction;
unsigned int subleading_channels; //! < see HEJFOG::Subleading
- ParticlesPropMap particles_properties;
+ ParticlesDecayMap particles_decays;
YAML::Node analysis_parameters;
HEJ::ScaleConfig scales;
std::vector<HEJ::OutputFile> output;
HEJ::RNGConfig rng;
HEJ::HiggsCouplingSettings Higgs_coupling;
+ HEJ::EWConstants ew_parameters;
HEJ::optional<UnweightSettings> unweight;
};
Config load_config(std::string const & config_file);
}
diff --git a/FixedOrderGen/src/EventGenerator.cc b/FixedOrderGen/src/EventGenerator.cc
index da0f2a5..3d2dfe6 100644
--- a/FixedOrderGen/src/EventGenerator.cc
+++ b/FixedOrderGen/src/EventGenerator.cc
@@ -1,85 +1,90 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include "EventGenerator.hh"
#include "Process.hh"
#include "Beam.hh"
#include "JetParameters.hh"
#include "PhaseSpacePoint.hh"
-#include "HEJ/Event.hh"
#include "HEJ/config.hh"
+#include "HEJ/Event.hh"
+#include "HEJ/EWConstants.hh"
namespace HEJFOG{
EventGenerator::EventGenerator(
Process process,
Beam beam,
HEJ::ScaleGenerator scale_gen,
JetParameters jets,
int pdf_id,
double subl_change,
unsigned int subl_channels,
- ParticlesPropMap particles_properties,
+ ParticlesDecayMap particles_decays,
HEJ::HiggsCouplingSettings Higgs_coupling,
+ HEJ::EWConstants ew_parameters,
HEJ::RNG & ran
):
pdf_{pdf_id, beam.particles[0], beam.particles[1]},
ME_{
[this](double mu){ return pdf_.Halphas(mu); },
HEJ::MatrixElementConfig{
false,
- std::move(Higgs_coupling)
+ std::move(Higgs_coupling),
+ ew_parameters
}
},
scale_gen_{std::move(scale_gen)},
process_{std::move(process)},
jets_{std::move(jets)},
beam_{std::move(beam)},
subl_change_{subl_change},
subl_channels_{subl_channels},
- particles_properties_{std::move(particles_properties)},
+ particles_decays_{std::move(particles_decays)},
+ ew_parameters_{ew_parameters},
ran_{ran}
{
}
HEJ::optional<HEJ::Event> EventGenerator::gen_event(){
HEJFOG::PhaseSpacePoint psp{
process_,
jets_,
pdf_, beam_.energy,
subl_change_, subl_channels_,
- particles_properties_,
+ particles_decays_,
+ ew_parameters_,
ran_
};
status_ = psp.status();
if(status_ != good) return {};
HEJ::Event ev = scale_gen_(
HEJ::Event{
to_EventData( std::move(psp) ).cluster( jets_.def, jets_.min_pt)
}
);
ev.generate_colours(ran_);
const double shat = HEJ::shat(ev);
const double xa = (ev.incoming()[0].E()-ev.incoming()[0].pz())/(2.*beam_.energy);
const double xb = (ev.incoming()[1].E()+ev.incoming()[1].pz())/(2.*beam_.energy);
// evaluate matrix element
ev.parameters() *= ME_.tree(ev)/(shat*shat);
// and PDFs
ev.central().weight *= pdf_.pdfpt(0,xa,ev.central().muf, ev.incoming()[0].type);
ev.central().weight *= pdf_.pdfpt(0,xb,ev.central().muf, ev.incoming()[1].type);
for(size_t i = 0; i < ev.variations().size(); ++i){
auto & var = ev.variations(i);
var.weight *= pdf_.pdfpt(0,xa,var.muf, ev.incoming()[0].type);
var.weight *= pdf_.pdfpt(0,xb,var.muf, ev.incoming()[1].type);
}
return ev;
}
}
diff --git a/FixedOrderGen/src/PhaseSpacePoint.cc b/FixedOrderGen/src/PhaseSpacePoint.cc
index 02880b6..63c7e2b 100644
--- a/FixedOrderGen/src/PhaseSpacePoint.cc
+++ b/FixedOrderGen/src/PhaseSpacePoint.cc
@@ -1,695 +1,693 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include "PhaseSpacePoint.hh"
#include <algorithm>
#include "CLHEP/Vector/LorentzVector.h"
#include "HEJ/Constants.hh"
+#include "HEJ/EWConstants.hh"
#include "HEJ/exceptions.hh"
#include "HEJ/kinematics.hh"
#include "HEJ/Particle.hh"
#include "HEJ/utility.hh"
#include "Process.hh"
#include "Subleading.hh"
using namespace HEJ;
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();
HEJ::Event::EventData to_EventData(PhaseSpacePoint const & psp){
HEJ::Event::EventData result;
result.incoming = psp.incoming();
assert(result.incoming.size() == 2);
result.outgoing=psp.outgoing();
// technically Event::EventData doesn't have to be sorted,
// but PhaseSpacePoint should be anyway
assert(
std::is_sorted(
begin(result.outgoing), end(result.outgoing),
HEJ::rapidity_less{}
)
);
assert(result.outgoing.size() >= 2);
result.decays=psp.decays();
result.parameters.central= {NaN, NaN, psp.weight() };
return result;
}
namespace{
bool can_swap_to_uno(
HEJ::Particle const & p1, HEJ::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);
}
bool is_up_type(Particle const & part){
return HEJ::is_anyquark(part) && !(abs(part.type)%2);
}
bool is_down_type(Particle const & part){
return HEJ::is_anyquark(part) && abs(part.type)%2;
}
bool can_couple_to_W(Particle const & part, pid::ParticleID const W_id){
const int W_charge = W_id>0?1:-1;
return abs(part.type)<5
&& ( (W_charge*part.type > 0 && is_up_type(part))
|| (W_charge*part.type < 0 && is_down_type(part)) );
}
}
void PhaseSpacePoint::maybe_turn_to_subl(
double chance,
unsigned int const channels,
Process const & proc,
HEJ::RNG & ran
){
if(proc.njets <= 2) return;
assert(outgoing_.size() >= 2);
// decide what kind of subleading process is allowed
bool allow_uno = false;
bool allow_strange = true;
const size_t nout = outgoing_.size();
const bool can_be_uno_backward = (channels&Subleading::uno)
&& can_swap_to_uno(outgoing_[0], outgoing_[1]);
const bool can_be_uno_forward = (channels&Subleading::uno)
&& 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 = (channels&Subleading::qqx)
&& can_change_to_qqx(outgoing_.cbegin(), outgoing_.cend());
if(std::none_of(outgoing_.cbegin(), outgoing_.cend(),
[&proc](Particle const & p){ return can_couple_to_W(p, *proc.boson);})) {
// enforce qqx if A/W/Z can't couple somewhere else
assert(allow_qqx);
allow_uno = false;
chance = 1.;
// strange not allowed for W
if(abs(*proc.boson)== pid::Wp) allow_strange = false;
}
}
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) {
turn_to_qqx(allow_strange, ran);
} else {
assert( allow_uno && allow_qqx);
if(ran.flat() < 0.5) turn_to_uno(can_be_uno_backward, can_be_uno_forward, ran);
else turn_to_qqx(allow_strange, ran);
weight_ *= 2.;
}
} else weight_ /= 1 - chance;
}
void PhaseSpacePoint::turn_to_uno(
const bool can_be_uno_backward, const bool can_be_uno_forward,
HEJ::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(const bool allow_strange, HEJ::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;});
std::vector<Particle*> FKL_gluons;
for(auto p = first; p!=outgoing_.end(); ++p){
if(p->type == pid::gluon) FKL_gluons.push_back(&*p);
else if(is_anyquark(*p)) break;
}
const size_t ng = FKL_gluons.size();
if(ng < 2)
throw std::logic_error("not enough gluons to create qqx");
// select flavour of quark
const double r1 = 2.*ran.flat()-1.;
const double max_flavour = allow_strange?n_f:n_f-1;
weight_ *= max_flavour*2;
int flavour = pid::down + std::floor(std::abs(r1)*max_flavour);
flavour*=r1<0.?-1:1;
// select gluon for switch
const size_t idx = floor((ng-1) * ran.flat());
weight_ *= (ng-1);
FKL_gluons[idx]->type = ParticleID(flavour);
FKL_gluons[idx+1]->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};
}
namespace {
//! adds a particle to target (in correct rapidity ordering)
//! @returns positon of insertion
auto insert_particle(std::vector<HEJ::Particle> & target,
HEJ::Particle && particle
){
const auto pos = std::upper_bound(
begin(target),end(target),particle,rapidity_less{}
);
target.insert(pos, std::move(particle));
return pos;
}
}
PhaseSpacePoint::PhaseSpacePoint(
- Process const & proc_in,
+ Process const & proc,
JetParameters const & jet_param,
HEJ::PDF & pdf, double E_beam,
double const subl_chance,
unsigned int const subl_channels,
- ParticlesPropMap const & particles_properties_in,
+ ParticlesDecayMap const & particles_decays,
+ HEJ::EWConstants const & ew_parameters,
HEJ::RNG & ran
)
{
- auto proc{ proc_in };
- auto particles_properties{ particles_properties_in };
+ // auto proc{ proc_in }; // @TODO remove
assert(proc.njets >= 2);
- if(proc.boson
- && particles_properties.find(*(proc.boson))
- == particles_properties.end())
- throw HEJ::missing_option("Boson "
- +std::to_string(*(proc.boson))+" can't be generated: missing properties");
status_ = good;
weight_ = 1;
const int nout = proc.njets + (proc.boson?1:0) + proc.boson_decay.size();
outgoing_.reserve(nout);
// generate parton momenta
const bool is_pure_jets = (nout == proc.njets);
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){ // decay boson
- const auto & boson_prop = particles_properties.at(*proc.boson);
+ const auto & boson_prop = ew_parameters.prop(*proc.boson) ;
auto boson{ gen_boson(*proc.boson, boson_prop.mass, boson_prop.width, ran) };
const auto pos{insert_particle(outgoing_, std::move(boson))};
const size_t boson_idx = std::distance(begin(outgoing_), pos);
- if( !proc.boson_decay.empty() ){
+ const auto & boson_decay = particles_decays.find(*proc.boson);
+ if( !proc.boson_decay.empty() ){ // decay given in proc
decays_.emplace(
boson_idx,
decay_boson(outgoing_[boson_idx], proc.boson_decay, ran)
);
- } else if( !boson_prop.decays.empty() ){
+ } else if( boson_decay != particles_decays.end()
+ && !boson_decay->second.empty() ){ // decay given explicitly
decays_.emplace(
boson_idx,
- decay_boson(outgoing_[boson_idx], boson_prop.decays, ran)
+ decay_boson(outgoing_[boson_idx], boson_decay->second, ran)
);
}
}
// normalisation of momentum-conserving delta function
weight_ *= pow(2*M_PI, 4);
/** @TODO
* uf (jet_param.min_pt) doesn't correspond to our final scale choice.
* The HEJ scale generators currently expect a full event as input,
* so fixing this is not completely trivial
*/
reconstruct_incoming(proc, subl_channels, 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, subl_channels, proc, ran);
if(proc.boson) couple_boson(*proc.boson, ran);
}
double PhaseSpacePoint::gen_hard_pt(
int np , double ptmin, double ptmax, double y,
HEJ::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, HEJ::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,
HEJ::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,
HEJ::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(
HEJ::ParticleID bosonid, double mass, double width,
HEJ::RNG & ran
){
// Usual phase space measure
weight_ /= 16.*pow(M_PI, 3);
// Generate a y Gaussian distributed around 0
/// @TODO check magic numbers for different boson Higgs
/// @TODO better sampling for W
const double stddev_y = 1.6;
const double y = random_normal(stddev_y, ran);
const double r1 = ran.flat();
const double s_boson = mass*(
mass + width*tan(M_PI/2.*r1 + (r1-1.)*atan(mass/width))
);
// off-shell s_boson sampling, compensates for Breit-Wigner
/// @TODO use a flag instead
if(abs(bosonid) == pid::Wp){
weight_/=M_PI*M_PI*8.;
weight_*= mass*width*( M_PI+2.*atan(mass/width) )
/ ( 1. + cos( M_PI*r1 + 2.*(r1-1.)*atan(mass/width) ) );
}
auto p = gen_last_momentum(outgoing_, s_boson, y);
return Particle{bosonid, std::move(p), {}};
}
Particle const & PhaseSpacePoint::most_backward_FKL(
std::vector<Particle> const & partons
) const{
if(!HEJ::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(!HEJ::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(!HEJ::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(!HEJ::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);
}
/// partons are ordered: even = anti, 0 = gluon
size_t pid_to_index(ParticleID id){
if(id==pid::gluon) return 0;
return id>0?id*2-1:abs(id)*2;
}
std::bitset<11> init_allowed(ParticleID const id){
if(abs(id) == pid::proton)
return ~0;
std::bitset<11> out = 0;
if(is_parton(id))
out[pid_to_index(id)] = 1;
return out;
}
/// decides which "index" (see index_to_pid) are allowed for process
std::bitset<11> allowed_quarks(ParticleID const boson){
std::bitset<11> allowed = ~0;
if(abs(boson) == pid::Wp){
// special case W:
// Wp: anti-down or up-type quark, no b/t -> 0001100110(1) = 205
// Wm: down or anti-up-type quark, no b/t -> 0010011001(1) = 307
allowed = boson>0?205:307;
}
return allowed;
}
}
/**
* checks which partons are allowed as initial state:
* 1. only allow what is given in the Runcard (p -> all)
* 2. A/W/Z require something to couple to
* a) no qqx => no incoming gluon
* b) 2j => no incoming gluon
* c) 3j => can couple OR is gluon => 2 gluons become qqx later
*/
std::array<std::bitset<11>,2> PhaseSpacePoint::filter_partons(
Process const & proc, unsigned int const subl_channels, HEJ::RNG & ran
){
std::array<std::bitset<11>,2> allowed_partons{
init_allowed(proc.incoming[0]),
init_allowed(proc.incoming[1])
};
bool const allow_qqx = subl_channels&Subleading::qqx;
// special case A/W/Z
if(is_AWZ_proccess(proc) && ((proc.njets < 4) || !allow_qqx)){
// all possible incoming states
auto allowed(allowed_quarks(*proc.boson));
if(proc.njets == 2 || !allow_qqx) allowed[0]=0;
// possible states per leg
std::array<std::bitset<11>,2> const maybe_partons{
allowed_partons[0]&allowed, allowed_partons[1]&allowed};
if(maybe_partons[0].any() && maybe_partons[1].any()){
// two options to get allowed initial state => choose one at random
const size_t idx = ran.flat() < 0.5;
allowed_partons[idx] = maybe_partons[idx];
// else choose the possible
} else if(maybe_partons[0].any()) {
allowed_partons[0] = maybe_partons[0];
} else if(maybe_partons[1].any()) {
allowed_partons[1] = maybe_partons[1];
} else{
throw std::invalid_argument{"Incoming state not allowed."};
}
}
return allowed_partons;
}
void PhaseSpacePoint::reconstruct_incoming(
Process const & proc, unsigned int const subl_channels,
HEJ::PDF & pdf, double E_beam,
double uf,
HEJ::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;
}
auto const & ids = proc.incoming;
std::array<std::bitset<11>,2> allowed_partons(
filter_partons(proc, subl_channels, ran));
for(size_t i = 0; i < 2; ++i){
if(ids[i] == pid::proton || ids[i] == pid::p_bar){
// pick ids according to pdfs
incoming_[i].type =
generate_incoming_id(i, i?xb:xa, uf, pdf, allowed_partons[i], ran);
} else {
assert(allowed_partons[i][pid_to_index(ids[i])]);
incoming_[i].type = ids[i];
}
}
assert(momentum_conserved(1e-7));
}
HEJ::ParticleID PhaseSpacePoint::generate_incoming_id(
size_t const beam_idx, double const x, double const uf,
HEJ::PDF & pdf, std::bitset<11> allowed_partons, HEJ::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"};
}
void PhaseSpacePoint::couple_boson(
HEJ::ParticleID const boson, HEJ::RNG & ran
){
if(abs(boson) != pid::Wp) return; // only matters for W
/// @TODO this could be use to sanity check gamma and Z
// find all possible quarks
std::vector<Particle*> allowed_parts;
for(auto & part: outgoing_){
// Wp -> up OR anti-down, Wm -> anti-up OR down, no bottom
if ( can_couple_to_W(part, boson) )
allowed_parts.push_back(&part);
}
if(allowed_parts.size() == 0){
throw std::logic_error{"Found no parton for coupling with boson"};
}
// select one and flip it
size_t idx = 0;
if(allowed_parts.size() > 1){
/// @TODO more efficient sampling
/// old code: probability[i] = exp(parton[i].y - W.y)
idx = floor(ran.flat()*allowed_parts.size());
weight_ *= allowed_parts.size();
}
const int W_charge = boson>0?1:-1;
allowed_parts[idx]->type =
static_cast<ParticleID>( allowed_parts[idx]->type - W_charge );
}
double PhaseSpacePoint::random_normal(
double stddev,
HEJ::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,
HEJ::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;
if(decays.size()==1) return decays.front();
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(
HEJ::Particle const & parent,
std::vector<Decay> const & decays,
HEJ::RNG & ran
){
const auto channel = select_decay_channel(decays, ran);
return decay_boson(parent, channel.products, ran);
}
std::vector<Particle> PhaseSpacePoint::decay_boson(
HEJ::Particle const & parent,
std::vector<HEJ::ParticleID> const & decays,
HEJ::RNG & ran
){
if(decays.size() != 2){
throw HEJ::not_implemented{
"only decays into two particles are implemented"
};
}
std::vector<Particle> decay_products(decays.size());
for(size_t i = 0; i < decays.size(); ++i){
decay_products[i].type = decays[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/src/config.cc b/FixedOrderGen/src/config.cc
index f0d6197..aa91355 100644
--- a/FixedOrderGen/src/config.cc
+++ b/FixedOrderGen/src/config.cc
@@ -1,408 +1,413 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include "config.hh"
#include <cctype>
#include "Subleading.hh"
#include "HEJ/config.hh"
#include "HEJ/YAMLreader.hh"
namespace HEJFOG{
using HEJ::set_from_yaml;
using HEJ::set_from_yaml_if_defined;
using HEJ::pid::ParticleID;
namespace{
//! Get YAML tree of supported options
/**
* The configuration file is checked against this tree of options
* in assert_all_options_known.
*/
YAML::Node const & get_supported_options(){
const static YAML::Node supported = [](){
YAML::Node supported;
static const auto opts = {
"process", "events", "subleading fraction","subleading channels",
- "scales", "scale factors", "max scale ratio", "pdf",
+ "scales", "scale factors", "max scale ratio", "pdf", "vev",
"event output", "analysis", "import scales"
};
// add subnodes to "supported" - the assigned value is irrelevant
for(auto && opt: opts) supported[opt] = "";
for(auto && jet_opt: {"min pt", "peak pt", "algorithm", "R", "max rapidity"}){
supported["jets"][jet_opt] = "";
}
- for(auto && particle_type: {"Higgs", "Wp", "W+", "Wm", "W-", "Z"}){
+ for(auto && particle_type: {"Higgs", "W", "Z"}){
for(auto && particle_opt: {"mass", "width"}){
supported["particle properties"][particle_type][particle_opt] = "";
}
- supported["particle properties"][particle_type]["decays"]["into"] = "";
- supported["particle properties"][particle_type]["decays"]["branching ratio"] = "";
+ }
+ for(auto && particle_type: {"Higgs", "Wp", "W+", "Wm", "W-", "Z"}){
+ for(auto && particle_opt: {"into", "branching ratio"}){
+ supported["decays"][particle_type][particle_opt] = "";
+ }
}
for(auto && opt: {"mt", "use impact factors", "include bottom", "mb"}){
supported["Higgs coupling"][opt] = "";
}
for(auto && beam_opt: {"energy", "particles"}){
supported["beam"][beam_opt] = "";
}
for(auto && unweight_opt: {"sample size", "max deviation"}){
supported["unweight"][unweight_opt] = "";
}
for(auto && opt: {"name", "seed"}){
supported["random generator"][opt] = "";
}
return supported;
}();
return supported;
}
JetParameters get_jet_parameters(
YAML::Node const & node, std::string const & entry
){
const auto p = HEJ::get_jet_parameters(node, entry);
JetParameters result;
result.def = p.def;
result.min_pt = p.min_pt;
set_from_yaml(result.max_y, node, entry, "max rapidity");
set_from_yaml_if_defined(result.peak_pt, node, entry, "peak pt");
if(result.peak_pt && *result.peak_pt <= result.min_pt)
throw std::invalid_argument{
"Value of option 'peak pt' has to be larger than 'min pt'."
};
return result;
}
Beam get_Beam(
YAML::Node const & node, std::string const & entry
){
Beam beam;
std::vector<HEJ::ParticleID> particles;
set_from_yaml(beam.energy, node, entry, "energy");
set_from_yaml_if_defined(particles, node, entry, "particles");
if(! particles.empty()){
for(HEJ::ParticleID particle: particles){
if(particle != HEJ::pid::p && particle != HEJ::pid::p_bar){
throw std::invalid_argument{
"Unsupported value in option " + entry + ": particles:"
" only proton ('p') and antiproton ('p_bar') beams are supported"
};
}
}
if(particles.size() != 2){
throw std::invalid_argument{"Not exactly two beam particles"};
}
beam.particles.front() = particles.front();
beam.particles.back() = particles.back();
}
return beam;
}
std::vector<std::string> split(
std::string const & str, std::string const & delims
){
std::vector<std::string> result;
for(size_t begin, end = 0; end != str.npos;){
begin = str.find_first_not_of(delims, end);
if(begin == str.npos) break;
end = str.find_first_of(delims, begin + 1);
result.emplace_back(str.substr(begin, end - begin));
}
return result;
}
std::invalid_argument invalid_incoming(std::string const & what){
return std::invalid_argument{
"Incoming particle type " + what + " not supported,"
" incoming particles have to be 'p', 'p_bar' or partons"
};
}
std::invalid_argument invalid_outgoing(std::string const & what){
return std::invalid_argument{
"Outgoing particle type " + what + " not supported,"
" outgoing particles have to be 'j', 'photon', 'H', 'Wm', 'Wp', 'e-', 'e+', 'nu_e', 'nu_e_bar'"
};
}
HEJ::ParticleID reconstruct_boson_id(
std::vector<HEJ::ParticleID> const & ids
){
assert(ids.size()==2);
const int pidsum = ids[0] + ids[1];
if(pidsum == +1) {
assert(HEJ::is_antilepton(ids[0]));
if(HEJ::is_antineutrino(ids[0])) {
throw HEJ::not_implemented{"lepton-flavour violating final state"};
}
assert(HEJ::is_neutrino(ids[1]));
// charged antilepton + neutrino means we had a W+
return HEJ::pid::Wp;
}
if(pidsum == -1) {
assert(HEJ::is_antilepton(ids[0]));
if(HEJ::is_neutrino(ids[1])) {
throw HEJ::not_implemented{"lepton-flavour violating final state"};
}
assert(HEJ::is_antineutrino(ids[0]));
// charged lepton + antineutrino means we had a W-
return HEJ::pid::Wm;
}
throw HEJ::not_implemented{
"final state with leptons "+HEJ::name(ids[0])+" and "+HEJ::name(ids[1])
+" not supported"
};
}
Process get_process(
YAML::Node const & node, std::string const & entry
){
Process result;
std::string process_string;
set_from_yaml(process_string, node, entry);
assert(! process_string.empty());
const auto particles = split(process_string, " \n\t\v=>");
if(particles.size() < 3){
throw std::invalid_argument{
"Bad format in option process: '" + process_string
+ "', expected format is 'in1 in2 => out1 ...'"
};
}
result.incoming.front() = HEJ::to_ParticleID(particles[0]);
result.incoming.back() = HEJ::to_ParticleID(particles[1]);
for(size_t i = 0; i < result.incoming.size(); ++i){
const HEJ::ParticleID in = result.incoming[i];
if(
in != HEJ::pid::proton && in != HEJ::pid::p_bar
&& !HEJ::is_parton(in)
){
throw invalid_incoming(particles[i]);
}
}
result.njets = 0;
for(size_t i = result.incoming.size(); i < particles.size(); ++i){
assert(! particles[i].empty());
if(particles[i] == "j") ++result.njets;
else if(std::isdigit(particles[i].front())
&& particles[i].back() == 'j')
result.njets += std::stoi(particles[i]);
else{
const auto pid = HEJ::to_ParticleID(particles[i]);
if(pid==HEJ::pid::Higgs || pid==HEJ::pid::Wp || pid==HEJ::pid::Wm){
if(result.boson)
throw std::invalid_argument{
"More than one outgoing boson is not supported"
};
if(!result.boson_decay.empty())
throw std::invalid_argument{
"Production of a boson together with a lepton is not supported"
};
result.boson = pid;
} else if (HEJ::is_anylepton(pid)){
// Do not accept more leptons, if two leptons are already mentioned
if( result.boson_decay.size()>=2 )
throw std::invalid_argument{"Too many leptons provided"};
if(result.boson)
throw std::invalid_argument{
"Production of a lepton together with a boson is not supported"
};
result.boson_decay.emplace_back(pid);
} else {
throw invalid_outgoing(particles[i]);
}
}
}
if(result.njets < 2){
throw std::invalid_argument{
"Process has to include at least two jets ('j')"
};
}
if(!result.boson_decay.empty()){
std::sort(begin(result.boson_decay),end(result.boson_decay));
assert(!result.boson);
result.boson = reconstruct_boson_id(result.boson_decay);
}
return result;
}
HEJFOG::Subleading to_subleading_channel(YAML::Node const & yaml){
std::string name;
using namespace HEJFOG::channels;
set_from_yaml(name, yaml);
if(name == "none")
return none;
if(name == "all")
return all;
if(name == "unordered" || name == "uno")
return uno;
if(name == "qqx")
return qqx;
throw HEJ::unknown_option("Unknown subleading channel '"+name+"'");
}
unsigned int get_subleading_channels(YAML::Node const & node){
using YAML::NodeType;
using namespace HEJFOG::channels;
// all channels allowed by default
if(!node) return all;
switch(node.Type()){
case NodeType::Undefined:
return all;
case NodeType::Null:
return none;
case NodeType::Scalar:
return to_subleading_channel(node);
case NodeType::Map:
throw HEJ::invalid_type{"map is not a valid option for subleading channels"};
case NodeType::Sequence:
unsigned int channels = HEJFOG::Subleading::none;
for(auto && channel_node: node){
channels |= get_subleading_channels(channel_node);
}
return channels;
}
throw std::logic_error{"unreachable"};
}
Decay get_decay(YAML::Node const & node){
Decay decay;
set_from_yaml(decay.products, node, "into");
decay.branching_ratio=1;
set_from_yaml_if_defined(decay.branching_ratio, node, "branching ratio");
return decay;
}
std::vector<Decay> get_decays(YAML::Node const & node){
using YAML::NodeType;
if(!node) return {};
switch(node.Type()){
case NodeType::Null:
case NodeType::Undefined:
return {};
case NodeType::Scalar:
throw HEJ::invalid_type{"value is not a list of decays"};
case NodeType::Map:
return {get_decay(node)};
case NodeType::Sequence:
std::vector<Decay> result;
for(auto && decay_str: node){
result.emplace_back(get_decay(decay_str));
}
return result;
}
throw std::logic_error{"unreachable"};
}
- ParticleProperties get_particle_properties(
- YAML::Node const & node, std::string const & entry
+ ParticlesDecayMap get_all_decays(YAML::Node const & node,
+ std::string const & entry
){
- ParticleProperties result;
- set_from_yaml(result.mass, node, entry, "mass");
- set_from_yaml(result.width, node, entry, "width");
- try{
- result.decays = get_decays(node[entry]["decays"]);
- }
- catch(HEJ::missing_option const & ex){
- throw HEJ::missing_option{entry + ": decays: " + ex.what()};
- }
- catch(HEJ::invalid_type const & ex){
- throw HEJ::invalid_type{entry + ": decays: " + ex.what()};
+ if(!node[entry]) return {};
+ if(!node[entry].IsMap())
+ throw HEJ::invalid_type{entry + " have to be a map"};
+ ParticlesDecayMap result;
+ for(auto const & sub_node: node[entry]) {
+ const auto name = sub_node.first.as<std::string>();
+ const auto id = HEJ::to_ParticleID(name);
+ result.emplace(id, get_decays(sub_node.second));
}
return result;
}
- ParticlesPropMap get_all_particles_properties(YAML::Node const & node){
- ParticlesPropMap result;
- for(auto const & entry: node) {
- const auto name = entry.first.as<std::string>();
- const auto id = HEJ::to_ParticleID(name);
- result.emplace(id, get_particle_properties(node,name));
- }
+ HEJ::ParticleProperties get_particle_properties(
+ YAML::Node const & node, std::string const & entry,
+ std::string const & boson
+ ){
+ HEJ::ParticleProperties result;
+ set_from_yaml(result.mass, node, entry, boson, "mass");
+ set_from_yaml(result.width, node, entry, boson, "width");
+ return result;
+ }
+
+ HEJ::EWConstants get_ew_parameters(YAML::Node const & node){
+ HEJ::EWConstants result;
+ double vev;
+ set_from_yaml(vev, node, "vev");
+ result.set_vevWZH(vev,
+ get_particle_properties(node, "particle properties", "W"),
+ get_particle_properties(node, "particle properties", "Z"),
+ get_particle_properties(node, "particle properties", "Higgs")
+ );
return result;
}
UnweightSettings get_unweight(
YAML::Node const & node, std::string const & entry
){
UnweightSettings result;
set_from_yaml(result.sample_size, node, entry, "sample size");
if(result.sample_size <= 0){
throw std::invalid_argument{
"negative sample size " + std::to_string(result.sample_size)
};
}
set_from_yaml(result.max_dev, node, entry, "max deviation");
return result;
}
Config to_Config(YAML::Node const & yaml){
try{
HEJ::assert_all_options_known(yaml, get_supported_options());
}
catch(HEJ::unknown_option const & ex){
throw HEJ::unknown_option{std::string{"Unknown option '"} + ex.what() + "'"};
}
Config config;
config.process = get_process(yaml, "process");
set_from_yaml(config.events, yaml, "events");
config.jets = get_jet_parameters(yaml, "jets");
config.beam = get_Beam(yaml, "beam");
for(size_t i = 0; i < config.process.incoming.size(); ++i){
const auto & in = config.process.incoming[i];
using namespace HEJ::pid;
if( (in == p || in == p_bar) && in != config.beam.particles[i]){
throw std::invalid_argument{
"Particle type of beam " + std::to_string(i+1) + " incompatible"
+ " with type of incoming particle " + std::to_string(i+1)
};
}
}
set_from_yaml(config.pdf_id, yaml, "pdf");
set_from_yaml(config.subleading_fraction, yaml, "subleading fraction");
if(config.subleading_fraction < 0 || config.subleading_fraction > 1){
throw std::invalid_argument{
"subleading fraction has to be between 0 and 1"
};
}
if(config.subleading_fraction == 0)
config.subleading_channels = Subleading::none;
else
config.subleading_channels = get_subleading_channels(yaml["subleading channels"]);
- if(yaml["particle properties"]){
- config.particles_properties = get_all_particles_properties(
- yaml["particle properties"]);
- }
- if(config.process.boson
- && config.particles_properties.find(*(config.process.boson))
- == config.particles_properties.end())
- throw HEJ::missing_option("Process wants to generate boson "
- +std::to_string(*(config.process.boson))+", but particle properties are missing");
+ config.ew_parameters = get_ew_parameters(yaml);
+ config.particles_decays = get_all_decays(yaml, "decays");
set_from_yaml_if_defined(config.analysis_parameters, yaml, "analysis");
config.scales = HEJ::to_ScaleConfig(yaml);
set_from_yaml_if_defined(config.output, yaml, "event output");
config.rng = HEJ::to_RNGConfig(yaml, "random generator");
config.Higgs_coupling = HEJ::get_Higgs_coupling(yaml, "Higgs coupling");
if(yaml["unweight"]) config.unweight = get_unweight(yaml, "unweight");
return config;
}
} // namespace anonymous
Config load_config(std::string const & config_file){
try{
return to_Config(YAML::LoadFile(config_file));
}
catch(...){
std::cerr << "Error reading " << config_file << ":\n ";
throw;
}
}
}
diff --git a/FixedOrderGen/src/main.cc b/FixedOrderGen/src/main.cc
index 461202a..f1fdbe9 100644
--- a/FixedOrderGen/src/main.cc
+++ b/FixedOrderGen/src/main.cc
@@ -1,233 +1,234 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#include <algorithm>
#include <chrono>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include "yaml-cpp/yaml.h"
#include "LHEF/LHEF.h"
#include "HEJ/CombinedEventWriter.hh"
#include "HEJ/CrossSectionAccumulator.hh"
#include "HEJ/get_analysis.hh"
#include "HEJ/LesHouchesWriter.hh"
#include "HEJ/make_RNG.hh"
#include "HEJ/ProgressBar.hh"
#include "HEJ/stream.hh"
#include "config.hh"
#include "EventGenerator.hh"
#include "PhaseSpacePoint.hh"
#include "Unweighter.hh"
#include "Version.hh"
namespace{
constexpr auto banner =
" __ ___ __ ______ __ "
" __ \n / / / (_)___ _/ /_ / ____/___ "
" ___ _________ ___ __ / /__ / /______ \n "
" / /_/ / / __ `/ __ \\ / __/ / __ \\/ _ \\/ ___/ __ `/ / / / __ / / _"
" \\/ __/ ___/ \n / __ / / /_/ / / / / / /___/ /"
" / / __/ / / /_/ / /_/ / / /_/ / __/ /_(__ ) "
" \n /_/ /_/_/\\__, /_/ /_/ /_____/_/ /_/\\___/_/ \\__, /\\__, / \\___"
"_/\\___/\\__/____/ \n ____///__/ "
"__ ____ ///__//____/ ______ __ "
" \n / ____(_) _____ ____/ / / __ \\_________/ /__ _____ / "
"____/__ ____ ___ _________ _/ /_____ _____\n / /_ / / |/_/ _ \\/ __"
" / / / / / ___/ __ / _ \\/ ___/ / / __/ _ \\/ __ \\/ _ \\/ ___/ __ `/ "
"__/ __ \\/ ___/\n / __/ / /> </ __/ /_/ / / /_/ / / / /_/ / __/ / "
" / /_/ / __/ / / / __/ / / /_/ / /_/ /_/ / / \n /_/ /_/_/|_|\\___"
"/\\__,_/ \\____/_/ \\__,_/\\___/_/ \\____/\\___/_/ /_/\\___/_/ "
"\\__,_/\\__/\\____/_/ \n";
constexpr double invGeV2_to_pb = 389379292.;
constexpr long long max_warmup_events = 10000;
}
HEJFOG::Config load_config(char const * filename){
try{
return HEJFOG::load_config(filename);
}
catch(std::exception const & exc){
std::cerr << "Error: " << exc.what() << '\n';
std::exit(EXIT_FAILURE);
}
}
std::unique_ptr<HEJ::Analysis> get_analysis(
YAML::Node const & parameters
){
try{
return HEJ::get_analysis(parameters);
}
catch(std::exception const & exc){
std::cerr << "Failed to load analysis: " << exc.what() << '\n';
std::exit(EXIT_FAILURE);
}
}
int main(int argn, char** argv) {
using namespace std::string_literals;
if (argn < 2) {
std::cerr << "\n# Usage:\n." << argv[0] << " config_file\n";
return EXIT_FAILURE;
}
std::cout << banner;
std::cout << "Version " << HEJFOG::Version::String()
<< ", revision " << HEJFOG::Version::revision() << std::endl;
fastjet::ClusterSequence::print_banner();
using clock = std::chrono::system_clock;
const auto start_time = clock::now();
// read configuration
auto config = load_config(argv[1]);
std::unique_ptr<HEJ::Analysis> analysis = get_analysis(
config.analysis_parameters
);
assert(analysis != nullptr);
auto ran = HEJ::make_RNG(config.rng.name, config.rng.seed);
assert(ran != nullptr);
HEJ::ScaleGenerator scale_gen{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
std::move(scale_gen),
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
*ran
};
LHEF::HEPRUP heprup;
heprup.IDBMUP=std::pair<long,long>(config.beam.particles[0], config.beam.particles[1]);
heprup.EBMUP=std::make_pair(config.beam.energy, config.beam.energy);
heprup.PDFGUP=std::make_pair(0,0);
heprup.PDFSUP=std::make_pair(config.pdf_id,config.pdf_id);
heprup.NPRUP=1;
heprup.XSECUP=std::vector<double>(1.);
heprup.XERRUP=std::vector<double>(1.);
heprup.LPRUP=std::vector<int>{1};
heprup.generators.emplace_back(LHEF::XMLTag{});
heprup.generators.back().name = HEJFOG::Version::package_name();
heprup.generators.back().version = HEJFOG::Version::String();
HEJ::CombinedEventWriter writer{config.output, heprup};
HEJ::optional<HEJFOG::Unweighter> unweighter{};
std::map<HEJFOG::Status, int> status_counter;
std::vector<HEJ::Event> events;
int trials = 0;
// warm-up phase to train unweighter
if(config.unweight) {
std::cout << "Calibrating unweighting ...\n";
const auto warmup_start = clock::now();
const size_t warmup_events = config.unweight->sample_size;
HEJ::ProgressBar<size_t> warmup_progress{std::cout, warmup_events};
for(; events.size() < warmup_events; ++trials){
auto ev = generator.gen_event();
++status_counter[generator.status()];
assert( (generator.status() == HEJFOG::good) == bool(ev) );
if(generator.status() == HEJFOG::good && analysis->pass_cuts(*ev, *ev)) {
events.emplace_back(std::move(*ev));
++warmup_progress;
}
}
std::cout << std::endl;
unweighter = HEJFOG::Unweighter{
begin(events), end(events), config.unweight->max_dev, *ran,
config.jets.peak_pt?(*config.jets.peak_pt):0.
};
std::vector<HEJ::Event> unweighted_events;
for(auto && ev: events) {
auto unweighted = unweighter->unweight(std::move(ev));
if(unweighted) {
unweighted_events.emplace_back(std::move(*unweighted));
}
}
events = std::move(unweighted_events);
if(events.empty()) {
std::cerr <<
"Failed to generate events. Please increase \"unweight: sample size\""
" or reduce \"unweight: max deviation\"\n";
return EXIT_FAILURE;
}
const auto warmup_end = clock::now();
const double completion = static_cast<double>(events.size())/config.events;
const std::chrono::duration<double> remaining_time =
(warmup_end- warmup_start)*(1./completion - 1);
const auto finish = clock::to_time_t(
std::chrono::time_point_cast<std::chrono::seconds>(warmup_end + remaining_time)
);
std::cout
<< "Generated " << events.size() << "/" << config.events << " events ("
<< static_cast<int>(std::round(100*completion)) << "%)\n"
<< "Estimated remaining generation time: "
<< remaining_time.count() << " seconds ("
<< std::put_time(std::localtime(&finish), "%c") << ")\n\n";
}
HEJ::ProgressBar<long long> progress{std::cout, config.events};
progress.increment(events.size());
events.reserve(config.events);
for(; events.size() < static_cast<size_t>(config.events); ++trials){
auto ev = generator.gen_event();
++status_counter[generator.status()];
assert( (generator.status() == HEJFOG::good) == bool(ev) );
if(generator.status() == HEJFOG::good && analysis->pass_cuts(*ev, *ev)) {
if(unweighter) {
auto unweighted = unweighter->unweight(std::move(*ev));
if(! unweighted) continue;
ev = std::move(unweighted);
}
events.emplace_back(std::move(*ev));
++progress;
}
}
std::cout << std::endl;
HEJ::CrossSectionAccumulator xs;
for(auto & ev: events){
ev.parameters() *= invGeV2_to_pb/trials;
analysis->fill(ev, ev);
writer.write(ev);
xs.fill(ev);
}
analysis->finalise();
const std::chrono::duration<double> run_time = (clock::now() - start_time);
std::cout << "\nTask Runtime: " << run_time.count() << " seconds.\n\n";
std::cout << xs << '\n';
for(auto && entry: status_counter){
const double fraction = static_cast<double>(entry.second)/trials;
const int percent = std::round(100*fraction);
std::cout << "status "
<< std::left << std::setw(16) << (to_string(entry.first) + ":")
<< " [";
for(int i = 0; i < percent/2; ++i) std::cout << '#';
for(int i = percent/2; i < 50; ++i) std::cout << ' ';
std::cout << "] " << percent << "%\n";
}
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/2j.cc b/FixedOrderGen/t/2j.cc
index 36380a7..99419ba 100644
--- a/FixedOrderGen/t/2j.cc
+++ b/FixedOrderGen/t/2j.cc
@@ -1,66 +1,67 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Mixmax.hh"
#include "HEJ/Event.hh"
#include "HEJ/PDF.hh"
#include "HEJ/MatrixElement.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 86.42031848*1e6; //calculated with "combined" HEJ svn r3480
auto config = load_config("config_2j.yml");
HEJ::Mixmax ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
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.01*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/4j.cc b/FixedOrderGen/t/4j.cc
index a5c33a9..8d9aa41 100644
--- a/FixedOrderGen/t/4j.cc
+++ b/FixedOrderGen/t/4j.cc
@@ -1,67 +1,68 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Mixmax.hh"
#include "HEJ/Event.hh"
#include "HEJ/PDF.hh"
#include "HEJ/MatrixElement.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 0.81063619*1e6; //calculated with "combined" HEJ svn r3480
auto config = load_config("config_2j.yml");
config.process.njets = 4;
HEJ::Mixmax ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
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.03*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/W_2j_classify.cc b/FixedOrderGen/t/W_2j_classify.cc
index bf1d22b..62e8779 100644
--- a/FixedOrderGen/t/W_2j_classify.cc
+++ b/FixedOrderGen/t/W_2j_classify.cc
@@ -1,152 +1,158 @@
/**
* \brief check that the PSP generates only "valid" W + 2 jets events
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
+#include "Decay.hh"
#include "JetParameters.hh"
-#include "ParticleProperties.hh"
#include "PhaseSpacePoint.hh"
#include "Process.hh"
#include "Subleading.hh"
+#include "HEJ/EWConstants.hh"
#include "HEJ/Mixmax.hh"
#include "HEJ/PDF.hh"
#include "HEJ/utility.hh"
using namespace HEJFOG;
using namespace HEJ;
namespace {
void print_psp(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_psp(psp);
throw std::logic_error{msg};
}
bool is_up_type(Particle const & part){
return HEJ::is_anyquark(part) && !(abs(part.type)%2);
}
bool is_down_type(Particle const & part){
return HEJ::is_anyquark(part) && abs(part.type)%2;
}
bool check_W2j(PhaseSpacePoint const & psp, ParticleID const W_type){
bool found_quark = false;
bool found_anti = false;
std::vector<Particle> out_partons;
std::vector<Particle> Wp;
for(auto const & p: psp.outgoing()){
if(p.type == W_type) Wp.push_back(p);
else if(is_parton(p)) out_partons.push_back(p);
else bail_out(psp, "Found particle with is not "
+std::to_string(int(W_type))+" 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");
} else if(abs(in.type)>4 || abs(out.type)>4){
bail_out(psp, "Found bottom/top pair");
}
found_anti = true;
if( is_up_type(in)) { // "up" in
if(W_type > 0){
// -> only allowed u -> Wp + d
if(in.type < 0 || is_up_type(out) || out.type < 0)
bail_out(psp, "u -/> Wp + d");
} else {
// -> only allowed ux -> Wm + dx
if(in.type > 0 || is_up_type(out) || out.type > 0)
bail_out(psp, "ux -/> Wm + dx");
}
} else { // "down" in
if(W_type > 0){
// -> only allowed dx -> Wp + ux
if(in.type > 0 || is_down_type(out) || out.type > 0)
bail_out(psp, "dx -/> Wp + ux");
} else {
// -> only allowed d -> Wm + u
if(in.type < 0 || is_down_type(out) || out.type < 0)
bail_out(psp, "d -/> Wm + u");
}
}
}
}
}
if(!found_quark) {
bail_out(psp, "Found no initial quarks");
} else if(!found_anti){
bail_out(psp, "Found no up/down pair");
}
return true;
}
}
int main(){
constexpr size_t n_psp_base = 1337;
const JetParameters jet_para{
fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 30, 5, 30};
PDF pdf(11000, pid::proton, pid::proton);
constexpr double E_cms = 13000.;
constexpr double subl_change = 0.5;
constexpr auto subl_channels = Subleading::all;
- const ParticlesPropMap boson_prop{
- {pid::Wp, {91.1876, 2.085, {Decay{ {pid::e_bar, pid::nu_e}, 1.}} }},
- {pid::Wm, {91.1876, 2.085, {Decay{ {pid::e, pid::nu_e_bar}, 1.}} }}
+ const ParticlesDecayMap boson_decays{
+ {pid::Wp, {Decay{ {pid::e_bar, pid::nu_e}, 1.} }},
+ {pid::Wm, {Decay{ {pid::e, pid::nu_e_bar}, 1.} }}
};
+ const EWConstants ew_constants{246.2196508,
+ ParticleProperties{80.385, 2.085},
+ ParticleProperties{91.187, 2.495},
+ ParticleProperties{125, 0.004165}
+ };
HEJ::Mixmax ran{};
// Wp2j
Process proc {{pid::proton,pid::proton}, 2, pid::Wp, {}};
size_t n_psp = n_psp_base;
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels,
- boson_prop, ran};
+ boson_decays, ew_constants, ran};
if(psp.status()==good){
check_W2j(psp, *proc.boson);
} else { // bad process -> try again
++n_psp;
}
}
std::cout << "Wp+2j: Took " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
// Wm2j
proc = Process{{pid::proton,pid::proton}, 2, pid::Wm, {}};
n_psp = n_psp_base;
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels,
- boson_prop, ran};
+ boson_decays, ew_constants, ran};
if(psp.status()==good){
check_W2j(psp, *proc.boson);
} else { // bad process -> try again
++n_psp;
}
}
std::cout << "Wm+2j: Took " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
std::cout << "All processes passed." << std::endl;
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/W_nj_classify.cc b/FixedOrderGen/t/W_nj_classify.cc
index bb95029..542ac76 100644
--- a/FixedOrderGen/t/W_nj_classify.cc
+++ b/FixedOrderGen/t/W_nj_classify.cc
@@ -1,184 +1,190 @@
/**
* \brief check that the PSP generates the all W+jet subleading processes
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include "JetParameters.hh"
-#include "ParticleProperties.hh"
+#include "Decay.hh"
#include "PhaseSpacePoint.hh"
#include "Process.hh"
#include "Subleading.hh"
#include "HEJ/Event.hh"
+#include "HEJ/EWConstants.hh"
#include "HEJ/Mixmax.hh"
#include "HEJ/PDF.hh"
#include "HEJ/utility.hh"
using namespace HEJFOG;
using namespace HEJ;
namespace {
void print_psp(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_psp(psp);
throw std::logic_error{msg};
}
}
int main(){
constexpr size_t n_psp_base = 10375;
const JetParameters jet_para{
fastjet::JetDefinition(fastjet::JetAlgorithm::antikt_algorithm, 0.4), 30, 5, 30};
PDF pdf(11000, pid::proton, pid::proton);
constexpr double E_cms = 13000.;
constexpr double subl_change = 0.8;
- const ParticlesPropMap boson_prop{
- {pid::Wp, {91.1876, 2.085, {Decay{ {pid::e_bar, pid::nu_e}, 1.}} }},
- {pid::Wm, {91.1876, 2.085, {Decay{ {pid::e, pid::nu_e_bar}, 1.}} }}
+ const ParticlesDecayMap boson_decays{
+ {pid::Wp, {Decay{ {pid::e_bar, pid::nu_e}, 1.} }},
+ {pid::Wm, {Decay{ {pid::e, pid::nu_e_bar}, 1.} }}
};
+ const EWConstants ew_constants{246.2196508,
+ ParticleProperties{80.385, 2.085},
+ ParticleProperties{91.187, 2.495},
+ ParticleProperties{125, 0.004165}
+ };
HEJ::Mixmax ran{};
auto subl_channels = Subleading::all;
std::vector<event_type::EventType> allowed_types{event_type::FKL,
event_type::unob, event_type::unof, event_type::qqxexb, event_type::qqxexf};
std::cout << "Wp3j" << std::endl;
// Wp3j
Process proc {{pid::proton,pid::proton}, 3, pid::Wp, {}};
size_t n_psp = n_psp_base;
std::unordered_map<event_type::EventType, size_t> type_counter;
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels,
- boson_prop, ran};
+ boson_decays, ew_constants, ran};
if(psp.status()==good){
const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt) };
++type_counter[ev.type()];
if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type())
== allowed_types.cend()) {
bail_out(psp, "Found not allowed event of type "
+std::string(event_type::name(ev.type())));
}
} else { // bad process -> try again
++n_psp;
}
}
std::cout << "Wp+3j: Took " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
std::cout << "States by classification:\n";
for(auto const & entry: type_counter){
const double fraction = static_cast<double>(entry.second)/n_psp_base;
const int percent = std::round(100*fraction);
std::cout << std::left << std::setw(25)
<< (event_type::name(entry.first) + std::string(":"))
<< entry.second << " (" << percent << "%)\n";
}
for(auto const & t: allowed_types){
if(type_counter[t] < 0.05 * n_psp_base){
std::cerr << "Less than 5% of the events are of type " << event_type::name(t) << std::endl;
return EXIT_FAILURE;
}
}
// Wm3j - only uno
proc = Process{{pid::proton,pid::proton}, 3, pid::Wm, {}};
n_psp = n_psp_base;
subl_channels = Subleading::uno;
allowed_types = {event_type::FKL, event_type::unob, event_type::unof};
type_counter.clear();
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels,
- boson_prop, ran};
+ boson_decays, ew_constants, ran};
if(psp.status()==good){
const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt) };
++type_counter[ev.type()];
if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type())
== allowed_types.cend()) {
bail_out(psp, "Found not allowed event of type "
+std::string(event_type::name(ev.type())));
}
} else { // bad process -> try again
++n_psp;
}
}
std::cout << "Wm+3j (only uno): Took " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
std::cout << "States by classification:\n";
for(auto const & entry: type_counter){
const double fraction = static_cast<double>(entry.second)/n_psp_base;
const int percent = std::round(100*fraction);
std::cout << std::left << std::setw(25)
<< (event_type::name(entry.first) + std::string(":"))
<< entry.second << " (" << percent << "%)\n";
}
for(auto const & t: allowed_types){
if(type_counter[t] < 0.05 * n_psp_base){
std::cerr << "Less than 5% of the events are of type " << event_type::name(t) << std::endl;
return EXIT_FAILURE;
}
}
// Wm4j
proc = Process{{pid::proton,pid::proton}, 4, pid::Wm, {}};
n_psp = n_psp_base;
subl_channels = Subleading::all;
allowed_types = {event_type::FKL,
event_type::unob, event_type::unof, event_type::qqxexb, event_type::qqxexf,
event_type::qqxmid};
type_counter.clear();
for( size_t i = 0; i<n_psp; ++i){
const PhaseSpacePoint psp{proc,jet_para,pdf,E_cms, subl_change,subl_channels,
- boson_prop, ran};
+ boson_decays, ew_constants, ran};
if(psp.status()==good){
const Event ev{ to_EventData(psp).cluster(jet_para.def, jet_para.min_pt)};
++type_counter[ev.type()];
if( std::find(allowed_types.cbegin(), allowed_types.cend(), ev.type())
== allowed_types.cend()) {
bail_out(psp, "Found not allowed event of type "
+std::string(event_type::name(ev.type())));
}
} else { // bad process -> try again
++n_psp;
}
}
std::cout << "Wm+4j: Took " << n_psp << " to generate "
<< n_psp_base << " successfully PSP (" << 1.*n_psp/n_psp_base << " trials/PSP)" << std::endl;
std::cout << "States by classification:\n";
for(auto const & entry: type_counter){
const double fraction = static_cast<double>(entry.second)/n_psp_base;
const int percent = std::round(100*fraction);
std::cout << std::left << std::setw(25)
<< (event_type::name(entry.first) + std::string(":"))
<< entry.second << " (" << percent << "%)\n";
}
for(auto const & t: allowed_types){
if(type_counter[t] < 0.03 * n_psp_base){
std::cerr << "Less than 3% of the events are of type " << event_type::name(t) << std::endl;
return EXIT_FAILURE;
}
}
std::cout << "All processes passed." << std::endl;
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/W_reconstruct_enu.cc b/FixedOrderGen/t/W_reconstruct_enu.cc
index 1db956a..8af3615 100644
--- a/FixedOrderGen/t/W_reconstruct_enu.cc
+++ b/FixedOrderGen/t/W_reconstruct_enu.cc
@@ -1,71 +1,72 @@
/**
* \brief that the reconstruction of the W works
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Event.hh"
#include "HEJ/Mixmax.hh"
using namespace HEJFOG;
using namespace HEJ;
namespace {
constexpr size_t num_events = 1000;
constexpr double invGeV2_to_pb = 389379292.;
}
double get_xs(std::string config_name){
auto config { load_config(config_name) };
config.events = num_events;
HEJ::Mixmax ran{1};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
ran
};
double xs = 0.;
for (int trials = 0; trials < config.events; ++trials){
auto ev = generator.gen_event();
if(generator.status() != good) continue;
assert(ev);
ev->central().weight *= invGeV2_to_pb;
ev->central().weight /= config.events;
xs += ev->central().weight;
}
return xs;
}
int main(){
double xs_W{ get_xs("config_Wp_2j.yml")};
double xs_enu{ get_xs("config_Wp_2j_decay.yml")};
if(std::abs(xs_W/xs_enu-1.)>1e-6){
std::cerr << "Reconstructing the W in the runcard gave a different results ("
<< xs_W << " vs. "<< xs_enu << " -> " << std::abs(xs_W/xs_enu-1.)*100 << "%)\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/config_2j.yml b/FixedOrderGen/t/config_2j.yml
index 4431412..3b605fd 100644
--- a/FixedOrderGen/t/config_2j.yml
+++ b/FixedOrderGen/t/config_2j.yml
@@ -1,28 +1,36 @@
events: 100000
jets:
min pt: 30
R: 0.4
algorithm: antikt
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 11000
process: p p => 2j
subleading fraction: 0.1
subleading channels: none
scales: 125
random generator:
name: mixmax
particle properties:
Higgs:
mass: 125
width: 0
+ W:
+ mass: 80.385
+ width: 2.085
+ Z:
+ mass: 91.187
+ width: 2.495
+
+vev: 246.2196508
diff --git a/FixedOrderGen/t/config_Wp_2j.yml b/FixedOrderGen/t/config_Wp_2j.yml
index 1f3874d..14b9216 100644
--- a/FixedOrderGen/t/config_Wp_2j.yml
+++ b/FixedOrderGen/t/config_Wp_2j.yml
@@ -1,27 +1,35 @@
events: 200000
jets:
min pt: 30
R: 0.4
algorithm: antikt
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 11000
process: p p => e+ nu_e 2j
subleading fraction: 0.37
scales: 125
particle properties:
- Wp:
+ Higgs:
+ mass: 125
+ width: 0.004165
+ W:
mass: 80.385
width: 2.085
+ Z:
+ mass: 91.187
+ width: 2.495
random generator:
name: mixmax
+
+vev: 246.2196508
diff --git a/FixedOrderGen/t/config_Wp_2j_decay.yml b/FixedOrderGen/t/config_Wp_2j_decay.yml
index 7979293..37ce351 100644
--- a/FixedOrderGen/t/config_Wp_2j_decay.yml
+++ b/FixedOrderGen/t/config_Wp_2j_decay.yml
@@ -1,28 +1,38 @@
events: 200000
jets:
min pt: 30
R: 0.4
algorithm: antikt
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 11000
process: p p => Wp 2j
subleading fraction: 0.37
scales: 125
particle properties:
- Wp:
+ Higgs:
+ mass: 125
+ width: 0.004165
+ W:
mass: 80.385
width: 2.085
- decays: {into: [e+, nu_e], branching ratio: 1}
+ Z:
+ mass: 91.187
+ width: 2.495
+
+decays:
+ Wp: {into: [e+, nu_e], branching ratio: 1}
random generator:
name: mixmax
+
+vev: 246.2196508
diff --git a/FixedOrderGen/t/config_h_2j.yml b/FixedOrderGen/t/config_h_2j.yml
index b5a4ff9..7e8695e 100644
--- a/FixedOrderGen/t/config_h_2j.yml
+++ b/FixedOrderGen/t/config_h_2j.yml
@@ -1,28 +1,36 @@
events: 200000
jets:
min pt: 30
R: 0.4
algorithm: antikt
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 11000
process: p p => h 2j
subleading fraction: 0.37
subleading channels: none
scales: 125
particle properties:
Higgs:
mass: 125
width: 0
+ W:
+ mass: 80.385
+ width: 2.085
+ Z:
+ mass: 91.187
+ width: 2.495
random generator:
name: mixmax
+
+vev: 246.2196508
diff --git a/FixedOrderGen/t/config_h_2j_decay.yml b/FixedOrderGen/t/config_h_2j_decay.yml
index fb157e9..d8ec47e 100644
--- a/FixedOrderGen/t/config_h_2j_decay.yml
+++ b/FixedOrderGen/t/config_h_2j_decay.yml
@@ -1,28 +1,38 @@
events: 200000
jets:
min pt: 30
R: 0.4
algorithm: antikt
max rapidity: 5
beam:
energy: 6500
particles: [p, p]
pdf: 11000
process: p p => h 2j
subleading fraction: 0
scales: 125
particle properties:
Higgs:
mass: 125
width: 0.00407
- decays: {into: [photon, photon], branching ratio: 0.00228}
+ W:
+ mass: 80.385
+ width: 2.085
+ Z:
+ mass: 91.187
+ width: 2.495
+
+decays:
+ Higgs: {into: [photon, photon], branching ratio: 0.00228}
random generator:
name: mixmax
+
+vev: 246.2196508
diff --git a/FixedOrderGen/t/h_2j.cc b/FixedOrderGen/t/h_2j.cc
index 0c557ad..18c11d0 100644
--- a/FixedOrderGen/t/h_2j.cc
+++ b/FixedOrderGen/t/h_2j.cc
@@ -1,74 +1,75 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Mixmax.hh"
#include "HEJ/Event.hh"
#include "HEJ/PDF.hh"
#include "HEJ/MatrixElement.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 2.04928; // +- 0.00377252
//calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20
auto config = load_config("config_h_2j.yml");
HEJ::Mixmax ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
ev->central().weight *= invGeV2_to_pb;
ev->central().weight /= config.events;
const auto the_Higgs = std::find_if(
begin(ev->outgoing()), end(ev->outgoing()),
[](HEJ::Particle const & p){ return p.type == HEJ::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 << std::endl;
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.01*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/h_2j_decay.cc b/FixedOrderGen/t/h_2j_decay.cc
index 49a942d..8774f18 100644
--- a/FixedOrderGen/t/h_2j_decay.cc
+++ b/FixedOrderGen/t/h_2j_decay.cc
@@ -1,93 +1,94 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Event.hh"
#include "HEJ/MatrixElement.hh"
#include "HEJ/Particle.hh"
#include "HEJ/PDF.hh"
#include "HEJ/Ranlux64.hh"
#include "HEJ/utility.hh"
using namespace HEJFOG;
bool pass_dR_cut(
std::vector<fastjet::PseudoJet> const & jets,
std::vector<HEJ::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.00429198; // +- 1.0488e-05
//calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20
auto config = load_config("config_h_2j_decay.yml");
HEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
assert(ev->decays().size() == 1);
const auto decay = begin(ev->decays());
assert(ev->outgoing().size() > decay->first);
const auto & the_Higgs = ev->outgoing()[decay->first];
assert(the_Higgs.type == HEJ::pid::Higgs);
assert(decay->second.size() == 2);
auto const & gamma = decay->second;
assert(gamma[0].type == HEJ::pid::photon);
assert(gamma[1].type == HEJ::pid::photon);
assert(HEJ::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 << std::endl;
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.012*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/h_3j.cc b/FixedOrderGen/t/h_3j.cc
index fc01803..c4a9e8a 100644
--- a/FixedOrderGen/t/h_3j.cc
+++ b/FixedOrderGen/t/h_3j.cc
@@ -1,75 +1,76 @@
/**
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cmath>
#include <cassert>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Ranlux64.hh"
#include "HEJ/Event.hh"
#include "HEJ/MatrixElement.hh"
#include "HEJ/PDF.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 1.07807; // +- 0.0071
//calculated with HEJ revision 93efdc851b02a907a6fcc63956387f9f4c1111c2 +1
auto config = load_config("config_h_2j.yml");
config.process.njets = 3;
HEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
ev->central().weight *= invGeV2_to_pb;
ev->central().weight /= config.events;
const auto the_Higgs = std::find_if(
begin(ev->outgoing()), end(ev->outgoing()),
[](HEJ::Particle const & p){ return p.type == HEJ::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 << std::endl;
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.02*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/h_3j_uno1.cc b/FixedOrderGen/t/h_3j_uno1.cc
index 1bb407c..0befb62 100644
--- a/FixedOrderGen/t/h_3j_uno1.cc
+++ b/FixedOrderGen/t/h_3j_uno1.cc
@@ -1,79 +1,80 @@
/**
* check that adding uno emissions doesn't change the FKL cross section
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Ranlux64.hh"
#include "Subleading.hh"
#include "HEJ/Event.hh"
#include "HEJ/MatrixElement.hh"
#include "HEJ/PDF.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 0.0243548; // +- 0.000119862
//calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20
auto config = load_config("config_h_2j.yml");
config.process.njets = 3;
config.process.incoming = {HEJ::pid::u, HEJ::pid::u};
config.subleading_channels = HEJFOG::Subleading::uno;
HEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
ran
};
double xs = 0., xs_err = 0.;
int uno_found = 0;
for (int trials = 0; trials < config.events; ++trials){
auto ev = generator.gen_event();
if(generator.status() != good) continue;
assert(ev);
if(ev->type() != HEJ::event_type::FKL){
++uno_found;
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';
std::cout << uno_found << " events with unordered emission" << std::endl;
assert(uno_found > 0);
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.05*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/h_3j_uno2.cc b/FixedOrderGen/t/h_3j_uno2.cc
index eb67ba9..3cb4ae7 100644
--- a/FixedOrderGen/t/h_3j_uno2.cc
+++ b/FixedOrderGen/t/h_3j_uno2.cc
@@ -1,74 +1,75 @@
/**
* check uno cross section
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Ranlux64.hh"
#include "Subleading.hh"
#include "HEJ/Event.hh"
#include "HEJ/MatrixElement.hh"
#include "HEJ/PDF.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 0.00347538; // +- 3.85875e-05
//calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20
auto config = load_config("config_h_2j.yml");
config.process.njets = 3;
config.process.incoming = {HEJ::pid::u, HEJ::pid::u};
config.subleading_fraction = 1.;
config.subleading_channels = HEJFOG::Subleading::uno;
HEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
if(ev->type() == HEJ::event_type::FKL) 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 << std::endl;
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.05*xs);
return EXIT_SUCCESS;
}
diff --git a/FixedOrderGen/t/h_5j.cc b/FixedOrderGen/t/h_5j.cc
index 8a94527..d6d3ffa 100644
--- a/FixedOrderGen/t/h_5j.cc
+++ b/FixedOrderGen/t/h_5j.cc
@@ -1,71 +1,72 @@
/**
* This is a regression test
* the reference cross section has not been checked against any other program
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include "config.hh"
#include "EventGenerator.hh"
#include "HEJ/Ranlux64.hh"
#include "HEJ/Event.hh"
#include "HEJ/MatrixElement.hh"
#include "HEJ/PDF.hh"
using namespace HEJFOG;
int main(){
constexpr double invGeV2_to_pb = 389379292.;
constexpr double xs_ref = 0.252273; // +- 0.00657742
//calculated with HEJ revision 9570e3809613272ac4b8bf3236279ba23cf64d20
auto config = load_config("config_h_2j.yml");
config.process.njets = 5;
HEJ::Ranlux64 ran{};
HEJFOG::EventGenerator generator{
config.process,
config.beam,
HEJ::ScaleGenerator{
config.scales.base,
config.scales.factors,
config.scales.max_ratio
},
config.jets,
config.pdf_id,
config.subleading_fraction,
config.subleading_channels,
- config.particles_properties,
+ config.particles_decays,
config.Higgs_coupling,
+ config.ew_parameters,
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);
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 << std::endl;
assert(std::abs(xs - xs_ref) < 3*xs_err);
assert(xs_err < 0.06*xs);
return EXIT_SUCCESS;
}
diff --git a/include/HEJ/EWConstants.hh b/include/HEJ/EWConstants.hh
index dedac59..b470f21 100644
--- a/include/HEJ/EWConstants.hh
+++ b/include/HEJ/EWConstants.hh
@@ -1,65 +1,86 @@
/** \file
* \brief Defines the electro weak parameters
*
* \authors The HEJ collaboration (see AUTHORS for details)
* \date 2019
* \copyright GPLv2 or later
*/
#pragma once
#include <cmath>
#include "HEJ/exceptions.hh"
+#include "HEJ/PDG_codes.hh"
namespace HEJ {
struct ParticleProperties{
double mass;
double width;
};
class EWConstants {
public:
EWConstants() = default;
+ EWConstants(
+ double vev,
+ ParticleProperties const & Wprop,
+ ParticleProperties const & Zprop,
+ ParticleProperties const & Hprop):
+ set{true},vev_{vev}, Wprop_{Wprop}, Zprop_{Zprop}, Hprop_{Hprop} {}
//! initialise constants by Vacuum expectation value & boson properties
void set_vevWZH(
double vev,
ParticleProperties const & Wprop,
ParticleProperties const & Zprop,
ParticleProperties const & Hprop
){
- vev_= vev; Wprop_= Wprop; Zprop_= Zprop; Hprop_= Hprop;
- set = true;
+ set = true; vev_= vev; Wprop_= Wprop; Zprop_= Zprop; Hprop_= Hprop;
}
//! vacuum expectation value
double vev() const {check_set(); return vev_;}
//! Properties of the W boson
ParticleProperties const & Wprop() const {check_set(); return Wprop_;}
//! Properties of the Z boson
ParticleProperties const & Zprop() const {check_set(); return Zprop_;}
//! Properties of the Higgs boson
ParticleProperties const & Hprop() const {check_set(); return Hprop_;}
+ //! access Properties by boson id
+ ParticleProperties const & prop(ParticleID const id) const {
+ using namespace pid;
+ switch(id){
+ case Wp:
+ case Wm:
+ return Wprop();
+ case Z:
+ return Zprop();
+ case h:
+ return Hprop();
+ default:
+ throw std::invalid_argument("No particle properties available for particle "+name(id));
+ }
+ }
//! cosine of Weinberg angle
double cos_tw() const {return Wprop().mass/Zprop().mass;}
//! cosine square of Weinberg angle
double cos2_tw() const {return cos_tw()*cos_tw();}
//! sinus Weinberg angle
double sin_tw() const {return sqrt(sin2_tw());}
//! sinus square of Weinberg angle
double sin2_tw() const {return 1. - cos2_tw();}
//! elector magnetic coupling
double alpha_em() const {return e2()/4./M_PI;}
//! weak coupling
double alpha_w() const {return gw2()/2.;}
private:
double gw2() const {return 4*Wprop().mass/vev()*Wprop().mass/vev();}
double e2() const {return gw2()*sin2_tw();}
void check_set() const {
if(!set) throw std::invalid_argument("EW constants not specified");
}
bool set{false};
double vev_;
ParticleProperties Wprop_;
ParticleProperties Zprop_;
ParticleProperties Hprop_;
};
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 23, 2:28 PM (5 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4486605
Default Alt Text
(105 KB)
Attached To
rHEJ HEJ
Event Timeline
Log In to Comment