diff --git a/FixedOrderGen/include/EventGenerator.hh b/FixedOrderGen/include/EventGenerator.hh index c696c72..e345a81 100644 --- a/FixedOrderGen/include/EventGenerator.hh +++ b/FixedOrderGen/include/EventGenerator.hh @@ -1,65 +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 "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, - ParticlesDecayMap particles_decays, + ParticlesDecayMap particle_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_; - ParticlesDecayMap particles_decays_; + ParticlesDecayMap particle_decays_; HEJ::EWConstants ew_parameters_; std::reference_wrapper<HEJ::RNG> ran_; }; } diff --git a/FixedOrderGen/include/PhaseSpacePoint.hh b/FixedOrderGen/include/PhaseSpacePoint.hh index 0764045..16bcd9d 100644 --- a/FixedOrderGen/include/PhaseSpacePoint.hh +++ b/FixedOrderGen/include/PhaseSpacePoint.hh @@ -1,230 +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 "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() = 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, - ParticlesDecayMap const & particles_decays, + ParticlesDecayMap const & particle_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 06a2487..d302168 100644 --- a/FixedOrderGen/include/config.hh +++ b/FixedOrderGen/include/config.hh @@ -1,45 +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 "Beam.hh" #include "Decay.hh" #include "JetParameters.hh" #include "Process.hh" #include "UnweightSettings.hh" namespace HEJFOG{ struct Config{ Process process; int events; JetParameters jets; Beam beam; int pdf_id; double subleading_fraction; unsigned int subleading_channels; //! < see HEJFOG::Subleading - ParticlesDecayMap particles_decays; + ParticlesDecayMap particle_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 3d2dfe6..8058577 100644 --- a/FixedOrderGen/src/EventGenerator.cc +++ b/FixedOrderGen/src/EventGenerator.cc @@ -1,90 +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/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, - ParticlesDecayMap particles_decays, + ParticlesDecayMap particle_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), 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_decays_{std::move(particles_decays)}, + particle_decays_{std::move(particle_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_decays_, + particle_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 63c7e2b..3ff9ddb 100644 --- a/FixedOrderGen/src/PhaseSpacePoint.cc +++ b/FixedOrderGen/src/PhaseSpacePoint.cc @@ -1,693 +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, JetParameters const & jet_param, HEJ::PDF & pdf, double E_beam, double const subl_chance, unsigned int const subl_channels, - ParticlesDecayMap const & particles_decays, + ParticlesDecayMap const & particle_decays, HEJ::EWConstants const & ew_parameters, HEJ::RNG & ran ) { // auto proc{ proc_in }; // @TODO remove assert(proc.njets >= 2); 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 = 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); - const auto & boson_decay = particles_decays.find(*proc.boson); + const auto & boson_decay = particle_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_decay != particles_decays.end() + } else if( boson_decay != particle_decays.end() && !boson_decay->second.empty() ){ // decay given explicitly decays_.emplace( boson_idx, 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 aa91355..447f6ab 100644 --- a/FixedOrderGen/src/config.cc +++ b/FixedOrderGen/src/config.cc @@ -1,413 +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", "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", "W", "Z"}){ for(auto && particle_opt: {"mass", "width"}){ supported["particle properties"][particle_type][particle_opt] = ""; } } 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"}; } ParticlesDecayMap get_all_decays(YAML::Node const & node, std::string const & entry ){ 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; } 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"]); config.ew_parameters = get_ew_parameters(yaml); - config.particles_decays = get_all_decays(yaml, "decays"); + config.particle_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 f1fdbe9..d0b83a3 100644 --- a/FixedOrderGen/src/main.cc +++ b/FixedOrderGen/src/main.cc @@ -1,234 +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_decays, + config.particle_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 99419ba..7d0ebd6 100644 --- a/FixedOrderGen/t/2j.cc +++ b/FixedOrderGen/t/2j.cc @@ -1,67 +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_decays, + config.particle_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 8d9aa41..b9fdef1 100644 --- a/FixedOrderGen/t/4j.cc +++ b/FixedOrderGen/t/4j.cc @@ -1,68 +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_decays, + config.particle_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_reconstruct_enu.cc b/FixedOrderGen/t/W_reconstruct_enu.cc index 8af3615..badb36a 100644 --- a/FixedOrderGen/t/W_reconstruct_enu.cc +++ b/FixedOrderGen/t/W_reconstruct_enu.cc @@ -1,72 +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_decays, + config.particle_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/h_2j.cc b/FixedOrderGen/t/h_2j.cc index 18c11d0..e993a8d 100644 --- a/FixedOrderGen/t/h_2j.cc +++ b/FixedOrderGen/t/h_2j.cc @@ -1,75 +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_decays, + config.particle_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 8774f18..0d25f19 100644 --- a/FixedOrderGen/t/h_2j_decay.cc +++ b/FixedOrderGen/t/h_2j_decay.cc @@ -1,94 +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_decays, + config.particle_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 c4a9e8a..8d134ca 100644 --- a/FixedOrderGen/t/h_3j.cc +++ b/FixedOrderGen/t/h_3j.cc @@ -1,76 +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_decays, + config.particle_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 0befb62..94bc80e 100644 --- a/FixedOrderGen/t/h_3j_uno1.cc +++ b/FixedOrderGen/t/h_3j_uno1.cc @@ -1,80 +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_decays, + config.particle_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 3cb4ae7..ab069d9 100644 --- a/FixedOrderGen/t/h_3j_uno2.cc +++ b/FixedOrderGen/t/h_3j_uno2.cc @@ -1,75 +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_decays, + config.particle_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 d6d3ffa..cbcd7a2 100644 --- a/FixedOrderGen/t/h_5j.cc +++ b/FixedOrderGen/t/h_5j.cc @@ -1,72 +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_decays, + config.particle_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; }