diff --git a/include/HEJ/EventReweighter.hh b/include/HEJ/EventReweighter.hh index 6b7c672..20af794 100644 --- a/include/HEJ/EventReweighter.hh +++ b/include/HEJ/EventReweighter.hh @@ -1,191 +1,194 @@ /** \file * \brief Declares the EventReweighter class * * EventReweighter is the main class used within HEJ 2. It reweights the * resummation events. * * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019-2020 * \copyright GPLv2 or later */ #pragma once #include <array> #include <cstddef> #include <memory> #include <utility> #include <vector> #include "HEJ/Config.hh" #include "HEJ/MatrixElement.hh" #include "HEJ/PDF.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/Parameters.hh" #include "HEJ/ScaleFunction.hh" #include "HEJ/StatusCode.hh" #include "HEJ/event_types.hh" namespace LHEF { class HEPRUP; } namespace HEJ { class Event; struct RNG; //! Beam parameters /** * Currently, only symmetric beams are supported, * so there is a single beam energy. */ struct Beam{ double E; /**< Beam energy */ std::array<ParticleID, 2> type; /**< Beam particles */ }; //! Main class for reweighting events in HEJ. class EventReweighter{ using EventType = event_type::EventType; public: EventReweighter( Beam const & beam, /**< Beam Energy */ int pdf_id, /**< PDF ID */ ScaleGenerator scale_gen, /**< Scale settings */ EventReweighterConfig conf, /**< Configuration parameters */ std::shared_ptr<RNG> ran /**< Random number generator */ ); EventReweighter( LHEF::HEPRUP const & heprup, /**< LHEF event header */ ScaleGenerator scale_gen, /**< Scale settings */ EventReweighterConfig conf, /**< Configuration parameters */ std::shared_ptr<RNG> ran /**< Random number generator */ ); //! Get the used pdf PDF const & pdf() const; + + //! Check the lowpt cut passes for lowpt runs + bool pass_low_pt(HEJ::Event); //! Get event treatment EventTreatment treatment(EventType type) const; //! Generate resummation events for a given fixed-order event /** * @param ev Fixed-order event corresponding * to the resummation events * @param num_events Number of trial resummation configurations. * @returns A vector of resummation events. * * The result vector depends on the type of the input event and the * \ref EventTreatment of different types as specified in the constructor: * * - EventTreatment::reweight: The result vector contains between 0 and * num_events resummation events. * - EventTreatment::keep: If the input event passes the resummation * jet cuts the result vector contains one * event. Otherwise it is empty. * - EventTreatment::discard: The result vector is empty */ std::vector<Event> reweight( Event const & ev, std::size_t num_events ); //! Gives all StatusCodes of the last reweight() /** * Each StatusCode corresponds to one tried generation. Only good * StatusCodes generated an event. */ std::vector<StatusCode> const & status() const { return status_; } private: /** \internal * \brief main generation/reweighting function: * generate phase space points and divide out Born factors */ std::vector<Event> gen_res_events( Event const & ev, std::size_t phase_space_points ); std::vector<Event> rescale( Event const & Born_ev, std::vector<Event> events ) const; /** \internal * \brief Do the Jets pass the resummation Cuts? * * @param ev Event in Question * @returns 0 or 1 depending on if ev passes Jet Cuts */ bool jets_pass_resummation_cuts(Event const & ev) const; /** \internal * \brief pdf_factors Function * * @param ev Event in Question * @returns EventFactor due to PDFs * * Calculates the Central value and the variation due * to the PDF choice made. */ Weights pdf_factors(Event const & ev) const; /** \internal * \brief matrix_elements Function * * @param ev Event in question * @returns EventFactor due to MatrixElements * * Calculates the Central value and the variation due * to the Matrix Element. */ Weights matrix_elements(Event const & ev) const; /** \internal * \brief Scale-dependent part of fixed-order matrix element * * @param ev Event in question * @returns EventFactor scale variation due to FO-ME. * * This is only called to compute the scale variation for events where * we don't do resummation (e.g. non-FKL). * Since at tree level the scale dependence is just due to alpha_s, * it is enough to return the alpha_s(mur) factors in the matrix element. * The rest drops out in the ratio of (output event ME)/(input event ME), * so we never have to compute it. */ Weights fixed_order_scale_ME(Event const & ev) const; /** \internal * \brief Computes the tree level matrix element * * @param ev Event in Question * @returns HEJ approximation to Tree level Matrix Element * * This computes the HEJ approximation to the tree level FO * Matrix element which is used within the LO weighting process. */ double tree_matrix_element(Event const & ev) const; //! \internal General parameters EventReweighterConfig param_; //! \internal Beam energy double E_beam_; //! \internal PDF PDF pdf_; //! \internal Object to calculate the square of the matrix element MatrixElement MEt2_; //! \internal Object to calculate event renormalisation and factorisation scales ScaleGenerator scale_gen_; //! \internal random number generator std::shared_ptr<RNG> ran_; //! \internal StatusCode of each attempt std::vector<StatusCode> status_; }; } // namespace HEJ diff --git a/src/EventReweighter.cc b/src/EventReweighter.cc index 9995bce..8200d66 100644 --- a/src/EventReweighter.cc +++ b/src/EventReweighter.cc @@ -1,294 +1,299 @@ /** * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019-2020 * \copyright GPLv2 or later */ #include "HEJ/EventReweighter.hh" #include <algorithm> #include <cassert> #include <cmath> #include <cstddef> #include <functional> #include <string> #include <unordered_map> #include <utility> #include "fastjet/ClusterSequence.hh" #include "fastjet/PseudoJet.hh" #include "LHEF/LHEF.h" #include "HEJ/Event.hh" #include "HEJ/Fraction.hh" #include "HEJ/PDG_codes.hh" #include "HEJ/Particle.hh" #include "HEJ/PhaseSpacePoint.hh" #include "HEJ/exceptions.hh" namespace HEJ { EventReweighter::EventReweighter( LHEF::HEPRUP const & heprup, ScaleGenerator scale_gen, EventReweighterConfig conf, std::shared_ptr<RNG> ran ): EventReweighter{ Beam{ heprup.EBMUP.first, {{ static_cast<ParticleID>(heprup.IDBMUP.first), static_cast<ParticleID>(heprup.IDBMUP.second) }} }, heprup.PDFSUP.first, std::move(scale_gen), std::move(conf), std::move(ran) } { if(heprup.EBMUP.second != E_beam_){ throw std::invalid_argument( "asymmetric beam: " + std::to_string(E_beam_) + " ---> <--- " + std::to_string(heprup.EBMUP.second) ); } if(heprup.PDFSUP.second != pdf_.id()){ throw std::invalid_argument( "conflicting PDF ids: " + std::to_string(pdf_.id()) + " vs. " + std::to_string(heprup.PDFSUP.second) ); } } EventReweighter::EventReweighter( Beam const & beam, int pdf_id, ScaleGenerator scale_gen, EventReweighterConfig conf, std::shared_ptr<RNG> ran ): param_{std::move(conf)}, E_beam_{beam.E}, pdf_{pdf_id, beam.type.front(), beam.type.back()}, MEt2_{ [this](double mu){ return pdf_.Halphas(mu); }, param_.ME_config }, scale_gen_{std::move(scale_gen)}, ran_{std::move(ran)} { // legacy code: override new variable with old if(param_.psp_config.max_ext_soft_pt_fraction){ param_.psp_config.soft_pt_regulator = *param_.psp_config.max_ext_soft_pt_fraction; param_.psp_config.max_ext_soft_pt_fraction = {}; } assert(ran_); } PDF const & EventReweighter::pdf() const{ return pdf_; } + + bool EventReweighter::pass_low_pt( + HEJ::Event input_ev + ){ + // Keep only events where there is a fixed order event with at least 1 + // jet below the resummation jet pt but all resummation jets are above + // the resummation jet pt + if(param_.treat.at(EventType::non_resummable) + != EventTreatment::discard){ + throw std::logic_error{ + "Non-resummable events should be discarded for lowpt runs" + }; + } + bool jet_below_cut = false; + for (size_t jet_it = 0; jet_it < input_ev.jets().size(); ++jet_it){ + jet_below_cut = jet_below_cut || input_ev.jets()[jet_it].pt() + < param_.jet_param().min_pt; + } + + if (!jet_below_cut) { + return false; + } + return true; + } std::vector<Event> EventReweighter::reweight( Event const & input_ev, std::size_t num_events ){ - if(param_.lowpt){ - // Keep only events where there is a fixed order event with at least 1 - // jet below the resummation jet pt but all resummation jets are above - // the resummation jet pt - if(param_.treat.at(EventType::non_resummable) - != EventTreatment::discard){ - throw std::logic_error{ - "Non-resummable events should be discarded for lowpt runs" - }; - } - bool jet_below_cut = false; - - for (size_t jet_it = 0; jet_it < input_ev.jets().size(); ++jet_it){ - jet_below_cut = jet_below_cut || input_ev.jets()[jet_it].pt() - < param_.jet_param().min_pt; - } - - if (!jet_below_cut) { - return {}; - } + if(param_.lowpt && !EventReweighter::pass_low_pt(input_ev)){ + return {}; } - auto res_events{ gen_res_events(input_ev, num_events) }; if(res_events.empty()) return {}; for(auto & event: res_events) event = scale_gen_(std::move(event)); return rescale(input_ev, std::move(res_events)); } EventTreatment EventReweighter::treatment(EventType type) const { return param_.treat.at(type); } std::vector<Event> EventReweighter::gen_res_events( Event const & ev, std::size_t phase_space_points ){ assert(ev.variations().empty()); status_.clear(); switch(treatment(ev.type())){ case EventTreatment::discard: { status_.emplace_back(StatusCode::discard); return {}; } case EventTreatment::keep: if(! jets_pass_resummation_cuts(ev)) { status_.emplace_back(StatusCode::failed_resummation_cuts); return {}; } else { status_.emplace_back(StatusCode::good); return {ev}; } default:; } const double Born_shat = shat(ev); std::vector<Event> resummation_events; status_.reserve(phase_space_points); for(std::size_t psp_number = 0; psp_number < phase_space_points; ++psp_number){ PhaseSpacePoint psp{ev, param_.psp_config, *ran_}; status_.emplace_back(psp.status()); assert(psp.status() != StatusCode::unspecified); if(psp.status() != StatusCode::good) continue; assert(psp.weight() != 0.); if(psp.incoming()[0].E() > E_beam_ || psp.incoming()[1].E() > E_beam_) { status_.back() = StatusCode::too_much_energy; continue; } resummation_events.emplace_back( to_EventData( std::move(psp) ).cluster( param_.jet_param().def, param_.jet_param().min_pt ) ); auto & new_event = resummation_events.back(); assert( new_event.valid_hej_state( param_.psp_config.soft_pt_regulator, param_.psp_config.min_extparton_pt ) ); if( new_event.type() != ev.type() ) { throw std::logic_error{ "Resummation Event does not match Born event: " + name(new_event.type()) + " != " + name(ev.type()) }; } new_event.generate_colours(*ran_); assert(new_event.variations().empty()); new_event.central().mur = ev.central().mur; new_event.central().muf = ev.central().muf; const double resum_shat = shat(new_event); new_event.central().weight *= ev.central().weight*Born_shat*Born_shat/ (phase_space_points*resum_shat*resum_shat); } return resummation_events; } std::vector<Event> EventReweighter::rescale( Event const & Born_ev, std::vector<Event> events ) const{ const double Born_pdf = pdf_factors(Born_ev).central; const double Born_ME = tree_matrix_element(Born_ev); for(auto & cur_event: events){ const auto pdf = pdf_factors(cur_event); assert(pdf.variations.size() == cur_event.variations().size()); const auto ME = matrix_elements(cur_event); assert(ME.variations.size() == cur_event.variations().size()); cur_event.parameters() *= pdf*ME/(Born_pdf*Born_ME); } return events; } bool EventReweighter::jets_pass_resummation_cuts( Event const & ev ) const{ const auto out_as_PseudoJet = to_PseudoJet(filter_partons(ev.outgoing())); fastjet::ClusterSequence cs{out_as_PseudoJet, param_.jet_param().def}; return cs.inclusive_jets(param_.jet_param().min_pt).size() == ev.jets().size(); } Weights EventReweighter::pdf_factors(Event const & ev) const{ auto const & a = ev.incoming().front(); auto const & b = ev.incoming().back(); const double xa = a.p.e()/E_beam_; const double xb = b.p.e()/E_beam_; Weights result; std::unordered_map<double, double> known_pdf; result.central = pdf_.pdfpt(0,xa,ev.central().muf,a.type)* pdf_.pdfpt(1,xb,ev.central().muf,b.type); known_pdf.emplace(ev.central().muf, result.central); result.variations.reserve(ev.variations().size()); for(auto const & ev_param: ev.variations()){ const double muf = ev_param.muf; auto cur_pdf = known_pdf.find(muf); if(cur_pdf == known_pdf.end()){ cur_pdf = known_pdf.emplace( muf, pdf_.pdfpt(0,xa,muf,a.type)*pdf_.pdfpt(1,xb,muf,b.type) ).first; } result.variations.emplace_back(cur_pdf->second); } assert(result.variations.size() == ev.variations().size()); return result; } Weights EventReweighter::matrix_elements(Event const & ev) const{ assert(param_.treat.count(ev.type()) > 0); if(param_.treat.find(ev.type())->second == EventTreatment::keep){ return fixed_order_scale_ME(ev); } return MEt2_(ev); } double EventReweighter::tree_matrix_element(Event const & ev) const{ assert(ev.variations().empty()); assert(param_.treat.count(ev.type()) > 0); if(param_.treat.find(ev.type())->second == EventTreatment::keep){ return fixed_order_scale_ME(ev).central; } return MEt2_.tree(ev).central; } Weights EventReweighter::fixed_order_scale_ME(Event const & ev) const{ int alpha_s_power = 0; for(auto const & part: ev.outgoing()){ if(is_parton(part)) ++alpha_s_power; else if(part.type == pid::Higgs) { alpha_s_power += 2; } // nothing to do for other uncoloured particles } Weights result; result.central = std::pow(pdf_.Halphas(ev.central().mur), alpha_s_power); for(auto const & var: ev.variations()){ result.variations.emplace_back( std::pow(pdf_.Halphas(var.mur), alpha_s_power) ); } return result; } } // namespace HEJ