diff --git a/t/test_ME_generic.cc b/t/test_ME_generic.cc index 8c433cc..546b49c 100644 --- a/t/test_ME_generic.cc +++ b/t/test_ME_generic.cc @@ -1,213 +1,280 @@ /** * \brief Generic tester for the ME for a given set of PSP * * \note reference weights and PSP (as LHE file) have to be given as * _individual_ files * * \authors The HEJ collaboration (see AUTHORS for details) * \date 2019-2020 * \copyright GPLv2 or later */ #include "hej_test.hh" +#include <algorithm> #include <cmath> #include <cstdlib> #include <fstream> #include <iostream> #include <string> #include "HEJ/Config.hh" #include "HEJ/Event.hh" #include "HEJ/EventReader.hh" #include "HEJ/exceptions.hh" #include "HEJ/MatrixElement.hh" +#include "HEJ/stream.hh" #include "HEJ/YAMLreader.hh" namespace { constexpr double alpha_s = 0.118; - constexpr double ep = 1e-9; + constexpr double ep = 1e-5; constexpr double ep_mirror = 1e-3; enum MEComponent {tree, virt}; MEComponent guess_component(std::string const & data_file) { if(data_file.find("virt") != data_file.npos) return MEComponent::virt; return MEComponent::tree; } + //! p_z -> -p_z HEJ::Event::EventData mirror_event(HEJ::Event::EventData ev){ for(auto & part: ev.incoming){ auto & p{ part.p }; p.reset(p.px(),p.py(),-p.pz(),p.E()); } for(auto & part: ev.outgoing){ auto & p{ part.p }; p.reset(p.px(),p.py(),-p.pz(),p.E()); } for(auto & decay: ev.decays){ for(auto & part: decay.second){ auto & p{ part.p }; p.reset(p.px(),p.py(),-p.pz(),p.E()); } } // If this is a Z event, we also have to change quarks and leptons to their antiparticle if(ev.decays.size() == 1){ auto decay = ev.decays.begin(); if(ev.outgoing[decay->first].type == HEJ::ParticleID::Z_photon_mix){ for(auto & part: ev.incoming){ if(is_anyquark(part)) part.type = (HEJ::ParticleID) -part.type; } for(auto & part: ev.outgoing){ if(is_anyquark(part)) part.type = (HEJ::ParticleID) -part.type; } for(auto & decay: ev.decays){ for(auto & part: decay.second){ part.type = (HEJ::ParticleID) -part.type; } } } } return ev; } + + void to_anti(HEJ::Particle & part){ + if(is_anyquark(part) + || is_anylepton(part) + || abs(part.type) == HEJ::ParticleID::Wp) + part.type = static_cast<HEJ::ParticleID>(-part.type); + } + + //! p -> -p + HEJ::Event::EventData reverse_event(HEJ::Event::EventData ev){ + for(auto & part: ev.incoming){ + to_anti(part); + auto & p{ part.p }; + p.reset(-p.px(),-p.py(),-p.pz(),p.E()); + } + for(auto & part: ev.outgoing){ + to_anti(part); + auto & p{ part.p }; + p.reset(-p.px(),-p.py(),-p.pz(),p.E()); + } + for(auto & decay: ev.decays){ + for(auto & part: decay.second){ + to_anti(part); + auto & p{ part.p }; + p.reset(-p.px(),-p.py(),-p.pz(),p.E()); + } + } + return ev; + } } int main(int argn, char** argv){ if(argn != 4 && argn != 5){ std::cerr << "\n# Usage:\n."<< argv[0] <<" config.yml ME_weights input_file.lhe\n\n"; return EXIT_FAILURE; } bool OUTPUT_MODE = false; if(argn == 5 && std::string("OUTPUT")==std::string(argv[4])) OUTPUT_MODE = true; const HEJ::Config config = HEJ::load_config(argv[1]); std::fstream wgt_file; if ( OUTPUT_MODE ) { std::cout << "_______________________USING OUTPUT MODE!_______________________" << std::endl; wgt_file.open(argv[2], std::fstream::out); wgt_file.precision(9); wgt_file << std::scientific; } else { wgt_file.open(argv[2], std::fstream::in); } auto reader{ HEJ::make_reader(argv[3])}; const auto component = guess_component(argv[2]); HEJ::MatrixElement ME{ [](double){ return alpha_s; }, HEJ::to_MatrixElementConfig(config) }; double max_ratio = 0.; std::size_t idx_max_ratio = 0; HEJ::Event ev_max_ratio(HEJ::Event::EventData{}.cluster( config.resummation_jets.def,0 ) ); double av_ratio = 0; std::size_t i = 0; while(reader->read_event()){ ++i; HEJ::Event::EventData data{reader->hepeup()}; shuffle_particles(data); HEJ::Event::EventData data_mirror{mirror_event(data)}; shuffle_particles(data_mirror); + HEJ::Event::EventData data_reverse{reverse_event(data)}; + shuffle_particles(data_reverse); + HEJ::Event event{ data.cluster( config.resummation_jets.def, config.resummation_jets.min_pt ) }; HEJ::Event event_mirror{ data_mirror.cluster( config.resummation_jets.def, config.resummation_jets.min_pt ) }; + HEJ::Event event_reverse{ + data_reverse.cluster( + config.resummation_jets.def, + config.resummation_jets.min_pt + ) + }; double our_ME; if(component == MEComponent::tree){ our_ME = ME.tree(event).central; }else{ double sum = 0.; for(size_t i=0; i<ME.virtual_corrections(event).size(); ++i) { sum += ME.virtual_corrections(event).at(i).central; } our_ME = sum; } if(!std::isfinite(our_ME)){ std::cerr << "Found non-finite ME ("<< our_ME <<")\n" << event << std::endl; return EXIT_FAILURE; } double ME_mirror; if(component == MEComponent::tree){ ME_mirror = ME.tree(event_mirror).central; }else{ double sum = 0.; for(size_t i=0; i<ME.virtual_corrections(event_mirror).size(); ++i) { sum += ME.virtual_corrections(event_mirror).at(i).central; } ME_mirror = sum; } if(!std::isfinite(ME_mirror)){ std::cerr << "Found non-finite ME ("<< ME_mirror <<")\n" << event_mirror << std::endl; return EXIT_FAILURE; } if(std::abs(our_ME/ME_mirror-1.)>ep_mirror){ std::size_t precision(std::cout.precision()); std::cerr.precision(16); std::cerr<< "z-Mirrored ME gives different result " << i << "\n" <<our_ME << " vs " << ME_mirror << " => difference: " << std::abs(our_ME/ME_mirror-1.) << "\n" << event << "\nmirrored:\n" << event_mirror << std::endl; std::cerr.precision(precision); return EXIT_FAILURE; } + double ME_reverse; + if(component == MEComponent::tree){ + ME_reverse = ME.tree(event_reverse).central; + }else{ + double sum = 0.; + for(size_t i=0; i<ME.virtual_corrections(event_reverse).size(); ++i) { + sum += ME.virtual_corrections(event_reverse).at(i).central; + } + ME_reverse = sum; + } + if(!std::isfinite(ME_reverse)){ + std::cerr << "Found non-finite ME ("<< ME_reverse <<")\n" << event_reverse << std::endl; + return EXIT_FAILURE; + } + if(std::abs(our_ME/ME_reverse-1.)>ep_mirror){ + std::size_t precision(std::cout.precision()); + std::cerr.precision(16); + std::cerr<< "p-reversed ME gives different result " << i << "\n" + <<our_ME << " vs " << ME_reverse << " => difference: " + << std::abs(our_ME/ME_reverse-1.) << "\n" << event + << "\nreversed:\n" << event_reverse << std::endl; + std::cerr.precision(precision); + // TODO activate + // return EXIT_FAILURE; + } + if ( OUTPUT_MODE ) { wgt_file << our_ME << std::endl; } else { std::string line; if(!std::getline(wgt_file,line)) break; const double ref_ME = std::stod(line); double diff; if(ref_ME == 0.){ diff = (our_ME != 0.); } else { diff = std::abs(our_ME/ref_ME-1.); } av_ratio+=diff; if( diff > max_ratio ) { max_ratio = diff; idx_max_ratio = i; ev_max_ratio = event; } if( diff > ep ){ std::size_t precision(std::cout.precision()); std::cerr.precision(16); std::cerr<< "Large difference in PSP " << i << "\nis: "<<our_ME << " should: " << ref_ME << " => difference: " << diff << "\n" << event << std::endl; std::cerr.precision(precision); return EXIT_FAILURE; } } } wgt_file.close(); if ( i<100 ) throw std::invalid_argument{"Not enough PSP tested"}; if ( !OUTPUT_MODE ) { std::size_t precision(std::cout.precision()); std::cout.precision(16); std::cout << "Avg ratio after " << i << " PSP: " << av_ratio/i << std::endl; std::cout << "maximal ratio at " << idx_max_ratio << ": " << max_ratio << std::endl; std::cout.precision(precision); } return EXIT_SUCCESS; }