diff --git a/CMakeLists.txt b/CMakeLists.txt index 8655b94..98c1dbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,75 +1,68 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(CepGen) set(PROJECT_VERSION 1) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/cmake $ENV{ROOTSYS}/cmake) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -#set(CMAKE_CXX_FLAGS "-Wall -Wextra") set(CMAKE_CXX_FLAGS_DEBUG "-pg") # for gprof #set(CMAKE_CXX_FLAGS_DEBUG "-fprofile-arcs -ftest-coverage") # for gcov -set(CMAKE_CXX_FLAGS_RELEASE "-O3") +set(CMAKE_CXX_FLAGS_RELEASE "-O2") #----- include external paths set(CEPGEN_EXTERNAL_CORE_REQS "") -set(CEPGEN_EXTERNAL_STRF_REQS "") include(UseEnvironment) set(CEPGEN_SOURCE_DIR ${PROJECT_SOURCE_DIR}/CepGen) set(CEPGEN_LIBRARIES CepGenCore CepGenEvent CepGenProcesses CepGenAddOns CepGenCards) #----- define all individual modules to be built beforehand set(CEPGEN_MODULES Processes Event Cards) #----- enable fortran for external libraries linking enable_language(Fortran) #----- build all the intermediate objects include_directories(${PROJECT_SOURCE_DIR}) add_subdirectory(${CEPGEN_SOURCE_DIR}) foreach(_module ${CEPGEN_MODULES}) add_subdirectory(${CEPGEN_SOURCE_DIR}/${_module}) endforeach() -if(NOT DEFINED ENV{PYTHONHOME}) - message(STATUS "No default PYTHONHOME path set. You might need to define it for Python steering cards parsing.") - message(STATUS "e.g. `export PYTHONHOME=${PYTHON_DIR}` (bash-like)") - message(STATUS " or, `setenv PYTHONHOME ${PYTHON_DIR}` (csh)") -endif() #----- copy the input cards and other files file(GLOB_RECURSE input_cards RELATIVE ${PROJECT_SOURCE_DIR} Cards/*) foreach(_files ${input_cards}) configure_file(${_files} ${_files} COPYONLY) endforeach() configure_file(${CEPGEN_SOURCE_DIR}/README README COPYONLY) configure_file(${PROJECT_SOURCE_DIR}/External/mstw_sf_scan_nnlo.dat ${PROJECT_BINARY_DIR}/External/mstw_sf_scan_nnlo.dat COPYONLY) #----- installation rules set(MODS "") foreach(_module ${CEPGEN_MODULES}) list(APPEND MODS CepGen/${module}) endforeach() install(DIRECTORY ${MODS} DESTINATION include/CepGen FILES_MATCHING PATTERN "*.h") #----- set the tests/utils directory add_subdirectory(test) #----- documentation find_package(Doxygen) if(DOXYGEN_FOUND) set(DOXYGEN_IN ${CMAKE_SOURCE_DIR}/docs/Doxyfile.in) set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY) message(STATUS "Doxygen build started") add_custom_target(doc_doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating documentation with Doxygen" VERBATIM) endif() diff --git a/Cards/legacy/lpair.card b/Cards/legacy/lpair.card index 5c832a2..df55cef 100644 --- a/Cards/legacy/lpair.card +++ b/Cards/legacy/lpair.card @@ -1,22 +1,24 @@ PROC lpair MODE 1 IEND 3 NCVG 100000 ITVG 10 INPP 6500. PMOD 11 INPE 6500. #EMOD 2 PAIR 13 MCUT 2 PTCT 15. ECUT 0. NGEN 100000 ETMN -2.5 ETMX 2.5 MXMX 1000.0 #THMN 0. #THMX 180. XIMN 0.02 XIMX 0.15 +#OUTP lhef +OUTP text diff --git a/Cards/lpair_cfg.py b/Cards/lpair_cfg.py index 51f0e07..69655df 100644 --- a/Cards/lpair_cfg.py +++ b/Cards/lpair_cfg.py @@ -1,38 +1,41 @@ import Config.Core as cepgen from Config.Integration.vegas_cff import integrator +#from Config.Hadronisation.pythia6_cff import pythia6 as hadroniser #from Config.Hadronisation.pythia8_cff import pythia8 as hadroniser from Config.PDG_cfi import PDG process = cepgen.Module('lpair', processParameters = cepgen.Parameters( mode = cepgen.ProcessMode.InelasticElastic, pair = PDG.muon, ), inKinematics = cepgen.Parameters( pz = (6500., 6500.), - #structureFunctions = cepgen.StructureFunctions.SuriYennie, + structureFunctions = cepgen.StructureFunctions.SuriYennie, #structureFunctions = cepgen.StructureFunctions.FioreBrasse, - structureFunctions = cepgen.StructureFunctions.LUXlike, + #structureFunctions = cepgen.StructureFunctions.LUXlike, ), outKinematics = cepgen.Parameters( pt = (25.,), energy = (0.,), eta = (-2.5, 2.5), mx = (1.07, 1000.), ), #tamingFunctions = cepgen.Parameters( # # example of a complex taming function - # cepgen.Parameters( - # variable = "m_central", - # expression = "(m_central>80.) ? exp(-(m_central-80)/10) : 1.0", - # ), + # cepgen.Parameters(variable = "m_ll", expression = "(m_ll>80.) ? exp(-(m_ll-80)/10) : 1.0"), #), ) +#--- example of an output module parameterisation +#output = cepgen.Module('text', variables = ['nev', 'm(4)', 'tgen']) +#output = cepgen.Module('lhef', output = 'test.lhe') +#output = cepgen.Module('hepmc', output = 'test.hepmc') + #--- let the user specify the run conditions from Config.generator_cff import generator generator = generator.clone( numEvents = 100000, printEvery = 10000, ) diff --git a/Cards/pptoll_cfg.py b/Cards/pptoll_cfg.py index 31258a6..43dd1c8 100644 --- a/Cards/pptoll_cfg.py +++ b/Cards/pptoll_cfg.py @@ -1,38 +1,38 @@ import Config.Core as cepgen import Config.ktProcess_cfi as kt from Config.Integration.vegas_cff import integrator +#from Config.Hadronisation.pythia6_cff import pythia6 as hadroniser #from Config.Hadronisation.pythia8_cff import pythia8 as hadroniser from Config.PDG_cfi import PDG, registerParticle -#--- auxiliary particles definition -registerParticle(1000001, 'sd_l', mass=100., charge=1., fermion=True) +#--- example of an auxiliary particles definition +#registerParticle(1000001, 'sd_l', mass=100., charge=1., fermion=True) # right now, only fermionic coupling handled process = kt.process.clone('pptoll', processParameters = cepgen.Parameters( mode = cepgen.ProcessMode.InelasticElastic, - #pair = PDG.muon, - pair = PDG.sd_l, + pair = PDG.muon, #pair = PDG.up, + #pair = PDG.sd_l, # whatever was defined above as "new" particle ), inKinematics = cepgen.Parameters( pz = (6500., 6500.), structureFunctions = cepgen.StructureFunctions.SuriYennie, #structureFunctions = cepgen.StructureFunctions.FioreBrasse, #pdgIds = (PDG.proton, PDG.electron), ), outKinematics = kt.process.outKinematics.clone( pt = (25.,), energy = (0.,), eta = (-2.5, 2.5), mx = (1.07, 1000.), #--- extra cuts on the p1t(l) and p2t(l) plane #ptdiff = (0., 2.5), #--- distance in rapidity between l^+ and l^- #dely = (4., 5.), ), ) -#print PDG #--- events generation from Config.generator_cff import generator generator.numEvents = 10000 diff --git a/Cards/pptottbar_cfg.py b/Cards/pptottbar_cfg.py index 1e43642..5026db4 100644 --- a/Cards/pptottbar_cfg.py +++ b/Cards/pptottbar_cfg.py @@ -1,36 +1,33 @@ import Config.Core as cepgen import Config.ktProcess_cfi as kt from Config.Integration.vegas_cff import integrator -from Config.Hadronisation.pythia8_cff import pythia8 as hadroniser +#from Config.Hadronisation.pythia6_cff import pythia6 as hadroniser +#from Config.Hadronisation.pythia8_cff import pythia8 as hadroniser from Config.PDG_cfi import PDG -from Config.logger_cfi import logger -logger.enabledModules += ('PPtoFF.prepare',) - process = kt.process.clone('pptoff', processParameters = cepgen.Parameters( mode = cepgen.ProcessMode.ElasticElastic, pair = PDG.top, ), inKinematics = cepgen.Parameters( pz = (6500., 6500.), #structureFunctions = cepgen.StructureFunctions.SuriYennie, structureFunctions = cepgen.StructureFunctions.LUXlike, - #structureFunctions = cepgen.StructureFunctions.FioreBrasse, ), outKinematics = kt.process.outKinematics.clone( pair = 6, #eta = (-2.5, 2.5), qt = (0., 2000.), mx = (1.07, 2000.), #--- extra cuts on the p1t(t) and p2t(t) plane ptdiff = (0., 2000.), #--- distance in rapidity between l^+ and l^- #dely = (4., 5.), ), ) #--- events generation from Config.generator_cff import generator generator.numEvents = 25000 diff --git a/Cards/pptoww_cfg.py b/Cards/pptoww_cfg.py index f0da45a..b66cb2c 100644 --- a/Cards/pptoww_cfg.py +++ b/Cards/pptoww_cfg.py @@ -1,63 +1,70 @@ import Config.Core as cepgen from Config.Integration.vegas_cff import integrator +#-------------------------------------------------------------------- +# Logging/debugging example +#-------------------------------------------------------------------- #from Config.logger_cfi import logger - -from Config.Hadronisation.pythia8_cff import pythia8 -hadroniser = pythia8.clone('pythia8', - preConfiguration = pythia8.preConfiguration+( - #'PartonLevel:MPI = on', - #'PartonLevel:ISR = on', - #'PartonLevel:FSR = on', - 'ProcessLevel:resonanceDecays = off', # disable the W decays - ), - pythiaConfiguration = ( - # process-specific - '13:onMode = off', # disable muon decays - '24:onMode = off', # disable all W decays, but... - #'24:onIfAny = 11 13', # enable e-nue + mu-numu final states - '24:onPosIfAny = 11', # enable W- -> e- + nu_e decay - '24:onNegIfAny = 13', # enable W+ -> mu+ + nu_mu decay - ), - processConfiguration = pythia8.processConfiguration+('pythiaConfiguration',), -) #logger.enabledModules += ('Hadroniser.configure', 'Generator.*',) +#-------------------------------------------------------------------- +# Pythia 6 example (with fully leptonic WW decay) +#-------------------------------------------------------------------- +#from Config.Hadronisation.pythia6_cff import pythia6 as hadroniser +#from Config.Hadronisation.pythia6Defaults_cfi import WDecayToEMu +#hadroniser.wDecays = WDecayToEMu +#hadroniser.processConfiguration += ('wDecays',) +#hadroniser.remnantsFragmentation = False +#-------------------------------------------------------------------- +# Pythia 8 example (with fully leptonic WW decay) +#-------------------------------------------------------------------- +#from Config.Hadronisation.pythia8_cff import pythia8 +#hadroniser = pythia8.clone('pythia8', +# pythiaConfiguration = ( +# # process-specific +# '13:onMode = off', # disable muon decays +# '24:onMode = off', # disable all W decays, but... +# #'24:onIfAny = 11 13', # enable e-nue + mu-numu final states +# '24:onPosIfAny = 11', # enable W- -> e- + nu_e decay +# '24:onNegIfAny = 13', # enable W+ -> mu+ + nu_mu decay +# ), +# processConfiguration = pythia8.processConfiguration+('pythiaConfiguration',), +#) import Config.ktProcess_cfi as kt process = kt.process.clone('pptoww', processParameters = cepgen.Parameters( - mode = cepgen.ProcessMode.InelasticElastic, + mode = cepgen.ProcessMode.InelasticInelastic, polarisationStates = 0, # full ), inKinematics = cepgen.Parameters( cmEnergy = 13.e3, #structureFunctions = cepgen.StructureFunctions.SzczurekUleshchenko, #structureFunctions = cepgen.StructureFunctions.ALLM97, structureFunctions = cepgen.StructureFunctions.LUXlike, ), outKinematics = kt.process.outKinematics.clone( mx = (1.07, 1000.), qt = (0., 1000.), #--- extra cuts on the pt(W+) and pt(W-) plane ptdiff = (0., 2000.), #--- extra cuts on the W+W- system invmass = (0.,), ptsum = (0.,), #--- cuts on single particles' level cuts = { # cuts on the single W level - 24: cepgen.Parameters(pt = (0.,)), # no pt cut on Ws + #24: cepgen.Parameters(pt = (0.,)), # no pt cut on Ws # cuts on the W decay products # (mimicking LHC-like experimental cuts) - 11: cepgen.Parameters(pt = (20.,), eta = (-2.5, 2.5)), - 13: cepgen.Parameters(pt = (20.,), eta = (-2.5, 2.5)) + #11: cepgen.Parameters(pt = (20.,), eta = (-2.5, 2.5)), + #13: cepgen.Parameters(pt = (20.,), eta = (-2.5, 2.5)) }, #xi = (0.02, 0.15), ) ) #--- generation parameters from Config.generator_cff import generator generator = generator.clone( numEvents = 10000, printEvery = 1000, ) diff --git a/CepGen/CMakeLists.txt b/CepGen/CMakeLists.txt index de81dfc..68a1cee 100644 --- a/CepGen/CMakeLists.txt +++ b/CepGen/CMakeLists.txt @@ -1,115 +1,127 @@ file(GLOB core_sources Core/*.cpp *.cpp) file(GLOB phys_sources Physics/*.cpp) file(GLOB sf_sources StructureFunctions/*.cpp) -file(GLOB io_sources IO/GenericExportHandler.cpp) +file(GLOB io_sources IO/GenericExportHandler.cpp IO/TextHandler.cpp) file(GLOB hadr_sources Hadronisers/GenericHadroniser.cpp) include_directories(${PROJECT_SOURCE_DIR}) #----- check the external dependencies for SFs set(GRV_PATH ${PROJECT_SOURCE_DIR}/External) file(GLOB grv_sources ${GRV_PATH}/grv_*.f) if(grv_sources) message(STATUS "GRV PDFset found in ${grv_sources}!") add_definitions(-DGRVPDF) list(APPEND sf_sources ${grv_sources}) else() message(STATUS "GRV PDFset not found. Will proceed without it") endif() #----- check the external dependencies for physics utilities if(alphas_sources) list(APPEND phys_sources ${alphas_sources}) endif() set(addons_libraries "") +set(strf_libraries ${GSL_LIB} ${GSL_CBLAS_LIB}) + +#--- linking with LHAPDF + +if(LHAPDF) + message(STATUS "LHAPDF found in ${LHAPDF}") + list(APPEND strf_libraries ${LHAPDF}) + include_directories(${LHAPDF_INCLUDE}) +else() + file(GLOB partonic_sf StructureFunctions/Partonic.cpp) + list(REMOVE_ITEM sf_sources ${partonic_sf}) +endif() #--- linking with Pythia 6 if(PYTHIA6) message(STATUS "Pythia 6 found in ${PYTHIA6}") list(APPEND hadr_sources "Hadronisers/Pythia6Hadroniser.cpp") list(APPEND addons_libraries ${PYTHIA6}) if(PYTHIA6DUMMY) message(STATUS "Pythia 6 addons found in ${PYTHIA6DUMMY}") list(APPEND addons_libraries ${PYTHIA6DUMMY}) endif() elseif(EXISTS $ENV{PYTHIA6_SRC}) file(GLOB pythia6_src $ENV{PYTHIA6_SRC}) message(STATUS "Pythia 6 source found in ${pythia6_src}") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wno-tabs -Wno-maybe-uninitialized -Wno-integer-division -Wno-unused-variable -Wno-unused-dummy-argument") add_library(pythia6 SHARED ${pythia6_src}) list(APPEND hadr_sources "Hadronisers/Pythia6Hadroniser.cpp") list(APPEND addons_libraries pythia6) endif() #--- linking with Pythia 8 if(PYTHIA8) message(STATUS "Pythia 8 found in ${PYTHIA8}") message(STATUS "Pythia 8 will be used for LHEF output") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-misleading-indentation") include_directories(${PYTHIA8_INCLUDE}) add_definitions(-DPYTHIA8) list(APPEND hadr_sources "Hadronisers/Pythia8Hadroniser.cpp") - list(APPEND hadr_sources "Hadronisers/PythiaEventInterface.cpp") + list(APPEND io_sources "IO/PythiaEventInterface.cpp") list(APPEND io_sources "IO/LHEFPythiaHandler.cpp") list(APPEND addons_libraries ${PYTHIA8} dl) endif() #--- linking with HepMC if(HEPMC_LIB) message(STATUS "HepMC found in ${HEPMC_LIB}") if(HEPMC_LIB MATCHES ".*HepMC3.?.so") message(STATUS "HepMC version 3 found") if(HEPMC_ROOT_LIB) message(STATUS "HepMC ROOT I/O library found") add_definitions(-DHEPMC3_ROOTIO) list(APPEND addons_libraries ${HEPMC_ROOT_LIB}) endif() add_definitions(-DHEPMC3) endif() list(APPEND io_sources "IO/HepMCHandler.cpp") if(NOT PYTHIA8) message(STATUS "HepMC will be used for LHEF output") list(APPEND io_sources "IO/LHEFHepMCHandler.cpp") endif() list(APPEND addons_libraries ${HEPMC_LIB}) include_directories(${HEPMC_INCLUDE}) endif() #--- linking with Delphes if(DELPHES) message(STATUS "Delphes found in ${DELPHES}") find_package(ROOT QUIET) if(ROOT_FOUND) message(STATUS "ROOT found in ${ROOT_INCLUDE_DIRS}") list(APPEND addons_libraries ${DELPHES} ${ROOT_LIBRARIES} ${TBB}) list(APPEND io_sources "IO/DelphesHandler.cpp") include_directories(${DELPHES_INCLUDE}) message(STATUS ${DELPHES_INCLUDE}) include_directories(${ROOT_INCLUDE_DIRS}) else() message(STATUS "ROOT not found! Disabling Delphes module.") endif() endif() #----- build the objects add_library(CepGenCore SHARED ${core_sources} ${phys_sources} ${sf_sources}) target_link_libraries(CepGenCore ${CEPGEN_EXTERNAL_CORE_REQS}) -target_link_libraries(CepGenCore ${CEPGEN_EXTERNAL_STRF_REQS}) +target_link_libraries(CepGenCore ${strf_libraries}) add_library(CepGenAddOns SHARED ${io_sources} ${hadr_sources}) target_link_libraries(CepGenAddOns ${addons_libraries}) target_link_libraries(CepGenAddOns CepGenEvent) #----- installation rules install(TARGETS CepGenCore DESTINATION lib) install(TARGETS CepGenAddOns DESTINATION lib) diff --git a/CepGen/Cards/LpairHandler.cpp b/CepGen/Cards/LpairHandler.cpp index a325016..d9378ab 100644 --- a/CepGen/Cards/LpairHandler.cpp +++ b/CepGen/Cards/LpairHandler.cpp @@ -1,238 +1,249 @@ #include "CepGen/Cards/LpairHandler.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Integrator.h" #include "CepGen/Processes/ProcessesHandler.h" #include "CepGen/Hadronisers/HadronisersHandler.h" +#include "CepGen/IO/ExportHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/GluonGrid.h" #include "CepGen/Physics/PDG.h" #include #include namespace cepgen { namespace card { const int LpairHandler::kInvalid = 99999; //----- specialization for LPAIR input cards LpairHandler::LpairHandler( const char* file ) : proc_params_( new ParametersList ), str_fun_( 11 ), sr_type_( 1 ), xi_min_( 0. ), xi_max_( 1. ), hi_1_( { 0, 0 } ), hi_2_( { 0, 0 } ) { std::ifstream f( file, std::fstream::in ); if ( !f.is_open() ) throw CG_FATAL( "LpairHandler" ) << "Failed to parse file \"" << file << "%s\"."; init(); //--- parse all fields std::unordered_map m_params; std::string key, value; std::ostringstream os; while ( f >> key >> value ) { if ( key[0] == '#' ) // FIXME need to ensure there is no extra space before! continue; setParameter( key, value ); m_params.insert( { key, value } ); if ( getDescription( key ) != "null" ) os << "\n>> " << key << " = " << std::setw( 15 ) << getParameter( key ) << " (" << getDescription( key ) << ")"; } f.close(); //--- parse the process name params_.setProcess( proc::ProcessesHandler::get().build( proc_name_, *proc_params_ ) ); const Limits lim_xi{ xi_min_, xi_max_ }; if ( lim_xi.valid() ) params_.kinematics.cuts.remnants.energy_single = ( lim_xi+(-1.) )*( -params_.kinematics.incoming_beams.first.pz ); //--- parse the structure functions code auto sf_params = ParametersList() .set( "id", str_fun_ ) .set( "sigmaRatio", ParametersList() .set( "id", sr_type_ ) ); const unsigned long kLHAPDFCodeDec = 10000000, kLHAPDFPartDec = 1000000; if ( str_fun_ / kLHAPDFCodeDec == 1 ) { // SF from parton const unsigned long icode = str_fun_ % kLHAPDFCodeDec; sf_params .set( "id", (int)strfun::Type::Partonic ) .set( "pdfId", icode % kLHAPDFPartDec ) .set( "mode", icode / kLHAPDFPartDec ); // 0, 1, 2 } else if ( str_fun_ == (int)strfun::Type::MSTWgrid ) sf_params .set( "gridPath", mstw_grid_path_ ); - params_.kinematics.structure_functions = strfun::Parameterisation::build( sf_params ); + params_.kinematics.structure_functions = strfun::StructureFunctionsHandler::get().build( sf_params ); //--- parse the integration algorithm name if ( integr_type_ == "plain" ) params_.integration().type = IntegratorType::plain; else if ( integr_type_ == "Vegas" ) params_.integration().type = IntegratorType::Vegas; else if ( integr_type_ == "MISER" ) params_.integration().type = IntegratorType::MISER; else if ( integr_type_ != "" ) throw CG_FATAL( "LpairHandler" ) << "Unrecognized integrator type: " << integr_type_ << "!"; //--- parse the hadronisation algorithm name if ( !hadr_name_.empty() ) { params_.setHadroniser( cepgen::hadr::HadronisersHandler::get().build( hadr_name_, ParametersList() ) ); params_.hadroniser()->setParameters( params_ ); } + //--- parse the output module name + if ( !out_mod_name_.empty() ) { + ParametersList outm; + if ( !out_file_name_.empty() ) + outm.set( "filename", out_file_name_ ); + params_.setOutputModule( cepgen::io::ExportHandler::get().build( out_mod_name_, outm ) ); + } + if ( m_params.count( "IEND" ) ) setValue( "IEND", ( std::stoi( m_params["IEND"] ) > 1 ) ); if ( m_params.count( "KMRG" ) && !kmr_grid_path_.empty() ) kmr::GluonGrid::get( kmr_grid_path_.c_str() ); //--- check if we are dealing with heavy ions for incoming states HeavyIon hi1{ hi_1_.first, (Element)hi_1_.second }, hi2{ hi_2_.first, (Element)hi_2_.second }; if ( hi1 ) params_.kinematics.incoming_beams.first.pdg = hi1; if ( hi2 ) params_.kinematics.incoming_beams.second.pdg = hi2; CG_INFO( "LpairHandler" ) << "File '" << file << "' succesfully opened!\n\t" << "The following parameters are set:" << os.str(); } void LpairHandler::init() { //------------------------------------------------------------------------------------------- // Process/integration/hadronisation parameters //------------------------------------------------------------------------------------------- registerParameter( "PROC", "Process name to simulate", &proc_name_ ); registerParameter( "ITYP", "Integration algorithm", &integr_type_ ); registerParameter( "HADR", "Hadronisation algorithm", &hadr_name_ ); + registerParameter( "OUTP", "Output module", &out_mod_name_ ); + registerParameter( "OUTF", "Output file name", &out_file_name_ ); registerParameter( "KMRG", "KMR grid interpolation path", &kmr_grid_path_ ); //------------------------------------------------------------------------------------------- // General parameters //------------------------------------------------------------------------------------------- registerParameter( "IEND", "Generation type", ¶ms_.generation().enabled ); registerParameter( "NTRT", "Smoothen the integrand", ¶ms_.generation().treat ); registerParameter( "DEBG", "Debugging verbosity", (int*)&utils::Logger::get().level ); registerParameter( "NCVG", "Number of function calls", (int*)¶ms_.integration().ncvg ); registerParameter( "ITVG", "Number of integration iterations", (int*)¶ms_.integration().vegas.iterations ); registerParameter( "SEED", "Random generator seed", (int*)¶ms_.integration().rng_seed ); registerParameter( "NTHR", "Number of threads to use for events generation", (int*)¶ms_.generation().num_threads ); registerParameter( "MODE", "Subprocess' mode", (int*)¶ms_.kinematics.mode ); registerParameter( "NCSG", "Number of points to probe", (int*)¶ms_.generation().num_points ); registerParameter( "NGEN", "Number of events to generate", (int*)¶ms_.generation().maxgen ); registerParameter( "NPRN", "Number of events before printout", (int*)¶ms_.generation().gen_print_every ); //------------------------------------------------------------------------------------------- // Process-specific parameters //------------------------------------------------------------------------------------------- registerParameter( "METH", "Computation method (kT-factorisation)", &proc_params_->operator[]( "method" ) ); registerParameter( "IPOL", "Polarisation states to consider", &proc_params_->operator[]( "polarisationStates" ) ); //------------------------------------------------------------------------------------------- // Process kinematics parameters //------------------------------------------------------------------------------------------- registerParameter( "MGRD", "MSTW grid interpolation path", &mstw_grid_path_ ); registerParameter( "PMOD", "Outgoing primary particles' mode", &str_fun_ ); registerParameter( "EMOD", "Outgoing primary particles' mode", &str_fun_ ); registerParameter( "RTYP", "R-ratio computation type", &sr_type_ ); registerParameter( "PAIR", "Outgoing particles' PDG id", (int*)&proc_params_->operator[]( "pair" ) ); registerParameter( "INA1", "Heavy ion atomic weight (1st incoming beam)", (int*)&hi_1_.first ); registerParameter( "INZ1", "Heavy ion atomic number (1st incoming beam)", (int*)&hi_1_.second ); registerParameter( "INA2", "Heavy ion atomic weight (1st incoming beam)", (int*)&hi_2_.first ); registerParameter( "INZ2", "Heavy ion atomic number (1st incoming beam)", (int*)&hi_2_.second ); registerParameter( "INP1", "Momentum (1st primary particle)", ¶ms_.kinematics.incoming_beams.first.pz ); registerParameter( "INP2", "Momentum (2nd primary particle)", ¶ms_.kinematics.incoming_beams.second.pz ); registerParameter( "INPP", "Momentum (1st primary particle)", ¶ms_.kinematics.incoming_beams.first.pz ); registerParameter( "INPE", "Momentum (2nd primary particle)", ¶ms_.kinematics.incoming_beams.second.pz ); registerParameter( "PTCT", "Minimal transverse momentum (single central outgoing particle)", ¶ms_.kinematics.cuts.central.pt_single.min() ); registerParameter( "MSCT", "Minimal central system mass", ¶ms_.kinematics.cuts.central.mass_sum.min() ); registerParameter( "ECUT", "Minimal energy (single central outgoing particle)", ¶ms_.kinematics.cuts.central.energy_single.min() ); registerParameter( "ETMN", "Minimal pseudo-rapidity (central outgoing particles)", ¶ms_.kinematics.cuts.central.eta_single.min() ); registerParameter( "ETMX", "Maximal pseudo-rapidity (central outgoing particles)", ¶ms_.kinematics.cuts.central.eta_single.max() ); registerParameter( "YMIN", "Minimal rapidity (central outgoing particles)", ¶ms_.kinematics.cuts.central.rapidity_single.min() ); registerParameter( "YMAX", "Maximal rapidity (central outgoing particles)", ¶ms_.kinematics.cuts.central.rapidity_single.max() ); registerParameter( "Q2MN", "Minimal Q² = -q² (exchanged parton)", ¶ms_.kinematics.cuts.initial.q2.min() ); registerParameter( "Q2MX", "Maximal Q² = -q² (exchanged parton)", ¶ms_.kinematics.cuts.initial.q2.max() ); registerParameter( "MXMN", "Minimal invariant mass of proton remnants", ¶ms_.kinematics.cuts.remnants.mass_single.min() ); registerParameter( "MXMX", "Maximal invariant mass of proton remnants", ¶ms_.kinematics.cuts.remnants.mass_single.max() ); registerParameter( "XIMN", "Minimal fractional momentum loss of outgoing proton (ξ)", &xi_min_ ); registerParameter( "XIMX", "Maximal fractional momentum loss of outgoing proton (ξ)", &xi_max_ ); } void LpairHandler::store( const char* file ) { std::ofstream f( file, std::fstream::out | std::fstream::trunc ); if ( !f.is_open() ) throw CG_ERROR( "LpairHandler" ) << "Failed to open file \"" << file << "%s\" for writing."; for ( const auto& it : p_strings_ ) if ( it.second.value ) f << it.first << " = " << *it.second.value << "\n"; for ( const auto& it : p_ints_ ) if ( it.second.value ) f << it.first << " = " << *it.second.value << "\n"; for ( const auto& it : p_doubles_ ) if ( it.second.value ) f << it.first << " = " << *it.second.value << "\n"; for ( const auto& it : p_bools_ ) if ( it.second.value ) f << it.first << " = " << *it.second.value << "\n"; f.close(); } void LpairHandler::setParameter( const std::string& key, const std::string& value ) { try { setValue( key.c_str(), std::stod( value ) ); } catch ( const std::invalid_argument& ) {} try { setValue( key.c_str(), std::stoi( value ) ); } catch ( const std::invalid_argument& ) {} try { setValue( key.c_str(), value ); } catch ( const std::invalid_argument& ) { throw CG_FATAL( "LpairHandler:setParameter" ) << "Failed to add the parameter \"" << key << "\" → \"" << value << "\"!"; } } std::string LpairHandler::getParameter( std::string key ) const { double dd = getValue( key.c_str() ); if ( dd != -999. ) return std::to_string( dd ); int ui = getValue( key.c_str() ); if ( ui != 999 ) return std::to_string( ui ); //if ( out = getValue( key.c_str() ) ); return getValue( key.c_str() ); } std::string LpairHandler::getDescription( std::string key ) const { if ( p_strings_.count( key ) ) return p_strings_.find( key )->second.description; if ( p_ints_.count( key ) ) return p_ints_.find( key )->second.description; if ( p_doubles_.count( key ) ) return p_doubles_.find( key )->second.description; if ( p_bools_.count( key ) ) return p_bools_.find( key )->second.description; return "null"; } } } diff --git a/CepGen/Cards/LpairHandler.h b/CepGen/Cards/LpairHandler.h index 0064dd0..fef13af 100644 --- a/CepGen/Cards/LpairHandler.h +++ b/CepGen/Cards/LpairHandler.h @@ -1,118 +1,121 @@ #ifndef CepGen_Cards_LpairReader_h #define CepGen_Cards_LpairReader_h #include "CepGen/Cards/Handler.h" #include using std::string; namespace cepgen { class ParametersList; namespace card { /// LPAIR-like steering cards parser and writer class LpairHandler : public Handler { public: /// Read a LPAIR steering card explicit LpairHandler( const char* file ); /// Store a configuration into a LPAIR steering card void store( const char* file ); private: /// Single parameter handler /// \tparam T Parameter type template struct Parameter { Parameter( const char* key, const char* descr, T* value ) : key( key ), description( descr ), value( value ) {} std::string key, description; T* value; }; /// Register a parameter to be steered to a configuration variable template void registerParameter( const char* key, const char* description, T* def ) {} /// Set a parameter value template void setValue( const char* key, const T& value ) {} /// Retrieve a parameter value template T getValue( const char* key ) const {} void setParameter( const std::string& key, const std::string& value ); std::string getParameter( std::string key ) const; std::string getDescription( std::string key ) const; static const int kInvalid; std::unordered_map > p_strings_; std::unordered_map > p_doubles_; std::unordered_map > p_ints_; std::unordered_map > p_bools_; void init(); std::shared_ptr proc_params_; int str_fun_, sr_type_; double xi_min_, xi_max_; - std::string proc_name_, hadr_name_, integr_type_, kmr_grid_path_, mstw_grid_path_; + std::string proc_name_, hadr_name_, out_mod_name_; + std::string out_file_name_; + std::string integr_type_; + std::string kmr_grid_path_, mstw_grid_path_; std::pair hi_1_, hi_2_; }; //----- specialised registerers /// Register a string parameter template<> inline void LpairHandler::registerParameter( const char* key, const char* description, std::string* def ) { p_strings_.insert( std::make_pair( key, Parameter( key, description, def ) ) ); } /// Register a double floating point parameter template<> inline void LpairHandler::registerParameter( const char* key, const char* description, double* def ) { p_doubles_.insert( std::make_pair( key, Parameter( key, description, def ) ) ); } /// Register an integer parameter template<> inline void LpairHandler::registerParameter( const char* key, const char* description, int* def ) { p_ints_.insert( std::make_pair( key, Parameter( key, description, def ) ) ); } /// Register a boolean parameter template<> inline void LpairHandler::registerParameter( const char* key, const char* description, bool* def ) { p_bools_.insert( std::make_pair( key, Parameter( key, description, def ) ) ); } //----- specialised setters template<> inline void LpairHandler::setValue( const char* key, const std::string& value ) { auto it = p_strings_.find( key ); if ( it != p_strings_.end() ) *it->second.value = value; } template<> inline void LpairHandler::setValue( const char* key, const double& value ) { auto it = p_doubles_.find( key ); if ( it != p_doubles_.end() ) *it->second.value = value; } template<> inline void LpairHandler::setValue( const char* key, const int& value ) { auto it = p_ints_.find( key ); if ( it != p_ints_.end() ) *it->second.value = value; } template<> inline void LpairHandler::setValue( const char* key, const bool& value ) { auto it = p_bools_.find( key ); if ( it != p_bools_.end() ) *it->second.value = value; } //----- specialised getters /// Retrieve a string parameter value template<> inline std::string LpairHandler::getValue( const char* key ) const { const auto& it = p_strings_.find( key ); if ( it != p_strings_.end() ) return *it->second.value; return "null"; } /// Retrieve a floating point parameter value template<> inline double LpairHandler::getValue( const char* key ) const { const auto& it = p_doubles_.find( key ); if ( it != p_doubles_.end() ) return *it->second.value; return -999.; } /// Retrieve an integer parameter value template<> inline int LpairHandler::getValue( const char* key ) const { const auto& it = p_ints_.find( key ); if ( it != p_ints_.end() ) return *it->second.value; return 999; } /// Retrieve a boolean parameter value template<> inline bool LpairHandler::getValue( const char* key ) const { const auto& it = p_bools_.find( key ); if ( it != p_bools_.end() ) return *it->second.value; return true; } } } #endif diff --git a/CepGen/Cards/PythonHandler.cpp b/CepGen/Cards/PythonHandler.cpp index 2d60da2..dab6e8d 100644 --- a/CepGen/Cards/PythonHandler.cpp +++ b/CepGen/Cards/PythonHandler.cpp @@ -1,372 +1,392 @@ #include "CepGen/Cards/PythonHandler.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/TamingFunction.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Integrator.h" #include "CepGen/Processes/ProcessesHandler.h" #include "CepGen/Hadronisers/HadronisersHandler.h" +#include "CepGen/IO/ExportHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/GluonGrid.h" #include "CepGen/Physics/PDG.h" #include #if PY_MAJOR_VERSION < 3 # define PYTHON2 #endif namespace cepgen { namespace card { //----- specialization for CepGen input cards PythonHandler::PythonHandler( const char* file ) { setenv( "PYTHONPATH", ".:Cards:test:../Cards", 1 ); + setenv( "PYTHONDONTWRITEBYTECODE", "1", 1 ); CG_DEBUG( "PythonHandler" ) << "Python PATH: " << getenv( "PYTHONPATH" ) << "."; std::string filename = pythonPath( file ); const size_t fn_len = filename.length()+1; //Py_DebugFlag = 1; //Py_VerboseFlag = 1; #ifdef PYTHON2 char* sfilename = new char[fn_len]; snprintf( sfilename, fn_len, "%s", filename.c_str() ); #else wchar_t* sfilename = new wchar_t[fn_len]; swprintf( sfilename, fn_len, L"%s", filename.c_str() ); #endif if ( sfilename ) Py_SetProgramName( sfilename ); Py_InitializeEx( 1 ); if ( sfilename ) delete [] sfilename; if ( !Py_IsInitialized() ) throw CG_FATAL( "PythonHandler" ) << "Failed to initialise the Python cards parser!"; CG_DEBUG( "PythonHandler" ) << "Initialised the Python cards parser\n\t" << "Python version: " << Py_GetVersion() << "\n\t" << "Platform: " << Py_GetPlatform() << "."; PyObject* cfg = PyImport_ImportModule( filename.c_str() ); // new if ( !cfg ) throwPythonError( Form( "Failed to parse the configuration card %s", file ) ); //--- additional particles definition PyObject* pextp = PyObject_GetAttrString( cfg, PDGLIST_NAME ); // new if ( pextp ) { parseExtraParticles( pextp ); Py_CLEAR( pextp ); } //--- process definition PyObject* process = PyObject_GetAttrString( cfg, PROCESS_NAME ); // new if ( !process ) throwPythonError( Form( "Failed to extract a \"%s\" keyword from the configuration card %s", PROCESS_NAME, file ) ); //--- list of process-specific parameters ParametersList proc_params; fillParameter( process, "processParameters", proc_params ); //--- type of process to consider PyObject* pproc_name = element( process, MODULE_NAME ); // borrowed if ( !pproc_name ) throwPythonError( Form( "Failed to extract the process name from the configuration card %s", file ) ); const std::string proc_name = get( pproc_name ); //--- process mode params_.kinematics.mode = (KinematicsMode)proc_params.get( "mode", (int)KinematicsMode::invalid ); params_.setProcess( cepgen::proc::ProcessesHandler::get().build( proc_name, proc_params ) ); //--- process kinematics PyObject* pin_kinematics = element( process, "inKinematics" ); // borrowed if ( pin_kinematics ) parseIncomingKinematics( pin_kinematics ); PyObject* pout_kinematics = element( process, "outKinematics" ); // borrowed if ( pout_kinematics ) parseOutgoingKinematics( pout_kinematics ); //--- taming functions PyObject* ptam = element( process, "tamingFunctions" ); // borrowed if ( ptam ) for ( const auto& p : getVector( ptam ) ) params_.taming_functions->add( p.get( "variable" ), p.get( "expression" ) ); Py_CLEAR( process ); PyObject* plog = PyObject_GetAttrString( cfg, LOGGER_NAME ); // new if ( plog ) { parseLogging( plog ); Py_CLEAR( plog ); } //--- hadroniser parameters PyObject* phad = PyObject_GetAttrString( cfg, HADR_NAME ); // new if ( phad ) { parseHadroniser( phad ); Py_CLEAR( phad ); } //--- generation parameters PyObject* pint = PyObject_GetAttrString( cfg, INTEGRATOR_NAME ); // new if ( pint ) { parseIntegrator( pint ); Py_CLEAR( pint ); } PyObject* pgen = PyObject_GetAttrString( cfg, GENERATOR_NAME ); // new if ( pgen ) { parseGenerator( pgen ); Py_CLEAR( pgen ); } + PyObject* pout = PyObject_GetAttrString( cfg, OUTPUT_NAME ); // new + if ( pout ) { + parseOutputModule( pout ); + Py_CLEAR( pout ); + } + //--- finalisation Py_CLEAR( cfg ); } PythonHandler::~PythonHandler() { if ( Py_IsInitialized() ) Py_Finalize(); } void PythonHandler::parseIncomingKinematics( PyObject* kin ) { //--- retrieve the beams PDG ids std::vector beams_pdg; fillParameter( kin, "pdgIds", beams_pdg ); if ( !beams_pdg.empty() ) { if ( beams_pdg.size() != 2 ) throwPythonError( Form( "Invalid list of PDG ids retrieved for incoming beams:\n\t2 PDG ids are expected, %d provided!", beams_pdg.size() ) ); params_.kinematics.incoming_beams. first.pdg = (pdgid_t)beams_pdg.at( 0 ).get( "pdgid" ); params_.kinematics.incoming_beams.second.pdg = (pdgid_t)beams_pdg.at( 1 ).get( "pdgid" ); } //--- incoming beams kinematics std::vector beams_pz; fillParameter( kin, "pz", beams_pz ); if ( !beams_pz.empty() ) { if ( beams_pz.size() != 2 ) throwPythonError( Form( "Invalid list of pz's retrieved for incoming beams:\n\t2 pz's are expected, %d provided!", beams_pz.size() ) ); params_.kinematics.incoming_beams. first.pz = beams_pz.at( 0 ); params_.kinematics.incoming_beams.second.pz = beams_pz.at( 1 ); } double sqrt_s = -1.; fillParameter( kin, "cmEnergy", sqrt_s ); if ( sqrt_s != -1. ) params_.kinematics.setSqrtS( sqrt_s ); //--- structure functions set for incoming beams PyObject* psf = element( kin, "structureFunctions" ); // borrowed if ( psf ) - params_.kinematics.structure_functions = strfun::Parameterisation::build( get( psf ) ); + params_.kinematics.structure_functions = strfun::StructureFunctionsHandler::get().build( get( psf ) ); //--- types of parton fluxes for kt-factorisation std::vector kt_fluxes; fillParameter( kin, "ktFluxes", kt_fluxes ); if ( !kt_fluxes.empty() ) { params_.kinematics.incoming_beams.first.kt_flux = (KTFlux)kt_fluxes.at( 0 ); params_.kinematics.incoming_beams.second.kt_flux = ( kt_fluxes.size() > 1 ) ? (KTFlux)kt_fluxes.at( 1 ) : (KTFlux)kt_fluxes.at( 0 ); } //--- specify where to look for the grid path for gluon emission std::string kmr_grid_path; fillParameter( kin, "kmrGridPath", kmr_grid_path ); if ( !kmr_grid_path.empty() ) kmr::GluonGrid::get( kmr_grid_path.c_str() ); //--- parse heavy ions beams std::vector hi_beam1, hi_beam2; fillParameter( kin, "heavyIonA", hi_beam1 ); if ( hi_beam1.size() == 2 ) params_.kinematics.incoming_beams. first.pdg = HeavyIon{ (unsigned short)hi_beam1[0], (Element)hi_beam1[1] }; fillParameter( kin, "heavyIonB", hi_beam2 ); if ( hi_beam2.size() == 2 ) params_.kinematics.incoming_beams.second.pdg = HeavyIon{ (unsigned short)hi_beam2[0], (Element)hi_beam2[1] }; } void PythonHandler::parseOutgoingKinematics( PyObject* kin ) { std::vector parts; fillParameter( kin, "minFinalState", parts ); for ( const auto& pdg : parts ) params_.kinematics.minimum_final_state.emplace_back( (pdgid_t)pdg ); ParametersList part_cuts; fillParameter( kin, "cuts", part_cuts ); for ( const auto& part : part_cuts.keys() ) { const auto pdg = (pdgid_t)stoi( part ); const auto& cuts = part_cuts.get( part ); if ( cuts.has( "pt" ) ) params_.kinematics.cuts.central_particles[pdg].pt_single = cuts.get( "pt" ); if ( cuts.has( "energy" ) ) params_.kinematics.cuts.central_particles[pdg].energy_single = cuts.get( "energy" ); if ( cuts.has( "eta" ) ) params_.kinematics.cuts.central_particles[pdg].eta_single = cuts.get( "eta" ); if ( cuts.has( "rapidity" ) ) params_.kinematics.cuts.central_particles[pdg].rapidity_single = cuts.get( "rapidity" ); } // for LPAIR/collinear matrix elements fillParameter( kin, "q2", params_.kinematics.cuts.initial.q2 ); // for the kT factorised matrix elements fillParameter( kin, "qt", params_.kinematics.cuts.initial.qt ); fillParameter( kin, "phiqt", params_.kinematics.cuts.initial.phi_qt ); fillParameter( kin, "ptdiff", params_.kinematics.cuts.central.pt_diff ); fillParameter( kin, "phiptdiff", params_.kinematics.cuts.central.phi_pt_diff ); fillParameter( kin, "rapiditydiff", params_.kinematics.cuts.central.rapidity_diff ); // generic phase space limits fillParameter( kin, "rapidity", params_.kinematics.cuts.central.rapidity_single ); fillParameter( kin, "eta", params_.kinematics.cuts.central.eta_single ); fillParameter( kin, "pt", params_.kinematics.cuts.central.pt_single ); fillParameter( kin, "ptsum", params_.kinematics.cuts.central.pt_sum ); fillParameter( kin, "invmass", params_.kinematics.cuts.central.mass_sum ); fillParameter( kin, "mx", params_.kinematics.cuts.remnants.mass_single ); fillParameter( kin, "yj", params_.kinematics.cuts.remnants.rapidity_single ); Limits lim_xi; fillParameter( kin, "xi", lim_xi ); if ( lim_xi.valid() ) params_.kinematics.cuts.remnants.energy_single = ( lim_xi+(-1.) )*( -params_.kinematics.incoming_beams.first.pz ); } void PythonHandler::parseLogging( PyObject* log ) { int log_level = 0; fillParameter( log, "level", log_level ); utils::Logger::get().level = (utils::Logger::Level)log_level; std::vector enabled_modules; fillParameter( log, "enabledModules", enabled_modules ); for ( const auto& mod : enabled_modules ) utils::Logger::get().addExceptionRule( mod ); } void PythonHandler::parseIntegrator( PyObject* integr ) { if ( !PyDict_Check( integr ) ) throwPythonError( "Integrator object should be a dictionary!" ); PyObject* palgo = element( integr, MODULE_NAME ); // borrowed if ( !palgo ) throwPythonError( "Failed to retrieve the integration algorithm name!" ); std::string algo = get( palgo ); if ( algo == "plain" ) params_.integration().type = IntegratorType::plain; else if ( algo == "Vegas" ) { params_.integration().type = IntegratorType::Vegas; fillParameter( integr, "alpha", (double&)params_.integration().vegas.alpha ); fillParameter( integr, "iterations", params_.integration().vegas.iterations ); fillParameter( integr, "mode", (int&)params_.integration().vegas.mode ); fillParameter( integr, "verbosity", (int&)params_.integration().vegas.verbose ); std::string vegas_logging_output = "cerr"; fillParameter( integr, "loggingOutput", vegas_logging_output ); if ( vegas_logging_output == "cerr" ) // redirect all debugging information to the error stream params_.integration().vegas.ostream = stderr; else if ( vegas_logging_output == "cout" ) // redirect all debugging information to the standard stream params_.integration().vegas.ostream = stdout; else params_.integration().vegas.ostream = fopen( vegas_logging_output.c_str(), "w" ); } else if ( algo == "MISER" ) { params_.integration().type = IntegratorType::MISER; fillParameter( integr, "estimateFraction", (double&)params_.integration().miser.estimate_frac ); fillParameter( integr, "minCalls", params_.integration().miser.min_calls ); fillParameter( integr, "minCallsPerBisection", params_.integration().miser.min_calls_per_bisection ); fillParameter( integr, "alpha", (double&)params_.integration().miser.alpha ); fillParameter( integr, "dither", (double&)params_.integration().miser.dither ); } else throwPythonError( Form( "Invalid integration() algorithm: %s", algo.c_str() ) ); fillParameter( integr, "numFunctionCalls", params_.integration().ncvg ); fillParameter( integr, "seed", (unsigned long&)params_.integration().rng_seed ); unsigned int rng_engine; fillParameter( integr, "rngEngine", rng_engine ); switch ( rng_engine ) { case 0: default: params_.integration().rng_engine = (gsl_rng_type*)gsl_rng_mt19937; break; case 1: params_.integration().rng_engine = (gsl_rng_type*)gsl_rng_taus2; break; case 2: params_.integration().rng_engine = (gsl_rng_type*)gsl_rng_gfsr4; break; case 3: params_.integration().rng_engine = (gsl_rng_type*)gsl_rng_ranlxs0; break; } fillParameter( integr, "chiSqCut", params_.integration().vegas_chisq_cut ); } void PythonHandler::parseGenerator( PyObject* gen ) { if ( !PyDict_Check( gen ) ) throwPythonError( "Generation information object should be a dictionary!" ); params_.generation().enabled = true; fillParameter( gen, "treat", params_.generation().treat ); fillParameter( gen, "numEvents", params_.generation().maxgen ); fillParameter( gen, "printEvery", params_.generation().gen_print_every ); fillParameter( gen, "numThreads", params_.generation().num_threads ); fillParameter( gen, "numPoints", params_.generation().num_points ); } void PythonHandler::parseHadroniser( PyObject* hadr ) { if ( !PyDict_Check( hadr ) ) throwPythonError( "Hadroniser object should be a dictionary!" ); PyObject* pname = element( hadr, MODULE_NAME ); // borrowed if ( !pname ) throwPythonError( "Hadroniser name is required!" ); std::string hadr_name = get( pname ); params_.setHadroniser( cepgen::hadr::HadronisersHandler::get().build( hadr_name, get( hadr ) ) ); auto h = params_.hadroniser(); h->setParameters( params_ ); { //--- before calling the init() method std::vector config; fillParameter( hadr, "preConfiguration", config ); h->readStrings( config ); } h->init(); { //--- after init() has been called std::vector config; fillParameter( hadr, "processConfiguration", config ); for ( const auto& block : config ) { std::vector config_blk; fillParameter( hadr, block.c_str(), config_blk ); h->readStrings( config_blk ); } } } void + PythonHandler::parseOutputModule( PyObject* pout ) + { + if ( !is( pout ) ) + throwPythonError( "Invalid type for output parameters list!" ); + + PyObject* pname = element( pout, MODULE_NAME ); // borrowed + if ( !pname ) + throwPythonError( "Output module name is required!" ); + params_.setOutputModule( io::ExportHandler::get().build( get( pname ), get( pout ) ) ); + } + + void PythonHandler::parseExtraParticles( PyObject* pparts ) { if ( !is( pparts ) ) throwPythonError( "Extra particles definition object should be a parameters list!" ); const auto& parts = get( pparts ); for ( const auto& k : parts.keys() ) { const auto& part = parts.get( k ); if ( part.pdgid == 0 || part.mass < 0. ) continue; CG_DEBUG( "PythonHandler:particles" ) << "Adding a new particle with name \"" << part.name << "\" to the PDG dictionary."; PDG::get().define( part ); } } } } diff --git a/CepGen/Cards/PythonHandler.h b/CepGen/Cards/PythonHandler.h index 977da14..cdc02cd 100644 --- a/CepGen/Cards/PythonHandler.h +++ b/CepGen/Cards/PythonHandler.h @@ -1,82 +1,84 @@ #ifndef CepGen_Cards_PythonHandler_h #define CepGen_Cards_PythonHandler_h #include #include "Handler.h" namespace cepgen { namespace strfun { class Parameterisation; } class Limits; class ParametersList; namespace card { /// CepGen Python configuration cards reader/writer class PythonHandler : public Handler { public: /// Read a standard configuration card explicit PythonHandler( const char* file ); ~PythonHandler(); private: static constexpr const char* MODULE_NAME = "mod_name"; static constexpr const char* PROCESS_NAME = "process"; static constexpr const char* HADR_NAME = "hadroniser"; static constexpr const char* LOGGER_NAME = "logger"; static constexpr const char* INTEGRATOR_NAME = "integrator"; static constexpr const char* GENERATOR_NAME = "generator"; + static constexpr const char* OUTPUT_NAME = "output"; static constexpr const char* PDGLIST_NAME = "PDG"; static void throwPythonError( const std::string& message ); static std::string pythonPath( const char* file ); static PyObject* element( PyObject* obj, const char* key ); static PyObject* encode( const char* str ); template bool is( PyObject* obj ) const; template T get( PyObject* obj ) const; template bool isVector( PyObject* obj ) const; template std::vector getVector( PyObject* obj ) const; void fillParameter( PyObject* parent, const char* key, bool& out ); void fillParameter( PyObject* parent, const char* key, int& out ); void fillParameter( PyObject* parent, const char* key, unsigned long& out ); void fillParameter( PyObject* parent, const char* key, unsigned int& out ); void fillParameter( PyObject* parent, const char* key, double& out ); void fillParameter( PyObject* parent, const char* key, std::string& out ); void fillParameter( PyObject* parent, const char* key, Limits& out ); void fillParameter( PyObject* parent, const char* key, std::vector& out ); void fillParameter( PyObject* parent, const char* key, std::vector& out ); void fillParameter( PyObject* parent, const char* key, std::vector& out ); void fillParameter( PyObject* parent, const char* key, ParametersList& out ); void fillParameter( PyObject* parent, const char* key, std::vector& out ); void parseIncomingKinematics( PyObject* ); void parseOutgoingKinematics( PyObject* ); void parseLogging( PyObject* ); void parseIntegrator( PyObject* ); void parseGenerator( PyObject* ); void parseHadroniser( PyObject* ); - void parseExtraParticles( PyObject* parts ); + void parseOutputModule( PyObject* ); + void parseExtraParticles( PyObject* ); }; template<> bool PythonHandler::is( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> int PythonHandler::get( PyObject* obj ) const; template<> unsigned long PythonHandler::get( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> ParametersList PythonHandler::get( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> double PythonHandler::get( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> std::string PythonHandler::get( PyObject* obj ) const; template<> bool PythonHandler::is( PyObject* obj ) const; template<> Limits PythonHandler::get( PyObject* obj ) const; } } #endif diff --git a/CepGen/Core/FortranInterface.cpp b/CepGen/Core/FortranInterface.cpp index 9d55ca4..47346ee 100644 --- a/CepGen/Core/FortranInterface.cpp +++ b/CepGen/Core/FortranInterface.cpp @@ -1,76 +1,76 @@ #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/KTFlux.h" #include "CepGen/Physics/HeavyIon.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #ifdef __cplusplus extern "C" { #endif /// Expose structure functions calculators to Fortran void cepgen_structure_functions_( int& sfmode, double& xbj, double& q2, double& f2, double& fl ) { using namespace cepgen; - static auto sf = strfun::Parameterisation::build( ParametersList().set( "id", sfmode ) ); + static auto sf = strfun::StructureFunctionsHandler::get().build( sfmode ); const auto& val = ( *sf )( xbj, q2 ); f2 = val.F2; fl = val.FL; } /// Compute a \f$k_{\rm T}\f$-dependent flux for single nucleons /// \param[in] fmode Flux mode (see cepgen::KTFlux) /// \param[in] x Fractional momentum loss /// \param[in] kt2 The \f$k_{\rm T}\f$ transverse momentum norm /// \param[in] sfmode Structure functions set for dissociative emission /// \param[in] mx Diffractive state mass for dissociative emission double cepgen_kt_flux_( int& fmode, double& x, double& kt2, int& sfmode, double& mx ) { using namespace cepgen; - static auto sf = strfun::Parameterisation::build( ParametersList().set( "id", sfmode ) ); + static auto sf = strfun::StructureFunctionsHandler::get().build( sfmode ); return ktFlux( (KTFlux)fmode, x, kt2, *sf, mx ); } /// Compute a \f$k_{\rm T}\f$-dependent flux for heavy ions /// \param[in] fmode Flux mode (see cepgen::KTFlux) /// \param[in] x Fractional momentum loss /// \param[in] kt2 The \f$k_{\rm T}\f$ transverse momentum norm /// \param[in] a Mass number for the heavy ion /// \param[in] z Atomic number for the heavy ion double cepgen_kt_flux_hi_( int& fmode, double& x, double& kt2, int& a, int& z ) { using namespace cepgen; return ktFlux( (KTFlux)fmode, x, kt2, HeavyIon{ (unsigned short)a, (Element)z } ); } /// Mass of a particle, in GeV/c^2 double cepgen_particle_mass_( int& pdg_id ) { try { return cepgen::PDG::get().mass( (cepgen::pdgid_t)pdg_id ); } catch ( const cepgen::Exception& e ) { e.dump(); exit( 0 ); } } /// Charge of a particle, in e double cepgen_particle_charge_( int& pdg_id ) { try { return cepgen::PDG::get().charge( (cepgen::pdgid_t)pdg_id ); } catch ( const cepgen::Exception& e ) { e.dump(); exit( 0 ); } } #ifdef __cplusplus } #endif diff --git a/CepGen/Core/Integrand.cpp b/CepGen/Core/Integrand.cpp index d6e8f12..0fae045 100644 --- a/CepGen/Core/Integrand.cpp +++ b/CepGen/Core/Integrand.cpp @@ -1,201 +1,202 @@ #include "CepGen/Core/Timer.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/TamingFunction.h" #include "CepGen/Event/Event.h" #include "CepGen/Event/Particle.h" #include "CepGen/Physics/Kinematics.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Hadronisers/GenericHadroniser.h" +#include "CepGen/IO/GenericExportHandler.h" #include "CepGen/Parameters.h" #include #include #include namespace cepgen { namespace integrand { utils::Logger::Level log_level; utils::Timer tmr; double eval( double* x, size_t ndim, void* func_params ) { log_level = utils::Logger::get().level; std::shared_ptr ev; Parameters* params = nullptr; if ( !func_params || !( params = static_cast( func_params ) ) ) throw CG_FATAL( "Integrand" ) << "Failed to retrieve the run parameters!"; proc::GenericProcess* proc = params->process(); if ( !proc ) throw CG_FATAL( "Integrand" ) << "Failed to retrieve the process!"; //================================================================ // start the timer //================================================================ tmr.reset(); //================================================================ // prepare the event content prior to the process generation //================================================================ if ( proc->hasEvent() ) // event is not empty ev = proc->event(); params->prepareRun(); //================================================================ // specify the phase space point to probe //================================================================ proc->setPoint( ndim, x ); //================================================================ // from this step on, the phase space point is supposed to be set //================================================================ proc->beforeComputeWeight(); double weight = proc->computeWeight(); //================================================================ // invalidate any unphysical behaviour //================================================================ if ( weight <= 0. ) return 0.; //================================================================ // speed up the integration process if no event is to be generated //================================================================ if ( !ev ) return weight; if ( !params->storage() && !params->taming_functions && !params->hadroniser() && params->kinematics.cuts.central_particles.empty() ) return weight; //================================================================ // fill in the process' Event object //================================================================ proc->fillKinematics(); //================================================================ // once the kinematics variables have been populated, can apply // the collection of taming functions //================================================================ if ( params->taming_functions ) { if ( params->taming_functions->has( "m_central" ) || params->taming_functions->has( "pt_central" ) ) { // build the kinematics of the central system Particle::Momentum central_system; for ( const auto& part : (*ev)[Particle::CentralSystem] ) central_system += part.momentum(); // tame the cross-section by the reweighting function if ( params->taming_functions->has( "m_central" ) ) weight *= params->taming_functions->eval( "m_central", central_system.mass() ); if ( params->taming_functions->has( "pt_central" ) ) weight *= params->taming_functions->eval( "pt_central", central_system.pt() ); } if ( params->taming_functions->has( "q2" ) ) { weight *= params->taming_functions->eval( "q2", -ev->getOneByRole( Particle::Parton1 ).momentum().mass() ); weight *= params->taming_functions->eval( "q2", -ev->getOneByRole( Particle::Parton2 ).momentum().mass() ); } } if ( weight <= 0. ) return 0.; //================================================================ // set the CepGen part of the event generation //================================================================ if ( params->storage() ) ev->time_generation = tmr.elapsed(); //================================================================ // event hadronisation and resonances decay //================================================================ if ( params->hadroniser() ) { double br = -1.; if ( !params->hadroniser()->run( *ev, br, params->storage() ) || br == 0. ) return 0.; weight *= br; // branching fraction for all decays } //================================================================ // apply cuts on final state system (after hadronisation!) // (polish your cuts, as this might be very time-consuming...) //================================================================ if ( !params->kinematics.cuts.central_particles.empty() ) { for ( const auto& part : (*ev)[Particle::CentralSystem] ) { // retrieve all cuts associated to this final state particle if ( params->kinematics.cuts.central_particles.count( part.pdgId() ) == 0 ) continue; const auto& cuts_pdgid = params->kinematics.cuts.central_particles.at( part.pdgId() ); // apply these cuts on the given particle if ( !cuts_pdgid.pt_single.passes( part.momentum().pt() ) ) return 0.; if ( !cuts_pdgid.energy_single.passes( part.momentum().energy() ) ) return 0.; if ( !cuts_pdgid.eta_single.passes( part.momentum().eta() ) ) return 0.; if ( !cuts_pdgid.rapidity_single.passes( part.momentum().rapidity() ) ) return 0.; } } for ( const auto& system : { Particle::OutgoingBeam1, Particle::OutgoingBeam2 } ) for ( const auto& part : (*ev)[system] ) { if ( part.status() != Particle::Status::FinalState ) continue; if ( !params->kinematics.cuts.remnants.energy_single.passes( fabs( part.momentum().energy() ) ) ) return 0.; if ( !params->kinematics.cuts.remnants.rapidity_single.passes( fabs( part.momentum().rapidity() ) ) ) return 0.; } //================================================================ // store the last event in parameters block for a later usage //================================================================ if ( params->storage() ) { proc->last_event = ev; proc->last_event->time_total = tmr.elapsed(); CG_DEBUG( "Integrand" ) << "[process 0x" << std::hex << proc << std::dec << "] " << "Individual time (gen+hadr+cuts): " << proc->last_event->time_total*1.e3 << " ms"; } //================================================================ // a bit of useful debugging //================================================================ if ( CG_LOG_MATCH( "Integrand", debugInsideLoop ) ) { std::ostringstream oss; for ( unsigned short i = 0; i < ndim; ++i ) oss << Form( "%10.8f ", x[i] ); CG_DEBUG( "Integrand" ) << "f value for dim-" << ndim << " point ( " << oss.str() << "): " << weight; } return weight; } } } diff --git a/CepGen/Core/Integrator.cpp b/CepGen/Core/Integrator.cpp index 5ff26a4..f267ae2 100644 --- a/CepGen/Core/Integrator.cpp +++ b/CepGen/Core/Integrator.cpp @@ -1,466 +1,475 @@ #include "CepGen/Core/Integrator.h" #include "CepGen/Core/GridParameters.h" #include "CepGen/Core/utils.h" #include "CepGen/Core/Exception.h" #include "CepGen/Parameters.h" #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Hadronisers/GenericHadroniser.h" +#include "CepGen/IO/GenericExportHandler.h" + #include "CepGen/Event/Event.h" #include #include #include #define COORD(s,i,j) ((s)->xi[(i)*(s)->dim + (j)]) namespace cepgen { Integrator::Integrator( unsigned int ndim, double integrand( double*, size_t, void* ), Parameters& params ) : ps_bin_( INVALID_BIN ), input_params_( params ), function_( new gsl_monte_function{ integrand, ndim, (void*)&input_params_ } ), rng_( gsl_rng_alloc( input_params_.integration().rng_engine ) ), grid_( new GridParameters( ndim ) ) { //--- initialise the random number generator unsigned long seed = ( input_params_.integration().rng_seed > 0 ) ? input_params_.integration().rng_seed : time( nullptr ); // seed with time gsl_rng_set( rng_.get(), seed ); //--- a bit of printout for debugging CG_DEBUG( "Integrator:build" ) << "Number of integration dimensions: " << function_->dim << ",\n\t" << "Number of function calls: " << input_params_.integration().ncvg << ",\n\t" << "Random numbers generator: " << gsl_rng_name( rng_.get() ) << "."; switch ( input_params_.integration().type ) { case IntegratorType::Vegas: CG_DEBUG( "Integrator:build" ) << "Vegas parameters:\n\t" << "Number of iterations in Vegas: " << input_params_.integration().vegas.iterations << ",\n\t" << "α-value: " << input_params_.integration().vegas.alpha << ",\n\t" << "Verbosity: " << input_params_.integration().vegas.verbose << ",\n\t" << "Grid interpolation mode: " << (Integrator::VegasMode)input_params_.integration().vegas.mode << "."; break; case IntegratorType::MISER: CG_DEBUG( "Integrator:build" ) << "MISER parameters:\n\t" << "Number of calls: " << input_params_.integration().miser.min_calls << ", " << "per bisection: " << input_params_.integration().miser.min_calls_per_bisection << ",\n\t" << "Estimate fraction: " << input_params_.integration().miser.estimate_frac << ",\n\t" << "α-value: " << input_params_.integration().miser.alpha << ",\n\t" << "Dither: " << input_params_.integration().miser.dither << "."; break; case IntegratorType::plain: break; } } Integrator::~Integrator() {} //----------------------------------------------------------------------------------------------- // integration part //----------------------------------------------------------------------------------------------- void Integrator::integrate( double& result, double& abserr ) { int res = -1; //--- integration bounds std::vector x_low( function_->dim, 0. ), x_up( function_->dim, 1. ); //--- launch integration switch ( input_params_.integration().type ) { case IntegratorType::plain: { std::unique_ptr pln_state( gsl_monte_plain_alloc( function_->dim ), gsl_monte_plain_free ); res = gsl_monte_plain_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, input_params_.integration().ncvg, rng_.get(), pln_state.get(), &result, &abserr ); } break; case IntegratorType::Vegas: { //----- warmup (prepare the grid) warmupVegas( x_low, x_up, 25000 ); //----- integration unsigned short it_chisq = 0; do { res = gsl_monte_vegas_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, 0.2 * input_params_.integration().ncvg, rng_.get(), veg_state_.get(), &result, &abserr ); CG_LOG( "Integrator:integrate" ) << "\t>> at call " << ( ++it_chisq ) << ": " << Form( "average = %10.6f " "sigma = %10.6f chi2 = %4.3f.", result, abserr, gsl_monte_vegas_chisq( veg_state_.get() ) ); } while ( fabs( gsl_monte_vegas_chisq( veg_state_.get() )-1. ) > input_params_.integration().vegas_chisq_cut-1. ); CG_DEBUG( "Integrator:integrate" ) << "Vegas grid information:\n\t" << "ran for " << veg_state_->dim << " dimensions, and generated " << veg_state_->bins_max << " bins.\n\t" << "Integration volume: " << veg_state_->vol << "."; grid_->r_boxes = std::pow( veg_state_->bins, function_->dim ); } break; case IntegratorType::MISER: { std::unique_ptr mis_state( gsl_monte_miser_alloc( function_->dim ), gsl_monte_miser_free ); gsl_monte_miser_params_set( mis_state.get(), &input_params_.integration().miser ); res = gsl_monte_miser_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, input_params_.integration().ncvg, rng_.get(), mis_state.get(), &result, &abserr ); } break; } input_params_.integration().result = result; input_params_.integration().err_result = abserr; if ( input_params_.hadroniser() ) input_params_.hadroniser()->setCrossSection( result, abserr ); if ( res != GSL_SUCCESS ) throw CG_FATAL( "Integrator:integrate" ) << "Error while performing the integration!\n\t" << "GSL error: " << gsl_strerror( res ) << "."; } void Integrator::warmupVegas( std::vector& x_low, std::vector& x_up, unsigned int ncall ) { // start by preparing the grid/state veg_state_.reset( gsl_monte_vegas_alloc( function_->dim ) ); gsl_monte_vegas_params_set( veg_state_.get(), &input_params_.integration().vegas ); // then perform a first integration with the given calls count double result = 0., abserr = 0.; const int res = gsl_monte_vegas_integrate( function_.get(), &x_low[0], &x_up[0], function_->dim, ncall, rng_.get(), veg_state_.get(), &result, &abserr ); // ensure the operation was successful if ( res != GSL_SUCCESS ) throw CG_ERROR( "Integrator:vegas" ) << "Failed to warm-up the Vegas grid.\n\t" << "GSL error: " << gsl_strerror( res ) << "."; CG_INFO( "Integrator:vegas" ) << "Finished the Vegas warm-up."; } //----------------------------------------------------------------------------------------------- // events generation part //----------------------------------------------------------------------------------------------- void Integrator::generateOne( std::function callback ) { if ( !grid_->gen_prepared ) computeGenerationParameters(); std::vector xtmp; //--- correction cycles if ( ps_bin_ != INVALID_BIN ) { bool has_correction = false; while ( !correctionCycle( xtmp, has_correction ) ) {} if ( has_correction ) { storeEvent( xtmp, callback ); return; } } double weight = 0.; //--- normal generation cycle while ( true ) { double y = -1.; //----- select a and reject if fmax is too small while ( true ) { // ... ps_bin_ = uniform() * grid_->size(); y = uniform() * grid_->globalMax(); grid_->num[ps_bin_] += 1; if ( y <= grid_->maxValue( ps_bin_ ) ) break; } // shoot a point x in this bin grid_->shoot( rng_.get(), ps_bin_, xtmp ); // get weight for selected x value weight = eval( xtmp ); if ( weight <= 0. ) continue; if ( weight > y ) break; } if ( weight <= grid_->maxValue( ps_bin_ ) ) ps_bin_ = INVALID_BIN; else { //--- if weight is higher than local or global maximum, // init correction cycle grid_->f_max_old = grid_->maxValue( ps_bin_ ); grid_->f_max_diff = weight-grid_->f_max_old; grid_->setValue( ps_bin_, weight ); grid_->correc = ( grid_->num[ps_bin_]-1. ) * grid_->f_max_diff / grid_->globalMax() - 1.; CG_DEBUG("Integrator::generateOne") << "Correction " << grid_->correc << " will be applied for phase space bin " << ps_bin_ << "."; } // return with an accepted event if ( weight > 0. ) storeEvent( xtmp, callback ); } void Integrator::generate( unsigned long num_events, std::function callback ) { if ( num_events < 1 ) num_events = input_params_.generation().maxgen; + if ( input_params_.outputModule() ) + input_params_.outputModule()->initialise( input_params_ ); try { while ( input_params_.numGeneratedEvents() < num_events ) generateOne( callback ); - } catch ( const Exception& e ) { return; } + } catch ( const Exception& ) { return; } } bool Integrator::correctionCycle( std::vector& x, bool& has_correction ) { CG_DEBUG_LOOP( "Integrator:correction" ) << "Correction cycles are started.\n\t" << "bin = " << ps_bin_ << "\t" << "correc = " << grid_->correc << "\t" << "corre2 = " << grid_->correc2 << "."; if ( grid_->correc >= 1. ) grid_->correc -= 1.; if ( uniform() < grid_->correc ) { grid_->correc = -1.; std::vector xtmp( function_->dim ); // Select x values in phase space bin grid_->shoot( rng_.get(), ps_bin_, xtmp ); const double weight = eval( xtmp ); // Parameter for correction of correction if ( weight > grid_->maxValue( ps_bin_ ) ) { grid_->f_max2 = std::max( grid_->f_max2, weight ); grid_->correc += 1.; grid_->correc2 -= 1.; } // Accept event if ( weight >= grid_->f_max_diff*uniform() + grid_->f_max_old ) { x = xtmp; has_correction = true; return true; } return false; } // Correction if too big weight is found while correction // (All your bases are belong to us...) if ( grid_->f_max2 > grid_->maxValue( ps_bin_ ) ) { grid_->f_max_old = grid_->maxValue( ps_bin_ ); grid_->f_max_diff = grid_->f_max2-grid_->f_max_old; grid_->correc = ( grid_->num[ps_bin_]-1. ) * grid_->f_max_diff / grid_->globalMax(); if ( grid_->f_max2 >= grid_->globalMax() ) grid_->correc *= grid_->f_max2 / grid_->globalMax(); grid_->setValue( ps_bin_, grid_->f_max2 ); grid_->correc -= grid_->correc2; grid_->correc2 = 0.; grid_->f_max2 = 0.; return false; } return true; } bool Integrator::storeEvent( const std::vector& x, std::function callback ) { //--- start by computing the matrix element for that point const double weight = eval( x ); //--- reject if unphysical if ( weight <= 0. ) return false; { if ( input_params_.numGeneratedEvents() % input_params_.generation().gen_print_every == 0 ) { CG_INFO( "Integrator:store" ) << "Generated events: " << input_params_.numGeneratedEvents(); input_params_.process()->last_event->dump(); } const Event& last_event = *input_params_.process()->last_event; if ( callback ) callback( last_event, input_params_.numGeneratedEvents() ); input_params_.addGenerationTime( last_event.time_total ); + if ( input_params_.outputModule() ) + *input_params_.outputModule() << last_event; } return true; } //----------------------------------------------------------------------------------------------- // initial preparation run before the generation of unweighted events //----------------------------------------------------------------------------------------------- void Integrator::computeGenerationParameters() { input_params_.setStorage( false ); if ( input_params_.generation().treat && input_params_.integration().type != IntegratorType::Vegas ) { CG_INFO( "Integrator:setGen" ) << "Treat switched on without a proper Vegas grid; running a warm-up beforehand."; std::vector x_low( function_->dim, 0. ), x_up( function_->dim, 1. ); try { warmupVegas( x_low, x_up, 25000 ); } catch ( const Exception& ) { throw CG_FATAL( "Integrator::setGen" ) << "Failed to perform a Vegas warm-up.\n\t" << "Try to re-run while disabling integrand treatment..."; } } CG_INFO( "Integrator:setGen" ) << "Preparing the grid (" << input_params_.generation().num_points << " points/bin) " << "for the generation of unweighted events."; const double inv_num_points = 1./input_params_.generation().num_points; std::vector x( function_->dim, 0. ); std::vector n( function_->dim, 0 );; // ... double sum = 0., sum2 = 0., sum2p = 0.; + utils::ProgressBar prog_bar( grid_->size(), 5 ); + //--- main loop for ( unsigned int i = 0; i < grid_->size(); ++i ) { double fsum = 0., fsum2 = 0.; for ( unsigned int j = 0; j < input_params_.generation().num_points; ++j ) { grid_->shoot( rng_.get(), i, x ); const double weight = eval( x ); grid_->setValue( i, weight ); fsum += weight; fsum2 += weight*weight; } const double av = fsum*inv_num_points, av2 = fsum2*inv_num_points, sig2 = av2-av*av; sum += av; sum2 += av2; sum2p += sig2; // per-bin debugging loop if ( CG_LOG_MATCH( "Integrator:setGen", debugInsideLoop ) ) { const double sig = sqrt( sig2 ); const double eff = ( grid_->maxValue( i ) != 0. ) ? grid_->maxValue( i )/av : 1.e4; CG_DEBUG_LOOP( "Integrator:setGen" ) << "n-vector for bin " << i << ": " << utils::repr( grid_->n( i ) ) << "\n\t" << "av = " << av << "\n\t" << "sig = " << sig << "\n\t" << "fmax = " << grid_->maxValue( i ) << "\n\t" << "eff = " << eff; } + prog_bar.update( i+1 ); } // end of main loop const double inv_max = 1./grid_->size(); sum *= inv_max; sum2 *= inv_max; sum2p *= inv_max; const double sig = sqrt( sum2-sum*sum ), sigp = sqrt( sum2p ); double eff1 = 0.; for ( unsigned int i = 0; i < grid_->size(); ++i ) eff1 += sum/grid_->size()*grid_->maxValue( i ); const double eff2 = sum/grid_->globalMax(); CG_DEBUG( "Integrator:setGen" ) << "Average function value = " << sum << "\n\t" << "Average squared function value = " << sum2 << "\n\t" << "Overall standard deviation = " << sig << "\n\t" << "Average standard deviation = " << sigp << "\n\t" << "Maximum function value = " << grid_->globalMax() << "\n\t" << "Average inefficiency = " << eff1 << "\n\t" << "Overall inefficiency = " << eff2; grid_->gen_prepared = true; input_params_.setStorage( true ); CG_INFO( "Integrator:setGen" ) << "Grid prepared! Now launching the production."; } //------------------------------------------------------------------------------------------------ // helper / alias methods //------------------------------------------------------------------------------------------------ unsigned short Integrator::dimensions() const { if ( !function_ ) return 0; return function_->dim; } double Integrator::eval( const std::vector& x ) { if ( !input_params_.generation().treat ) return function_->f( (double*)&x[0], function_->dim, (void*)&input_params_ ); //--- treatment of the integration grid double w = grid_->r_boxes; std::vector x_new( x.size() ); for ( unsigned short j = 0; j < function_->dim; ++j ) { //--- find surrounding coordinates and interpolate const double z = x[j]*veg_state_->bins; const unsigned int id = z; // coordinate of point before const double rel_pos = z-id; // position between coordinates (norm.) const double bin_width = ( id == 0 ) ? COORD( veg_state_, 1, j ) : COORD( veg_state_, id+1, j )-COORD( veg_state_, id, j ); //--- build new coordinate from linear interpolation x_new[j] = COORD( veg_state_, id+1, j )-bin_width*( 1.-rel_pos ); w *= bin_width; } return w*function_->f( (double*)&x_new[0], function_->dim, (void*)&input_params_ ); } double Integrator::uniform() const { return gsl_rng_uniform( rng_.get() ); } //------------------------------------------------------------------------------------------------ std::ostream& operator<<( std::ostream& os, const IntegratorType& type ) { switch ( type ) { case IntegratorType::plain: return os << "plain"; case IntegratorType::Vegas: return os << "Vegas"; case IntegratorType::MISER: return os << "MISER"; } return os; } std::ostream& operator<<( std::ostream& os, const Integrator::VegasMode& mode ) { switch ( mode ) { case Integrator::VegasMode::importance: return os << "importance"; case Integrator::VegasMode::importanceOnly: return os << "importance-only"; case Integrator::VegasMode::stratified: return os << "stratified"; } return os; } } diff --git a/CepGen/Core/Parameters.cpp b/CepGen/Core/Parameters.cpp index 238987f..33ab96a 100644 --- a/CepGen/Core/Parameters.cpp +++ b/CepGen/Core/Parameters.cpp @@ -1,307 +1,332 @@ #include "CepGen/Parameters.h" #include "CepGen/Core/Integrator.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/TamingFunction.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Hadronisers/GenericHadroniser.h" +#include "CepGen/IO/GenericExportHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include namespace cepgen { Parameters::Parameters() : general( new ParametersList ), taming_functions( new utils::TamingFunctionsCollection ), store_( false ), total_gen_time_( 0. ), num_gen_events_( 0ul ) {} Parameters::Parameters( Parameters& param ) : general( param.general ), kinematics( param.kinematics ), taming_functions( param.taming_functions ), process_( std::move( param.process_ ) ), hadroniser_( std::move( param.hadroniser_ ) ), + out_module_( std::move( param.out_module_ ) ), store_( false ), total_gen_time_( param.total_gen_time_ ), num_gen_events_( param.num_gen_events_ ), integration_( param.integration_ ), generation_( param.generation_ ) {} Parameters::Parameters( const Parameters& param ) : general( param.general ), kinematics( param.kinematics ), taming_functions( param.taming_functions ), store_( false ), total_gen_time_( param.total_gen_time_ ), num_gen_events_( param.num_gen_events_ ), integration_( param.integration_ ), generation_( param.generation_ ) {} Parameters::~Parameters() // required for unique_ptr initialisation! {} Parameters& Parameters::operator=( Parameters param ) { general = param.general; kinematics = param.kinematics; taming_functions = param.taming_functions; process_ = std::move( param.process_ ); hadroniser_ = std::move( param.hadroniser_ ); + out_module_ = std::move( param.out_module_ ); total_gen_time_ = param.total_gen_time_; num_gen_events_ = param.num_gen_events_; integration_ = param.integration_; generation_ = param.generation_; return *this; } void Parameters::setThetaRange( float thetamin, float thetamax ) { kinematics.cuts.central.eta_single = { Particle::thetaToEta( thetamax ), Particle::thetaToEta( thetamin ) }; CG_DEBUG( "Parameters" ) << "eta in range: " << kinematics.cuts.central.eta_single << " => theta(min) = " << thetamin << ", theta(max) = " << thetamax << "."; } void Parameters::prepareRun() { //--- first-run preparation if ( !process_ || !process_->first_run ) return; CG_DEBUG( "Parameters" ) << "Run started for " << process_->name() << " process " << "0x" << std::hex << process_.get() << std::dec << ".\n\t" << "Process mode considered: " << kinematics.mode << "\n\t" << " first beam: " << kinematics.incoming_beams.first << "\n\t" << " second beam: " << kinematics.incoming_beams.second << "\n\t" << " structure functions: " << kinematics.structure_functions; if ( process_->hasEvent() ) process_->clearEvent(); //--- clear the run statistics total_gen_time_ = 0.; num_gen_events_ = 0ul; process_->first_run = false; } void Parameters::addGenerationTime( double gen_time ) { total_gen_time_ += gen_time; num_gen_events_++; } proc::GenericProcess* Parameters::process() { return process_.get(); } const proc::GenericProcess* Parameters::process() const { return process_.get(); } std::string Parameters::processName() const { if ( !process_ ) return "no process"; return process_->name(); } void Parameters::setProcess( std::unique_ptr proc ) { process_ = std::move( proc ); } void Parameters::setProcess( proc::GenericProcess* proc ) { if ( !proc ) throw CG_FATAL( "Parameters" ) << "Trying to clone an invalid process!"; process_.reset( proc ); } hadr::GenericHadroniser* Parameters::hadroniser() { return hadroniser_.get(); } std::string Parameters::hadroniserName() const { if ( !hadroniser_ ) return ""; return hadroniser_->name(); } void Parameters::setHadroniser( std::unique_ptr hadr ) { hadroniser_ = std::move( hadr ); } void Parameters::setHadroniser( hadr::GenericHadroniser* hadr ) { hadroniser_.reset( hadr ); } + io::GenericExportHandler* + Parameters::outputModule() + { + return out_module_.get(); + } + + void + Parameters::setOutputModule( std::unique_ptr mod ) + { + out_module_ = std::move( mod ); + } + + void + Parameters::setOutputModule( io::GenericExportHandler* mod ) + { + out_module_.reset( mod ); + } + std::ostream& operator<<( std::ostream& os, const Parameters* param ) { const bool pretty = true; const int wb = 90, wt = 33; os << std::left << "\n" << std::setfill('_') << std::setw( wb+3 ) << "_/¯ PROCESS INFORMATION ¯\\_" << std::setfill( ' ' ) << "\n" << std::right << std::setw( wb ) << std::left << std::endl << std::setw( wt ) << "Process to generate" << ( pretty ? boldify( param->processName().c_str() ) : param->processName() ); if ( param->process_ ) { os << ", " << param->process_->description(); for ( const auto& par : param->process()->parameters().keys() ) if ( par != "mode" ) os << "\n" << std::setw( wt ) << "" << par << ": " << param->process_->parameters().getString( par ); std::ostringstream proc_mode; proc_mode << param->kinematics.mode; if ( param->kinematics.mode != KinematicsMode::invalid ) os << "\n" << std::setw( wt ) << "Subprocess mode" << ( pretty ? boldify( proc_mode.str().c_str() ) : proc_mode.str() ) << "\n"; } os << "\n" << std::setfill('_') << std::setw( wb+3 ) << "_/¯ RUN INFORMATION ¯\\_" << std::setfill( ' ' ) << "\n" << std::right << std::setw( wb ) << std::left << std::endl << std::setw( wt ) << "Events generation? " << ( pretty ? yesno( param->generation_.enabled ) : std::to_string( param->generation_.enabled ) ) << "\n" << std::setw( wt ) << "Number of events to generate" << ( pretty ? boldify( param->generation_.maxgen ) : std::to_string( param->generation_.maxgen ) ) << "\n"; + if ( param->out_module_ ) + os << std::setw( wt ) << "Output module" << param->out_module_->name() << "\n"; if ( param->generation_.num_threads > 1 ) os << std::setw( wt ) << "Number of threads" << param->generation_.num_threads << "\n"; os << std::setw( wt ) << "Number of points to try per bin" << param->generation_.num_points << "\n" << std::setw( wt ) << "Integrand treatment" << ( pretty ? yesno( param->generation_.treat ) : std::to_string( param->generation_.treat ) ) << "\n" << std::setw( wt ) << "Verbosity level " << utils::Logger::get().level << "\n"; if ( param->hadroniser_ ) { os << "\n" << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Hadronisation algorithm " ) : "Hadronisation algorithm" ) << std::setfill( ' ' ) << "\n\n" << std::setw( wt ) << "Name" - << ( pretty ? boldify( param->hadroniser_->name().c_str() ) : param->hadroniser_->name() ) << "\n"; + << ( pretty ? boldify( param->hadroniser_->name().c_str() ) : param->hadroniser_->name() ) << "\n" + << std::setw( wt ) << "Remnants fragmentation? " + << ( pretty ? yesno( param->hadroniser_->fragmentRemnants() ) : std::to_string( param->hadroniser_->fragmentRemnants() ) ) << "\n"; } os << "\n" << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Integration parameters " ) : "Integration parameters" ) << std::setfill( ' ' ) << "\n\n"; std::ostringstream int_algo; int_algo << param->integration_.type; os << std::setw( wt ) << "Integration algorithm" << ( pretty ? boldify( int_algo.str().c_str() ) : int_algo.str() ) << "\n" << std::setw( wt ) << "Number of function calls" << param->integration_.ncvg << "\n" << std::setw( wt ) << "Random number generator seed" << param->integration_.rng_seed << "\n"; if ( param->integration_.rng_engine ) os << std::setw( wt ) << "Random number generator engine" << param->integration_.rng_engine->name << "\n"; os << "\n" << std::setfill('_') << std::setw( wb+3 ) << "_/¯ EVENTS KINEMATICS ¯\\_" << std::setfill( ' ' ) << "\n\n" << std::setw( wt ) << "Incoming particles" << param->kinematics.incoming_beams.first << ",\n" << std::setw( wt ) << "" << param->kinematics.incoming_beams.second << "\n" << std::setw( wt ) << "C.m. energy (GeV)" << param->kinematics.sqrtS() << "\n"; if ( param->kinematics.mode != KinematicsMode::ElasticElastic ) os << std::setw( wt ) << "Structure functions" << *param->kinematics.structure_functions << "\n"; os << "\n" << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Incoming partons " ) : "Incoming partons" ) << std::setfill( ' ' ) << "\n\n"; for ( const auto& lim : param->kinematics.cuts.initial.list() ) // map(particles class, limits) if ( lim.second.valid() ) os << std::setw( wt ) << lim.first << lim.second << "\n"; os << "\n" << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Outgoing central system " ) : "Outgoing central system" ) << std::setfill( ' ' ) << "\n\n"; for ( const auto& lim : param->kinematics.cuts.central.list() ) if ( lim.second.valid() ) os << std::setw( wt ) << lim.first << lim.second << "\n"; if ( param->kinematics.cuts.central_particles.size() > 0 ) { os << std::setw( wt ) << ( pretty ? boldify( ">>> per-particle cuts:" ) : ">>> per-particle cuts:" ) << "\n"; for ( const auto& part_per_lim : param->kinematics.cuts.central_particles ) { - os << " * all single " << std::setw( wt-3 ) << part_per_lim.first << "\n"; + os << " * all single " << std::setw( wt-3 ) << PDG::get().name( part_per_lim.first ) << "\n"; for ( const auto& lim : part_per_lim.second.list() ) if ( lim.second.valid() ) os << " - " << std::setw( wt-5 ) << lim.first << lim.second << "\n"; } } os << "\n"; os << std::setfill( '-' ) << std::setw( wb+6 ) << ( pretty ? boldify( " Proton / remnants " ) : "Proton / remnants" ) << std::setfill( ' ' ) << "\n"; for ( const auto& lim : param->kinematics.cuts.remnants.list() ) os << "\n" << std::setw( wt ) << lim.first << lim.second; os << "\n"; return os; } //----------------------------------------------------------------------------------------------- Parameters::Integration::Integration() : type( IntegratorType::Vegas ), ncvg( 50000 ), rng_seed( 0 ), rng_engine( (gsl_rng_type*)gsl_rng_mt19937 ), vegas_chisq_cut( 1.5 ), result( -1. ), err_result( -1. ) { const size_t ndof = 10; // random number of dimensions for VEGAS parameters retrieval { std::shared_ptr tmp_state( gsl_monte_vegas_alloc( ndof ), gsl_monte_vegas_free ); gsl_monte_vegas_params_get( tmp_state.get(), &vegas ); vegas.iterations = 10; } { std::shared_ptr tmp_state( gsl_monte_miser_alloc( ndof ), gsl_monte_miser_free ); gsl_monte_miser_params_get( tmp_state.get(), &miser ); } } Parameters::Integration::Integration( const Integration& rhs ) : type( rhs.type ), ncvg( rhs.ncvg ), rng_seed( rhs.rng_seed ), rng_engine( rhs.rng_engine ), vegas( rhs.vegas ), vegas_chisq_cut( rhs.vegas_chisq_cut ), miser( rhs.miser ), result( -1. ), err_result( -1. ) {} Parameters::Integration::~Integration() { //if ( vegas.ostream && vegas.ostream != stdout && vegas.ostream != stderr ) // fclose( vegas.ostream ); } //----------------------------------------------------------------------------------------------- Parameters::Generation::Generation() : enabled( false ), maxgen( 0 ), symmetrise( false ), treat( true ), gen_print_every( 10000 ), num_threads( 2 ), num_points( 100 ) {} Parameters::Generation::Generation( const Generation& rhs ) : enabled( rhs.enabled ), maxgen( rhs.maxgen ), symmetrise( rhs.symmetrise ), treat( rhs.treat ), gen_print_every( rhs.gen_print_every ), num_threads( rhs.num_threads ), num_points( rhs.num_points ) {} } diff --git a/CepGen/Core/ParametersList.cpp b/CepGen/Core/ParametersList.cpp index 005456c..248be0a 100644 --- a/CepGen/Core/ParametersList.cpp +++ b/CepGen/Core/ParametersList.cpp @@ -1,311 +1,318 @@ #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Physics/PDG.h" #include namespace cepgen { ParametersList::ParametersList( const ParametersList& oth ) : param_values_( oth.param_values_ ), int_values_( oth.int_values_ ), dbl_values_( oth.dbl_values_ ), str_values_( oth.str_values_ ), lim_values_( oth.lim_values_ ), vec_param_values_( oth.vec_param_values_ ), vec_int_values_( oth.vec_int_values_ ), vec_dbl_values_( oth.vec_dbl_values_ ), vec_str_values_( oth.vec_str_values_ ) {} ParametersList& ParametersList::operator+=( const ParametersList& oth ) { param_values_.insert( oth.param_values_.begin(), oth.param_values_.end() ); int_values_.insert( oth.int_values_.begin(), oth.int_values_.end() ); dbl_values_.insert( oth.dbl_values_.begin(), oth.dbl_values_.end() ); str_values_.insert( oth.str_values_.begin(), oth.str_values_.end() ); lim_values_.insert( oth.lim_values_.begin(), oth.lim_values_.end() ); vec_param_values_.insert( oth.vec_param_values_.begin(), oth.vec_param_values_.end() ); vec_int_values_.insert( oth.vec_int_values_.begin(), oth.vec_int_values_.end() ); vec_dbl_values_.insert( oth.vec_dbl_values_.begin(), oth.vec_dbl_values_.end() ); vec_str_values_.insert( oth.vec_str_values_.begin(), oth.vec_str_values_.end() ); return *this; } std::ostream& operator<<( std::ostream& os, const ParametersList& params ) { const auto beg = os.tellp(); for ( const auto& kv : params.int_values_ ) os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=int(" << kv.second << ")"; for ( const auto& kv : params.dbl_values_ ) os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=double(" << kv.second << ")"; for ( const auto& kv : params.str_values_ ) os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=string(" << kv.second << ")"; for ( const auto& kv : params.param_values_ ) os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=param({" << kv.second << "})"; for ( const auto& kv : params.lim_values_ ) os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=limits(" << kv.second << ")"; for ( const auto& kv : params.vec_int_values_ ) { os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=vint("; bool first = true; for ( const auto& v : kv.second ) os << ( first ? "" : ", " ) << v, first = false; os << ")"; } for ( const auto& kv : params.vec_dbl_values_ ) { os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=vdouble("; bool first = true; for ( const auto& v : kv.second ) os << ( first ? "" : ", " ) << v, first = false; os << ")"; } for ( const auto& kv : params.vec_str_values_ ) { os << ( os.tellp() > beg ? ", " : "" ) << kv.first << "=vstring("; bool first = true; for ( const auto& v : kv.second ) os << ( first ? "" : ", " ) << v, first = false; os << ")"; } return os; } std::vector ParametersList::keys() const { std::vector out; for ( const auto& p : param_values_ ) out.emplace_back( p.first ); for ( const auto& p : vec_param_values_ ) out.emplace_back( p.first ); for ( const auto& p : int_values_ ) out.emplace_back( p.first ); for ( const auto& p : vec_int_values_ ) out.emplace_back( p.first ); for ( const auto& p : dbl_values_ ) out.emplace_back( p.first ); for ( const auto& p : vec_dbl_values_ ) out.emplace_back( p.first ); for ( const auto& p : str_values_ ) out.emplace_back( p.first ); for ( const auto& p : vec_str_values_ ) out.emplace_back( p.first ); for ( const auto& p : lim_values_ ) out.emplace_back( p.first ); return out; } std::string ParametersList::getString( const std::string& key ) const { std::ostringstream os; if ( has( key ) ) os << "params{" << get( key ) << "}"; else if ( has( key ) ) os << get( key ); else if ( has( key ) ) os << get( key ); else if ( has( key ) ) os << get( key ); else if ( has( key ) ) os << get( key ); else if ( has >( key ) ) { bool first = true; for ( const auto& p : get >( key ) ) { os << ( first ? "" : ", " ) << p; first = false; } } else if ( has >( key ) ) { bool first = true; for ( const auto& p : get >( key ) ) { os << ( first ? "" : ", " ) << p; first = false; } } else if ( has >( key ) ) { bool first = true; for ( const auto& p : get >( key ) ) { os << ( first ? "" : ", " ) << p; first = false; } } else if ( has >( key ) ) { bool first = true; for ( const auto& p : get >( key ) ) { os << ( first ? "" : ", " ) << p; first = false; } } return os.str(); } //------------------------------------------------------------------ // default template (placeholders) //------------------------------------------------------------------ template bool ParametersList::has( std::string key ) const { throw CG_FATAL( "ParametersList" ) << "Invalid type for key=" << key << "!"; } template T ParametersList::get( std::string key, const T& def ) const { throw CG_FATAL( "ParametersList" ) << "Invalid type retrieved for key=" << key << "!"; } template T& ParametersList::operator[]( std::string key ) { throw CG_FATAL( "ParametersList" ) << "Invalid type retrieved for key=" << key << "!"; } template ParametersList& ParametersList::set( std::string key, const T& value ) { throw CG_FATAL( "ParametersList" ) << "Invalid type to be set for key=" << key << "!"; } //------------------------------------------------------------------ // sub-parameters-type attributes //------------------------------------------------------------------ template<> ParametersList ParametersList::get( std::string key, const ParametersList& def ) const { for ( const auto& kv : param_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector ParametersList::get >( std::string key, const std::vector& def ) const { for ( const auto& kv : vec_param_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } //------------------------------------------------------------------ // integer-type attributes //------------------------------------------------------------------ template<> int ParametersList::get( std::string key, const int& def ) const { for ( const auto& kv : int_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector ParametersList::get >( std::string key, const std::vector& def ) const { for ( const auto& kv : vec_int_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } //------------------------------------------------------------------ // floating point-type attributes //------------------------------------------------------------------ template<> double ParametersList::get( std::string key, const double& def ) const { for ( const auto& kv : dbl_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector ParametersList::get >( std::string key, const std::vector& def ) const { for ( const auto& kv : vec_dbl_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } //------------------------------------------------------------------ // string-type attributes //------------------------------------------------------------------ template<> std::string ParametersList::get( std::string key, const std::string& def ) const { for ( const auto& kv : str_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector ParametersList::get >( std::string key, const std::vector& def ) const { for ( const auto& kv : vec_str_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } //------------------------------------------------------------------ // limits-type attributes //------------------------------------------------------------------ template<> Limits ParametersList::get( std::string key, const Limits& def ) const { for ( const auto& kv : lim_values_ ) if ( kv.first == key ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } //------------------------------------------------------------------ // particle properties-type attributes //------------------------------------------------------------------ template<> ParticleProperties ParametersList::get( std::string key, const ParticleProperties& def ) const { if ( has( key ) ) { const auto& plist = get( key ); - const std::string pname = plist.has( "name" ) - ? plist.get( "name" ) - : key; - const std::string pdesc = plist.has( "description" ) - ? plist.get( "description" ) - : pname; - return ParticleProperties{ - (pdgid_t)plist.get( "pdgid", 0 ), - pname, pdesc, - (short)plist.get( "colours", 1 ), - plist.get( "mass", -1. ), - plist.get( "width", -1. ), - (short)( plist.get( "charge", 0 )*3 ), - plist.get( "fermion", false ) - }; + ParticleProperties out; + try { + out = PDG::get()( plist.get( "pdgid", 0 ) ); + } catch ( const Exception& ) {} + bool modified = false; + if ( plist.has( "name" ) ) + out.name = plist.get( "name" ), modified = true; + if ( plist.has( "description" ) ) + out.description = plist.get( "description" ), modified = true; + if ( plist.has( "colours" ) ) + out.colours = plist.get( "colours" ), modified = true; + if ( plist.has( "mass" ) ) + out.mass = plist.get( "mass" ), modified = true; + if ( plist.has( "width" ) ) + out.width = plist.get( "width" ), modified = true; + if ( plist.has( "charge" ) ) + out.charge = short( plist.get( "charge" )*3 ), modified = true; + if ( plist.has( "fermion" ) ) + out.fermion = plist.get( "fermion" ), modified = true; + if ( modified ) + PDG::get().define( out ); + return out; } else if ( has( key ) ) return PDG::get()( get( key ) ); else { CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } } template<> ParametersList& ParametersList::set( std::string key, const ParticleProperties& value ) { return set( key, ParametersList() .set( "pdgid", value.pdgid ) .set( "name", value.name ) .set( "description", value.description ) .set( "colours", value.colours ) .set( "mass", value.mass ) .set( "width", value.width ) .set( "charge", value.charge*1./3 ) .set( "fermion", value.fermion ) ); } } diff --git a/CepGen/Core/Version.cpp b/CepGen/Core/Version.cpp index 868096f..432ea30 100644 --- a/CepGen/Core/Version.cpp +++ b/CepGen/Core/Version.cpp @@ -1,12 +1,12 @@ #include "CepGen/Version.h" #include "CepGen/Core/utils.h" namespace cepgen { const std::string version() { - return Form( "%02u.%02u.%02u", ( cepgen_version >> 16 ) & 0xff, - ( cepgen_version >> 8 ) & 0xff, - cepgen_version & 0xff ); + return Form( "%u.%u.%u", ( cepgen_version >> 16 ) & 0xff, + ( cepgen_version >> 8 ) & 0xff, + cepgen_version & 0xff ); } } diff --git a/CepGen/Core/utils.cpp b/CepGen/Core/utils.cpp index 1e1296c..a297fe0 100644 --- a/CepGen/Core/utils.cpp +++ b/CepGen/Core/utils.cpp @@ -1,41 +1,61 @@ #include "CepGen/Core/utils.h" #include #include // For va_start, etc. namespace cepgen { std::string Form( const std::string fmt, ... ) { int size = ( (int)fmt.size() ) * 2 + 50; std::string str; va_list ap; while ( true ) { //--- maximum two passes on a POSIX system... str.resize( size ); va_start( ap, fmt ); int n = vsnprintf( (char*)str.data(), size, fmt.c_str(), ap ); va_end( ap ); //--- check if everything worked if ( n > -1 && n < size ) { str.resize( n ); return str; } size = ( n > -1 ) ? n+1 : size*2; } return str; } size_t replace_all( std::string& str, const std::string& from, const std::string& to ) { size_t count = 0, pos = 0; while ( ( pos = str.find( from, pos ) ) != std::string::npos ) { str.replace( pos, from.length(), to ); pos += to.length(); ++count; } return count; } + + namespace utils + { + ProgressBar::ProgressBar( size_t tot, size_t freq ) : + bar_pattern_( BAR_LENGTH, '=' ), total_( tot ), frequency_( freq ) + {} + + void ProgressBar::update( size_t iter ) const + { + const size_t percent = iter*100./total_; + if ( percent % frequency_ == 0 || iter == total_ ) { + int lpad = int( percent/100. * BAR_LENGTH ); + int rpad = BAR_LENGTH-lpad; + fprintf( stderr, "\r%3zu%% [%.*s%*s]", percent, lpad, bar_pattern_.c_str(), rpad, "" ); + fflush( stderr ); + if ( iter == total_ ) + fprintf( stderr, "\n" ); + } + } + } } diff --git a/CepGen/Core/utils.h b/CepGen/Core/utils.h index e94fac1..13f287d 100644 --- a/CepGen/Core/utils.h +++ b/CepGen/Core/utils.h @@ -1,50 +1,61 @@ #ifndef CepGen_Core_utils_h #define CepGen_Core_utils_h #include #include #include namespace cepgen { /// Format a string using a printf style format descriptor. std::string Form( const std::string fmt, ... ); /// Human-readable boolean printout inline const char* yesno( const bool& test ) { return ( test ) ? "\033[32;1myes\033[0m" : "\033[31;1mno\033[0m"; } //inline const char* boldify( const char* str ) { const std::string out = std::string( "\033[33;1m" ) + std::string( str ) + std::string( "\033[0m" ); return out.c_str(); } /// Boldify a string for TTY-type output streams inline std::string boldify( const std::string& str ) { return Form( "\033[1m%s\033[0m", str.c_str() ); } /// Boldify a string for TTY-type output streams inline std::string boldify( const char* str ) { return boldify( std::string( str ) ); } /// Boldify a double floating point number for TTY-type output streams inline std::string boldify( const double& dbl ) { return boldify( Form("%.2f", dbl ) ); } /// Boldify an integer for TTY-type output streams inline std::string boldify( const int& i ) { return boldify( Form("% d", i ) ); } /// Boldify an unsigned integer for TTY-type output streams inline std::string boldify( const unsigned int& ui ) { return boldify( Form("%d", ui ) ); } /// Boldify an unsigned long integer for TTY-type output streams inline std::string boldify( const unsigned long& ui ) { return boldify( Form("%lu", ui ) ); } /// TTY-type enumeration of colours enum class Colour { gray = 30, red = 31, green = 32, yellow = 33, blue = 34, purple = 35 }; /// Colourise a string for TTY-type output streams inline std::string colourise( const std::string& str, const Colour& col ) { return Form( "\033[%d%s\033[0m", (int)col, str.c_str() ); } /// Replace all occurences of a text by another size_t replace_all( std::string& str, const std::string& from, const std::string& to ); namespace utils { /// Add a trailing "s" when needed inline const char* s( unsigned short num ) { return ( num > 1 ) ? "s" : ""; } /// Helper to print a vector template std::string repr( const std::vector& vec, const std::string& sep = "," ) { return std::accumulate( std::next( vec.begin() ), vec.end(), std::to_string( *vec.begin() ), [&sep]( std::string str, T xv ) { return std::move( str )+sep+std::to_string( xv ); } ); } + class ProgressBar + { + public: + ProgressBar( size_t tot, size_t freq = 10 ); + void update( size_t iter ) const; + + private: + static constexpr size_t BAR_LENGTH = 50; + const std::string bar_pattern_; + size_t total_, frequency_; + }; } } /// Provide a random number generated along a uniform distribution between 0 and 1 #define drand() (double)rand()/RAND_MAX #endif diff --git a/CepGen/Event/Event.cpp b/CepGen/Event/Event.cpp index 467d8b1..89c48e2 100644 --- a/CepGen/Event/Event.cpp +++ b/CepGen/Event/Event.cpp @@ -1,356 +1,356 @@ #include "CepGen/Event/Event.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/HeavyIon.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include #include namespace cepgen { Event::Event() : num_hadronisation_trials( 0 ), time_generation( -1. ), time_total( -1. ) {} Event::Event( const Event& rhs ) : num_hadronisation_trials( rhs.num_hadronisation_trials ), time_generation( rhs.time_generation ), time_total( rhs.time_total ), particles_( rhs.particles_ ), evtcontent_( rhs.evtcontent_ ) {} void Event::clear() { particles_.clear(); time_generation = -1.; time_total = -1.; } void Event::freeze() { //--- store a snapshot of the primordial event block if ( particles_.count( Particle::CentralSystem ) > 0 ) evtcontent_.cs = particles_[Particle::CentralSystem].size(); if ( particles_.count( Particle::OutgoingBeam1 ) > 0 ) evtcontent_.op1 = particles_[Particle::OutgoingBeam1].size(); if ( particles_.count( Particle::OutgoingBeam2 ) > 0 ) evtcontent_.op2 = particles_[Particle::OutgoingBeam2].size(); } void Event::restore() { //--- remove all particles after the primordial event block if ( particles_.count( Particle::CentralSystem ) > 0 ) particles_[Particle::CentralSystem].resize( evtcontent_.cs ); if ( particles_.count( Particle::OutgoingBeam1 ) > 0 ) particles_[Particle::OutgoingBeam1].resize( evtcontent_.op1 ); if ( particles_.count( Particle::OutgoingBeam2 ) > 0 ) particles_[Particle::OutgoingBeam2].resize( evtcontent_.op2 ); } double Event::cmEnergy() const { return CMEnergy( getOneByRole( Particle::IncomingBeam1 ), getOneByRole( Particle::IncomingBeam2 ) ); } Particles& Event::operator[]( Particle::Role role ) { //--- retrieve all particles with a given role return particles_[role]; } const Particles& Event::operator[]( Particle::Role role ) const { if ( particles_.count( role ) == 0 ) throw CG_FATAL( "Event" ) << "Failed to retrieve a particle with " << role << " role."; //--- retrieve all particles with a given role return particles_.at( role ); } ParticlesIds Event::ids( Particle::Role role ) const { ParticlesIds out; //--- retrieve all particles ids with a given role if ( particles_.count( role ) == 0 ) return out; for ( const auto& part : particles_.at( role ) ) out.insert( part.id() ); return out; } Particle& Event::getOneByRole( Particle::Role role ) { //--- retrieve the first particle of a given role Particles& parts_by_role = operator[]( role ); if ( parts_by_role.empty() ) throw CG_FATAL( "Event" ) << "No particle retrieved with " << role << " role."; if ( parts_by_role.size() > 1 ) throw CG_FATAL( "Event" ) << "More than one particle with " << role << " role: " << parts_by_role.size() << " particles."; return *parts_by_role.begin(); } const Particle& Event::getOneByRole( Particle::Role role ) const { //--- retrieve the first particle of a given role const Particles& parts_by_role = operator[]( role ); if ( parts_by_role.empty() ) throw CG_FATAL( "Event" ) << "No particle retrieved with " << role << " role."; if ( parts_by_role.size() > 1 ) throw CG_FATAL( "Event" ) << "More than one particle with " << role << " role: " << parts_by_role.size() << " particles"; return *parts_by_role.begin(); } Particle& Event::operator[]( int id ) { for ( auto& role_part : particles_ ) for ( auto& part : role_part.second ) if ( part.id() == id ) return part; throw CG_FATAL( "Event" ) << "Failed to retrieve the particle with id=" << id << "."; } const Particle& Event::operator[]( int id ) const { for ( const auto& role_part : particles_ ) for ( const auto& part : role_part.second ) if ( part.id() == id ) return part; throw CG_FATAL( "Event" ) << "Failed to retrieve the particle with id=" << id << "."; } Particles Event::getByIds( const ParticlesIds& ids ) const { Particles out; for ( const auto& id : ids ) out.emplace_back( operator[]( id ) ); return out; } Particles Event::mothers( const Particle& part ) const { return getByIds( part.mothers() ); } Particles Event::daughters( const Particle& part ) const { return getByIds( part.daughters() ); } ParticleRoles Event::roles() const { ParticleRoles out; for ( const auto& pr : particles_ ) out.emplace_back( pr.first ); return out; } Particle& Event::addParticle( Particle& part, bool replace ) { CG_DEBUG_LOOP( "Event" ) << "Particle with PDGid = " << part.integerPdgId() << " has role " << part.role(); if ( part.role() <= 0 ) throw CG_FATAL( "Event" ) << "Trying to add a particle with role=" << (int)part.role() << "."; //--- retrieve the list of particles with the same role Particles& part_with_same_role = operator[]( part.role() ); //--- specify the id - if ( part_with_same_role.empty() && part.id() < 0 ) part.setId( numParticles() ); // set the id if previously invalid/inexistent + if ( part_with_same_role.empty() && part.id() < 0 ) part.setId( size() ); // set the id if previously invalid/inexistent if ( !part_with_same_role.empty() ) { if ( replace ) part.setId( part_with_same_role[0].id() ); // set the previous id if replacing a particle - else part.setId( numParticles() ); + else part.setId( size() ); } //--- add the particle to the collection if ( replace ) part_with_same_role = Particles( 1, part ); // generate a vector containing only this particle else part_with_same_role.emplace_back( part ); return part_with_same_role.back(); } Particle& Event::addParticle( Particle::Role role, bool replace ) { Particle np( role, PDG::invalid ); return addParticle( np, replace ); } size_t - Event::numParticles() const + Event::size() const { size_t out = 0; for ( const auto& role_part : particles_ ) out += role_part.second.size(); return out; } const Particles Event::particles() const { Particles out; for ( const auto& role_part : particles_ ) out.insert( out.end(), role_part.second.begin(), role_part.second.end() ); std::sort( out.begin(), out.end() ); return out; } const Particles Event::stableParticles() const { Particles out; for ( const auto& role_part : particles_ ) for ( const auto& part : role_part.second ) if ( (short)part.status() > 0 ) out.emplace_back( part ); std::sort( out.begin(), out.end() ); return out; } void Event::checkKinematics() const { // check the kinematics through parentage for ( const auto& part : particles() ) { ParticlesIds daughters = part.daughters(); if ( daughters.empty() ) continue; Particle::Momentum ptot; for ( const auto& daugh : daughters ) { const Particle& d = operator[]( daugh ); const ParticlesIds mothers = d.mothers(); ptot += d.momentum(); if ( mothers.size() < 2 ) continue; for ( const auto& moth : mothers ) if ( moth != part.id() ) ptot -= operator[]( moth ).momentum(); } const double mass_diff = ( ptot-part.momentum() ).mass(); if ( fabs( mass_diff ) > MIN_PRECISION ) { dump(); throw CG_FATAL( "Event" ) << "Error in momentum balance for particle " << part.id() << ": mdiff = " << mass_diff << "."; } } } void Event::dump( bool stable ) const { const Particles parts = ( stable ) ? stableParticles() : particles(); std::ostringstream os; Particle::Momentum p_total; for ( const auto& part : parts ) { const ParticlesIds mothers = part.mothers(); { std::ostringstream oss_pdg; if ( part.pdgId() == PDG::invalid && !mothers.empty() ) { //--- if particles compound std::string delim; for ( unsigned short i = 0; i < mothers.size(); ++i ) try { oss_pdg << delim << PDG::get().name( operator[]( *std::next( mothers.begin(), i ) ).pdgId() ), delim = "/"; } catch ( const Exception& ) { oss_pdg << delim << operator[]( *std::next( mothers.begin(), i ) ).pdgId(), delim = "/"; } os << Form( "\n %2d\t\t %-7s", part.id(), oss_pdg.str().c_str() ); } else { //--- if single particle/HI if ( (HeavyIon)part.pdgId() ) oss_pdg << (HeavyIon)part.pdgId(); else try { oss_pdg << PDG::get().name( part.pdgId() ); } catch ( const Exception& ) { oss_pdg << "?"; } os << Form( "\n %2d\t%-+10d %-7s", part.id(), part.integerPdgId(), oss_pdg.str().c_str() ); } } os << "\t"; if ( part.charge() != (int)part.charge() ) { if ( part.charge()*2 == (int)( part.charge()*2 ) ) os << Form( "%-d/2", (int)( part.charge()*2 ) ); else if ( part.charge()*3 == (int)( part.charge()*3 ) ) os << Form( "%-d/3", (int)( part.charge()*3 ) ); else os << Form( "%-.2f", part.charge() ); } else os << Form( "%-g", part.charge() ); os << "\t"; { std::ostringstream oss; oss << part.role(); os << Form( "%-8s %6d\t", oss.str().c_str(), part.status() ); } if ( !mothers.empty() ) { std::ostringstream oss; unsigned short i = 0; for ( const auto& moth : mothers ) { oss << ( i > 0 ? "+" : "" ) << moth; ++i; } os << Form( "%6s ", oss.str().c_str() ); } else os << " "; const Particle::Momentum mom = part.momentum(); os << Form( "% 9.6e % 9.6e % 9.6e % 9.6e % 12.5f", mom.px(), mom.py(), mom.pz(), part.energy(), part.mass() ); // discard non-primary, decayed particles if ( part.status() >= Particle::Status::Undefined ) { const int sign = ( part.status() == Particle::Status::Undefined ) ? -1 : +1; p_total += sign*mom; } } //--- set a threshold to the computation precision p_total.truncate(); // CG_INFO( "Event" ) << Form( "Dump of event content:\n" " Id\tPDG id\t Name\t\tCharge\tRole\t Status\tMother\tpx py pz E \t M \n" " --\t------\t ----\t\t------\t----\t ------\t------\t----GeV/c--- ----GeV/c--- ----GeV/c--- ----GeV/c---\t --GeV/c²--" "%s\n" " ----------------------------------------------------------------------------------------------------------------------------------\n" "\t\t\t\t\t\t\tBalance% 9.6e % 9.6e % 9.6e % 9.6e", os.str().c_str(), p_total.px(), p_total.py(), p_total.pz(), p_total.energy() ); } //------------------------------------------------------------------------------------------------ Event::NumParticles::NumParticles() : cs( 0 ), op1( 0 ), op2( 0 ) {} Event::NumParticles::NumParticles( const NumParticles& np ) : cs( np.cs ), op1( np.op1 ), op2( np.op2 ) {} } diff --git a/CepGen/Event/Event.h b/CepGen/Event/Event.h index 6ba640c..47bcb2f 100644 --- a/CepGen/Event/Event.h +++ b/CepGen/Event/Event.h @@ -1,124 +1,124 @@ #ifndef CepGen_Event_Event_h #define CepGen_Event_Event_h #include "CepGen/Event/Particle.h" namespace cepgen { /** * Class containing all the information on the in- and outgoing particles' kinematics * \brief Kinematic information on the particles in the event */ class Event { public: /// Build an empty event Event(); /// Copy constructor Event( const Event& ); /// Empty the whole event content void clear(); /// Initialize an "empty" event collection void freeze(); /// Restore the event to its "empty" state void restore(); /// Dump all the known information on every Particle object contained in this Event container in the output stream /// \param[out] os Output stream where to dump the information /// \param[in] stable_ Do we only show the stable particles in this event? void dump( bool stable_ = false ) const; /// Incoming beams centre-of-mass energy, in GeV double cmEnergy() const; //----- particles adders /// \brief Set the information on one particle in the process /// \param[in] part The Particle object to insert or modify in the event /// \param[in] replace Do we replace the particle if already present in the event or do we append another particle with the same role ? Particle& addParticle( Particle& part, bool replace = false ); /// \brief Create a new particle in the event, with no kinematic information but the role it has to play in the process /// \param[in] role The role the particle will play in the process /// \param[in] replace Do we replace the particle if already present in the event or do we append another particle with the same role ? Particle& addParticle( Particle::Role role, bool replace = false ); //----- particles retrievers /// Number of particles in the event - size_t numParticles() const; + size_t size() const; /// Vector of all particles in the event const Particles particles() const; /// Vector of all stable particles in the event const Particles stableParticles() const; /** Get a list of Particle objects corresponding to a certain role in the process kinematics * \param[in] role The role the particles have to play in the process * \return A vector of references to the requested Particle objects */ Particles& operator[]( Particle::Role role ); /// Get a list of constant Particle objects corresponding to a certain role in the process kinematics const Particles& operator[]( Particle::Role role ) const; /// Get a list of particle identifiers in Event corresponding to a certain role in the process kinematics ParticlesIds ids( Particle::Role role ) const; /** \brief Get the first Particle object in the particles list whose role corresponds to the given argument * \param[in] role The role the particle has to play in the event * \return A Particle object corresponding to the first particle with the role */ Particle& getOneByRole( Particle::Role role ); const Particle& getOneByRole( Particle::Role role ) const; /** \brief Get the reference to the Particle object corresponding to a unique identifier in the event * \param[in] id The unique identifier to this particle in the event * \return A reference to the requested Particle object */ Particle& operator[]( int id ); /** \brief Get a const Particle object using its unique identifier * \param[in] id Unique identifier of the particle in the event * \return Constant object to be retrieved */ const Particle& operator[]( int id ) const; /** \brief Get references to the Particle objects corresponding to the unique identifiers in the event * \param[in] ids_ The unique identifiers to the particles to be selected in the event * \return A vector of references to the requested Particle objects */ Particles getByIds( const ParticlesIds& ids_ ) const; /** \brief Get the list of mother particles of any given Particle object in this event * \param[in] part The reference to the Particle object from which we want to extract the mother particles * \return A list of parenting Particle object */ //----- general particles information retriever Particles mothers( const Particle& part ) const; /// Get a vector containing all the daughters from a particle /// \param[in] part The particle for which the daughter particles have to be retrieved /// \return Vector of Particle objects containing all the daughters' kinematic information Particles daughters( const Particle& part ) const; /// Get a list of roles for the given event (really process-dependant for the central system) /// \return Vector of integers corresponding to all the roles the particles can play in the event ParticleRoles roles() const; /// Number of trials before the event was "correctly" hadronised unsigned short num_hadronisation_trials; /// Time needed to generate the event at parton level (in seconds) float time_generation; /// Time needed to generate the hadronised (if needed) event (in seconds) float time_total; private: static constexpr double MIN_PRECISION = 1.e-10; /// Check if the event kinematics is properly defined void checkKinematics() const; /// List of particles in the event, mapped to their role in the process ParticlesMap particles_; /// Typical event indices structure struct NumParticles { NumParticles(); NumParticles( const NumParticles& np ); unsigned short cs; ///< Index of the first central system particle unsigned short op1; ///< Index of the first positive-z outgoing beam state unsigned short op2; ///< Index of the first negative-z outgoing beam state }; /// Event indices structure NumParticles evtcontent_; }; } #endif diff --git a/CepGen/Hadronisers/GenericHadroniser.cpp b/CepGen/Hadronisers/GenericHadroniser.cpp index 4ea2614..aa2a160 100644 --- a/CepGen/Hadronisers/GenericHadroniser.cpp +++ b/CepGen/Hadronisers/GenericHadroniser.cpp @@ -1,53 +1,54 @@ #include "CepGen/Hadronisers/GenericHadroniser.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/ParametersList.h" namespace cepgen { namespace hadr { GenericHadroniser::GenericHadroniser( const ParametersList& plist, const std::string& name ) : name_( name ), seed_ ( plist.get( "seed", -1ll ) ), - max_trials_( plist.get( "maxTrials", 1 ) ) + max_trials_( plist.get( "maxTrials", 1 ) ), + remn_fragm_( plist.get( "remnantsFragmentation", true ) ) { CG_DEBUG( "Hadroniser:init" ) << "\"" << name_ << "\"-type hadroniser built with:\n\t" << "* seed = " << seed_ << "\n\t" << "* maximum trials: " << max_trials_; } void GenericHadroniser::readStrings( const std::vector& params ) { if ( params.empty() ) return; std::ostringstream os; for ( const auto& p : params ) { readString( p ); os << "\n\t '" << p << "'"; } CG_DEBUG( "Hadroniser:configure" ) << "Feeding \"" << name_ << "\" hadroniser with:" << os.str(); } std::string GenericHadroniser::name() const { return name_; } } std::ostream& operator<<( std::ostream& os, const hadr::GenericHadroniser& hadr ) { return os << hadr.name(); } std::ostream& operator<<( std::ostream& os, const hadr::GenericHadroniser* hadr ) { return os << hadr->name(); } } diff --git a/CepGen/Hadronisers/GenericHadroniser.h b/CepGen/Hadronisers/GenericHadroniser.h index bdc4416..82d7ed3 100644 --- a/CepGen/Hadronisers/GenericHadroniser.h +++ b/CepGen/Hadronisers/GenericHadroniser.h @@ -1,72 +1,76 @@ #ifndef CepGen_Hadronisers_GenericHadroniser_h #define CepGen_Hadronisers_GenericHadroniser_h #include #include #include namespace cepgen { class Event; class Particle; class Parameters; class ParametersList; /// Location for all hadronisers to be run downstream to the events generation namespace hadr { /** * \brief Class template to define any hadroniser as a general object with defined methods * \author Laurent Forthomme * \date January 2014 */ class GenericHadroniser { public: /// Write out all hadroniser attributes in output stream friend std::ostream& operator<<( std::ostream& os, const GenericHadroniser& hadr ); /// Write out all hadroniser attributes in output stream friend std::ostream& operator<<( std::ostream& os, const GenericHadroniser* hadr ); /// Default constructor for an undefined hadroniser explicit GenericHadroniser( const ParametersList&, const std::string& name = "" ); virtual ~GenericHadroniser() {} /// Parse a configuration string virtual void readString( const char* ) {} /// Parse a configuration string virtual void readString( const std::string& param ) { readString( param.c_str() ); } /// Parse a list of configuration strings virtual void readStrings( const std::vector& params ); /// Initialise the event hadroniser before its running virtual void init() = 0; /** \brief Hadronise a full event * \param[inout] ev Event to hadronise * \param[inout] weight Event weight after hadronisation * \param[in] full Perform the full state hadronisation (incl. remnants fragmentation) * \return Boolean stating whether or not the hadronisation occured successfully */ virtual bool run( Event& ev, double& weight, bool full ) = 0; /// Specify the process cross section, in pb virtual void setCrossSection( double xsec, double xsec_err ) {} virtual void setParameters( const Parameters& params ) { params_ = ¶ms; } /// \brief Specify a random numbers generator seed for the hadroniser /// \param[in] seed A RNG seed void setSeed( long long seed ) { seed_ = seed; } + /// Specify whether the beam remnants are to be fragmented + bool fragmentRemnants() const { return remn_fragm_; } /// Return a human-readable name for this hadroniser std::string name() const; protected: /// Name of the hadroniser std::string name_; /// Random numbers generator seed for the hadroniser long long seed_; /// Maximal number of trials for the hadronisation of the proton(s) remnants unsigned short max_trials_; const Parameters* params_; // not owning + /// Switch on/off the remnants fragmentation where applicable + const bool remn_fragm_; }; } } #endif diff --git a/CepGen/Hadronisers/Pythia6Hadroniser.cpp b/CepGen/Hadronisers/Pythia6Hadroniser.cpp index 5cf52e8..a6f1111 100644 --- a/CepGen/Hadronisers/Pythia6Hadroniser.cpp +++ b/CepGen/Hadronisers/Pythia6Hadroniser.cpp @@ -1,333 +1,337 @@ #include "CepGen/Hadronisers/GenericHadroniser.h" #include "CepGen/Hadronisers/HadronisersHandler.h" #include "CepGen/Event/Event.h" #include "CepGen/Event/Particle.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/ParametersList.h" //FIXME #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include extern "C" { /// Get the particle's mass in GeV from Pythia extern double pymass_( int& ); /// Launch the Pythia6 fragmentation extern void pyexec_(); /// Set a parameter value to the Pythia module extern void pygive_( const char*, int ); extern void pyckbd_(); /// List all the particles in the event in a human-readable format extern void pylist_( int& ); /// Join two coloured particles in a colour singlet extern void pyjoin_( int&, int& ); /// Get a particle's human-readable name from Pythia extern void pyname_( int&, char*, int ); /// Get integer-valued event information from Pythia extern int pyk_( int&, int& ); /// Get real-valued event information from Pythia extern double pyp_( int&, int& ); /// Purely virtual method to call at the end of the run void pystop_() { CG_INFO( "Pythia6Hadroniser" ) << "End of run"; } /// Particles content of the event extern struct { /// Number of particles in the event int n; int npad; /// Particles' general information (status, PDG id, mother, daughter 1, daughter 2) int k[5][4000]; /// Particles' kinematics, in GeV (px, py, pz, E, M) double p[5][4000]; /// Primary vertex for the particles double v[5][4000]; } pyjets_; } namespace cepgen { namespace hadr { /** * Full interface to the Pythia 6 algorithm. It can be used in a single particle decay mode as well as a full event hadronisation using the string model, as in Jetset. * \brief Pythia 6 hadronisation algorithm */ class Pythia6Hadroniser : public GenericHadroniser { public: - Pythia6Hadroniser( const ParametersList& ); + explicit Pythia6Hadroniser( const ParametersList& ); void setParameters( const Parameters& ) override {} inline void readString( const char* param ) override { pygive( param ); } - void init() override {} + void init() override; bool run( Event& ev, double& weight, bool full ) override; void setCrossSection( double xsec, double xsec_err ) override {} private: static constexpr unsigned short MAX_PART_STRING = 3; static constexpr unsigned short MAX_STRING_EVENT = 2; /// Maximal number of characters to fetch for the particle's name static constexpr unsigned short NAME_CHR = 16; static const std::unordered_map kStatusMatchMap; inline static double pymass(int pdgid_) { return pymass_(pdgid_); } inline static void pyckbd() { pyckbd_(); } inline static void pygive( const std::string& line ) { pygive_( line.c_str(), line.length() ); } inline static void pylist( int mlist ) { pylist_( mlist ); } inline static int pyk( int id, int qty ) { return pyk_( id, qty ); } inline static double pyp( int id, int qty ) { return pyp_( id, qty ); } inline static std::string pyname( int pdgid ) { char out[NAME_CHR]; std::string s; pyname_( pdgid, out, NAME_CHR ); s = std::string( out, NAME_CHR ); s.erase( remove( s.begin(), s.end(), ' ' ), s.end() ); return s; } /// Connect entries with colour flow information /// \param[in] njoin Number of particles to join in the colour flow /// \param[in] ijoin List of particles unique identifier to join in the colour flow inline static void pyjoin( int njoin, int ijoin[2] ) { return pyjoin_( njoin, *ijoin ); } bool prepareHadronisation( Event& ); std::pair pickPartonsContent() const; unsigned int fillParticles( const Event& ) const; }; Pythia6Hadroniser::Pythia6Hadroniser( const ParametersList& plist ) : GenericHadroniser( plist, "pythia6" ) {} const std::unordered_map Pythia6Hadroniser::kStatusMatchMap = { { Particle::Status::PrimordialIncoming, 21 }, { Particle::Status::FinalState, 1 }, { Particle::Status::Unfragmented, 3 }, { Particle::Status::Undecayed, 1 }, { Particle::Status::Fragmented, 11 }, { Particle::Status::Propagator, 11 }, { Particle::Status::Incoming, 11 }, }; + void + Pythia6Hadroniser::init() + { + CG_WARNING( "Pythia6Hadroniser" ) + << "Branching fraction not yet implemented in this hadroniser.\n\t" + << "You will have to specify manually the multiplication factor according\n\t" + << "to your list of open channels."; + } + bool Pythia6Hadroniser::run( Event& ev, double& weight, bool full ) { weight = 1.; - if ( full ) + //--- only prepare remnants for fragmentation in full (event builder) mode + if ( full && remn_fragm_ ) prepareHadronisation( ev ); - if ( CG_LOG_MATCH( "Pythia6Hadroniser", debug ) ) { + if ( CG_LOG_MATCH( "Pythia6Hadroniser:dump", debug ) ) { CG_DEBUG( "Pythia6Hadroniser" ) << "Dump of the event before the hadronisation:"; ev.dump(); } //--- fill Pythia 6 common blocks const unsigned short str_in_evt = fillParticles( ev ); - if ( CG_LOG_MATCH( "Pythia6Hadroniser", debug ) ) { - CG_DEBUG( "Pythia6Hadroniser" ) - << "Passed the string construction stage.\n\t" - << str_in_evt << " string object" << utils::s( str_in_evt ) - << " identified and constructed."; - ev.dump(); - } + CG_DEBUG( "Pythia6Hadroniser" ) + << "Passed the string construction stage.\n\t" + << str_in_evt << " string object" << utils::s( str_in_evt ) + << " identified and constructed."; - const int oldnpart = pyjets_.n; + const int old_npart = pyjets_.n; //--- run the algorithm pyexec_(); - if ( full && pyjets_.n == oldnpart ) + if ( full && pyjets_.n == old_npart ) return false; // hadronisation failed //--- update the event - for ( int p = oldnpart; p < pyjets_.n; ++p ) { + for ( int p = old_npart; p < pyjets_.n; ++p ) { // filter the first particles already present in the event const pdgid_t pdg_id = abs( pyjets_.k[1][p] ); - const short charge = pyjets_.k[1][p]/(short)pdg_id; ParticleProperties prop; if ( full ) try { prop = PDG::get()( pdg_id ); } catch ( const Exception& ) { prop = ParticleProperties{ pdg_id, pyname( pdg_id ), pyname( pdg_id ), (short)pyk( p+1, 12 ), // colour factor pymass( pdg_id ), -1., //pmas( pdg_id, 2 ), (short)pyk( p+1, 6 ), // charge false }; PDG::get().define( prop ); } const unsigned short moth_id = pyjets_.k[2][p]-1; const Particle::Role role = pyjets_.k[2][p] != 0 ? ev[moth_id].role() // child particle inherits its mother's role : Particle::Role::UnknownRole; auto& pa = ev.addParticle( role ); pa.setId( p ); - pa.setPdgId( pdg_id, charge ); + pa.setPdgId( (short)pyjets_.k[1][p] ); int status = pyjets_.k[0][p]; if ( status == 11 || status == 14 ) status = -3; pa.setStatus( (Particle::Status)status ); pa.setMomentum( Particle::Momentum( pyjets_.p[0][p], pyjets_.p[1][p], pyjets_.p[2][p], pyjets_.p[3][p] ) ); pa.setMass( pyjets_.p[4][p] ); if ( role != Particle::Role::UnknownRole ) { auto& moth = ev[moth_id]; moth.setStatus( role == Particle::Role::CentralSystem ? Particle::Status::Resonance : Particle::Status::Fragmented ); pa.addMother( moth ); } } return true; } bool Pythia6Hadroniser::prepareHadronisation( Event& ev ) { CG_DEBUG( "Pythia6Hadroniser" ) << "Hadronisation preparation called."; for ( const auto& part : ev.particles() ) { if ( part.status() != Particle::Status::Unfragmented ) continue; //--- only loop over all protons to be fragmented const auto partons = pickPartonsContent(); const double mx2 = part.mass2(); const double mq = pymass( partons.first ), mq2 = mq*mq; const double mdq = pymass( partons.second ), mdq2 = mdq*mdq; //--- choose random direction in MX frame const double phi = 2.*M_PI*drand(), theta = acos( 2.*drand()-1. ); // theta angle //--- compute momentum of decay particles from MX const double px = std::sqrt( 0.25*std::pow( mx2-mdq2+mq2, 2 )/mx2-mq2 ); //--- build 4-vectors and boost decay particles auto pdq = Particle::Momentum::fromPThetaPhi( px, theta, phi, std::hypot( px, mdq ) ); auto pq = -pdq; pq.setEnergy( std::hypot( px, mq ) ); //--- singlet auto& quark = ev.addParticle( part.role() ); quark.addMother( ev[part.id()] ); quark.setPdgId( partons.first, +1 ); quark.setStatus( Particle::Status::Unfragmented ); quark.setMomentum( pq.lorentzBoost( part.momentum() ) ); //--- doublet auto& diquark = ev.addParticle( part.role() ); diquark.addMother( ev[part.id()] ); diquark.setPdgId( partons.second, +1 ); diquark.setStatus( Particle::Status::Unfragmented ); diquark.setMomentum( pdq.lorentzBoost( part.momentum() ) ); ev[part.id()].setStatus( Particle::Status::Fragmented ); } return true; } unsigned int Pythia6Hadroniser::fillParticles( const Event& ev ) const { - pyjets_.n = 0; - //--- initialising the string fragmentation variables unsigned int str_in_evt = 0; unsigned int num_part_in_str[MAX_STRING_EVENT] = { 0 }; int jlpsf[MAX_STRING_EVENT][MAX_PART_STRING] = { 0 }; + pyjets_.n = 0; // reinitialise the event content + for ( const auto& role : ev.roles() ) { // loop on roles unsigned int part_in_str = 0; bool role_has_string = false; for ( const auto& part : ev[role] ) { - unsigned int np = part.id(); - - pyjets_.p[0][np] = part.momentum().px(); - pyjets_.p[1][np] = part.momentum().py(); - pyjets_.p[2][np] = part.momentum().pz(); - pyjets_.p[3][np] = part.energy(); - pyjets_.p[4][np] = part.mass(); + const unsigned short i = part.id(); + pyjets_.p[0][i] = part.momentum().px(); + pyjets_.p[1][i] = part.momentum().py(); + pyjets_.p[2][i] = part.momentum().pz(); + pyjets_.p[3][i] = part.energy(); + pyjets_.p[4][i] = part.mass(); try { - pyjets_.k[0][np] = kStatusMatchMap.at( part.status() ); + pyjets_.k[0][i] = kStatusMatchMap.at( part.status() ); } catch ( const std::out_of_range& ) { ev.dump(); throw CG_FATAL( "Pythia6Hadroniser" ) << "Failed to retrieve a Pythia 6 particle status translation for " << "CepGen status " << (int)part.status() << "!"; } - pyjets_.k[1][np] = part.integerPdgId(); + pyjets_.k[1][i] = part.integerPdgId(); const auto& moth = part.mothers(); - pyjets_.k[2][np] = moth.empty() + pyjets_.k[2][i] = moth.empty() ? 0 // no mother : *moth.begin()+1; // mother const auto& daug = part.daughters(); - if ( daug.empty() ) - pyjets_.k[3][np] = pyjets_.k[4][np] = 0; // no daughters + if ( daug.empty() ) // no daughters + pyjets_.k[3][i] = pyjets_.k[4][i] = 0; else { - pyjets_.k[3][np] = *daug.begin()+1; // daughter 1 - pyjets_.k[4][np] = *daug.rbegin()+1; // daughter 2 + pyjets_.k[3][i] = *daug.begin()+1; // daughter 1 + pyjets_.k[4][i] = *daug.rbegin()+1; // daughter 2 } - for ( int i = 0; i < 5; ++i ) - pyjets_.v[i][np] = 0.; // vertex position + for ( int j = 0; j < 5; ++j ) + pyjets_.v[j][i] = 0.; // vertex position if ( part.status() == Particle::Status::Unfragmented ) { - pyjets_.k[0][np] = 1; // PYTHIA/JETSET workaround + pyjets_.k[0][i] = 1; // PYTHIA/JETSET workaround jlpsf[str_in_evt][part_in_str++] = part.id()+1; num_part_in_str[str_in_evt]++; role_has_string = true; } else if ( part.status() == Particle::Status::Undecayed ) - pyjets_.k[0][np] = 2; // intermediate resonance + pyjets_.k[0][i] = 2; // intermediate resonance pyjets_.n++; } //--- at most one string per role if ( role_has_string ) str_in_evt++; } //--- loop over the strings to bind everything together for ( unsigned short i = 0; i < str_in_evt; ++i ) { if ( num_part_in_str[i] < 2 ) continue; if ( CG_LOG_MATCH( "Pythia6Hadroniser", debug ) ) { std::ostringstream dbg; for ( unsigned short j = 0; j < num_part_in_str[i]; ++j ) if ( jlpsf[i][j] != -1 ) dbg << Form( "\n\t * %2d (pdgId=%4d)", jlpsf[i][j], pyjets_.k[1][jlpsf[i][j]-1] ); CG_DEBUG( "Pythia6Hadroniser" ) << "Joining " << num_part_in_str[i] << " particle" << utils::s( num_part_in_str[i] ) << " with " << ev[jlpsf[i][0]].role() << " role" << " in a same string (id=" << i << ")" << dbg.str(); } pyjoin( num_part_in_str[i], jlpsf[i] ); } return str_in_evt; } std::pair Pythia6Hadroniser::pickPartonsContent() const { const double ranudq = drand(); if ( ranudq < 1./9. ) return { PDG::down, 2203 }; // (d,uu1) if ( ranudq < 5./9. ) return { PDG::up, 2101 }; // (u,ud0) return { PDG::up, 2103 }; // (u,ud1) } - } } // register hadroniser and define alias REGISTER_HADRONISER( pythia6, Pythia6Hadroniser ) diff --git a/CepGen/Hadronisers/Pythia8Hadroniser.cpp b/CepGen/Hadronisers/Pythia8Hadroniser.cpp index 47eb001..ac17279 100644 --- a/CepGen/Hadronisers/Pythia8Hadroniser.cpp +++ b/CepGen/Hadronisers/Pythia8Hadroniser.cpp @@ -1,291 +1,359 @@ -#include "CepGen/Hadronisers/Pythia8Hadroniser.h" -#include "CepGen/Hadronisers/PythiaEventInterface.h" +#include "CepGen/Hadronisers/GenericHadroniser.h" #include "CepGen/Hadronisers/HadronisersHandler.h" +#include "CepGen/IO/PythiaEventInterface.h" + #include "CepGen/Parameters.h" #include "CepGen/Physics/Kinematics.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include "CepGen/Event/Event.h" #include "CepGen/Event/Particle.h" -#include "CepGen/Version.h" +#include + +#include +#include +#include namespace cepgen { namespace hadr { + /** + * Full interface to the Pythia8 hadronisation algorithm. It can be used in a single particle decay mode as well as a full event hadronisation using the string model, as in Jetset. + * \brief Pythia8 hadronisation algorithm + */ + class Pythia8Hadroniser : public GenericHadroniser + { + public: + explicit Pythia8Hadroniser( const ParametersList& ); + ~Pythia8Hadroniser(); + + void setParameters( const Parameters& ) override; + void readString( const char* param ) override; + void init() override; + bool run( Event& ev, double& weight, bool full ) override; + + void setCrossSection( double xsec, double xsec_err ) override; + + private: + static constexpr unsigned short PYTHIA_STATUS_IN_BEAM = 12; + static constexpr unsigned short PYTHIA_STATUS_IN_PARTON_KT = 61; + + std::vector min_ids_; + std::unordered_map py_cg_corresp_; + unsigned short findRole( const Event& ev, const Pythia8::Particle& p ) const; + void updateEvent( Event& ev, double& weight ) const; + Particle& addParticle( Event& ev, const Pythia8::Particle&, const Pythia8::Vec4& mom, unsigned short ) const; + /// A Pythia8 core to be wrapped + std::unique_ptr pythia_; + std::unique_ptr cg_evt_; + const bool correct_central_; + const bool debug_lhef_; + bool res_decay_; + bool enable_hadr_; + unsigned short offset_; + bool first_evt_; + }; + Pythia8Hadroniser::Pythia8Hadroniser( const ParametersList& plist ) : GenericHadroniser( plist, "pythia8" ), pythia_( new Pythia8::Pythia ), cg_evt_( new Pythia8::CepGenEvent ), correct_central_( plist.get( "correctCentralSystem", false ) ), - enable_hadr_( false ), offset_( 0 ), first_evt_( true ) + debug_lhef_( plist.get( "debugLHEF", false ) ), + res_decay_( true ), enable_hadr_( false ), + offset_( 0 ), first_evt_( true ) {} void Pythia8Hadroniser::setParameters( const Parameters& params ) { params_ = ¶ms; cg_evt_->initialise( params ); pythia_->setLHAupPtr( (Pythia8::LHAup*)cg_evt_.get() ); pythia_->settings.parm( "Beams:idA", (short)params_->kinematics.incoming_beams.first.pdg ); pythia_->settings.parm( "Beams:idB", (short)params_->kinematics.incoming_beams.second.pdg ); // specify we will be using a LHA input pythia_->settings.mode( "Beams:frameType", 5 ); pythia_->settings.parm( "Beams:eCM", params_->kinematics.sqrtS() ); - for ( const auto& pdgid : params_->kinematics.minimum_final_state ) - min_ids_.emplace_back( (unsigned short)pdgid ); + min_ids_ = params_->kinematics.minimum_final_state; + if ( debug_lhef_ ) + cg_evt_->openLHEF( "debug.lhe" ); } Pythia8Hadroniser::~Pythia8Hadroniser() { pythia_->settings.writeFile( "last_pythia_config.cmd", false ); + if ( debug_lhef_ ) + cg_evt_->closeLHEF( true ); } void Pythia8Hadroniser::readString( const char* param ) { if ( !pythia_->readString( param ) ) throw CG_FATAL( "Pythia8Hadroniser" ) << "The Pythia8 core failed to parse the following setting:\n\t" << param; } void Pythia8Hadroniser::init() { + pythia_->settings.flag( "ProcessLevel:resonanceDecays", res_decay_ ); if ( pythia_->settings.flag( "ProcessLevel:all" ) != enable_hadr_ ) pythia_->settings.flag( "ProcessLevel:all", enable_hadr_ ); if ( seed_ == -1ll ) pythia_->settings.flag( "Random:setSeed", false ); else { pythia_->settings.flag( "Random:setSeed", true ); pythia_->settings.mode( "Random:seed", seed_ ); } #if defined( PYTHIA_VERSION_INTEGER ) && PYTHIA_VERSION_INTEGER >= 8226 switch ( params_->kinematics.mode ) { case KinematicsMode::ElasticElastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 3 ); pythia_->settings.flag( "PartonLevel:all", false ); } break; case KinematicsMode::InelasticElastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 2 ); } break; case KinematicsMode::ElasticInelastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 1 ); } break; case KinematicsMode::InelasticInelastic: default: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 0 ); } break; } #else CG_WARNING( "Pythia8Hadroniser" ) << "Beam remnants framework for this version of Pythia " << "(" << Form( "%.3f", PYTHIA_VERSION ) << ")\n\t" << "does not support mixing of unresolved hadron states.\n\t" << "The proton remnants output might hence be wrong.\n\t" << "Please update the Pythia version or disable this part."; #endif - if ( correct_central_ && pythia_->settings.flag( "ProcessLevel:resonanceDecays" ) ) + if ( correct_central_ && res_decay_ ) CG_WARNING( "Pythia8Hadroniser" ) << "Central system's kinematics correction enabled while resonances are\n\t" << "expected to be decayed. Please check that this is fully intended."; if ( !pythia_->init() ) throw CG_FATAL( "Pythia8Hadroniser" ) << "Failed to initialise the Pythia8 core!\n\t" << "See the message above for more details."; + + if ( debug_lhef_ ) + cg_evt_->initLHEF(); } void Pythia8Hadroniser::setCrossSection( double xsec, double xsec_err ) { cg_evt_->setCrossSection( 0, xsec, xsec_err ); } bool Pythia8Hadroniser::run( Event& ev, double& weight, bool full ) { //--- initialise the event weight before running any decay algorithm weight = 1.; //--- only launch Pythia if: - // 1) the full event kinematics (i.e. with remnants) is to be specified, or - // 2) the resonances are to be decayed. - if ( !full && !pythia_->settings.flag( "ProcessLevel:resonanceDecays" ) ) + // 1) the full event kinematics (i.e. with remnants) is to be specified, + // 2) the remnants are to be fragmented, or + // 3) the resonances are to be decayed. + if ( full && !remn_fragm_ && !res_decay_ ) + return true; + if ( !full && !res_decay_ ) return true; //--- switch full <-> partial event if ( full != enable_hadr_ ) { enable_hadr_ = full; init(); } //=========================================================================================== // convert our event into a custom LHA format //=========================================================================================== cg_evt_->feedEvent( ev, full ? Pythia8::CepGenEvent::Type::centralAndBeamRemnants : Pythia8::CepGenEvent::Type::centralAndPartons ); //if ( full ) cg_evt_->listEvent(); + if ( debug_lhef_ && full ) + cg_evt_->eventLHEF(); //=========================================================================================== // launch the hadronisation / resonances decays, and update the event accordingly //=========================================================================================== ev.num_hadronisation_trials = 0; while ( true ) { if ( ev.num_hadronisation_trials++ > max_trials_ ) return false; //--- run the hadronisation/fragmentation algorithm if ( pythia_->next() ) { //--- hadronisation successful if ( first_evt_ && full ) { offset_ = 0; for ( unsigned short i = 1; i < pythia_->event.size(); ++i ) if ( pythia_->event[i].status() == -PYTHIA_STATUS_IN_BEAM ) //--- no incoming particles in further stages offset_++; first_evt_ = false; } break; } } CG_DEBUG( "Pythia8Hadroniser" ) << "Pythia8 hadronisation performed successfully.\n\t" << "Number of trials: " << ev.num_hadronisation_trials << "/" << max_trials_ << ".\n\t" << "Particles multiplicity: " << ev.particles().size() << " → " << pythia_->event.size() << ".\n\t" << " indices offset: " << offset_ << "."; //=========================================================================================== // update the event content with Pythia's output //=========================================================================================== updateEvent( ev, weight ); return true; } Particle& Pythia8Hadroniser::addParticle( Event& ev, const Pythia8::Particle& py_part, const Pythia8::Vec4& mom, unsigned short role ) const { Particle& op = ev.addParticle( (Particle::Role)role ); - op.setPdgId( (pdgid_t)abs( py_part.id() ), (short)( py_part.charge()/fabs( py_part.charge() ) ) ); + ParticleProperties prop; + const pdgid_t pdg_id = abs( py_part.id() ); + try { prop = PDG::get()( pdg_id ); } catch ( const Exception& ) { + prop = ParticleProperties{ pdg_id, + py_part.name(), py_part.name(), + (short)py_part.col(), // colour factor + py_part.m0(), py_part.mWidth(), + (short)py_part.charge(), // charge + py_part.isLepton() + }; + PDG::get().define( prop ); + } + op.setPdgId( (short)py_part.id() ); op.setStatus( py_part.isFinal() ? Particle::Status::FinalState : (Particle::Role)role == Particle::Role::CentralSystem ? Particle::Status::Propagator : Particle::Status::Fragmented ); op.setMomentum( Particle::Momentum( mom.px(), mom.py(), mom.pz(), mom.e() ) ); op.setMass( mom.mCalc() ); cg_evt_->addCorresp( py_part.index()-offset_, op.id() ); return op; } void Pythia8Hadroniser::updateEvent( Event& ev, double& weight ) const { std::vector central_parts; for ( unsigned short i = 1+offset_; i < pythia_->event.size(); ++i ) { const Pythia8::Particle& p = pythia_->event[i]; const unsigned short cg_id = cg_evt_->cepgenId( i-offset_ ); if ( cg_id != Pythia8::CepGenEvent::INVALID_ID ) { //----- particle already in the event Particle& cg_part = ev[cg_id]; //--- fragmentation result if ( cg_part.role() == Particle::OutgoingBeam1 || cg_part.role() == Particle::OutgoingBeam2 ) { cg_part.setStatus( Particle::Status::Fragmented ); continue; } //--- resonance decayed; apply branching ratio for this decay if ( cg_part.role() == Particle::CentralSystem && p.status() < 0 ) { - if ( pythia_->settings.flag( "ProcessLevel:resonanceDecays" ) ) + if ( res_decay_ ) weight *= p.particleDataEntry().pickChannel().bRatio(); cg_part.setStatus( Particle::Status::Resonance ); central_parts.emplace_back( i ); } //--- particle is not what we expect if ( p.idAbs() != abs( cg_part.integerPdgId() ) ) { CG_INFO( "Pythia8Hadroniser:update" ) << "LHAEVT event content:"; cg_evt_->listEvent(); CG_INFO( "Pythia8Hadroniser:update" ) << "Pythia event content:"; pythia_->event.list(); CG_INFO( "Pythia8Hadroniser:update" ) << "CepGen event content:"; ev.dump(); CG_INFO( "Pythia8Hadroniser:update" ) << "Correspondence:"; cg_evt_->dumpCorresp(); throw CG_FATAL( "Pythia8Hadroniser:update" ) << "Event list corruption detected for (Pythia/CepGen) particle " << i << "/" << cg_id << ":\n\t" << "should be " << abs( p.id() ) << ", " << "got " << cg_part.integerPdgId() << "!"; } } - //--- FIXME check for messed up particles parentage and discard incoming beam particles + //--- check for messed up particles parentage and discard incoming beam particles /*else if ( p.mother1() > i || p.mother1() <= offset_ ) continue; else if ( p.mother2() > i || p.mother2() <= offset_ ) continue;*/ else { //----- new particle to be added const unsigned short role = findRole( ev, p ); switch ( (Particle::Role)role ) { case Particle::OutgoingBeam1: ev[Particle::OutgoingBeam1][0].setStatus( Particle::Status::Fragmented ); break; case Particle::OutgoingBeam2: ev[Particle::OutgoingBeam2][0].setStatus( Particle::Status::Fragmented ); break; default: break; } // found the role ; now we can add the particle Particle& cg_part = addParticle( ev, p, p.p(), role ); if ( correct_central_ && (Particle::Role)role == Particle::CentralSystem ) { const auto& ip = std::find( central_parts.begin(), central_parts.end(), p.mother1() ); if ( ip != central_parts.end() ) cg_part.setMomentum( ev[cg_evt_->cepgenId( *ip-offset_ )].momentum() ); } for ( const auto& moth_id : p.motherList() ) { if ( moth_id <= offset_ ) continue; const unsigned short moth_cg_id = cg_evt_->cepgenId( moth_id-offset_ ); if ( moth_cg_id != Pythia8::CepGenEvent::INVALID_ID ) cg_part.addMother( ev[moth_cg_id] ); else cg_part.addMother( addParticle( ev, pythia_->event[moth_id], p.p(), role ) ); if ( !p.isFinal() ) { if ( p.isResonance() || !p.daughterList().empty() ) cg_part.setStatus( Particle::Status::Resonance ); else cg_part.setStatus( Particle::Status::Undefined ); } } } } } unsigned short Pythia8Hadroniser::findRole( const Event& ev, const Pythia8::Particle& p ) const { for ( const auto& par_id : p.motherList() ) { if ( par_id == 1 && offset_ > 0 ) return (unsigned short)Particle::OutgoingBeam1; if ( par_id == 2 && offset_ > 0 ) return (unsigned short)Particle::OutgoingBeam2; const unsigned short par_cg_id = cg_evt_->cepgenId( par_id-offset_ ); if ( par_cg_id != Pythia8::CepGenEvent::INVALID_ID ) return (unsigned short)ev[par_cg_id].role(); return findRole( ev, pythia_->event[par_id] ); } return (unsigned short)Particle::UnknownRole; } } } // register hadroniser and define alias REGISTER_HADRONISER( pythia8, Pythia8Hadroniser ) diff --git a/CepGen/Hadronisers/Pythia8Hadroniser.h b/CepGen/Hadronisers/Pythia8Hadroniser.h deleted file mode 100644 index 70c151d..0000000 --- a/CepGen/Hadronisers/Pythia8Hadroniser.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef CepGen_Hadronisers_Pythia8Hadroniser_h -#define CepGen_Hadronisers_Pythia8Hadroniser_h - -#include "CepGen/Hadronisers/GenericHadroniser.h" - -#include - -#include -#include -#include - -namespace Pythia8 { class CepGenEvent; } -namespace cepgen -{ - class Particle; - class Parameters; - class ParametersList; - enum class KinematicsMode; - - namespace hadr - { - /** - * Full interface to the Pythia8 hadronisation algorithm. It can be used in a single particle decay mode as well as a full event hadronisation using the string model, as in Jetset. - * \brief Pythia8 hadronisation algorithm - */ - class Pythia8Hadroniser : public GenericHadroniser - { - public: - explicit Pythia8Hadroniser( const ParametersList& ); - ~Pythia8Hadroniser(); - - void setParameters( const Parameters& ) override; - void readString( const char* param ) override; - void init() override; - bool run( Event& ev, double& weight, bool full ) override; - - void setCrossSection( double xsec, double xsec_err ) override; - - private: - static constexpr unsigned short PYTHIA_STATUS_IN_BEAM = 12; - static constexpr unsigned short PYTHIA_STATUS_IN_PARTON_KT = 61; - - std::vector min_ids_; - std::unordered_map py_cg_corresp_; - unsigned short findRole( const Event& ev, const Pythia8::Particle& p ) const; - void updateEvent( Event& ev, double& weight ) const; - Particle& addParticle( Event& ev, const Pythia8::Particle&, const Pythia8::Vec4& mom, unsigned short ) const; - /// A Pythia8 core to be wrapped - std::unique_ptr pythia_; - std::unique_ptr cg_evt_; - bool correct_central_; - bool enable_hadr_; - unsigned short offset_; - bool first_evt_; - }; - } -} - -#endif diff --git a/CepGen/IO/ExportHandler.h b/CepGen/IO/ExportHandler.h index ed08dcc..6d4352c 100644 --- a/CepGen/IO/ExportHandler.h +++ b/CepGen/IO/ExportHandler.h @@ -1,24 +1,24 @@ #ifndef CepGen_IO_ExportHandler_h #define CepGen_IO_ExportHandler_h #include "CepGen/Core/ModuleFactory.h" #include "CepGen/IO/GenericExportHandler.h" #define REGISTER_IO_MODULE( name, obj ) \ - namespace cepgen { namespace output { \ + namespace cepgen { namespace io { \ struct BUILDERNM( name ) { \ BUILDERNM( name )() { ExportHandler::get().registerModule( STRINGIFY( name ) ); } }; \ static BUILDERNM( name ) g ## name; \ } } namespace cepgen { - namespace output + namespace io { /// A hadroniser modules factory typedef ModuleFactory ExportHandler; } } #endif diff --git a/CepGen/IO/GenericExportHandler.cpp b/CepGen/IO/GenericExportHandler.cpp index 6a16659..5c5cd6b 100644 --- a/CepGen/IO/GenericExportHandler.cpp +++ b/CepGen/IO/GenericExportHandler.cpp @@ -1,69 +1,72 @@ #include "CepGen/IO/GenericExportHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Parameters.h" #include "CepGen/Version.h" #include namespace cepgen { - namespace output + namespace io { - GenericExportHandler::GenericExportHandler() : - event_num_( 0. ) + GenericExportHandler::GenericExportHandler( const std::string& name ) : + name_( name ), event_num_( 0. ) + {} + + GenericExportHandler::~GenericExportHandler() {} std::string - GenericExportHandler::banner( const Parameters& params ) + GenericExportHandler::banner( const Parameters& params, const std::string& prep ) { std::ostringstream os; os - << " ***** Sample generated with CepGen v" << version() << " *****\n" - << " * process: " << params.processName() << " (" << params.kinematics.mode << ")\n"; + << prep << " ***** Sample generated with CepGen v" << version() << " *****\n" + << prep << " * process: " << params.processName() << " (" << params.kinematics.mode << ")\n"; if ( params.kinematics.mode != KinematicsMode::ElasticElastic ) { - os << " * structure functions: " << params.kinematics.structure_functions->description() << "\n"; + os << prep << " * structure functions: " << params.kinematics.structure_functions->description() << "\n"; if ( !params.hadroniserName().empty() ) - os << " * hadroniser: " << params.hadroniserName() << "\n"; + os << prep << " * hadroniser: " << params.hadroniserName() << "\n"; } os - << " *--- incoming state\n"; + << prep << " *--- incoming state\n"; if ( params.kinematics.cuts.initial.q2.valid() ) os - << " * Q2 range (GeV2): " + << prep << " * Q2 range (GeV2): " << params.kinematics.cuts.initial.q2 << "\n"; if ( params.kinematics.mode != KinematicsMode::ElasticElastic && params.kinematics.cuts.remnants.mass_single.valid() ) os - << " * remnants mass range (GeV/c2): " + << prep << " * remnants mass range (GeV/c2): " << params.kinematics.cuts.remnants.mass_single << "\n"; - os << " *--- central system\n"; + os << prep << " *--- central system\n"; if ( params.kinematics.cuts.central.pt_single.valid() ) os - << " * single particle pt (GeV/c): " + << prep << " * single particle pt (GeV/c): " << params.kinematics.cuts.central.pt_single << "\n"; if ( params.kinematics.cuts.central.energy_single.valid() ) os - << " * single particle energy (GeV): " + << prep << " * single particle energy (GeV): " << params.kinematics.cuts.central.energy_single << "\n"; if ( params.kinematics.cuts.central.eta_single.valid() ) os - << " * single particle eta: " + << prep << " * single particle eta: " << params.kinematics.cuts.central.eta_single << "\n"; if ( params.kinematics.cuts.central.pt_sum.valid() ) os - << " * total pt (GeV/c): " + << prep << " * total pt (GeV/c): " << params.kinematics.cuts.central.mass_sum << "\n"; if ( params.kinematics.cuts.central.mass_sum.valid() ) os - << " * total invariant mass (GeV/c2): " + << prep << " * total invariant mass (GeV/c2): " << params.kinematics.cuts.central.mass_sum << "\n"; os - << " **************************************************"; + << prep << " **************************************************"; return os.str(); } } } diff --git a/CepGen/IO/GenericExportHandler.h b/CepGen/IO/GenericExportHandler.h index 72261cc..775ce03 100644 --- a/CepGen/IO/GenericExportHandler.h +++ b/CepGen/IO/GenericExportHandler.h @@ -1,41 +1,46 @@ #ifndef CepGen_IO_GenericExportHandler_h #define CepGen_IO_GenericExportHandler_h #include +#include namespace cepgen { class Event; class Parameters; /// Location for all output generators - namespace output + namespace io { /** * \brief Output format handler for events export * \author Laurent Forthomme * \date Sep 2016 */ class GenericExportHandler { public: /// Class constructor - explicit GenericExportHandler(); + explicit GenericExportHandler( const std::string& ); + virtual ~GenericExportHandler(); + const std::string& name() const { return name_; } /// Initialise the handler and its inner parameterisation virtual void initialise( const Parameters& ) = 0; /// Set the process cross section and its associated error virtual void setCrossSection( double /*xsec*/, double /*err_xsec*/ ) {} /// Set the event number void setEventNumber( const unsigned int& ev_id ) { event_num_ = ev_id; } /// Writer operator virtual void operator<<( const Event& ) = 0; protected: - static std::string banner( const Parameters& ); + static std::string banner( const Parameters&, const std::string& prep = "" ); + /// Module unique name + const std::string name_; /// Event index unsigned int event_num_; }; } } #endif diff --git a/CepGen/IO/HepMCHandler.cpp b/CepGen/IO/HepMCHandler.cpp index 3556bb1..300403b 100644 --- a/CepGen/IO/HepMCHandler.cpp +++ b/CepGen/IO/HepMCHandler.cpp @@ -1,220 +1,239 @@ #include "CepGen/IO/ExportHandler.h" #include "CepGen/Parameters.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Event/Event.h" #include "CepGen/Physics/Constants.h" #ifdef HEPMC3 +# include "HepMC3/Version.h" +# define HEPMC_VERSION HEPMC3_VERSION # include "HepMC3/WriterAscii.h" # include "HepMC3/WriterAsciiHepMC2.h" # include "HepMC3/WriterHEPEVT.h" # ifdef HEPMC3_ROOTIO # include "HepMC3/WriterRoot.h" # include "HepMC3/WriterRootTree.h" # endif # include "HepMC3/FourVector.h" # include "HepMC3/GenEvent.h" # include "HepMC3/GenRunInfo.h" # include "HepMC3/GenVertex.h" # include "HepMC3/GenParticle.h" using namespace HepMC3; #else # include "HepMC/Version.h" # if !defined( HEPMC_VERSION_CODE ) // HepMC v2 # include "HepMC/IO_GenEvent.h" # include "HepMC/SimpleVector.h" # include "HepMC/GenEvent.h" # include "HepMC/GenVertex.h" # include "HepMC/GenParticle.h" -using namespace HepMC; +# else +# include "HepMC/WriterAscii.h" +# include "HepMC/WriterHEPEVT.h" +# include "HepMC/FourVector.h" +# include "HepMC/GenEvent.h" +# include "HepMC/GenRunInfo.h" +# include "HepMC/GenVertex.h" +# include "HepMC/GenParticle.h" +# define HEPMC3 # endif +using namespace HepMC; #endif #include namespace cepgen { - namespace output + namespace io { /// Handler for the HepMC file output /// \tparam T HepMC writer handler (format-dependent) /// \author Laurent Forthomme /// \date Sep 2016 template class HepMCHandler : public GenericExportHandler { public: /// Class constructor - HepMCHandler( const ParametersList& ); + explicit HepMCHandler( const ParametersList& ); void initialise( const Parameters& /*params*/ ) override; /// Writer operator void operator<<( const Event& ) override; void setCrossSection( double, double ) override; private: /// Clear the associated HepMC event content void clearEvent(); /// Populate the associated HepMC event with a Event object void fillEvent( const Event& ); /// Writer object std::unique_ptr output_; /// Generator cross section and error std::shared_ptr xs_; #ifdef HEPMC3 /// Auxiliary information on run std::shared_ptr runinfo_; #endif /// Associated HepMC event std::shared_ptr event_; }; template HepMCHandler::HepMCHandler( const ParametersList& params ) : + GenericExportHandler( "hepmc" ), output_( new T( params.get( "filename", "output.hepmc" ) ) ), xs_( new GenCrossSection ), #ifdef HEPMC3 runinfo_( new GenRunInfo ), #endif event_( new GenEvent( Units::GEV, Units::MM ) ) { #ifdef HEPMC3 output_->set_run_info( runinfo_ ); runinfo_->set_weight_names( { "Default" } ); #endif + CG_INFO( "HepMC" ) + << "Interfacing module initialised " + << "for HepMC version " << HEPMC_VERSION << "."; } template void HepMCHandler::operator<<( const Event& evt ) { fillEvent( evt ); #ifdef HEPMC3 output_->write_event( *event_ ); #else output_->write_event( event_.get() ); #endif } template void HepMCHandler::initialise( const Parameters& ) { #ifdef HEPMC3 event_->add_attribute( "AlphaQCD", make_shared( constants::ALPHA_QCD ) ); event_->add_attribute( "AlphaEM", make_shared( constants::ALPHA_EM ) ); #else event_->set_alphaQCD( constants::ALPHA_QCD ); event_->set_alphaQED( constants::ALPHA_EM ); #endif } template void HepMCHandler::setCrossSection( double xsect, double xsect_err ) { xs_->set_cross_section( xsect, xsect_err ); } template void HepMCHandler::fillEvent( const Event& evt ) { event_->clear(); // general information #ifdef HEPMC3 event_->set_cross_section( xs_ ); event_->set_run_info( runinfo_ ); #else event_->set_cross_section( *xs_ ); #endif event_->set_event_number( event_num_ ); event_->weights().push_back( 1. ); // unweighted events // filling the particles content const FourVector origin( 0., 0., 0., 0. ); Particles part_vec = evt.particles(); int cm_id = 0, idx = 1; #ifdef HEPMC3 GenVertexPtr v1 = make_shared( origin ), v2 = make_shared( origin ), vcm = make_shared( origin ); #else GenVertex* v1 = new GenVertex( origin ), *v2 = new GenVertex( origin ), *vcm = new GenVertex( origin ); #endif for ( unsigned int i = 0; i < part_vec.size(); ++i ) { const Particle part_orig = part_vec.at( i ); FourVector pmom( part_orig.momentum().px(), part_orig.momentum().py(), part_orig.momentum().pz(), part_orig.energy() ); #ifdef HEPMC3 - GenParticlePtr part = make_shared( pmom, part_orig.integerPdgId(), (int)part_orig.status() ); + auto part = make_shared( pmom, part_orig.integerPdgId(), (int)part_orig.status() ); #else - GenParticle* part = new GenParticle( pmom, part_orig.integerPdgId(), (int)part_orig.status() ); + auto part = new GenParticle( pmom, part_orig.integerPdgId(), (int)part_orig.status() ); part->suggest_barcode( idx++ ); #endif const ParticlesIds moth = part_orig.mothers(); switch ( part_orig.role() ) { case Particle::IncomingBeam1: { v1->add_particle_in( part ); } break; case Particle::IncomingBeam2: { v2->add_particle_in( part ); } break; case Particle::OutgoingBeam1: { v1->add_particle_out( part ); } break; case Particle::OutgoingBeam2: { v2->add_particle_out( part ); } break; case Particle::Parton1: { v1->add_particle_out( part ); vcm->add_particle_in( part ); } break; case Particle::Parton2: { v2->add_particle_out( part ); vcm->add_particle_in( part ); } break; case Particle::Intermediate: { cm_id = i; continue; } break; case Particle::CentralSystem: default: { if ( moth.empty() ) continue; if ( *moth.begin() == cm_id ) vcm->add_particle_out( part ); else throw CG_FATAL( "HepMCHandler:fillEvent" ) << "Other particle requested! Not yet implemented!"; } break; } idx++; } event_->add_vertex( v1 ); event_->add_vertex( v2 ); event_->add_vertex( vcm ); #ifndef HEPMC3 event_->set_beam_particles( *v1->particles_in_const_begin(), *v2->particles_in_const_begin() ); event_->set_signal_process_vertex( *v1->vertices_begin() ); event_->set_beam_particles( *v1->particles_in_const_begin(), *v2->particles_in_const_end() ); #endif event_num_++; } #ifdef HEPMC3 +# if HEPMC_VERSION_CODE >= 3001000 typedef HepMCHandler HepMC2Handler; +# endif typedef HepMCHandler HepMC3Handler; typedef HepMCHandler HEPEVTHandler; # ifdef HEPMC3_ROOTIO typedef HepMCHandler RootHandler; typedef HepMCHandler RootTreeHandler; # endif #else typedef HepMCHandler HepMC2Handler; #endif } } #ifdef HEPMC3 REGISTER_IO_MODULE( hepmc3, HepMC3Handler ) REGISTER_IO_MODULE( hepmc, HepMC3Handler ) REGISTER_IO_MODULE( hepevt, HEPEVTHandler ) # ifdef HEPMC3_ROOTIO REGISTER_IO_MODULE( hepmc_root, RootHandler ) REGISTER_IO_MODULE( hepmc_root_tree, RootTreeHandler ) # endif #else REGISTER_IO_MODULE( hepmc, HepMC2Handler ) #endif +#if defined( HEPMC3 ) && HEPMC_VERSION_CODE >= 3001000 REGISTER_IO_MODULE( hepmc2, HepMC2Handler ) +#endif diff --git a/CepGen/IO/LHEFHepMCHandler.cpp b/CepGen/IO/LHEFHepMCHandler.cpp index 83b4f4f..408f029 100644 --- a/CepGen/IO/LHEFHepMCHandler.cpp +++ b/CepGen/IO/LHEFHepMCHandler.cpp @@ -1,104 +1,106 @@ #include "CepGen/IO/ExportHandler.h" #include "CepGen/Parameters.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Event/Event.h" #include +#ifdef HEPMC3 using namespace std; // account for improper scoping in following includes -#if !defined( HEPMC3 ) +# include "HepMC3/LHEF.h" +#else # include "HepMC/Version.h" -# ifndef HEPMC_VERSION_CODE // HepMC v2 -# error "HepMC v3 is required for the LHEF export!" -# else // HepMC v3+ +# ifdef HEPMC_VERSION_CODE // HepMC v3+ # include "HepMC/LHEF.h" +# else +# define NO_LHEF # endif -#else // HepMC v3+ -using namespace std; -# include "HepMC3/LHEF.h" #endif +#ifndef NO_LHEF namespace cepgen { - namespace output + namespace io { /** * \brief Handler for the LHE file output * \author Laurent Forthomme * \date Sep 2016 */ class LHEFHepMCHandler : public GenericExportHandler { public: /// Class constructor explicit LHEFHepMCHandler( const ParametersList& ); void initialise( const Parameters& ) override; /// Writer operator void operator<<( const Event& ) override; void setCrossSection( double, double ) override {} private: /// Writer object (from HepMC) std::unique_ptr lhe_output_; LHEF::HEPRUP run_; }; LHEFHepMCHandler::LHEFHepMCHandler( const ParametersList& params ) : + GenericExportHandler( "lhef" ), lhe_output_( new LHEF::Writer( params.get( "filename", "output.lhe" ) ) ) {} void LHEFHepMCHandler::initialise( const Parameters& params ) { lhe_output_->headerBlock() << ""; //--- first specify information about the run LHEF::HEPRUP run = lhe_output_->heprup; run.IDBMUP = { (int)params.kinematics.incoming_beams.first.pdg, (int)params.kinematics.incoming_beams.second.pdg }; run.EBMUP = { (double)params.kinematics.incoming_beams.first.pz, (double)params.kinematics.incoming_beams.second.pz }; run.NPRUP = 1; run.resize(); run.XSECUP[0] = params.integration().result; run.XERRUP[0] = params.integration().err_result; run.XMAXUP[0] = 1.; run.LPRUP[0] = 1; lhe_output_->heprup = run; //--- ensure everything is properly parsed lhe_output_->init(); } void LHEFHepMCHandler::operator<<( const Event& ev ) { LHEF::HEPEUP out; out.heprup = &lhe_output_->heprup; out.XWGTUP = 1.; out.XPDWUP = std::pair( 0., 0. ); out.SCALUP = 0.; out.AQEDUP = constants::ALPHA_EM; out.AQCDUP = constants::ALPHA_QCD; out.NUP = ev.numParticles(); out.resize(); for ( unsigned short ip = 0; ip < ev.numParticles(); ++ip ) { const Particle part = ev[ip]; out.IDUP[ip] = part.integerPdgId(); // PDG id out.ISTUP[ip] = (short)part.status(); // status code out.PUP[ip] = part.momentum().pVector(); // momentum out.MOTHUP[ip] = { // mothers part.mothers().size() > 0 ? *part.mothers(). begin()+1 : 0, part.mothers().size() > 1 ? *part.mothers().rbegin()+1 : 0 }; out.ICOLUP[ip] = { 0, 0 }; out.VTIMUP[ip] = 0.; // invariant lifetime out.SPINUP[ip] = 0.; } //lhe_output_->eventComments() << "haha"; lhe_output_->hepeup = out; lhe_output_->writeEvent(); } } } REGISTER_IO_MODULE( lhef, LHEFHepMCHandler ) +#endif diff --git a/CepGen/IO/LHEFPythiaHandler.cpp b/CepGen/IO/LHEFPythiaHandler.cpp index 9dc6e98..8e6eadd 100644 --- a/CepGen/IO/LHEFPythiaHandler.cpp +++ b/CepGen/IO/LHEFPythiaHandler.cpp @@ -1,84 +1,87 @@ #include "CepGen/IO/ExportHandler.h" +#include "CepGen/IO/PythiaEventInterface.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Event/Event.h" -#include "CepGen/Hadronisers/PythiaEventInterface.h" #include "Pythia8/Pythia.h" #include namespace cepgen { - namespace output + namespace io { /** * \brief Handler for the LHE file output * \author Laurent Forthomme * \date Sep 2016 */ class LHEFPythiaHandler : public GenericExportHandler { public: /// Class constructor explicit LHEFPythiaHandler( const ParametersList& ); ~LHEFPythiaHandler(); void initialise( const Parameters& ) override; /// Writer operator void operator<<( const Event& ) override; void setCrossSection( double, double ) override; private: std::unique_ptr pythia_; std::unique_ptr lhaevt_; }; LHEFPythiaHandler::LHEFPythiaHandler( const ParametersList& params ) : + GenericExportHandler( "lhef" ), pythia_( new Pythia8::Pythia ), lhaevt_( new Pythia8::CepGenEvent ) { lhaevt_->openLHEF( params.get( "filename", "output.lhe" ) ); } LHEFPythiaHandler::~LHEFPythiaHandler() { if ( lhaevt_ ) lhaevt_->closeLHEF( false ); // we do not want to rewrite the init block } void LHEFPythiaHandler::initialise( const Parameters& params ) { std::ostringstream oss_init; oss_init << ""; oss_init << std::endl; // LHEF is usually not as beautifully parsed as a standard XML... // we're physicists, what do you expect? lhaevt_->addComments( oss_init.str() ); lhaevt_->initialise( params ); + pythia_->setLHAupPtr( lhaevt_.get() ); + pythia_->settings.flag( "ProcessLevel:all", false ); // we do not want Pythia to interfere... + pythia_->settings.flag( "PartonLevel:all", false ); // we do not want Pythia to interfere... + pythia_->settings.flag( "HadronLevel:all", false ); // we do not want Pythia to interfere... pythia_->settings.mode( "Beams:frameType", 5 ); // LHEF event readout pythia_->settings.mode( "Next:numberCount", 0 ); // remove some of the Pythia output - pythia_->settings.flag( "ProcessLevel:all", false ); // we do not want Pythia to interfere... - pythia_->settings.flag( "Check:event", false ); - pythia_->setLHAupPtr( lhaevt_.get() ); + //pythia_->settings.flag( "Check:event", false ); pythia_->init(); lhaevt_->initLHEF(); } void LHEFPythiaHandler::operator<<( const Event& ev ) { lhaevt_->feedEvent( ev, Pythia8::CepGenEvent::Type::centralAndFullBeamRemnants ); pythia_->next(); lhaevt_->eventLHEF(); } void LHEFPythiaHandler::setCrossSection( double xsect, double xsect_err ) { lhaevt_->setCrossSection( 0, xsect, xsect_err ); } } } REGISTER_IO_MODULE( lhef, LHEFPythiaHandler ) diff --git a/CepGen/Hadronisers/PythiaEventInterface.cpp b/CepGen/IO/PythiaEventInterface.cpp similarity index 99% rename from CepGen/Hadronisers/PythiaEventInterface.cpp rename to CepGen/IO/PythiaEventInterface.cpp index ad4eb2d..aa57263 100644 --- a/CepGen/Hadronisers/PythiaEventInterface.cpp +++ b/CepGen/IO/PythiaEventInterface.cpp @@ -1,243 +1,243 @@ -#include "CepGen/Hadronisers/PythiaEventInterface.h" +#include "CepGen/IO/PythiaEventInterface.h" #include "CepGen/Core/Exception.h" #include "CepGen/Parameters.h" #include "CepGen/Physics/Kinematics.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Event/Event.h" #include "CepGen/Event/Particle.h" namespace Pythia8 { /// Convert a CepGen particle momentum into its Pythia8 counterpart Vec4 momToVec4( const cepgen::Particle::Momentum& mom ) { return Vec4( mom.px(), mom.py(), mom.pz(), mom.energy() ); } const double CepGenEvent::mp_ = cepgen::PDG::get().mass( cepgen::PDG::proton ); const double CepGenEvent::mp2_ = CepGenEvent::mp_*CepGenEvent::mp_; CepGenEvent::CepGenEvent() : LHAup( 3 ), inel1_( false ), inel2_( false ), params_( nullptr ) {} void CepGenEvent::initialise( const cepgen::Parameters& params ) { params_ = ¶ms; const cepgen::KinematicsMode& mode = params_->kinematics.mode; inel1_ = ( mode == cepgen::KinematicsMode::InelasticElastic || mode == cepgen::KinematicsMode::InelasticInelastic ); inel2_ = ( mode == cepgen::KinematicsMode::ElasticInelastic || mode == cepgen::KinematicsMode::InelasticInelastic ); setBeamA( (short)params_->kinematics.incoming_beams.first.pdg, params_->kinematics.incoming_beams.first.pz ); setBeamB( (short)params_->kinematics.incoming_beams.second.pdg, params_->kinematics.incoming_beams.second.pz ); addProcess( 0, params_->integration().result, params_->integration().err_result, 100. ); } void CepGenEvent::setCrossSection( int id, double xsec, double xsec_err ) { setXSec( id, xsec ); setXErr( id, xsec_err ); //listInit(); } void CepGenEvent::feedEvent( const cepgen::Event& ev, const Type& type ) { const double scale = ev[cepgen::Particle::Intermediate][0].mass(); setProcess( 0, 1., scale, cepgen::constants::ALPHA_EM, cepgen::constants::ALPHA_QCD ); const auto& part1 = ev[cepgen::Particle::Parton1][0], &part2 = ev[cepgen::Particle::Parton2][0]; const auto& op1 = ev[cepgen::Particle::OutgoingBeam1][0], &op2 = ev[cepgen::Particle::OutgoingBeam2][0]; const double q2_1 = -part1.momentum().mass2(), q2_2 = -part2.momentum().mass2(); const double x1 = q2_1/( q2_1+op1.mass2()-mp2_ ), x2 = q2_2/( q2_2+op2.mass2()-mp2_ ); unsigned short colour_index = MIN_COLOUR_INDEX; const Vec4 mom_part1( momToVec4( part1.momentum() ) ), mom_part2( momToVec4( part2.momentum() ) ); if ( type == Type::centralAndBeamRemnants ) { // full event content (with collinear partons) Vec4 mom_iq1 = mom_part1, mom_iq2 = mom_part2; unsigned short parton1_id = 0, parton2_id = 0; unsigned short parton1_pdgid = part1.integerPdgId(), parton2_pdgid = part2.integerPdgId(); unsigned short parton1_colour = 0, parton2_colour = 0; //FIXME select quark flavours accordingly if ( inel1_ ) { parton1_pdgid = 2; parton1_colour = colour_index++; mom_iq1 = momToVec4( x1*ev[cepgen::Particle::IncomingBeam1][0].momentum() ); } if ( inel2_ ) { parton2_pdgid = 2; parton2_colour = colour_index++; mom_iq2 = momToVec4( x2*ev[cepgen::Particle::IncomingBeam2][0].momentum() ); } //--- flavour / x value of hard-process initiators setIdX( part1.integerPdgId(), part2.integerPdgId(), x1, x2 ); setPdf( parton1_pdgid, parton2_pdgid, x1, x2, scale, 0., 0., false ); //=========================================================================================== // incoming valence quarks //=========================================================================================== parton1_id = sizePart(); addCorresp( parton1_id, op1.id() ); addParticle( parton1_pdgid, -1, 0, 0, parton1_colour, 0, mom_iq1.px(), mom_iq1.py(), mom_iq1.pz(), mom_iq1.e(), mom_iq1.mCalc(), 0., 1. ); parton2_id = sizePart(); addCorresp( parton2_id, op2.id() ); addParticle( parton2_pdgid, -1, 0, 0, parton2_colour, 0, mom_iq2.px(), mom_iq2.py(), mom_iq2.pz(), mom_iq2.e(), mom_iq2.mCalc(), 0., 1. ); //=========================================================================================== // outgoing valence quarks //=========================================================================================== if ( inel1_ ) { const Vec4 mom_oq1 = mom_iq1-mom_part1; addParticle( parton1_pdgid, 1, parton1_id, parton2_id, parton1_colour, 0, mom_oq1.px(), mom_oq1.py(), mom_oq1.pz(), mom_oq1.e(), mom_oq1.mCalc(), 0., 1. ); } if ( inel2_ ) { const Vec4 mom_oq2 = mom_iq2-mom_part2; addParticle( parton2_pdgid, 1, parton1_id, parton2_id, parton2_colour, 0, mom_oq2.px(), mom_oq2.py(), mom_oq2.pz(), mom_oq2.e(), mom_oq2.mCalc(), 0., 1. ); } } else { //=========================================================================================== // incoming partons //=========================================================================================== addCepGenParticle( part1, -2 ); addCepGenParticle( part2, -2 ); if ( type == Type::centralAndFullBeamRemnants ) { //========================================================================================= // full beam remnants content //========================================================================================= for ( const auto& syst : { cepgen::Particle::OutgoingBeam1, cepgen::Particle::OutgoingBeam2 } ) { for ( const auto& p : ev[syst] ) addCepGenParticle( p, INVALID_ID, findMothers( ev, p ) ); } } } //============================================================================================= // central system //============================================================================================= const unsigned short central_colour = colour_index++; for ( const auto& p : ev[cepgen::Particle::CentralSystem] ) { std::pair colours = { 0, 0 }, mothers = { 1, 2 }; if ( type != Type::centralAndBeamRemnants ) mothers = findMothers( ev, p ); try { if ( cepgen::PDG::get().colours( p.pdgId() ) > 1 ) { if ( p.integerPdgId() > 0 ) //--- particle colours.first = central_colour; else //--- anti-particle colours.second = central_colour; } } catch ( const cepgen::Exception& ) {} int status = 1; if ( type == Type::centralAndFullBeamRemnants && p.status() == cepgen::Particle::Status::Resonance ) status = 2; addCepGenParticle( p, status, mothers, colours ); } } void CepGenEvent::setProcess( int id, double xsec, double q2_scale, double alpha_qed, double alpha_qcd ) { LHAup::setProcess( id, xsec, q2_scale, alpha_qed, alpha_qcd ); py_cg_corresp_.clear(); } unsigned short CepGenEvent::cepgenId( unsigned short py_id ) const { if ( py_cg_corresp_.count( py_id ) == 0 ) return INVALID_ID; return py_cg_corresp_.at( py_id ); } unsigned short CepGenEvent::pythiaId( unsigned short cg_id ) const { for ( const auto& py_cg : py_cg_corresp_ ) if ( py_cg.second == cg_id ) return py_cg.first; return INVALID_ID; } void CepGenEvent::addCepGenParticle( const cepgen::Particle& part, int status, const std::pair& mothers, const std::pair& colours ) { const Vec4 mom_part( momToVec4( part.momentum() ) ); if ( status == INVALID_ID ) switch ( part.status() ) { case cepgen::Particle::Status::Resonance: case cepgen::Particle::Status::Fragmented: status = 2; break; default: status = 1; break; } addCorresp( sizePart(), part.id() ); addParticle( part.integerPdgId(), status, mothers.first, mothers.second, colours.first, colours.second, mom_part.px(), mom_part.py(), mom_part.pz(), mom_part.e(), mom_part.mCalc(), 0., 0., 0. ); } void CepGenEvent::addCorresp( unsigned short py_id, unsigned short cg_id ) { py_cg_corresp_[py_id] = cg_id; } void CepGenEvent::dumpCorresp() const { std::ostringstream oss; oss << "List of Pythia ←|→ CepGen particle ids correspondance"; for ( const auto& py_cg : py_cg_corresp_ ) oss << "\n\t" << py_cg.first << " <-> " << py_cg.second; CG_INFO( "CepGenEvent:dump" ) << oss.str(); } std::pair CepGenEvent::findMothers( const cepgen::Event& ev, const cepgen::Particle& p ) const { std::pair out = { 0, 0 }; const auto& mothers = p.mothers(); if ( mothers.empty() ) return out; const unsigned short moth1_cg_id = *mothers.begin(); out.first = pythiaId( moth1_cg_id ); if ( out.first == INVALID_ID ) { const auto& moth = ev[moth1_cg_id]; out = { ( moth.mothers().size() > 0 ) ? pythiaId( *moth.mothers().begin() ) : 0, ( moth.mothers().size() > 1 ) ? pythiaId( *moth.mothers().rbegin() ) : 0 }; } if ( mothers.size() > 1 ) { const unsigned short moth2_cg_id = *mothers.rbegin(); out.second = pythiaId( moth2_cg_id ); if ( out.second == INVALID_ID ) out.second = 0; } return out; } } diff --git a/CepGen/Hadronisers/PythiaEventInterface.h b/CepGen/IO/PythiaEventInterface.h similarity index 97% rename from CepGen/Hadronisers/PythiaEventInterface.h rename to CepGen/IO/PythiaEventInterface.h index 5d09e9c..ca907e9 100644 --- a/CepGen/Hadronisers/PythiaEventInterface.h +++ b/CepGen/IO/PythiaEventInterface.h @@ -1,83 +1,83 @@ -#ifndef CepGen_Hadronisers_PythiaEventInterface_h -#define CepGen_Hadronisers_PythiaEventInterface_h +#ifndef CepGen_IO_PythiaEventInterface_h +#define CepGen_IO_PythiaEventInterface_h #include #include namespace cepgen { class Parameters; class Event; class Particle; } namespace Pythia8 { /// Interfacing between CepGen and Pythia8 event definitions class CepGenEvent : public LHAup { public: /// List of particles to be included to the event content enum struct Type { centralAndPartons, ///< only include initiators and central system centralAndBeamRemnants, ///< include undissociated beam remnants and central system centralAndFullBeamRemnants ///< include dissociated beam remnants and central system }; explicit CepGenEvent(); /// Initialise this conversion object with CepGen parameters void initialise( const cepgen::Parameters& ); /// Feed a new CepGen event to this conversion object /// \param[in] ev CepGen event to be fed /// \param[in] type Type of storage void feedEvent( const cepgen::Event& ev, const Type& type ); /// Set the cross section for a given process /// \param[in] id Process identifier /// \param[in] xsec Process cross section, in pb /// \param[in] xsec_err Uncertainty on process cross section, in pb void setCrossSection( int id, double xsec, double xsec_err ); /// Specify new process attributes /// \param[in] id Process identifier /// \param[in] xsec Process cross section, in pb /// \param[in] q2_scale Hard event scale \f$Q^2\f$, in GeV\f$^2\f$ /// \param[in] alpha_qed \f$\alpha_{\rm em}\f$ for this process /// \param[in] alpha_qcd \f$\alpha_{\rm s}\f$ for this process void setProcess( int id, double xsec, double q2_scale, double alpha_qed, double alpha_qcd ); /// Feed comments to the LHEF block void addComments( const std::string& comments ) { osLHEF << comments; } /// Retrieve the CepGen particle index given its Pythia8 event id /// \param[in] py_id Pythia8 particle id /// \return CepGen particle id unsigned short cepgenId( unsigned short py_id ) const; /// Retrieve the Pythia8 particle index given its CepGen event id /// \param[in] cg_id CepGen particle id /// \return Pythia8 particle id unsigned short pythiaId( unsigned short cg_id ) const; /// Add a CepGen particle to the event content void addCepGenParticle( const cepgen::Particle& part, int status = INVALID_ID, const std::pair& mothers = { 0, 0 }, const std::pair& colours = { 0, 0 } ); /// Register a new Pythia8 / CepGen particle mapping /// \param[in] py_id Pythia8 particle id /// \param[in] cg_id CepGen particle id void addCorresp( unsigned short py_id, unsigned short cg_id ); /// Print all Pythia8 / CepGen Particles correspondences void dumpCorresp() const; static constexpr unsigned short INVALID_ID = 999; ///< Invalid id association static constexpr unsigned short MIN_COLOUR_INDEX = 501; ///< Minimal colour indexing number inline bool setInit() override { return true; } inline bool setEvent( int ) override { return true; } private: std::pair findMothers( const cepgen::Event& ev, const cepgen::Particle& p ) const; static const double mp_, mp2_; bool inel1_, inel2_; std::unordered_map py_cg_corresp_; const cepgen::Parameters* params_; // borrowed }; } #endif diff --git a/CepGen/IO/TextHandler.cpp b/CepGen/IO/TextHandler.cpp new file mode 100644 index 0000000..6c214b9 --- /dev/null +++ b/CepGen/IO/TextHandler.cpp @@ -0,0 +1,208 @@ +#include "CepGen/IO/ExportHandler.h" + +#include "CepGen/Core/Exception.h" +#include "CepGen/Core/ParametersList.h" +#include "CepGen/Event/Event.h" +#include "CepGen/Parameters.h" +#include "CepGen/Version.h" + +#include +#include + +namespace cepgen +{ + namespace io + { + /** + * \brief Handler for the generic text file output + * \author Laurent Forthomme + * \date Jul 2019 + */ + class TextHandler : public GenericExportHandler + { + public: + explicit TextHandler( const ParametersList& ); + ~TextHandler(); + + void initialise( const Parameters& ) override; + void operator<<( const Event& ) override; + + private: + /// Retrieve a named variable from a particle + double variable( const Particle&, const std::string& ) const; + /// Retrieve a named variable from the whole event + double variable( const Event&, const std::string& ) const; + + static const std::regex rgx_select_id_, rgx_select_role_; + static constexpr double INVALID_OUTPUT = -999.; + + std::ofstream file_; + const std::vector variables_; + const bool print_banner_, print_variables_; + const std::string separator_; + + //--- variables definition + typedef std::pair IndexedVariable; + std::unordered_map > variables_per_id_; + std::unordered_map > variables_per_role_; + std::vector variables_for_event_; + unsigned short num_vars_; + std::ostringstream oss_vars_; + + //--- auxiliary helper maps + const std::unordered_map role_str_ = { + { "ib1", Particle::Role::IncomingBeam1 }, { "ib2", Particle::Role::IncomingBeam2 }, + { "ob1", Particle::Role::OutgoingBeam1 }, { "ob2", Particle::Role::OutgoingBeam2 }, + { "pa1", Particle::Role::Parton1 }, { "pa2", Particle::Role::Parton2 }, + { "cs", Particle::Role::CentralSystem }, + { "int", Particle::Role::Intermediate } + }; + typedef double( Particle::Momentum::*pMethod )(void) const; + /// Mapping of string variables to momentum getter methods + const std::unordered_map m_mom_str_ = { + { "px", &Particle::Momentum::px }, + { "py", &Particle::Momentum::py }, + { "pz", &Particle::Momentum::pz }, + { "pt", &Particle::Momentum::pt }, + { "eta", &Particle::Momentum::eta }, + { "phi", &Particle::Momentum::phi }, + { "m", &Particle::Momentum::mass }, + { "e", &Particle::Momentum::energy }, + { "p", &Particle::Momentum::p }, + { "pt2", &Particle::Momentum::pt2 }, + { "th", &Particle::Momentum::theta }, + { "y", &Particle::Momentum::rapidity } + }; + + //--- kinematic variables + double sqrts_; + unsigned long num_evts_; + }; + + const std::regex TextHandler::rgx_select_id_( "(\\w+)\\((\\d+)\\)" ); + const std::regex TextHandler::rgx_select_role_( "(\\w+)\\(([a-z]+\\d?)\\)" ); + + TextHandler::TextHandler( const ParametersList& params ) : + GenericExportHandler( "text" ), + file_ ( params.get( "filename", "output.txt" ) ), + variables_ ( params.get >( "variables" ) ), + print_banner_ ( params.get( "saveBanner", true ) ), + print_variables_( params.get( "saveVariables", true ) ), + separator_ ( params.get( "separator", "\t" ) ), + num_vars_( 0 ) + { + std::smatch sm; + oss_vars_.clear(); + std::string sep; + for ( const auto& var : variables_ ) { + if ( std::regex_match( var, sm, rgx_select_id_ ) ) + variables_per_id_[stod( sm[2].str() )].emplace_back( std::make_pair( num_vars_, sm[1].str() ) ); + else if ( std::regex_match( var, sm, rgx_select_role_ ) ) { + const auto& str_role = sm[2].str(); + if ( role_str_.count( str_role ) == 0 ) { + CG_WARNING( "TextHandler" ) + << "Invalid particle role retrieved from configuration: \"" << str_role << "\".\n\t" + << "Skipping the variable \"" << var << "\" in the output module."; + continue; + } + variables_per_role_[role_str_.at( str_role )].emplace_back( std::make_pair( num_vars_, sm[1].str() ) ); + } + else // event-level variables + variables_for_event_.emplace_back( std::make_pair( num_vars_, var ) ); + oss_vars_ << sep << var, sep = separator_; + ++num_vars_; + } + } + + TextHandler::~TextHandler() + { + file_.close(); + } + + void + TextHandler::initialise( const Parameters& params ) + { + sqrts_ = params.kinematics.sqrtS(); + num_evts_ = 0ul; + if ( print_banner_ ) + file_ << banner( params, "#" ) << "\n"; + if ( print_variables_ ) + file_ << "# " << oss_vars_.str() << "\n"; + } + + void + TextHandler::operator<<( const Event& ev ) + { + std::vector vars( num_vars_ ); + //--- extract and order the variables to be retrieved + //--- particle-level variables (indexed by integer id) + for ( const auto& id_vars : variables_per_id_ ) { + const auto& part = ev[id_vars.first]; + //--- loop over the list of variables for this particle + for ( const auto& var : id_vars.second ) + vars[var.first] = variable( part, var.second ); + } + //--- particle-level variables (indexed by role) + for ( const auto& role_vars : variables_per_role_ ) { + const auto& part = ev[role_vars.first][0]; + //--- loop over the list of variables for this particle + for ( const auto& var : role_vars.second ) + vars[var.first] = variable( part, var.second ); + } + //--- event-level variables + for ( const auto& var : variables_for_event_ ) + vars[var.first] = variable( ev, var.second ); + //--- write down the variables list in the file + std::string sep; + for ( const auto& var : vars ) + file_ << sep << var, sep = separator_; + file_ << "\n"; + ++num_evts_; + } + + double + TextHandler::variable( const Particle& part, const std::string& var ) const + { + if ( m_mom_str_.count( var ) ) { + auto meth = m_mom_str_.at( var ); + return ( part.momentum().*meth )(); + } + if ( var == "xi" ) return 1.-part.energy()*2./sqrts_; + if ( var == "pdg" ) return (double)part.integerPdgId(); + if ( var == "charge" ) return part.charge(); + if ( var == "status" ) return (double)part.status(); + CG_WARNING( "TextHandler" ) + << "Failed to retrieve variable \"" << var << "\"."; + return INVALID_OUTPUT; + } + + double + TextHandler::variable( const Event& ev, const std::string& var ) const + { + if ( var == "np" ) + return (double)ev.size(); + if ( var == "nev" ) + return (double)num_evts_+1; + if ( var == "nob1" || var == "nob2" ) { + unsigned short out = 0.; + for ( const auto& part : ev[ + var == "nob1" + ? Particle::Role::OutgoingBeam1 + : Particle::Role::OutgoingBeam2 + ] ) + if ( (int)part.status() > 0 ) + out++; + return (double)out; + } + if ( var == "tgen" ) + return ev.time_generation; + if ( var == "ttot" ) + return ev.time_total; + CG_WARNING( "TextHandler" ) + << "Failed to retrieve the event-level variable \"" << var << "\"."; + return INVALID_OUTPUT; + } + } +} + +REGISTER_IO_MODULE( text, TextHandler ) diff --git a/CepGen/Parameters.h b/CepGen/Parameters.h index 7411797..75d6dd7 100644 --- a/CepGen/Parameters.h +++ b/CepGen/Parameters.h @@ -1,147 +1,157 @@ #ifndef CepGen_Parameters_h #define CepGen_Parameters_h #include "CepGen/Physics/Kinematics.h" #include #include #include namespace cepgen { class Event; class ParametersList; namespace proc { class GenericProcess; } namespace hadr { class GenericHadroniser; } + namespace io { class GenericExportHandler; } namespace utils { class TamingFunctionsCollection; } enum class IntegratorType; /// List of parameters used to start and run the simulation job class Parameters { public: Parameters(); /// Copy constructor (transfers ownership to the process/hadroniser!) Parameters( Parameters& ); /// Const copy constructor (all but the process and the hadroniser) Parameters( const Parameters& ); ~Parameters(); // required for unique_ptr initialisation! /// Assignment operator Parameters& operator=( Parameters ); /// Set the polar angle range for the produced leptons /// \param[in] thetamin The minimal value of \f$\theta\f$ for the outgoing leptons /// \param[in] thetamax The maximal value of \f$\theta\f$ for the outgoing leptons void setThetaRange( float thetamin, float thetamax ); /// Dump the input parameters in the terminal friend std::ostream& operator<<( std::ostream&, const Parameters* ); std::shared_ptr general; //----- process to compute /// Process for which the cross-section will be computed and the events will be generated proc::GenericProcess* process(); /// Process for which the cross-section will be computed and the events will be generated const proc::GenericProcess* process() const; /// Name of the process considered std::string processName() const; /// Set the process to study void setProcess( std::unique_ptr proc ); /// Set the process to study void setProcess( proc::GenericProcess* proc ); //----- events kinematics /// Events kinematics for phase space definition Kinematics kinematics; //----- VEGAS /// Collection of integrator parameters struct Integration { Integration(); Integration( const Integration& ); ~Integration(); IntegratorType type; unsigned int ncvg; ///< Number of function calls to be computed for each point long rng_seed; ///< Random number generator seed gsl_rng_type* rng_engine; ///< Random number generator engine gsl_monte_vegas_params vegas; double vegas_chisq_cut; gsl_monte_miser_params miser; double result, err_result; }; Integration& integration() { return integration_; } const Integration& integration() const { return integration_; } //----- events generation /// Collection of events generation parameters struct Generation { Generation(); Generation( const Generation& ); bool enabled; ///< Are we generating events ? (true) or are we only computing the cross-section ? (false) unsigned long maxgen; ///< Maximal number of events to generate in this run bool symmetrise; ///< Do we want the events to be symmetrised with respect to the \f$z\f$-axis ? bool treat; ///< Is the integrand to be smoothed for events generation? unsigned int gen_print_every; ///< Frequency at which the events are displayed to the end-user unsigned int num_threads; ///< Number of threads to perform the integration unsigned int num_points; ///< Number of points to "shoot" in each integration bin by the algorithm }; Generation& generation() { return generation_; } const Generation& generation() const { return generation_; } /// Specify if the generated events are to be stored void setStorage( bool store ) { store_ = store; } /// Are the events generated in this run to be stored in the output file ? bool storage() const { return store_; } + /// Set a new output module definition + void setOutputModule( std::unique_ptr mod ); + /// Set the pointer to a output module + void setOutputModule( io::GenericExportHandler* mod ); + /// Output module definition + io::GenericExportHandler* outputModule(); + //----- hadronisation algorithm /// Hadronisation algorithm to use for the proton(s) fragmentation hadr::GenericHadroniser* hadroniser(); /// Name of the hadroniser (if applicable) std::string hadroniserName() const; /// Set the hadronisation algorithm void setHadroniser( std::unique_ptr hadr ); /// Set the hadronisation algorithm void setHadroniser( hadr::GenericHadroniser* hadr ); //----- taming functions /// Functionals to be used to account for rescattering corrections (implemented within the process) std::shared_ptr taming_functions; //----- run operations /// Reset the total generation time and the number of events generated for this run, prepare kinematics void prepareRun(); /// Add a new timing into the total generation time /// \param[in] gen_time Time to add (in seconds) void addGenerationTime( double gen_time ); /// Return the total generation time for this run (in seconds) inline double totalGenerationTime() const { return total_gen_time_; } /// Total number of events already generated in this run inline unsigned int numGeneratedEvents() const { return num_gen_events_; } private: std::unique_ptr process_; std::unique_ptr hadroniser_; + /// Storage object + std::unique_ptr out_module_; bool store_; /// Total generation time (in seconds) double total_gen_time_; /// Number of events already generated unsigned long num_gen_events_; /// Integrator parameters Integration integration_; /// Events generation parameters Generation generation_; }; } #endif diff --git a/CepGen/Physics/Kinematics.cpp b/CepGen/Physics/Kinematics.cpp index f714f04..1dde95a 100644 --- a/CepGen/Physics/Kinematics.cpp +++ b/CepGen/Physics/Kinematics.cpp @@ -1,97 +1,99 @@ #include "CepGen/Physics/Kinematics.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/HeavyIon.h" #include "CepGen/Physics/KTFlux.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" + #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" -#include "CepGen/StructureFunctions/SuriYennie.h" #include "CepGen/Event/Particle.h" #include namespace cepgen { Kinematics::Kinematics() : incoming_beams( { { 6500., PDG::proton, KTFlux::invalid }, { 6500., PDG::proton, KTFlux::invalid } } ), - mode( KinematicsMode::invalid ), structure_functions( new strfun::SuriYennie ) + mode( KinematicsMode::invalid ), + structure_functions( strfun::StructureFunctionsHandler::get().build( (int)strfun::Type::SuriYennie ) ) {} void Kinematics::setSqrtS( double sqrts ) { if ( incoming_beams.first.pdg != incoming_beams.second.pdg ) throw CG_FATAL( "Kinematics" ) << "Trying to set √s with asymmetric beams.\n" << "Please fill incoming beams objects manually!"; incoming_beams.first.pz = incoming_beams.second.pz = 0.5 * sqrts; } double Kinematics::sqrtS() const { const HeavyIon hi1( incoming_beams.first.pdg ), hi2( incoming_beams.second.pdg ); const double m1 = hi1 ? HeavyIon::mass( hi1 ) : PDG::get().mass( incoming_beams.first .pdg ); const double m2 = hi2 ? HeavyIon::mass( hi2 ) : PDG::get().mass( incoming_beams.second.pdg ); const auto p1 = Particle::Momentum::fromPxPyPzM( 0., 0., +incoming_beams.first .pz, m1 ); const auto p2 = Particle::Momentum::fromPxPyPzM( 0., 0., -incoming_beams.second.pz, m2 ); return ( p1+p2 ).mass(); } //-------------------------------------------------------------------- // User-friendly display of the kinematics mode //-------------------------------------------------------------------- std::ostream& operator<<( std::ostream& os, const KinematicsMode& pm ) { switch ( pm ) { case KinematicsMode::invalid: return os << "invalid"; case KinematicsMode::ElectronElectron: return os << "electron/electron"; case KinematicsMode::ElectronProton: return os << "electron/proton"; case KinematicsMode::ProtonElectron: return os << "proton/electron"; case KinematicsMode::ElasticElastic: return os << "elastic/elastic"; case KinematicsMode::InelasticElastic: return os << "inelastic/elastic"; case KinematicsMode::ElasticInelastic: return os << "elastic/inelastic"; case KinematicsMode::InelasticInelastic: return os << "inelastic/inelastic"; } return os; } //-------------------------------------------------------------------- // User-friendly display of incoming particles //-------------------------------------------------------------------- std::ostream& operator<<( std::ostream& os, const Kinematics::Beam& beam ) { if ( (HeavyIon)beam.pdg ) os << (HeavyIon)beam.pdg; else os << PDG::get().name( beam.pdg ); os << " (" << beam.pz << " GeV/c)"; if ( beam.kt_flux != KTFlux::invalid ) os << " [unint.flux: " << beam.kt_flux << "]"; return os; } //-------------------------------------------------------------------- // List of kinematics limits //-------------------------------------------------------------------- Kinematics::CutsList::CutsList() { initial.q2 = { 0., 1.e5 }; central.pt_single.min() = 0.; remnants.mass_single = { 1.07, 320. }; } } diff --git a/CepGen/Processes/PPtoWW.cpp b/CepGen/Processes/PPtoWW.cpp index ac0d24c..dd25a50 100644 --- a/CepGen/Processes/PPtoWW.cpp +++ b/CepGen/Processes/PPtoWW.cpp @@ -1,392 +1,391 @@ #include "CepGen/Processes/PPtoWW.h" #include "CepGen/Processes/ProcessesHandler.h" #include "CepGen/Event/Event.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Physics/FormFactors.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/Exception.h" #include namespace cepgen { namespace proc { const double PPtoWW::mw_ = PDG::get().mass( PDG::W ); const double PPtoWW::mw2_ = PPtoWW::mw_*PPtoWW::mw_; PPtoWW::PPtoWW( const ParametersList& params ) : GenericKTProcess( params, "pptoww", "ɣɣ → W⁺W¯", { { PDG::photon, PDG::photon } }, { PDG::W, PDG::W } ), method_ ( params.get( "method", 1 ) ), pol_state_( (Polarisation)params.get( "polarisationStates", 0 ) ), y1_( 0. ), y2_( 0. ), pt_diff_( 0. ), phi_pt_diff_( 0. ) {} void PPtoWW::preparePhaseSpace() { registerVariable( y1_, Mapping::linear, kin_.cuts.central.rapidity_single, { -6., 6. }, "First outgoing W rapidity" ); registerVariable( y2_, Mapping::linear, kin_.cuts.central.rapidity_single, { -6., 6. }, "Second outgoing W rapidity" ); registerVariable( pt_diff_, Mapping::linear, kin_.cuts.central.pt_diff, { 0., 500. }, "Ws transverse momentum difference" ); registerVariable( phi_pt_diff_, Mapping::linear, kin_.cuts.central.phi_pt_diff, { 0., 2.*M_PI }, "Ws azimuthal angle difference" ); switch ( pol_state_ ) { case Polarisation::LL: pol_w1_ = pol_w2_ = { 0 }; break; case Polarisation::LT: pol_w1_ = { 0 }; pol_w2_ = { -1, 1 }; break; case Polarisation::TL: pol_w1_ = { -1, 1 }; pol_w2_ = { 0 }; break; case Polarisation::TT: pol_w1_ = pol_w2_ = { -1, 1 }; break; default: case Polarisation::full: pol_w1_ = pol_w2_ = { -1, 0, 1 }; break; } CG_DEBUG( "PPtoWW:mode" ) << "matrix element computation method: " << method_ << "."; } double PPtoWW::computeKTFactorisedMatrixElement() { //================================================================= // matrix element computation //================================================================= //const double stild = s_/2.*(1+sqrt(1.-(4*pow(mp2_, 2))/s_*s_)); // Inner photons const double q1tx = qt1_*cos( phi_qt1_ ), q1ty = qt1_*sin( phi_qt1_ ), q2tx = qt2_*cos( phi_qt2_ ), q2ty = qt2_*sin( phi_qt2_ ); CG_DEBUG_LOOP( "PPtoWW:qt" ) << "q1t(x/y) = " << q1tx << " / " << q1ty << "\n\t" << "q2t(x/y) = " << q2tx << " / " << q2ty << "."; // Two-photon system const double ptsumx = q1tx+q2tx, ptsumy = q1ty+q2ty, ptsum = sqrt( ptsumx*ptsumx+ptsumy*ptsumy ); const double ptdiffx = pt_diff_*cos( phi_pt_diff_ ), ptdiffy = pt_diff_*sin( phi_pt_diff_ ); //--- outgoing Ws const double pt1x = ( ptsumx+ptdiffx )*0.5, pt1y = ( ptsumy+ptdiffy )*0.5, pt1 = std::hypot( pt1x, pt1y ), pt2x = ( ptsumx-ptdiffx )*0.5, pt2y = ( ptsumy-ptdiffy )*0.5, pt2 = std::hypot( pt2x, pt2y ); if ( kin_.cuts.central_particles.count( PDG::W ) > 0 && kin_.cuts.central_particles.at( PDG::W ).pt_single.valid() ) { const Limits pt_limits = kin_.cuts.central_particles.at( PDG::W ).pt_single; if ( !pt_limits.passes( pt1 ) || !pt_limits.passes( pt2 ) ) return 0.; } //--- transverse mass for the two Ws const double amt1 = std::hypot( pt1, mw_ ), amt2 = std::hypot( pt2, mw_ ); //================================================================= // a window in two-boson invariant mass //================================================================= const double invm = sqrt( amt1*amt1 + amt2*amt2 + 2.*amt1*amt2*cosh( y1_-y2_ ) - ptsum*ptsum ); if ( !kin_.cuts.central.mass_sum.passes( invm ) ) return 0.; //================================================================= // a window in transverse momentum difference //================================================================= if ( !kin_.cuts.central.pt_diff.passes( fabs( pt1-pt2 ) ) ) return 0.; //================================================================= // a window in rapidity distance //================================================================= if ( !kin_.cuts.central.rapidity_diff.passes( fabs( y1_-y2_ ) ) ) return 0.; //================================================================= // auxiliary quantities //================================================================= const double alpha1 = amt1/sqs_*exp( y1_ ), beta1 = amt1/sqs_*exp( -y1_ ), alpha2 = amt2/sqs_*exp( y2_ ), beta2 = amt2/sqs_*exp( -y2_ ); CG_DEBUG_LOOP( "PPtoWW:sudakov" ) << "Sudakov parameters:\n\t" << " alpha1/2 = " << alpha1 << " / " << alpha2 << "\n\t" << " beta1/2 = " << beta1 << " / " << beta2 << "."; const double q1t2 = q1tx*q1tx+q1ty*q1ty, q2t2 = q2tx*q2tx+q2ty*q2ty; const double x1 = alpha1+alpha2, x2 = beta1+beta2; const double z1p = alpha1/x1, z1m = alpha2/x1, z2p = beta1 /x2, z2m = beta2 /x2; CG_DEBUG_LOOP( "PPtoWW:zeta" ) << "z(1/2)p = " << z1p << " / " << z2p << "\n\t" << "z(1/2)m = " << z1m << " / " << z2m << "."; if ( x1 > 1. || x2 > 1. ) return 0.; // sanity check - // FIXME FIXME FIXME - const double ak10 = event_->getOneByRole( Particle::IncomingBeam1 ).energy(), - ak1z = event_->getOneByRole( Particle::IncomingBeam1 ).momentum().pz(), - ak20 = event_->getOneByRole( Particle::IncomingBeam2 ).energy(), - ak2z = event_->getOneByRole( Particle::IncomingBeam2 ).momentum().pz(); + const auto& ib1 = event_->getOneByRole( Particle::IncomingBeam1 ), + &ib2 = event_->getOneByRole( Particle::IncomingBeam2 ); + const double ak10 = ib1.energy(), ak1z = ib1.momentum().pz(), + ak20 = ib2.energy(), ak2z = ib2.momentum().pz(); CG_DEBUG_LOOP( "PPtoWW:incoming" ) << "incoming particles: p1: " << ak1z << " / " << ak10 << "\n\t" << " p2: " << ak2z << " / " << ak20 << "."; //================================================================= // additional conditions for energy-momentum conservation //================================================================= const double s1_eff = x1*s_-qt1_*qt1_, s2_eff = x2*s_-qt2_*qt2_; CG_DEBUG_LOOP( "PPtoWW:central" ) << "s(1/2)_eff = " << s1_eff << " / " << s2_eff << " GeV^2\n\t" << "diboson invariant mass = " << invm << " GeV"; if ( ( kin_.mode == KinematicsMode::ElasticInelastic || kin_.mode == KinematicsMode::InelasticInelastic ) && ( sqrt( s1_eff ) <= ( MY_+invm ) ) ) return 0.; if ( ( kin_.mode == KinematicsMode::InelasticElastic || kin_.mode == KinematicsMode::InelasticInelastic ) && ( sqrt( s2_eff ) <= ( MX_+invm ) ) ) return 0.; //const double qcaptx = pcaptx, qcapty = pcapty; //================================================================= // four-momenta of the outgoing protons (or remnants) //================================================================= const double px_plus = ( 1.-x1 )*fabs( ak1z )*M_SQRT2, px_minus = ( MX_*MX_ + q1t2 )*0.5/px_plus; const double py_minus = ( 1.-x2 )*fabs( ak2z )*M_SQRT2, // warning! sign of pz?? py_plus = ( MY_*MY_ + q2t2 )*0.5/py_minus; CG_DEBUG_LOOP( "PPtoWW:pxy" ) << "px± = " << px_plus << " / " << px_minus << "\n\t" << "py± = " << py_plus << " / " << py_minus << "."; PX_ = Particle::Momentum( -q1tx, -q1ty, ( px_plus-px_minus )*M_SQRT1_2, ( px_plus+px_minus )*M_SQRT1_2 ); PY_ = Particle::Momentum( -q2tx, -q2ty, ( py_plus-py_minus )*M_SQRT1_2, ( py_plus+py_minus )*M_SQRT1_2 ); CG_DEBUG_LOOP( "PPtoWW:remnants" ) << "First remnant: " << PX_ << ", mass = " << PX_.mass() << "\n\t" << "Second remnant: " << PY_ << ", mass = " << PY_.mass() << "."; /*assert( fabs( PX_.mass()-MX_ ) < 1.e-6 ); assert( fabs( PY_.mass()-MY_ ) < 1.e-6 );*/ //================================================================= // four-momenta squared of the virtual photons //================================================================= const double ww = 0.5 * ( 1.+sqrt( 1.-4.*mp2_/s_ ) ); // FIXME FIXME FIXME ///////////////////// const Particle::Momentum q1( q1tx, q1ty, +0.5 * x1*ww*sqs_*( 1.-q1t2/x1/x1/ww/ww/s_ ), +0.5 * x1*ww*sqs_*( 1.+q1t2/x1/x1/ww/ww/s_ ) ); const Particle::Momentum q2( q2tx, q2ty, -0.5 * x2*ww*sqs_*( 1.-q2t2/x2/x2/ww/ww/s_ ), +0.5 * x2*ww*sqs_*( 1.+q2t2/x2/x2/ww/ww/s_ ) ); ////////////////////////////////////////// CG_DEBUG_LOOP( "PPtoWW:partons" ) << "First photon*: " << q1 << ", mass2 = " << q1.mass2() << "\n\t" << "Second photon*: " << q2 << ", mass2 = " << q2.mass2() << "."; //const double q12 = q1.mass2(), q22 = q2.mass2(); //================================================================= // four-momenta of the outgoing W^+ and W^- //================================================================= p_w1_ = Particle::Momentum( pt1x, pt1y, alpha1*ak1z + beta1*ak2z, alpha1*ak10 + beta1*ak20 ); p_w2_ = Particle::Momentum( pt2x, pt2y, alpha2*ak1z + beta2*ak2z, alpha2*ak10 + beta2*ak20 ); CG_DEBUG_LOOP( "PPtoWW:central" ) << "First W: " << p_w1_ << ", mass = " << p_w1_.mass() << "\n\t" << "Second W: " << p_w2_ << ", mass = " << p_w2_.mass() << "."; //assert( fabs( p_w1_.mass()-(*event_)[Particle::CentralSystem][0].mass() ) < 1.e-6 ); //assert( fabs( p_w2_.mass()-(*event_)[Particle::CentralSystem][1].mass() ) < 1.e-6 ); //================================================================= // Mendelstam variables //================================================================= //const double shat = s_*x1*x2; // ishat = 1 (approximation) const double shat = ( q1+q2 ).mass2(); // ishat = 2 (exact formula) const double that1 = ( q1-p_w1_ ).mass2(), that2 = ( q2-p_w2_ ).mass2(); const double uhat1 = ( q1-p_w2_ ).mass2(), uhat2 = ( q2-p_w1_ ).mass2(); CG_DEBUG_LOOP( "PPtoWW" ) << "that(1/2) = " << that1 << " / " << that2 << "\n\t" << "uhat(1/2) = " << uhat1 << " / " << uhat2 << "."; //const double mll = sqrt( shat ); const double that = 0.5*( that1+that2 ), uhat = 0.5*( uhat1+uhat2 ); //================================================================= // matrix elements //================================================================= double amat2 = 0.; //================================================================= // How matrix element is calculated //================================================================= CG_DEBUG_LOOP( "PPtoWW" ) << "matrix element mode: " << method_ << "."; //================================================================= // matrix element for gamma gamma --> W^+ W^- // (Denner+Dittmaier+Schuster) // (work in collaboration with C. Royon) //================================================================= if ( method_ == 0 ) amat2 = onShellME( shat, that, uhat ); //================================================================= // off-shell Nachtmann formulae //================================================================= else if ( method_ == 1 ) amat2 = offShellME( shat, that, uhat, phi_qt1_+phi_qt2_, phi_qt1_-phi_qt2_ ); if ( amat2 <= 0. ) return 0.; //============================================ // unintegrated photon distributions //============================================ const std::pair fluxes = GenericKTProcess::incomingFluxes( x1, q1t2, x2, q2t2 ); CG_DEBUG_LOOP( "PPtoWW:fluxes" ) << "Incoming photon fluxes for (x/kt2) = " << "(" << x1 << "/" << q1t2 << "), " << "(" << x2 << "/" << q2t2 << "):\n\t" << fluxes.first << ", " << fluxes.second << "."; //================================================================= // factor 2.*pi from integration over phi_sum // factor 1/4 from jacobian of transformations // factors 1/pi and 1/pi due to integration over // d^2 kappa_1 d^2 kappa_2 instead d kappa_1^2 d kappa_2^2 //================================================================= const double aintegral = amat2 / ( 16.*M_PI*M_PI*( x1*x2*s_ )*( x1*x2*s_ ) ) * fluxes.first*M_1_PI * fluxes.second*M_1_PI * 0.25 * constants::GEVM2_TO_PB; /*const double aintegral = amat2 / ( 16.*M_PI*M_PI*x1*x1*x2*x2*s_*s_ ) * fluxes.first*M_1_PI * fluxes.second*M_1_PI * constants::GEVM2_TO_PB * 0.25;*/ //================================================================= return aintegral*qt1_*qt2_*pt_diff_; //================================================================= } void PPtoWW::fillCentralParticlesKinematics() { // randomise the charge of the outgoing leptons short sign = ( drand() > 0.5 ) ? +1 : -1; //================================================================= // first outgoing lepton //================================================================= Particle& ow1 = (*event_)[Particle::CentralSystem][0]; ow1.setPdgId( ow1.pdgId(), sign ); ow1.setStatus( Particle::Status::Undecayed ); ow1.setMomentum( p_w1_ ); //================================================================= // second outgoing lepton //================================================================= Particle& ow2 = (*event_)[Particle::CentralSystem][1]; ow2.setPdgId( ow2.pdgId(), -sign ); ow2.setStatus( Particle::Status::Undecayed ); ow2.setMomentum( p_w2_ ); } double PPtoWW::onShellME( double shat, double that, double uhat ) { const double mw4 = mw2_*mw2_; const double term1 = 2.*shat * ( 2.*shat+3.*mw2_ ) / ( 3.*( mw2_-that )*( mw2_-uhat ) ); const double term2 = 2.*shat*shat * ( shat*shat + 3.*mw4 ) / ( 3.*pow( mw2_-that, 2 )*pow( mw2_-uhat, 2 ) ); const double auxil_gamgam = 1.-term1+term2; const double beta = sqrt( 1.-4.*mw2_/shat ); return 3.*constants::ALPHA_EM*constants::ALPHA_EM*beta / ( 2.*shat ) * auxil_gamgam / ( beta/( 64.*M_PI*M_PI*shat ) ); } double PPtoWW::offShellME( double shat, double that, double uhat, double phi_sum, double phi_diff ) { const double e2 = 4.*M_PI*constants::ALPHA_EM; double amat2_0 = 0., amat2_1 = 0., amat2_interf = 0.; for ( const auto lam3 : pol_w1_ ) for ( const auto lam4 : pol_w2_ ) { double ampli_pp = amplitudeWW( shat, that, uhat, +1, +1, lam3, lam4 ); double ampli_mm = amplitudeWW( shat, that, uhat, -1, -1, lam3, lam4 ); double ampli_pm = amplitudeWW( shat, that, uhat, +1, -1, lam3, lam4 ); double ampli_mp = amplitudeWW( shat, that, uhat, -1, +1, lam3, lam4 ); amat2_0 += ampli_pp*ampli_pp + ampli_mm*ampli_mm + 2.*cos( 2.*phi_diff )*ampli_pp*ampli_mm; amat2_1 += ampli_pm*ampli_pm + ampli_mp*ampli_mp + 2.*cos( 2.*phi_sum )*ampli_pm*ampli_mp; amat2_interf -= 2.*( cos( phi_sum+phi_diff )*( ampli_pp*ampli_pm+ampli_mm*ampli_mp ) +cos( phi_sum-phi_diff )*( ampli_pp*ampli_mp+ampli_mm*ampli_pm ) ); } return e2*e2*( amat2_0+amat2_1+amat2_interf ); } double PPtoWW::amplitudeWW( double shat, double that, double uhat, short lam1, short lam2, short lam3, short lam4 ) { //--- first compute some kinematic variables const double cos_theta = ( that-uhat ) / shat / sqrt( 1.+1.e-10-4.*mw2_/shat ), cos_theta2 = cos_theta*cos_theta; const double sin_theta2 = 1.-cos_theta2, sin_theta = sqrt( sin_theta2 ); const double beta = sqrt( 1.-4.*mw2_/shat ), beta2 = beta*beta; const double inv_gamma = sqrt( 1.-beta2 ), gamma = 1./inv_gamma, gamma2 = gamma*gamma, inv_gamma2 = inv_gamma*inv_gamma; const double invA = 1./( 1.-beta2*cos_theta2 ); //--- per-helicity amplitude // longitudinal-longitudinal if ( lam3 == 0 && lam4 == 0 ) return invA*inv_gamma2*( ( gamma2+1. )*( 1.-lam1*lam2 )*sin_theta2 - ( 1.+lam1*lam2 ) ); // transverse-longitudinal if ( lam4 == 0 ) return invA*( -M_SQRT2*inv_gamma*( lam1-lam2 )*( 1.+lam1*lam3*cos_theta )*sin_theta ); // longitudinal-transverse if ( lam3 == 0 ) return invA*( -M_SQRT2*inv_gamma*( lam2-lam1 )*( 1.+lam2*lam4*cos_theta )*sin_theta ); // transverse-transverse if ( lam3 != 0 && lam4 != 0 ) return -0.5*invA*( 2.*beta*( lam1+lam2 )*( lam3+lam4 ) -inv_gamma2*( 1.+lam3*lam4 )*( 2.*lam1*lam2+( 1.-lam1*lam2 ) * cos_theta2 ) +( 1.+lam1*lam2*lam3*lam4 )*( 3.+lam1*lam2 ) +2.*( lam1-lam2 )*( lam3-lam4 )*cos_theta +( 1.-lam1*lam2 )*( 1.-lam3*lam4 )*cos_theta2 ); return 0.; } } } // register process and define aliases REGISTER_PROCESS( pptoww, PPtoWW ) diff --git a/CepGen/StructureFunctions/ALLM.cpp b/CepGen/StructureFunctions/ALLM.cpp index a4ca62b..d119c83 100644 --- a/CepGen/StructureFunctions/ALLM.cpp +++ b/CepGen/StructureFunctions/ALLM.cpp @@ -1,218 +1,267 @@ -#include "CepGen/StructureFunctions/ALLM.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" -#include -#include +#include +#include +#include namespace cepgen { namespace strfun { + /// \f$F_{2,L}\f$ parameterisation by Abramowicz, Levin, Levy, and Maor \cite Abramowicz:1991xz\cite Abramowicz:1997ms + class ALLM : public Parameterisation + { + public: + class Parameters + { + private: + struct Trajectory + { + Trajectory( const ParametersList& params = ParametersList() ); + std::vector a, b, c; + }; + + public: + Parameters( const ParametersList& params = ParametersList() ); + /// Pre-HERA data fit (694 data points) + static Parameters allm91(); + /// Fixed target and HERA photoproduction total cross sections (1356 points) + static Parameters allm97(); + static Parameters hht_allm(); + static Parameters hht_allm_ft(); + static Parameters gd07p(); + static Parameters gd11p(); + + Trajectory pomeron, reggeon; + /// Effective photon squared mass + double m02; + /// Effective pomeron squared mass + double mp2; + /// Effective reggeon squared mass + double mr2; + double q02; + /// Squared QCD scale + double lambda2; + Type type; + }; + + explicit ALLM( const ParametersList& params = ParametersList() ); + ALLM& operator()( double xbj, double q2 ) override; + + private: + Parameters params_; + }; + ALLM::ALLM( const ParametersList& params ) : Parameterisation( params ), params_( params.get( "parameterisation" ) ) { const auto& model = params.get( "model" ); if ( model == "GD07p" ) params_ = Parameters::gd07p(); else if ( model == "GD11p" ) params_ = Parameters::gd11p(); else if ( model == "ALLM91" ) params_ = Parameters::allm91(); else if ( model == "ALLM97" ) params_ = Parameters::allm97(); else if ( model == "HHT_ALLM" ) params_ = Parameters::hht_allm(); else if ( model == "HHT_ALLM_FT" ) params_ = Parameters::hht_allm_ft(); CG_DEBUG( "ALLM" ) << "ALLM structure functions builder initialised.\n" << "Parameterisation (" << params_.type << "):\n" << " *) Pomeron trajectory:\n" << " a = {" << params_.pomeron.a.at( 0 ) << ", " << params_.pomeron.a.at( 1 ) << ", " << params_.pomeron.a.at( 2 ) << "}\n" << " b = {" << params_.pomeron.b.at( 0 ) << ", " << params_.pomeron.b.at( 1 ) << ", " << params_.pomeron.b.at( 2 ) << "}\n" << " c = {" << params_.pomeron.c.at( 0 ) << ", " << params_.pomeron.c.at( 1 ) << ", " << params_.pomeron.c.at( 2 ) << "}\n" << " *) Reggeon trajectory:\n" << " a = {" << params_.reggeon.a.at( 0 ) << ", " << params_.reggeon.a.at( 1 ) << ", " << params_.reggeon.a.at( 2 ) << "}\n" << " b = {" << params_.reggeon.b.at( 0 ) << ", " << params_.reggeon.b.at( 1 ) << ", " << params_.reggeon.b.at( 2 ) << "}\n" << " c = {" << params_.reggeon.c.at( 0 ) << ", " << params_.reggeon.c.at( 1 ) << ", " << params_.reggeon.c.at( 2 ) << "}\n" << " masses: m₀²=" << params_.m02 << ", mp²=" << params_.mp2 << ", mr²=" << params_.mr2 << " GeV²\n" << " q₀²=" << params_.q02 << ", Λ²=" << params_.lambda2 << " GeV²."; } ALLM& ALLM::operator()( double xbj, double q2 ) { const double W2_eff = q2*( 1.-xbj )/xbj; const double xp = ( q2+params_.mp2 )/( q2+W2_eff+params_.mp2 ), xr = ( q2+params_.mr2 )/( q2+W2_eff+params_.mr2 ); const double xlog1 = log( ( q2+params_.q02 )/ params_.lambda2 ), xlog2 = log( params_.q02/params_.lambda2 ); const double t = log( xlog1/xlog2 ); const double apom = params_.pomeron.a.at( 0 )+( params_.pomeron.a.at( 0 )-params_.pomeron.a.at( 1 ) )*( 1./( 1.+pow( t, params_.pomeron.a.at( 2 ) ) ) - 1. ); const double bpom = params_.pomeron.b.at( 0 )+ params_.pomeron.b.at( 1 )*pow( t, params_.pomeron.b.at( 2 ) ); const double cpom = params_.pomeron.c.at( 0 )+( params_.pomeron.c.at( 0 )-params_.pomeron.c.at( 1 ) )*( 1./( 1.+pow( t, params_.pomeron.c.at( 2 ) ) ) - 1. ); const double areg = params_.reggeon.a.at( 0 )+params_.reggeon.a.at( 1 )*pow( t, params_.reggeon.a.at( 2 ) ); const double breg = params_.reggeon.b.at( 0 )+params_.reggeon.b.at( 1 )*pow( t, params_.reggeon.b.at( 2 ) ); const double creg = params_.reggeon.c.at( 0 )+params_.reggeon.c.at( 1 )*pow( t, params_.reggeon.c.at( 2 ) ); const double F2_Pom = cpom*pow( xp, apom )*pow( 1.-xbj, bpom ), F2_Reg = creg*pow( xr, areg )*pow( 1.-xbj, breg ); F2 = q2/( q2+params_.m02 ) * ( F2_Pom+F2_Reg ); return *this; } //--------------------------------------------------------------------------------------------- // parameterisation object //--------------------------------------------------------------------------------------------- ALLM::Parameters::Parameters( const ParametersList& params ) : pomeron( params.get( "pomeronTrajectory" ) ), reggeon( params.get( "reggeonTrajectory" ) ), m02 ( params.get( "m02" ) ), mp2 ( params.get( "mp2" ) ), mr2 ( params.get( "mr2" ) ), q02 ( params.get( "q02" ) ), lambda2( params.get( "lambda2" ) ), type ( (Type)params.get( "type", (int)Type::Invalid ) ) {} ALLM::Parameters ALLM::Parameters::allm91() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.04503, -0.36407, 8.17091 } ) .set >( "b", { 0.49222, 0.52116, 3.5515 } ) .set >( "c", { 0.26550, 0.04856, 1.04682 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.60408, 0.17353, 1.61812 } ) .set >( "b", { 1.26066, 1.83624, 0.81141 } ) .set >( "c", { 0.67639, 0.49027, 2.66275 } ) ) .set( "m02", 0.30508 ) .set( "mp2", 10.676 ) .set( "mr2", 0.20623 ) .set( "q02", 0.27799 ) .set( "lambda2", 0.06527 ) .set( "type", (int)Type::ALLM91 ) ); return p; } ALLM::Parameters ALLM::Parameters::allm97() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.0808, -0.44812, 1.1709 } ) .set >( "b", { 0.36292, 1.8917, 1.8439 } ) .set >( "c", { 0.28067, 0.22291, 2.1979 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.58400, 0.37888, 2.6063 } ) .set >( "b", { 0.01147, 3.7582, 0.49338 } ) .set >( "c", { 0.80107, 0.97307, 3.4924 } ) ) .set( "m02", 0.31985 ) .set( "mp2", 49.457 ) .set( "mr2", 0.15052 ) .set( "q02", 0.52544 ) .set( "lambda2", 0.06526 ) .set( "type", (int)Type::ALLM97 ) ); return p; } ALLM::Parameters ALLM::Parameters::hht_allm() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.835, -0.446, 10.6 } ) .set >( "b", {-45.8, 55.7, -0.031 } ) .set >( "c", { 0.412, 0.164, 17.7 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.706, 0.185, -16.4 } ) .set >( "b", { -1.29, 4.51, 1.16 } ) .set >( "c", { -1.04, 2.97, 0.163 } ) ) .set( "m02", 0.446 ) .set( "mp2", 74.2 ) .set( "mr2", 29.3 ) .set( "q02", 4.74e-5 ) .set( "lambda2", 2.2e-8 ) ); return p; } ALLM::Parameters ALLM::Parameters::hht_allm_ft() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.075, -0.470, 9.2 } ) .set >( "b", { -0.477, 54.0, 0.073 } ) .set >( "c", { 0.356, 0.171, 18.6 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.882, 0.082, -8.5 } ) .set >( "b", { 0.339, 3.38, 1.07 } ) .set >( "c", { -0.636, 3.37, -0.660 } ) ) .set( "m02", 0.388 ) .set( "mp2", 50.8 ) .set( "mr2", 0.838 ) .set( "q02", 1.87e-5 ) .set( "lambda2", 4.4e-9 ) ); return p; } ALLM::Parameters ALLM::Parameters::gd07p() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.105, -0.495, 1.29 } ) .set >( "b", { -1.42, 4.51, 0.551 } ) .set >( "c", { 0.339, 0.127, 1.16 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.374, 0.998, 0.775 } ) .set >( "b", { 2.71, 1.83, 1.26 } ) .set >( "c", { 0.838, 2.36, 1.77 } ) ) .set( "m02", 0.454 ) .set( "mp2", 30.7 ) .set( "mr2", 0.117 ) .set( "q02", 1.15 ) .set( "lambda2", 0.06527 ) .set( "type", (int)Type::GD07p ) ); return p; } ALLM::Parameters ALLM::Parameters::gd11p() { static Parameters p( ParametersList() .set( "pomeronTrajectory", ParametersList() .set >( "a", { -0.11895, -0.4783, 1.353 } ) .set >( "b", { 1.0833, 2.656, 1.771 } ) .set >( "c", { 0.3638, 0.1211, 1.166 } ) ) .set( "reggeonTrajectory", ParametersList() .set >( "a", { 0.3425, 1.0603, 0.5164 } ) .set >( "b", {-10.408, 14.857, 0.07739 } ) .set >( "c", { 1.3633, 2.256, 2.209 } ) ) .set( "m02", 0.5063 ) .set( "mp2", 34.75 ) .set( "mr2", 0.03190 ) .set( "q02", 1.374 ) .set( "lambda2", 0.06527 ) .set( "type", (int)Type::GD11p ) ); return p; } ALLM::Parameters::Trajectory::Trajectory( const ParametersList& params ) : a( params.get >( "a", { 0., 0., 0. } ) ), b( params.get >( "b", { 0., 0., 0. } ) ), c( params.get >( "c", { 0., 0., 0. } ) ) { assert( a.size() == 3 ); assert( b.size() == 3 ); assert( c.size() == 3 ); } } } +REGISTER_STRFUN_PARAMS( ALLM91, strfun::ALLM, ParametersList().set( "model", "ALLM91" ) ) +REGISTER_STRFUN_PARAMS( ALLM97, strfun::ALLM, ParametersList().set( "model", "ALLM97" ) ) +REGISTER_STRFUN_PARAMS( GD07p, strfun::ALLM, ParametersList().set( "model", "GD07p" ) ) +REGISTER_STRFUN_PARAMS( GD11p, strfun::ALLM, ParametersList().set( "model", "GD11p" ) ) diff --git a/CepGen/StructureFunctions/ALLM.h b/CepGen/StructureFunctions/ALLM.h deleted file mode 100644 index 8247f6e..0000000 --- a/CepGen/StructureFunctions/ALLM.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef CepGen_StructureFunctions_ALLM_h -#define CepGen_StructureFunctions_ALLM_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -#include - -namespace cepgen -{ - namespace strfun - { - /// \f$F_{2,L}\f$ parameterisation by Abramowicz, Levin, Levy, and Maor \cite Abramowicz:1991xz\cite Abramowicz:1997ms - class ALLM : public Parameterisation - { - public: - class Parameters - { - private: - struct Trajectory - { - Trajectory( const ParametersList& params = ParametersList() ); - std::vector a, b, c; - }; - - public: - Parameters( const ParametersList& params = ParametersList() ); - /// Pre-HERA data fit (694 data points) - static Parameters allm91(); - /// Fixed target and HERA photoproduction total cross sections (1356 points) - static Parameters allm97(); - static Parameters hht_allm(); - static Parameters hht_allm_ft(); - static Parameters gd07p(); - static Parameters gd11p(); - - Trajectory pomeron, reggeon; - /// Effective photon squared mass - double m02; - /// Effective pomeron squared mass - double mp2; - /// Effective reggeon squared mass - double mr2; - double q02; - /// Squared QCD scale - double lambda2; - Type type; - }; - - explicit ALLM( const ParametersList& params = ParametersList() ); - ALLM& operator()( double xbj, double q2 ) override; - - private: - Parameters params_; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/BlockDurandHa.cpp b/CepGen/StructureFunctions/BlockDurandHa.cpp index 2ecdf84..485f87d 100644 --- a/CepGen/StructureFunctions/BlockDurandHa.cpp +++ b/CepGen/StructureFunctions/BlockDurandHa.cpp @@ -1,54 +1,74 @@ -#include "CepGen/StructureFunctions/BlockDurandHa.h" - +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/Exception.h" -#include -#include +#include +#include +#include namespace cepgen { namespace strfun { + /// \f$F_2\f$ parameterisation from Block, Durand, and Ha \cite Block:2014kza + class BlockDurandHa : public Parameterisation + { + public: + explicit BlockDurandHa( const ParametersList& params = ParametersList() ); + BlockDurandHa& operator()( double xbj, double q2 ) override; + + private: + std::vector a_, b_, c_; + double n_; + /// Effective mass spread parameter + double lambda_; + /// Asymptotic log-behaviour transition scale factor + double mu2_; + /// Squared effective mass (~VM mass) + double m2_; + }; + BlockDurandHa::BlockDurandHa( const ParametersList& params ) : Parameterisation( params ), a_( params.get >( "a", { 8.205e-4, -5.148e-2, -4.725e-3 } ) ), b_( params.get >( "b", { 2.217e-3, 1.244e-2, 5.958e-4 } ) ), c_( params.get >( "c", { 0.255e0, 1.475e-1 } ) ), n_ ( params.get( "n", 11.49 ) ), lambda_( params.get( "lambda", 2.430 ) ), mu2_ ( params.get( "mu2", 2.82 ) ), m2_ ( params.get( "m2", 0.753 ) ) { assert( a_.size() == 3 ); assert( b_.size() == 3 ); assert( c_.size() == 2 ); } BlockDurandHa& BlockDurandHa::operator()( double xbj, double q2 ) { std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; if ( q2 <= 0 ) { F2 = 0.; return *this; } const double tau = q2 / ( q2 + mu2_ ); const double xl = log1p( q2 / mu2_ ); const double xlx = log( tau/xbj ); const double A = a_[0] + a_[1]*xl + a_[2]*xl*xl; const double B = b_[0] + b_[1]*xl + b_[2]*xl*xl; const double C = c_[0] + c_[1]*xl; const double D = q2*( q2+lambda_*m2_ ) / pow( q2+m2_, 2 ); F2 = D*pow( 1.-xbj, n_ ) * ( C + A*xlx + B*xlx*xlx ); return *this; } } } + +REGISTER_STRFUN( BlockDurandHa, strfun::BlockDurandHa ) diff --git a/CepGen/StructureFunctions/BlockDurandHa.h b/CepGen/StructureFunctions/BlockDurandHa.h deleted file mode 100644 index 089a1a1..0000000 --- a/CepGen/StructureFunctions/BlockDurandHa.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CepGen_StructureFunctions_BlockDurandHa_h -#define CepGen_StructureFunctions_BlockDurandHa_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" -#include - -namespace cepgen -{ - namespace strfun - { - /// \f$F_2\f$ parameterisation from Block, Durand, and Ha \cite Block:2014kza - class BlockDurandHa : public Parameterisation - { - public: - explicit BlockDurandHa( const ParametersList& params = ParametersList() ); - BlockDurandHa& operator()( double xbj, double q2 ) override; - - private: - std::vector a_, b_, c_; - double n_; - /// Effective mass spread parameter - double lambda_; - /// Asymptotic log-behaviour transition scale factor - double mu2_; - /// Squared effective mass (~VM mass) - double m2_; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/CLAS.cpp b/CepGen/StructureFunctions/CLAS.cpp index e9514ae..2362b2f 100644 --- a/CepGen/StructureFunctions/CLAS.cpp +++ b/CepGen/StructureFunctions/CLAS.cpp @@ -1,231 +1,291 @@ -#include "CepGen/StructureFunctions/CLAS.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Event/Particle.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" +#include +#include + namespace cepgen { namespace strfun { + /// \brief CLAS parameterisation for nucleon data at \f$Q^2\f$ > 0.5 GeV\f$^2\f$ and \f$x_{\rm Bj}\f$ > 0.15 + /// \note This code was provided on 2016-04-13 by Silvano Simula and reflects the parameterisation used in \cite Osipenko:2003bu (CLAS) and described in \cite Ricco:1998yr. + class CLAS : public Parameterisation + { + public: + /// List of steering parameters for a physics case + struct Parameters + { + /// Standard parameterisation of a parton-from-neutron emission + static Parameters standard_neutron(); + /// Standard parameterisation of a parton-from-proton emission + static Parameters standard_proton(); + /// Standard parameterisation of a parton-from-deuteron emission + static Parameters standard_deuteron(); + + /// Physical properties associated to a resonance + struct Resonance + { + double amplitude, mass, width; + short angular_momentum; + }; + + enum { neutron = 0, proton = 1, deuteron = 2 } mode; ///< Nucleon type + double mp; ///< Proton mass + double mpi0; ///< Neutral pion mass + // SLAC fit parameters + std::array c_slac; + // CLAS parameterisation + double alpha, beta, mu, mup; + std::array x; + std::array b; + std::vector resonances; + std::array lr; + }; + + /// Standard parameterisation interpolator constructor (photon from proton) + explicit CLAS( const ParametersList& params = ParametersList() ); + + CLAS& operator()( double xbj, double q2 ) override; + + private: + /// \brief Method to evaluate the background/resonance terms of + /// the modulating function for the nucleon + /// \note SLAC parameterisation + std::pair resbkg( double q2, double w ) const; + /// \brief Method to evaluate the deep inelastic structure function + /// \f$F_{2}^{N}\f$ using the SLAC parameterisation + /// \param[in] q2 squared four-momentum transfer in GeV\f$^2\f$ + /// \param[in] xbj Bjorken scaling variable + /// \return \f$F_{2}^{N}\f$ + double f2slac( double xbj, double q2 ) const; + Parameters params_; + static constexpr double COEFF = 6.08974; + }; + CLAS::Parameters CLAS::Parameters::standard_proton() { Parameters params; params.mode = Parameters::proton; params.mp = mp_; params.mpi0 = PDG::get().mass( PDG::piZero ); // SLAC fit parameters params.c_slac = { { 0.25615, 2.1785, 0.89784, -6.7162, 3.7557, 1.6421, 0.37636 } }; // CLAS parameterisation params.x = { { -0.599937, 4.76158, 0.411676 } }; params.b = { { 0.755311, 3.35065, 3.51024, 1.74470 } }; params.alpha = -0.174985; params.beta = 0.00967019; params.mu = -0.0352567; params.mup = 3.51852; Parameters::Resonance r0; r0.amplitude = 1.04; r0.mass = 1.22991; r0.width = 0.106254; r0.angular_momentum = 1; params.resonances.emplace_back( r0 ); Parameters::Resonance r1; r1.amplitude = 0.481327; r1.mass = 1.51015; r1.width = 0.0816620; r1.angular_momentum = 2; params.resonances.emplace_back( r1 ); Parameters::Resonance r2; r2.amplitude = 0.655872; r2.mass = 1.71762; r2.width = 0.125520; r2.angular_momentum = 3; params.resonances.emplace_back( r2 ); Parameters::Resonance r3; r3.amplitude = 0.747338; r3.mass = 1.95381; r3.width = 0.198915; r3.angular_momentum = 2; params.resonances.emplace_back( r3 ); return params; } CLAS::Parameters CLAS::Parameters::standard_neutron() { Parameters params = standard_proton(); params.mode = Parameters::neutron; params.c_slac = { { 0.0640, 0.2250, 4.1060, -7.0790, 3.0550, 1.6421, 0.37636 } }; return params; } CLAS::Parameters CLAS::Parameters::standard_deuteron() { Parameters params = standard_proton(); params.mode = Parameters::deuteron; params.c_slac = { { 0.47709, 2.1602, 3.6274, -10.470, 4.9272, 1.5121, 0.35115 } }; params.x = { { -0.21262, 6.9690, 0.40314 } }; params.b = { { 0.76111, 4.1470, 3.7119, 1.4218 } }; params.alpha = -0.24480; params.beta = 0.014503; params.resonances.clear(); Parameters::Resonance r0; r0.amplitude = 0.74847; r0.mass = 1.2400; r0.width = 0.12115; r0.angular_momentum = 1; params.resonances.emplace_back( r0 ); Parameters::Resonance r1; r1.amplitude = 0.011500; r1.mass = 1.4772; r1.width = 0.0069580; r1.angular_momentum = 2; params.resonances.emplace_back( r1 ); Parameters::Resonance r2; r2.amplitude = 0.12662; r2.mass = 1.5233; r2.width = 0.084095; r2.angular_momentum = 3; params.resonances.emplace_back( r2 ); Parameters::Resonance r3; r3.amplitude = 0.747338; r3.mass = 1.95381; r3.width = 0.198915; r3.angular_momentum = 2; params.resonances.emplace_back( r3 ); return params; } CLAS::CLAS( const ParametersList& params ) : Parameterisation( params ) { const auto& model = params.get( "model", "proton" ); if ( model == "proton" ) params_ = Parameters::standard_proton(); else if ( model == "neutron" ) params_ = Parameters::standard_neutron(); else if ( model == "deuteron" ) params_ = Parameters::standard_deuteron(); else throw CG_FATAL( "CLAS" ) << "Invalid modelling selected: " << model << "!"; } CLAS& CLAS::operator()( double xbj, double q2 ) { std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double mp2 = params_.mp*params_.mp; const double w2 = mp2 + q2*( 1.-xbj )/xbj; const double w_min = params_.mp+params_.mpi0; if ( sqrt( w2 ) < w_min ) { F2 = 0.; return *this; } F2 = f2slac( xbj, q2 ); std::pair rb = resbkg( q2, sqrt( w2 ) ); F2 *= ( rb.first+rb.second ); return *this; } double CLAS::f2slac( double xbj, double q2 ) const { if ( xbj >= 1. ) return 0.; const double xsxb = ( q2+params_.c_slac[6] )/( q2+params_.c_slac[5]*xbj ); const double xs = xbj*xsxb; double f2 = 0.; for ( unsigned short i = 0; i < 5; ++i ) f2 += params_.c_slac[i]*pow( 1.-xs, i ); if ( params_.mode == Parameters::deuteron && xbj > 0. ) f2 /= ( 1.-exp( -7.70*( 1./xbj-1.+params_.mp*params_.mp/q2 ) ) ); return f2 * pow( 1.-xs, 3 ) / xsxb; } std::pair CLAS::resbkg( double q2, double w ) const { const double mp2 = params_.mp*params_.mp, mpi02 = params_.mpi0*params_.mpi0; double wth = params_.mp+params_.mpi0; if ( w < wth ) return std::make_pair( 0., 0. ); if ( w > 4. ) return std::make_pair( 1., 0. ); const double w2 = w*w; double qs = pow( w2+mp2-mpi02, 2 )-4.*mp2*w2; if ( qs <= 0. ) return std::make_pair( 1., 0. ); qs = 0.5 * sqrt( qs )/w; const double omega = 0.5*( w2+q2-mp2 )/params_.mp; const double xn = 0.5*q2/( params_.mp*omega ); const double bkg2 = ( w > params_.b[3] ) ? exp( -params_.b[2]*( w2-params_.b[3]*params_.b[3] ) ) : 1.; double f2bkg = ( params_.b[0] )*( 1.-exp( -params_.b[1]*( w-wth ) ) ) + ( 1.-params_.b[0] )*( 1.-bkg2 ); f2bkg *= ( 1.+( 1.-f2bkg )*( params_.x[0]+params_.x[1]*pow( xn-params_.x[2], 2 ) ) ); double etab = 1., etad = 1.; if ( params_.mode != Parameters::deuteron && q2 <= 2. && w <= 2.5 ) { etab = 1.-2.5*q2*exp( -12.5*q2*q2-50.*( w-1.325 )*( w-1.325 ) ); etad = 1.+2.5*q2*exp( -12.5*q2*q2 ); } f2bkg *= etab; double f2resn = 0.; unsigned short i = 0; for ( const auto& res : params_.resonances ) { const double ai = ( i == 0 ) ? etad * ( res.amplitude + q2*std::min( 0., params_.alpha+params_.beta*q2 ) ) : res.amplitude; const double dmi = ( i == 2 ) ? res.mass * ( 1.+params_.mu/( 1.+params_.mup*q2 ) ) : res.mass; double qs0 = pow( dmi*dmi+mp2-mpi02, 2 )-4.*mp2*dmi*dmi; if ( qs0 <= 0. ) break; qs0 = 0.5*sqrt( qs0 )/dmi; int ji = 2*res.angular_momentum; const double dg = 0.5*res.width*pow( qs/qs0, ji+1 )*( 1.+pow( COEFF*qs0, ji ) )/( 1.+pow( COEFF*qs, ji ) ); f2resn += ai*dg/( ( w-dmi )*( w-dmi )+dg*dg ); ++i; } f2resn *= 0.5*( 1.-params_.b[0] )*bkg2/params_.mp*M_1_PI; return std::make_pair( f2bkg, f2resn ); } } } + +REGISTER_STRFUN( CLAS, strfun::CLAS ) diff --git a/CepGen/StructureFunctions/CLAS.h b/CepGen/StructureFunctions/CLAS.h deleted file mode 100644 index a4cce93..0000000 --- a/CepGen/StructureFunctions/CLAS.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CepGen_StructureFunctions_CLAS_h -#define CepGen_StructureFunctions_CLAS_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -#include -#include - -namespace cepgen -{ - namespace strfun - { - /// \brief CLAS parameterisation for nucleon data at \f$Q^2\f$ > 0.5 GeV\f$^2\f$ and \f$x_{\rm Bj}\f$ > 0.15 - /// \note This code was provided on 2016-04-13 by Silvano Simula and reflects the parameterisation used in \cite Osipenko:2003bu (CLAS) and described in \cite Ricco:1998yr. - class CLAS : public Parameterisation - { - public: - /// List of steering parameters for a physics case - struct Parameters - { - /// Standard parameterisation of a parton-from-neutron emission - static Parameters standard_neutron(); - /// Standard parameterisation of a parton-from-proton emission - static Parameters standard_proton(); - /// Standard parameterisation of a parton-from-deuteron emission - static Parameters standard_deuteron(); - - /// Physical properties associated to a resonance - struct Resonance - { - double amplitude, mass, width; - short angular_momentum; - }; - - enum { neutron = 0, proton = 1, deuteron = 2 } mode; ///< Nucleon type - double mp; ///< Proton mass - double mpi0; ///< Neutral pion mass - // SLAC fit parameters - std::array c_slac; - // CLAS parameterisation - double alpha, beta, mu, mup; - std::array x; - std::array b; - std::vector resonances; - std::array lr; - }; - - /// Standard parameterisation interpolator constructor (photon from proton) - explicit CLAS( const ParametersList& params = ParametersList() ); - - CLAS& operator()( double xbj, double q2 ) override; - - private: - /// \brief Method to evaluate the background/resonance terms of - /// the modulating function for the nucleon - /// \note SLAC parameterisation - std::pair resbkg( double q2, double w ) const; - /// \brief Method to evaluate the deep inelastic structure function - /// \f$F_{2}^{N}\f$ using the SLAC parameterisation - /// \param[in] q2 squared four-momentum transfer in GeV\f$^2\f$ - /// \param[in] xbj Bjorken scaling variable - /// \return \f$F_{2}^{N}\f$ - double f2slac( double xbj, double q2 ) const; - Parameters params_; - static constexpr double COEFF = 6.08974; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/ChristyBosted.cpp b/CepGen/StructureFunctions/ChristyBosted.cpp index 6a0bcdc..9f6e9db 100644 --- a/CepGen/StructureFunctions/ChristyBosted.cpp +++ b/CepGen/StructureFunctions/ChristyBosted.cpp @@ -1,287 +1,363 @@ -#include "CepGen/StructureFunctions/ChristyBosted.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/PDG.h" +#include "CepGen/Physics/Constants.h" #include "CepGen/Core/Exception.h" +#include +#include + namespace cepgen { namespace strfun { + /// \f$F_{2,L}\f$ parameterisation by Christy and Bosted \cite Bosted:2007xd + class ChristyBosted : public Parameterisation + { + public: + struct Parameters + { + static Parameters standard(); + + struct Resonance + { + /// Branching ratios container for resonance decay into single, double pion or eta states + struct BR + { + BR() : singlepi( 0. ), doublepi( 0. ), eta( 0. ) {} + BR( double singlepi, double doublepi, double eta ) : singlepi( singlepi ), doublepi( doublepi ), eta( eta ) {} + bool valid() const { return ( singlepi+doublepi+eta == 1. ); } + /// single pion branching ratio + double singlepi; + /// double pion branching ratio + double doublepi; + /// eta meson branching ratio + double eta; + }; + Resonance() : angular_momentum( 0. ), x0( 0. ), mass( 0. ), width( 0. ), A0_T( 0. ), A0_L( 0. ) {} + double kr() const; + double ecmr( double m2 ) const; + double kcmr() const { return ecmr( 0. ); } + double pcmr( double m2 ) const { return sqrt( std::max( 0., ecmr( m2 )*ecmr( m2 )-m2 ) ); } + BR br; + /// meson angular momentum + double angular_momentum; + /// damping parameter + double x0; + /// mass, in GeV/c2 + double mass; + /// full width, in GeV + double width; + double A0_T; + double A0_L; + std::array fit_parameters; + }; + struct Continuum + { + struct Direction + { + Direction() : sig0( 0. ) {} + Direction( double sig0, const std::vector& params ) : sig0( sig0 ), fit_parameters( params ) {} + double sig0; + std::vector fit_parameters; + }; + std::array transverse; + std::array longitudinal; + }; + double m0; + std::vector resonances; + Continuum continuum; + }; + + explicit ChristyBosted( const ParametersList& params = ParametersList() ); + ChristyBosted& operator()( double xbj, double q2 ) override; + + //--- already computed internally during F2 computation + ChristyBosted& computeFL( double xbj, double q2 ) override { return *this; } + ChristyBosted& computeFL( double xbj, double q2, double r ) override { return *this; } + + private: + double resmod507( char sf, double w2, double q2 ) const; + Parameters params_; + }; + ChristyBosted::ChristyBosted( const ParametersList& params ) : Parameterisation( params ) { const auto& model = params.get( "model", "standard" ); if ( model == "standard" ) params_ = Parameters::standard(); else throw CG_FATAL( "ChristyBosted" ) << "Invalid modelling selected: " << model << "!"; } double ChristyBosted::resmod507( char sf, double w2, double q2 ) const { const double mpi = PDG::get().mass( PDG::piZero ), mpi2 = mpi*mpi, meta = PDG::get().mass( PDG::eta ), meta2 = meta*meta; const double w = sqrt( w2 ); const double xb = q2/( q2+w2-mp2_ ); double m0 = 0., q20 = 0.; if ( sf == 'T' ) // transverse m0 = 0.125, q20 = 0.05; else if ( sf == 'L' ) // longitudinal m0 = params_.m0, q20 = 0.125; else throw CG_FATAL( "ChristyBosted" ) << "Invalid direction retrieved ('" << sf << "')! Aborting."; const double norm_q2 = 1./0.330/0.330; const double t = log( log( ( q2+m0 )*norm_q2 )/log( m0*norm_q2 ) ); //--- calculate kinematics needed for threshold relativistic B-W // equivalent photon energies const double k = 0.5 * ( w2 - mp2_ )/mp_; const double kcm = 0.5 * ( w2 - mp2_ )/w; const double epicm = 0.5 * ( w2 + mpi2 - mp2_ )/w, ppicm = sqrt( std::max( 0., epicm* epicm - mpi2 ) ); const double epi2cm = 0.5 * ( w2 + 4.*mpi2 - mp2_ )/w, ppi2cm = sqrt( std::max( 0., epi2cm*epi2cm - 4*mpi2 ) ); const double eetacm = 0.5 * ( w2 + meta2 - mp2_ )/w, petacm = sqrt( std::max( 0., eetacm*eetacm - meta2 ) ); std::array width, height, pgam; for ( unsigned short i = 0; i < 7; ++i ) { const Parameters::Resonance& res = params_.resonances[i]; width[i] = res.width; //--- calculate partial widths //----- 1-pion decay mode const double x02 = res.x0*res.x0; const double partial_width_singlepi = pow( ppicm /res.pcmr( mpi2 ), 2.*res.angular_momentum+1. ) * pow( ( res.pcmr( mpi2 )*res.pcmr( mpi2 )+x02 )/( ppicm *ppicm +x02 ), res.angular_momentum ); //----- 2-pion decay mode const double partial_width_doublepi = pow( ppi2cm/res.pcmr( 4.*mpi2 ), 2.*( res.angular_momentum+2. ) ) * pow( ( res.pcmr( 4.*mpi2 )*res.pcmr( 4.*mpi2 )+x02 )/( ppi2cm*ppi2cm+x02 ), res.angular_momentum+2 ) * w / res.mass; //----- eta decay mode (only for S11's) const double partial_width_eta = ( res.br.eta == 0. ) ? 0. : pow( petacm/res.pcmr( meta2 ), 2.*res.angular_momentum+1. ) * pow( ( res.pcmr( meta2 )*res.pcmr( meta2 )+x02 )/( petacm*petacm+x02 ), res.angular_momentum ); // virtual photon width pgam[i] = res.width * pow( kcm/res.kcmr(), 2 ) * ( res.kcmr()*res.kcmr()+x02 )/( kcm*kcm+x02 ); width[i] = ( partial_width_singlepi * res.br.singlepi + partial_width_doublepi * res.br.doublepi + partial_width_eta * res.br.eta ) * res.width; //--- resonance Q^2 dependence calculations if ( sf == 'T' ) height[i] = res.A0_T*( 1.+res.fit_parameters[0]*q2/( 1.+res.fit_parameters[1]*q2 ) )/pow( 1.+q2/0.91, res.fit_parameters[2] ); else if ( sf == 'L' ) height[i] = res.A0_L/( 1.+res.fit_parameters[3]*q2 )*q2*exp( -q2*res.fit_parameters[4] ); height[i] = height[i]*height[i]; } //--- calculate Breit-Wigners for all resonances double sig_res = 0.; for ( unsigned short i = 0; i < 7; ++i ) { const Parameters::Resonance& res = params_.resonances[i]; const double mass2 = res.mass*res.mass, width2 = width[i]*width[i]; const double sigr = height[i]*res.kr()/k*res.kcmr()/kcm/res.width * ( width[i]*pgam[i] / ( pow( w2-mass2, 2 ) + mass2*width2 ) ); sig_res += sigr; } sig_res *= w; //--- non-resonant background calculation const double xpr = 1./( 1.+( w2-pow( mp_+mpi, 2 ) )/( q2+q20 ) ); if ( xpr > 1. ) return 0.; double sig_nr = 0.; if ( sf == 'T' ) { // transverse const double wdif = w-( mp_+mpi ); if ( wdif >= 0. ) { for ( unsigned short i = 0; i < 2; ++i ) { const double expo = params_.continuum.transverse[i].fit_parameters[1] + params_.continuum.transverse[i].fit_parameters[2]*q2 + params_.continuum.transverse[i].fit_parameters[3]*q2*q2; sig_nr += params_.continuum.transverse[i].sig0 / pow( q2+params_.continuum.transverse[i].fit_parameters[0], expo ) * pow( wdif, i+1.5 ); } } sig_nr *= xpr; } else if ( sf == 'L' ) { // longitudinal for ( unsigned short i = 0; i < 1; ++i ) { const double expo = params_.continuum.longitudinal[i].fit_parameters[0] + params_.continuum.longitudinal[i].fit_parameters[1]; sig_nr += params_.continuum.longitudinal[i].sig0 * pow( 1.-xpr, expo )/( 1.-xb ) * pow( q2/( q2+q20 ), params_.continuum.longitudinal[i].fit_parameters[2] )/( q2+q20 ) * pow( xpr, params_.continuum.longitudinal[i].fit_parameters[3]+params_.continuum.longitudinal[i].fit_parameters[4]*t ); } } return sig_res + sig_nr; } ChristyBosted::Parameters ChristyBosted::Parameters::standard() { Parameters params; params.m0 = 4.2802; params.continuum.transverse = { { Continuum::Direction( 246.06, { { 0.067469, 1.3501, 0.12054, -0.0038495 } } ), Continuum::Direction( -89.360, { { 0.20977, 1.5715, 0.090736, 0.010362 } } ) } }; params.continuum.longitudinal = { { Continuum::Direction( 86.746, { { 0., 4.0294, 3.1285, 0.33403, 4.9623 } } ) } }; { //--- P33(1232) Resonance p33; p33.br = Resonance::BR( 1., 0., 0. ); p33.angular_momentum = 1.; //p33.x0 = 0.15; p33.x0 = 0.14462; p33.mass = 1.2298; p33.width = 0.13573; p33.fit_parameters = { { 4.2291, 1.2598, 2.1242, 19.910, 0.22587 } }; p33.A0_T = 7.7805; p33.A0_L = 29.414; params.resonances.emplace_back( p33 ); } { //--- S11(1535) Resonance s11_1535; s11_1535.br = Resonance::BR( 0.45, 0.1, 0.45 ); s11_1535.angular_momentum = 0.; s11_1535.x0 = 0.215; s11_1535.mass = 1.5304; s11_1535.width = 0.220; s11_1535.fit_parameters = { { 6823.2, 33521., 2.5686, 0., 0. } }; s11_1535.A0_T = 6.3351; s11_1535.A0_L = 0.; params.resonances.emplace_back( s11_1535 ); } { //--- D13(1520) Resonance d13; d13.br = Resonance::BR( 0.65, 0.35, 0. ); d13.angular_momentum = 2.; d13.x0 = 0.215; d13.mass = 1.5057; d13.width = 0.082956; d13.fit_parameters = { { 21.240, 0.055746, 2.4886, 97.046, 0.31042 } }; d13.A0_T = 0.60347; d13.A0_L = 157.92; params.resonances.emplace_back( d13 ); } { //--- F15(1680) Resonance f15; f15.br = Resonance::BR( 0.65, 0.35, 0. ); f15.angular_momentum = 3.; f15.x0 = 0.215; f15.mass = 1.6980; f15.width = 0.095782; f15.fit_parameters = { { -0.28789, 0.18607, 0.063534, 0.038200, 1.2182 } }; f15.A0_T = 2.3305; f15.A0_L = 4.2160; params.resonances.emplace_back( f15 ); } { //--- S11(1650) Resonance s11_1650; s11_1650.br = Resonance::BR( 0.4, 0.5, 0.1 ); s11_1650.angular_momentum = 0.; s11_1650.x0 = 0.215; s11_1650.mass = 1.6650; s11_1650.width = 0.10936; s11_1650.fit_parameters = { { -0.56175, 0.38964, 0.54883, 0.31393, 2.9997 } }; s11_1650.A0_T = 1.9790; s11_1650.A0_L = 13.764; params.resonances.emplace_back( s11_1650 ); } { //--- P11(1440) roper Resonance p11; p11.br = Resonance::BR( 0.65, 0.35, 0. ); p11.angular_momentum = 1.; p11.x0 = 0.215; p11.mass = 1.4333; p11.width = 0.37944; p11.fit_parameters = { { 46.213, 0.19221, 1.9141, 0.053743, 1.3091 } }; p11.A0_T = 0.022506; p11.A0_L = 5.5124; params.resonances.emplace_back( p11 ); } { //--- F37(1950) Resonance f37; f37.br = Resonance::BR( 0.5, 0.5, 0. ); f37.angular_momentum = 3.; f37.x0 = 0.215; f37.mass = 1.9341; f37.width = 0.380; f37.fit_parameters = { { 0., 0., 1., 1.8951, 0.51376 } }; f37.A0_T = 3.4187; f37.A0_L = 1.8951; params.resonances.emplace_back( f37 ); } return params; } double ChristyBosted::Parameters::Resonance::kr() const { return 0.5 * ( mass*mass-mp2_ ) / mp_; } double ChristyBosted::Parameters::Resonance::ecmr( double m2 ) const { if ( mass == 0. ) return 0.; return 0.5 * ( mass*mass+m2-mp2_ ) / mass; } ChristyBosted& ChristyBosted::operator()( double xbj, double q2 ) { std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double w2 = mp2_ + q2*( 1.-xbj )/xbj; const double w_min = mp_+PDG::get().mass( PDG::piZero ); if ( sqrt( w2 ) < w_min ) { F2 = 0.; return *this; } //----------------------------- // modification of Christy-Bosted at large q2 as described in the LUXqed paper //----------------------------- const double q21 = 30., q20 = 8.; const double delq2 = q2 - q20; const double qq = q21 - q20; const double prefac = 0.25 * M_1_PI*M_1_PI/constants::ALPHA_EM * ( 1.-xbj ); //------------------------------ double q2_eff = q2, w2_eff = w2; if ( q2 > q20 ) { q2_eff = q20 + delq2/( 1.+delq2/qq ); w2_eff = mp2_ + q2_eff*( 1.-xbj )/xbj; } const double tau = 4.*xbj*xbj*mp2_/q2_eff; const double sigT = resmod507( 'T', w2_eff, q2_eff ), sigL = resmod507( 'L', w2_eff, q2_eff ); F2 = prefac * q2_eff / ( 1+tau ) * ( sigT+sigL ) / constants::GEVM2_TO_PB * 1.e6; if ( q2 > q20 ) F2 *= q21/( q21 + delq2 ); if ( sigT != 0. ) Parameterisation::computeFL( q2_eff, xbj, sigL/sigT ); return *this; } } } + +REGISTER_STRFUN( ChristyBosted, strfun::ChristyBosted ) diff --git a/CepGen/StructureFunctions/ChristyBosted.h b/CepGen/StructureFunctions/ChristyBosted.h deleted file mode 100644 index 0525482..0000000 --- a/CepGen/StructureFunctions/ChristyBosted.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef CepGen_StructureFunctions_ChristyBosted_h -#define CepGen_StructureFunctions_ChristyBosted_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" -#include "CepGen/Physics/Constants.h" - -#include -#include - -namespace cepgen -{ - namespace strfun - { - /// \f$F_{2,L}\f$ parameterisation by Christy and Bosted \cite Bosted:2007xd - class ChristyBosted : public Parameterisation - { - public: - struct Parameters - { - static Parameters standard(); - - struct Resonance - { - /// Branching ratios container for resonance decay into single, double pion or eta states - struct BR - { - BR() : singlepi( 0. ), doublepi( 0. ), eta( 0. ) {} - BR( double singlepi, double doublepi, double eta ) : singlepi( singlepi ), doublepi( doublepi ), eta( eta ) {} - bool valid() const { return ( singlepi+doublepi+eta == 1. ); } - /// single pion branching ratio - double singlepi; - /// double pion branching ratio - double doublepi; - /// eta meson branching ratio - double eta; - }; - Resonance() : angular_momentum( 0. ), x0( 0. ), mass( 0. ), width( 0. ), A0_T( 0. ), A0_L( 0. ) {} - double kr() const; - double ecmr( double m2 ) const; - double kcmr() const { return ecmr( 0. ); } - double pcmr( double m2 ) const { return sqrt( std::max( 0., ecmr( m2 )*ecmr( m2 )-m2 ) ); } - BR br; - /// meson angular momentum - double angular_momentum; - /// damping parameter - double x0; - /// mass, in GeV/c2 - double mass; - /// full width, in GeV - double width; - double A0_T; - double A0_L; - std::array fit_parameters; - }; - struct Continuum - { - struct Direction - { - Direction() : sig0( 0. ) {} - Direction( double sig0, const std::vector& params ) : sig0( sig0 ), fit_parameters( params ) {} - double sig0; - std::vector fit_parameters; - }; - std::array transverse; - std::array longitudinal; - }; - double m0; - std::vector resonances; - Continuum continuum; - }; - - explicit ChristyBosted( const ParametersList& params = ParametersList() ); - ChristyBosted& operator()( double xbj, double q2 ) override; - - //--- already computed internally during F2 computation - ChristyBosted& computeFL( double xbj, double q2 ) override { return *this; } - ChristyBosted& computeFL( double xbj, double q2, double r ) override { return *this; } - - private: - double resmod507( char sf, double w2, double q2 ) const; - Parameters params_; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/FioreBrasse.cpp b/CepGen/StructureFunctions/FioreBrasse.cpp index 240c9d5..07807d3 100644 --- a/CepGen/StructureFunctions/FioreBrasse.cpp +++ b/CepGen/StructureFunctions/FioreBrasse.cpp @@ -1,105 +1,134 @@ -#include "CepGen/StructureFunctions/FioreBrasse.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/Constants.h" #include +#include namespace cepgen { namespace strfun { + ///\f${\cal W}_{1,2}\f$ structure functions parameterisation by Fiore et al \cite Fiore:2002re and Brasse et al \cite Brasse:1976bf + class FioreBrasse : public Parameterisation + { + public: + /// General parameters for this modelling + struct Parameters + { + static Parameters standard(); + static Parameters alternative(); + /// Description of a single resonance in the modelling + struct Resonance { + double alpha0, alpha1, alpha2, a, q02; + float spin; + }; + /// All resonances considered in this modelling + std::vector resonances; + double s0, norm; + }; + /// Fiore \cite Fiore:2002re and Brasse \cite Brasse:1976bf proton structure functions + explicit FioreBrasse( const ParametersList& params = ParametersList() ); + FioreBrasse& operator()( double xbj, double q2 ) override; + + private: + Parameters params_; + }; + FioreBrasse::Parameters FioreBrasse::Parameters::standard() { Parameters p; p.s0 = 1.14; p.norm = 0.021; p.resonances.emplace_back( Resonance{ -0.8377, 0.95, 0.1473, 1.0, 2.4617, 3./2. } ); // N*(1520) p.resonances.emplace_back( Resonance{ -0.37, 0.95, 0.1471, 0.5399, 2.4617, 5./2. } ); // N*(1680) p.resonances.emplace_back( Resonance{ 0.0038, 0.85, 0.1969, 4.2225, 1.5722, 3./2. } ); // Δ(1236) p.resonances.emplace_back( Resonance{ 0.5645, 0.1126, 1.3086, 19.2694, 4.5259, 1. } ); // exotic return p; } FioreBrasse::Parameters FioreBrasse::Parameters::alternative() { Parameters p; p.s0 = 1.2871; p.norm = 0.0207; p.resonances.emplace_back( Resonance{ -0.8070, 0.9632, 0.1387, 1.0, 2.6066, 3./2. } ); // N*(1520) p.resonances.emplace_back( Resonance{ -0.3640, 0.9531, 0.1239, 0.6086, 2.6066, 5./2. } ); // N*(1680) p.resonances.emplace_back( Resonance{ -0.0065, 0.8355, 0.2320, 4.7279, 1.4828, 3./2. } ); // Δ(1236) p.resonances.emplace_back( Resonance{ 0.5484, 0.1373, 1.3139, 14.7267, 4.6041, 1. } ); // exotic return p; } FioreBrasse::FioreBrasse( const ParametersList& params ) : Parameterisation( params ) { const auto& model = params.get( "model", "standard" ); if ( model == "standard" ) params_ = Parameters::standard(); else if ( model == "alternative" ) params_ = Parameters::alternative(); else throw CG_FATAL( "FioreBrasse" ) << "Invalid modelling selected: " << model << "!"; } FioreBrasse& FioreBrasse::operator()( double xbj, double q2 ) { std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double akin = 1. + 4.*mp2_ * xbj*xbj/q2; const double prefactor = q2*( 1.-xbj ) / ( 4.*M_PI*constants::ALPHA_EM*akin ); const double s = q2*( 1.-xbj )/xbj + mp2_; double ampli_res = 0., ampli_bg = 0., ampli_tot = 0.; for ( unsigned short i = 0; i < 3; ++i ) { //FIXME 4?? const Parameters::Resonance& res = params_.resonances[i]; const double sqrts0 = sqrt( params_.s0 ); std::complex alpha; if ( s > params_.s0 ) alpha = std::complex( res.alpha0 + res.alpha2*sqrts0 + res.alpha1*s, res.alpha2*sqrt( s-params_.s0 ) ); else alpha = std::complex( res.alpha0 + res.alpha1*s + res.alpha2*( sqrts0 - sqrt( params_.s0 - s ) ), 0. ); double formfactor = 1./pow( 1. + q2/res.q02, 2 ); double denom = pow( res.spin-std::real( alpha ), 2 ) + pow( std::imag( alpha ), 2 ); double ampli_imag = res.a*formfactor*formfactor*std::imag( alpha )/denom; ampli_res += ampli_imag; } { const Parameters::Resonance& res = params_.resonances[3]; double sE = res.alpha2, sqrtsE = sqrt( sE ); std::complex alpha; if ( s > sE ) alpha = std::complex( res.alpha0 + res.alpha1*sqrtsE, res.alpha1*sqrt( s-sE ) ); else alpha = std::complex( res.alpha0 + res.alpha1*( sqrtsE - sqrt( sE-s ) ), 0. ); double formfactor = 1./pow( 1. + q2/res.q02, 2 ); double sp = 1.5*res.spin; double denom = pow( sp-std::real( alpha ), 2 ) + pow( std::imag( alpha ), 2 ); ampli_bg = res.a*formfactor*formfactor*std::imag( alpha )/denom; } ampli_tot = params_.norm*( ampli_res+ampli_bg ); CG_DEBUG_LOOP( "FioreBrasse:amplitudes" ) << "Amplitudes:\n\t" << " resonance part: " << ampli_res << ",\n\t" << " background part: " << ampli_bg << ",\n\t" << " total (with norm.): " << ampli_tot << "."; F2 = prefactor*ampli_tot; return *this; } } } + +REGISTER_STRFUN( FioreBrasse, strfun::FioreBrasse ) diff --git a/CepGen/StructureFunctions/FioreBrasse.h b/CepGen/StructureFunctions/FioreBrasse.h deleted file mode 100644 index 30ca756..0000000 --- a/CepGen/StructureFunctions/FioreBrasse.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef CepGen_StructureFunctions_FioreBrasse_h -#define CepGen_StructureFunctions_FioreBrasse_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -#include - -namespace cepgen -{ - namespace strfun - { - ///\f${\cal W}_{1,2}\f$ structure functions parameterisation by Fiore et al \cite Fiore:2002re and Brasse et al \cite Brasse:1976bf - class FioreBrasse : public Parameterisation - { - public: - /// General parameters for this modelling - struct Parameters - { - static Parameters standard(); - static Parameters alternative(); - /// Description of a single resonance in the modelling - struct Resonance { - double alpha0, alpha1, alpha2, a, q02; - float spin; - }; - /// All resonances considered in this modelling - std::vector resonances; - double s0, norm; - }; - /// Fiore \cite Fiore:2002re and Brasse \cite Brasse:1976bf proton structure functions - explicit FioreBrasse( const ParametersList& params = ParametersList() ); - FioreBrasse& operator()( double xbj, double q2 ) override; - - private: - Parameters params_; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/MSTWGrid.cpp b/CepGen/StructureFunctions/MSTWGrid.cpp index aace5f5..1408ee7 100644 --- a/CepGen/StructureFunctions/MSTWGrid.cpp +++ b/CepGen/StructureFunctions/MSTWGrid.cpp @@ -1,126 +1,162 @@ -#include "CepGen/StructureFunctions/MSTWGrid.h" +#include "CepGen/IO/GridHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include +/// Martin-Stirling-Thorne-Watt PDFs structure functions namespace mstw { - std::shared_ptr Grid::singl_; - - std::shared_ptr - Grid::get( const char* filename ) - { - if ( !singl_ ) - singl_.reset( new Grid( cepgen::ParametersList() - .set( "id", (int)cepgen::strfun::Type::MSTWgrid ) - .set( "gridPath", filename ) ) ); - return singl_; - } - - std::shared_ptr - Grid::get( const cepgen::ParametersList& params ) + /// A \f$F_{2,L}\f$ grid interpolator + class Grid : public cepgen::strfun::Parameterisation, private cepgen::GridHandler<2,2> { - if ( !singl_ ) - singl_.reset( new Grid( params ) ); - return singl_; - } + public: + Grid( const cepgen::ParametersList& params = cepgen::ParametersList() ); + + /// Grid header information as parsed from the file + struct header_t + { + /// Interpolation order + enum order_t : unsigned short { lo = 0, nlo = 1, nnlo = 2 }; + /// Confidence level + enum cl_t : unsigned short { cl68 = 0, cl95 = 1 }; + /// Type of nucleon interpolated + enum nucleon_t : unsigned short { proton = 1, neutron = 2 }; + unsigned int magic; ///< Grid file magic number + order_t order; ///< Interpolation order + cl_t cl; ///< Confidence level + nucleon_t nucleon; ///< Type of nucleon interpolated + }; + /// Structure functions value at a given \f$Q^2/x_{\rm Bj}\f$ coordinate + struct sfval_t + { + float q2; ///< four-momentum transfer, in GeV\f$^2\f$ + float xbj; ///< Bjorken's scaling variable + double f2; ///< Transverse structure function value + double fl; ///< Longitudinal structure function value + }; + + /// Compute the structure functions at a given \f$Q^2/x_{\rm Bj}\f$ + Grid& operator()( double xbj, double q2 ) override; + /// Retrieve the grid's header information + header_t header() const { return header_; } + /// Grid parameterisation object + + //--- already retrieved from grid, so no need to recompute it + Grid& computeFL( double xbj, double q2 ) override { return *this; } + Grid& computeFL( double xbj, double q2, double r ) override { return *this; } + + static constexpr const char* DEFAULT_MSTW_GRID_PATH = "External/mstw_sf_scan_nnlo.dat"; + + private: + std::string description() const override; + static constexpr unsigned int GOOD_MAGIC = 0x5754534d; // MSTW in ASCII + + header_t header_; + }; + + std::ostream& operator<<( std::ostream&, const Grid::sfval_t& ); ///< Human-readable description of a values point + std::ostream& operator<<( std::ostream&, const Grid::header_t::order_t& ); ///< Human-readable description of an interpolation order + std::ostream& operator<<( std::ostream&, const Grid::header_t::cl_t& ); ///< Human-readable description of a confidence level + std::ostream& operator<<( std::ostream&, const Grid::header_t::nucleon_t& ); ///< Human-readable description of a nucleon type Grid::Grid( const cepgen::ParametersList& params ) : cepgen::strfun::Parameterisation( params ), cepgen::GridHandler<2,2>( cepgen::GridType::logarithmic ) { { // file readout part const std::string grid_path = params_.get( "gridPath", DEFAULT_MSTW_GRID_PATH ); std::ifstream file( grid_path, std::ios::binary | std::ios::in ); if ( !file.is_open() ) throw CG_FATAL( "MSTW" ) << "Failed to load grid file \"" << grid_path << "\"!"; file.read( reinterpret_cast( &header_ ), sizeof( header_t ) ); // first checks on the file header if ( header_.magic != GOOD_MAGIC ) throw CG_FATAL( "MSTW" ) << "Wrong magic number retrieved: " << header_.magic << ", expecting " << GOOD_MAGIC << "."; if ( header_.nucleon != header_t::proton ) throw CG_FATAL( "MSTW" ) << "Only proton structure function grids can be retrieved for this purpose!"; // retrieve all points and evaluate grid boundaries sfval_t val; while ( file.read( reinterpret_cast( &val ), sizeof( sfval_t ) ) ) insert( { val.xbj, val.q2 }, { val.f2, val.fl } ); file.close(); } init(); const auto& bounds = boundaries(); CG_DEBUG( "MSTW" ) << "MSTW@" << header_.order << " grid evaluator built " << "for " << header_.nucleon << " structure functions (" << header_.cl << ")\n\t" << "xBj in range [" << pow( 10., bounds[0].first ) << ":" << pow( 10., bounds[0].second ) << "]\n\t" << " Q² in range [" << pow( 10., bounds[1].first ) << ":" << pow( 10., bounds[1].second ) << "]."; } std::string Grid::description() const { std::ostringstream os; const auto& bounds = boundaries(); os << "MSTW(grid){" << pow( 10., bounds[0].first ) << " val = cepgen::GridHandler<2,2>::eval( { xbj, q2 } ); F2 = val[0]; FL = val[1]; return *this; } std::ostream& operator<<( std::ostream& os, const Grid::sfval_t& val ) { return os << cepgen::Form( "xbj = %.4f\tQ² = %.5e GeV²\tF₂ = % .6e\tFₗ = % .6e", val.xbj, val.q2, val.f2, val.fl ); } std::ostream& operator<<( std::ostream& os, const Grid::header_t::order_t& order ) { switch ( order ) { case Grid::header_t::lo: return os << "LO"; case Grid::header_t::nlo: return os << "nLO"; case Grid::header_t::nnlo: return os << "nnLO"; } return os; } std::ostream& operator<<( std::ostream& os, const Grid::header_t::cl_t& cl ) { switch ( cl ) { case Grid::header_t::cl68: return os << "68% C.L."; case Grid::header_t::cl95: return os << "95% C.L."; } return os; } std::ostream& operator<<( std::ostream& os, const Grid::header_t::nucleon_t& nucl ) { switch ( nucl ) { case Grid::header_t::proton: return os << "proton"; case Grid::header_t::neutron: return os << "neutron"; } return os; } } + +REGISTER_STRFUN( MSTWgrid, mstw::Grid ) diff --git a/CepGen/StructureFunctions/MSTWGrid.h b/CepGen/StructureFunctions/MSTWGrid.h deleted file mode 100644 index 01ef2e2..0000000 --- a/CepGen/StructureFunctions/MSTWGrid.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef CepGen_StructureFunctions_MSTWGrid_h -#define CepGen_StructureFunctions_MSTWGrid_h - -#include "CepGen/IO/GridHandler.h" -#include "CepGen/StructureFunctions/StructureFunctions.h" - -/// Martin-Stirling-Thorne-Watt PDFs structure functions -namespace mstw -{ - /// A \f$F_{2,L}\f$ grid interpolator - class Grid : public cepgen::strfun::Parameterisation, private cepgen::GridHandler<2,2> - { - public: - /// Grid header information as parsed from the file - struct header_t - { - /// Interpolation order - enum order_t : unsigned short { lo = 0, nlo = 1, nnlo = 2 }; - /// Confidence level - enum cl_t : unsigned short { cl68 = 0, cl95 = 1 }; - /// Type of nucleon interpolated - enum nucleon_t : unsigned short { proton = 1, neutron = 2 }; - unsigned int magic; ///< Grid file magic number - order_t order; ///< Interpolation order - cl_t cl; ///< Confidence level - nucleon_t nucleon; ///< Type of nucleon interpolated - }; - /// Structure functions value at a given \f$Q^2/x_{\rm Bj}\f$ coordinate - struct sfval_t - { - float q2; ///< four-momentum transfer, in GeV\f$^2\f$ - float xbj; ///< Bjorken's scaling variable - double f2; ///< Transverse structure function value - double fl; ///< Longitudinal structure function value - }; - static constexpr const char* DEFAULT_MSTW_GRID_PATH = "External/mstw_sf_scan_nnlo.dat"; - - public: - /// Retrieve the grid interpolator (singleton) - static std::shared_ptr get( const char* path = DEFAULT_MSTW_GRID_PATH ); - /// Retrieve the grid interpolator (singleton) - static std::shared_ptr get( const cepgen::ParametersList& params = cepgen::ParametersList() ); - - /// Compute the structure functions at a given \f$Q^2/x_{\rm Bj}\f$ - Grid& operator()( double xbj, double q2 ) override; - /// Retrieve the grid's header information - header_t header() const { return header_; } - /// Grid parameterisation object - - //--- already retrieved from grid, so no need to recompute it - Grid& computeFL( double xbj, double q2 ) override { return *this; } - Grid& computeFL( double xbj, double q2, double r ) override { return *this; } - - public: - Grid( const Grid& ) = delete; - void operator=( const GridHandler& ) = delete; - - private: - explicit Grid( const cepgen::ParametersList& = cepgen::ParametersList() ); - std::string description() const override; - static constexpr unsigned int GOOD_MAGIC = 0x5754534d; // MSTW in ASCII - static std::shared_ptr singl_; - - header_t header_; - }; - - std::ostream& operator<<( std::ostream&, const Grid::sfval_t& ); ///< Human-readable description of a values point - std::ostream& operator<<( std::ostream&, const Grid::header_t::order_t& ); ///< Human-readable description of an interpolation order - std::ostream& operator<<( std::ostream&, const Grid::header_t::cl_t& ); ///< Human-readable description of a confidence level - std::ostream& operator<<( std::ostream&, const Grid::header_t::nucleon_t& ); ///< Human-readable description of a nucleon type -} - -#endif - diff --git a/CepGen/StructureFunctions/Partonic.cpp b/CepGen/StructureFunctions/Partonic.cpp index 3ff35e8..af89afa 100644 --- a/CepGen/StructureFunctions/Partonic.cpp +++ b/CepGen/StructureFunctions/Partonic.cpp @@ -1,174 +1,211 @@ -#include "CepGen/StructureFunctions/Partonic.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" -#ifdef LIBLHAPDF -# if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 -# define LHAPDF_GE_6 1 -# endif +#include "LHAPDF/LHAPDF.h" + +#if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 +# define LHAPDF_GE_6 1 #endif +#include +#include + namespace cepgen { namespace strfun { + /// Generic partonic level perturbative structure functions built from an external PDFs grid + class Partonic : public Parameterisation + { + public: + /// Quarks types + enum class Mode { full = 0, valence = 1, sea = 2 }; + /// Build a calculator from its Parameters object + explicit Partonic( const ParametersList& params = ParametersList() ); + /// Build a calculator from a set, its member, and the contributing quarks + explicit Partonic( const char* set, unsigned short member = 0, const Mode& mode = Mode::full ); + Partonic& operator()( double xbj, double q2 ) override; + + private: + std::string description() const override; + void initialise(); + /// String-type PDF identifier (default) + std::string pdf_set_; + /// Number of quark flavours considered in the SF building + unsigned short num_flavours_; + /// Integer-type PDF identifier (if no string version is provided) + int pdf_code_; + /// PDF set used + int pdf_member_; + /// Quarks types considered in the SF building + Mode mode_; + bool initialised_; + +#if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION >= 6 + LHAPDF::PDFSet lha_pdf_set_; + std::vector > pdfs_; +#endif + static constexpr std::array QUARK_PDGS = { { 1, 2, 3, 4, 5, 6 } }; + static constexpr std::array Q_TIMES_3 = { { + -1 /*d*/, 2 /*u*/, + -1 /*s*/, 2 /*c*/, + -1 /*b*/, 2 /*t*/ + } }; + }; + constexpr std::array Partonic::Q_TIMES_3, Partonic::QUARK_PDGS; + std::ostream& + operator<<( std::ostream& os, const strfun::Partonic::Mode& mode ) + { + switch ( mode ) { + case strfun::Partonic::Mode::full: + return os << "all quarks"; + case strfun::Partonic::Mode::valence: + return os << "valence quarks"; + case strfun::Partonic::Mode::sea: + return os << "sea quarks"; + } + return os; + } + Partonic::Partonic( const ParametersList& params ) : Parameterisation( params ), pdf_set_ ( params.get( "pdfSet", "cteq6" ) ), num_flavours_( params.get( "numFlavours", 4 ) ), pdf_code_ ( params.get( "pdfCode", 0 ) ), pdf_member_ ( params.get( "pdfMember", 0 ) ), mode_ ( (Mode)params.get( "mode", (int)Mode::full ) ), initialised_( false ) {} Partonic::Partonic( const char* set, unsigned short member, const Mode& mode ) : Parameterisation( ParametersList().set( "id", (int)Type::Partonic ) ), pdf_set_( set ), num_flavours_( 4 ), pdf_code_( 0 ), pdf_member_( member ), mode_( mode ), initialised_( false ) {} std::string Partonic::description() const { std::ostringstream os; os << "Partonic{" << pdf_set_ << ",m=" << pdf_member_ << ",mode=" << mode_ << "}"; return os.str(); } void Partonic::initialise() { if ( initialised_ ) return; -#ifdef LIBLHAPDF std::string lhapdf_version, pdf_description, pdf_type; -# ifdef LHAPDF_GE_6 +#ifdef LHAPDF_GE_6 try { //--- check if PDF code is set - if ( pdf_code_ != 0l ) { + if ( pdf_code_ != 0 ) { auto pdf = LHAPDF::lookupPDF( pdf_code_ ); if ( pdf.second != 0 ) throw CG_FATAL( "Partonic" ) << "Failed to retrieve PDFset with id=" << pdf_code_ << "!"; if ( !pdf_set_.empty() && pdf_set_ != pdf.first ) CG_WARNING( "Partonic" ) << "PDF set name changed from \"" << pdf_set_ << "\" to \"" << pdf.first << "\"."; pdf_set_ = pdf.first; } lha_pdf_set_ = LHAPDF::PDFSet( pdf_set_ ); lha_pdf_set_.mkPDFs >( pdfs_ ); lhapdf_version = LHAPDF::version(); pdf_description = lha_pdf_set_.description(); pdf_type = pdfs_[pdf_member_]->type(); } catch ( const LHAPDF::Exception& e ) { throw CG_FATAL( "Partonic" ) << "Caught LHAPDF exception:\n\t" << e.what(); } -# else - if ( pdf_code_ != 0l ) - LHAPDF::initPDFSet( (int)pdf_code_, pdf_member_ ); +#else + if ( pdf_code_ != 0 ) + LHAPDF::initPDFSet( pdf_code_, pdf_member_ ); else LHAPDF::initPDFSet( pdf_set_, LHAPDF::LHGRID, pdf_member_ ); lhapdf_version = LHAPDF::getVersion(); -# endif +#endif replace_all( pdf_description, ". ", ".\n " ); CG_INFO( "Partonic" ) << "Partonic structure functions evaluator successfully built.\n" << " * LHAPDF version: " << lhapdf_version << "\n" << " * number of flavours: " << num_flavours_ << "\n" << " * quarks mode: " << mode_ << "\n" << " * PDF set: " << pdf_set_ << "\n" << " * PDF member: " << pdf_member_ << ( pdf_type.empty() ? "" : " ("+pdf_type+")" ) << "\n" -# ifdef LHAPDF_GE_6 +#ifdef LHAPDF_GE_6 << ( pdf_description.empty() ? "" : " "+pdf_description ); -# else - ; LHAPDF::getDescription(); -# endif - initialised_ = true; #else - throw CG_FATAL( "Partonic" ) << "LHAPDF is not liked to this instance!"; + ; LHAPDF::getDescription(); #endif + initialised_ = true; } Partonic& Partonic::operator()( double xbj, double q2 ) { -#ifdef LIBLHAPDF std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; F2 = 0.; if ( num_flavours_ == 0 || num_flavours_ > 6 ) return *this; if ( !initialised_ ) initialise(); -# ifdef LHAPDF_GE_6 +#ifdef LHAPDF_GE_6 auto& member = *pdfs_[pdf_member_]; if ( !member.inPhysicalRangeXQ2( xbj, q2 ) ) { CG_WARNING( "Partonic" ) << "(x=" << xbj << ", Q²=" << q2 << " GeV²) " << "not in physical range for PDF member " << pdf_member_ << ":\n\t" << " min: (x=" << member.xMin() << ", Q²=" << member.q2Min() << "),\n\t" << " max: (x=" << member.xMax() << ", Q²=" << member.q2Max() << ")."; return *this; } -# else +#else if ( q2 < LHAPDF::getQ2min( pdf_member_ ) || q2 > LHAPDF::getQ2max( pdf_member_ ) || xbj < LHAPDF::getXmin( pdf_member_ ) || xbj > LHAPDF::getXmax( pdf_member_ ) ) { CG_WARNING( "Partonic" ) << "(x=" << xbj << "/Q²=" << q2 << " GeV²) " << "not in physical range for PDF member " << pdf_member_ << ":\n" << " min: (x=" << LHAPDF::getXmin( pdf_member_ ) << "/Q²=" << LHAPDF::getQ2min( pdf_member_ ) << "),\n" << " max: (x=" << LHAPDF::getXmax( pdf_member_ ) << "/Q²=" << LHAPDF::getQ2max( pdf_member_ ) << ")."; return *this; } const double q = sqrt( q2 ); -# endif +#endif for ( int i = 0; i < num_flavours_; ++i ) { const double prefactor = 1./9.*Q_TIMES_3[i]*Q_TIMES_3[i]; -# ifdef LHAPDF_GE_6 +#ifdef LHAPDF_GE_6 if ( !pdfs_[pdf_member_]->hasFlavor( QUARK_PDGS[i] ) ) throw CG_FATAL( "Partonic" ) << "Flavour " << QUARK_PDGS[i] << " is unsupported!"; const double xq = member.xfxQ2( QUARK_PDGS[i], xbj, q2 ); const double xqbar = member.xfxQ2( -QUARK_PDGS[i], xbj, q2 ); -# else +#else const double xq = LHAPDF::xfx( xbj, q, QUARK_PDGS[i] ); const double xqbar = LHAPDF::xfx( xbj, q, -QUARK_PDGS[i] ); -# endif +#endif switch ( mode_ ) { case Mode::full: F2 += prefactor*( xq+xqbar ); break; case Mode::valence: F2 += prefactor*( xq-xqbar ); break; case Mode::sea: F2 += prefactor*( 2.*xqbar ); break; } } -#else - throw CG_FATAL( "Partonic" ) << "LHAPDF is not liked to this instance!"; -#endif - return *this; } } - - std::ostream& - operator<<( std::ostream& os, const strfun::Partonic::Mode& mode ) - { - switch ( mode ) { - case strfun::Partonic::Mode::full: return os << "all quarks"; - case strfun::Partonic::Mode::valence: return os << "valence quarks"; - case strfun::Partonic::Mode::sea: return os << "sea quarks"; - } - return os; - } } #ifdef LHAPDF_GE_6 # undef LHAPDF_GE_6 #endif +REGISTER_STRFUN( Partonic, strfun::Partonic ) diff --git a/CepGen/StructureFunctions/Partonic.h b/CepGen/StructureFunctions/Partonic.h deleted file mode 100644 index 3e48476..0000000 --- a/CepGen/StructureFunctions/Partonic.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef CepGen_StructureFunctions_Partonic_h -#define CepGen_StructureFunctions_Partonic_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -#ifdef LIBLHAPDF -#include "LHAPDF/LHAPDF.h" -#endif - -#include - -namespace cepgen -{ - namespace strfun - { - /// Generic partonic level perturbative structure functions built from an external PDFs grid - class Partonic : public Parameterisation - { - public: - /// Quarks types - enum class Mode { full = 0, valence = 1, sea = 2 }; - /// Build a calculator from its Parameters object - explicit Partonic( const ParametersList& params = ParametersList() ); - /// Build a calculator from a set, its member, and the contributing quarks - explicit Partonic( const char* set, unsigned short member = 0, const Mode& mode = Mode::full ); - Partonic& operator()( double xbj, double q2 ) override; - - private: - std::string description() const override; - void initialise(); - /// String-type PDF identifier (default) - std::string pdf_set_; - /// Number of quark flavours considered in the SF building - unsigned short num_flavours_; - /// Integer-type PDF identifier (if no string version is provided) - unsigned long pdf_code_; - /// PDF set used - unsigned short pdf_member_; - /// Quarks types considered in the SF building - Mode mode_; - bool initialised_; - -#ifdef LIBLHAPDF -# if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION >= 6 - LHAPDF::PDFSet lha_pdf_set_; - std::vector > pdfs_; -# endif -#endif - static constexpr std::array QUARK_PDGS = { { 1, 2, 3, 4, 5, 6 } }; - static constexpr std::array Q_TIMES_3 = { { - -1 /*d*/, 2 /*u*/, - -1 /*s*/, 2 /*c*/, - -1 /*b*/, 2 /*t*/ - } }; - }; - } - std::ostream& operator<<( std::ostream& os, const strfun::Partonic::Mode& mode ); -} - -#endif - diff --git a/CepGen/StructureFunctions/Schaefer.cpp b/CepGen/StructureFunctions/Schaefer.cpp index f831b3f..7ae5966 100644 --- a/CepGen/StructureFunctions/Schaefer.cpp +++ b/CepGen/StructureFunctions/Schaefer.cpp @@ -1,113 +1,145 @@ -#include "CepGen/StructureFunctions/Schaefer.h" -#include "CepGen/StructureFunctions/Partonic.h" - +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/Exception.h" - #include "CepGen/Physics/Constants.h" +#include +#include + namespace cepgen { namespace strfun { + /// LUX-like hybrid modelling of \f$F_{2,L}\f$ structure functions + class Schaefer : public Parameterisation + { + public: + explicit Schaefer( const ParametersList& params = ParametersList() ); + Schaefer& operator()( double xbj, double q2 ) override; + + private: + std::string description() const override; + double rho( double w2 ) const; + void initialise(); + /// Transition \f$Q^2\f$ before reaching the continuum/perturbative regions + double q2_cut_; + /// Transition \f$W^2\f$ between: + /// - resonances and hybrid continuum/resonances low-\f$Q^2\f$ regions, + /// - hybrid continuum/resonances and continuum low-\f$Q^2\f$ regions, or + /// - continuum and perturbative high-\f$Q^2\f$ regions + std::vector w2_lim_; + /// Enable/disable the HT correction + bool higher_twist_; + /// Resonances-dominated region (low-\f$Q^2/W^2\f$) modelling + std::shared_ptr resonances_model_; + /// Perturbative region (high-\f$Q^2/W^2\f$) modelling + std::shared_ptr perturbative_model_; + /// Continuum regions modelling + std::shared_ptr continuum_model_; + bool initialised_; + double inv_omega_range_; + }; + Schaefer::Schaefer( const ParametersList& params ) : Parameterisation( params ), q2_cut_( params.get( "Q2cut", 9. ) ), w2_lim_( params.get >( "W2limits", { 3., 4. } ) ), higher_twist_( params.get( "higherTwist", true ) ), - resonances_model_ ( Parameterisation::build( params.get( "resonancesSF", ParametersList().set( "id", (int)Type::ChristyBosted ) ) ) ), - perturbative_model_( Parameterisation::build( params.get( "perturbativeSF", ParametersList().set( "id", (int)Type::MSTWgrid ) ) ) ), - continuum_model_ ( Parameterisation::build( params.get( "continuumSF", ParametersList().set( "id", (int)Type::GD11p ) ) ) ), + resonances_model_ ( StructureFunctionsHandler::get().build( params.get( "resonancesSF", ParametersList().set( "id", (int)Type::ChristyBosted ) ) ) ), + perturbative_model_( StructureFunctionsHandler::get().build( params.get( "perturbativeSF", ParametersList().set( "id", (int)Type::MSTWgrid ) ) ) ), + continuum_model_ ( StructureFunctionsHandler::get().build( params.get( "continuumSF", ParametersList().set( "id", (int)Type::GD11p ) ) ) ), initialised_( false ), inv_omega_range_( -1. ) {} std::string Schaefer::description() const { std::ostringstream os; os << "LUXlike{" << "r=" << resonances_model_->description() << "," << "p=" << perturbative_model_->description() << "," << "c=" << continuum_model_->description(); if ( higher_twist_ ) os << ",HT"; os << "}"; return os.str(); } void Schaefer::initialise() { CG_DEBUG( "LUXlike" ) << "LUXlike structure functions evaluator successfully initialised.\n" << " * Q² cut: " << q2_cut_ << " GeV²\n" << " * W² ranges: " << w2_lim_.at( 0 ) << " GeV² / " << w2_lim_.at( 1 ) << " GeV²\n" << " * resonance model: " << *resonances_model_ << "\n" << " * perturbative model: " << *perturbative_model_ << "\n" << " * continuum model: " << *continuum_model_ << "\n" << " * higher-twist? " << std::boolalpha << higher_twist_; inv_omega_range_ = 1./( w2_lim_.at( 1 )-w2_lim_.at( 0 ) ); initialised_ = true; } Schaefer& Schaefer::operator()( double xbj, double q2 ) { if ( !initialised_ ) initialise(); std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double w2 = mp2_+q2*( 1.-xbj )/xbj; strfun::Parameterisation sel_sf; if ( q2 < q2_cut_ ) { if ( w2 < w2_lim_.at( 0 ) ) sel_sf = ( *resonances_model_ )( xbj, q2 ); else if ( w2 < w2_lim_.at( 1 ) ) { auto sf_r = ( *resonances_model_ )( xbj, q2 ); auto sf_c = ( *continuum_model_ )( xbj, q2 ); sf_r.computeFL( xbj, q2 ); sf_c.computeFL( xbj, q2 ); const double r = rho( w2 ); F2 = r*sf_c.F2 + ( 1.-r )*sf_r.F2; FL = r*sf_c.FL + ( 1.-r )*sf_r.FL; return *this; } else sel_sf = ( *continuum_model_ )( xbj, q2 ); } else { if ( w2 < w2_lim_.at( 1 ) ) sel_sf = ( *continuum_model_ )( xbj, q2 ); else { auto sf_p = ( *perturbative_model_ )( xbj, q2 ); F2 = sf_p.F2; sf_p.computeFL( xbj, q2 ); FL = sf_p.FL; if ( higher_twist_ ) F2 *= ( 1.+5.5/q2 ); return *this; } } F2 = sel_sf( xbj, q2 ).F2; sel_sf.computeFL( xbj, q2 ); FL = sel_sf.FL; return *this; } double Schaefer::rho( double w2 ) const { if ( inv_omega_range_ <= 0. ) throw CG_FATAL( "LUXlike" ) << "Invalid W² limits: " << w2_lim_.at( 0 ) << " / " << w2_lim_.at( 1 ) << " GeV²!"; const double omega = ( w2-w2_lim_.at( 0 ) )*inv_omega_range_; const double omega2 = omega*omega; return 2.*omega2-omega*omega; } } } + +REGISTER_STRFUN( Schaefer, strfun::Schaefer ) diff --git a/CepGen/StructureFunctions/Schaefer.h b/CepGen/StructureFunctions/Schaefer.h deleted file mode 100644 index 5d8a60c..0000000 --- a/CepGen/StructureFunctions/Schaefer.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CepGen_StructureFunctions_Schaefer_h -#define CepGen_StructureFunctions_Schaefer_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -#include -#include - -namespace cepgen -{ - namespace strfun - { - /// LUX-like hybrid modelling of \f$F_{2,L}\f$ structure functions - class Schaefer : public Parameterisation - { - public: - explicit Schaefer( const ParametersList& params = ParametersList() ); - Schaefer& operator()( double xbj, double q2 ) override; - - private: - std::string description() const override; - double rho( double w2 ) const; - void initialise(); - /// Transition \f$Q^2\f$ before reaching the continuum/perturbative regions - double q2_cut_; - /// Transition \f$W^2\f$ between: - /// - resonances and hybrid continuum/resonances low-\f$Q^2\f$ regions, - /// - hybrid continuum/resonances and continuum low-\f$Q^2\f$ regions, or - /// - continuum and perturbative high-\f$Q^2\f$ regions - std::vector w2_lim_; - /// Enable/disable the HT correction - bool higher_twist_; - /// Resonances-dominated region (low-\f$Q^2/W^2\f$) modelling - std::shared_ptr resonances_model_; - /// Perturbative region (high-\f$Q^2/W^2\f$) modelling - std::shared_ptr perturbative_model_; - /// Continuum regions modelling - std::shared_ptr continuum_model_; - bool initialised_; - double inv_omega_range_; - }; - } -} - -#endif diff --git a/CepGen/StructureFunctions/StructureFunctions.cpp b/CepGen/StructureFunctions/StructureFunctions.cpp index d073add..39ac512 100644 --- a/CepGen/StructureFunctions/StructureFunctions.cpp +++ b/CepGen/StructureFunctions/StructureFunctions.cpp @@ -1,85 +1,109 @@ #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/StructureFunctions/SigmaRatio.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" namespace cepgen { namespace strfun { const double Parameterisation::mp_ = PDG::get().mass( PDG::proton ); const double Parameterisation::mp2_ = Parameterisation::mp_*Parameterisation::mp_; Parameterisation::Parameterisation( double f2, double fl ) : type( Type::Invalid ), F2( f2 ), FL( fl ), old_vals_({ 0., 0. }), r_ratio_( new sigrat::E143 ) {} Parameterisation::Parameterisation( const Parameterisation& sf ) : type( sf.type ), F2( sf.F2 ), FL( sf.FL ), params_( sf.params_ ), old_vals_( sf.old_vals_ ), r_ratio_( sf.r_ratio_ ) {} Parameterisation::Parameterisation( const ParametersList& params ) : type( (Type)params.get( "id" ) ), F2( 0. ), FL( 0. ), params_( params ), old_vals_({ 0., 0. }), r_ratio_( sigrat::Parameterisation::build( params.get( "sigmaRatio", ParametersList().set( "id", (int)sigrat::Type::E143 ) ) ) ) {} double Parameterisation::F1( double xbj, double q2 ) const { if ( xbj == 0. || q2 == 0. ) { CG_WARNING( "StructureFunctions:F1" ) << "Invalid range for Q² = " << q2 << " or xBj = " << xbj << "."; return 0.; } const double F1 = 0.5*( ( 1+4.*xbj*xbj*mp2_/q2 )*F2 - FL )/xbj; CG_DEBUG_LOOP( "StructureFunctions:F1" ) << "F1 for Q² = " << q2 << ", xBj = " << xbj << ": " << F1 << "\n\t" << "(F2 = " << F2 << ", FL = " << FL << ")."; return F1; } Parameterisation& Parameterisation::computeFL( double xbj, double q2 ) { if ( !r_ratio_ ) throw CG_FATAL( "StructureFunctions:FL" ) << "Failed to retrieve a R-ratio calculator!"; double r_error = 0.; return computeFL( xbj, q2, (*r_ratio_)( xbj, q2, r_error ) ); } Parameterisation& Parameterisation::computeFL( double xbj, double q2, double r ) { const double tau = 4.*xbj*xbj*mp2_/q2; FL = F2 * ( 1.+tau ) * ( r/( 1.+r ) ); return *this; } std::string Parameterisation::description() const { std::ostringstream os; os << type; return os.str(); } std::ostream& operator<<( std::ostream& os, const Parameterisation& sf ) { os << sf.description(); if ( sf.old_vals_ != std::pair() ) os << " at (" << sf.old_vals_.first << ", " << sf.old_vals_.second << "): " << "F2 = " << sf.F2 << ", FL = " << sf.FL; return os; } } + /// Human-readable format of a structure function type + std::ostream& + operator<<( std::ostream& os, const strfun::Type& sf ) + { + switch ( sf ) { + case strfun::Type::Invalid: return os << "[INVALID]"; + case strfun::Type::Electron: return os << "electron"; + case strfun::Type::ElasticProton: return os << "elastic proton"; + case strfun::Type::SuriYennie: return os << "Suri-Yennie"; + case strfun::Type::SzczurekUleshchenko: return os << "Szczurek-Uleshchenko"; + case strfun::Type::FioreBrasse: return os << "Fiore-Brasse"; + case strfun::Type::ChristyBosted: return os << "Christy-Bosted"; + case strfun::Type::CLAS: return os << "CLAS"; + case strfun::Type::BlockDurandHa: return os << "BDH"; + case strfun::Type::ALLM91: return os << "ALLM91"; + case strfun::Type::ALLM97: return os << "ALLM97"; + case strfun::Type::GD07p: return os << "GD07p"; + case strfun::Type::GD11p: return os << "GD11p"; + case strfun::Type::Schaefer: return os << "LUXlike"; + case strfun::Type::MSTWgrid: return os << "MSTW (grid)"; + case strfun::Type::Partonic: return os << "Partonic"; + } + return os; + } } diff --git a/CepGen/StructureFunctions/StructureFunctions.h b/CepGen/StructureFunctions/StructureFunctions.h index 657bedf..a4e2b17 100644 --- a/CepGen/StructureFunctions/StructureFunctions.h +++ b/CepGen/StructureFunctions/StructureFunctions.h @@ -1,95 +1,105 @@ #ifndef CepGen_StructureFunctions_StructureFunctions_h #define CepGen_StructureFunctions_StructureFunctions_h -#include "CepGen/Core/ParametersList.h" +#include "CepGen/Core/ModuleFactory.h" #include #include namespace cepgen { - class ParametersList; namespace sigrat { class Parameterisation; } /// Structure functions modelling scope namespace strfun { /// Proton structure function to be used in the outgoing state description /// \note Values correspond to the LPAIR legacy steering card values enum struct Type { Invalid = 0, Electron = 1, ElasticProton = 2, SuriYennie = 11, SzczurekUleshchenko = 12, BlockDurandHa = 13, FioreBrasse = 101, ChristyBosted = 102, CLAS = 103, ALLM91 = 201, ALLM97 = 202, GD07p = 203, GD11p = 204, MSTWgrid = 205, Schaefer = 301, Partonic = 401, }; /// Generic placeholder for the parameterisation of nucleon structure functions class Parameterisation { public: /// Standard SF parameterisation constructor Parameterisation( double f2 = 0., double fl = 0. ); /// Copy constructor Parameterisation( const Parameterisation& ); Parameterisation( const ParametersList& ); ~Parameterisation() {} /// Assign from another SF parameterisation object Parameterisation& operator=( const Parameterisation& sf ) { type = sf.type, F2 = sf.F2, FL = sf.FL, old_vals_ = sf.old_vals_; return *this; } /// Human-readable dump of the SF parameterisation at this (xBj,Q^2) value friend std::ostream& operator<<( std::ostream&, const Parameterisation& ); /// Human-readable description of this SF parameterisation virtual std::string description() const; ///< Human-readable description of this SF set - /// Build a SF parameterisation for a given type - static std::shared_ptr build( const ParametersList& ); - /// Build a SF parameterisation for a given type - static std::shared_ptr build( const Type& type, const ParametersList& params = ParametersList() ); - /// Set of parameters used to build this parameterisation const ParametersList& parameters() const { return params_; } /// Compute all relevant structure functions for a given \f$(x_{\rm Bj},Q^2)\f$ couple virtual Parameterisation& operator()( double /*xbj*/, double /*q2*/ ) { return *this; } /// Compute the longitudinal structure function for a given point virtual Parameterisation& computeFL( double xbj, double q2 ); /// Compute the longitudinal structure function for a given point virtual Parameterisation& computeFL( double xbj, double q2, double r ); /// Compute the \f$F_1\f$ structure function for a given point double F1( double xbj, double q2 ) const; public: /// Interpolation type of structure functions Type type; double F2; ///< Last computed transverse structure function value double FL; ///< Last computed longitudinal structure function value protected: static const double mp_; ///< Proton mass, in GeV/c\f$^2\f$ static const double mp2_; ///< Squared proton mass, in GeV\f$^2\f$/c\f$^4\f$ ParametersList params_; ///< List of parameters used for this builder definition std::pair old_vals_; ///< Last \f$(x_{\rm Bj},Q^2)\f$ couple computed /// Longitudinal/transverse cross section ratio parameterisation used to compute \f$F_{1/L}\f$ std::shared_ptr r_ratio_; }; + /// A structure functions parameterisations factory + typedef ModuleFactory StructureFunctionsHandler; } /// Human-readable description of this SF parameterisation type std::ostream& operator<<( std::ostream&, const strfun::Type& ); } -#endif +/// Add a structure functions definition to the list of handled parameterisation +#define REGISTER_STRFUN( id, obj ) \ + namespace cepgen { \ + struct BUILDERNM( id ) { \ + BUILDERNM( id )() { strfun::StructureFunctionsHandler::get().registerModule( (int)strfun::Type::id ); } }; \ + static BUILDERNM( id ) g ## id; \ + } +/// Add a structure functions definition (with its associated default parameters) to the list of handled parameterisation +#define REGISTER_STRFUN_PARAMS( id, obj, params ) \ + namespace cepgen { \ + struct BUILDERNM( id ) { \ + BUILDERNM( id )() { strfun::StructureFunctionsHandler::get().registerModule( (int)strfun::Type::id, params ); } }; \ + static BUILDERNM( id ) g ## id; \ + } +#endif diff --git a/CepGen/StructureFunctions/StructureFunctionsBuilder.cpp b/CepGen/StructureFunctions/StructureFunctionsBuilder.cpp deleted file mode 100644 index cff696b..0000000 --- a/CepGen/StructureFunctions/StructureFunctionsBuilder.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "CepGen/Core/ParametersList.h" - -#include "CepGen/StructureFunctions/ALLM.h" -#include "CepGen/StructureFunctions/BlockDurandHa.h" -#include "CepGen/StructureFunctions/FioreBrasse.h" -#include "CepGen/StructureFunctions/ChristyBosted.h" -#include "CepGen/StructureFunctions/CLAS.h" -#include "CepGen/StructureFunctions/Partonic.h" -#include "CepGen/StructureFunctions/SuriYennie.h" -#include "CepGen/StructureFunctions/SzczurekUleshchenko.h" -#include "CepGen/StructureFunctions/Schaefer.h" -#include "CepGen/StructureFunctions/MSTWGrid.h" - -namespace cepgen -{ - namespace strfun - { - std::shared_ptr - Parameterisation::build( const Type& type, const ParametersList& params ) - { - ParametersList pcopy = params; - return build( pcopy.set( "id", (int)type ) ); - } - - std::shared_ptr - Parameterisation::build( const ParametersList& params ) - { - ParametersList pcopy = params; - switch ( (Type)params.get( "id" ) ) { - case Type::Electron: - case Type::ElasticProton: - default: return std::make_shared( params ); - case Type::SzczurekUleshchenko: return std::make_shared( params ); - case Type::SuriYennie: return std::make_shared( params ); - case Type::FioreBrasse: return std::make_shared( params ); - case Type::ChristyBosted: return std::make_shared( params ); - case Type::CLAS: return std::make_shared( params ); - case Type::BlockDurandHa: return std::make_shared( params ); - case Type::ALLM91: return std::make_shared( pcopy.set( "model", "ALLM91" ) ); - case Type::ALLM97: return std::make_shared( pcopy.set( "model", "ALLM97" ) ); - case Type::GD07p: return std::make_shared( pcopy.set( "model", "GD07p" ) ); - case Type::GD11p: return std::make_shared( pcopy.set( "model", "GD11p" ) ); - case Type::Schaefer: return std::make_shared( params ); - case Type::Partonic: return std::make_shared( params ); - //--- particular case for the MSTW grid as we are dealing - //--- with a singleton ; hence, no deleter is needed! - case Type::MSTWgrid: return std::shared_ptr( mstw::Grid::get( params ).get(), [=]( mstw::Grid* ){} ); - } - } - } - - /// Human-readable format of a structure function type - std::ostream& - operator<<( std::ostream& os, const strfun::Type& sf ) - { - switch ( sf ) { - case strfun::Type::Invalid: return os << "[INVALID]"; - case strfun::Type::Electron: return os << "electron"; - case strfun::Type::ElasticProton: return os << "elastic proton"; - case strfun::Type::SuriYennie: return os << "Suri-Yennie"; - case strfun::Type::SzczurekUleshchenko: return os << "Szczurek-Uleshchenko"; - case strfun::Type::FioreBrasse: return os << "Fiore-Brasse"; - case strfun::Type::ChristyBosted: return os << "Christy-Bosted"; - case strfun::Type::CLAS: return os << "CLAS"; - case strfun::Type::BlockDurandHa: return os << "BDH"; - case strfun::Type::ALLM91: return os << "ALLM91"; - case strfun::Type::ALLM97: return os << "ALLM97"; - case strfun::Type::GD07p: return os << "GD07p"; - case strfun::Type::GD11p: return os << "GD11p"; - case strfun::Type::Schaefer: return os << "LUXlike"; - case strfun::Type::MSTWgrid: return os << "MSTW (grid)"; - case strfun::Type::Partonic: return os << "Partonic"; - } - return os; - } -} diff --git a/CepGen/StructureFunctions/SuriYennie.cpp b/CepGen/StructureFunctions/SuriYennie.cpp index dbd1223..3d7101c 100644 --- a/CepGen/StructureFunctions/SuriYennie.cpp +++ b/CepGen/StructureFunctions/SuriYennie.cpp @@ -1,76 +1,78 @@ #include "CepGen/StructureFunctions/SuriYennie.h" #include "CepGen/Core/Exception.h" #include namespace cepgen { namespace strfun { SuriYennie::Parameters SuriYennie::Parameters::standard() { Parameters p; p.C1 = 0.86926; p.C2 = 2.23422; p.D1 = 0.12549; p.rho2 = 0.585; p.Cp = 0.96; p.Bp = 0.63; return p; } SuriYennie::Parameters SuriYennie::Parameters::alternative() { Parameters p; p.C1 = 0.6303; p.C2 = 2.3049; p.D1 = 0.04681; p.rho2 = 1.05; p.Cp = 1.23; p.Bp = 0.61; return p; } SuriYennie::SuriYennie( const ParametersList& params ) : Parameterisation( params ), F1( 0. ), FE( 0. ), FM( 0. ) { const auto& model = params.get( "model", "standard" ); if ( model == "standard" ) params_ = Parameters::standard(); else if ( model == "alternative" ) params_ = Parameters::alternative(); else throw CG_FATAL( "SuriYennie" ) << "Invalid modelling selected: " << model << "!"; } SuriYennie& SuriYennie::operator()( double xbj, double q2 ) { std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double inv_q2 = 1./q2; const double dm2 = q2*( 1.-xbj )/xbj; const double mx2 = mp2_ + dm2; // [GeV^2] const double en = dm2+q2, en2 = en*en; // [GeV^2] const double nu = 0.5 * en / mp_, Xpr = q2/( q2+mx2 ), tau = 0.25 * q2/mp2_; const double mq = params_.rho2+q2; FM = ( params_.C1*dm2*pow( params_.rho2/mq, 2 ) + ( params_.C2*mp2_*pow( 1.-Xpr, 4 ) ) / ( 1.+Xpr*( Xpr*params_.Cp-2.*params_.Bp ) ) ) * inv_q2; FE = ( tau*FM + params_.D1*dm2*q2*params_.rho2/mp2_*pow( dm2/mq, 2 )/en2 ) / ( 1.+0.25*en2/mp2_*inv_q2 ); //const double w2 = 2.*mp*FE; F1 = 0.5*FM*q2/mp_; F2 = 2.*nu*FE; return *this; } } } + +REGISTER_STRFUN( SuriYennie, strfun::SuriYennie ) diff --git a/CepGen/StructureFunctions/SzczurekUleshchenko.cpp b/CepGen/StructureFunctions/SzczurekUleshchenko.cpp index 0363f76..a92ec29 100644 --- a/CepGen/StructureFunctions/SzczurekUleshchenko.cpp +++ b/CepGen/StructureFunctions/SzczurekUleshchenko.cpp @@ -1,50 +1,74 @@ -#include "CepGen/StructureFunctions/SzczurekUleshchenko.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" +extern "C" +{ + extern void grv95lo_( float&, float&, float&, float&, float&, float&, float&, float& ); +} + namespace cepgen { namespace strfun { + /// Szcurek and Uleshchenko modelling of \f$F_{1,2}\f$ \cite Szczurek:1999wp + class SzczurekUleshchenko : public Parameterisation + { + public: + SzczurekUleshchenko( const ParametersList& params = ParametersList() ); + SzczurekUleshchenko& operator()( double xbj, double q2 ) override; + + private: + /// \f$Q^2\f$ scale shift + const float q2_shift_; + + public: + double F1; + }; + SzczurekUleshchenko::SzczurekUleshchenko( const ParametersList& params ) : - Parameterisation( params ), F1( 0. ) + Parameterisation( params ), + q2_shift_( params.get( "q2shift", 0.8 ) ), + F1( 0. ) {} SzczurekUleshchenko& SzczurekUleshchenko::operator()( double xbj, double q2 ) { #ifndef GRVPDF throw CG_FATAL( "SzczurekUleshchenko" ) << "Szczurek-Uleshchenko structure functions cannot be computed" << " as GRV PDF set is not linked to this instance!"; #else std::pair nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; - float amu2 = q2+Q2_SHIFT; // shift the overall scale + float amu2 = q2+q2_shift_; // shift the overall scale float xuv, xdv, xus, xds, xss, xg; float xbj_arg = xbj; grv95lo_( xbj_arg, amu2, xuv, xdv, xus, xds, xss, xg ); CG_DEBUG_LOOP( "SzczurekUleshchenko" ) << "Form factor content at xB = " << xbj << " (scale = " << amu2 << " GeV^2):\n\t" << " valence quarks: u / d = " << xuv << " / " << xdv << "\n\t" << " sea quarks: u / d / s = " << xus << " / " << xds << " / " << xss << "\n\t" << " gluons: = " << xg; // standard partonic structure function const double F2_aux = 4./9.*( xuv + 2.*xus ) + 1./9.*( xdv + 2.*xds ) + 1./9.*( 2.*xss ); F2 = F2_aux * q2 / amu2; // F2 corrected for low Q^2 behaviour return *this; #endif } } } + +REGISTER_STRFUN( SzczurekUleshchenko, strfun::SzczurekUleshchenko ) diff --git a/CepGen/StructureFunctions/SzczurekUleshchenko.h b/CepGen/StructureFunctions/SzczurekUleshchenko.h deleted file mode 100644 index 2fc6b95..0000000 --- a/CepGen/StructureFunctions/SzczurekUleshchenko.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef CepGen_StructureFunctions_SzczurekUleshchenko_h -#define CepGen_StructureFunctions_SzczurekUleshchenko_h - -#include "CepGen/StructureFunctions/StructureFunctions.h" - -extern "C" -{ - extern void grv95lo_( float&, float&, float&, float&, float&, float&, float&, float& ); -} - -namespace cepgen -{ - namespace strfun - { - /// Szcurek and Uleshchenko modelling of \f$F_{1,2}\f$ \cite Szczurek:1999wp - class SzczurekUleshchenko : public Parameterisation - { - public: - SzczurekUleshchenko( const ParametersList& params = ParametersList() ); - SzczurekUleshchenko& operator()( double xbj, double q2 ) override; - - double F1; - - private: - static constexpr float Q2_SHIFT = 0.8; - }; - } -} - -#endif diff --git a/CepGen/Version.h b/CepGen/Version.h index 623afdc..0e42102 100644 --- a/CepGen/Version.h +++ b/CepGen/Version.h @@ -1,18 +1,18 @@ #ifndef CepGen_Version_h #define CepGen_Version_h #include namespace cepgen { /// CepGen version /// \note Format: 0xMMmmff, with /// - MM = major version /// - mm = minor version /// - ff = feature(s) release - const unsigned int cepgen_version = 0x000900; + const unsigned int cepgen_version = 0x000906; /// Human-readable version number const std::string version(); } #endif diff --git a/External/Processes/nucl_to_ff.f b/External/Processes/nucl_to_ff.f index 87f87b7..f5b65ce 100644 --- a/External/Processes/nucl_to_ff.f +++ b/External/Processes/nucl_to_ff.f @@ -1,492 +1,495 @@ function nucl_to_ff() implicit none double precision nucl_to_ff c ================================================================= c CepGen common blocks for kinematics definition c ================================================================= include 'KTBlocks.inc' data iflux1,iflux2,sfmod,pdg_l/10,100,11,13/ data a_nuc1,z_nuc1,a_nuc2,z_nuc2/1,1,208,82/ c ================================================================= c local variables c ================================================================= double precision s,s12 double precision alpha1,alpha2,amt1,amt2 double precision pt1,pt2,eta1,eta2,dely double precision pt1x,pt1y,pt2x,pt2y double precision ak10,ak1x,ak1y,ak1z,ak20,ak2x,ak2y,ak2z double precision beta1,beta2,x1,x2 double precision z1p,z1m,z2p,z2m double precision q1tx,q1ty,q1z,q10,q1t2 double precision q2tx,q2ty,q2z,q20,q2t2 double precision ptsum double precision that1,that2,that,uhat1,uhat2,uhat double precision term1,term2,term3,term4,term5,term6,term7 double precision term8,term9,term10,amat2 double precision ak1_x,ak1_y,ak2_x,ak2_y double precision eps12,eps22 double precision aux2_1,aux2_2,f1,f2 double precision Phi10,Phi102,Phi11_x,Phi11_y,Phi112 double precision Phi20,Phi202,Phi21_x,Phi21_y,Phi212 double precision Phi11_dot_e,Phi11_cross_e double precision Phi21_dot_e,Phi21_cross_e double precision aintegral integer imat1,imat2 double precision px_plus,px_minus,py_plus,py_minus double precision r1,r2 double precision ptdiffx,ptsumx,ptdiffy,ptsumy double precision invm,invm2,s1_eff,s2_eff double precision t1abs,t2abs double precision am_l,q_l double precision inp_A,inp_B,am_A,am_B double precision p1_plus, p2_minus double precision amat2_1,amat2_2 integer iterm11,iterm22,iterm12,itermtt double precision coupling c ================================================================= c quarks production c ================================================================= #ifdef ALPHA_S double precision t_max,amu2,alphas #endif logical first_init data first_init/.true./ save first_init,am_l,q_l call CepGen_print if(first_init) then am_l = CepGen_particle_mass(pdg_l) ! central particles mass q_l = CepGen_particle_charge(pdg_l) ! central particles charge if(iflux1.ge.20.and.iflux1.lt.40) then if(icontri.eq.3.or.icontri.eq.4) then print *,'Invalid process mode for collinear gluon emission!' stop endif #ifdef ALPHA_S print *,'Initialisation of the alpha(S) evolution algorithm..' call initAlphaS(0,1.d0,1.d0,0.5d0, & CepGen_particle_mass(4), ! charm & CepGen_particle_mass(5), ! bottom & CepGen_particle_mass(6)) ! top #endif endif first_init = .false. endif c ================================================================= c FIXME c ================================================================= nucl_to_ff = 0.d0 + amat2 = 0.d0 + eps12 = 0.d0 + eps22 = 0.d0 q10 = 0.d0 q1z = 0.d0 q20 = 0.d0 q2z = 0.d0 c ================================================================= c go to energy of Nucleus = A*inp in order that generator puts out c proper momenta in LAB frame c ================================================================= inp_A = inp1*a_nuc1 am_A = am_p*a_nuc1 inp_B = inp2*a_nuc2 am_B = am_p*a_nuc2 c ================================================================= c four-momenta for incoming beams in LAB !!!! c ================================================================= r1 = dsqrt(1.d0+am_A**2/inp_A**2) r2 = dsqrt(1.d0+am_B**2/inp_B**2) ak10 = inp_A*r1 ak1x = 0.d0 ak1y = 0.d0 ak1z = inp_A ak20 = inp_B*r2 ak2x = 0.d0 ak2y = 0.d0 ak2z = -inp_B s = 4.*inp_A*inp_B*(1.d0 + r1*r2)/2.d0+(am_A**2+am_B**2) s12 = dsqrt(s) p1_plus = (ak10+ak1z)/dsqrt(2.d0) p2_minus = (ak20-ak2z)/dsqrt(2.d0) c terms in the matrix element c iterm11 = 1 ! LL iterm22 = 1 ! TT iterm12 = 1 ! LT itermtt = 1 ! TT' c ================================================================= c two terms in the Wolfgang's formula for c off-shell gamma gamma --> l^+ l^- c ================================================================= imat1 = 1 imat2 = 1 c ================================================================= c Outgoing proton final state's mass c ================================================================= if((icontri.eq.1).or.(icontri.eq.2)) am_x = am_A if((icontri.eq.1).or.(icontri.eq.3)) am_y = am_B q1tx = q1t*cos(phiq1t) q1ty = q1t*sin(phiq1t) q2tx = q2t*cos(phiq2t) q2ty = q2t*sin(phiq2t) ptsumx = q1tx+q2tx ptsumy = q1ty+q2ty ptsum = sqrt(ptsumx**2+ptsumy**2) c ================================================================= c a window in final state transverse momentum c ================================================================= if(iptsum) then if(ptsum.lt.ptsum_min.or.ptsum.gt.ptsum_max) return endif c ================================================================= c compute the individual central particles momentum c ================================================================= ptdiffx = ptdiff*cos(phiptdiff) ptdiffy = ptdiff*sin(phiptdiff) pt1x = 0.5*(ptsumx+ptdiffx) pt1y = 0.5*(ptsumy+ptdiffy) pt2x = 0.5*(ptsumx-ptdiffx) pt2y = 0.5*(ptsumy-ptdiffy) pt1 = sqrt(pt1x**2+pt1y**2) pt2 = sqrt(pt2x**2+pt2y**2) if(ipt) then if(pt1.lt.pt_min.or.pt2.lt.pt_min) return if(pt_max.gt.0d0.and.(pt2.gt.pt_max.or.pt2.gt.pt_max)) return endif amt1 = dsqrt(pt1**2+am_l**2) amt2 = dsqrt(pt2**2+am_l**2) invm2 = amt1**2 + amt2**2 + 2.d0*amt1*amt2*dcosh(y1-y2) & -ptsum**2 invm = dsqrt(invm2) c ================================================================= c a window in final state invariant mass c ================================================================= if(iinvm) then if(invm.lt.invm_min) return if(invm_max.gt.0d0.and.invm.gt.invm_max) return endif c ================================================================= c a window in rapidity distance c ================================================================= dely = dabs(y1-y2) if(idely) then if(dely.lt.dely_min.or.dely.gt.dely_max) return endif c ================================================================= c auxiliary quantities c ================================================================= alpha1 = amt1/(dsqrt(2.d0)*p1_plus)*dexp( y1) alpha2 = amt2/(dsqrt(2.d0)*p1_plus)*dexp( y2) beta1 = amt1/(dsqrt(2.d0)*p2_minus)*dexp(-y1) beta2 = amt2/(dsqrt(2.d0)*p2_minus)*dexp(-y2) q1t2 = q1tx**2 + q1ty**2 q2t2 = q2tx**2 + q2ty**2 x1 = alpha1 + alpha2 x2 = beta1 + beta2 z1p = alpha1/x1 z1m = alpha2/x1 z2p = beta1/x2 z2m = beta2/x2 c ----------------------------------------------------------------- if(x1.gt.1.0.or.x2.gt.1.0) return c ----------------------------------------------------------------- s1_eff = x1*s - q1t**2 s2_eff = x2*s - q2t**2 c ----------------------------------------------------------------- c Additional conditions for energy-momentum conservation c ----------------------------------------------------------------- if(((icontri.eq.2).or.(icontri.eq.4)) 1 .and.(dsqrt(s1_eff).le.(am_y+invm))) return if(((icontri.eq.3).or.(icontri.eq.4)) 1 .and.(dsqrt(s2_eff).le.(am_x+invm))) return c ================================================================= c >>> TO THE OUTPUT COMMON BLOCK c ================================================================= c ================================================================= c four-momenta of the outgoing protons (or remnants) c ================================================================= px_plus = (1.d0-x1) * p1_plus px_minus = ((a_nuc1*am_x)**2 + q1tx**2 + q1ty**2)/2.d0/px_plus px(1) = - q1tx px(2) = - q1ty px(3) = (px_plus - px_minus)/dsqrt(2.d0) px(4) = (px_plus + px_minus)/dsqrt(2.d0) py_minus = (1.d0-x2) * p2_minus py_plus = ((a_nuc2*am_y)**2 + q2tx**2 + q2ty**2)/2.d0/py_minus py(1) = - q2tx py(2) = - q2ty py(3) = (py_plus - py_minus)/dsqrt(2.d0) py(4) = (py_plus + py_minus)/dsqrt(2.d0) q1t = dsqrt(q1t2) q2t = dsqrt(q2t2) c ================================================================= c four-momenta of the outgoing central particles c ================================================================= nout = 2 ipdg(1) = pdg_l pc(1,1) = pt1x pc(1,2) = pt1y pc(1,3) = alpha1*ak1z + beta1*ak2z pc(1,4) = alpha1*ak10 + beta1*ak20 ipdg(2) = -pdg_l pc(2,1) = pt2x pc(2,2) = pt2y pc(2,3) = alpha2*ak1z + beta2*ak2z pc(2,4) = alpha2*ak10 + beta2*ak20 eta1 = 0.5d0*dlog((dsqrt(amt1**2*(dcosh(y1))**2 - am_l**2) + 2 amt1*dsinh(y1))/(dsqrt(amt1**2*(dcosh(y1))**2 - am_l**2) 3 - amt1*dsinh(y1))) eta2 = 0.5d0*dlog((dsqrt(amt2**2*(dcosh(y2))**2 - am_l**2) + 2 amt2*dsinh(y2))/(dsqrt(amt2**2*(dcosh(y2))**2 - am_l**2) 3 - amt2*dsinh(y2))) if(ieta) then if(eta1.lt.eta_min.or.eta1.gt.eta_max) return if(eta2.lt.eta_min.or.eta2.gt.eta_max) return endif c ================================================================= c matrix element squared c averaged over initial spin polarizations c and summed over final spin polarizations c (--> see Wolfgang's notes c ================================================================= c ================================================================= c Mendelstam variables c ================================================================= that1 = (q10-pc(1,4))**2 & -(q1tx-pc(1,1))**2-(q1ty-pc(2,1))**2-(q1z-pc(3,1))**2 uhat1 = (q10-pc(2,4))**2 & -(q1tx-pc(1,2))**2-(q1ty-pc(2,2))**2-(q1z-pc(3,2))**2 that2 = (q20-pc(2,4))**2 & -(q2tx-pc(1,2))**2-(q2ty-pc(2,2))**2-(q2z-pc(3,2))**2 uhat2 = (q20-pc(1,4))**2 & -(q2tx-pc(1,1))**2-(q2ty-pc(2,1))**2-(q2z-pc(3,1))**2 that = (that1+that2)/2.d0 uhat = (uhat1+uhat2)/2.d0 c ================================================================= c matrix elements c ================================================================= c How matrix element is calculated c imethod = 0: on-shell formula c imethod = 1: off-shell formula c ================================================================= if(imethod.eq.0) then c ================================================================= c on-shell formula for M^2 c ================================================================= term1 = 6.d0*am_l**8 term2 = -3.d0*am_l**4*that**2 term3 = -14.d0*am_l**4*that*uhat term4 = -3.d0*am_l**4*uhat**2 term5 = am_l**2*that**3 term6 = 7.d0*am_l**2*that**2*uhat term7 = 7.d0*am_l**2*that*uhat**2 term8 = am_l**2*uhat**3 term9 = -that**3*uhat term10 = -that*uhat**3 amat2 = -2.d0*( term1+term2+term3+term4+term5 2 +term6+term7+term8+term9+term10 ) 3 / ( (am_l**2-that)**2 * (am_l**2-uhat)**2 ) elseif(imethod.eq.1)then c ================================================================= c Wolfgang's formulae c ================================================================= ak1_x = z1m*pt1x-z1p*pt2x ak1_y = z1m*pt1y-z1p*pt2y ak2_x = z2m*pt1x-z2p*pt2x ak2_y = z2m*pt1y-z2p*pt2y !FIXME FIXME FIXME am_p or am_A/B??? t1abs = (q1t2+x1*(am_x**2-am_p**2)+x1**2*am_p**2)/(1.d0-x1) t2abs = (q2t2+x2*(am_y**2-am_p**2)+x2**2*am_p**2)/(1.d0-x2) eps12 = am_l**2 + z1p*z1m*t1abs eps22 = am_l**2 + z2p*z2m*t2abs Phi10 = 1.d0/((ak1_x+z1p*q2tx)**2+(ak1_y+z1p*q2ty)**2+eps12) 2 - 1.d0/((ak1_x-z1m*q2tx)**2+(ak1_y-z1m*q2ty)**2+eps12) Phi11_x = (ak1_x+z1p*q2tx)/ 2 ((ak1_x+z1p*q2tx)**2+(ak1_y+z1p*q2ty)**2+eps12) 3 - (ak1_x-z1m*q2tx)/ 4 ((ak1_x-z1m*q2tx)**2+(ak1_y-z1m*q2ty)**2+eps12) Phi11_y = (ak1_y+z1p*q2ty)/ 2 ((ak1_x+z1p*q2tx)**2+(ak1_y+z1p*q2ty)**2+eps12) 3 - (ak1_y-z1m*q2ty)/ 4 ((ak1_x-z1m*q2tx)**2+(ak1_y-z1m*q2ty)**2+eps12) Phi102 = Phi10*Phi10 Phi112 = Phi11_x**2+Phi11_y**2 Phi20 = 1.d0/((ak2_x+z2p*q1tx)**2+(ak2_y+z2p*q1ty)**2+eps22) 2 - 1.d0/((ak2_x-z2m*q1tx)**2+(ak2_y-z2m*q1ty)**2+eps22) Phi21_x = (ak2_x+z2p*q1tx)/ 2 ((ak2_x+z2p*q1tx)**2+(ak2_y+z2p*q1ty)**2+eps22) 3 - (ak2_x-z2m*q1tx)/ 4 ((ak2_x-z2m*q1tx)**2+(ak2_y-z2m*q1ty)**2+eps22) Phi21_y = (ak2_y+z2p*q1ty)/ 2 ((ak2_x+z2p*q1tx)**2+(ak2_y+z2p*q1ty)**2+eps22) 3 - (ak2_y-z2m*q1ty)/ 4 ((ak2_x-z2m*q1tx)**2+(ak2_y-z2m*q1ty)**2+eps22) Phi202 = Phi20*Phi20 Phi212 = Phi21_x**2+Phi21_y**2 Phi11_dot_e = (Phi11_x*q1tx + Phi11_y*q1ty)/dsqrt(q1t2) Phi11_cross_e = (Phi11_x*q1ty - Phi11_y*q1tx)/dsqrt(q1t2) Phi21_dot_e = (Phi21_x*q2tx +Phi21_y*q2ty)/dsqrt(q2t2) Phi21_cross_e = (Phi21_x*q2ty -Phi21_y*q2tx)/dsqrt(q2t2) aux2_1 = iterm11*(am_l**2+4.d0*z1p**2*z1m**2*t1abs)*Phi102 1 +iterm22*( (z1p**2 + z1m**2)*(Phi11_dot_e**2 + 2 Phi11_cross_e**2) ) 3 + itermtt*( Phi11_cross_e**2 - Phi11_dot_e**2) 4 - iterm12*4.d0*z1p*z1m*(z1p-z1m)*Phi10 5 *(q1tx*Phi11_x+q1ty*Phi11_y) aux2_2 = iterm11*(am_l**2+4.d0*z2p**2*z2m**2*t2abs)*Phi202 1 +iterm22*( (z2p**2 + z2m**2)*(Phi21_dot_e**2 + 2 Phi21_cross_e**2) ) 3 + itermtt*( Phi21_cross_e**2 - Phi21_dot_e**2) 4 - iterm12*4.d0*z2p*z2m*(z2p-z2m)*Phi20 5 *(q2tx*Phi21_x+q2ty*Phi21_y) c ================================================================= c convention of matrix element as in our kt-factorization c for heavy flavours c ================================================================= amat2_1 = (x1*x2*s)**2 * aux2_1 * 2.*z1p*z1m*q1t2 / (q1t2*q2t2) amat2_2 = (x1*x2*s)**2 * aux2_2 * 2.*z2p*z2m*q2t2 / (q1t2*q2t2) c ================================================================= c symmetrization c ================================================================= amat2 = (imat1*amat2_1 + imat2*amat2_2)/2.d0 endif coupling = 1.d0 c ================================================================= c first parton coupling c ================================================================= if(iflux1.ge.20.and.iflux1.lt.40) then ! at least one gluon exchanged #ifdef ALPHA_S t_max = max(amt1**2,amt2**2) amu2 = max(eps12,t_max) am_x = dsqrt(amu2) coupling = coupling * 4.d0*pi*alphaS(am_x)/2.d0 ! colour flow #else print *,'alphaS not linked to this instance!' stop #endif else ! photon exchange coupling = coupling * 4.d0*pi*alpha_em*q_l**2 endif c ================================================================= c second parton coupling c ================================================================= coupling = coupling * 4.d0*pi*alpha_em*q_l**2 ! photon exchange coupling = coupling * 3.d0 c ============================================ c unintegrated parton distributions c ============================================ if(a_nuc1.le.1) then f1 = CepGen_kT_flux(iflux1,x1,q1t2,sfmod,am_x) else f1 = CepGen_kT_flux_HI(iflux1,x1,q1t2,a_nuc1,z_nuc1) endif if(a_nuc2.le.1) then f2 = CepGen_kT_flux(iflux2,x2,q2t2,sfmod,am_y) else f2 = CepGen_kT_flux_HI(iflux2,x2,q2t2,a_nuc2,z_nuc2) endif c ================================================================= c factor 2.*pi below from integration over phi_sum c factor 1/4 below from jacobian of transformations c factors 1/pi and 1/pi due to integration c over d^2 kappa_1 d^2 kappa_2 instead d kappa_1^2 d kappa_2^2 c ================================================================= aintegral = (2.d0*pi)*1.d0/(16.d0*pi**2*(x1*x2*s)**2) * amat2 & * coupling & * f1/pi * f2/pi * (1.d0/4.d0) * units & * 0.5d0 * 4.0d0 / (4.d0*pi) c ***************************************************************** c ================================================================= nucl_to_ff = aintegral*q1t*q2t*ptdiff c ================================================================= c ***************************************************************** c print *,nucl_to_ff,aintegral,coupling return end diff --git a/cmake/UseEnvironment.cmake b/cmake/UseEnvironment.cmake index d1633fb..0b3531c 100644 --- a/cmake/UseEnvironment.cmake +++ b/cmake/UseEnvironment.cmake @@ -1,93 +1,91 @@ -set(LXPLUS_SRC_ENV "source ${CMAKE_SOURCE_DIR}/source-lxplus.sh") +if(NOT CMAKE_VERSION VERSION_LESS 3.1) + set(CMAKE_CXX_STANDARD 14) +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") +endif() set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wall -cpp") +#--- check if we are at CERN if($ENV{HOSTNAME} MATCHES "^lxplus[0-9]+.cern.ch") set(IS_LXPLUS "yes") endif() +#--- ensure a proper version of the compiler is found if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic-errors -g") else() message(STATUS "clang or gcc above 6.1 is required") if(IS_LXPLUS) + set(LXPLUS_SRC_ENV "source ${CMAKE_SOURCE_DIR}/source-lxplus.sh") message(STATUS "Compiling on LXPLUS. Did you properly source the environment variables? E.g.\n\n\t${LXPLUS_SRC_ENV}\n") endif() message(FATAL_ERROR "Please clean up this build environment, i.e.\n\trm -rf CMake*\nand try again...") endif() -if(NOT CMAKE_VERSION VERSION_LESS 3.1) - set(CMAKE_CXX_STANDARD 14) -else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") -endif() +#--- set the default paths for external dependencies if(IS_LXPLUS) set(BASE_DIR "/cvmfs/sft.cern.ch/lcg") list(APPEND CMAKE_PREFIX_PATH "${BASE_DIR}/external/CMake/2.8.9/Linux-i386/share/cmake-2.8/Modules") set(GSL_DIR "${BASE_DIR}/releases/GSL/2.5-32fc5/x86_64-centos7-gcc62-opt") set(HEPMC_DIR "${BASE_DIR}/releases/HepMC/2.06.09-0a23a/x86_64-centos7-gcc62-opt") set(LHAPDF_DIR "${BASE_DIR}/releases/MCGenerators/lhapdf/6.2.2-8a3e6/x86_64-centos7-gcc62-opt") set(PYTHIA6_DIR "${BASE_DIR}/releases/MCGenerators/pythia6/429.2-c4089/x86_64-centos7-gcc62-opt") set(PYTHIA8_DIR "${BASE_DIR}/releases/MCGenerators/pythia8/240p1-ecd34/x86_64-centos7-gcc62-opt") set(DELPHES_DIR "${BASE_DIR}/releases/delphes/3.4.0-03b2c/x86_64-centos7-gcc62-opt") set(TBB_DIR "${BASE_DIR}/releases/tbb/2019_U7-ba3eb/x86_64-centos7-gcc62-opt") set(PYTHON_DIR "${BASE_DIR}/releases/Python/2.7.15-075d4/x86_64-centos7-gcc62-opt") set(PYTHON_LIBRARY "${PYTHON_DIR}/lib/libpython2.7.so") set(PYTHON_EXECUTABLE "${PYTHON_DIR}/bin/python") set(PYTHON_INCLUDE_DIR "${PYTHON_DIR}/include/python2.7") message(STATUS "Compiling on LXPLUS. Do not forget to source the environment variables!") message(STATUS "e.g. `${LXPLUS_SRC_ENV}`") endif() #--- searching for GSL find_library(GSL_LIB gsl HINTS ${GSL_DIR} PATH_SUFFIXES lib REQUIRED) find_library(GSL_CBLAS_LIB gslcblas HINTS ${GSL_DIR} PATH_SUFFIXES lib) find_path(GSL_INCLUDE gsl HINTS ${GSL_DIR} PATH_SUFFIXES include) include_directories(${GSL_INCLUDE}) #--- searching for LHAPDF find_library(LHAPDF LHAPDF HINTS ${LHAPDF_DIR} PATH_SUFFIXES lib) find_path(LHAPDF_INCLUDE LHAPDF HINTS ${LHAPDF_DIR} PATH_SUFFIXES include) #--- searching for HepMC find_library(HEPMC_LIB NAMES HepMC3 HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES lib) +find_library(HEPMC_ROOT_LIB NAMES HepMC3rootIO PATH_SUFFIXES root) find_path(HEPMC_INCLUDE NAMES HepMC3 HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES include) #--- searching for Pythia 6 set(PYTHIA6_DIRS $ENV{PYTHIA6_DIR} ${PYTHIA6_DIR} /usr /usr/local /opt/pythia6) find_library(PYTHIA6 pythia6 HINTS ${PYTHIA6_DIRS} PATH_SUFFIXES lib) find_library(PYTHIA6DUMMY pythia6_dummy HINTS ${PYTHIA6_DIRS} PATH_SUFFIXES lib) #--- searching for Pythia 8 set(PYTHIA8_DIRS $ENV{PYTHIA8_DIR} ${PYTHIA8_DIR} /usr /usr/local /opt/pythia8) find_library(PYTHIA8 pythia8 HINTS ${PYTHIA8_DIRS} PATH_SUFFIXES lib) find_path(PYTHIA8_INCLUDE Pythia8 HINTS ${PYTHIA8_DIRS} PATH_SUFFIXES include include/Pythia8 include/pythia8) #--- searching for Delphes find_library(DELPHES Delphes HINTS ${DELPHES_DIR} PATH_SUFFIXES lib) find_path(DELPHES_INCLUDE NAMES modules classes HINTS ${DELPHES_DIR} PATH_SUFFIXES include) #--- searching for tbb find_library(TBB tbb HINTS ${TBB_DIR} PATH_SUFFIXES lib) message(STATUS "GSL found in ${GSL_LIB}") list(APPEND CEPGEN_EXTERNAL_CORE_REQS ${GSL_LIB} ${GSL_CBLAS_LIB}) -list(APPEND CEPGEN_EXTERNAL_STRF_REQS ${GSL_LIB} ${GSL_CBLAS_LIB}) -if(LHAPDF) - message(STATUS "LHAPDF found in ${LHAPDF}") - list(APPEND CEPGEN_EXTERNAL_STRF_REQS ${LHAPDF}) - add_definitions(-DLIBLHAPDF) - include_directories(${LHAPDF_INCLUDE}) -endif() find_package(PythonLibs 2.7) find_library(MUPARSER muparser) if(MUPARSER) message(STATUS "muParser found in ${MUPARSER}") list(APPEND CEPGEN_EXTERNAL_CORE_REQS ${MUPARSER}) add_definitions(-DMUPARSER) else() find_path(EXPRTK exprtk.hpp PATH_SUFFIXES include) if(EXPRTK) message(STATUS "exprtk found in ${EXPRTK}") add_definitions(-DEXPRTK) include_directories(${EXPRTK}) endif() endif() +#--- semi-external dependencies set(ALPHAS_PATH ${PROJECT_SOURCE_DIR}/External) file(GLOB alphas_sources ${ALPHAS_PATH}/alphaS.f) if(alphas_sources) message(STATUS "alphaS evolution found in ${alphas_sources}") add_definitions(-DALPHA_S) endif() diff --git a/release-notes.md b/release-notes.md index 3fbcbc6..81fd31b 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,40 +1,45 @@ # Release notes +## v0.9.6 (11 Jul 2019) +* Added support of Pythia6 hadronisation/fragmentation algorithm for legacy tests +* Structure functions parameterisation objects polished +* New output modes handled for HepMC interfacing module + ## v0.9.5 (25 Jun 2019) * Increased flexibility in particles (and their associated properties) definitions * Small corrections in the LPAIR process definition of the output kinematics * Improved Pythia8 interfacing, better handling of the LHEF output format when remnants dissociation is triggered * Better exceptions handling ## v0.9.4 (9 May 2019) * pptoff polarisation terms may be steered for off-shell ME * Functional is now handling exprtk in addition to μParser * Refactored exceptions and tests * Improved accessors for integrator/grid definition * Better memory management for parameters/processes/hadronisers definition ## v0.9.1-3 (29-30 Nov 2018) * Fixes in includes chain * Fix in LPAIR cards parser, simplified cards handler interface * External Fortran processes now defined through a function instead of a subroutine * Fix in Pythia8 interface parton colours definition and resonances decay * Structure functions interface modified ## v0.9 (28-29 Nov 2018) * Fixed memory leaks in Python configuration files handler * First HI process! (and first Fortran process interfaced) * Polarisation states may be specified for the off-shell γγ → W+W- ME * New structure functions definitions: ALLM (+subsequent), MSTW grid, CLAS, LUXlike, LHAPDF * Introduced R-ratio definitions for FL calculation from F2 * New cuts definition * Better memory management ## v0.8 (24 Aug 2017) * Major refactoring of the code * Dropped the hadronisers and other unfinished processes definition for clarity * Several bug fixes and memory management improvements through the usage of smart pointers / C++11 migration * Taming functions introduced ## v0.7 (3 May 2016) * Introduced a generic templating class for the kT factorisation method * Added a placeholder for the γγ → W+W- process computation diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index afd8352..867ae34 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,54 +1,53 @@ #----- list all test executables file(GLOB executables_noroot RELATIVE ${PROJECT_SOURCE_DIR}/test *.cpp) file(GLOB executables_root RELATIVE ${PROJECT_SOURCE_DIR}/test *.cxx) file(GLOB executables_fortran RELATIVE ${PROJECT_SOURCE_DIR}/test *.f) #----- include the utilitaries set(tests "") #----- build all tests and link them to the core library foreach(exec_src ${executables_noroot}) string(REPLACE ".cpp" "" exec_bin ${exec_src}) add_executable(${exec_bin} ${exec_src}) set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true) target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES}) list(APPEND tests ${exec_bin}) endforeach() foreach(exec_src ${executables_fortran}) string(REPLACE ".f" "" exec_bin ${exec_src}) add_executable(${exec_bin} ${exec_src}) set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true) target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES}) list(APPEND tests ${exec_bin}) endforeach() #----- specify the tests requiring ROOT find_package(ROOT QUIET) if(ROOT_FOUND) - set(CMAKE_CXX_STANDARD 14) - include_directories(${ROOT_INCLUDE_DIR}) + include_directories(${ROOT_INCLUDE_DIRS}) link_directories(${ROOT_LIBRARY_DIR}) foreach(exec_src ${executables_root}) string(REPLACE ".cxx" "" exec_bin ${exec_src}) add_executable(${exec_bin} ${exec_src}) set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true) target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES} ${ROOT_LIBRARIES}) list(APPEND tests ${exec_bin}) endforeach() else() message(STATUS "ROOT not found! skipping these tests!") endif() -message(STATUS "list of available tests: ${tests}") +message(STATUS "The following tests/executables are available:\n${tests}") file(GLOB_RECURSE test_input_cards RELATIVE ${PROJECT_SOURCE_DIR}/test test_processes/* __init__.py) foreach(_files ${test_input_cards}) configure_file(${_files} ${_files} COPYONLY) endforeach() configure_file(${PROJECT_SOURCE_DIR}/test/test_processes.cfg test_processes.cfg COPYONLY) diff --git a/test/cepgen-event.cpp b/test/cepgen-event.cpp index 7f61022..3485918 100644 --- a/test/cepgen-event.cpp +++ b/test/cepgen-event.cpp @@ -1,82 +1,82 @@ #include "CepGen/Cards/Handler.h" #include "CepGen/IO/ExportHandler.h" #include "CepGen/Generator.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Event/Event.h" #include "AbortHandler.h" #include using namespace std; // we use polymorphism here -std::unique_ptr writer; +std::unique_ptr writer; void storeEvent( const cepgen::Event& ev, unsigned long ) { if ( !writer ) throw CG_FATAL( "storeEvent" ) << "Failed to retrieve a valid writer!"; *writer << ev; } /** * Main caller for this Monte Carlo generator. Loads the configuration files' * variables if set as an argument to this program, else loads a default * "LHC-like" configuration, then launches the cross-section computation and * the events generation. * \author Laurent Forthomme */ int main( int argc, char* argv[] ) { ostringstream os; string delim; - for ( const auto& mod : cepgen::output::ExportHandler::get().modules() ) + for ( const auto& mod : cepgen::io::ExportHandler::get().modules() ) os << delim << mod, delim = ","; if ( argc < 2 ) throw CG_FATAL( "main" ) << "No config file provided!\n\t" << "Usage: " << argv[0] << " config-file [format=" << os.str() << "] [filename=example.dat]"; cepgen::Generator mg; //----------------------------------------------------------------------------------------------- // Steering card readout //----------------------------------------------------------------------------------------------- CG_DEBUG( "main" ) << "Reading config file stored in \"" << argv[1] << "\""; mg.setParameters( cepgen::card::Handler::parse( argv[1] ) ); //----------------------------------------------------------------------------------------------- // Output file writer definition //----------------------------------------------------------------------------------------------- const string format = ( argc > 2 ) ? argv[2] : "lhef"; const char* filename = ( argc > 3 ) ? argv[3] : "example.dat"; - writer = cepgen::output::ExportHandler::get().build( format, cepgen::ParametersList() + writer = cepgen::io::ExportHandler::get().build( format, cepgen::ParametersList() .set( "filename", filename ) ); //----------------------------------------------------------------------------------------------- // CepGen run part //----------------------------------------------------------------------------------------------- // We might want to cross-check visually the validity of our run CG_INFO( "main" ) << mg.parametersPtr(); cepgen::utils::AbortHandler ctrl_c; //--- let there be cross-section... double xsec = 0., err = 0.; mg.computeXsection( xsec, err ); writer->initialise( mg.parameters() ); writer->setCrossSection( xsec, err ); // The events generation starts here! mg.generate( storeEvent ); return 0; } diff --git a/test/test_event_writer.cpp b/test/test_event_writer.cpp index 1f2e7e4..bc02f37 100644 --- a/test/test_event_writer.cpp +++ b/test/test_event_writer.cpp @@ -1,30 +1,30 @@ #include "CepGen/IO/ExportHandler.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Event/Event.h" using namespace std; using namespace cepgen; int main() { - auto writer = output::ExportHandler::get().build( "hepmc" ); + auto writer = io::ExportHandler::get().build( "hepmc" ); writer->setCrossSection( 1., 2. ); Event ev; Particle p1( Particle::IncomingBeam1, PDG::proton ); p1.setMomentum( 1., -15., 100. ); p1.setStatus( Particle::Status::Incoming ); ev.addParticle(p1); Particle p2( Particle::IncomingBeam2, PDG::electron ); p2.setMomentum( 10., 5., 3200. ); p2.setStatus( Particle::Status::Incoming ); ev.addParticle(p2); ev.dump(); *writer << ev; return 0; }