diff --git a/CMakeLists.txt b/CMakeLists.txt index 44591f5..80e9c6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,55 +1,66 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(CepGen) set(PROJECT_VERSION 1) #----- include external paths set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/cmake) set(CEPGEN_EXTERNAL_CORE_REQS "") set(CEPGEN_EXTERNAL_CARDS_REQS "") set(CEPGEN_EXTERNAL_IO_REQS "") set(CEPGEN_EXTERNAL_HADR_REQS "") set(CEPGEN_EXTERNAL_STRF_REQS "") include(UseEnvironment) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") set(CEPGEN_SOURCE_DIR ${PROJECT_SOURCE_DIR}/CepGen) set(CEPGEN_LIBRARIES CepGenCore CepGenEvent CepGenProcesses CepGenIO CepGenExternalHadronisers CepGenCards) #----- define all individual modules to be built beforehand set(CEPGEN_MODULES Processes Event IO Hadronisers 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() #----- 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/Config/Core.py b/Cards/Config/Core.py index 10a4ab1..86a0fe1 100644 --- a/Cards/Config/Core.py +++ b/Cards/Config/Core.py @@ -1,173 +1,14 @@ #!/usr/bin/env python -class PrintHelper(object): - _indent = 0 - _indent_size = 4 - def indent(self): - self._indent += self._indent_size - def unindent(self): - self._indent -= self._indent_size - def indentation(self): - return ' '*self._indent +'''@package cepgen +A collection of tools for Python steering cards definition +''' -class Parameters(dict): - '''A raw list of steering parameters''' - __getattr__ = dict.get - __setattr__ = dict.__setitem__ - __delattr__ = dict.__delitem__ - def __init__(self, *args, **kwargs): - self.update(*args, **kwargs) - super(Parameters, self).__init__(*args, **kwargs) - def __deepcopy__(self, memo): - from copy import deepcopy - return Parameters([(deepcopy(k, memo), deepcopy(v, memo)) for k, v in self.items()]) - def dump(self, printer=PrintHelper()): - out = self.__class__.__name__+'(\n' - for k, v in self.items(): - printer.indent() - out += ('%s%s = ' % (printer.indentation(), k)) - if v.__class__.__name__ not in ['Parameters', 'Module']: - out += v.__repr__() - else: - out += v.dump(printer) - out += ',\n' - printer.unindent() - out += printer.indentation()+')' - return out - def __repr__(self): - return self.dump() - def clone(self, *args, **kwargs): - from copy import deepcopy - out = deepcopy(self) - for k in kwargs: - out[k] = kwargs.get(k) - return type(self)(out) - def load(self, mod): - mod = mod.replace('/', '.') - module = __import__(mod) - self.extend(sys.modules[mod]) +#--- core components includes +from containers_cfi import Module, Parameters +from logger_cfi import Logging -class Module(Parameters): - '''A named parameters set to steer a generic module''' - def __init__(self, name, *args, **kwargs): - super(Module, self).__init__(*args, **kwargs) - self.mod_name = name - def __len__(self): - return dict.__len__(self)-1 # discard the name key - def dump(self, printer=PrintHelper()): - out = self.__class__.__name__+'('+self.mod_name.__repr__()+'\n' - mod_repr = self.clone('') - mod_repr.pop('mod_name', None) - for k, v in mod_repr.items(): - printer.indent() - out += ('%s%s = ' % (printer.indentation(), k)) - if v.__class__.__name__ not in ['Parameters', 'Module']: - out += v.__repr__() - else: - out += v.dump(printer) - out += ',\n' - printer.unindent() - out += printer.indentation()+')' - return out - def __repr__(self): - return self.dump() - def clone(self, name, **kwargs): - out = Parameters(self).clone(**kwargs) - out.mod_name = name - return out - -class Logging: - '''Logging verbosity''' - Nothing = 0 - Error = 1 - Warning = 2 - Information = 3 - Debug = 4 - DebugInsideLoop = 5 - -class StructureFunctions: - class PDFMode: - AllQuarks = 0 - ValenceQuarks = 1 - SeaQuarks = 2 - '''Types of structure functions supported''' - Electron = Parameters(id=1) - ElasticProton = Parameters(id=2) - SuriYennie = Parameters(id=11) - SzczurekUleshchenko = Parameters(id=12) - BlockDurandHa = Parameters(id=13) - FioreBrasse = Parameters(id=101) - ChristyBosted = Parameters(id=102) - CLAS = Parameters(id=103) - ALLM91 = Parameters(id=201) - ALLM97 = Parameters(id=202) - GD07p = Parameters(id=203) - GD11p = Parameters(id=204) - MSTWgrid = Parameters( - id = 205, - gridPath = 'External/F2_Luxlike_fit/mstw_f2_scan_nnlo.dat', - ) - LUXlike = Parameters( - id = 301, - #Q2cut = 10., - #W2limits = (4.,1.), - continuumSF = GD11p, - resonancesSF = ChristyBosted, - ) - LHAPDF = Parameters( - id = 401, - pdfSet = 'LUXqed17_plus_PDF4LHC15_nnlo_100', - numFlavours = 4, - mode = PDFMode.AllQuarks, - ) - -class ProcessMode: - '''Types of processes supported''' - ElectronProton = 0 - ElasticElastic = 1 - ElasticInelastic = 2 - InelasticElastic = 3 - InelasticInelastic = 4 - ProtonElectron = 5 - ElectronElectron = 6 - -if __name__ == '__main__': - import unittest - class TestTypes(unittest.TestCase): - def testModules(self): - mod = Module('empty') - self.assertEqual(len(mod), 0) - mod.param1 = 'foo' - self.assertEqual(len(mod), 1) - # playing with modules clones - mod_copy = mod.clone('notEmpty', param1 = 'boo', param2 = 'bar') - self.assertEqual(mod.param1, 'foo') - self.assertEqual(mod_copy.param1, 'boo') - self.assertEqual(mod_copy.param2, 'bar') - self.assertEqual(mod.param1+mod_copy.param2, 'foobar') - def testParameters(self): - params = Parameters( - first = 'foo', - second = 'bar', - third = 42, - fourth = (1, 2), - ) - params_copy = params.clone( - second = 'bak', - ) - self.assertEqual(len(params), 4) - self.assertEqual(params.first, params['first']) - self.assertEqual(params['second'], 'bar') - self.assertTrue(int(params.third) == params.third) - self.assertEqual(len(params.fourth), 2) - self.assertEqual(params.second, 'bar') - # playing with parameters clones - self.assertEqual(params_copy.second, 'bak') - # check that the clone does not change value if the origin does - # (i.e. we indeed have a deep copy and not a shallow one...) - params.third = 43 - self.assertEqual(params.third, 43) - self.assertEqual(params_copy.third, 42) - - unittest.main() +#--- physics-level includes +from StructureFunctions_cfi import StructureFunctions +from ProcessMode_cfi import ProcessMode diff --git a/Cards/Config/gsl_cff.py b/Cards/Config/Gsl_cfi.py similarity index 83% rename from Cards/Config/gsl_cff.py rename to Cards/Config/Gsl_cfi.py index 6366a11..fc422a5 100644 --- a/Cards/Config/gsl_cff.py +++ b/Cards/Config/Gsl_cfi.py @@ -1,8 +1,6 @@ -#import Config.Core as cepgen - class GslRngEngine: '''GSL random number generator engine''' MT19937 = 0 Taus = 1 GFSR4 = 2 RanLXS0 = 3 diff --git a/Cards/Config/pdg_cff.py b/Cards/Config/PDG_cfi.py similarity index 88% rename from Cards/Config/pdg_cff.py rename to Cards/Config/PDG_cfi.py index 3328dd0..dbcabff 100644 --- a/Cards/Config/pdg_cff.py +++ b/Cards/Config/PDG_cfi.py @@ -1,16 +1,17 @@ class PDG: + '''Named list of PDG identifiers''' down = 1 up = 2 strange = 3 charm = 4 bottom = 5 top = 6 electron = 11 muon = 13 tau = 15 gluon = 21 photon = 22 Z = 23 W = 24 proton = 2212 neutron = 2112 diff --git a/Cards/Config/ProcessMode_cfi.py b/Cards/Config/ProcessMode_cfi.py new file mode 100644 index 0000000..093fc9e --- /dev/null +++ b/Cards/Config/ProcessMode_cfi.py @@ -0,0 +1,10 @@ +class ProcessMode: + '''Types of processes supported''' + ElectronProton = 0 + ElasticElastic = 1 + ElasticInelastic = 2 + InelasticElastic = 3 + InelasticInelastic = 4 + ProtonElectron = 5 + ElectronElectron = 6 + diff --git a/Cards/Config/StructureFunctions_cfi.py b/Cards/Config/StructureFunctions_cfi.py new file mode 100644 index 0000000..ce93fb8 --- /dev/null +++ b/Cards/Config/StructureFunctions_cfi.py @@ -0,0 +1,38 @@ +from containers_cfi import Parameters + +class StructureFunctions: + class PDFMode: + AllQuarks = 0 + ValenceQuarks = 1 + SeaQuarks = 2 + '''Types of structure functions supported''' + Electron = Parameters(id=1) + ElasticProton = Parameters(id=2) + SuriYennie = Parameters(id=11) + SzczurekUleshchenko = Parameters(id=12) + BlockDurandHa = Parameters(id=13) + FioreBrasse = Parameters(id=101) + ChristyBosted = Parameters(id=102) + CLAS = Parameters(id=103) + ALLM91 = Parameters(id=201) + ALLM97 = Parameters(id=202) + GD07p = Parameters(id=203) + GD11p = Parameters(id=204) + MSTWgrid = Parameters( + id = 205, + gridPath = 'External/F2_Luxlike_fit/mstw_f2_scan_nnlo.dat', + ) + LUXlike = Parameters( + id = 301, + #Q2cut = 10., + #W2limits = (4.,1.), + continuumSF = GD11p, + resonancesSF = ChristyBosted, + ) + LHAPDF = Parameters( + id = 401, + pdfSet = 'LUXqed17_plus_PDF4LHC15_nnlo_100', + numFlavours = 4, + mode = PDFMode.AllQuarks, + ) + diff --git a/Cards/Config/Core.py b/Cards/Config/containers_cfi.py similarity index 72% copy from Cards/Config/Core.py copy to Cards/Config/containers_cfi.py index 10a4ab1..c4a377e 100644 --- a/Cards/Config/Core.py +++ b/Cards/Config/containers_cfi.py @@ -1,173 +1,134 @@ -#!/usr/bin/env python - class PrintHelper(object): + '''Helper class for the pretty-printing of configuration parameters''' _indent = 0 _indent_size = 4 def indent(self): + '''Move to the next indentation block''' self._indent += self._indent_size def unindent(self): + '''Go up to the previous indentation block''' self._indent -= self._indent_size def indentation(self): + '''Current indentation level''' return ' '*self._indent class Parameters(dict): '''A raw list of steering parameters''' __getattr__ = dict.get __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ def __init__(self, *args, **kwargs): + '''Construct from dictionary arguments''' self.update(*args, **kwargs) super(Parameters, self).__init__(*args, **kwargs) def __deepcopy__(self, memo): + '''Override the default dict deep copy operator''' from copy import deepcopy return Parameters([(deepcopy(k, memo), deepcopy(v, memo)) for k, v in self.items()]) def dump(self, printer=PrintHelper()): + '''Human-readable dump of this object''' out = self.__class__.__name__+'(\n' for k, v in self.items(): printer.indent() out += ('%s%s = ' % (printer.indentation(), k)) if v.__class__.__name__ not in ['Parameters', 'Module']: out += v.__repr__() else: out += v.dump(printer) out += ',\n' printer.unindent() out += printer.indentation()+')' return out def __repr__(self): + '''Human-readable version of this object''' return self.dump() def clone(self, *args, **kwargs): + '''Return a deep copy of this object''' from copy import deepcopy out = deepcopy(self) for k in kwargs: out[k] = kwargs.get(k) return type(self)(out) def load(self, mod): + '''Extend this object by an include''' mod = mod.replace('/', '.') module = __import__(mod) self.extend(sys.modules[mod]) class Module(Parameters): '''A named parameters set to steer a generic module''' def __init__(self, name, *args, **kwargs): + '''Construct from dictionary arguments''' super(Module, self).__init__(*args, **kwargs) self.mod_name = name def __len__(self): + '''Number of keys handled''' return dict.__len__(self)-1 # discard the name key def dump(self, printer=PrintHelper()): + '''Human-readable dump of this object''' out = self.__class__.__name__+'('+self.mod_name.__repr__()+'\n' mod_repr = self.clone('') mod_repr.pop('mod_name', None) for k, v in mod_repr.items(): printer.indent() out += ('%s%s = ' % (printer.indentation(), k)) if v.__class__.__name__ not in ['Parameters', 'Module']: out += v.__repr__() else: out += v.dump(printer) out += ',\n' printer.unindent() out += printer.indentation()+')' return out def __repr__(self): + '''Human-readable version of this object''' return self.dump() def clone(self, name, **kwargs): + '''Return a deep copy of this object''' out = Parameters(self).clone(**kwargs) out.mod_name = name return out -class Logging: - '''Logging verbosity''' - Nothing = 0 - Error = 1 - Warning = 2 - Information = 3 - Debug = 4 - DebugInsideLoop = 5 - -class StructureFunctions: - class PDFMode: - AllQuarks = 0 - ValenceQuarks = 1 - SeaQuarks = 2 - '''Types of structure functions supported''' - Electron = Parameters(id=1) - ElasticProton = Parameters(id=2) - SuriYennie = Parameters(id=11) - SzczurekUleshchenko = Parameters(id=12) - BlockDurandHa = Parameters(id=13) - FioreBrasse = Parameters(id=101) - ChristyBosted = Parameters(id=102) - CLAS = Parameters(id=103) - ALLM91 = Parameters(id=201) - ALLM97 = Parameters(id=202) - GD07p = Parameters(id=203) - GD11p = Parameters(id=204) - MSTWgrid = Parameters( - id = 205, - gridPath = 'External/F2_Luxlike_fit/mstw_f2_scan_nnlo.dat', - ) - LUXlike = Parameters( - id = 301, - #Q2cut = 10., - #W2limits = (4.,1.), - continuumSF = GD11p, - resonancesSF = ChristyBosted, - ) - LHAPDF = Parameters( - id = 401, - pdfSet = 'LUXqed17_plus_PDF4LHC15_nnlo_100', - numFlavours = 4, - mode = PDFMode.AllQuarks, - ) - -class ProcessMode: - '''Types of processes supported''' - ElectronProton = 0 - ElasticElastic = 1 - ElasticInelastic = 2 - InelasticElastic = 3 - InelasticInelastic = 4 - ProtonElectron = 5 - ElectronElectron = 6 - if __name__ == '__main__': import unittest class TestTypes(unittest.TestCase): + '''A small collection of tests for our new types''' def testModules(self): + '''Test the Module object''' mod = Module('empty') self.assertEqual(len(mod), 0) mod.param1 = 'foo' self.assertEqual(len(mod), 1) # playing with modules clones mod_copy = mod.clone('notEmpty', param1 = 'boo', param2 = 'bar') self.assertEqual(mod.param1, 'foo') self.assertEqual(mod_copy.param1, 'boo') self.assertEqual(mod_copy.param2, 'bar') self.assertEqual(mod.param1+mod_copy.param2, 'foobar') def testParameters(self): + '''Test the Parameters object''' params = Parameters( first = 'foo', second = 'bar', third = 42, fourth = (1, 2), ) params_copy = params.clone( second = 'bak', ) self.assertEqual(len(params), 4) self.assertEqual(params.first, params['first']) self.assertEqual(params['second'], 'bar') self.assertTrue(int(params.third) == params.third) self.assertEqual(len(params.fourth), 2) self.assertEqual(params.second, 'bar') # playing with parameters clones self.assertEqual(params_copy.second, 'bak') # check that the clone does not change value if the origin does # (i.e. we indeed have a deep copy and not a shallow one...) params.third = 43 self.assertEqual(params.third, 43) self.assertEqual(params_copy.third, 42) unittest.main() diff --git a/Cards/Config/integrators_cff.py b/Cards/Config/integrators_cff.py index d007d66..79c7a24 100644 --- a/Cards/Config/integrators_cff.py +++ b/Cards/Config/integrators_cff.py @@ -1,30 +1,30 @@ -import Config.Core as cepgen -from Config.gsl_cff import GslRngEngine +from containers_cfi import Module +from Gsl_cfi import GslRngEngine -plain = cepgen.Module('plain', +plain = Module('plain', numFunctionCalls = 1000000, rngEngine = GslRngEngine.MT19937, ) class VegasIntegrationMode: Stratified = -1 ImportanceOnly = 0 Importance = 1 vegas = plain.clone('Vegas', numFunctionCalls = 50000, chiSqCut = 1.5, # VEGAS-specific parameters iterations = 10, alpha = 1.5, mode = VegasIntegrationMode.Importance, verbosity = -1, loggingOutput = 'cerr', ) miser = plain.clone('MISER', # MISER-specific parameters estimateFraction = 0.1, alpha = 2., dither = 0., ) diff --git a/Cards/Config/ktProcess_cfi.py b/Cards/Config/ktProcess_cfi.py index fd40eb0..8f84bcd 100644 --- a/Cards/Config/ktProcess_cfi.py +++ b/Cards/Config/ktProcess_cfi.py @@ -1,22 +1,24 @@ import Config.Core as cepgen from math import pi class ProtonFlux: + '''Type of parton (from proton) flux modelling''' PhotonElastic = 0 PhotonInelastic = 1 PhotonInelasticBudnev = 11 GluonKMR = 20 class HeavyIonFlux: + '''Type of parton (from heavy ion) flux modelling''' PhotonElastic = 100 process = cepgen.Module('ktProcess', outKinematics = cepgen.Parameters( qt = (0., 50.), phiqt = (0., 2.*pi), #--- cuts on individual particles defining the central system rapidity = (-6., 6.), #--- cuts on the pt(outgoing system) (hyper-)plane ptdiff = (0., 500.), phiptdiff = (0., 2.*pi), ), ) diff --git a/Cards/Config/logger_cfi.py b/Cards/Config/logger_cfi.py index bedc59f..447ba0d 100644 --- a/Cards/Config/logger_cfi.py +++ b/Cards/Config/logger_cfi.py @@ -1,6 +1,15 @@ -import Config.Core as cepgen +from containers_cfi import Parameters -logger = cepgen.Parameters( - level = cepgen.Logging.Information, +class Logging: + '''Logging verbosity''' + Nothing = 0 + Error = 1 + Warning = 2 + Information = 3 + Debug = 4 + DebugInsideLoop = 5 + +logger = Parameters( + level = Logging.Information, enabledModules = (), ) diff --git a/Cards/Config/pythia8_cff.py b/Cards/Config/pythia8_cff.py index 24a26b5..ca361da 100644 --- a/Cards/Config/pythia8_cff.py +++ b/Cards/Config/pythia8_cff.py @@ -1,33 +1,37 @@ -import Config.Core as cepgen +from containers_cfi import Module, Parameters -pythia8 = cepgen.Module('pythia8', - seed = 1000, - maxTrials = 1, - pythiaPreConfiguration = ( +pythia8 = Module('pythia8', + moduleParameters = Parameters( + seed = 1000, + maxTrials = 1, + ), + preConfiguration = ( # printout properties # start by disabling some unnecessary output 'Next:numberCount = 0', # parameterise the fragmentation part #'PartonLevel:Remnants = off', # disable all Bremsstrahlung/FSR photon production 'PartonLevel:ISR = off', 'PartonLevel:FSR = off', 'PartonLevel:MPI = off', 'BeamRemnants:primordialKT = off', ), - pythiaConfiguration = ( + pythiaDefaults = ( 'ParticleDecays:allowPhotonRadiation = off', 'Tune:preferLHAPDF = 2', #'Beams:setProductionScalesFromLHEF = off', 'SLHA:keepSM = on', 'SLHA:minMassSM = 1000.', 'ParticleDecays:limitTau0 = on', 'ParticleDecays:tau0Max = 10', # CUEP8M1 tuning 'Tune:pp 14', # Monash 2013 tune by Peter Skands (January 2014) 'MultipartonInteractions:pT0Ref = 2.4024', 'MultipartonInteractions:ecmPow = 0.25208', 'MultipartonInteractions:expPow = 1.6', ), - pythiaProcessConfiguration = (), + processConfiguration = ( + 'pythiaDefaults', + ), ) diff --git a/Cards/patoccbar_cfg.py b/Cards/patoccbar_cfg.py index c3d6834..c10a708 100644 --- a/Cards/patoccbar_cfg.py +++ b/Cards/patoccbar_cfg.py @@ -1,40 +1,40 @@ import Config.Core as cepgen -import Config.ktProcess_cfi as ktfactor +import Config.ktProcess_cfi as kt from Config.integrators_cff import vegas as integrator -from Config.pdg_cff import PDG +from Config.PDG_cfi import PDG from Config.logger_cfi import logger logger.enabledModules += ('GenericKTProcess.registerVariable',) -process = ktfactor.process.clone('patoll', +process = kt.process.clone('patoff', processParameters = cepgen.Parameters( pair = PDG.charm, ), inKinematics = cepgen.Parameters( pz = (6500., 2562.2), structureFunctions = cepgen.StructureFunctions.SuriYennie, #structureFunctions = cepgen.StructureFunctions.FioreBrasse, - ktFluxes = (ktfactor.ProtonFlux.GluonKMR, ktfactor.HeavyIonFlux.PhotonElastic), - #ktFluxes = (ktfactor.ProtonFlux.PhotonElastic, ktfactor.HeavyIonFlux.PhotonElastic), + ktFluxes = (kt.ProtonFlux.GluonKMR, kt.HeavyIonFlux.PhotonElastic), + #ktFluxes = (kt.ProtonFlux.PhotonElastic, kt.HeavyIonFlux.PhotonElastic), heavyIonB = (208, 82), kmrGridPath = 'gluon_mmht2014nlo_Watt.dat', ), - outKinematics = ktfactor.process.outKinematics.clone( + outKinematics = kt.process.outKinematics.clone( pt = (0.,), energy = (0.,), rapidity = (-7., 9.), #qt = (0.,1000.), #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.), ), ) #--- events generation from Config.generator_cff import generator generator.numEvents = 10000 generator.numThreads = 1 diff --git a/Cards/patoll_cfg.py b/Cards/patoll_cfg.py index 25b9830..cc33bb7 100644 --- a/Cards/patoll_cfg.py +++ b/Cards/patoll_cfg.py @@ -1,35 +1,35 @@ import Config.Core as cepgen -import Config.ktProcess_cfi as ktfactor +import Config.ktProcess_cfi as kt from Config.integrators_cff import vegas as integrator -from Config.pdg_cff import PDG +from Config.PDG_cfi import PDG -process = ktfactor.process.clone('patoll', +process = kt.process.clone('patoff', processParameters = cepgen.Parameters( pair = PDG.muon, ), inKinematics = cepgen.Parameters( pz = (6500., 2562.2), #structureFunctions = cepgen.StructureFunctions.SuriYennie, #structureFunctions = cepgen.StructureFunctions.FioreBrasse, - #structureFunctions = cepgen.StructureFunctions.ALLM91, + #structureFunctions = cepgen.StructureFunctions.ALLM97, structureFunctions = cepgen.StructureFunctions.LUXlike, - ktFluxes = (ktfactor.ProtonFlux.PhotonInelasticBudnev, ktfactor.HeavyIonFlux.PhotonElastic), + ktFluxes = (kt.ProtonFlux.PhotonInelasticBudnev, kt.HeavyIonFlux.PhotonElastic), heavyIonB = (208, 82), ), - outKinematics = ktfactor.process.outKinematics.clone( + outKinematics = kt.process.outKinematics.clone( pt = (4.,), energy = (0.,), rapidity = (-6., 7.), #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.), ), ) #--- events generation from Config.generator_cff import generator generator.numEvents = 100000 diff --git a/Cards/pptoll_cfg.py b/Cards/pptoll_cfg.py index 998059e..2bf1f9a 100644 --- a/Cards/pptoll_cfg.py +++ b/Cards/pptoll_cfg.py @@ -1,31 +1,31 @@ import Config.Core as cepgen -import Config.ktProcess_cfi as ktfactor +import Config.ktProcess_cfi as kt from Config.integrators_cff import miser as integrator -#from Config.pythia8_cff import pythia8 as hadroniser -from Config.pdg_cff import PDG +from Config.pythia8_cff import pythia8 as hadroniser +from Config.PDG_cfi import PDG -process = ktfactor.process.clone('pptoll', +process = kt.process.clone('pptoll', processParameters = cepgen.Parameters( mode = cepgen.ProcessMode.ElasticInelastic, pair = PDG.muon, ), inKinematics = cepgen.Parameters( pz = (6500., 6500.), structureFunctions = cepgen.StructureFunctions.SuriYennie, #structureFunctions = cepgen.StructureFunctions.FioreBrasse, ), - outKinematics = ktfactor.process.outKinematics.clone( + 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.), ), ) #--- events generation from Config.generator_cff import generator generator.numEvents = 10000 diff --git a/Cards/pptottbar_cfg.py b/Cards/pptottbar_cfg.py index 3da665e..6bc823c 100644 --- a/Cards/pptottbar_cfg.py +++ b/Cards/pptottbar_cfg.py @@ -1,34 +1,36 @@ import Config.Core as cepgen -import Config.ktProcess_cfi as ktfactor +import Config.ktProcess_cfi as kt from Config.integrators_cff import vegas as integrator #from Config.pythia8_cff import pythia8 as hadroniser +from Config.PDG_cfi import PDG from Config.logger_cfi import logger logger.enabledModules += ('PPtoFF.prepare',) -process = ktfactor.process.clone('pptoff', +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 = ktfactor.process.outKinematics.clone( + outKinematics = kt.process.outKinematics.clone( pair = 6, #eta = (-2.5, 2.5), mx = (1.07, 1000.), #--- 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 #generator.treat = True diff --git a/Cards/pptoww_cfg.py b/Cards/pptoww_cfg.py index 80b5025..cfd5c38 100644 --- a/Cards/pptoww_cfg.py +++ b/Cards/pptoww_cfg.py @@ -1,67 +1,64 @@ import Config.Core as cepgen -import Config.ktProcess_cfi as ktfactor from Config.integrators_cff import vegas as integrator from Config.logger_cfi import logger -from Config.pythia8_cff import pythia8 as hadroniser -from Config.generator_cff import generator -hadroniser.pythiaProcessConfiguration += ( - # 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 -) -hadroniser.pythiaPreConfiguration += ( - #'PartonLevel:MPI = on', - #'PartonLevel:ISR = on', - #'PartonLevel:FSR = on', - 'ProcessLevel:resonanceDecays = off', # disable the W decays +from Config.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',), ) +#from Config.logger_cfi import logger +#logger.enabledModules += ('Hadroniser.configure',) -process = ktfactor.process.clone('pptoww', +import Config.ktProcess_cfi as kt +process = kt.process.clone('pptoww', processParameters = cepgen.Parameters( mode = cepgen.ProcessMode.ElasticElastic, polarisationStates = 0, # full ), inKinematics = cepgen.Parameters( cmEnergy = 13.e3, #structureFunctions = cepgen.StructureFunctions.SzczurekUleshchenko, #structureFunctions = cepgen.StructureFunctions.ALLM97, structureFunctions = cepgen.StructureFunctions.LUXlike, ), - outKinematics = ktfactor.process.outKinematics.clone( + 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)) }, ) ) -#--- import the default generation parameters +#--- generation parameters +from Config.generator_cff import generator generator = generator.clone( numEvents = 1000, printEvery = 100, treat = True, # smoothing of the integrand ) diff --git a/CepGen/Cards/LpairHandler.cpp b/CepGen/Cards/LpairHandler.cpp index cfb0b7c..1f4121a 100644 --- a/CepGen/Cards/LpairHandler.cpp +++ b/CepGen/Cards/LpairHandler.cpp @@ -1,205 +1,233 @@ #include "CepGen/Cards/LpairHandler.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Physics/PDG.h" +#include "CepGen/StructureFunctions/StructureFunctionsBuilder.h" +#include "CepGen/StructureFunctions/LHAPDF.h" + #include "CepGen/Processes/GamGamLL.h" #include "CepGen/Processes/PPtoFF.h" #include "CepGen/Processes/PPtoWW.h" +#include "CepGen/Processes/FortranProcesses.h" #include "CepGen/Hadronisers/Pythia8Hadroniser.h" #include <fstream> namespace CepGen { namespace Cards { const int LpairHandler::kInvalid = 99999; //----- specialization for LPAIR input cards LpairHandler::LpairHandler( const char* file ) : proc_params_( new ParametersList ), - hi_1_( { 0, 0 } ), hi_2_( { 0, 0 } ) + str_fun_( 11 ), 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( ¶ms_ ); + //--- parse all fields std::unordered_map<std::string, std::string> m_params; std::string key, value; std::ostringstream os; while ( f >> key >> value ) { - if ( key[0] == '#' ) continue; // FIXME need to ensure there is no extra space before! + 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 if ( proc_name_ == "lpair" ) params_.setProcess( new Process::GamGamLL( *proc_params_ ) ); else if ( proc_name_ == "pptoll" || proc_name_ == "pptoff" ) params_.setProcess( new Process::PPtoFF( *proc_params_ ) ); else if ( proc_name_ == "pptoww" ) params_.setProcess( new Process::PPtoWW( *proc_params_ ) ); + else { + Process::generateFortranProcesses(); + for ( auto& proc : Process::FortranProcessesHandler::get().list() ) + if ( proc_name_ == std::string( proc.name ) ) + params_.setProcess( new Process::FortranKTProcess( *proc_params_, proc.name, proc.description, proc.method ) ); + if ( !params_.process() ) + throw CG_FATAL( "LpairHandler" ) << "Unrecognised process name: " << proc_name_ << "!"; + } + + //--- parse the structure functions code + const unsigned long kLHAPDFCodeDec = 10000000, kLHAPDFPartDec = 1000000; + if ( str_fun_ / kLHAPDFCodeDec == 1 ) { // SF from parton + params_.kinematics.structure_functions = StructureFunctionsBuilder::get( SF::Type::LHAPDF ); + auto sf = dynamic_cast<SF::LHAPDF*>( params_.kinematics.structure_functions.get() ); + const unsigned long icode = str_fun_ % kLHAPDFCodeDec; + sf->params.pdf_code = icode % kLHAPDFPartDec; + sf->params.mode = (SF::LHAPDF::Parameterisation::Mode)( icode / kLHAPDFPartDec ); // 0, 1, 2 + } else - throw CG_FATAL( "LpairHandler" ) << "Unrecognised process name: " << proc_name_ << "!"; + params_.kinematics.structure_functions = StructureFunctionsBuilder::get( (SF::Type)str_fun_ ); + //--- parse the integration algorithm name if ( integr_type_ == "plain" ) params_.integrator.type = Integrator::Type::plain; else if ( integr_type_ == "Vegas" ) params_.integrator.type = Integrator::Type::Vegas; else if ( integr_type_ == "MISER" ) params_.integrator.type = Integrator::Type::MISER; else if ( integr_type_ != "" ) throw CG_FATAL( "LpairHandler" ) << "Unrecognized integrator type: " << integr_type_ << "!"; + //--- parse the hadronisation algorithm name if ( hadr_name_ == "pythia8" ) - params_.setHadroniser( new Hadroniser::Pythia8Hadroniser( params_ ) ); + params_.setHadroniser( new Hadroniser::Pythia8Hadroniser( params_, ParametersList() ) ); if ( m_params.count( "IEND" ) ) setValue<bool>( "IEND", ( std::stoi( m_params["IEND"] ) > 1 ) ); + //--- 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( Parameters* params ) { //------------------------------------------------------------------------------------------- // Process/integration/hadronisation parameters //------------------------------------------------------------------------------------------- registerParameter<std::string>( "PROC", "Process name to simulate", &proc_name_ ); registerParameter<std::string>( "ITYP", "Integration algorithm", &integr_type_ ); registerParameter<std::string>( "HADR", "Hadronisation algorithm", &hadr_name_ ); registerParameter<std::string>( "KMRG", "KMR grid interpolation path", ¶ms_.kinematics.kmr_grid_path ); //------------------------------------------------------------------------------------------- // General parameters //------------------------------------------------------------------------------------------- registerParameter<bool>( "IEND", "Generation type", ¶ms->generation.enabled ); registerParameter<bool>( "NTRT", "Smoothen the integrand", ¶ms->generation.treat ); registerParameter<int>( "DEBG", "Debugging verbosity", (int*)&Logger::get().level ); registerParameter<int>( "NCVG", "Number of function calls", (int*)¶ms->integrator.ncvg ); registerParameter<int>( "ITVG", "Number of integration iterations", (int*)¶ms->integrator.vegas.iterations ); registerParameter<int>( "SEED", "Random generator seed", (int*)¶ms->integrator.rng_seed ); registerParameter<int>( "NTHR", "Number of threads to use for events generation", (int*)¶ms->generation.num_threads ); registerParameter<int>( "MODE", "Subprocess' mode", (int*)¶ms->kinematics.mode ); registerParameter<int>( "NCSG", "Number of points to probe", (int*)¶ms->generation.num_points ); registerParameter<int>( "NGEN", "Number of events to generate", (int*)¶ms->generation.maxgen ); registerParameter<int>( "NPRN", "Number of events before printout", (int*)¶ms->generation.gen_print_every ); //------------------------------------------------------------------------------------------- // Process-specific parameters //------------------------------------------------------------------------------------------- registerParameter<int>( "METH", "Computation method (kT-factorisation)", &proc_params_->operator[]<int>( "method" ) ); registerParameter<int>( "IPOL", "Polarisation states to consider", &proc_params_->operator[]<int>( "polarisationStates" ) ); //------------------------------------------------------------------------------------------- // Process kinematics parameters //------------------------------------------------------------------------------------------- - registerParameter<int>( "PMOD", "Outgoing primary particles' mode", (int*)¶ms->kinematics.structure_functions ); - registerParameter<int>( "EMOD", "Outgoing primary particles' mode", (int*)¶ms->kinematics.structure_functions ); + registerParameter<int>( "PMOD", "Outgoing primary particles' mode", &str_fun_ ); + registerParameter<int>( "EMOD", "Outgoing primary particles' mode", &str_fun_ ); registerParameter<int>( "PAIR", "Outgoing particles' PDG id", (int*)&proc_params_->operator[]<int>( "pair" ) ); registerParameter<int>( "INA1", "Heavy ion atomic weight (1st incoming beam)", (int*)&hi_1_.first ); registerParameter<int>( "INZ1", "Heavy ion atomic number (1st incoming beam)", (int*)&hi_1_.second ); registerParameter<int>( "INA2", "Heavy ion atomic weight (1st incoming beam)", (int*)&hi_2_.first ); registerParameter<int>( "INZ2", "Heavy ion atomic number (1st incoming beam)", (int*)&hi_2_.second ); registerParameter<double>( "INP1", "Momentum (1st primary particle)", ¶ms->kinematics.incoming_beams.first.pz ); registerParameter<double>( "INP2", "Momentum (2nd primary particle)", ¶ms->kinematics.incoming_beams.second.pz ); registerParameter<double>( "INPP", "Momentum (1st primary particle)", ¶ms->kinematics.incoming_beams.first.pz ); registerParameter<double>( "INPE", "Momentum (2nd primary particle)", ¶ms->kinematics.incoming_beams.second.pz ); registerParameter<double>( "PTCT", "Minimal transverse momentum (single central outgoing particle)", ¶ms->kinematics.cuts.central.pt_single.min() ); registerParameter<double>( "MSCT", "Minimal central system mass", ¶ms->kinematics.cuts.central.mass_sum.min() ); registerParameter<double>( "ECUT", "Minimal energy (single central outgoing particle)", ¶ms->kinematics.cuts.central.energy_single.min() ); registerParameter<double>( "ETMN", "Minimal pseudo-rapidity (central outgoing particles)", ¶ms->kinematics.cuts.central.eta_single.min() ); registerParameter<double>( "ETMX", "Maximal pseudo-rapidity (central outgoing particles)", ¶ms->kinematics.cuts.central.eta_single.max() ); registerParameter<double>( "YMIN", "Minimal rapidity (central outgoing particles)", ¶ms->kinematics.cuts.central.rapidity_single.min() ); registerParameter<double>( "YMAX", "Maximal rapidity (central outgoing particles)", ¶ms->kinematics.cuts.central.rapidity_single.max() ); registerParameter<double>( "Q2MN", "Minimal Q² = -q² (exchanged parton)", ¶ms->kinematics.cuts.initial.q2.min() ); registerParameter<double>( "Q2MX", "Maximal Q² = -q² (exchanged parton)", ¶ms->kinematics.cuts.initial.q2.max() ); registerParameter<double>( "MXMN", "Minimal invariant mass of proton remnants", ¶ms->kinematics.cuts.remnants.mass_single.min() ); registerParameter<double>( "MXMX", "Maximal invariant mass of proton remnants", ¶ms->kinematics.cuts.remnants.mass_single.max() ); } void LpairHandler::store( const char* file ) { std::ofstream f( file, std::fstream::out | std::fstream::trunc ); if ( !f.is_open() ) { 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<double>( key.c_str(), std::stod( value ) ); } catch ( std::invalid_argument& ) {} try { setValue<int>( key.c_str(), std::stoi( value ) ); } catch ( std::invalid_argument& ) {} //setValue<bool>( key.c_str(), std::stoi( value ) ); setValue<std::string>( key.c_str(), value ); } std::string LpairHandler::getParameter( std::string key ) const { double dd = getValue<double>( key.c_str() ); if ( dd != -999. ) return std::to_string( dd ); int ui = getValue<int>( key.c_str() ); if ( ui != 999 ) return std::to_string( ui ); //if ( out = getValue<bool>( key.c_str() ) ); return getValue<std::string>( 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 78cf708..6425106 100644 --- a/CepGen/Cards/LpairHandler.h +++ b/CepGen/Cards/LpairHandler.h @@ -1,110 +1,115 @@ #ifndef CepGen_Cards_LpairReader_h #define CepGen_Cards_LpairReader_h #include "CepGen/Cards/Handler.h" #include <unordered_map> using std::string; namespace CepGen { class ParametersList; namespace Cards { /// 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: template<class T> 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<class T> void registerParameter( const char* key, const char* description, T* def ) {} /// Set a parameter value template<class T> void setValue( const char* key, const T& value ) {} /// Retrieve a parameter value template<class T> 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<std::string, Parameter<std::string> > p_strings_; std::unordered_map<std::string, Parameter<double> > p_doubles_; std::unordered_map<std::string, Parameter<int> > p_ints_; std::unordered_map<std::string, Parameter<bool> > p_bools_; void init( Parameters* ); std::shared_ptr<ParametersList> proc_params_; + int str_fun_; std::string proc_name_, hadr_name_, integr_type_; std::pair<unsigned short,unsigned short> hi_1_, hi_2_; }; //----- specialised registerers + /// Register a string parameter template<> inline void LpairHandler::registerParameter<std::string>( const char* key, const char* description, std::string* def ) { p_strings_.insert( std::make_pair( key, Parameter<std::string>( key, description, def ) ) ); } + /// Register a double floating point parameter template<> inline void LpairHandler::registerParameter<double>( const char* key, const char* description, double* def ) { p_doubles_.insert( std::make_pair( key, Parameter<double>( key, description, def ) ) ); } + /// Register an integer parameter template<> inline void LpairHandler::registerParameter<int>( const char* key, const char* description, int* def ) { p_ints_.insert( std::make_pair( key, Parameter<int>( key, description, def ) ) ); } + /// Register a boolean parameter template<> inline void LpairHandler::registerParameter<bool>( const char* key, const char* description, bool* def ) { p_bools_.insert( std::make_pair( key, Parameter<bool>( key, description, def ) ) ); } //----- specialised setters template<> inline void LpairHandler::setValue<std::string>( 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<double>( 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<int>( 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<bool>( 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 f6949c2..2670dc2 100644 --- a/CepGen/Cards/PythonHandler.cpp +++ b/CepGen/Cards/PythonHandler.cpp @@ -1,415 +1,420 @@ #include "CepGen/Cards/PythonHandler.h" #include "CepGen/Core/Exception.h" #ifdef PYTHON #include "CepGen/Core/TamingFunction.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Processes/GamGamLL.h" #include "CepGen/Processes/PPtoFF.h" #include "CepGen/Processes/PPtoWW.h" -#include "CepGen/Processes/FortranKTProcess.h" +#include "CepGen/Processes/FortranProcesses.h" #include "CepGen/StructureFunctions/StructureFunctionsBuilder.h" #include "CepGen/StructureFunctions/LHAPDF.h" #include "CepGen/StructureFunctions/MSTWGrid.h" #include "CepGen/StructureFunctions/Schaefer.h" #include "CepGen/Hadronisers/Pythia8Hadroniser.h" #include <algorithm> -extern "C" -{ - extern void nucl_to_ff_( double& ); -} - #if PY_MAJOR_VERSION < 3 # define PYTHON2 #endif namespace CepGen { namespace Cards { //----- specialization for CepGen input cards PythonHandler::PythonHandler( const char* file ) { setenv( "PYTHONPATH", ".:..:Cards", 1 ); std::string filename = getPythonPath( 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_INFO( "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 ) ); 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 = getElement( 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<std::string>( pproc_name ); //--- process mode params_.kinematics.mode = (KinematicsMode)proc_params.get<int>( "mode", (int)KinematicsMode::invalid ); if ( proc_name == "lpair" ) params_.setProcess( new Process::GamGamLL( proc_params ) ); else if ( proc_name == "pptoll" || proc_name == "pptoff" ) params_.setProcess( new Process::PPtoFF( proc_params ) ); else if ( proc_name == "pptoww" ) params_.setProcess( new Process::PPtoWW( proc_params ) ); - else if ( proc_name == "patoll" ) - params_.setProcess( new Process::FortranKTProcess( proc_params, "nucltoff", "(p/A)(p/A) ↝ (g/ɣ)ɣ → f⁺f¯", nucl_to_ff_ ) ); - else throw CG_FATAL( "PythonHandler" ) << "Unrecognised process: " << proc_name << "."; + else { + Process::generateFortranProcesses(); + for ( auto& proc : Process::FortranProcessesHandler::get().list() ) + if ( proc_name == std::string( proc.name ) ) + params_.setProcess( new Process::FortranKTProcess( proc_params, proc.name, proc.description, proc.method ) ); + if ( !params_.process() ) + throw CG_FATAL( "PythonHandler" ) << "Unrecognised process name: " << proc_name << "!"; + } //--- process kinematics PyObject* pin_kinematics = getElement( process, "inKinematics" ); // borrowed if ( pin_kinematics ) parseIncomingKinematics( pin_kinematics ); PyObject* pout_kinematics = getElement( process, "outKinematics" ); // borrowed if ( pout_kinematics ) parseOutgoingKinematics( pout_kinematics ); //--- taming functions PyObject* ptam = getElement( process, "tamingFunctions" ); // borrowed if ( ptam ) parseTamingFunctions( ptam ); Py_CLEAR( process ); PyObject* plog = PyObject_GetAttrString( cfg, "logger" ); // new if ( plog ) { parseLogging( plog ); Py_CLEAR( plog ); } //--- hadroniser parameters PyObject* phad = PyObject_GetAttrString( cfg, "hadroniser" ); // new if ( phad ) { parseHadroniser( phad ); Py_CLEAR( phad ); } //--- generation parameters PyObject* pint = PyObject_GetAttrString( cfg, "integrator" ); // new if ( pint ) { parseIntegrator( pint ); Py_CLEAR( pint ); } PyObject* pgen = PyObject_GetAttrString( cfg, "generator" ); // new if ( pgen ) { parseGenerator( pgen ); Py_CLEAR( pgen ); } //--- finalisation Py_CLEAR( cfg ); } PythonHandler::~PythonHandler() { if ( Py_IsInitialized() ) Py_Finalize(); } void PythonHandler::parseIncomingKinematics( PyObject* kin ) { //--- retrieve the beams PDG ids std::vector<double> beams_pz; fillParameter( kin, "pz", beams_pz ); if ( beams_pz.size() == 2 ) { params_.kinematics.incoming_beams.first.pz = beams_pz.at( 0 ); params_.kinematics.incoming_beams.second.pz = beams_pz.at( 1 ); } //--- retrieve the beams longitudinal momentum std::vector<int> beams_pdg; fillParameter( kin, "pdgIds", beams_pdg ); if ( beams_pdg.size() == 2 ) { params_.kinematics.incoming_beams.first.pdg = (PDG)beams_pdg.at( 0 ); params_.kinematics.incoming_beams.second.pdg = (PDG)beams_pdg.at( 1 ); } double sqrt_s = -1.; fillParameter( kin, "cmEnergy", sqrt_s ); fillParameter( kin, "kmrGridPath", params_.kinematics.kmr_grid_path ); if ( sqrt_s != -1. ) params_.kinematics.setSqrtS( sqrt_s ); PyObject* psf = getElement( kin, "structureFunctions" ); // borrowed if ( psf ) parseStructureFunctions( psf, params_.kinematics.structure_functions ); std::vector<int> kt_fluxes; fillParameter( kin, "ktFluxes", kt_fluxes ); if ( kt_fluxes.size() > 0 ) params_.kinematics.incoming_beams.first.kt_flux = (KTFlux)kt_fluxes.at( 0 ); if ( kt_fluxes.size() > 1 ) params_.kinematics.incoming_beams.second.kt_flux = (KTFlux)kt_fluxes.at( 1 ); std::vector<int> 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::parseStructureFunctions( PyObject* psf, std::shared_ptr<StructureFunctions>& sf_handler ) { int str_fun = 0; fillParameter( psf, "id", str_fun ); sf_handler = StructureFunctionsBuilder::get( (SF::Type)str_fun ); switch( (SF::Type)str_fun ) { case SF::Type::LHAPDF: { auto sf = std::dynamic_pointer_cast<SF::LHAPDF>( params_.kinematics.structure_functions ); fillParameter( psf, "pdfSet", sf->params.pdf_set ); fillParameter( psf, "numFlavours", (unsigned int&)sf->params.num_flavours ); fillParameter( psf, "pdfMember", (unsigned int&)sf->params.pdf_member ); fillParameter( psf, "mode", (unsigned int&)sf->params.mode ); } break; case SF::Type::MSTWgrid: { auto sf = std::dynamic_pointer_cast<mstw::Grid>( params_.kinematics.structure_functions ); fillParameter( psf, "gridPath", sf->params.grid_path ); } break; case SF::Type::Schaefer: { auto sf = std::dynamic_pointer_cast<SF::Schaefer>( params_.kinematics.structure_functions ); fillParameter( psf, "Q2cut", sf->params.q2_cut ); std::vector<double> w2_lims; fillParameter( psf, "W2limits", w2_lims ); if ( w2_lims.size() != 0 ) { if ( w2_lims.size() != 2 ) throwPythonError( Form( "Invalid size for W2limits attribute: %d != 2!", w2_lims.size() ) ); else { sf->params.w2_lo = *std::min_element( w2_lims.begin(), w2_lims.end() ); sf->params.w2_hi = *std::max_element( w2_lims.begin(), w2_lims.end() ); } } PyObject* pcsf = getElement( psf, "continuumSF" ); // borrowed if ( pcsf ) parseStructureFunctions( pcsf, sf->params.continuum_model ); PyObject* ppsf = getElement( psf, "perturbativeSF" ); // borrowed if ( ppsf ) parseStructureFunctions( ppsf, sf->params.perturbative_model ); PyObject* prsf = getElement( psf, "resonancesSF" ); // borrowed if ( prsf ) parseStructureFunctions( prsf, sf->params.resonances_model ); fillParameter( psf, "higherTwist", (bool&)sf->params.higher_twist ); } break; default: break; } } void PythonHandler::parseOutgoingKinematics( PyObject* kin ) { PyObject* pparts = getElement( kin, "minFinalState" ); // borrowed if ( pparts && PyTuple_Check( pparts ) ) for ( unsigned short i = 0; i < PyTuple_Size( pparts ); ++i ) params_.kinematics.minimum_final_state.emplace_back( (PDG)get<int>( PyTuple_GetItem( pparts, i ) ) ); PyObject* pcuts = getElement( kin, "cuts" ); // borrowed if ( pcuts ) parseParticlesCuts( pcuts ); // for LPAIR/collinear matrix elements fillLimits( kin, "q2", params_.kinematics.cuts.initial.q2 ); // for the kT factorised matrix elements fillLimits( kin, "qt", params_.kinematics.cuts.initial.qt ); fillLimits( kin, "phiqt", params_.kinematics.cuts.initial.phi_qt ); fillLimits( kin, "ptdiff", params_.kinematics.cuts.central.pt_diff ); fillLimits( kin, "phiptdiff", params_.kinematics.cuts.central.phi_pt_diff ); fillLimits( kin, "rapiditydiff", params_.kinematics.cuts.central.rapidity_diff ); // generic phase space limits fillLimits( kin, "rapidity", params_.kinematics.cuts.central.rapidity_single ); fillLimits( kin, "eta", params_.kinematics.cuts.central.eta_single ); fillLimits( kin, "pt", params_.kinematics.cuts.central.pt_single ); fillLimits( kin, "ptsum", params_.kinematics.cuts.central.pt_sum ); fillLimits( kin, "invmass", params_.kinematics.cuts.central.mass_sum ); fillLimits( kin, "mx", params_.kinematics.cuts.remnants.mass_single ); } void PythonHandler::parseParticlesCuts( PyObject* cuts ) { if ( !PyDict_Check( cuts ) ) throwPythonError( "Particle cuts object should be a dictionary!" ); PyObject* pkey = nullptr, *pvalue = nullptr; Py_ssize_t pos = 0; while ( PyDict_Next( cuts, &pos, &pkey, &pvalue ) ) { const PDG pdg = (PDG)get<int>( pkey ); fillLimits( pvalue, "pt", params_.kinematics.cuts.central_particles[pdg].pt_single ); fillLimits( pvalue, "energy", params_.kinematics.cuts.central_particles[pdg].energy_single ); fillLimits( pvalue, "eta", params_.kinematics.cuts.central_particles[pdg].eta_single ); fillLimits( pvalue, "rapidity", params_.kinematics.cuts.central_particles[pdg].rapidity_single ); } } void PythonHandler::parseLogging( PyObject* log ) { fillParameter( log, "level", (int&)Logger::get().level ); std::vector<std::string> enabled_modules; fillParameter( log, "enabledModules", enabled_modules ); for ( const auto& mod : enabled_modules ) Logger::get().addExceptionRule( mod ); } void PythonHandler::parseIntegrator( PyObject* integr ) { if ( !PyDict_Check( integr ) ) throwPythonError( "Integrator object should be a dictionary!" ); PyObject* palgo = getElement( integr, MODULE_NAME ); // borrowed if ( !palgo ) throwPythonError( "Failed to retrieve the integration algorithm name!" ); std::string algo = get<std::string>( palgo ); if ( algo == "plain" ) params_.integrator.type = Integrator::Type::plain; else if ( algo == "Vegas" ) { params_.integrator.type = Integrator::Type::Vegas; fillParameter( integr, "alpha", (double&)params_.integrator.vegas.alpha ); fillParameter( integr, "iterations", params_.integrator.vegas.iterations ); fillParameter( integr, "mode", (int&)params_.integrator.vegas.mode ); fillParameter( integr, "verbosity", (int&)params_.integrator.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_.integrator.vegas.ostream = stderr; else if ( vegas_logging_output == "cout" ) // redirect all debugging information to the standard stream params_.integrator.vegas.ostream = stdout; else params_.integrator.vegas.ostream = fopen( vegas_logging_output.c_str(), "w" ); } else if ( algo == "MISER" ) { params_.integrator.type = Integrator::Type::MISER; fillParameter( integr, "estimateFraction", (double&)params_.integrator.miser.estimate_frac ); fillParameter( integr, "minCalls", params_.integrator.miser.min_calls ); fillParameter( integr, "minCallsPerBisection", params_.integrator.miser.min_calls_per_bisection ); fillParameter( integr, "alpha", (double&)params_.integrator.miser.alpha ); fillParameter( integr, "dither", (double&)params_.integrator.miser.dither ); } else throwPythonError( Form( "Invalid integration algorithm: %s", algo.c_str() ) ); fillParameter( integr, "numFunctionCalls", params_.integrator.ncvg ); fillParameter( integr, "seed", (unsigned long&)params_.integrator.rng_seed ); unsigned int rng_engine; fillParameter( integr, "rngEngine", rng_engine ); switch ( rng_engine ) { case 0: default: params_.integrator.rng_engine = (gsl_rng_type*)gsl_rng_mt19937; break; case 1: params_.integrator.rng_engine = (gsl_rng_type*)gsl_rng_taus2; break; case 2: params_.integrator.rng_engine = (gsl_rng_type*)gsl_rng_gfsr4; break; case 3: params_.integrator.rng_engine = (gsl_rng_type*)gsl_rng_ranlxs0; break; } fillParameter( integr, "chiSqCut", params_.integrator.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::parseTamingFunctions( PyObject* tf ) { if ( !PyList_Check( tf ) ) throwPythonError( "Taming functions list should be a list!" ); for ( Py_ssize_t i = 0; i < PyList_Size( tf ); ++i ) { PyObject* pit = PyList_GetItem( tf, i ); // borrowed if ( !pit ) continue; if ( !PyDict_Check( pit ) ) throwPythonError( Form( "Item %d has invalid type %s", i, pit->ob_type->tp_name ) ); PyObject* pvar = getElement( pit, "variable" ), *pexpr = getElement( pit, "expression" ); // borrowed params_.taming_functions->add( get<std::string>( pvar ).c_str(), get<std::string>( pexpr ).c_str() ); } } void PythonHandler::parseHadroniser( PyObject* hadr ) { if ( !PyDict_Check( hadr ) ) throwPythonError( "Hadroniser object should be a dictionary!" ); PyObject* pname = getElement( hadr, MODULE_NAME ); // borrowed if ( !pname ) throwPythonError( "Hadroniser name is required!" ); std::string hadr_name = get<std::string>( pname ); - fillParameter( hadr, "maxTrials", params_.hadroniser_max_trials ); - PyObject* pseed = getElement( hadr, "seed" ); // borrowed - long long seed = -1ll; - if ( pseed && is<int>( pseed ) ) { - seed = PyLong_AsLongLong( pseed ); - CG_DEBUG( "PythonHandler:hadroniser" ) << "Hadroniser seed set to " << seed; + //--- list of module-specific parameters + ParametersList mod_params; + fillParameter( hadr, "moduleParameters", mod_params ); + + if ( hadr_name == "pythia8" ) + params_.setHadroniser( new Hadroniser::Pythia8Hadroniser( params_, mod_params ) ); + else + throwPythonError( Form( "Unrecognised hadronisation algorithm: \"%s\"!", hadr_name.c_str() ) ); + + auto h = params_.hadroniser(); + { //--- before calling the init() method + std::vector<std::string> config; + fillParameter( hadr, "preConfiguration", config ); + h->readStrings( config ); } - if ( hadr_name == "pythia8" ) { - params_.setHadroniser( new Hadroniser::Pythia8Hadroniser( params_ ) ); + h->init(); + { //--- after init() has been called std::vector<std::string> config; - auto pythia8 = dynamic_cast<Hadroniser::Pythia8Hadroniser*>( params_.hadroniser() ); - pythia8->setSeed( seed ); - fillParameter( hadr, "pythiaPreConfiguration", config ); - pythia8->readStrings( config ); - pythia8->init(); - fillParameter( hadr, "pythiaConfiguration", config ); - pythia8->readStrings( config ); - fillParameter( hadr, "pythiaProcessConfiguration", config ); - pythia8->readStrings( config ); + fillParameter( hadr, "processConfiguration", config ); + for ( const auto& block : config ) { + std::vector<std::string> config_blk; + fillParameter( hadr, block.c_str(), config_blk ); + h->readStrings( config_blk ); + } } } } } #endif diff --git a/CepGen/Cards/PythonTypes.cpp b/CepGen/Cards/PythonTypes.cpp index 0c6b7e8..66361ff 100644 --- a/CepGen/Cards/PythonTypes.cpp +++ b/CepGen/Cards/PythonTypes.cpp @@ -1,165 +1,171 @@ #include "CepGen/Cards/PythonHandler.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/utils.h" #ifdef PYTHON #if PY_MAJOR_VERSION < 3 # define PYTHON2 #endif namespace CepGen { namespace Cards { //------------------------------------------------------------------ // typed retrieval helpers //------------------------------------------------------------------ template<> bool PythonHandler::is<int>( PyObject* obj ) const { #ifdef PYTHON2 return ( PyInt_Check( obj ) || PyBool_Check( obj ) ); #else return ( PyLong_Check( obj ) || PyBool_Check( obj ) ); #endif } template<> int PythonHandler::get<int>( PyObject* obj ) const { #ifdef PYTHON2 return PyInt_AsLong( obj ); #else return PyLong_AsLong( obj ); #endif } template<> unsigned long PythonHandler::get<unsigned long>( PyObject* obj ) const { #ifdef PYTHON2 return PyInt_AsUnsignedLongMask( obj ); #else if ( !PyLong_Check( obj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, obj->ob_type->tp_name ) ); return PyLong_AsUnsignedLong( obj ); #endif } + template<> long long + PythonHandler::get<long long>( PyObject* obj ) const + { + return PyLong_AsLongLong( obj ); + } + template<> bool PythonHandler::is<double>( PyObject* obj ) const { return PyFloat_Check( obj ); } template<> double PythonHandler::get<double>( PyObject* obj ) const { return PyFloat_AsDouble( obj ); } template<> bool PythonHandler::is<std::string>( PyObject* obj ) const { #ifdef PYTHON2 return PyString_Check( obj ); #else return PyUnicode_Check( obj ); #endif } template<> std::string PythonHandler::get<std::string>( PyObject* obj ) const { std::string out; #ifdef PYTHON2 out = PyString_AsString( obj ); // deprecated in python v3+ #else PyObject* pstr = PyUnicode_AsEncodedString( obj, "utf-8", "strict" ); // new if ( !pstr ) throwPythonError( "Failed to decode a Python object!" ); out = PyBytes_AS_STRING( pstr ); Py_CLEAR( pstr ); #endif return out; } template<> bool PythonHandler::is<ParametersList>( PyObject* obj ) const { return PyDict_Check( obj ); } template<> ParametersList PythonHandler::get<ParametersList>( PyObject* obj ) const { ParametersList out; PyObject* pkey = nullptr, *pvalue = nullptr; Py_ssize_t pos = 0; while ( PyDict_Next( obj, &pos, &pkey, &pvalue ) ) { const std::string skey = get<std::string>( pkey ); if ( is<int>( pvalue ) ) out.set<int>( skey, get<int>( pvalue ) ); else if ( is<double>( pvalue ) ) out.set<double>( skey, get<double>( pvalue ) ); else if ( is<std::string>( pvalue ) ) out.set<std::string>( skey, get<std::string>( pvalue ) ); else if ( is<ParametersList>( pvalue ) ) out.set<ParametersList>( skey, get<ParametersList>( pvalue ) ); else if ( PyTuple_Check( pvalue ) || PyList_Check( pvalue ) ) { // vector PyObject* pfirst = PyTuple_GetItem( pvalue, 0 ); PyObject* pit = nullptr; const bool tuple = PyTuple_Check( pvalue ); const Py_ssize_t num_entries = ( tuple ) ? PyTuple_Size( pvalue ) : PyList_Size( pvalue ); if ( is<int>( pfirst ) ) { std::vector<int> vec; for ( Py_ssize_t i = 0; i < num_entries; ++i ) { pit = ( tuple ) ? PyTuple_GetItem( pvalue, i ) : PyList_GetItem( pvalue, i ); if ( pit->ob_type != pfirst->ob_type ) throwPythonError( Form( "Mixed types detected in vector '%s'", skey.c_str() ) ); vec.emplace_back( get<int>( pit ) ); } out.set<std::vector<int> >( skey, vec ); } else if ( is<double>( pfirst ) ) { std::vector<double> vec; for ( Py_ssize_t i = 0; i < num_entries; ++i ) { pit = ( tuple ) ? PyTuple_GetItem( pvalue, i ) : PyList_GetItem( pvalue, i ); if ( pit->ob_type != pfirst->ob_type ) throwPythonError( Form( "Mixed types detected in vector '%s'", skey.c_str() ) ); vec.emplace_back( get<double>( pit ) ); } out.set<std::vector<double> >( skey, vec ); } else if ( is<std::string>( pfirst ) ) { std::vector<std::string> vec; for ( Py_ssize_t i = 0; i < num_entries; ++i ) { pit = ( tuple ) ? PyTuple_GetItem( pvalue, i ) : PyList_GetItem( pvalue, i ); if ( pit->ob_type != pfirst->ob_type ) throwPythonError( Form( "Mixed types detected in vector '%s'", skey.c_str() ) ); vec.emplace_back( get<std::string>( pit ) ); } out.set<std::vector<std::string> >( skey, vec ); } else if ( is<ParametersList>( pfirst ) ) { std::vector<ParametersList> vec; for ( Py_ssize_t i = 0; i < num_entries; ++i ) { pit = ( tuple ) ? PyTuple_GetItem( pvalue, i ) : PyList_GetItem( pvalue, i ); if ( pit->ob_type != pfirst->ob_type ) throwPythonError( Form( "Mixed types detected in vector '%s'", skey.c_str() ) ); vec.emplace_back( get<ParametersList>( pit ) ); } out.set<std::vector<ParametersList> >( skey, vec ); } } } return out; } } } #endif diff --git a/CepGen/Cards/PythonUtils.cpp b/CepGen/Cards/PythonUtils.cpp index 50885c7..b53a57d 100644 --- a/CepGen/Cards/PythonUtils.cpp +++ b/CepGen/Cards/PythonUtils.cpp @@ -1,252 +1,251 @@ #include "CepGen/Cards/PythonHandler.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #ifdef PYTHON #include <string> #include <algorithm> #include <frameobject.h> #if PY_MAJOR_VERSION < 3 # define PYTHON2 #endif namespace CepGen { namespace Cards { //------------------------------------------------------------------ // Python API helpers //------------------------------------------------------------------ std::string PythonHandler::getPythonPath( const char* file ) { std::string s_filename = file; s_filename = s_filename.substr( 0, s_filename.find_last_of( "." ) ); // remove the extension std::replace( s_filename.begin(), s_filename.end(), '/', '.' ); // replace all '/' by '.' return s_filename; } void PythonHandler::throwPythonError( const std::string& message ) { PyObject* ptype = nullptr, *pvalue = nullptr, *ptraceback_obj = nullptr; // retrieve error indicator and clear it to handle ourself the error PyErr_Fetch( &ptype, &pvalue, &ptraceback_obj ); PyErr_Clear(); // ensure the objects retrieved are properly normalised and point to compatible objects PyErr_NormalizeException( &ptype, &pvalue, &ptraceback_obj ); std::ostringstream oss; oss << message; if ( ptype != nullptr ) { // we can start the traceback oss << "\n\tError: " #ifdef PYTHON2 << PyString_AsString( PyObject_Str( pvalue ) ); // deprecated in python v3+ #else << PyUnicode_AsUTF8( PyObject_Str( pvalue ) ); #endif PyTracebackObject* ptraceback = (PyTracebackObject*)ptraceback_obj; std::string tabul = "↪ "; if ( ptraceback != nullptr ) { while ( ptraceback->tb_next != nullptr ) { PyFrameObject* pframe = ptraceback->tb_frame; if ( pframe != nullptr ) { int line = PyCode_Addr2Line( pframe->f_code, pframe->f_lasti ); #ifdef PYTHON2 const char* filename = PyString_AsString( pframe->f_code->co_filename ); const char* funcname = PyString_AsString( pframe->f_code->co_name ); #else const char* filename = PyUnicode_AsUTF8( pframe->f_code->co_filename ); const char* funcname = PyUnicode_AsUTF8( pframe->f_code->co_name ); #endif oss << Form( "\n\t%s%s on %s (line %d)", tabul.c_str(), boldify( funcname ).c_str(), filename, line ); } else oss << Form( "\n\t%s issue in line %d", tabul.c_str(), ptraceback->tb_lineno ); tabul = std::string( " " )+tabul; ptraceback = ptraceback->tb_next; } } } Py_Finalize(); throw CG_FATAL( "PythonHandler:error" ) << oss.str(); } PyObject* PythonHandler::encode( const char* str ) { PyObject* obj = PyUnicode_FromString( str ); // new if ( !obj ) throwPythonError( Form( "Failed to encode the following string:\n\t%s", str ) ); return obj; } PyObject* PythonHandler::getElement( PyObject* obj, const char* key ) { PyObject* pout = nullptr, *nink = encode( key ); if ( !nink ) return pout; pout = PyDict_GetItem( obj, nink ); // borrowed Py_CLEAR( nink ); if ( pout ) CG_DEBUG( "PythonHandler:getElement" ) << "retrieved " << pout->ob_type->tp_name << " element \"" << key << "\" " << "from " << obj->ob_type->tp_name << " object\n\t" << "new reference count: " << pout->ob_refcnt; else CG_DEBUG( "PythonHandler:getElement" ) << "did not retrieve a valid element \"" << key << "\""; return pout; } void PythonHandler::fillLimits( PyObject* obj, const char* key, Limits& lim ) { PyObject* pobj = getElement( obj, key ); // borrowed if ( !pobj ) return; if ( !PyTuple_Check( pobj ) ) throw CG_FATAL( "PythonHandler:fillLimits" ) << "Invalid value retrieved for " << key << "."; if ( PyTuple_Size( pobj ) < 1 ) throw CG_FATAL( "PythonHandler:fillLimits" ) << "Invalid number of values unpacked for " << key << "!"; double min = get<double>( PyTuple_GetItem( pobj, 0 ) ); lim.min() = min; if ( PyTuple_Size( pobj ) > 1 ) { double max = get<double>( PyTuple_GetItem( pobj, 1 ) ); if ( max != -1 ) lim.max() = max; } } void PythonHandler::fillParameter( PyObject* parent, const char* key, bool& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !PyBool_Check( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); fillParameter( parent, key, (int&)out ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, int& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !is<int>( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); out = get<int>( pobj ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, unsigned long& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !is<int>( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); out = get<unsigned long>( pobj ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, unsigned int& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !is<int>( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); out = get<unsigned long>( pobj ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, double& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !is<double>( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); out = get<double>( pobj ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, std::string& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !is<std::string>( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); out = get<std::string>( pobj ); } void PythonHandler::fillParameter( PyObject* parent, const char* key, std::vector<double>& out ) { out.clear(); PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !PyTuple_Check( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); for ( Py_ssize_t i = 0; i < PyTuple_Size( pobj ); ++i ) { PyObject* pit = PyTuple_GetItem( pobj, i ); // borrowed - if ( !is<double>( pit ) ) - continue; - out.emplace_back( get<double>( pit ) ); + if ( is<double>( pit ) ) + out.emplace_back( get<double>( pit ) ); } } void PythonHandler::fillParameter( PyObject* parent, const char* key, std::vector<std::string>& out ) { out.clear(); PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !PyTuple_Check( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type %s", key, pobj->ob_type->tp_name ) ); for ( Py_ssize_t i = 0; i < PyTuple_Size( pobj ); ++i ) { PyObject* pit = PyTuple_GetItem( pobj, i ); // borrowed out.emplace_back( get<std::string>( pit ) ); } } void PythonHandler::fillParameter( PyObject* parent, const char* key, std::vector<int>& out ) { out.clear(); PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !PyTuple_Check( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type", key ) ); for ( Py_ssize_t i = 0; i < PyTuple_Size( pobj ); ++i ) { PyObject* pit = PyTuple_GetItem( pobj, i ); if ( !is<int>( pit ) ) throwPythonError( Form( "Object %d has invalid type", i ) ); out.emplace_back( get<int>( pit ) ); } } void PythonHandler::fillParameter( PyObject* parent, const char* key, ParametersList& out ) { PyObject* pobj = getElement( parent, key ); // borrowed if ( !pobj ) return; if ( !PyDict_Check( pobj ) ) throwPythonError( Form( "Object \"%s\" has invalid type", key ) ); out += get<ParametersList>( pobj ); } } } #endif diff --git a/CepGen/Core/Exception.h b/CepGen/Core/Exception.h index 353f9c9..38e0e0f 100644 --- a/CepGen/Core/Exception.h +++ b/CepGen/Core/Exception.h @@ -1,191 +1,194 @@ #ifndef CepGen_Core_Exception_h #define CepGen_Core_Exception_h #include <sstream> #include <stdexcept> #include <csignal> #include "CepGen/Core/Logger.h" #define CG_EXCEPT_MATCH( str, type ) \ CepGen::Logger::get().passExceptionRule( str, CepGen::Logger::Level::type ) #define CG_LOG( mod ) \ ( !CG_EXCEPT_MATCH( mod, information ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::verbatim ) #define CG_INFO( mod ) \ ( !CG_EXCEPT_MATCH( mod, information ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::info ) #define CG_DEBUG( mod ) \ ( !CG_EXCEPT_MATCH( mod, debug ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::debug ) #define CG_DEBUG_LOOP( mod ) \ ( !CG_EXCEPT_MATCH( mod, debugInsideLoop ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::debug ) #define CG_WARNING( mod ) \ ( !CG_EXCEPT_MATCH( mod, warning ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::warning ) #define CG_ERROR( mod ) \ ( !CG_EXCEPT_MATCH( mod, error ) ) \ ? CepGen::NullStream( mod ) \ : CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::warning ) #define CG_FATAL( mod ) \ CepGen::Exception( __PRETTY_FUNCTION__, mod, CepGen::Exception::Type::fatal ) namespace CepGen { - /// A simple exception handler + /// \brief A simple exception handler /// \author Laurent Forthomme <laurent.forthomme@cern.ch> /// \date 24 Mar 2015 class Exception : public std::exception { public: /// Enumeration of exception severities /// \author Laurent Forthomme <laurent.forthomme@cern.ch> /// \date 27 Mar 2015 enum class Type { undefined = -1, debug, verbatim, info, warning, error, fatal }; /// Generic constructor - /// \param[in] from method invoking the exception /// \param[in] module exception classifier /// \param[in] type exception type /// \param[in] id exception code (useful for logging) explicit inline Exception( const char* module = "", Type type = Type::undefined, const int id = 0 ) : module_( module ), type_( type ), error_num_( id ) {} /// Generic constructor /// \param[in] from method invoking the exception /// \param[in] module exception classifier /// \param[in] type exception type /// \param[in] id exception code (useful for logging) explicit inline Exception( const char* from, const char* module, Type type = Type::undefined, const int id = 0 ) : from_( from ), module_( module ), type_( type ), error_num_( id ) {} /// Generic constructor /// \param[in] from method invoking the exception /// \param[in] module exception classifier /// \param[in] type exception type /// \param[in] id exception code (useful for logging) explicit inline Exception( const char* from, const std::string& module, Type type = Type::undefined, const int id = 0 ) : from_( from ), module_( module ), type_( type ), error_num_( id ) {} /// Copy constructor inline Exception( const Exception& rhs ) : from_( rhs.from_ ), module_( rhs.module_ ), message_( rhs.message_.str() ), type_( rhs.type_ ), error_num_( rhs.error_num_ ) {} /// Default destructor (potentially killing the process) inline ~Exception() noexcept override { do { dump(); } while ( 0 ); // we stop this process' execution on fatal exception if ( type_ == Type::fatal ) if ( raise( SIGINT ) != 0 ) exit( 0 ); } //----- Overloaded stream operators /// Generic templated message feeder operator template<typename T> inline friend const Exception& operator<<( const Exception& exc, T var ) { Exception& nc_except = const_cast<Exception&>( exc ); nc_except.message_ << var; return exc; } /// Pipe modifier operator inline friend const Exception& operator<<( const Exception& exc, std::ios_base&( *f )( std::ios_base& ) ) { Exception& nc_except = const_cast<Exception&>( exc ); f( nc_except.message_ ); return exc; } /// Exception message /*inline const char* what() const noexcept override { return message_.str().c_str(); }*/ /// Extract the origin of the exception inline std::string from() const { return from_; } /// Extract the exception code inline int errorNumber() const { return error_num_; } /// Extract the exception type inline Type type() const { return type_; } /// Extract a human-readable (and colourified) version of the exception type inline std::string typeString() const { switch ( type() ) { case Type::warning: return "\033[34;1mWarning\033[0m"; case Type::info: return "\033[32;1mInfo.\033[0m"; case Type::debug: return "\033[33;1mDebug\033[0m"; case Type::error: return "\033[31;1mError\033[0m"; case Type::fatal: return "\033[31;1mFatal\033[0m"; case Type::undefined: default: return "\33[7;1mUndefined\033[0m"; } } /// Dump the full exception information in a given output stream /// \param[inout] os the output stream where the information is dumped inline void dump( std::ostream& os = *Logger::get().output ) const { os << fullMessage() << std::endl; } /// Extract a one-line summary of the exception inline std::string shortMessage() const { std::ostringstream os; os << "[" << typeString() << "]"; if ( type_ == Type::debug || type_ == Type::warning ) os << " \033[30;4m" << from_ << "\033[0m\n"; os << "\t" << message_.str(); return os.str(); } private: inline static char* now() { static char buffer[10]; time_t rawtime; time( &rawtime ); struct tm* timeinfo = localtime( &rawtime ); strftime( buffer, 10, "%H:%M:%S", timeinfo ); return buffer; } /// Extract a full exception message inline std::string fullMessage() const { if ( type_ == Type::info || type_ == Type::debug || type_ == Type::warning ) return shortMessage(); if ( type_ == Type::verbatim ) return message_.str(); std::ostringstream os; os << "============================= Exception detected! =============================" << std::endl << " Class: " << typeString() << std::endl; if ( !from_.empty() ) os << " Raised by: " << from_ << std::endl; os << " Description: \t" << message_.str() << std::endl; if ( errorNumber() != 0 ) os << "-------------------------------------------------------------------------------" << std::endl << " Error #" << error_num_ << std::endl; os << "==============================================================================="; return os.str(); } /// Origin of the exception std::string from_; /// Exception classificator std::string module_; /// Message to throw std::ostringstream message_; /// Exception type Type type_; /// Integer exception number int error_num_; }; - /// Placeholder for debugging messages if logging threshold is not reached + /// \brief Placeholder for debugging messages if logging threshold is not reached /// \date Apr 2018 struct NullStream { + /// Construct from a module name explicit NullStream( const char* ) {} + /// Construct from a module name explicit NullStream( const std::string& ) {} + /// Copy constructor NullStream( const Exception& ) {} + /// Stream operator (null and void) template<class T> NullStream& operator<<( const T& ) { return *this; } }; } #endif diff --git a/CepGen/IO/FortranInterface.cpp b/CepGen/Core/FortranInterface.cpp similarity index 97% rename from CepGen/IO/FortranInterface.cpp rename to CepGen/Core/FortranInterface.cpp index b709844..7f8dca2 100644 --- a/CepGen/IO/FortranInterface.cpp +++ b/CepGen/Core/FortranInterface.cpp @@ -1,98 +1,99 @@ #include "CepGen/StructureFunctions/StructureFunctionsBuilder.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/KTFlux.h" #include "CepGen/Physics/HeavyIon.h" #include "CepGen/Physics/ParticleProperties.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; SF::Type sf_mode = (SF::Type)sfmode; CG_DEBUG( "cepgen_structure_functions" ) << sf_mode; static StructureFunctions& val = StructureFunctionsBuilder::get( sf_mode )->operator()( xbj, q2 ); f2 = val.F2; fl = val.FL; } double cepgen_kt_flux_( int& fmode, double& x, double& kt2, int& sfmode, double& mx ) { using namespace CepGen; static auto sf = StructureFunctionsBuilder::get( (SF::Type)sfmode ); return ktFlux( (KTFlux)fmode, x, kt2, *sf, mx ); } 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 } ); } double cepgen_particle_mass_( int& pdg_id ) { try { return CepGen::ParticleProperties::mass( (CepGen::PDG)pdg_id ); } catch ( const CepGen::Exception& e ) { e.dump(); exit( 0 ); } } double cepgen_particle_charge_( int& pdg_id ) { try { return CepGen::ParticleProperties::charge( pdg_id ); } catch ( const CepGen::Exception& e ) { e.dump(); exit( 0 ); } } #ifdef __cplusplus } #endif namespace CepGen { namespace Process { struct FortranKTProcessWrapper : GenericKTProcess { FortranKTProcessWrapper( const std::string& name, unsigned short parton_pdg, unsigned short outgoing_pdg ) : GenericKTProcess( name, std::string( "Fortran wrapped ")+name, 4, { (ParticleCode)parton_pdg, (ParticleCode)parton_pdg }, { (ParticleCode)outgoing_pdg, (ParticleCode)outgoing_pdg } ) {} ~FortranKTProcessWrapper() {} double x[10]; }; } } extern "C" { extern double test_weight_(); extern struct { } test_params_; } #define add_kt_process( name, prefix, parton_pdg, outgoing_pdg ) \ extern "C" {\ extern double prefix##_weight_();\ extern struct {\ } prefix##_params_;\ } \ add_kt_process( pptoll_fortran, pptoll, 22, 11 ) diff --git a/CepGen/Core/Generator.cpp b/CepGen/Core/Generator.cpp index ca646fc..a402891 100644 --- a/CepGen/Core/Generator.cpp +++ b/CepGen/Core/Generator.cpp @@ -1,165 +1,171 @@ #include "CepGen/Generator.h" #include "CepGen/Parameters.h" #include "CepGen/Version.h" #include "CepGen/Core/Integrator.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/Timer.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Event/Event.h" #include <fstream> #include <chrono> namespace CepGen { volatile int gSignal; Generator::Generator() : - parameters( std::unique_ptr<Parameters>( new Parameters ) ), - cross_section_( -1. ), cross_section_error_( -1. ) + parameters( std::unique_ptr<Parameters>( new Parameters ) ), result_( -1. ), result_error_( -1. ) { CG_DEBUG( "Generator:init" ) << "Generator initialized"; try { printHeader(); } catch ( Exception& e ) { e.dump(); } // Random number initialization std::chrono::system_clock::time_point time = std::chrono::system_clock::now(); srandom( time.time_since_epoch().count() ); } Generator::Generator( Parameters* ip ) : - parameters( ip ), - cross_section_( -1. ), cross_section_error_( -1. ) + parameters( ip ), result_( -1. ), result_error_( -1. ) {} Generator::~Generator() { if ( parameters->generation.enabled && parameters->process() && parameters->numGeneratedEvents() > 0 ) { CG_INFO( "Generator" ) << "Mean generation time / event: " << parameters->totalGenerationTime()*1.e3/parameters->numGeneratedEvents() << " ms."; } } size_t Generator::numDimensions() const { if ( !parameters->process() ) return 0; parameters->process()->addEventContent(); parameters->process()->setKinematics( parameters->kinematics ); return parameters->process()->numDimensions(); } void Generator::clearRun() { integrator_.reset(); parameters->process()->first_run = true; - cross_section_ = cross_section_error_ = -1.; + result_ = result_error_ = -1.; } void Generator::setParameters( Parameters& ip ) { parameters = std::unique_ptr<Parameters>( new Parameters( ip ) ); // copy constructor } void Generator::printHeader() { std::string tmp; std::ostringstream os; os << "version " << version() << std::endl; std::ifstream hf( "README" ); if ( !hf.good() ) throw CG_WARNING( "Generator" ) << "Failed to open README file."; while ( true ) { if ( !hf.good() ) break; getline( hf, tmp ); os << "\n " << tmp; } hf.close(); CG_INFO( "Generator" ) << os.str(); } double Generator::computePoint( double* x ) { double res = Integrand::eval( x, numDimensions(), (void*)parameters.get() ); std::ostringstream os; for ( unsigned int i = 0; i < numDimensions(); ++i ) os << x[i] << " "; CG_DEBUG( "Generator:computePoint" ) - << "Result for x[" << numDimensions() << "] = ( " << os.str() << "):\n\t" + << "Result for x[" << numDimensions() << "] = { " << os.str() << "}:\n\t" << res << "."; return res; } void Generator::computeXsection( double& xsec, double& err ) { CG_INFO( "Generator" ) << "Starting the computation of the process cross-section."; + integrate(); + + xsec = result_; + err = result_error_; + + if ( xsec < 1.e-2 ) + CG_INFO( "Generator" ) + << "Total cross section: " << xsec*1.e3 << " +/- " << err*1.e3 << " fb."; + else if ( xsec > 5.e2 ) + CG_INFO( "Generator" ) + << "Total cross section: " << xsec*1.e-3 << " +/- " << err*1.e-3 << " nb."; + else + CG_INFO( "Generator" ) + << "Total cross section: " << xsec << " +/- " << err << " pb."; + } + + void + Generator::integrate() + { // first destroy and recreate the integrator instance if ( !integrator_ ) integrator_ = std::unique_ptr<Integrator>( new Integrator( numDimensions(), Integrand::eval, parameters.get() ) ); else if ( integrator_->dimensions() != numDimensions() ) integrator_.reset( new Integrator( numDimensions(), Integrand::eval, parameters.get() ) ); CG_DEBUG( "Generator:newInstance" ) << "New integrator instance created\n\t" << "Considered topology: " << parameters->kinematics.mode << " case\n\t" << "Will proceed with " << numDimensions() << "-dimensional integration."; - const int res = integrator_->integrate( cross_section_, cross_section_error_ ); + const int res = integrator_->integrate( result_, result_error_ ); if ( res != 0 ) - throw CG_FATAL( "Generator" ) << "Error while computing the cross-section: return value = " << res << "."; - - xsec = cross_section_; - err = cross_section_error_; - - if ( xsec < 1.e-2 ) - CG_INFO( "Generator" ) - << "Total cross section: " << xsec*1.e3 << " +/- " << err*1.e3 << " fb."; - else if ( xsec > 5.e2 ) - CG_INFO( "Generator" ) - << "Total cross section: " << xsec*1.e-3 << " +/- " << err*1.e-3 << " nb."; - else - CG_INFO( "Generator" ) - << "Total cross section: " << xsec << " +/- " << err << " pb."; + throw CG_FATAL( "Generator" ) + << "Error while computing the cross-section!\n\t" + << "GSL error: " << gsl_strerror( res ) << "."; } std::shared_ptr<Event> Generator::generateOneEvent() { integrator_->generateOne(); parameters->addGenerationTime( parameters->process()->last_event->time_total ); return parameters->process()->last_event; } void Generator::generate( std::function<void( const Event&, unsigned long )> callback ) { const Timer tmr; CG_INFO( "Generator" ) << parameters->generation.maxgen << " events will be generated."; integrator_->generate( parameters->generation.maxgen, callback, &tmr ); const double gen_time_s = tmr.elapsed(); CG_INFO( "Generator" ) << parameters->generation.ngen << " events generated " << "in " << gen_time_s << " s " << "(" << gen_time_s/parameters->generation.ngen*1.e3 << " ms/event)."; } } diff --git a/CepGen/Core/GridParameters.h b/CepGen/Core/GridParameters.h index 9418bf5..098efa9 100644 --- a/CepGen/Core/GridParameters.h +++ b/CepGen/Core/GridParameters.h @@ -1,39 +1,40 @@ #ifndef CepGen_Core_GridParameters_h #define CepGen_Core_GridParameters_h #include <vector> #include <map> namespace CepGen { + /// A parameters placeholder for the grid integration helper class GridParameters { public: /// Maximal number of dimensions handled by this integrator instance static const unsigned short max_dimensions_; /// Integration grid size parameter static const unsigned short mbin_; static const double inv_mbin_; GridParameters(); std::map<unsigned int,std::vector<unsigned short> > n_map; unsigned int max; /// Has the generation been prepared? bool gen_prepared; double correc; double correc2; /// Maximal value of the function at one given point std::vector<double> f_max; /// Maximal value of the function in the considered integration range double f_max_global; double f_max2; double f_max_diff; double f_max_old; std::vector<unsigned int> num; }; } #endif diff --git a/CepGen/Core/Hasher.h b/CepGen/Core/Hasher.h index 149b6ba..6dba163 100644 --- a/CepGen/Core/Hasher.h +++ b/CepGen/Core/Hasher.h @@ -1,34 +1,37 @@ #ifndef CepGen_Core_Hasher_h #define CepGen_Core_Hasher_h #include <cstddef> #include <functional> namespace CepGen { + /// A hasher table for a given structure template<class T,bool> struct hasher { inline size_t operator()( const T& t ) const { return std::hash<T>()( t ); } }; + /// A hasher table for a given structure template<class T> struct hasher<T, true> { inline size_t operator() ( const T& t ) { typedef typename std::underlying_type<T>::type enumType; return std::hash<enumType>()( static_cast<enumType>( t ) ); } }; + /// A hasher table for an enumeration template<class T> struct EnumHash { inline size_t operator()( const T& t ) const { return hasher<T,std::is_enum<T>::value>()( t ); } }; } #endif diff --git a/CepGen/Core/Integrator.h b/CepGen/Core/Integrator.h index c21af56..630e0c5 100644 --- a/CepGen/Core/Integrator.h +++ b/CepGen/Core/Integrator.h @@ -1,99 +1,98 @@ #ifndef CepGen_Core_Integrator_h #define CepGen_Core_Integrator_h #include <vector> #include <memory> #include <functional> #include <string.h> #include <gsl/gsl_monte.h> #include <gsl/gsl_monte_vegas.h> #include <gsl/gsl_rng.h> namespace CepGen { class Parameters; class Event; class GridParameters; class Timer; /// Monte-Carlo integrator instance class Integrator { public: enum class Type { plain = 0, - Vegas = 1, ///< @cite PeterLepage1978192 developed by G.P. Lepage in 1978 + Vegas = 1, ///< VEGAS algorithm \cite Lepage:1977sw developed by G.P. Lepage MISER = 2 }; enum class VegasMode { importance = 1, importanceOnly = 0, stratified = -1 }; /** * Book the memory slots and structures for the integrator * \note Three integration algorithms are currently supported: * * the plain algorithm randomly sampling points in the phase space - * * the Vegas algorithm developed by P. Lepage, as documented in @cite PeterLepage1978192, - * * the MISER algorithm developed by W.H. Press and G.R. Farrar, as documented in @cite Press:1989vk. + * * the Vegas algorithm developed by P. Lepage, as documented in \cite Lepage:1977sw + * * the MISER algorithm developed by W.H. Press and G.R. Farrar, as documented in \cite Press:1989vk. * \param[in] ndim Number of dimensions on which the function will be integrated * \param[in] integrand Function to be integrated * \param[inout] params Run parameters to define the phase space on which this integration is performed (embedded in an Parameters object) */ Integrator( unsigned int ndim, double integrand(double*,size_t,void*), Parameters* params ); /// Class destructor ~Integrator(); /** * Algorithm to perform the n-dimensional Monte Carlo integration of a given function. * \author This C++ implementation: GSL * \param[out] result_ The cross section as integrated for the given phase space restrictions * \param[out] abserr_ The error associated to the computed cross section * \return 0 if the integration was performed successfully */ int integrate( double& result_, double& abserr_ ); /// Dimensional size of the phase space unsigned short dimensions() const; void generateOne( std::function<void( const Event&, unsigned long )> callback = nullptr ); void generate( unsigned long num_events = 0, std::function<void( const Event&, unsigned long )> callback = nullptr, const Timer* tmr = nullptr ); private: /** * Store the event characterized by its _ndim-dimensional point in the phase * space to the output file * \brief Store the event in the output file * \param[in] x The d-dimensional point in the phase space defining the unique event to store * \return A boolean stating whether or not the event could be saved */ bool storeEvent( const std::vector<double>& x, std::function<void( const Event&, unsigned long )> callback = nullptr ); /// Start the correction cycle on the grid /// \param x Point in the phase space considered /// \param has_correction Correction cycle started? bool correctionCycle( std::vector<double>& x, bool& has_correction ); int warmupVegas( std::vector<double>& x_low, std::vector<double>& x_up, unsigned int ncall ); /** * Set all the generation mode variables and align them to the integration grid set while computing the cross-section * \brief Prepare the class for events generation */ void computeGenerationParameters(); double uniform() const; double eval( const std::vector<double>& x ); /// Selected bin at which the function will be evaluated int ps_bin_; /// List of parameters to specify the integration range and the physics determining the phase space Parameters* input_params_; /// GSL structure storing the function to be integrated by this integrator instance (along with its parameters) std::unique_ptr<gsl_monte_function> function_; std::unique_ptr<gsl_rng,void(*)( gsl_rng* )> rng_; std::unique_ptr<GridParameters> grid_; struct gsl_monte_vegas_deleter { void operator()( gsl_monte_vegas_state* state ) { gsl_monte_vegas_free( state ); } }; std::unique_ptr<gsl_monte_vegas_state,gsl_monte_vegas_deleter> veg_state_; double r_boxes_; }; std::ostream& operator<<( std::ostream&, const Integrator::Type& ); std::ostream& operator<<( std::ostream&, const Integrator::VegasMode& ); } #endif - diff --git a/CepGen/Core/Parameters.cpp b/CepGen/Core/Parameters.cpp index 36a3bd3..51cd203 100644 --- a/CepGen/Core/Parameters.cpp +++ b/CepGen/Core/Parameters.cpp @@ -1,268 +1,260 @@ #include "CepGen/Parameters.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/StructureFunctions/StructureFunctions.h" #include <iomanip> namespace CepGen { Parameters::Parameters() : general( new ParametersList ), - hadroniser_max_trials( 5 ), taming_functions( new TamingFunctionsCollection ), store_( false ), total_gen_time_( 0. ), num_gen_events_( 0 ) {} Parameters::Parameters( Parameters& param ) : general( param.general ), kinematics( param.kinematics ), integrator( param.integrator ), generation( param.generation ), - hadroniser_max_trials( param.hadroniser_max_trials ), taming_functions( param.taming_functions ), process_( std::move( param.process_ ) ), hadroniser_( std::move( param.hadroniser_ ) ), store_( false ), total_gen_time_( param.total_gen_time_ ), num_gen_events_( param.num_gen_events_ ) {} Parameters::Parameters( const Parameters& param ) : general( param.general ), kinematics( param.kinematics ), integrator( param.integrator ), generation( param.generation ), - hadroniser_max_trials( param.hadroniser_max_trials ), taming_functions( param.taming_functions ), store_( false ), total_gen_time_( param.total_gen_time_ ), num_gen_events_( param.num_gen_events_ ) {} Parameters::~Parameters() // required for unique_ptr initialisation! {} 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::clearRunStatistics() { total_gen_time_ = 0.; num_gen_events_ = 0; } void Parameters::addGenerationTime( double gen_time ) { total_gen_time_ += gen_time; num_gen_events_++; } Process::GenericProcess* Parameters::process() { return process_.get(); } std::string Parameters::processName() const { if ( !process_ ) return "no process"; return process_->name(); } void Parameters::setProcess( Process::GenericProcess* proc ) { if ( !proc ) throw CG_FATAL( "Parameters" ) << "Trying to clone an invalid process!"; process_.reset( proc ); } void Parameters::cloneProcess( const Process::GenericProcess* proc ) { if ( !proc ) throw CG_FATAL( "Parameters" ) << "Trying to clone an invalid process!"; process_ = std::move( proc->clone() ); } Hadroniser::GenericHadroniser* Parameters::hadroniser() { return hadroniser_.get(); } std::string Parameters::hadroniserName() const { if ( !hadroniser_ ) return ""; return hadroniser_->name(); } void Parameters::setHadroniser( Hadroniser::GenericHadroniser* hadr ) { hadroniser_.reset( hadr ); } std::ostream& operator<<( std::ostream& os, const Parameters* p ) { const bool pretty = true; const int wb = 90, wt = 40; os << "Parameters dump" << std::left << "\n\n" << std::setfill('_') << std::setw( wb+3 ) << "_/¯¯RUN¯INFORMATION¯¯\\_" << std::setfill( ' ' ) << "\n" << std::right << std::setw( wb ) << std::left << std::endl << std::setw( wt ) << "Process to generate"; if ( p->process_ ) { os << ( pretty ? boldify( p->process_->name().c_str() ) : p->process_->name() ) << "\n" << std::setw( wt ) << "" << p->process_->description(); } else os << ( pretty ? boldify( "no process!" ) : "no process!" ); os << "\n" << std::setw( wt ) << "Events generation? " << ( pretty ? yesno( p->generation.enabled ) : std::to_string( p->generation.enabled ) ) << "\n" << std::setw( wt ) << "Number of events to generate" << ( pretty ? boldify( p->generation.maxgen ) : std::to_string( p->generation.maxgen ) ) << "\n"; if ( p->generation.num_threads > 1 ) os << std::setw( wt ) << "Number of threads" << p->generation.num_threads << "\n"; os << std::setw( wt ) << "Number of points to try per bin" << p->generation.num_points << "\n" - << std::setw( wt ) << "Integrand treatment" << std::boolalpha << p->generation.treat << "\n" + << std::setw( wt ) << "Integrand treatment" + << ( pretty ? yesno( p->generation.treat ) : std::to_string( p->generation.treat ) ) << "\n" << std::setw( wt ) << "Verbosity level " << Logger::get().level << "\n"; if ( p->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( p->hadroniser_->name().c_str() ) : p->hadroniser_->name() ) << "\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 << p->integrator.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" << p->integrator.ncvg << "\n" << std::setw( wt ) << "Random number generator seed" << p->integrator.rng_seed << "\n"; if ( p->integrator.rng_engine ) os << std::setw( wt ) << "Random number generator engine" << p->integrator.rng_engine->name << "\n"; std::ostringstream proc_mode; proc_mode << p->kinematics.mode; os << "\n" << std::setfill('_') << std::setw( wb+3 ) << "_/¯¯EVENTS¯KINEMATICS¯¯\\_" << std::setfill( ' ' ) << "\n\n" << std::setw( wt ) << "Incoming particles" << p->kinematics.incoming_beams.first << ",\n" << std::setw( wt ) << "" << p->kinematics.incoming_beams.second << "\n"; if ( p->kinematics.mode != KinematicsMode::invalid ) os << std::setw( wt ) << "Subprocess mode" << ( pretty ? boldify( proc_mode.str().c_str() ) : proc_mode.str() ) << "\n"; if ( p->kinematics.mode != KinematicsMode::ElasticElastic ) - os << std::setw( wt ) << "Structure functions" << p->kinematics.structure_functions->type << "\n"; + os << std::setw( wt ) << "Structure functions" << *p->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 : p->kinematics.cuts.initial.list() ) { // map(particles class, limits) - if ( !lim.second.valid() ) - continue; - os << std::setw( wt ) << lim.first << lim.second << "\n"; - } + for ( const auto& lim : p->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 : p->kinematics.cuts.central.list() ) { - if ( !lim.second.valid() ) - continue; - os << std::setw( wt ) << lim.first << lim.second << "\n"; - } + for ( const auto& lim : p->kinematics.cuts.central.list() ) + if ( lim.second.valid() ) + os << std::setw( wt ) << lim.first << lim.second << "\n"; if ( p->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 : p->kinematics.cuts.central_particles ) { os << " * all single " << std::setw( wt-3 ) << part_per_lim.first << "\n"; - for ( const auto& lim : part_per_lim.second.list() ) { - if ( !lim.second.valid() ) - continue; - os << " - " << std::setw( wt-5 ) << lim.first << lim.second << "\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\n"; for ( const auto& lim : p->kinematics.cuts.remnants.list() ) os << std::setw( wt ) << lim.first << lim.second << "\n"; return os; } std::ostream& operator<<( std::ostream& os, const Parameters& p ) { return os << &p; } //----------------------------------------------------------------------------------------------- Parameters::Integration::Integration() : type( Integrator::Type::Vegas ), ncvg( 500000 ), 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; { std::shared_ptr<gsl_monte_vegas_state> tmp_state( gsl_monte_vegas_alloc( ndof ), gsl_monte_vegas_free ); gsl_monte_vegas_params_get( tmp_state.get(), &vegas ); } { std::shared_ptr<gsl_monte_miser_state> 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( false ), ngen( 0 ), gen_print_every( 10000 ), num_threads( 2 ), num_points( 100 ) {} } diff --git a/CepGen/Core/ParametersList.cpp b/CepGen/Core/ParametersList.cpp index f15c953..f94cc67 100644 --- a/CepGen/Core/ParametersList.cpp +++ b/CepGen/Core/ParametersList.cpp @@ -1,298 +1,298 @@ #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Exception.h" namespace CepGen { 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() ); 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 ) { for ( const auto& kv : params.int_values_ ) os << "\n" << kv.first << ": int(" << kv.second << ")"; for ( const auto& kv : params.dbl_values_ ) os << "\n" << kv.first << ": double(" << kv.second << ")"; for ( const auto& kv : params.str_values_ ) os << "\n" << kv.first << ": string(" << kv.second << ")"; for ( const auto& kv : params.param_values_ ) os << "\n" << kv.first << ": param({" << kv.second << "\n})"; for ( const auto& kv : params.vec_int_values_ ) { os << "\n" << 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 << "\n" << 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 << "\n" << kv.first << ": vstring("; bool first = true; for ( const auto& v : kv.second ) { os << ( first ? "" : ", " ) << v; first = false; } os << ")"; } return os; } //------------------------------------------------------------------ // default template (placeholders) //------------------------------------------------------------------ template<typename T> T ParametersList::get( std::string key, T def ) const { throw CG_FATAL( "ParametersList" ) << "Invalid type retrieved for key=" << key << "!"; } template<typename T> T& ParametersList::operator[]( std::string key ) { throw CG_FATAL( "ParametersList" ) << "Invalid type retrieved for key=" << key << "!"; } template<typename T> void 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<ParametersList>( std::string key, ParametersList def ) const { for ( const auto& kv : param_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> ParametersList& ParametersList::operator[]<ParametersList>( std::string key ) { for ( auto& kv : param_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return param_values_[key]; } template<> void ParametersList::set<ParametersList>( std::string key, const ParametersList& value ) { param_values_[key] = value; } template<> std::vector<ParametersList> ParametersList::get<std::vector<ParametersList> >( std::string key, std::vector<ParametersList> def ) const { for ( const auto& kv : vec_param_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector<ParametersList>& ParametersList::operator[]<std::vector<ParametersList> >( std::string key ) { for ( auto& kv : vec_param_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return vec_param_values_[key]; } template<> void ParametersList::set<std::vector<ParametersList> >( std::string key, const std::vector<ParametersList>& value ) { vec_param_values_[key] = value; } //------------------------------------------------------------------ // integer-type attributes //------------------------------------------------------------------ template<> int ParametersList::get<int>( std::string key, int def ) const { for ( const auto& kv : int_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> int& ParametersList::operator[]<int>( std::string key ) { for ( auto& kv : int_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return int_values_[key]; } template<> void ParametersList::set<int>( std::string key, const int& value ) { int_values_[key] = value; } template<> std::vector<int> ParametersList::get<std::vector<int> >( std::string key, std::vector<int> def ) const { for ( const auto& kv : vec_int_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector<int>& ParametersList::operator[]<std::vector<int> >( std::string key ) { for ( auto& kv : vec_int_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return vec_int_values_[key]; } template<> void ParametersList::set<std::vector<int> >( std::string key, const std::vector<int>& value ) { vec_int_values_[key] = value; } //------------------------------------------------------------------ // floating point-type attributes //------------------------------------------------------------------ template<> double ParametersList::get<double>( std::string key, double def ) const { for ( const auto& kv : dbl_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> double& ParametersList::operator[]<double>( std::string key ) { for ( auto& kv : dbl_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return dbl_values_[key]; } template<> void ParametersList::set<double>( std::string key, const double& value ) { dbl_values_[key] = value; } template<> std::vector<double> ParametersList::get<std::vector<double> >( std::string key, std::vector<double> def ) const { for ( const auto& kv : vec_dbl_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector<double>& ParametersList::operator[]<std::vector<double> >( std::string key ) { for ( auto& kv : vec_dbl_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return vec_dbl_values_[key]; } template<> void ParametersList::set<std::vector<double> >( std::string key, const std::vector<double>& value ) { vec_dbl_values_[key] = value; } //------------------------------------------------------------------ // string-type attributes //------------------------------------------------------------------ template<> std::string ParametersList::get<std::string>( std::string key, std::string def ) const { for ( const auto& kv : str_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::string& ParametersList::operator[]<std::string>( std::string key ) { for ( auto& kv : str_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return str_values_[key]; } template<> void ParametersList::set<std::string>( std::string key, const std::string& value ) { str_values_[key] = value; } template<> std::vector<std::string> ParametersList::get<std::vector<std::string> >( std::string key, std::vector<std::string> def ) const { for ( const auto& kv : vec_str_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; CG_DEBUG( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; return def; } template<> std::vector<std::string>& ParametersList::operator[]<std::vector<std::string> >( std::string key ) { for ( auto& kv : vec_str_values_ ) if ( kv.first.compare( key ) == 0 ) return kv.second; - throw CG_FATAL( "ParametersList" ) << "Failed to retrieve parameter with key=" << key << "."; + return vec_str_values_[key]; } template<> void ParametersList::set<std::vector<std::string> >( std::string key, const std::vector<std::string>& value ) { vec_str_values_[key] = value; } } diff --git a/CepGen/Core/ParametersList.h b/CepGen/Core/ParametersList.h index 01f46ad..5abb45e 100644 --- a/CepGen/Core/ParametersList.h +++ b/CepGen/Core/ParametersList.h @@ -1,68 +1,98 @@ #ifndef CepGen_Core_ParametersList_h #define CepGen_Core_ParametersList_h #include <vector> #include <map> #include <unordered_map> #include <string> namespace CepGen { + /// Parameters container class ParametersList { private: template<typename T> struct default_arg { static T get() { return T(); } }; public: ParametersList() = default; ~ParametersList() = default; // required for unique_ptr initialisation! + /// Get a parameter value template<typename T> T get( std::string key, T def = default_arg<T>::get() ) const; + /// Reference to a parameter value template<typename T> T& operator[]( std::string key ); + /// Set a parameter value template<typename T> void set( std::string key, const T& value ); + /// Concatenate two parameters containers ParametersList& operator+=( const ParametersList& oth ); + /// Human-readable version of a parameters container friend std::ostream& operator<<( std::ostream& os, const ParametersList& ); private: std::map<std::string,ParametersList> param_values_; std::unordered_map<std::string,int> int_values_; std::unordered_map<std::string,double> dbl_values_; std::unordered_map<std::string,std::string> str_values_; std::unordered_map<std::string,std::vector<ParametersList> > vec_param_values_; std::unordered_map<std::string,std::vector<int> > vec_int_values_; std::unordered_map<std::string,std::vector<double> > vec_dbl_values_; std::unordered_map<std::string,std::vector<std::string> > vec_str_values_; }; + /// Get an integer parameter value template<> int ParametersList::get<int>( std::string key, int def ) const; + /// Reference to an integer parameter value template<> int& ParametersList::operator[]<int>( std::string key ); + /// Set an integer parameter value template<> void ParametersList::set<int>( std::string key, const int& value ); + /// Get a vector of integers parameter value template<> std::vector<int> ParametersList::get<std::vector<int> >( std::string key, std::vector<int> def ) const; + /// Reference to a vector of integers parameter value template<> std::vector<int>& ParametersList::operator[]<std::vector<int> >( std::string key ); + /// Set a vector of integers parameter value template<> void ParametersList::set<std::vector<int> >( std::string key, const std::vector<int>& value ); + /// Get a double floating point parameter value template<> double ParametersList::get<double>( std::string key, double def ) const; + /// Reference to a double floating point parameter value template<> double& ParametersList::operator[]<double>( std::string key ); + /// Set a double floating point parameter value template<> void ParametersList::set<double>( std::string key, const double& value ); + /// Get a vector of double floating point parameter value template<> std::vector<double> ParametersList::get<std::vector<double> >( std::string key, std::vector<double> def ) const; + /// Reference to a vector of double floating point parameter value template<> std::vector<double>& ParametersList::operator[]<std::vector<double> >( std::string key ); + /// Set a vector of double floating point parameter value template<> void ParametersList::set<std::vector<double> >( std::string key, const std::vector<double>& value ); + /// Get a string parameter value template<> std::string ParametersList::get<std::string>( std::string key, std::string def ) const; + /// Reference to a string parameter value template<> std::string& ParametersList::operator[]<std::string>( std::string key ); + /// Set a string parameter value template<> void ParametersList::set<std::string>( std::string key, const std::string& value ); + /// Get a vector of strings parameter value template<> std::vector<std::string> ParametersList::get<std::vector<std::string> >( std::string key, std::vector<std::string> def ) const; + /// Reference to a vector of strings parameter value template<> std::vector<std::string>& ParametersList::operator[]<std::vector<std::string> >( std::string key ); + /// Set a vector of strings parameter value template<> void ParametersList::set<std::vector<std::string> >( std::string key, const std::vector<std::string>& value ); + /// Get a parameters list parameter value template<> ParametersList ParametersList::get<ParametersList>( std::string key, ParametersList def ) const; + /// Reference to a parameters list parameter value template<> ParametersList& ParametersList::operator[]<ParametersList>( std::string key ); + /// Set a parameters list parameter value template<> void ParametersList::set<ParametersList>( std::string key, const ParametersList& value ); + /// Get a vector of parameters list parameter value template<> std::vector<ParametersList> ParametersList::get<std::vector<ParametersList> >( std::string key, std::vector<ParametersList> def ) const; + /// Reference to a vector of parameters list parameter value template<> std::vector<ParametersList>& ParametersList::operator[]<std::vector<ParametersList> >( std::string key ); + /// Set a vector of parameters list parameter value template<> void ParametersList::set<std::vector<ParametersList> >( std::string key, const std::vector<ParametersList>& value ); } #endif diff --git a/CepGen/Core/utils.h b/CepGen/Core/utils.h index 3a3bd46..dd7678d 100644 --- a/CepGen/Core/utils.h +++ b/CepGen/Core/utils.h @@ -1,31 +1,38 @@ #ifndef CepGen_Core_utils_h #define CepGen_Core_utils_h #include <string> namespace CepGen { + /// Add a closing "s" when needed inline const char* s( unsigned short num ) { return ( num > 1 ) ? "s" : ""; } - /// 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 ); } /// Provide a random number generated along a uniform distribution between 0 and 1 -//inline double drand() { srand (time(nullptr)); return static_cast<double>(rand())/RAND_MAX; } #define drand() static_cast<double>( rand()/RAND_MAX ) #endif diff --git a/CepGen/Event/Event.cpp b/CepGen/Event/Event.cpp index eda5a35..bce4c2a 100644 --- a/CepGen/Event/Event.cpp +++ b/CepGen/Event/Event.cpp @@ -1,341 +1,339 @@ #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 <algorithm> #include <math.h> 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::getByRole( Particle::Role role ) { //--- retrieve all particles with a given role return particles_[role]; } const Particles& Event::getByRole( 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::getIdsByRole( 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 a the given role Particles& parts_by_role = getByRole( role ); if ( parts_by_role.size() == 0 ) 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 { if ( particles_.count( role ) == 0 ) throw CG_FATAL( "Event" ) << "Failed to retrieve a particle with " << role << " role."; //--- retrieve the first particle a the given role const Particles& parts_by_role = particles_.at( role ); if ( parts_by_role.size() == 0 ) 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::getConstById( int id ) const + Event::at( 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( getConstById( id ) ); + out.emplace_back( at( id ) ); return out; } Particles Event::mothers( const Particle& part ) { return getByIds( part.mothers() ); } Particles Event::daughters( const Particle& part ) { return getByIds( part.daughters() ); } ParticleRoles Event::roles() const { ParticleRoles out; ParticlesMap::const_iterator it, end = particles_.end(); for ( it = particles_.begin(); it != end; it = particles_.upper_bound( it->first ) ) { out.emplace_back( it->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 = getByRole( 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() ) { if ( replace ) part.setId( part_with_same_role[0].id() ); // set the previous id if replacing a particle else part.setId( numParticles() ); } //--- 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 { 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 = getConstById( daugh ); + const Particle& d = at( daugh ); const ParticlesIds mothers = d.mothers(); ptot += d.momentum(); if ( mothers.size() < 2 ) continue; - for ( const auto& moth : mothers ) { - if ( moth == part.id() ) - continue; - ptot -= getConstById( moth ).momentum(); - } + for ( const auto& moth : mothers ) + if ( moth != part.id() ) + ptot -= at( moth ).momentum(); } const double mass_diff = ( ptot-part.momentum() ).mass(); if ( fabs( mass_diff ) > minimal_precision_ ) { dump(); throw CG_FATAL( "Event" ) << "Error in momentum balance for particle " << part.id() << ": mdiff = " << mass_diff << "."; } } } void Event::dump( std::ostream& out, 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.size() > 0 ) { for ( unsigned short i = 0; i < mothers.size(); ++i ) - oss_pdg << ( i > 0 ? "/" : "" ) << getConstById( *std::next( mothers.begin(), i ) ).pdgId(); + oss_pdg << ( i > 0 ? "/" : "" ) << at( *std::next( mothers.begin(), i ) ).pdgId(); os << Form( "\n %2d\t\t%-10s", part.id(), oss_pdg.str().c_str() ); } else { if ( (HeavyIon)part.pdgId() ) oss_pdg << (HeavyIon)part.pdgId(); else oss_pdg << part.pdgId(); os << Form( "\n %2d\t%-+7d %-10s", part.id(), part.integerPdgId(), oss_pdg.str().c_str() ); } } os << "\t"; if ( part.charge() != 999. ) os << Form( "%-.2f\t", part.charge() ); else 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\tName\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 d5193bf..599b592 100644 --- a/CepGen/Event/Event.h +++ b/CepGen/Event/Event.h @@ -1,124 +1,119 @@ #ifndef CepGen_Event_Event_h #define CepGen_Event_Event_h #include "CepGen/Event/Particle.h" #include "CepGen/Core/Logger.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: Event(); 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( std::ostream& os = *Logger::get().output, bool stable_ = false ) const; - + /// Incoming beams centre-of-mass energy, in GeV double cmEnergy() const; //----- particles adders - /// Set the information on one particle in the process + /// \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; - /// \brief Vector of all particles in the event + /// Vector of all particles in the event const Particles particles() const; - /// \brief Vector of all stable particles in the event + /// Vector of all stable particles in the event const Particles stableParticles() const; - /** - * Returns the list of Particle objects corresponding to a certain role in the process kinematics - * \brief Gets a list of particles by their role in the event + /** 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& getByRole( Particle::Role role ); + /// Get a list of constant Particle objects corresponding to a certain role in the process kinematics const Particles& getByRole( Particle::Role role ) const; + /// Get a list of particle identifiers in Event corresponding to a certain role in the process kinematics ParticlesIds getIdsByRole( Particle::Role role ) const; - /** - * Returns the first Particle object in the particles list whose role corresponds to the given argument + /** \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; - /** - * Returns the reference to the Particle object corresponding to a unique identifier in the event - * \brief Gets one particle by its unique identifier in the event - * \param[in] id_ The unique identifier to this particle in the event + /** \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_ ); - /// 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& getConstById( int id_ ) const; - /** - * Returns the references to the Particle objects corresponding to the unique identifiers in the event - * \brief Gets a vector of particles by their unique identifier in the event + 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& at( 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; - /** - * Returns the list of mother particles of any given Particle object in this event + /** \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 ); /// 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 ); /// 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 minimal_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_; /// Last particle in an "empty" event struct NumParticles { NumParticles(); NumParticles( const NumParticles& np ); unsigned short cs, op1, op2; }; NumParticles evtcontent_; }; } #endif diff --git a/CepGen/Event/Particle.cpp b/CepGen/Event/Particle.cpp index 0362063..40a8306 100644 --- a/CepGen/Event/Particle.cpp +++ b/CepGen/Event/Particle.cpp @@ -1,259 +1,264 @@ #include "CepGen/Event/Particle.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include "CepGen/Physics/Constants.h" namespace CepGen { Particle::Particle() : id_( -1 ), charge_sign_( 1 ), mass_( -1. ), helicity_( 0. ), role_( UnknownRole ), status_( Status::Undefined ), pdg_id_( PDG::invalid ) {} Particle::Particle( Role role, PDG pdgId, Status st ) : id_( -1 ), charge_sign_( 1 ), mass_( -1. ), helicity_( 0. ), role_( role ), status_( st ), pdg_id_( pdgId ) { - if ( pdg_id_ != PDG::invalid ) { + if ( pdg_id_ != PDG::invalid ) computeMass(); - } } Particle::Particle( const Particle& part ) : id_( part.id_ ), charge_sign_( part.charge_sign_ ), momentum_( part.momentum_ ), mass_( part.mass_ ), helicity_( part.helicity_ ), role_( part.role_ ), status_( part.status_ ), mothers_( part.mothers_ ), daughters_( part.daughters_ ), pdg_id_( part.pdg_id_ ) {} bool Particle::operator<( const Particle& rhs ) const { - return ( id_ >= 0 && rhs.id_ > 0 && id_ < rhs.id_ ); + return id_ >= 0 + && rhs.id_ > 0 + && id_ < rhs.id_; } double Particle::thetaToEta( double theta ) { - return -log( tan( 0.5 * theta * M_PI/180. ) ); + return -log( tan( 0.5*theta*M_PI/180. ) ); } double Particle::etaToTheta( double eta ) { - return 2.*atan( exp( -eta ) )*180. / M_PI; + return 2.*atan( exp( -eta ) )*180.*M_1_PI; } bool Particle::valid() { - if ( pdg_id_ == PDG::invalid ) return false; - if ( momentum_.p() == 0. && mass() == 0. ) return false; + if ( pdg_id_ == PDG::invalid ) + return false; + if ( momentum_.p() == 0. && mass_ == 0. ) + return false; return true; } void Particle::computeMass( bool off_shell ) { if ( !off_shell && pdg_id_ != PDG::invalid ) { // retrieve the mass from the on-shell particle's properties mass_ = ParticleProperties::mass( pdg_id_ ); } else if ( momentum_.energy() >= 0. ) { mass_ = sqrt( energy2() - momentum_.p2() ); } //--- finish by setting the energy accordingly if ( momentum_.energy() < 0. ) { // invalid energy momentum_.setEnergy( sqrt( momentum_.p2() + mass2() ) ); } } void Particle::setMass( double m ) { - if ( m >= 0. ) mass_ = m; - else computeMass(); + if ( m >= 0. ) + mass_ = m; + else + computeMass(); } void Particle::addMother( Particle& part ) { mothers_.insert( part.id() ); CG_DEBUG_LOOP( "Particle" ) << "Particle " << id() << " (pdgId=" << part.integerPdgId() << ") " << "is the new mother of " << id_ << " (pdgId=" << (int)pdg_id_ << ")."; part.addDaughter( *this ); } void Particle::addDaughter( Particle& part ) { const auto ret = daughters_.insert( part.id() ); if ( CG_EXCEPT_MATCH( "Particle", debugInsideLoop ) ) { std::ostringstream os; for ( const auto& daugh : daughters_ ) os << Form( "\n\t * id=%d", daugh ); CG_DEBUG_LOOP( "Particle" ) << "Particle " << role_ << " (pdgId=" << (int)pdg_id_ << ") " << "has now " << daughters_.size() << " daughter(s):" << os.str(); } if ( ret.second ) { CG_DEBUG_LOOP( "Particle" ) << "Particle " << part.role() << " (pdgId=" << part.integerPdgId() << ") " << "is a new daughter of " << role_ << " (pdgId=" << (int)pdg_id_ << "%4d)."; if ( part.mothers().find( id_ ) == part.mothers().end() ) part.addMother( *this ); } } void Particle::setMomentum( const Momentum& mom, bool offshell ) { momentum_ = mom; - if ( !offshell && mom.mass() > 0. ) mass_ = momentum_.mass(); - else computeMass(); - } - - void - Particle::setMomentum( double px, double py, double pz ) - { - momentum_.setP( px, py, pz ); - setEnergy(); + if ( !offshell && mom.mass() > 0. ) + mass_ = momentum_.mass(); + else + computeMass(); } void Particle::setMomentum( double px, double py, double pz, double e ) { - setMomentum( px, py, pz ); - if ( fabs( e-momentum_.energy() )>1.e-6 ) { // more than 1 eV difference + momentum_.setP( px, py, pz ); + setEnergy( e ); + if ( fabs( e-momentum_.energy() ) > 1.e-6 ) // more than 1 eV difference CG_ERROR( Form( "Energy difference: %.5e", e-momentum_.energy() ) ); - return; - } } double Particle::energy() const { - return ( momentum_.energy() < 0. ) ? sqrt( mass2()+momentum_.p2() ) : momentum_.energy(); + return ( momentum_.energy() < 0. + ? std::hypot( mass_, momentum_.p() ) + : momentum_.energy() ); } void Particle::setEnergy( double e ) { - if ( e < 0. && mass_ >= 0. ) e = sqrt( mass2()+momentum_.p2() ); + if ( e < 0. && mass_ >= 0. ) + e = std::hypot( mass_, momentum_.p() ); momentum_.setEnergy( e ); } void Particle::setPdgId( short pdg ) { pdg_id_ = (PDG)abs( pdg ); switch ( pdg_id_ ) { case PDG::electron: case PDG::muon: case PDG::tau: charge_sign_ = -pdg/abs( pdg ); break; default: charge_sign_ = pdg/abs( pdg ); break; } } void Particle::setPdgId( const PDG& pdg, short ch ) { pdg_id_ = pdg; switch ( pdg_id_ ) { case PDG::electron: case PDG::muon: case PDG::tau: charge_sign_ = -ch; break; default: charge_sign_ = ch; break; } } int Particle::integerPdgId() const { const float ch = ParticleProperties::charge( pdg_id_ ); - if ( ch == 0 ) return static_cast<int>( pdg_id_ ); + if ( ch == 0 ) + return static_cast<int>( pdg_id_ ); return static_cast<int>( pdg_id_ ) * charge_sign_ * ( ch/fabs( ch ) ); } void Particle::dump() const { std::ostringstream osm, osd; if ( !primary() ) { osm << ": mother(s): "; unsigned short i = 0; for ( const auto& moth : mothers_ ) { osm << ( i > 0 ? ", " : "" ) << moth; ++i; } } const ParticlesIds daughters_list = daughters(); if ( daughters_list.size() > 0 ) { osd << ": id = "; unsigned short i = 0; for ( const auto& daugh : daughters_list ) { osm << ( i > 0 ? ", " : "" ) << daugh; ++i; } } CG_INFO( "Particle" ) << "Dumping a particle with id=" << id_ << ", role=" << role_ << ", status=" << (int)status_ << "\n\t" - << "Particle id: " << integerPdgId() << " (" << pdg_id_ << "), mass = " << mass() << " GeV\n\t" + << "Particle id: " << integerPdgId() << " (" << pdg_id_ << "), mass = " << mass_ << " GeV\n\t" << "Momentum: " << momentum_ << " GeV\t" << "(|P| = p = " << momentum_.p() << " GeV)\n\t" << " p⟂ = " << momentum_.pt() << " GeV, eta = " << momentum_.eta() << ", phi = " << momentum_.phi() << "\n\t" << "Primary? " << yesno( primary() ) << osm.str() << "\n\t" << numDaughters() << " daughter(s)" << osd.str(); } double Particle::etaToY( double eta_, double m_, double pt_ ) { - const double mt = m_*m_ + pt_*pt_; - return asinh( sqrt( ( ( ( mt*mt-m_*m_ )*cosh( 2.*eta_ ) + m_*m_ )/ mt*mt - 1. ) / 2. ) ); + const double m2 = m_*m_, mt = std::hypot( m_, pt_ ); + return asinh( sqrt( ( ( mt*mt-m2 )*cosh( 2.*eta_ )+m2 )/ mt*mt - 1. )*M_SQRT1_2 ); } std::ostream& operator<<( std::ostream& os, const Particle::Role& rl ) { switch ( rl ) { case Particle::UnknownRole: return os << "unknown"; - case Particle::IncomingBeam1: return os << "in.b.1"; - case Particle::IncomingBeam2: return os << "in.b.2"; - case Particle::OutgoingBeam1: return os << "out.b.1"; - case Particle::OutgoingBeam2: return os << "out.b.2"; - case Particle::Parton1: return os << "parton1"; - case Particle::Parton2: return os << "parton2"; - case Particle::Parton3: return os << "parton3"; - case Particle::Intermediate: return os << "hard.pr."; + case Particle::IncomingBeam1: return os << "i.beam 1"; + case Particle::IncomingBeam2: return os << "i.beam 2"; + case Particle::OutgoingBeam1: return os << "o.beam 1"; + case Particle::OutgoingBeam2: return os << "o.beam 2"; + case Particle::Parton1: return os << "parton 1"; + case Particle::Parton2: return os << "parton 2"; + case Particle::Parton3: return os << "parton 3"; + case Particle::Intermediate: return os << "hard pr."; case Particle::CentralSystem: return os << "central"; } return os; } double CMEnergy( const Particle& p1, const Particle& p2 ) { - if ( p1.mass()*p2.mass() < 0. ) return 0.; - if ( p1.energy()*p2.energy() < 0. ) return 0.; + if ( p1.mass()*p2.mass() < 0. + || p1.energy()*p2.energy() < 0. ) + return 0.; return sqrt( p1.mass2()+p2.mass2() + 2.*p1.energy()*p2.energy() - 2.*( p1.momentum()*p2.momentum() ) ); } double CMEnergy( const Particle::Momentum& m1, const Particle::Momentum& m2 ) { - if ( m1.mass()*m2.mass() < 0. ) return 0.; - if ( m1.energy()*m2.energy() < 0. ) return 0.; + if ( m1.mass()*m2.mass() < 0. + || m1.energy()*m2.energy() < 0. ) + return 0.; return sqrt( m1.mass2()+m2.mass2() + 2.*m1.energy()*m2.energy() - 2.*( m1*m2 ) ); } } diff --git a/CepGen/Event/Particle.h b/CepGen/Event/Particle.h index 7de41a8..d76ec6b 100644 --- a/CepGen/Event/Particle.h +++ b/CepGen/Event/Particle.h @@ -1,368 +1,346 @@ #ifndef CepGen_Event_Particle_h #define CepGen_Event_Particle_h #include "CepGen/Physics/ParticleProperties.h" #include <set> #include <map> #include <vector> namespace CepGen { /// A set of integer-type particle identifiers typedef std::set<int> ParticlesIds; /// Kinematic information for one particle class Particle { public: /// Internal status code for a particle enum class Status { PrimordialIncoming = -9, DebugResonance = -5, Resonance = -4, Fragmented = -3, Propagator = -2, Incoming = -1, Undefined = 0, FinalState = 1, Undecayed = 2, Unfragmented = 3 }; /// Role of the particle in the process enum Role { UnknownRole = -1, IncomingBeam1 = 1, IncomingBeam2 = 2, OutgoingBeam1 = 3, OutgoingBeam2 = 5, CentralSystem = 6, Intermediate = 4, Parton1 = 41, Parton2 = 42, Parton3 = 43 }; /** * Container for a particle's 4-momentum, along with useful methods to ease the development of any matrix element level generator * \brief 4-momentum for a particle * \date Dec 2015 * \author Laurent Forthomme <laurent.forthomme@cern.ch> */ class Momentum { public: /// Build a 4-momentum at rest with an invalid energy (no mass information known) Momentum(); /// Build a 4-momentum using its 3-momentum coordinates and its energy Momentum( double x, double y, double z, double t = -1. ); /// Build a 4-momentum using its 3-momentum coordinates and its energy Momentum( double* p ); // --- static definitions /// Build a 3-momentum from its three pseudo-cylindric coordinates static Momentum fromPtEtaPhi( double pt, double eta, double phi, double e = -1. ); /// Build a 4-momentum from its scalar momentum, and its polar and azimuthal angles static Momentum fromPThetaPhi( double p, double theta, double phi, double e = -1. ); /// Build a 4-momentum from its four momentum and energy coordinates static Momentum fromPxPyPzE( double px, double py, double pz, double e ); + /// Build a 4-momentum from its transverse momentum, rapidity and mass static Momentum fromPxPyYM( double px, double py, double rap, double m ); // --- vector and scalar operators /// Scalar product of the 3-momentum with another 3-momentum double threeProduct( const Momentum& ) const; /// Scalar product of the 4-momentum with another 4-momentum double fourProduct( const Momentum& ) const; /// Vector product of the 3-momentum with another 3-momentum double crossProduct( const Momentum& ) const; /// Add a 4-momentum through a 4-vector sum Momentum& operator+=( const Momentum& ); /// Subtract a 4-momentum through a 4-vector sum Momentum& operator-=( const Momentum& ); /// Scalar product of the 3-momentum with another 3-momentum double operator*=( const Momentum& ); /// Multiply all 4-momentum coordinates by a scalar Momentum& operator*=( double c ); /// Equality operator bool operator==( const Momentum& ) const; /// Human-readable format for a particle's momentum friend std::ostream& operator<<( std::ostream& os, const Particle::Momentum& mom ); Momentum& betaGammaBoost( double gamma, double betagamma ); /// Forward Lorentz boost Momentum& lorentzBoost( const Particle::Momentum& p ); // --- setters and getters /// Set all the components of the 4-momentum (in GeV) void setP( double px, double py, double pz, double e ); /// Set all the components of the 3-momentum (in GeV) void setP( double px, double py, double pz ); /// Set the energy (in GeV) inline void setEnergy( double e ) { energy_ = e; } /// Compute the energy from the mass inline void setMass( double m ) { setMass2( m*m ); } /// Compute the energy from the mass void setMass2( double m2 ); /// Get one component of the 4-momentum (in GeV) double operator[]( const unsigned int i ) const; /// Get one component of the 4-momentum (in GeV) double& operator[]( const unsigned int i ); /// Momentum along the \f$x\f$-axis (in GeV) inline double px() const { return px_; } /// Momentum along the \f$y\f$-axis (in GeV) inline double py() const { return py_; } /// Longitudinal momentum (in GeV) inline double pz() const { return pz_; } /// Transverse momentum (in GeV) double pt() const; - /// Squared transverse momentum (in GeV\f$^\textrm{2}\f$) + /// Squared transverse momentum (in GeV\f${}^2\f$) double pt2() const; /// 4-vector of double precision floats (in GeV) const std::vector<double> pVector() const; /// 3-momentum norm (in GeV) inline double p() const { return p_; } - /// Squared 3-momentum norm (in GeV\f$^\textrm{2}\f$) + /// Squared 3-momentum norm (in GeV\f${}^2\f$) inline double p2() const { return p_*p_; } /// Energy (in GeV) inline double energy() const { return energy_; } - /// Squared energy (in GeV^2) + /// Squared energy (in GeV\f${}^2\f$) inline double energy2() const { return energy_*energy_; } - /// Squared mass (in GeV^2) as computed from its energy and momentum + /// Squared mass (in GeV\f${}^2\f$) as computed from its energy and momentum inline double mass2() const { return energy2()-p2(); } /// Mass (in GeV) as computed from its energy and momentum /// \note Returns \f$-\sqrt{|E^2-\mathbf{p}^2|}<0\f$ if \f$\mathbf{p}^2>E^2\f$ double mass() const; /// Polar angle (angle with respect to the longitudinal direction) double theta() const; /// Azimutal angle (angle in the transverse plane) double phi() const; /// Pseudo-rapidity double eta() const; /// Rapidity double rapidity() const; void truncate( double tolerance = 1.e-10 ); /// Rotate the transverse components by an angle phi (and reflect the y coordinate) Momentum& rotatePhi( double phi, double sign ); /// Rotate the particle's momentum by a polar/azimuthal angle Momentum& rotateThetaPhi( double theta_, double phi_ ); /// Apply a \f$ z\rightarrow -z\f$ transformation inline Momentum& mirrorZ() { pz_ = -pz_; return *this; } private: /// Compute the 3-momentum's norm void computeP(); /// Momentum along the \f$x\f$-axis double px_; /// Momentum along the \f$y\f$-axis double py_; /// Momentum along the \f$z\f$-axis double pz_; /// 3-momentum's norm (in GeV/c) double p_; /// Energy (in GeV) double energy_; }; /// Human-readable format for a particle's PDG code friend std::ostream& operator<<( std::ostream& os, const PDG& pc ); /// Human-readable format for a particle's role in the event friend std::ostream& operator<<( std::ostream& os, const Particle::Role& rl ); /// Compute the 4-vector sum of two 4-momenta friend Particle::Momentum operator+( const Particle::Momentum& mom1, const Particle::Momentum& mom2 ); /// Compute the 4-vector difference of two 4-momenta friend Particle::Momentum operator-( const Particle::Momentum& mom1, const Particle::Momentum& mom2 ); /// Compute the inverse per-coordinate 4-vector friend Particle::Momentum operator-( const Particle::Momentum& mom ); /// Scalar product of two 3-momenta friend double operator*( const Particle::Momentum& mom1, const Particle::Momentum& mom2 ); /// Multiply all components of a 4-momentum by a scalar friend Particle::Momentum operator*( const Particle::Momentum& mom, double c ); /// Multiply all components of a 4-momentum by a scalar friend Particle::Momentum operator*( double c, const Particle::Momentum& mom ); //----- static getters /// Convert a polar angle to a pseudo-rapidity static double thetaToEta( double theta ); /// Convert a pseudo-rapidity to a polar angle static double etaToTheta( double eta ); /// Convert a pseudo-rapidity to a rapidity static double etaToY( double eta_, double m_, double pt_ ); Particle(); /// Build using the role of the particle in the process and its PDG id /// \param[in] pdgId PDG identifier /// \param[in] role Role of the particle in the process /// \param[in] st Current status Particle( Role role, PDG pdgId, Status st = Status::Undefined ); /// Copy constructor Particle( const Particle& ); inline ~Particle() {} /// Comparison operator (from unique identifier) bool operator<( const Particle& rhs ) const; /// Comparison operator (from their reference's unique identifier) //bool operator<( Particle *rhs ) const { return ( id < rhs->id ); } // --- general particle properties /// Unique identifier (in a Event object context) int id() const { return id_; } //void setId( int id ) { id_ = id; } /// Set the particle unique identifier in an event void setId( int id ) { id_ = id; } /// Electric charge (given as a float number, for the quarks and bound states) float charge() const { return charge_sign_ * ParticleProperties::charge( pdg_id_ ); } /// Set the electric charge sign (+-1 for charged or 0 for neutral particles) void setChargeSign( int sign ) { charge_sign_ = sign; } /// Role in the considered process Role role() const { return role_; } /// Set the particle role in the process void setRole( const Role& role ) { role_ = role; } /** * Codes 1-10 correspond to currently existing partons/particles, and larger codes contain partons/particles which no longer exist, or other kinds of event information * \brief Particle status */ Status status() const { return status_; } /// Set the particle decay/stability status void setStatus( Status status ) { status_ = status; } /// Set the PDG identifier (along with the particle's electric charge) /// \param[in] pdg PDG identifier /// \param[in] ch Electric charge (0, 1, or -1) void setPdgId( const PDG& pdg, short ch = 0 ); /// Set the PDG identifier (along with the particle's electric charge) /// \param[in] pdg_id PDG identifier (incl. electric charge in e) void setPdgId( short pdg_id ); /// Retrieve the objectified PDG identifier inline PDG pdgId() const { return pdg_id_; } /// Retrieve the integer value of the PDG identifier int integerPdgId() const; /// Particle's helicity float helicity() const { return helicity_; } /// Set the helicity of the particle void setHelicity( float heli ) { helicity_ = heli; } - /** - * Gets the particle's mass in \f$\textrm{GeV}/c^{2}\f$. - * \brief Gets the particle's mass - * \return The particle's mass - */ + /// Particle mass in GeV/c\f${}^2\f$ + /// \return Particle's mass inline double mass() const { return mass_; }; - /** - * Set the mass of the particle in \f$\textrm{GeV}/c^{2}\f$ while ensuring that the kinematics is properly set (the mass is set according to the energy and the momentum in priority) - * \brief Compute the particle's mass in \f$\textrm{GeV}/c^{2}\f$ - */ + /// Compute the particle mass + /// \param[in] off_shell Allow the particle to be produced off-shell? + /// \note This method ensures that the kinematics is properly set (the mass is set according to the energy and the momentum in priority) void computeMass( bool off_shell = false ); - /** - * Set the mass of the particle in \f$\textrm{GeV}/c^{2}\f$ according to a value given as an argument. This method ensures that the kinematics is properly set (the mass is set according to the energy and the momentum in priority) - * \param m The mass in \f$\textrm{GeV}/c^{2}\f$ to set - * \brief Set the particle's mass in \f$\textrm{GeV}/c^{2}\f$ - */ + /// Set the particle mass, in GeV/c\f${}^2\f$ + /// \param m Mass in GeV/c\f${}^2\f$ + /// \note This method ensures that the kinematics is properly set (the mass is set according to the energy and the momentum in priority) void setMass( double m = -1. ); - /// Get the particle's squared mass (in \f$\textrm{GeV}^\textrm{2}\f$) + /// Particle squared mass, in GeV\f${}^2\f$/c\f${}^4\f$ inline double mass2() const { return mass_*mass_; }; /// Retrieve the momentum object associated with this particle inline Momentum& momentum() { return momentum_; } /// Retrieve the momentum object associated with this particle inline Momentum momentum() const { return momentum_; } /// Associate a momentum object to this particle void setMomentum( const Momentum& mom, bool offshell = false ); /** - * \brief Set the 3-momentum associated to the particle - * \param[in] px Momentum along the \f$x\f$-axis, in \f$\textrm{GeV}/c\f$ - * \param[in] py Momentum along the \f$y\f$-axis, in \f$\textrm{GeV}/c\f$ - * \param[in] pz Momentum along the \f$z\f$-axis, in \f$\textrm{GeV}/c\f$ - */ - void setMomentum( double px, double py, double pz ); - /** - * \brief Set the 4-momentum associated to the particle - * \param[in] px Momentum along the \f$x\f$-axis, in \f$\textrm{GeV}/c\f$ - * \param[in] py Momentum along the \f$y\f$-axis, in \f$\textrm{GeV}/c\f$ - * \param[in] pz Momentum along the \f$z\f$-axis, in \f$\textrm{GeV}/c\f$ + * \brief Set the 3- or 4-momentum associated to the particle + * \param[in] px Momentum along the \f$x\f$-axis, in GeV/c + * \param[in] py Momentum along the \f$y\f$-axis, in GeV/c + * \param[in] pz Momentum along the \f$z\f$-axis, in GeV/c * \param[in] e Energy, in GeV */ - void setMomentum( double px, double py, double pz, double e ); - /** - * \brief Set the 4-momentum associated to the particle - * \param[in] p 4-momentum - */ + void setMomentum( double px, double py, double pz, double e = -1. ); + /// Set the 4-momentum associated to the particle + /// \param[in] p 4-momentum inline void setMomentum( double p[4] ) { setMomentum( p[0], p[1], p[2], p[3] ); } - /** - * \brief Set the particle's energy - * \param[in] e Energy, in GeV - */ - void setEnergy( double e=-1. ); - /// Get the particle's energy (in GeV) + /// Set the particle's energy + /// \param[in] e Energy, in GeV + void setEnergy( double e = -1. ); + /// Get the particle's energy, in GeV double energy() const; - /// Get the particle's squared energy (in \f$\textrm{GeV}^\textrm{2}\f$) + /// Get the particle's squared energy, in GeV\f${}^2\f$ inline double energy2() const { return energy()*energy(); }; /// Is this particle a valid particle which can be used for kinematic computations? bool valid(); // --- particle relations /// Is this particle a primary particle? inline bool primary() const { return mothers_.empty(); } - /** - * \brief Set the mother particle - * \param[in] part A Particle object containing all the information on the mother particle - */ + /// Set the mother particle + /// \param[in] part A Particle object containing all the information on the mother particle void addMother( Particle& part ); - /** - * \brief Gets the unique identifier to the mother particle from which this particle arises - * \return An integer representing the unique identifier to the mother of this particle in the event - */ + /// Get the unique identifier to the mother particle from which this particle arises + /// \return An integer representing the unique identifier to the mother of this particle in the event inline ParticlesIds mothers() const { return mothers_; } /** * \brief Add a decay product * \param[in] part The Particle object in which this particle will desintegrate or convert * \return A boolean stating if the particle has been added to the daughters list or if it was already present before */ void addDaughter( Particle& part ); /// Gets the number of daughter particles inline unsigned int numDaughters() const { return daughters_.size(); }; - /** - * \brief Get an identifiers list all daughter particles - * \return An integer vector containing all the daughters' unique identifier in the event - */ + /// Get an identifiers list all daughter particles + /// \return An integer vector containing all the daughters' unique identifier in the event inline ParticlesIds daughters() const { return daughters_; } // --- global particle information extraction /// Dump all the information on this particle into the standard output stream void dump() const; private: /// Unique identifier in an event int id_; /// Electric charge (+-1 or 0) short charge_sign_; /// Momentum properties handler Momentum momentum_; - /// Mass in \f$\textrm{GeV}/c^2\f$ + /// Mass, in GeV/c\f${}^2\f$ double mass_; /// Helicity float helicity_; /// Role in the process Role role_; /// Decay/stability status Status status_; /// List of mother particles ParticlesIds mothers_; /// List of daughter particles ParticlesIds daughters_; /// PDG id PDG pdg_id_; }; /// Compute the centre of mass energy of two particles (incoming or outgoing states) double CMEnergy( const Particle& p1, const Particle& p2 ); /// Compute the centre of mass energy of two particles (incoming or outgoing states) double CMEnergy( const Particle::Momentum& m1, const Particle::Momentum& m2 ); //bool operator<( const Particle& a, const Particle& b ) { return a.id<b.id; } // --- particle containers /// List of Particle objects typedef std::vector<Particle> Particles; /// List of particles' roles typedef std::vector<Particle::Role> ParticleRoles; /// Map between a particle's role and its associated Particle object typedef std::map<Particle::Role,Particles> ParticlesMap; } #endif diff --git a/CepGen/Generator.h b/CepGen/Generator.h index 764ba13..3520ac3 100644 --- a/CepGen/Generator.h +++ b/CepGen/Generator.h @@ -1,122 +1,122 @@ #ifndef CepGen_Generator_h #define CepGen_Generator_h #include <sstream> #include <memory> #include <functional> //////////////////////////////////////////////////////////////////////////////// /** - * \image latex cepgen_logo.pdf * \mainpage Foreword * This Monte Carlo generator was developed as a modern version of the LPAIR code introduced - * in the early 1990s by J. Vermaseren *et al*\cite Vermaseren1983347. This latter allows to + * in the early 1990s by J. Vermaseren *et al*\cite Baranov:1991yq\cite Vermaseren:1982cz. This latter allows to * compute the cross-section and to generate events for the \f$\gamma\gamma\to\ell^{+}\ell^{-}\f$ * process in the scope of high energy physics. * * Soon after the integration of its matrix element, it was extended as a tool to compute and * generate events for any generic 2\f$\rightarrow\f$ 3 central exclusive process. * To do so, the main operation performed here is the integration of the matrix element (given as a - * subset of a GenericProcess object) by the GSL implementation of the *Vegas* algorithm, a - * numerical technique for importance sampling integration developed in 1972 by G. P. Lepage\cite PeterLepage1978192. + * subset of a GenericProcess object) over the full available phase space. * */ //////////////////////////////////////////////////////////////////////////////// /// Common namespace for this Monte Carlo generator namespace CepGen { namespace Integrand { /** * Function to be integrated. It returns the value of the weight for one point * of the full phase space (or "event"). This weights includes the matrix element * of the process considered, along with all the kinematic factors, and the cut * restrictions imposed on this phase space. \f$x\f$ is therefore an array of random * numbers defined inside its boundaries (as normalised so that \f$\forall i<\mathrm{ndim}\f$, * \f$0<x_i<1\f$. */ double eval( double*, size_t, void* ); } class Event; class Integrator; class Parameters; //////////////////////////////////////////////////////////////////////////////// /** * This object represents the core of this Monte Carlo generator, with its * capability to generate the events (using the embedded Vegas object) and to * study the phase space in term of the variation of resulting cross section - * while scanning the various parameters (point \f$\textbf{x}\f$ in the + * while scanning the various parameters (point \f${\bf x}\f$ in the * multi-dimensional phase space). * * The phase space is constrained using the Parameters object given as an * argument to the constructor, and the differential cross-sections for each - * value of the array \f$\textbf{x}\f$ are computed in the \a f-function defined + * value of the array \f${\bf x}\f$ are computed in the \a f-function defined * outside (but populated inside) this object. * * This f-function embeds a GenericProcess-inherited object which defines all the * methods to compute this differential cross-section as well as the in- and outgoing * kinematics associated to each particle. * * \author Laurent Forthomme <laurent.forthomme@cern.ch> * \date Feb 2013 * \brief Core of the Monte-Carlo generator * */ class Generator { public: /// Core of the Monte Carlo integrator and events generator Generator(); /// Core of the Monte Carlo integrator and events generator /// \param[in] ip List of input parameters defining the phase space on which to perform the integration Generator( Parameters *ip ); ~Generator(); /// Dump this program's header into the standard output stream void printHeader(); /// Feed the generator with a Parameters object void setParameters( Parameters& ip ); /// Remove all references to a previous generation/run void clearRun(); /** * Compute the cross section for the run parameters defined by this object. * This returns the cross section as well as the absolute error computed along. * \brief Compute the cross-section for the given process * \param[out] xsec The computed cross-section, in pb * \param[out] err The absolute integration error on the computed cross-section, in pb */ void computeXsection( double& xsec, double& err ); + /// Integrate the functional over the whole phase space + void integrate(); /// Last cross section computed by the generator - double crossSection() const { return cross_section_; } + double crossSection() const { return result_; } /// Last error on the cross section computed by the generator - double crossSectionError() const { return cross_section_error_; } + double crossSectionError() const { return result_error_; } //void terminate(); /// Generate one single event given the phase space computed by Vegas in the integration step /// \return A pointer to the Event object generated in this run std::shared_ptr<Event> generateOneEvent(); /// Launch the generation of events void generate( std::function<void( const Event&, unsigned long )> callback = {} ); /// Number of dimensions on which the integration is performed size_t numDimensions() const; /// Compute one single point from the total phase space /// \param[in] x the n-dimensional point to compute /// \return the function value for the given point double computePoint( double* x ); /// Physical Parameters used in the events generation and cross-section computation std::unique_ptr<Parameters> parameters; private: /// Vegas instance which will integrate the function std::unique_ptr<Integrator> integrator_; /// Cross section value computed at the last integration - double cross_section_; + double result_; /// Error on the cross section as computed in the last integration - double cross_section_error_; + double result_error_; }; } #endif diff --git a/CepGen/Hadronisers/GenericHadroniser.cpp b/CepGen/Hadronisers/GenericHadroniser.cpp index ac2d150..b2049da 100644 --- a/CepGen/Hadronisers/GenericHadroniser.cpp +++ b/CepGen/Hadronisers/GenericHadroniser.cpp @@ -1,45 +1,54 @@ #include "CepGen/Hadronisers/GenericHadroniser.h" + #include "CepGen/Core/Exception.h" +#include "CepGen/Core/ParametersList.h" namespace CepGen { namespace Hadroniser { - GenericHadroniser::GenericHadroniser( const char* name ) : - name_( name ) - {} + GenericHadroniser::GenericHadroniser( const char* name, const ParametersList& plist ) : + name_( name ), + seed_ ( plist.get<int>( "seed", -1ll ) ), + max_trials_( plist.get<int>( "maxTrials", 1 ) ) + { + 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<std::string>& 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 Hadroniser::GenericHadroniser& hadr ) { return os << hadr.name().c_str(); } std::ostream& operator<<( std::ostream& os, const Hadroniser::GenericHadroniser* hadr ) { return os << hadr->name().c_str(); } } diff --git a/CepGen/Hadronisers/GenericHadroniser.h b/CepGen/Hadronisers/GenericHadroniser.h index da08557..b7b7440 100644 --- a/CepGen/Hadronisers/GenericHadroniser.h +++ b/CepGen/Hadronisers/GenericHadroniser.h @@ -1,56 +1,70 @@ #ifndef CepGen_Hadronisers_GenericHadroniser_h #define CepGen_Hadronisers_GenericHadroniser_h #include <vector> #include <memory> #include <iostream> namespace CepGen { class Event; class Particle; class Parameters; + class ParametersList; /// Location for all hadronisers to be run downstream to the events generation namespace Hadroniser { /** - * Class template to define any hadroniser as a general object with defined methods + * \brief Class template to define any hadroniser as a general object with defined methods * \author Laurent Forthomme <laurent.forthomme@cern.ch> * \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 char* name = "unnamed_hadroniser" ); + explicit GenericHadroniser( const char* name, const ParametersList& ); virtual ~GenericHadroniser() {} - /// 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 a random numbers generator seed for the hadroniser - /// \param[in] seed A RNG seed - virtual void setSeed( long long seed ) = 0; - virtual void setCrossSection( double xsec, double xsec_err ) {} - + /// 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<std::string>& 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 ) {} + + /// \brief Specify a random numbers generator seed for the hadroniser + /// \param[in] seed A RNG seed + void setSeed( long long seed ) { seed_ = seed; } /// 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_; }; } } #endif diff --git a/CepGen/Hadronisers/Pythia8Hadroniser.cpp b/CepGen/Hadronisers/Pythia8Hadroniser.cpp index b8a0669..85964dd 100644 --- a/CepGen/Hadronisers/Pythia8Hadroniser.cpp +++ b/CepGen/Hadronisers/Pythia8Hadroniser.cpp @@ -1,475 +1,464 @@ #include "CepGen/Hadronisers/Pythia8Hadroniser.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" namespace CepGen { namespace Hadroniser { #ifdef PYTHIA8 Pythia8::Vec4 momToVec4( const Particle::Momentum& mom ) { return Pythia8::Vec4( mom.px(), mom.py(), mom.pz(), mom.energy() ); } #endif - Pythia8Hadroniser::Pythia8Hadroniser( const Parameters& params ) : - GenericHadroniser( "pythia8" ), max_attempts_( params.hadroniser_max_trials ), + Pythia8Hadroniser::Pythia8Hadroniser( const Parameters& params, const ParametersList& plist ) : + GenericHadroniser( "pythia8", plist ), #ifdef PYTHIA8 pythia_( new Pythia8::Pythia ), lhaevt_( new LHAEvent( ¶ms ) ), #endif full_evt_( false ), offset_( 0 ), first_evt_( true ), params_( ¶ms ) { #ifdef PYTHIA8 pythia_->setLHAupPtr( (Pythia8::LHAup*)lhaevt_.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() ); #endif for ( const auto& pdgid : params.kinematics.minimum_final_state ) min_ids_.emplace_back( (unsigned short)pdgid ); } Pythia8Hadroniser::~Pythia8Hadroniser() { #ifdef PYTHIA8 - pythia_->settings.writeFile( "last_pythia_config.cmd", true ); + pythia_->settings.writeFile( "last_pythia_config.cmd", false ); #endif } - bool + void + Pythia8Hadroniser::readString( const char* param ) + { +#ifdef PYTHIA8 + if ( !pythia_->readString( param ) ) + throw CG_FATAL( "Pythia8Hadroniser" ) << "The Pythia8 core failed to parse the following setting:\n\t" << param; +#endif + } + + void Pythia8Hadroniser::init() { #ifdef PYTHIA8 if ( pythia_->settings.flag( "ProcessLevel:all" ) != full_evt_ ) pythia_->settings.flag( "ProcessLevel:all", full_evt_ ); + if ( seed_ == -1ll ) + pythia_->settings.flag( "Random:setSeed", false ); + else { + pythia_->settings.flag( "Random:setSeed", true ); + pythia_->settings.mode( "Random:seed", seed_ ); + } + switch ( params_->kinematics.mode ) { - case KinematicsMode::ElasticElastic: + case KinematicsMode::ElasticElastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 3 ); - break; - case KinematicsMode::InelasticElastic: + } break; + case KinematicsMode::InelasticElastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 2 ); - break; - case KinematicsMode::ElasticInelastic: + } break; + case KinematicsMode::ElasticInelastic: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 1 ); - break; - case KinematicsMode::InelasticInelastic: default: + } break; + case KinematicsMode::InelasticInelastic: default: { pythia_->settings.mode( "BeamRemnants:unresolvedHadron", 0 ); - break; + } break; } -// pythia_->settings.mode( "BeamRemnants:remnantMode", 1 ); if ( !pythia_->init() ) throw CG_FATAL( "Pythia8Hadroniser" ) << "Failed to initialise the Pythia8 core!\n\t" << "See the message above for more details."; #else throw CG_FATAL( "Pythia8Hadroniser" ) - << "Pythia8 is not linked to thin instance!"; -#endif - return true; - } - - void - Pythia8Hadroniser::readString( const char* param ) - { -#ifdef PYTHIA8 - if ( !pythia_->readString( param ) ) - throw CG_FATAL( "Pythia8Hadroniser" ) << "The Pythia8 core failed to parse the following setting:\n\t" << param; -#endif - } - - void - Pythia8Hadroniser::setSeed( long long seed ) - { -#ifdef PYTHIA8 - if ( seed == -1ll ) - pythia_->settings.flag( "Random:setSeed", false ); - else { - pythia_->settings.flag( "Random:setSeed", true ); - pythia_->settings.mode( "Random:seed", seed ); - } + << "Pythia8 is not linked to this instance!"; #endif } void Pythia8Hadroniser::setCrossSection( double xsec, double xsec_err ) { #ifdef PYTHIA8 lhaevt_->setCrossSection( 0, xsec, xsec_err ); #endif } bool Pythia8Hadroniser::run( Event& ev, double& weight, bool full ) { //--- initialise the event weight before running any decay algorithm weight = 1.; -#ifndef PYTHIA8 - throw CG_FATAL( "Pythia8Hadroniser" ) << "Pythia8 is not linked to this instance!"; -#else +#ifdef PYTHIA8 if ( !full && !pythia_->settings.flag( "ProcessLevel:resonanceDecays" ) ) return true; //--- switch full <-> partial event if ( full != full_evt_ ) { full_evt_ = full; init(); } //=========================================================================================== // convert our event into a custom LHA format //=========================================================================================== lhaevt_->feedEvent( ev, full, params_->kinematics.mode ); //if ( full ) lhaevt_->listEvent(); //=========================================================================================== // launch the hadronisation / resonances decays, and update the event accordingly //=========================================================================================== ev.num_hadronisation_trials = 0; while ( true ) { - ev.num_hadronisation_trials++; // start at 1 - if ( ev.num_hadronisation_trials > max_attempts_ ) + if ( ev.num_hadronisation_trials++ > max_trials_ ) return false; //--- run the hadronisation/fragmentation algorithm - if ( !pythia_->next() ) - continue; - //--- hadronisation successful - if ( first_evt_ && full ) { - offset_ = 0; - for ( unsigned short i = 1; i < pythia_->event.size(); ++i ) - if ( pythia_->event[i].status() == -12 ) // skip the incoming particles - offset_++; - first_evt_ = false; + 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() == -12 ) // skip the incoming particles + offset_++; + first_evt_ = false; + } + break; } - break; } //=========================================================================================== // update the event content with Pythia's output //=========================================================================================== updateEvent( ev, weight, full ); - -#endif return true; +#else + throw CG_FATAL( "Pythia8Hadroniser" ) << "Pythia8 is not linked to this instance!"; +#endif } #ifdef PYTHIA8 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( static_cast<PDG>( abs( py_part.id() ) ), py_part.charge() ); op.setStatus( py_part.isFinal() ? Particle::Status::FinalState : Particle::Status::Propagator ); op.setMomentum( Particle::Momentum( mom.px(), mom.py(), mom.pz(), mom.e() ) ); op.setMass( mom.mCalc() ); lhaevt_->addCorresp( py_part.index()-offset_, op.id() ); return op; } void Pythia8Hadroniser::updateEvent( Event& ev, double& weight, bool full ) const { for ( unsigned short i = 1+offset_; i < pythia_->event.size(); ++i ) { const Pythia8::Particle& p = pythia_->event[i]; - const unsigned short cg_id = lhaevt_->cgPart( i-offset_ ); + const unsigned short cg_id = lhaevt_->cepgenId( i-offset_ ); if ( cg_id != LHAEvent::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; } //--- particle is not what we expect - if ( abs( p.id() ) != abs( cg_part.integerPdgId() ) ) { + if ( p.idAbs() != abs( cg_part.integerPdgId() ) ) { CG_INFO( "Pythia8Hadroniser:update" ) << "LHAEVT event content:"; lhaevt_->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:"; lhaevt_->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() << "!"; } - //--- no decay for this particle - if ( p.particleDataEntry().sizeChannels() == 0 ) - continue; //--- resonance decayed; apply branching ratio for this decay - weight *= p.particleDataEntry().pickChannel().bRatio(); - cg_part.setStatus( Particle::Status::Resonance ); + if ( p.particleDataEntry().sizeChannels() > 0 ) { + weight *= p.particleDataEntry().pickChannel().bRatio(); + cg_part.setStatus( Particle::Status::Resonance ); + } } else { //----- new particle to be added - Particle::Role role = (Particle::Role)findRole( ev, p ); - Pythia8::Vec4 mom = p.p(); - switch ( role ) { + const unsigned short role = findRole( ev, p ); + switch ( (Particle::Role)role ) { default: break; - case Particle::OutgoingBeam1: // no break! + case Particle::OutgoingBeam1: { ev.getByRole( Particle::OutgoingBeam1 )[0].setStatus( Particle::Status::Fragmented ); if ( abs( p.status() ) != 61 ) break; - case Particle::OutgoingBeam2: // no break! + } // no break! + case Particle::OutgoingBeam2: { ev.getByRole( Particle::OutgoingBeam2 )[0].setStatus( Particle::Status::Fragmented ); if ( abs( p.status() ) != 61 ) break; + } // no break! } // found the role ; now we can add the particle - Particle& cg_part = addParticle( ev, p, mom, (unsigned short)role ); + Particle& cg_part = addParticle( ev, p, p.p(), role ); for ( const auto& moth_id : p.motherList() ) { if ( moth_id <= offset_ ) continue; - const unsigned short moth_cg_id = lhaevt_->cgPart( moth_id-offset_ ); + const unsigned short moth_cg_id = lhaevt_->cepgenId( moth_id-offset_ ); if ( moth_cg_id != LHAEvent::invalid_id ) cg_part.addMother( ev[moth_cg_id] ); else - cg_part.addMother( addParticle( ev, pythia_->event[moth_id], mom, (unsigned short)role ) ); + cg_part.addMother( addParticle( ev, pythia_->event[moth_id], p.p(), role ) ); if ( !p.isFinal() ) { if ( p.isResonance() || p.daughterList().size() > 0 ) 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 = lhaevt_->cgPart( par_id-offset_ ); + const unsigned short par_cg_id = lhaevt_->cepgenId( par_id-offset_ ); if ( par_cg_id != LHAEvent::invalid_id ) - return (unsigned short)ev.getConstById( par_cg_id ).role(); + return (unsigned short)ev.at( par_cg_id ).role(); return findRole( ev, pythia_->event[par_id] ); } return (unsigned short)Particle::UnknownRole; } #endif } //================================================================================================ // Custom LHA event definition //================================================================================================ #ifdef PYTHIA8 const double LHAEvent::mp_ = ParticleProperties::mass( PDG::proton ); const double LHAEvent::mp2_ = LHAEvent::mp_*LHAEvent::mp_; LHAEvent::LHAEvent( const Parameters* params ) : LHAup( 3 ), params_( params ) { addProcess( 0, 1., 1., 1.e3 ); if ( params_ ) { 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 ); } } void LHAEvent::setCrossSection( int id, double xsec, double xsec_err ) { setXSec( id, xsec ); setXErr( id, xsec_err ); //listInit(); } void LHAEvent::feedEvent( const Event& ev, bool full, const KinematicsMode& mode ) { const double scale = ev.getOneByRole( Particle::Intermediate ).mass(); setProcess( 0, 1., scale, Constants::alphaEM, Constants::alphaQCD ); const Particle& part1 = ev.getOneByRole( Particle::Parton1 ), &part2 = ev.getOneByRole( Particle::Parton2 ); const Particle& op1 = ev.getOneByRole( Particle::OutgoingBeam1 ), &op2 = ev.getOneByRole( Particle::OutgoingBeam2 ); 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 quark1_id = 0, quark2_id = 0; unsigned short quark1_pdgid = part1.integerPdgId(), quark2_pdgid = part2.integerPdgId(); const Pythia8::Vec4 mom_part1( Hadroniser::momToVec4( part1.momentum() ) ), mom_part2( Hadroniser::momToVec4( part2.momentum() ) ); if ( !full ) { //============================================================================================= // incoming partons //============================================================================================= addCorresp( sizePart(), part1.id() ); addParticle( quark1_pdgid, -2, quark1_id, 0, 0, 0, mom_part1.px(), mom_part1.py(), mom_part1.pz(), mom_part1.e(), mom_part1.mCalc(), 0., 0. ); addCorresp( sizePart(), part2.id() ); addParticle( quark2_pdgid, -2, quark2_id, 0, 0, 0, mom_part2.px(), mom_part2.py(), mom_part2.pz(), mom_part2.e(), mom_part2.mCalc(), 0., 0. ); } else { // full event content (with collinear partons) const bool inel1 = ( mode == KinematicsMode::InelasticElastic || mode == KinematicsMode::InelasticInelastic ); const bool inel2 = ( mode == KinematicsMode::ElasticInelastic || mode == KinematicsMode::InelasticInelastic ); - unsigned short quark1_colour = 0, quark2_colour = 0; Pythia8::Vec4 mom_iq1 = mom_part1, mom_iq2 = mom_part2; + unsigned short colour_index = 501, quark1_colour = 0, quark2_colour = 0; //FIXME select quark flavours accordingly if ( inel1 ) { quark1_pdgid = 2; - quark1_colour = 501; - const Particle& ip1 = ev.getOneByRole( Particle::IncomingBeam1 ); - mom_iq1 = Pythia8::Vec4( 0., 0., x1*ip1.momentum().pz(), x1*ip1.energy() ); + quark1_colour = colour_index++; + mom_iq1 = Hadroniser::momToVec4( x1*ev.getOneByRole( Particle::IncomingBeam1 ).momentum() ); } if ( inel2 ) { quark2_pdgid = 2; - quark2_colour = 502; - const Particle& ip2 = ev.getOneByRole( Particle::IncomingBeam2 ); - mom_iq2 = Pythia8::Vec4( 0., 0., x2*ip2.momentum().pz(), x2*ip2.energy() ); + quark2_colour = colour_index++; + mom_iq2 = Hadroniser::momToVec4( x2*ev.getOneByRole( Particle::IncomingBeam2 ).momentum() ); } //--- flavour / x value of hard-process initiators setIdX( part1.integerPdgId(), part2.integerPdgId(), x1, x2 ); //=========================================================================================== // incoming valence quarks //=========================================================================================== quark1_id = sizePart(); - addCorresp( sizePart(), op1.id() ); + addCorresp( quark1_id, op1.id() ); addParticle( quark1_pdgid, -1, 0, 0, quark1_colour, 0, mom_iq1.px(), mom_iq1.py(), mom_iq1.pz(), mom_iq1.e(), mom_iq1.mCalc(), 0., 1. ); quark2_id = sizePart(); - addCorresp( sizePart(), op2.id() ); + addCorresp( quark2_id, op2.id() ); addParticle( quark2_pdgid, -1, 0, 0, quark2_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 Pythia8::Vec4 mom_oq1 = mom_iq1-mom_part1; addParticle( quark1_pdgid, 1, quark1_id, quark2_id, quark1_colour, 0, mom_oq1.px(), mom_oq1.py(), mom_oq1.pz(), mom_oq1.e(), mom_oq1.mCalc(), 0., 1. ); } if ( inel2 ) { const Pythia8::Vec4 mom_oq2 = mom_iq2-mom_part2; addParticle( quark2_pdgid, 1, quark1_id, quark2_id, quark2_colour, 0, mom_oq2.px(), mom_oq2.py(), mom_oq2.pz(), mom_oq2.e(), mom_oq2.mCalc(), 0., 1. ); } } //============================================================================================= // central system //============================================================================================= for ( const auto& p : ev.getByRole( Particle::CentralSystem ) ) { const auto mothers = p.mothers(); unsigned short moth1_id = 1, moth2_id = 2; if ( !full ) { moth1_id = moth2_id = 0; if ( mothers.size() > 0 ) { const unsigned short moth1_cg_id = *mothers.begin(); - moth1_id = pyPart( moth1_cg_id ); + moth1_id = pythiaId( moth1_cg_id ); if ( moth1_id == invalid_id ) { - const Particle& moth = ev.getConstById( moth1_cg_id ); + const Particle& moth = ev.at( moth1_cg_id ); if ( moth.mothers().size() > 0 ) - moth1_id = pyPart( *moth.mothers().begin() ); + moth1_id = pythiaId( *moth.mothers().begin() ); if ( moth.mothers().size() > 1 ) - moth2_id = pyPart( *moth.mothers().rbegin() ); + moth2_id = pythiaId( *moth.mothers().rbegin() ); } if ( mothers.size() > 1 ) { const unsigned short moth2_cg_id = *mothers.rbegin(); - moth2_id = pyPart( moth2_cg_id ); + moth2_id = pythiaId( moth2_cg_id ); if ( moth2_id == invalid_id ) { - const Particle& moth = ev.getConstById( moth2_cg_id ); + const Particle& moth = ev.at( moth2_cg_id ); moth.dump(); - moth2_id = pyPart( *moth.mothers().rbegin() ); + moth2_id = pythiaId( *moth.mothers().rbegin() ); } } } } const Pythia8::Vec4 mom_part( p.momentum().px(), p.momentum().py(), p.momentum().pz(), p.momentum().energy() ); addCorresp( sizePart(), p.id() ); addParticle( p.integerPdgId(), 1, moth1_id, moth2_id, 0, 0, mom_part.px(), mom_part.py(), mom_part.pz(), mom_part.e(), mom_part.mCalc(), 0., 0., 0. ); } setPdf( quark1_pdgid, quark2_pdgid, x1, x2, scale, 0., 0., false ); } bool LHAEvent::setInit() { return true; } bool LHAEvent::setEvent( int ) { return true; } void LHAEvent::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 - LHAEvent::cgPart( unsigned short py_id ) const + LHAEvent::cepgenId( unsigned short py_id ) const { for ( const auto& py_cg : py_cg_corresp_ ) if ( py_cg.first == py_id ) return py_cg.second; return invalid_id; } unsigned short - LHAEvent::pyPart( unsigned short cg_id ) const + LHAEvent::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 LHAEvent::addCorresp( unsigned short py_id, unsigned short cg_id ) { py_cg_corresp_.emplace_back( py_id, cg_id ); } void LHAEvent::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( "LHAEvent:dump" ) << oss.str(); } #endif } diff --git a/CepGen/Hadronisers/Pythia8Hadroniser.h b/CepGen/Hadronisers/Pythia8Hadroniser.h index 84e1f20..dfdbcbc 100644 --- a/CepGen/Hadronisers/Pythia8Hadroniser.h +++ b/CepGen/Hadronisers/Pythia8Hadroniser.h @@ -1,86 +1,84 @@ #ifndef CepGen_Hadronisers_Pythia8Hadroniser_h #define CepGen_Hadronisers_Pythia8Hadroniser_h #include "CepGen/Hadronisers/GenericHadroniser.h" #ifdef PYTHIA8 #include <Pythia8/Pythia.h> #include <memory> #endif #include <unordered_map> #include <vector> namespace CepGen { class Particle; + class ParametersList; enum class KinematicsMode; #ifdef PYTHIA8 class LHAEvent : public Pythia8::LHAup { public: explicit LHAEvent( const Parameters* ); void feedEvent( const Event& ev, bool full, const KinematicsMode& ); bool setInit() override; bool setEvent( int ) override; void setCrossSection( int id, double xsec, double xsec_err ); void setProcess( int id, double xsec, double q2_scale, double alpha_qed, double alpha_qcd ); - unsigned short cgPart( unsigned short py_id ) const; - unsigned short pyPart( unsigned short cg_id ) const; + unsigned short cepgenId( unsigned short py_id ) const; + unsigned short pythiaId( unsigned short cg_id ) const; void addCorresp( unsigned short py_id, unsigned short cg_id ); void dumpCorresp() const; static constexpr unsigned short invalid_id = 999; private: static const double mp_, mp2_; std::vector<std::pair<unsigned short, unsigned short> > py_cg_corresp_; const Parameters* params_; }; #endif namespace Hadroniser { /** * 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 Parameters& ); + explicit Pythia8Hadroniser( const Parameters&, const ParametersList& ); ~Pythia8Hadroniser(); + void readString( const char* param ) override; + void init() override; bool run( Event& ev, double& weight, bool full ) override; - void setSeed( long long seed ) override; + void setCrossSection( double xsec, double xsec_err ) override; bool fullEvent() const { return full_evt_; } void setFullEvent( bool full = true ) { full_evt_ = full; } - bool init(); - void readString( const char* param ) override; - private: static constexpr unsigned short invalid_idx_ = 999; - unsigned short max_attempts_; std::vector<unsigned short> min_ids_; std::unordered_map<short,short> py_cg_corresp_; #ifdef PYTHIA8 unsigned short findRole( const Event& ev, const Pythia8::Particle& p ) const; void updateEvent( Event& ev, double& weight, bool full ) const; Particle& addParticle( Event& ev, const Pythia8::Particle&, const Pythia8::Vec4& mom, unsigned short ) const; /// A Pythia8 core to be wrapped std::unique_ptr<Pythia8::Pythia> pythia_; - std::shared_ptr<LHAEvent> lhaevt_; + std::unique_ptr<LHAEvent> lhaevt_; #endif bool full_evt_; unsigned short offset_; bool first_evt_; const Parameters* params_; // not owning }; } } #endif - diff --git a/CepGen/IO/ExportHandler.h b/CepGen/IO/ExportHandler.h index 741a32e..dcf77a8 100644 --- a/CepGen/IO/ExportHandler.h +++ b/CepGen/IO/ExportHandler.h @@ -1,57 +1,59 @@ #ifndef CepGen_Export_ExportHandler_h #define CepGen_Export_ExportHandler_h #include <iostream> namespace CepGen { class Event; class Parameters; /// Location for all output generators namespace OutputHandler { /** * \brief Output format handler for events export * \author Laurent Forthomme <laurent.forthomme@cern.ch> * \date Sep 2016 */ class ExportHandler { public: /// All types of output available for export enum OutputType { HepMC, ///< HepMC ASCII format LHE ///< LHEF format }; + /// Human-readable output name friend std::ostream& operator<<( std::ostream& os, const OutputType& type ) { switch ( type ) { case HepMC: return os << "HepMC ASCII"; case LHE: return os << "LHEF"; } return os; } public: - /// Class constructor + /// \brief Class constructor /// \param[in] type Requested output type explicit ExportHandler( const OutputType& type ) : type_( type ), event_num_( 0. ) {} virtual ~ExportHandler() {} + /// 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: /// Type of output requested OutputType type_; /// Event index unsigned int event_num_; }; } } #endif diff --git a/CepGen/IO/GridHandler.h b/CepGen/IO/GridHandler.h index 18ba207..68e1556 100644 --- a/CepGen/IO/GridHandler.h +++ b/CepGen/IO/GridHandler.h @@ -1,303 +1,314 @@ #ifndef CepGen_IO_GridHandler_h #define CepGen_IO_GridHandler_h #include <gsl/gsl_version.h> #ifdef GSL_MAJOR_VERSION # if GSL_MAJOR_VERSION > 2 || ( GSL_MAJOR_VERSION == 2 && GSL_MINOR_VERSION >= 1 ) # include <gsl/gsl_interp2d.h> # include <gsl/gsl_spline2d.h> # define GOOD_GSL 1 # endif #endif #include <gsl/gsl_interp.h> #include <gsl/gsl_spline.h> #include <gsl/gsl_errno.h> #include <gsl/gsl_math.h> #include "CepGen/Core/Exception.h" #include <vector> #include <map> namespace CepGen { class StructureFunctions; enum struct GridType { linear = 0, logarithmic = 1, square = 2 }; - /// A generic class for D-dimensional grid interpolation + /// \brief A generic class for D-dimensional grid interpolation /// \param N Number of values handled per point template <size_t D,size_t N=1> class GridHandler { public: typedef std::vector<double> coord_t; typedef std::array<double,N> values_t; public: explicit GridHandler( const GridType& grid_type ) : grid_type_( grid_type ), accel_{} { for ( size_t i = 0; i < D; ++i ) accel_.emplace_back( gsl_interp_accel_alloc(), gsl_interp_accel_free ); } ~GridHandler() {} /// Interpolate a point to a given coordinate values_t eval( coord_t in_coords ) const { values_t out; coord_t coord = in_coords; switch ( grid_type_ ) { case GridType::logarithmic: { for ( auto& c : coord ) c = log10( c ); } break; case GridType::square: { for ( auto& c : coord ) c *= c; } break; default: break; } //--- dimension of the vector space coordinate to evaluate switch ( D ) { case 1: { for ( size_t i = 0; i < N; ++i ) { int res = gsl_spline_eval_e( splines_1d_.at( i ).get(), coord.at( 0 ), accel_.at( 0 ).get(), &out[i] ); if ( res != GSL_SUCCESS ) { out[i] = 0.; CG_WARNING( "GridHandler" ) << "Failed to evaluate the grid value (N=" << i << ") " << "for x = " << in_coords.at( 0 ) << ". " << "GSL error: " << gsl_strerror( res ); } } } break; case 2: { #ifdef GOOD_GSL const double x = coord.at( 0 ), y = coord.at( 1 ); for ( size_t i = 0; i < N; ++i ) { int res = gsl_spline2d_eval_e( splines_2d_.at( i ).get(), x, y, accel_.at( 0 ).get(), accel_.at( 1 ).get(), &out[i] ); if ( res != GSL_SUCCESS ) { out[i] = 0.; CG_WARNING( "GridHandler" ) << "Failed to evaluate the grid value (N=" << i << ") " << "for x = " << in_coords.at( 0 ) << " / y = " << in_coords.at( 1 ) << ". " << "GSL error: " << gsl_strerror( res ); } } #else //--- retrieve the indices of the bin in the set coord_t before, after; findIndices( coord, before, after ); //--- find boundaries values const gridpoint_t& ext_11 = values_raw_.at( { before[0], before[1] } ), &ext_12 = values_raw_.at( { before[0], after[1] } ), &ext_21 = values_raw_.at( { after[0], before[1] } ), &ext_22 = values_raw_.at( { after[0], after[1] } ); //--- now that we have the boundaries, we may interpolate coord_t c_d( D ); for ( size_t i = 0; i < D; ++i ) c_d[i] = ( after[i] != before[i] ) ? ( coord.at( i )-before[i] )/( after[i]-before[i] ) : 0.; const gridpoint_t ext_1 = ext_11*( 1.-c_d[0] ) + ext_21*c_d[0]; const gridpoint_t ext_2 = ext_12*( 1.-c_d[0] ) + ext_22*c_d[0]; out = ext_1*( 1.-c_d[1] )+ext_2*c_d[1]; #endif } break; case 3: { //--- retrieve the indices of the bin in the set coord_t before, after; findIndices( coord, before, after ); //--- find boundaries values const gridpoint_t& ext_111 = values_raw_.at( { before[0], before[1], before[2] } ), &ext_112 = values_raw_.at( { before[0], before[1], after[2] } ), &ext_121 = values_raw_.at( { before[0], after[1], before[2] } ), &ext_122 = values_raw_.at( { before[0], after[1], after[2] } ), &ext_211 = values_raw_.at( { after[0], before[1], before[2] } ), &ext_212 = values_raw_.at( { after[0], before[1], after[2] } ), &ext_221 = values_raw_.at( { after[0], after[1], before[2] } ), &ext_222 = values_raw_.at( { after[0], after[1], after[2] } ); //--- now that we have the boundaries, we may interpolate coord_t c_d( D ); for ( size_t i = 0; i < D; ++i ) c_d[i] = ( after[i] != before[i] ) ? ( coord.at( i )-before[i] )/( after[i]-before[i] ) : 0.; const gridpoint_t ext_11 = ext_111*( 1.-c_d[0] ) + ext_211*c_d[0]; const gridpoint_t ext_12 = ext_112*( 1.-c_d[0] ) + ext_212*c_d[0]; const gridpoint_t ext_21 = ext_121*( 1.-c_d[0] ) + ext_221*c_d[0]; const gridpoint_t ext_22 = ext_122*( 1.-c_d[0] ) + ext_222*c_d[0]; const gridpoint_t ext_1 = ext_11*( 1.-c_d[1] ) + ext_21*c_d[1]; const gridpoint_t ext_2 = ext_12*( 1.-c_d[1] ) + ext_22*c_d[1]; out = ext_1*( 1.-c_d[2] )+ext_2*c_d[2]; } break; default: throw CG_FATAL( "GridHandler" ) << "Unsupported number of dimensions: " << N << ".\n\t" << "Please contact the developers to add such a new feature."; } return out; } /// Insert a new value in the grid void insert( coord_t coord, values_t value ) { auto mod_coord = coord; if ( grid_type_ != GridType::linear ) for ( auto& c : mod_coord ) switch ( grid_type_ ) { case GridType::logarithmic: c = log10( c ); break; case GridType::square: c *= c; break; default: break; } values_raw_[mod_coord] = value; } /// Return the list of values handled in the grid std::map<coord_t,values_t> values() const { return values_raw_; } /// Initialise the grid and all useful interpolators/accelerators void init() { if ( values_raw_.empty() ) CG_ERROR( "GridHandler" ) << "Empty grid."; gsl_set_error_handler_off(); //--- start by building grid coordinates from raw values for ( auto& c : coords_ ) c.clear(); for ( const auto& val : values_raw_ ) { unsigned short i = 0; for ( const auto& c : val.first ) { if ( std::find( coords_.at( i ).begin(), coords_.at( i ).end(), c ) == coords_.at( i ).end() ) coords_.at( i ).emplace_back( c ); ++i; } } for ( auto& c : coords_ ) std::sort( c.begin(), c.end() ); { //--- debugging of the grid coordinates std::ostringstream os; unsigned short i = 0; for ( const auto& cs : coords_ ) { os << "\n>> coordinate " << (i++) << " has " << cs.size() << " member" << ( cs.size() > 1 ? "s" : "" ) << ":"; unsigned short j = 0; for ( const auto& val : cs ) os << ( j++ % 20 == 0 ? "\n " : " " ) << val; } CG_DEBUG( "GridHandler" ) << "Grid dump:" << os.str(); } //--- particularise by dimension switch ( D ) { case 1: { //--- x |-> (f1,...) const gsl_interp_type* type = gsl_interp_cspline; //const gsl_interp_type* type = gsl_interp_steffen; #ifdef GOOD_GSL const unsigned short min_size = gsl_interp_type_min_size( type ); #else const unsigned short min_size = type->min_size; #endif if ( min_size >= values_raw_.size() ) throw CG_FATAL( "GridHandler" ) << "Not enough points for \"" << type->name << "\" type of interpolation.\n\t" << "Minimum required: " << min_size << ", got " << values_raw_.size() << "!"; for ( size_t i = 0; i < N; ++i ) { values_[i].reset( new double[values_raw_.size()] ); splines_1d_.emplace_back( gsl_spline_alloc( type, values_raw_.size() ), gsl_spline_free ); } std::vector<double> x_vec; unsigned short i = 0; for ( const auto& vals : values_raw_ ) { x_vec.emplace_back( vals.first.at( 0 ) ); unsigned short j = 0; for ( const auto& val : vals.second ) values_[j++].get()[i++] = val; } for ( unsigned short i = 0; i < splines_1d_.size(); ++i ) gsl_spline_init( splines_1d_.at( i ).get(), &x_vec[0], values_[i].get(), values_raw_.size() ); } break; case 2: { //--- (x,y) |-> (f1,...) #ifdef GOOD_GSL const gsl_interp2d_type* type = gsl_interp2d_bilinear; splines_2d_.clear(); for ( size_t i = 0; i < N; ++i ) { values_[i].reset( new double[coords_.at( 0 ).size() * coords_.at( 1 ).size()] ); splines_2d_.emplace_back( gsl_spline2d_alloc( type, coords_.at( 0 ).size(), coords_.at( 1 ).size() ), gsl_spline2d_free ); } // second loop over all points to populate the grid for ( const auto& val : values_raw_ ) { double val_x = val.first.at( 0 ), val_y = val.first.at( 1 ); // retrieve the index of the bin in the set const unsigned short id_x = std::distance( coords_.at( 0 ).begin(), std::lower_bound( coords_.at( 0 ).begin(), coords_.at( 0 ).end(), val_x ) ); const unsigned short id_y = std::distance( coords_.at( 1 ).begin(), std::lower_bound( coords_.at( 1 ).begin(), coords_.at( 1 ).end(), val_y ) ); for ( unsigned short i = 0; i < splines_2d_.size(); ++i ) gsl_spline2d_set( splines_2d_.at( i ).get(), values_[i].get(), id_x, id_y, val.second[i] ); } // initialise splines objects const coord_t& x_vec = coords_.at( 0 ), &y_vec = coords_.at( 1 ); for ( unsigned short i = 0; i < splines_2d_.size(); ++i ) gsl_spline2d_init( splines_2d_.at( i ).get(), &x_vec[0], &y_vec[0], values_[i].get(), x_vec.size(), y_vec.size() ); #else CG_WARNING( "GridHandler" ) << "GSL version ≥ 2.1 is required for spline bilinear interpolation.\n\t" << "Version " << GSL_VERSION << " is installed on this system!\n\t" << "Will use a simple bilinear approximation instead."; #endif } break; } } + std::array<std::pair<double,double>,D> boundaries() const { + std::array<std::pair<double,double>,D> out; + unsigned short i = 0; + for ( const auto& c : coords_ ) { + const auto& min = std::min_element( c.begin(), c.end() ), max = std::max_element( c.begin(), c.end() ); + out[i++] = { + ( min != c.end() ) ? *min : std::numeric_limits<double>::infinity(), + ( max != c.end() ) ? *max : std::numeric_limits<double>::infinity() }; + } + return out; + } protected: GridType grid_type_; /// List of coordinates and associated value(s) in the grid std::map<coord_t,values_t> values_raw_; std::vector<std::unique_ptr<gsl_interp_accel,void(*)( gsl_interp_accel* )> > accel_; std::vector<std::unique_ptr<gsl_spline,void(*)( gsl_spline* )> > splines_1d_; #ifdef GOOD_GSL std::vector<std::unique_ptr<gsl_spline2d,void(*)( gsl_spline2d* )> > splines_2d_; #endif std::array<coord_t,D> coords_; std::array<std::unique_ptr<double[]>,N> values_; private: void findIndices( const coord_t& coord, coord_t& min, coord_t& max ) const { min.reserve( D ); max.reserve( D ); for ( size_t i = 0; i < D; ++i ) { const auto& c = coords_.at( i ); if ( coord.at( i ) < c.front() ) min[i] = max[i] = c.front(); else if ( coord.at( i ) > c.back() ) min[i] = max[i] = c.back(); else { auto it_coord = std::lower_bound( c.begin(), c.end(), coord.at( i ) ); min[i] = *it_coord; max[i] = ( it_coord != c.end() ) ? *( it_coord++ ) : *it_coord; } } } struct gridpoint_t : values_t { gridpoint_t() : values_t() {} gridpoint_t( const values_t& arr ) : values_t( arr ) {} gridpoint_t operator*( double c ) const { gridpoint_t out = *this; for ( auto& a : out ) a *= c; return out; } gridpoint_t operator+( const gridpoint_t& rhs ) const { gridpoint_t out = *this; for ( size_t i = 0; i < out.size(); ++i ) out[i] += rhs[i]; return out; } }; }; } #endif diff --git a/CepGen/IO/HepMCHandler.cpp b/CepGen/IO/HepMCHandler.cpp index ad0a216..e8b1948 100644 --- a/CepGen/IO/HepMCHandler.cpp +++ b/CepGen/IO/HepMCHandler.cpp @@ -1,136 +1,134 @@ #include "CepGen/IO/HepMCHandler.h" #include "CepGen/Parameters.h" #include "CepGen/Core/Exception.h" #include "CepGen/Event/Event.h" #include "CepGen/Physics/Constants.h" #ifdef LIBHEPMC # include "HepMC/GenVertex.h" # include "HepMC/GenParticle.h" #endif namespace CepGen { namespace OutputHandler { HepMCHandler::HepMCHandler( const char* filename, const ExportHandler::OutputType& type ) : ExportHandler( type ) #ifdef LIBHEPMC # ifdef HEPMC_VERSION3 , output_( new HepMC::WriterAscii( filename ) ), # else , output_( new HepMC::IO_GenEvent( filename ) ), # endif event_( new HepMC::GenEvent() ) #endif {} void HepMCHandler::operator<<( const Event& evt ) { fillEvent( evt ); #ifdef LIBHEPMC # ifdef HEPMC_VERSION3 output_->write_event( *event_ ); # else output_->write_event( event_.get() ); # endif #endif } void HepMCHandler::setCrossSection( double xsect, double xsect_err ) { #ifdef LIBHEPMC # ifdef HEPMC_VERSION3 xs_->set_cross_section( xsect, xsect_err ); event_->add_attribute( "AlphaQCD", HepMC::make_shared<HepMC::DoubleAttribute>( Constants::alphaQCD ) ); event_->add_attribute( "AlphaEM", HepMC::make_shared<HepMC::DoubleAttribute>( Constants::alphaEM ) ); # else xs_.set_cross_section( xsect, xsect_err ); event_->set_alphaQCD( Constants::alphaQCD ); event_->set_alphaQED( Constants::alphaEM ); # endif #endif } void HepMCHandler::fillEvent( const Event& evt ) { #ifdef LIBHEPMC event_->clear(); // general information event_->set_cross_section( xs_ ); event_->set_event_number( event_num_ ); event_->weights().push_back( 1. ); // unweighted events // filling the particles content const HepMC::FourVector origin( 0., 0., 0., 0. ); Particles part_vec = evt.particles(); int cm_id = 0, idx = 1; # ifdef HEPMC_VERSION3 HepMC::GenVertexPtr v1 = HepMC::make_shared<HepMC::GenVertex>( origin ), v2 = HepMC::make_shared<HepMC::GenVertex>( origin ), vcm = HepMC::make_shared<HepMC::GenVertex>( origin ); # else HepMC::GenVertex* v1 = new HepMC::GenVertex( origin ), *v2 = new HepMC::GenVertex( origin ), *vcm = new HepMC::GenVertex( origin ); # endif for ( unsigned int i = 0; i < part_vec.size(); ++i ) { const Particle part_orig = part_vec.at( i ); HepMC::FourVector pmom( part_orig.momentum().px(), part_orig.momentum().py(), part_orig.momentum().pz(), part_orig.energy() ); # ifdef HEPMC_VERSION3 HepMC::GenParticlePtr part = HepMC::make_shared<HepMC::GenParticle>( pmom, part_orig.integerPdgId(), (int)part_orig.status() ); # else HepMC::GenParticle* part = new HepMC::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::Parton3: { 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.size() == 0 ) continue; if ( *moth.begin() == cm_id ) vcm->add_particle_out( part ); - else { - std::cout << "other particle!!" << std::endl; - continue; - //FIXME secondary products... to be implemented! - } + 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 HEPMC_VERSION3 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 #endif event_num_++; } } } diff --git a/CepGen/IO/LHEFHandler.cpp b/CepGen/IO/LHEFHandler.cpp index e87cc2e..7429b69 100644 --- a/CepGen/IO/LHEFHandler.cpp +++ b/CepGen/IO/LHEFHandler.cpp @@ -1,252 +1,252 @@ #include "CepGen/IO/LHEFHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Event/Event.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Parameters.h" #include "CepGen/Version.h" namespace CepGen { namespace OutputHandler { LHEFHandler::LHEFHandler( const char* filename ) : ExportHandler( ExportHandler::LHE ) #if defined ( HEPMC_LHEF ) , lhe_output_( new LHEF::Writer( filename ) ) #elif defined ( PYTHIA_LHEF ) , pythia_( new Pythia8::Pythia ), lhaevt_( new LHAevent ) #endif { #if defined ( PYTHIA_LHEF ) lhaevt_->openLHEF( filename ); #endif } LHEFHandler::~LHEFHandler() { #if defined ( PYTHIA_LHEF ) if ( lhaevt_ ) lhaevt_->closeLHEF( false ); // we do not want to rewrite the init block #endif } void LHEFHandler::initialise( const Parameters& params ) { std::ostringstream oss_init; oss_init << "<!--\n" << " ***** Sample generated with CepGen v" << version() << " *****\n" << " * process: " << params.processName() << " (" << params.kinematics.mode << ")\n"; if ( params.kinematics.mode != KinematicsMode::ElasticElastic ) { oss_init << " * structure functions: " << params.kinematics.structure_functions->type << "\n"; if ( !params.hadroniserName().empty() ) oss_init << " * hadroniser: " << params.hadroniserName() << "\n"; } oss_init << " *--- incoming state\n"; if ( params.kinematics.cuts.initial.q2.valid() ) oss_init << " * Q2 range (GeV2): " << params.kinematics.cuts.initial.q2.min() << ", " << params.kinematics.cuts.initial.q2.max() << "\n"; if ( params.kinematics.mode != KinematicsMode::ElasticElastic && params.kinematics.cuts.remnants.mass_single.valid() ) oss_init << " * remnants mass range (GeV/c2): " << params.kinematics.cuts.remnants.mass_single.min() << ", " << params.kinematics.cuts.remnants.mass_single.max() << "\n"; oss_init << " *--- central system\n"; if ( params.kinematics.cuts.central.pt_single.valid() ) oss_init << " * single particle pt (GeV/c): " << params.kinematics.cuts.central.pt_single.min() << ", " << params.kinematics.cuts.central.pt_single.max() << "\n"; if ( params.kinematics.cuts.central.energy_single.valid() ) oss_init << " * single particle energy (GeV): " << params.kinematics.cuts.central.energy_single.min() << ", " << params.kinematics.cuts.central.energy_single.max() << "\n"; if ( params.kinematics.cuts.central.eta_single.valid() ) oss_init << " * single particle eta: " << params.kinematics.cuts.central.eta_single.min() << ", " << params.kinematics.cuts.central.eta_single.max() << "\n"; if ( params.kinematics.cuts.central.pt_sum.valid() ) oss_init << " * total pt (GeV/c): " << params.kinematics.cuts.central.mass_sum.min() << ", " << params.kinematics.cuts.central.mass_sum.max() << "\n"; if ( params.kinematics.cuts.central.mass_sum.valid() ) oss_init << " * total invariant mass (GeV/c2): " << params.kinematics.cuts.central.mass_sum.min() << ", " << params.kinematics.cuts.central.mass_sum.max() << "\n"; oss_init << " **************************************************\n" << "-->"; #if defined ( HEPMC_LHEF ) lhe_output_->headerBlock() << oss_init.str(); //params.dump( lhe_output_->initComments(), false ); 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.integrator.result; run.XERRUP[0] = params.integrator.err_result; run.XMAXUP[0] = 1.; run.LPRUP[0] = 1; lhe_output_->heprup = run; lhe_output_->init(); #elif defined ( PYTHIA_LHEF ) oss_init << std::endl; // LHEF is usually not beautifully parsed as a standard XML... lhaevt_->addComments( oss_init.str() ); lhaevt_->initialise( params ); pythia_->settings.mode( "Beams:frameType", 5 ); 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_->setLHAupPtr( lhaevt_.get() ); pythia_->init(); lhaevt_->initLHEF(); #endif } void LHEFHandler::operator<<( const Event& ev ) { #if defined ( HEPMC_LHEF ) LHEF::HEPEUP out; out.heprup = &lhe_output_->heprup; out.XWGTUP = 1.; out.XPDWUP = std::pair<double,double>( 0., 0. ); out.SCALUP = 0.; out.AQEDUP = Constants::alphaEM; out.AQCDUP = Constants::alphaQCD; out.NUP = ev.numParticles(); out.resize(); for ( unsigned short ip = 0; ip < ev.numParticles(); ++ip ) { - const Particle part = ev.getConstById( ip ); + const Particle part = ev.at( ip ); out.IDUP[ip] = part.integerPdgId(); // PDG id out.ISTUP[ip] = (short)part.status(); // status code out.MOTHUP[ip] = std::pair<int,int>( ( part.mothers().size() > 0 ) ? *part.mothers().begin()+1 : 0, ( part.mothers().size() > 1 ) ? *part.mothers().rbegin()+1 : 0 ); // mothers out.ICOLUP[ip] = std::pair<int,int>( 0, 0 ); out.PUP[ip] = std::vector<double>( { { part.momentum().px(), part.momentum().py(), part.momentum().pz(), part.energy(), part.mass() } } ); // momentum out.VTIMUP[ip] = 0.; // invariant lifetime out.SPINUP[ip] = 0.; } lhe_output_->eventComments() << "haha"; lhe_output_->hepeup = out; lhe_output_->writeEvent(); #elif defined ( PYTHIA_LHEF ) lhaevt_->feedEvent( 0, ev ); pythia_->next(); lhaevt_->eventLHEF(); #endif } void LHEFHandler::setCrossSection( double xsect, double xsect_err ) { #if defined ( PYTHIA_LHEF ) lhaevt_->setCrossSection( 0, xsect, xsect_err ); #endif } //--------------------------------------------------------------------------------------------- // Define LHA event record if one uses Pythia to store the LHE //--------------------------------------------------------------------------------------------- #if defined ( PYTHIA_LHEF ) LHEFHandler::LHAevent::LHAevent() : LHAup( 3 ) {} void LHEFHandler::LHAevent::initialise( const Parameters& params ) { 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.integrator.result, params.integrator.err_result, 100. ); } void LHEFHandler::LHAevent::addComments( const std::string& comments ) { osLHEF << comments; } void LHEFHandler::LHAevent::setCrossSection( unsigned short proc_id, double xsect, double xsect_err ) { setXSec( proc_id, xsect ); setXErr( proc_id, xsect_err ); } void LHEFHandler::LHAevent::feedEvent( unsigned short proc_id, const Event& ev, bool full_event ) { const double scale = ev.getOneByRole( Particle::Intermediate ).mass(); setProcess( proc_id, 1., scale, Constants::alphaEM, Constants::alphaQCD ); const Particle& ip1 = ev.getOneByRole( Particle::IncomingBeam1 ), &ip2 = ev.getOneByRole( Particle::IncomingBeam2 ); const Particles& op1 = ev.getByRole( Particle::OutgoingBeam1 ), &op2 = ev.getByRole( Particle::OutgoingBeam2 ); const double q2_1 = -( ip1.momentum()-op1[0].momentum() ).mass2(), q2_2 = -( ip2.momentum()-op2[0].momentum() ).mass2(); const double x1 = q2_1/( q2_1+op1[0].mass2()-ip1.mass2() ), x2 = q2_2/( q2_2+op2[0].mass2()-ip2.mass2() ); setIdX( ip1.integerPdgId(), ip2.integerPdgId(), x1, x2 ); short parton1_pdgid = 0, parton2_pdgid = 0; for ( const auto& part : ev.particles() ) { short pdg_id = part.integerPdgId(), status = 0, moth1 = 0, moth2 = 0; switch ( part.role() ) { case Particle::Parton1: case Particle::Parton2: { if ( part.role() == Particle::Parton1 ) parton1_pdgid = part.integerPdgId(); if ( part.role() == Particle::Parton2 ) parton2_pdgid = part.integerPdgId(); if ( !full_event ) continue; status = -2; // conserving xbj/Q2 } break; case Particle::Intermediate: { if ( !full_event ) continue; status = 2; if ( pdg_id == 0 ) - pdg_id = ev.getConstById( *part.mothers().begin() ).integerPdgId(); + pdg_id = ev.at( *part.mothers().begin() ).integerPdgId(); } break; case Particle::IncomingBeam1: case Particle::IncomingBeam2: { if ( !full_event ) continue; status = -9; } break; case Particle::OutgoingBeam1: case Particle::OutgoingBeam2: case Particle::CentralSystem: { status = (short)part.status(); if ( status != 1 ) continue; } break; default: break; } if ( full_event ) { const auto& mothers = part.mothers(); if ( mothers.size() > 0 ) moth1 = *mothers.begin()+1; if ( mothers.size() > 1 ) moth2 = *mothers.rbegin()+1; } const Particle::Momentum& mom = part.momentum(); addParticle( pdg_id, status, moth1, moth2, 0, 0, mom.px(), mom.py(), mom.pz(), mom.energy(), mom.mass(), 0. ,0., 0. ); } setPdf( parton1_pdgid, parton2_pdgid, x1, x2, scale, 0., 0., true ); } #endif } } diff --git a/CepGen/Parameters.h b/CepGen/Parameters.h index fb21f43..2b76c79 100644 --- a/CepGen/Parameters.h +++ b/CepGen/Parameters.h @@ -1,148 +1,146 @@ #ifndef CepGen_Parameters_h #define CepGen_Parameters_h #include "CepGen/Core/Integrator.h" #include "CepGen/Physics/Kinematics.h" #include <memory> #include <gsl/gsl_monte_vegas.h> #include <gsl/gsl_monte_miser.h> namespace CepGen { class Event; class TamingFunctionsCollection; class ParametersList; namespace Process { class GenericProcess; } namespace Hadroniser { class GenericHadroniser; } /// 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! /// 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& os, const Parameters* ); friend std::ostream& operator<<( std::ostream& os, const Parameters& ); std::shared_ptr<ParametersList> general; //----- process to compute /// Process for which the cross-section will be computed and the events will be generated Process::GenericProcess* process(); /// Name of the process considered std::string processName() const; /// Set the process to study void setProcess( Process::GenericProcess* proc ); void cloneProcess( const Process::GenericProcess* proc ); //----- events kinematics /// Events kinematics for phase space definition Kinematics kinematics; //----- VEGAS /// Collection of integrator parameters struct Integration { Integration(); Integration( const Integration& ); ~Integration(); Integrator::Type type; /// Number of function calls to be computed for each point unsigned int ncvg; // ?? /// Random number generator seed long rng_seed; /// Random number generator engine gsl_rng_type* rng_engine; gsl_monte_vegas_params vegas; double vegas_chisq_cut; gsl_monte_miser_params miser; double result, err_result; }; /// Integrator parameters Integration integrator; //----- events generation /// Collection of events generation parameters struct Generation { Generation(); /// Are we generating events ? (true) or are we only computing the cross-section ? (false) bool enabled; /// Maximal number of events to generate in this run unsigned int maxgen; /// Do we want the events to be symmetrised with respect to the \f$z\f$-axis ? bool symmetrise; /// Is the integrand to be smoothed for events generation? bool treat; /// Number of events already generated in this run unsigned int ngen; /// Frequency at which the events are displayed to the end-user unsigned int gen_print_every; /// Number of threads to perform the integration unsigned int num_threads; /// Number of points to "shoot" in each integration bin by the algorithm unsigned int num_points; }; /// Events generation parameters Generation 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_; } //----- hadronisation algorithm /// Hadronisation algorithm to use for the proton(s) fragmentation Hadroniser::GenericHadroniser* hadroniser(); /// Name of the hadroniser (if applicable) std::string hadroniserName() const; /// Set the hadronisation algorithm void setHadroniser( Hadroniser::GenericHadroniser* hadr ); - /// Maximal number of trials for the hadronisation of the proton(s) remnants - unsigned int hadroniser_max_trials; //----- taming functions /// Functionals to be used to account for rescattering corrections (implemented within the process) std::shared_ptr<TamingFunctionsCollection> taming_functions; //----- run statistics /// Reset the total generation time and the number of events generated for this run void clearRunStatistics(); /// 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::GenericProcess> process_; std::unique_ptr<Hadroniser::GenericHadroniser> hadroniser_; bool store_; /// Total generation time (in seconds) double total_gen_time_; /// Number of events already generated unsigned int num_gen_events_; }; } #endif diff --git a/CepGen/Physics/BreitWigner.h b/CepGen/Physics/BreitWigner.h index 65c3276..f3f0302 100644 --- a/CepGen/Physics/BreitWigner.h +++ b/CepGen/Physics/BreitWigner.h @@ -1,37 +1,44 @@ #ifndef CepGen_Physics_BreitWigner_h #define CepGen_Physics_BreitWigner_h #include <math.h> namespace CepGen { + /// A Breit-Wigner/Cauchy distribution generator class BreitWigner { public: BreitWigner( double mean = 0., double gamma = 0., double emin = -1., double emax = -1. ) : mean_( mean ), gamma_( gamma ), emin_( emin ), emax_( emax ) {} + /// Copy constructor BreitWigner( const BreitWigner& oth ) : mean_( oth.mean_ ), gamma_( oth.gamma_ ), emin_( oth.emin_ ), emax_( oth.emax_ ) {} + /// Minimal energy to consider double min() const { return emin_; } + /// Maximal energy to consider double max() const { return emax_; } + /// Shoot a value according to parameterisation inline double operator()( double x ) const { const double val = mean_+0.5*gamma_*tan( ( 2.*x-1. )*M_PI_2 ); - if ( ( emin_ >= 0. && val < emin_ ) || ( emax_ >= 0. && val > emax_ ) ) + if ( emin_ >= 0. && val < emin_ ) + return -1.; + if ( emax_ >= 0. && val > emax_ ) return -1.; return val; } private: /// Mean of distribution double mean_; /// Width of distribution double gamma_; /// Minimal value double emin_; /// Maximal value double emax_; }; } #endif diff --git a/CepGen/Physics/Constants.h b/CepGen/Physics/Constants.h index 3828b8a..0c971c6 100644 --- a/CepGen/Physics/Constants.h +++ b/CepGen/Physics/Constants.h @@ -1,22 +1,22 @@ #ifndef CepGen_Physics_Constants_h #define CepGen_Physics_Constants_h #include <math.h> namespace CepGen { /// List of physical constants useful that may be used for the matrix element definition namespace Constants { - /// Electromagnetic coupling constant \f$\alpha_\textrm{em}=\frac{e^2}{4\pi\epsilon_0\hbar c}\f$ + /// Electromagnetic coupling constant \f$\alpha_{\rm em}=\frac{e^2}{4\pi\epsilon_0\hbar c}\f$ constexpr double alphaEM = 1./137.035; - /// Strong coupling constant \f$\alpha_\textrm{QCD}\f$ + /// Strong coupling constant \f$\alpha_{\rm QCD}\f$ constexpr double alphaQCD = 0.1184; // at the Z pole - /// Conversion factor between GeV^2 and barn + /// Conversion factor between GeV\f${}^2\f$ and barn constexpr double GeV2toBarn = 0.389351824e9; // 1.e4*(197.3271**2); constexpr double sconstb = 2.1868465e10; // 1.1868465e10; } } #endif diff --git a/CepGen/Physics/Cuts.h b/CepGen/Physics/Cuts.h index afd3147..6c8e1e7 100644 --- a/CepGen/Physics/Cuts.h +++ b/CepGen/Physics/Cuts.h @@ -1,31 +1,32 @@ #ifndef CepGen_Physics_Cuts_h #define CepGen_Physics_Cuts_h #include "CepGen/Physics/Limits.h" #include <vector> namespace CepGen { /// Constraints to be applied on the events kinematics struct Cuts { Limits pt_single; ///< single particle transverse momentum Limits eta_single; ///< single particle pseudo-rapidity Limits rapidity_single; ///< single particle rapidity Limits energy_single; ///< single particle energy Limits mass_single; ///< single particle mass Limits pt_sum; ///< multiparticle system transverse momentum Limits eta_sum; ///< multiparticle system pseudo-rapidity Limits energy_sum; ///< multiparticle system energy Limits mass_sum; ///< multiparticle system invariant mass Limits pt_diff; ///< transverse momentum balance between the central particles Limits phi_pt_diff; ///< azimuthal angles difference between the central particles Limits rapidity_diff; ///< rapidity balance between the central particles Limits q2; ///< parton virtuality Limits qt; ///< parton transverse virtuality Limits phi_qt; ///< parton azimuthal angle difference + /// A collection of name -> limits std::vector<std::pair<std::string,Limits> > list() const; }; } #endif diff --git a/CepGen/Physics/GluonGrid.h b/CepGen/Physics/GluonGrid.h index 5580ae5..588b140 100644 --- a/CepGen/Physics/GluonGrid.h +++ b/CepGen/Physics/GluonGrid.h @@ -1,40 +1,42 @@ #ifndef CepGen_Physics_GluonGrid_h #define CepGen_Physics_GluonGrid_h #include "CepGen/IO/GridHandler.h" #define DEFAULT_KMR_GRID_PATH "gluon_mmht2014nlo_Watt.dat" /// Kimber-Martin-Ryskin unintegrated gluon densities namespace kmr { /// A KMR unintegrated gluon densities grid interpolator class GluonGrid : private CepGen::GridHandler<3,1> { public: struct Parameterisation { Parameterisation() : grid_path( DEFAULT_KMR_GRID_PATH ) {} + /// Location of the grid to be interpolated std::string grid_path; }; public: /// Retrieve the grid interpolator (singleton) static GluonGrid& get( const char* path = DEFAULT_KMR_GRID_PATH ); /// Compute the gluon flux double operator()( double x, double kt2, double mu2 ) const; + /// Grid parameterisation object Parameterisation params; public: GluonGrid( const GluonGrid& ) = delete; void operator=( const GridHandler& ) = delete; private: explicit GluonGrid( const Parameterisation& = Parameterisation() ); }; } #undef DEFAULT_KMR_GRID_PATH #endif diff --git a/CepGen/Physics/KTFlux.h b/CepGen/Physics/KTFlux.h index db8df10..5e16ba5 100644 --- a/CepGen/Physics/KTFlux.h +++ b/CepGen/Physics/KTFlux.h @@ -1,35 +1,45 @@ #ifndef CepGen_Physics_KTFlux_h #define CepGen_Physics_KTFlux_h #include "CepGen/Physics/PDG.h" #include <ostream> namespace CepGen { class StructureFunctions; class HeavyIon; + /// Collection of fundamental constants for kT fluxes definition struct KTFluxParameters { - static const double kMinKTFlux, kMP, kMP2; + static const double kMinKTFlux; ///< Minimal value taken for a kT-factorised flux + static const double kMP; ///< Proton mass, un GeV/c\f${}^2\f$ + static const double kMP2; ///< Squared proton mass }; /// Type of incoming partons fluxes enum class KTFlux { invalid = -1, P_Photon_Elastic = 0, P_Photon_Inelastic = 1, P_Photon_Inelastic_Budnev = 11, P_Gluon_KMR = 20, HI_Photon_Elastic = 100 }; + /// Human version of the flux name std::ostream& operator<<( std::ostream&, const KTFlux& ); - /// Get the flux at a given parton x/kT + /// \brief Compute the flux for a given parton x/kT + /// \param[in] type Flux modelling /// \param[in] x Parton momentum fraction /// \param[in] kt2 Transverse 2-momentum \f$\mathbf{q}_{\mathrm{T}}^2\f$ of the incoming parton /// \param[in] sf Structure functions evaluator /// \param[in] mx Outgoing diffractive proton mass double ktFlux( const KTFlux& type, double x, double kt2, StructureFunctions& sf, double mx = KTFluxParameters::kMP ); + /// \brief Compute the flux (from heavy ion) for a given parton x/kT + /// \param[in] type Flux modelling + /// \param[in] x Parton momentum fraction + /// \param[in] kt2 Transverse 2-momentum \f$\mathbf{q}_{\mathrm{T}}^2\f$ of the incoming parton + /// \param[in] hi Heavy ion properties double ktFlux( const KTFlux& type, double x, double kt2, const HeavyIon& hi ); } #endif diff --git a/CepGen/Physics/Kinematics.h b/CepGen/Physics/Kinematics.h index bafb8b8..1acddef 100644 --- a/CepGen/Physics/Kinematics.h +++ b/CepGen/Physics/Kinematics.h @@ -1,79 +1,80 @@ #ifndef CepGen_Physics_Kinematics_h #define CepGen_Physics_Kinematics_h #include "CepGen/Core/Hasher.h" #include "CepGen/Physics/Cuts.h" #include "CepGen/Physics/HeavyIon.h" #include <ostream> #include <vector> #include <unordered_map> #include <memory> namespace CepGen { enum class PDG; enum class KTFlux; class StructureFunctions; /// Type of kinematics to consider for the process enum class KinematicsMode { invalid = -1, ElectronProton = 0, ///< electron-proton elastic case ElasticElastic = 1, ///< proton-proton elastic case ElasticInelastic = 2, ///< proton-proton single-dissociative (or inelastic-elastic) case InelasticElastic = 3, ///< proton-proton single-dissociative (or elastic-inelastic) case InelasticInelastic = 4, ///< proton-proton double-dissociative case ProtonElectron, ElectronElectron }; /// Human-readable format of a process mode (elastic/dissociative parts) std::ostream& operator<<( std::ostream&, const KinematicsMode& ); /// List of kinematic constraints to apply on the process phase space. class Kinematics { public: Kinematics(); ~Kinematics(); + /// Incoming beams characteristics struct Beam { - /// Incoming particle's momentum (in \f$\text{GeV}/c\f$) - double pz; - PDG pdg; - KTFlux kt_flux; + double pz; ///< Incoming particle momentum, in GeV/c + PDG pdg; ///< PDG identifier for the beam + KTFlux kt_flux; ///< Type of kT-factorised flux to be considered (if any) }; friend std::ostream& operator<<( std::ostream&, const Beam& ); /// Beam/primary particle's kinematics std::pair<Beam,Beam> incoming_beams; /// Set the incoming particles' momenta (if the collision is symmetric) void setSqrtS( double sqrts ); /// Process centre of mass energy double sqrtS() const; /// Minimum list of central particles required std::vector<PDG> minimum_final_state; /// Type of kinematics to consider for the phase space KinematicsMode mode; /// Type of structure functions to consider std::shared_ptr<StructureFunctions> structure_functions; + /// A collection of cuts to apply on the physical phase space struct CutsList { CutsList(); /// Cuts on the initial particles kinematics Cuts initial; /// Cuts on the central system produced Cuts central; std::unordered_map<PDG,Cuts,EnumHash<PDG> > central_particles; /// Cuts on the beam remnants system Cuts remnants; }; CutsList cuts; std::string kmr_grid_path; }; } #endif diff --git a/CepGen/Physics/ParticleProperties.h b/CepGen/Physics/ParticleProperties.h index e3d747a..dff3d94 100644 --- a/CepGen/Physics/ParticleProperties.h +++ b/CepGen/Physics/ParticleProperties.h @@ -1,27 +1,33 @@ #ifndef CepGen_Physics_ParticleProperties_h #define CepGen_Physics_ParticleProperties_h namespace CepGen { enum class PDG; namespace ParticleProperties { - /// Mass (in GeV) of a particle - /// \param pdg_id PDG identifier - /// \return Mass of the particle in \f$\textrm{GeV}/c^2\f$ + /** \brief Mass of a particle, in GeV/c\f${}^2\f$ + * \param pdg_id PDG identifier + */ double mass( const PDG& pdg_id ); - /// Electric charge of a particle, in \f$e\f$ - /// \param[in] pdg_id PDG id + /** \brief Electric charge of a particle, in \f$e\f$ + * \param[in] pdg_id PDG id + */ double charge( const PDG& pdg_id ); - /// Electric charge of a particle, in \f$e\f$ - /// \param[in] id integer PDG id + /** \brief Electric charge of a particle, in \f$e\f$ + * \param[in] id integer PDG id + */ double charge( int id ); + /** \brief Colour factor for a given particle + * \param[in] id integer PDG id + */ unsigned short colours( const PDG& pdg_id ); - /// Total decay width of an unstable particle, in GeV - /// \param[in] pdg_id PDG (PDG ID) + /** \brief Total decay width of an unstable particle, in GeV + * \param[in] pdg_id PDG (PDG ID) + */ double width( const PDG& pdg_id ); } } #endif diff --git a/CepGen/Processes/CMakeLists.txt b/CepGen/Processes/CMakeLists.txt index 8050ba9..7489f0c 100644 --- a/CepGen/Processes/CMakeLists.txt +++ b/CepGen/Processes/CMakeLists.txt @@ -1,7 +1,14 @@ file(GLOB sources *.cpp Fortran/*.f) include_directories(${PROJECT_SOURCE_DIR}) +include_directories(Fortran) + +set(F77_PROC_PATH ${PROJECT_SOURCE_DIR}/External/Processes) +file(GLOB oth_proc_sources ${F77_PROC_PATH}/*.f ${F77_PROC_PATH}/CepGenWrapper.cpp) +if(oth_proc_sources) + list(APPEND sources ${oth_proc_sources}) +endif() add_library(CepGenProcesses SHARED ${sources}) install(TARGETS CepGenProcesses DESTINATION lib) diff --git a/CepGen/Processes/Fortran/cepgen_blocks.inc b/CepGen/Processes/Fortran/cepgen_blocks.inc index ff15b10..3df9e0e 100644 --- a/CepGen/Processes/Fortran/cepgen_blocks.inc +++ b/CepGen/Processes/Fortran/cepgen_blocks.inc @@ -1,61 +1,61 @@ + !> \file cepgen_blocks.inc c ================================================================ c F77 process-to-CepGen helper c > this header file defines a set of common blocks useful for c > the interfacing of any kt-factorised matrix element computation c > to a mother CepGen instance c ================================================================ c ================================================================= -c collection of fundamental physics constants -c ================================================================= + !> collection of fundamental physics constants common/constants/am_p,units,pi,alpha_em double precision am_p,units,pi,alpha_em c ================================================================= c information on the full process c inp1 = proton energy in lab frame c inp2 = nucleus energy **per nucleon** in LAB frame c Collision is along z-axis c ================================================================= common/params/icontri,iflux1,iflux2,imethod,sfmod,pdg_l, & a_nuc1,z_nuc1,a_nuc2,z_nuc2, & inp1,inp2 integer icontri,iflux1,iflux2,imethod,sfmod,pdg_l, & a_nuc1,z_nuc1,a_nuc2,z_nuc2 double precision inp1,inp2 c ================================================================= c kt-factorisation kinematics c ================================================================= common/ktkin/q1t,q2t,phiq1t,phiq2t,y1,y2,ptdiff,phiptdiff, & am_x,am_y double precision q1t,q2t,phiq1t,phiq2t,y1,y2,ptdiff,phiptdiff, & am_x,am_y c ================================================================= c phase space cuts c ================================================================= common/kincuts/ipt,iene,ieta,iinvm,iptsum,idely, & pt_min,pt_max,ene_min,ene_max,eta_min,eta_max, & invm_min,invm_max,ptsum_min,ptsum_max, & dely_min,dely_max integer ipt,iene,ieta,iinvm,iptsum,idely double precision pt_min,pt_max,ene_min,ene_max,eta_min,eta_max, & invm_min,invm_max,ptsum_min,ptsum_max, & dely_min,dely_max c ================================================================= c generated event kinematics c ================================================================= common/evtkin/px,py,nout,idum,ipdg,pc integer nout,idum,ipdg(4) double precision px(4),py(4),pc(4,4) c ================================================================= c helpers for the evaluation of unintegrated parton fluxes c ================================================================= external CepGen_kT_flux,CepGen_kT_flux_HI double precision CepGen_kT_flux,CepGen_kT_flux_HI external CepGen_particle_charge,CepGen_particle_mass double precision CepGen_particle_charge,CepGen_particle_mass diff --git a/CepGen/Processes/Fortran/cepgen_print.f b/CepGen/Processes/Fortran/cepgen_print.f index 38954f6..6c11061 100644 --- a/CepGen/Processes/Fortran/cepgen_print.f +++ b/CepGen/Processes/Fortran/cepgen_print.f @@ -1,40 +1,42 @@ + !> \file cepgen_print.f subroutine cepgen_print + !> Print useful run information in standard stream implicit none include 'cepgen_blocks.inc' logical params_shown data params_shown/.false./ save params_shown if(params_shown) return print *,'========================================================' print *,'Parameter value(s)' print *,'--------------------------------------------------------' print 101,'Process mode:',icontri print 101,'Computation method:',imethod print 101,'Structure functions:',sfmod print 101,'Central system PDG:',pdg_l print 103,'Beams momenta:',inp1,inp2 print 102,'Fluxes modes:',iflux1,iflux2 print 104,'Beams (A,Z):',a_nuc1,z_nuc1,a_nuc2,z_nuc2 print *,'========================================================' print *,'Cut enabled minimum maximum' print *,'--------------------------------------------------------' print 100,'pt(single)',ipt,pt_min,pt_max print 100,'energy(single)',iene,ene_min,ene_max print 100,'eta(single)',ieta,eta_min,eta_max print 100,'m(sum)',iinvm,invm_min,invm_max print 100,'pt(sum)',iptsum,ptsum_min,ptsum_max print 100,'delta(y)',idely,dely_min,dely_max print *,'========================================================' params_shown=.true. 100 format(A26,' ',L2,f12.4,f12.4) 101 format(A33,I12) 102 format(A33,I12,I12) 103 format(A33,f12.2,f12.2) 104 format(A33,' (',I3,',',I3,'), (',I3,',',I3,')') end diff --git a/CepGen/Processes/FortranKTProcess.cpp b/CepGen/Processes/FortranKTProcess.cpp index c5c6f01..8ec897a 100644 --- a/CepGen/Processes/FortranKTProcess.cpp +++ b/CepGen/Processes/FortranKTProcess.cpp @@ -1,187 +1,231 @@ #include "CepGen/Processes/FortranKTProcess.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Event/Event.h" #include "CepGen/Physics/KTFlux.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Physics/PDG.h" extern "C" { + /// General physics constants struct Constants { - double m_p, units, pi, alpha_em; + double m_p; ///< Proton mass + double units; ///< Conversion factor GeV\f${}^2\to\f$ barn + double pi; ///< \f$\pi\f$ + double alpha_em; ///< Electromagnetic coupling constant }; + /// Generic run parameters struct Parameters { - int icontri, iflux1, iflux2, imethod, sfmod, pdg_l, a_nuc1, z_nuc1, a_nuc2, z_nuc2; - double inp1, inp2; + int icontri; ///< Kinematics mode + int iflux1; ///< Type of kT-factorised flux for first incoming parton + int iflux2; ///< Type of kT-factorised flux for second incoming parton + int imethod; ///< Computation method for matrix element + int sfmod; ///< Structure functions modelling + int pdg_l; ///< Central system PDG id + int a_nuc1; ///< First beam mass number + int z_nuc1; ///< First beam atomic number + int a_nuc2; ///< Second beam mass number + int z_nuc2; ///< Second beam atomic number + double inp1; ///< First beam momentum, in GeV/c + double inp2; ///< Second beam momentum, in GeV/c }; + /// Kinematics properties of the kT-factorised process struct KtKinematics { - double q1t, q2t, phiq1t, phiq2t, y1, y2, ptdiff, phiptdiff, m_x, m_y; + double q1t; ///< Transverse momentum of the first incoming parton + double q2t; ///< Transverse momentum of the second incoming parton + double phiq1t; ///< Azimutal angle of the first incoming parton + double phiq2t; ///< Azimutal angle of the second incoming parton + double y1; ///< First incoming parton rapidity + double y2; ///< Second incoming parton rapidity + double ptdiff; ///< Central system pT balance + double phiptdiff; ///< Central system azimutal angle difference + double m_x; ///< Invariant mass for the first diffractive state + double m_y; ///< Invariant mass for the second diffractive state }; + /// Phase space cuts for event kinematics struct KinematicsCuts { - int ipt, iene, ieta, iinvm, iptsum, idely; - double pt_min, pt_max, ene_min, ene_max, eta_min, eta_max; - double invm_min, invm_max, ptsum_min, ptsum_max; - double dely_min, dely_max; + int ipt; ///< Switch for cut on single particle transverse momentum + int iene; ///< Switch for cut on single particle energy + int ieta; ///< Switch for cut on single particle pseudo-rapidity + int iinvm; ///< Switch for cut on central system invariant mass + int iptsum; ///< Switch for cut on central system transverse momentum + int idely; ///< Switch for cut on rapididty difference + double pt_min; ///< Minimal single particle transverse momentum + double pt_max; ///< Maximal single particle transverse momentum + double ene_min; ///< Minimal single particle energy + double ene_max; ///< Maximal single particle energy + double eta_min; ///< Minimal single particle pseudo-rapidity + double eta_max; ///< Maximal single particle pseudo-rapidity + double invm_min; ///< Minimal central system invariant mass + double invm_max; ///< Maximal central system invariant mass + double ptsum_min; ///< Minimal central system transverse momentum + double ptsum_max; ///< Maximal central system transverse momentum + double dely_min; ///< Minimal rapidity difference for central system + double dely_max; ///< Maximal rapidity difference for central system }; + /// Single event kinematics struct EventKinematics { - double px[4], py[4]; - int nout, idum, pdg[4]; - double pc[4][4]; + double px[4]; ///< 4-momentum of first outgoing proton state + double py[4]; ///< 4-momentum of second outgoing proton state + int nout; ///< Number of particles in central system + int idum; ///< Placeholder for blocks alignment + int pdg[4]; ///< PDG ids of all particles in central system + double pc[4][4]; ///< 4-momenta of all particles in central system }; extern Constants constants_; extern Parameters params_; extern KtKinematics ktkin_; extern KinematicsCuts kincuts_; extern EventKinematics evtkin_; } namespace CepGen { namespace Process { FortranKTProcess::FortranKTProcess( const ParametersList& params, const char* name, const char* descr, std::function<void( double& )> func ) : GenericKTProcess( params, name, descr, { { PDG::photon, PDG::photon } }, { PDG::muon, PDG::muon } ), pair_( params.get<int>( "pair", 13 ) ), method_( params.get<int>( "method", 1 ) ), func_( func ) { - constants_.m_p = ParticleProperties::mass( PDG::proton ); + constants_.m_p = GenericProcess::mp_; constants_.units = Constants::GeV2toBarn; constants_.pi = M_PI; constants_.alpha_em = Constants::alphaEM; } void FortranKTProcess::preparePhaseSpace() { mom_ip1_ = event_->getOneByRole( Particle::IncomingBeam1 ).momentum(); mom_ip2_ = event_->getOneByRole( Particle::IncomingBeam2 ).momentum(); registerVariable( y1_, Mapping::linear, cuts_.cuts.central.rapidity_single, { -6., 6. }, "First central particle rapidity" ); registerVariable( y2_, Mapping::linear, cuts_.cuts.central.rapidity_single, { -6., 6. }, "Second central particle rapidity" ); registerVariable( pt_diff_, Mapping::linear, cuts_.cuts.central.pt_diff, { 0., 50. }, "Transverse momentum difference between central particles" ); registerVariable( phi_pt_diff_, Mapping::linear, cuts_.cuts.central.phi_pt_diff, { 0., 2.*M_PI }, "Central particles azimuthal angle difference" ); //=========================================================================================== // feed phase space cuts to the common block //=========================================================================================== cuts_.cuts.central.pt_single.save( (bool&)kincuts_.ipt, kincuts_.pt_min, kincuts_.pt_max ); cuts_.cuts.central.energy_single.save( (bool&)kincuts_.iene, kincuts_.ene_min, kincuts_.ene_max ); cuts_.cuts.central.eta_single.save( (bool&)kincuts_.ieta, kincuts_.eta_min, kincuts_.eta_max ); cuts_.cuts.central.mass_sum.save( (bool&)kincuts_.iinvm, kincuts_.invm_min, kincuts_.invm_max ); cuts_.cuts.central.pt_sum.save( (bool&)kincuts_.iptsum, kincuts_.ptsum_min, kincuts_.ptsum_max ); cuts_.cuts.central.rapidity_diff.save( (bool&)kincuts_.idely, kincuts_.dely_min, kincuts_.dely_max ); //=========================================================================================== // feed run parameters to the common block //=========================================================================================== params_.icontri = (int)cuts_.mode; params_.imethod = method_; params_.sfmod = (int)cuts_.structure_functions->type; params_.pdg_l = pair_; //------------------------------------------------------------------------------------------- // incoming beams information //------------------------------------------------------------------------------------------- params_.inp1 = cuts_.incoming_beams.first.pz; params_.inp2 = cuts_.incoming_beams.second.pz; const HeavyIon in1 = (HeavyIon)cuts_.incoming_beams.first.pdg; if ( in1 ) { params_.a_nuc1 = in1.A; params_.z_nuc1 = (unsigned short)in1.Z; if ( params_.z_nuc1 > 1 ) { event_->getOneByRole( Particle::IncomingBeam1 ).setPdgId( (PDG)in1 ); event_->getOneByRole( Particle::OutgoingBeam1 ).setPdgId( (PDG)in1 ); } } else params_.a_nuc1 = params_.z_nuc1 = 1; const HeavyIon in2 = (HeavyIon)cuts_.incoming_beams.second.pdg; if ( in2 ) { params_.a_nuc2 = in2.A; params_.z_nuc2 = (unsigned short)in2.Z; if ( params_.z_nuc2 > 1 ) { event_->getOneByRole( Particle::IncomingBeam2 ).setPdgId( (PDG)in2 ); event_->getOneByRole( Particle::OutgoingBeam2 ).setPdgId( (PDG)in2 ); } } else params_.a_nuc2 = params_.z_nuc2 = 1; //------------------------------------------------------------------------------------------- // intermediate partons information //------------------------------------------------------------------------------------------- params_.iflux1 = (int)cuts_.incoming_beams.first.kt_flux; params_.iflux2 = (int)cuts_.incoming_beams.second.kt_flux; if ( (KTFlux)params_.iflux1 == KTFlux::P_Gluon_KMR ) event_->getOneByRole( Particle::Parton1 ).setPdgId( PDG::gluon ); if ( (KTFlux)params_.iflux2 == KTFlux::P_Gluon_KMR ) event_->getOneByRole( Particle::Parton2 ).setPdgId( PDG::gluon ); } double FortranKTProcess::computeKTFactorisedMatrixElement() { ktkin_.q1t = qt1_; ktkin_.q2t = qt2_; ktkin_.phiq1t = phi_qt1_; ktkin_.phiq2t = phi_qt2_; ktkin_.y1 = y1_; ktkin_.y2 = y2_; ktkin_.ptdiff = pt_diff_; ktkin_.phiptdiff = phi_pt_diff_; ktkin_.m_x = MX_; ktkin_.m_y = MY_; + + //--- compute the event weight double weight = 0.; func_( weight ); return weight; } void FortranKTProcess::fillCentralParticlesKinematics() { //=========================================================================================== // outgoing beam remnants //=========================================================================================== PX_ = Particle::Momentum( evtkin_.px ); PY_ = Particle::Momentum( evtkin_.py ); // express these momenta per nucleon PX_ *= 1./params_.a_nuc1; PY_ *= 1./params_.a_nuc2; -//std::cout << PX_ << PY_ << std::endl; - //=========================================================================================== // intermediate partons //=========================================================================================== const Particle::Momentum mom_par1 = mom_ip1_-PX_, mom_par2 = mom_ip2_-PY_; event_->getOneByRole( Particle::Parton1 ).setMomentum( mom_par1 ); event_->getOneByRole( Particle::Parton2 ).setMomentum( mom_par2 ); event_->getOneByRole( Particle::Intermediate ).setMomentum( mom_par1+mom_par2 ); //=========================================================================================== // central system //=========================================================================================== Particles& oc = event_->getByRole( Particle::CentralSystem ); for ( int i = 0; i < evtkin_.nout; ++i ) { - auto& p = oc[i]; + Particle& p = oc[i]; p.setPdgId( evtkin_.pdg[i] ); p.setStatus( Particle::Status::FinalState ); p.setMomentum( Particle::Momentum( evtkin_.pc[i] ) ); } } } } diff --git a/CepGen/Processes/FortranKTProcess.h b/CepGen/Processes/FortranKTProcess.h index af15df0..7a726c0 100644 --- a/CepGen/Processes/FortranKTProcess.h +++ b/CepGen/Processes/FortranKTProcess.h @@ -1,35 +1,38 @@ #ifndef CepGen_Processes_FortranKTProcess_h #define CepGen_Processes_FortranKTProcess_h #include "GenericKTProcess.h" #include <functional> namespace CepGen { namespace Process { /// Compute the matrix element for a generic \f$k_T\f$-factorised process defined in a Fortran subroutine class FortranKTProcess : public GenericKTProcess { public: FortranKTProcess( const ParametersList& params, const char* name, const char* descr, std::function<void(double&)> func ); ProcessPtr clone() const override { return ProcessPtr( new FortranKTProcess( *this ) ); } private: void preparePhaseSpace() override; double computeKTFactorisedMatrixElement() override; void fillCentralParticlesKinematics() override; - int pair_; - int method_; - /// Subroutine to be called for weight computation - std::function<void(double&)> func_; - double y1_, y2_, pt_diff_, phi_pt_diff_; + int pair_; ///< Outgoing particles type + int method_; ///< Computation method for the process + std::function<void(double&)> func_; ///< Subroutine to be called for weight computation + double y1_; ///< First outgoing particle rapidity + double y2_; ///< Second outgoing particle rapidity + double pt_diff_; ///< Transverse momentum balance between outgoing particles + double phi_pt_diff_; ///< Azimutal angle difference between outgoing particles - Particle::Momentum mom_ip1_, mom_ip2_; + Particle::Momentum mom_ip1_; ///< First incoming beam momentum + Particle::Momentum mom_ip2_; ///< Second incoming beam momentum }; } } #endif diff --git a/CepGen/Processes/FortranProcesses.h b/CepGen/Processes/FortranProcesses.h new file mode 100644 index 0000000..e07e32b --- /dev/null +++ b/CepGen/Processes/FortranProcesses.h @@ -0,0 +1,52 @@ +#ifndef CepGen_Processes_FortranProcesses_h +#define CepGen_Processes_FortranProcesses_h + +#include "CepGen/Processes/FortranKTProcess.h" + +namespace CepGen +{ + namespace Process + { + /// A Fortran process handler + struct FortranProcess + { + const char* name; ///< CepGen-readable process name + void ( *method )( double& ); ///< Pointer to the weight computation functional + const char* description; ///< Human-readable process description + }; + /// Fortran processes collector + class FortranProcessesHandler + { + public: + /// Static collector retrieval method + static FortranProcessesHandler& get() { + static FortranProcessesHandler fph; + return fph; + } + /// Register a Fortran process into the collector + void add( const FortranProcess& proc ) { + processes_.emplace_back( proc ); + } + /// Get a list of processes handled by this collector + const std::vector<FortranProcess>& list() const { return processes_; } + /// Generic copy-constructor + FortranProcessesHandler( const FortranProcessesHandler& ) = delete; + + private: + explicit FortranProcessesHandler() {} + std::vector<FortranProcess> processes_; + }; + + void generateFortranProcesses(); + } +} +#define DECLARE_FORTRAN_SUBROUTINE( method ) \ + extern "C" { extern void method ## _( double& ); } +#define BEGIN_FORTRAN_PROCESSES_ENUM \ + namespace CepGen { namespace Process { void generateFortranProcesses() { +#define REGISTER_FORTRAN_PROCESS( name, method, description ) \ + CepGen::Process::FortranProcessesHandler::get().add( CepGen::Process::FortranProcess{ name, method ## _, description } ); +#define END_FORTRAN_PROCESSES_ENUM }}} + +#endif + diff --git a/CepGen/Processes/GamGamLL.h b/CepGen/Processes/GamGamLL.h index cdc3528..d7f46f2 100644 --- a/CepGen/Processes/GamGamLL.h +++ b/CepGen/Processes/GamGamLL.h @@ -1,229 +1,221 @@ #ifndef CepGen_Processes_GamGamLL_h #define CepGen_Processes_GamGamLL_h #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Core/ParametersList.h" namespace CepGen { namespace Process { /** * Full class of methods and objects to compute the full analytic matrix element - * \cite Vermaseren1983347 for the \f$\gamma\gamma\to\ell^{+}\ell^{-}\f$ process + * \cite Vermaseren:1982cz for the \f$\gamma\gamma\to\ell^{+}\ell^{-}\f$ process * according to a set of kinematic constraints provided for the incoming and * outgoing particles (the Kinematics object). - * The particle roles in this process are defined as following: \n - * \image latex lpair_kinematics.pdf Detailed particle roles in the two-photon process as defined by the @a GamGamLL object. The incoming protons/electrons are denoted by a role 1, and 2, as the outgoing protons/protons remnants/ electrons carry the indices 3 and 5. The two outgoing leptons have the roles 6 and 7, while the lepton/antilepton distinction is done randomly (thus, the arrow convention is irrelevant here). - * * The \a f function created by this Process child has its \a _ndim -dimensional * coordinates mapped as : * - 0 = \f$t_1\f$, first incoming photon's virtuality * - 1 = \f$t_2\f$, second incoming photon's virtuality * - 2 = \f$s_2\f$ mapping * - 3 = yy4 = \f$\cos\left(\pi x_3\right)\f$ definition * - 4 = \f$w_4\f$, the two-photon system's invariant mass - * - 5 = xx6 = \f$\frac{1}{2}\left(1-\cos\theta^\text{CM}_6\right)\f$ definition (3D rotation of the first outgoing lepton with respect to the two-photon centre-of-mass system). If the @a nm_ optimisation flag is set this angle coefficient value becomes - * \f[\frac{1}{2}\left(\frac{a_\text{map}}{b_\text{map}}\frac{\beta-1}{\beta+1}+1\right)\f] - * with \f$a_\text{map}=\frac{1}{2}\left(w_4-t_1-t_2\right)\f$, \f$b_\text{map}=\frac{1}{2}\sqrt{\left(\left(w_4-t_1-t_2\right)^2-4t_1t_2\right)\left(1-4\frac{w_6}{w_4}\right)}\f$, and \f$\beta=\left(\frac{a_\text{map}+b_\text{map}}{a_\text{map}-b_\text{map}}\right)^{2x_5-1}\f$ - * and the \a fJacobian element is scaled by a factor \f$\frac{1}{2}\frac{\left(a_\text{map}^2-b_\text{map}^2\cos^2\theta^\text{CM}_6\right)}{a_\text{map}b_\text{map}}\log\left(\frac{a_\text{map}+b_\text{map}}{a_\text{map}-b_\text{map}}\right)\f$ - * - 6 = _phicm6_, or \f$\phi_6^\text{CM}\f$ the rotation angle of the dilepton system in the centre-of-mass + * - 5 = xx6 = \f$\frac{1}{2}\left(1-\cos\theta^{\rm CM}_6\right)\f$ definition (3D rotation of the first outgoing lepton with respect to the two-photon centre-of-mass system). If the \a nm_ optimisation flag is set this angle coefficient value becomes + * \f[\frac{1}{2}\left(\frac{a_{\rm map}}{b_{\rm map}}\frac{\beta-1}{\beta+1}+1\right)\f] + * with \f$a_{\rm map}=\frac{1}{2}\left(w_4-t_1-t_2\right)\f$, \f$b_{\rm map}=\frac{1}{2}\sqrt{\left(\left(w_4-t_1-t_2\right)^2-4t_1t_2\right)\left(1-4\frac{w_6}{w_4}\right)}\f$, and \f$\beta=\left(\frac{a_{\rm map}+b_{\rm map}}{a_{\rm map}-b_{\rm map}}\right)^{2x_5-1}\f$ + * and the Jacobian element is scaled by a factor \f$\frac{1}{2}\frac{\left(a_{\rm map}^2-b_{\rm map}^2\cos^2\theta^{\rm CM}_6\right)}{a_{\rm map}b_{\rm map}}\log\left(\frac{a_{\rm map}+b_{\rm map}}{a_{\rm map}-b_{\rm map}}\right)\f$ + * - 6 = _phicm6_, or \f$\phi_6^{\rm CM}\f$ the rotation angle of the dilepton system in the centre-of-mass * system * - 7 = \f$x_q\f$, \f$w_X\f$ mappings, as used in the single- and double-dissociative * cases only * \brief Compute the matrix element for a CE \f$\gamma\gamma\to\ell^{+}\ell^{-}\f$ * process */ class GamGamLL : public GenericProcess { public: - /// Class constructor ; set the mandatory parameters before integration and events generation - /// \param[in] nopt Optimisation (legacy from LPAIR) + /// \brief Class constructor: set the mandatory parameters before integration and events generation + /// \param[in] params General process parameters (nopt = Optimisation, legacy from LPAIR) explicit GamGamLL( const ParametersList& params = ParametersList() ); ProcessPtr clone() const override { return ProcessPtr( new GamGamLL( *this ) ); } void addEventContent() override; void beforeComputeWeight() override; - /// Compute the process' weight for the given point - /// \return \f$\mathrm d\sigma(\mathbf x)(\gamma\gamma\to\ell^{+}\ell^{-})\f$, - /// the differential cross-section for the given point in the phase space. double computeWeight() override; unsigned int numDimensions() const override; void setKinematics( const Kinematics& cuts ) override; void fillKinematics( bool ) override; /// Compute the ougoing proton remnant mass /// \param[in] x A random number (between 0 and 1) /// \param[in] outmass The maximal outgoing particles' invariant mass /// \param[in] lepmass The outgoing leptons' mass /// \param[out] dw The size of the integration bin /// \return Mass of the outgoing proton remnant double computeOutgoingPrimaryParticlesMasses( double x, double outmass, double lepmass, double& dw ); /// Set all the kinematic variables for the outgoing proton remnants, and prepare the hadronisation - /// \param[in] part_ Particle to "prepare" for the hadronisation to be performed - void prepareHadronisation( Particle *part_ ); + /// \param[in] part Particle to "prepare" for the hadronisation to be performed + void prepareHadronisation( Particle *part ); private: /** * Calculate energies and momenta of the * 1st, 2nd (resp. the "proton-like" and the "electron-like" incoming particles), * 3rd (the "proton-like" outgoing particle), * 4th (the two-photons central system), and * 5th (the "electron-like" outgoing particle) particles in the overall centre-of-mass frame. * \brief Energies/momenta computation for the various particles, in the CM system * \return Success state of the operation */ bool orient(); /** * Compute the expression of the matrix element squared for the \f$\gamma\gamma\rightarrow\ell^{+}\ell^{-}\f$ process. * It returns the value of the convolution of the form factor or structure functions with the central two-photons matrix element squared. * \brief Computes the matrix element squared for the requested process * \return Full matrix element for the two-photon production of a pair of spin\f$-\frac{1}{2}-\f$point particles. * It is noted as \f[ * M = \frac{1}{4bt_1 t_2}\sum_{i=1}^2\sum_{j=1}^2 u_i v_j t_{ij} = \frac{1}{4}\frac{u_1 v_1 t_{11}+u_2 v_1 t_{21}+u_1 v_2 t_{12}+u_2 v_2 t_{22}}{t_1 t_2 b} * \f] where \f$b\f$ = \a bb_ is defined in \a ComputeWeight as : \f[ - * b = t_1 t_2+\left(w_{\gamma\gamma}\sin^2{\theta^\text{CM}_6}+4m_\ell\cos^2{\theta^\text{CM}_6}\right) p_g^2 + * b = t_1 t_2+\left(w_{\gamma\gamma}\sin^2{\theta^{\rm CM}_6}+4m_\ell\cos^2{\theta^{\rm CM}_6}\right) p_g^2 * \f] */ double periPP( int, int ); /** * Describe the kinematics of the process \f$p_1+p_2\to p_3+p_4+p_5\f$ in terms of Lorentz-invariant variables. * These variables (along with others) will then be fed into the \a PeriPP method (thus are essential for the evaluation of the full matrix element). * \return Success state of the operation */ bool pickin(); /// Internal switch for the optimised code version (LPAIR legacy ; unimplemented here) int n_opt_; int pair_; Limits w_limits_; Limits q2_limits_; Limits mx_limits_; struct Masses { Masses(); /// squared mass of the first proton-like outgoing particle double MX2_; /// squared mass of the second proton-like outgoing particle double MY2_; /// squared mass of the outgoing leptons double Ml2_; /// \f$\delta_2=m_1^2-m_2^2\f$ as defined in Vermaseren's paper - /// \cite Vermaseren1983347 for the full definition of this quantity + /// \cite Vermaseren:1982cz for the full definition of this quantity double w12_; /// \f$\delta_1=m_3^2-m_1^2\f$ as defined in Vermaseren's paper - /// \cite Vermaseren1983347 for the full definition of this quantity + /// \cite Vermaseren:1982cz for the full definition of this quantity double w31_; double dw31_; /// \f$\delta_4=m_5^2-m_2^2\f$ as defined in Vermaseren's paper - /// \cite Vermaseren1983347 for the full definition of this quantity + /// \cite Vermaseren:1982cz for the full definition of this quantity double w52_; double dw52_; }; Masses masses_; /// energy of the first proton-like incoming particle double ep1_; /// energy of the second proton-like incoming particle double ep2_; double p_cm_; /// energy of the two-photon central system double ec4_; /// 3-momentum norm of the two-photon central system double pc4_; /// mass of the two-photon central system double mc4_; /// squared mass of the two-photon central system double w4_; /// \f$p_{12} = \frac{1}{2}\left(s-m_{p_1}^2-m_{p_2}^2\right)\f$ double p12_; double p1k2_, p2k1_; /// \f$p_{13} = -\frac{1}{2}\left(t_1-m_{p_1}^2-m_{p_3}^2\right)\f$ double p13_; double p14_, p25_; double q1dq_, q1dq2_; double s1_, s2_; double epsi_; double g5_, g6_; double a5_, a6_; double bb_; double gram_; double dd1_, dd2_, dd3_; /// \f$\delta_5=m_4^2-t_1\f$ as defined in Vermaseren's paper - /// \cite Vermaseren1983347 for the full definition of this quantity + /// \cite Vermaseren:1982cz for the full definition of this quantity double dd4_; double dd5_; /** * Invariant used to tame divergences in the matrix element computation. It is defined as * \f[\Delta = \left(p_1\cdot p_2\right)\left(q_1\cdot q_2\right)-\left(p_1\cdot q_2\right)\left(p_2\cdot q_1\right)\f] * with \f$p_i, q_i\f$ the 4-momenta associated to the incoming proton-like particle and to the photon emitted from it. */ double delta_; double g4_; double sa1_, sa2_; double sl1_; /// cosine of the polar angle for the two-photons centre-of-mass system double cos_theta4_; /// sine of the polar angle for the two-photons centre-of-mass system double sin_theta4_; double al4_; double be4_; double de3_, de5_; double pt4_; /// Kinematics of the first incoming proton Particle::Momentum p1_lab_; /// Kinematics of the second incoming proton Particle::Momentum p2_lab_; /// Kinematics of the first outgoing proton Particle::Momentum p3_lab_; /// Kinematics of the two-photon system (in the two-proton CM) Particle::Momentum p4_lab_; /// Kinematics of the second outgoing proton Particle::Momentum p5_lab_; /// Kinematics of the first outgoing lepton (in the two-proton CM) Particle::Momentum p6_cm_; /// Kinematics of the second outgoing lepton (in the two-proton CM) Particle::Momentum p7_cm_; double jacobian_; private: /** - * Define modified variables of integration to avoid peaks integrations (see @cite Vermaseren1983347 for details) + * Define modified variables of integration to avoid peaks integrations (see \cite Vermaseren:1982cz for details) * Return a set of two modified variables of integration to maintain the stability of the integrant. These two new variables are : * - \f$y_{out} = x_{min}\left(\frac{x_{max}}{x_{min}}\right)^{exp}\f$ the new variable * - \f$\mathrm dy_{out} = x_{min}\left(\frac{x_{max}}{x_{min}}\right)^{exp}\log\frac{x_{min}}{x_{max}}\f$, the new variable's differential form - * @brief Redefine the variables of integration in order to avoid the strong peaking of the integrant. - * @param[in] expo Exponant - * @param[in] xmin Minimal value of the variable - * @param[in] xmax Maximal value of the variable - * @param[out] out The new variable definition - * @param[out] dout The differential variant of the new variable definition - * @param[in] var_name The variable name - * @note This method overrides the set of `mapxx` subroutines in ILPAIR, with a slight difference according to the sign of the + * \brief Redefine the variables of integration in order to avoid the strong peaking of the integrant + * \param[in] expo Exponant + * \param[in] lim Min/maximal value of the variable + * \param[out] out The new variable definition + * \param[out] dout The bin width the new variable definition + * \param[in] var_name The variable name + * \note This method overrides the set of `mapxx` subroutines in ILPAIR, with a slight difference according to the sign of the * \f$\mathrm dy_{out}\f$ parameter : * - left unchanged : * > `mapw2`, `mapxq`, `mapwx`, `maps2` * - opposite sign : * > `mapt1`, `mapt2` */ - void map( double expo, const Limits& lim, double& out, double& dout, const std::string& var_name="" ); + void map( double expo, const Limits& lim, double& out, double& dout, const std::string& var_name = "" ); void mapla( double y, double z, int u, double xm, double xp, double& x, double& d ); /// Compute the electric/magnetic form factors for the two considered \f$Q^{2}\f$ momenta transfers void formFactors( double q1, double q2, FormFactors& fp1, FormFactors& fp2 ) const; }; } } #endif - diff --git a/CepGen/Processes/GenericKTProcess.h b/CepGen/Processes/GenericKTProcess.h index e5ce598..a1fd04c 100644 --- a/CepGen/Processes/GenericKTProcess.h +++ b/CepGen/Processes/GenericKTProcess.h @@ -1,143 +1,143 @@ #ifndef CepGen_Processes_GenericKTProcess_h #define CepGen_Processes_GenericKTProcess_h #include "GenericProcess.h" namespace CepGen { class ParametersList; namespace Process { /** * A generic kT-factorisation process. * \note * - First 4 dimensions of the phase space are required for the * incoming partons' virtualities (radial and azimuthal coordinates). * - Last 0-2 dimensions may be used for the scattered diffractive * system(s)' invariant mass definition. * \brief Class template to define any kT-factorisation process * \author Laurent Forthomme <laurent.forthomme@cern.ch> * \date Apr 2016 */ class GenericKTProcess : public GenericProcess { public: /// Class constructor /// \param[in] params Parameters list /// \param[in] name Generic process name /// \param[in] description Human-readable kT-factorised process name /// \param[in] partons First and second incoming parton /// \param[in] output Produced final state particles GenericKTProcess( const ParametersList& params, const std::string& name, const std::string& description, const std::array<PDG,2>& partons, const std::vector<PDG>& output ); /// Populate the event content with the generated process' topology void addEventContent() override; /// Retrieve the total number of dimensions on which the integration is being performet unsigned int numDimensions() const override; /// Retrieve the event weight in the phase space double computeWeight() override; /// Populate the event content with the generated process' kinematics void fillKinematics( bool ) override; - + /// List all variables handled by this generic process void dumpVariables() const; protected: /// Set the kinematics associated to the phase space definition void setKinematics( const Kinematics& kin ) override; /// Set the kinematics of the central system before any point computation virtual void setExtraContent() {} /// Prepare the central part of the Jacobian (only done once, as soon as the kinematics is set) virtual void preparePhaseSpace() = 0; /// kT-factorised matrix element (event weight) /// \return Weight of the point in the phase space to the integral virtual double computeKTFactorisedMatrixElement() = 0; /// Compute the unintegrated photon fluxes (for inelastic distributions, interpolation on double logarithmic grid) std::pair<double,double> incomingFluxes( double, double, double, double ) const; /// Set the kinematics of the incoming and outgoing protons (or remnants) void fillPrimaryParticlesKinematics(); /// Set the kinematics of the outgoing central system virtual void fillCentralParticlesKinematics() = 0; /// Type of mapping to apply on the variable enum class Mapping { - /// a linear \f$\textrm dx\f$ mapping + /// a linear \f${\rm d}x\f$ mapping linear = 0, - /// a logarithmic \f$\frac{\textrm dx}{x} = \textrm d(\log x)\f$ mapping + /// a logarithmic \f$\frac{{\rm d}x}{x} = {\rm d}(\log x)\f$ mapping logarithmic, - /// a square \f$\textrm dx^2=2x\cdot\textrm dx\f$ mapping + /// a square \f${\rm d}x^2=2x\cdot{\rm d}x\f$ mapping square }; friend std::ostream& operator<<( std::ostream&, const Mapping& ); /// Register a variable to be handled and populated whenever /// a new phase space point weight is to be calculated. /// \note To be run once per generation (before any point computation) /// \param[out] out Reference to the variable to be mapped /// \param[in] type Type of mapping to apply /// \param[in] in Integration limits /// \param[in] default_limits Limits to apply if none retrieved from the user configuration /// \param[in] description Human-readable description of the variable void registerVariable( double& out, const Mapping& type, const Limits& in, Limits default_limits, const char* description ); /// Generate and initialise all variables handled by this process /// \return Phase space point-dependent component of the Jacobian weight of the point in the phase space for integration /// \note To be run at each point computation (therefore, to be optimised!) double generateVariables() const; - + /// Number of dimensions on which to perform the integration unsigned short num_dimensions_; /// Phase space point-independant component of the Jacobian weight of the point in the phase space for integration double kt_jacobian_; /// Log-virtuality range of the intermediate parton Limits log_qt_limits_; /// Intermediate azimuthal angle range Limits phi_qt_limits_; /// Invariant mass range for the scattered excited system Limits mx_limits_; /// Virtuality of the first intermediate parton (photon, pomeron, ...) double qt1_; /// Azimuthal rotation of the first intermediate parton's transverse virtuality double phi_qt1_; /// Virtuality of the second intermediate parton (photon, pomeron, ...) double qt2_; /// Azimuthal rotation of the second intermediate parton's transverse virtuality double phi_qt2_; /// First outgoing proton Particle::Momentum PX_; /// Second outgoing proton Particle::Momentum PY_; /// Handler to a variable mapped by this process struct MappingVariable { /// Human-readable description of the variable std::string description; /// Kinematic limits to apply on the variable Limits limits; /// Reference to the process variable to generate/map double& variable; /// Interpolation type Mapping type; /// Corresponding integration variable unsigned short index; }; /// Collection of variables to be mapped at the weight generation stage std::vector<MappingVariable> mapped_variables_; private: /// First and second intermediate parton (photon, pomeron, ...) std::array<PDG,2> kIntermediateParts; /// Type of particles produced in the final state std::vector<PDG> kProducedParts; }; } } #endif diff --git a/CepGen/Processes/GenericProcess.h b/CepGen/Processes/GenericProcess.h index 4cd3cae..f52bc95 100644 --- a/CepGen/Processes/GenericProcess.h +++ b/CepGen/Processes/GenericProcess.h @@ -1,165 +1,166 @@ #ifndef CepGen_Processes_GenericProcess_h #define CepGen_Processes_GenericProcess_h #include "CepGen/Event/Particle.h" #include "CepGen/Physics/Kinematics.h" #include <vector> #include <memory> namespace CepGen { class Event; class FormFactors; /// Location for all physics processes to be generated namespace Process { - /// Class template to define any process to compute using this MC integrator/events generator + /// \brief Class template to define any process to compute using this MC integrator/events generator /// \author Laurent Forthomme <laurent.forthomme@cern.ch> /// \date Jan 2014 class GenericProcess { public: /// Default constructor for an undefined process /// \param[in] name Process name /// \param[in] description Human-readable description of the process /// \param[in] has_event Do we generate the associated event structure? GenericProcess( const std::string& name, const std::string& description = "<invalid process>", bool has_event = true ); /// Copy constructor for a user process GenericProcess( const GenericProcess& ); virtual ~GenericProcess() = default; /// Assignment operator GenericProcess& operator=( const GenericProcess& ); /// Human-readable format dump of a GenericProcess object friend std::ostream& operator<<( std::ostream& os, const GenericProcess& proc ); /// Human-readable format dump of a pointer to a GenericProcess object friend std::ostream& operator<<( std::ostream& os, const GenericProcess* proc ); /// Generic map of particles with their role in the process typedef std::map<Particle::Role,PDG> ParticlesRoleMap; /// Pair of particle with their associated role in the process typedef std::pair<Particle::Role,PDG> ParticleWithRole; /// Map of all incoming state particles in the process typedef ParticlesRoleMap IncomingState; /// Map of all outgoing particles in the process typedef std::map<Particle::Role,std::vector<PDG> > OutgoingState; - /// Copy all process' attributes into a new object + /// Copy all process attributes into a new object virtual std::unique_ptr<GenericProcess> clone() const = 0; /// Restore the Event object to its initial state void clearEvent(); /// Set the kinematics of the incoming state particles void setIncomingKinematics( const Particle::Momentum& p1, const Particle::Momentum& p2 ); /// Compute the incoming state kinematics void prepareKinematics(); public: /// Set the incoming and outgoing state to be expected in the process inline virtual void addEventContent() {} /// Set the list of kinematic cuts to apply on the outgoing particles' final state /// \param[in] cuts The Cuts object containing the kinematic parameters virtual void setKinematics( const Kinematics& cuts ); /// Return the number of dimensions on which the integration has to be performed /// \return Number of dimensions on which to integrate virtual unsigned int numDimensions() const = 0; /// Prepare the process for its integration over the whole phase space inline virtual void beforeComputeWeight() {} /// Compute the weight for this point in the phase-space virtual double computeWeight() = 0; /// Fill the Event object with the particles' kinematics /// \param[in] symmetrise Symmetrise the event? (randomise the production of positively- and negatively-charged outgoing central particles) virtual void fillKinematics( bool symmetrise = false ) = 0; public: /** * Sets the phase space point to compute the weight associated to it. * \brief Sets the phase space point to compute * \param[in] ndim The number of dimensions of the point in the phase space * \param[in] x[] The (\a ndim_)-dimensional point in the phase space on which the kinematics and the cross-section are computed */ void setPoint( const unsigned int ndim, double* x ); /// Dump the evaluated point's coordinates in the standard output stream void dumpPoint() const; /// Complete list of Particle with their role in the process for the point considered in the phase space, returned as an Event object. /// \return Event object containing all the generated Particle objects inline std::shared_ptr<Event> event() const { return event_; } ///Get the number of dimensions on which the integration is performed inline const unsigned int ndim() const { return x_.size(); } /// Get the value of a component of the d-dimensional point considered double x( unsigned int idx ) const; /// Name of the process considered inline const std::string& name() const { return name_; } /// Human-readable description of the process inline const std::string& description() const { return description_; } /// Does the process contain (and hold) an event? bool hasEvent() const { return has_event_; } /// Pointer to the last event produced in this run std::shared_ptr<Event> last_event; protected: - static const double mp_, mp2_; + 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$ /// Set the incoming and outgoing states to be defined in this process (and prepare the Event object accordingly) void setEventContent( const IncomingState& ini, const OutgoingState& fin ); // --- /// Name of the process std::string name_; /// Process human-readable description std::string description_; public: /// Is it the first time the process is computed? bool first_run; protected: /// Array of double precision floats representing the point on which the weight in the cross-section is computed std::vector<double> x_; /// \f$s\f$, squared centre of mass energy of the incoming particles' system, in \f$\mathrm{GeV}^2\f$ double s_; /// \f$\sqrt s\f$, centre of mass energy of the incoming particles' system (in GeV) double sqs_; /// Invariant mass of the first proton-like outgoing particle (or remnant) double MX_; /// Invariant mass of the second proton-like outgoing particle (or remnant) double MY_; /// \f$m_1^2\f$, squared mass of the first proton-like incoming particle double w1_; /// \f$m_2^2\f$, squared mass of the second proton-like incoming particle double w2_; /// Virtuality of the first incoming photon double t1_; /// Virtuality of the second incoming photon double t2_; /// Set of cuts to apply on the final phase space Kinematics cuts_; /// Does the process contain (and hold) an event? bool has_event_; /// Event object containing all the information on the in- and outgoing particles std::shared_ptr<Event> event_; /// Is the phase space point set? bool is_point_set_; private: /** * Is the system's kinematics well defined and compatible with the process ? * This check is mandatory to perform the d-dimensional point's cross-section computation. * \brief Is the system's kinematics well defined? * \return A boolean stating if the input kinematics and the final states are well-defined */ bool isKinematicsDefined(); }; } /// Helper typedef for a Process unique pointer typedef std::unique_ptr<Process::GenericProcess> ProcessPtr; } #endif diff --git a/CepGen/Processes/PPtoFF.cpp b/CepGen/Processes/PPtoFF.cpp index 4c6a69b..8e218cf 100644 --- a/CepGen/Processes/PPtoFF.cpp +++ b/CepGen/Processes/PPtoFF.cpp @@ -1,372 +1,373 @@ #include "CepGen/Processes/PPtoFF.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 <iomanip> namespace CepGen { namespace Process { PPtoFF::PPtoFF( const ParametersList& params ) : GenericKTProcess( params, "pptoff", "ɣɣ → f⁺f¯", { { PDG::photon, PDG::photon } }, { PDG::muon, PDG::muon } ), pair_( params.get<int>( "pair", 0 ) ), method_( params.get<int>( "method", 1 ) ), y1_( 0. ), y2_( 0. ), pt_diff_( 0. ), phi_pt_diff_( 0. ) {} void PPtoFF::preparePhaseSpace() { registerVariable( y1_, Mapping::linear, cuts_.cuts.central.rapidity_single, { -6., 6. }, "First outgoing fermion rapidity" ); registerVariable( y2_, Mapping::linear, cuts_.cuts.central.rapidity_single, { -6., 6. }, "Second outgoing fermion rapidity" ); registerVariable( pt_diff_, Mapping::linear, cuts_.cuts.central.pt_diff, { 0., 50. }, "Fermions transverse momentum difference" ); registerVariable( phi_pt_diff_, Mapping::linear, cuts_.cuts.central.phi_pt_diff, { 0., 2.*M_PI }, "Fermions azimuthal angle difference" ); if ( (PDG)pair_ == PDG::invalid ) throw CG_FATAL( "PPtoFF:prepare" ) << "Invalid fermion pair selected: " << pair_ << "!"; const PDG pdg_f = (PDG)pair_; mf_ = ParticleProperties::mass( pdg_f ); mf2_ = mf_*mf_; qf_ = ParticleProperties::charge( pdg_f ); colf_ = ParticleProperties::colours( pdg_f ); CG_DEBUG( "PPtoFF:prepare" ) << "Produced particles (" << pdg_f << ") " << "with mass = " << mf_ << " GeV, " - << "and charge = " << qf_ << " e"; + << "and charge = " << std::setprecision( 2 ) << qf_ << " e"; CG_DEBUG( "PPtoFF:mode" ) << "matrix element computation method: " << method_ << "."; } double PPtoFF::computeKTFactorisedMatrixElement() { //================================================================= // matrix element computation //================================================================= //--- central partons const Particle::Momentum q1t( qt1_*cos( phi_qt1_ ), qt1_*sin( phi_qt1_ ), 0. ); const Particle::Momentum q2t( qt2_*cos( phi_qt2_ ), qt2_*sin( phi_qt2_ ), 0. ); CG_DEBUG_LOOP( "PPtoFF" ) << "q(1/2)t = " << q1t << ", " << q2t << "."; //--- two-parton system const Particle::Momentum ptsum = q1t+q2t; const Particle::Momentum ptdiff( pt_diff_*cos( phi_pt_diff_ ), pt_diff_*sin( phi_pt_diff_ ), 0. ); //--- outgoing fermions const Particle::Momentum p1_cm = 0.5*( ptsum+ptdiff ), p2_cm = 0.5*( ptsum-ptdiff ); //================================================================= // a window in single particle transverse momentum //================================================================= const Limits& pt_limits = cuts_.cuts.central.pt_single; if ( !pt_limits.passes( p1_cm.pt() ) || !pt_limits.passes( p2_cm.pt() ) ) return 0.; //================================================================= // a window in transverse momentum difference //================================================================= if ( !cuts_.cuts.central.pt_diff.passes( fabs( p1_cm.pt()-p2_cm.pt() ) ) ) return 0.; //================================================================= // a window in rapidity distance //================================================================= if ( !cuts_.cuts.central.rapidity_diff.passes( fabs( y1_-y2_ ) ) ) return 0.; //================================================================= // auxiliary quantities //================================================================= // transverse mass for the two fermions const double amt1 = std::hypot( p1_cm.pt(), mf_ ), amt2 = std::hypot( p2_cm.pt(), mf_ ); 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( "PPtoFF" ) << "Sudakov parameters:\n\t" << " alpha(1/2) = " << alpha1 << ", " << alpha2 << "\n\t" << " beta(1/2) = " << beta1 << ", " << beta2 << "."; const double x1 = alpha1+alpha2, x2 = beta1+beta2; if ( x1 <= 0. || x1 > 1. || x2 <= 0. || x2 > 1. ) return 0.; // sanity check //================================================================= // additional conditions for energy-momentum conservation //================================================================= const double s1_eff = x1*s_-qt1_*qt1_, s2_eff = x2*s_-qt2_*qt2_; const double invm = sqrt( amt1*amt1 + amt2*amt2 + 2.*amt1*amt2*cosh(y1_-y2_) - ptsum.pt2() ); CG_DEBUG_LOOP( "PPtoFF" ) << "s(1/2)eff = " << s1_eff << ", " << s2_eff << " GeV²\n\t" << "central system's invariant mass = " << invm << " GeV."; if ( ( cuts_.mode == KinematicsMode::ElasticInelastic || cuts_.mode == KinematicsMode::InelasticInelastic ) && ( sqrt( s1_eff ) <= ( MY_+invm ) ) ) return 0.; if ( ( cuts_.mode == KinematicsMode::InelasticElastic || cuts_.mode == KinematicsMode::InelasticInelastic ) && ( sqrt( s2_eff ) <= ( MX_+invm ) ) ) return 0.; //================================================================= // four-momenta of the outgoing protons (or remnants) //================================================================= const Particle::Momentum& ak1 = event_->getOneByRole( Particle::IncomingBeam1 ).momentum(), &ak2 = event_->getOneByRole( Particle::IncomingBeam2 ).momentum(); CG_DEBUG_LOOP( "PPtoFF" ) << "incoming particles: p(1/2) = " << ak1 << ", " << ak2 << "."; const double px_plus = ( 1.-x1 )*M_SQRT2*ak1.p(), px_minus = ( MX_*MX_ + q1t.pt2() )*0.5/px_plus; const double py_minus = ( 1.-x2 )*M_SQRT2*ak2.p(), py_plus = ( MY_*MY_ + q2t.pt2() )*0.5/py_minus; CG_DEBUG_LOOP( "PPtoFF" ) << "px± = " << px_plus << ", " << px_minus << "\n\t" << "py± = " << py_plus << ", " << py_minus << "."; PX_ = Particle::Momentum( -q1t.px(), -q1t.py(), ( px_plus-px_minus )*M_SQRT1_2, ( px_plus+px_minus )*M_SQRT1_2 ); PY_ = Particle::Momentum( -q2t.px(), -q2t.py(), ( py_plus-py_minus )*M_SQRT1_2, ( py_plus+py_minus )*M_SQRT1_2 ); CG_DEBUG_LOOP( "PPtoFF" ) << "First remnant: " << PX_ << ", mass = " << PX_.mass() << "\n\t" << "Second remnant: " << PY_ << ", mass = " << PY_.mass() << "."; if ( fabs( PX_.mass()-MX_ ) > 1.e-6 ) throw CG_FATAL( "PPtoFF" ) << "Invalid X system mass: " << PX_.mass() << "/" << MX_ << "."; if ( fabs( PY_.mass()-MY_ ) > 1.e-6 ) throw CG_FATAL( "PPtoFF" ) << "Invalid Y system mass: " << PY_.mass() << "/" << MY_ << "."; //================================================================= // four-momenta of the outgoing l^+ and l^- //================================================================= const Particle::Momentum p1 = p1_cm + alpha1*ak1 + beta1*ak2; const Particle::Momentum p2 = p2_cm + alpha2*ak1 + beta2*ak2; CG_DEBUG_LOOP( "PPtoFF" ) << "unboosted first fermion: " << p1 << ", mass = " << p1.mass() << "\n\t" << " second fermion: " << p2 << ", mass = " << p2.mass() << "."; p_f1_ = Particle::Momentum::fromPxPyYM( p1_cm.px(), p1_cm.py(), y2_, mf_ ); p_f2_ = Particle::Momentum::fromPxPyYM( p2_cm.px(), p2_cm.py(), y1_, mf_ ); CG_DEBUG_LOOP( "PPtoFF" ) << "First fermion: " << p_f1_ << ", mass = " << p_f1_.mass() << "\n\t" << "Second fermion: " << p_f2_ << ", mass = " << p_f2_.mass() << "."; if ( fabs( p_f1_.mass()-mf_ ) > 1.e-4 ) throw CG_FATAL( "PPtoFF" ) << "Invalid fermion 1 mass: " << p_f1_.mass() << "/" << mf_ << "."; if ( fabs( p_f2_.mass()-mf_ ) > 1.e-4 ) throw CG_FATAL( "PPtoFF" ) << "Invalid fermion 2 mass: " << p_f2_.mass() << "/" << mf_ << "."; //================================================================= // matrix elements //================================================================= double amat2 = 0.; //================================================================= // How matrix element is calculated //================================================================= if ( method_ == 0 ) { //=============================================================== // Mendelstam variables //=============================================================== //const double shat = s_*x1*x2; // approximation const double shat = ( q1t+q2t ).mass2(); // exact formula //const double mll = sqrt( shat ); const double that1 = ( q1t-p1 ).mass2(), that2 = ( q2t-p2 ).mass2(); const double uhat1 = ( q1t-p2 ).mass2(), uhat2 = ( q2t-p1 ).mass2(); const double that = 0.5*( that1+that2 ), uhat = 0.5*( uhat1+uhat2 ); amat2 = onShellME( shat, that, uhat ); CG_DEBUG_LOOP( "PPtoFF:onShell" ) << "that(1/2) = " << that1 << " / " << that2 << "\n\t" << "uhat(1/2) = " << uhat1 << " / " << uhat2 << "\n\t" << "squared matrix element: " << amat2 << "."; } else if ( method_ == 1 ) { const double t1abs = ( q1t.pt2() + x1*( MX_*MX_-mp2_ )+x1*x1*mp2_ )/( 1.-x1 ), t2abs = ( q2t.pt2() + x2*( MY_*MY_-mp2_ )+x2*x2*mp2_ )/( 1.-x2 ); const double z1p = alpha1/x1, z1m = alpha2/x1, z2p = beta1 /x2, z2m = beta2 /x2; CG_DEBUG_LOOP( "PPtoFF:offShell" ) << "z(1/2)p = " << z1p << ", " << z2p << "\n\t" << "z(1/2)m = " << z1m << ", " << z2m << "."; amat2 = offShellME( t1abs, t2abs, z1m, z1p, z2m, z2p, q1t, q2t ) * pow( x1*x2*s_, 2 ); } //============================================ // unintegrated photon distributions //============================================ const std::pair<double,double> fluxes = GenericKTProcess::incomingFluxes( x1, q1t.pt2(), x2, q2t.pt2() ); CG_DEBUG_LOOP( "PPtoFF" ) << "Incoming photon fluxes for (x/kt2) = " << "(" << x1 << "/" << q1t.pt2() << "), " << "(" << x2 << "/" << q2t.pt2() << "):\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 g_em = 4.*M_PI*Constants::alphaEM*qf_*qf_; const double aintegral = amat2 * colf_ * ( g_em*g_em ) * 1. / pow( 4.*M_PI*( x1*x2*s_ ), 2 ) * fluxes.first*M_1_PI * fluxes.second*M_1_PI * 0.25 * Constants::GeV2toBarn; //================================================================= return aintegral*qt1_*qt2_*pt_diff_; //================================================================= } void PPtoFF::fillCentralParticlesKinematics() { // randomise the charge of the outgoing fermions short sign = ( drand() > 0.5 ) ? +1 : -1; //================================================================= // first outgoing fermion //================================================================= Particle& of1 = event_->getByRole( Particle::CentralSystem )[0]; of1.setPdgId( of1.pdgId(), sign ); of1.setStatus( Particle::Status::FinalState ); of1.setMomentum( p_f1_ ); //================================================================= // second outgoing fermion //================================================================= Particle& of2 = event_->getByRole( Particle::CentralSystem )[1]; of2.setPdgId( of2.pdgId(), -sign ); of2.setStatus( Particle::Status::FinalState ); of2.setMomentum( p_f2_ ); } double PPtoFF::onShellME( double shat, double that, double uhat ) const { CG_DEBUG_LOOP( "PPtoFF:onShell" ) << "shat: " << shat << ", that: " << that << ", uhat: " << uhat << "."; //================================================================= // on-shell formula for M^2 //================================================================= const double ml4 = mf2_*mf2_, ml8 = ml4*ml4; const double term1 = 6. *ml8, term2 = -3. *ml4 *that*that, term3 = -14.*ml4 *that*uhat, term4 = -3. *ml4 *uhat*uhat, term5 = mf2_*that*that*that, term6 = 7.* mf2_*that*that*uhat, term7 = 7.* mf2_*that*uhat*uhat, term8 = mf2_*uhat*uhat*uhat, term9 = -that*that*that*uhat, term10 = -that*uhat*uhat*uhat; return -2.*( term1+term2+term3+term4+term5 +term6+term7+term8+term9+term10 )/( pow( ( mf2_-that )*( mf2_-uhat ), 2) ); } double PPtoFF::offShellME( double t1abs, double t2abs, double z1m, double z1p, double z2m, double z2p, const Particle::Momentum& q1, const Particle::Momentum& q2 ) const { //================================================================= // Wolfgang's formulae //================================================================= const double z1 = z1p*z1m, z2 = z2p*z2m; const double eps12 = mf2_+z1*t1abs, eps22 = mf2_+z2*t2abs; const Particle::Momentum ak1 = ( z1m*p_f1_-z1p*p_f2_ ), ak2 = ( z2m*p_f1_-z2p*p_f2_ ); const Particle::Momentum ph_p1 = ak1+z1p*q2, ph_m1 = ak1-z1m*q2; const Particle::Momentum ph_p2 = ak2+z2p*q1, ph_m2 = ak2-z2m*q1; const Particle::Momentum phi1( ph_p1.px()/( ph_p1.pt2()+eps12 )-ph_m1.px()/( ph_m1.pt2()+eps12 ), ph_p1.py()/( ph_p1.pt2()+eps12 )-ph_m1.py()/( ph_m1.pt2()+eps12 ), 0., 1./( ph_p1.pt2()+eps12 )-1./( ph_m1.pt2()+eps12 ) ); const Particle::Momentum phi2( ph_p2.px()/( ph_p2.pt2()+eps22 )-ph_m2.px()/( ph_m2.pt2()+eps22 ), ph_p2.py()/( ph_p2.pt2()+eps22 )-ph_m2.py()/( ph_m2.pt2()+eps22 ), 0., 1./( ph_p2.pt2()+eps22 )-1./( ph_m2.pt2()+eps22 ) ); const double dot1 = phi1.threeProduct( q1 )/qt1_, cross1 = phi1.crossProduct( q1 )/qt1_; const double dot2 = phi2.threeProduct( q2 )/qt2_, cross2 = phi2.crossProduct( q2 )/qt2_; CG_DEBUG_LOOP( "PPtoFF:offShell" ) << "phi1 = " << phi1 << "\n\t" << "phi2 = " << phi2 << "\n\t" << "(dot): " << dot1 << " / " << dot2 << "\n\t" << "(cross): " << cross1 << " / " << cross2 << "."; //================================================================= // six terms in Wolfgang's formula for // off-shell gamma gamma --> l^+ l^- //================================================================= const unsigned short imat1 = 1, imat2 = 1; const unsigned short itermLL = 1, itermTT = 1, itermLT = 1, itermtt = 1; const double aux2_1 = itermLL * ( mf2_ + 4.*z1*z1*t1abs ) * phi1.energy2() +itermTT * ( ( z1p*z1p + z1m*z1m )*( dot1*dot1 + cross1*cross1 ) ) +itermtt * ( cross1*cross1 - dot1*dot1 ) -itermLT * 4.*z1*( z1p-z1m ) * phi1.energy() * q1.threeProduct( phi1 ); const double aux2_2 = itermLL * ( mf2_ + 4.*z2*z2*t2abs ) * phi2.energy2() +itermTT * ( ( z2p*z2p + z2m*z2m )*( dot2*dot2 + cross2*cross2 ) ) +itermtt * ( cross2*cross2 - dot2*dot2 ) -itermLT * 4.*z2*( z2p-z2m ) * phi2.energy() * q2.threeProduct( phi2 ); //================================================================= // convention of matrix element as in our kt-factorization // for heavy flavours //================================================================= const double amat2_1 = aux2_1*2.*z1*q1.pt2()/( q1.pt2()*q2.pt2() ), amat2_2 = aux2_2*2.*z2*q2.pt2()/( q1.pt2()*q2.pt2() ); //================================================================= // symmetrization //================================================================= CG_DEBUG_LOOP( "PPtoFF:offShell" ) << "aux2(1/2) = " << aux2_1 << " / " << aux2_2 << "\n\t" << "amat2(1/2), amat2 = " << amat2_1 << " / " << amat2_2 << " / " << ( 0.5*( imat1*amat2_1 + imat2*amat2_2 ) ) << "."; return 0.5*( imat1*amat2_1 + imat2*amat2_2 ); } } } diff --git a/CepGen/Processes/PPtoWW.h b/CepGen/Processes/PPtoWW.h index 541f86f..01971af 100644 --- a/CepGen/Processes/PPtoWW.h +++ b/CepGen/Processes/PPtoWW.h @@ -1,58 +1,59 @@ #ifndef CepGen_Processes_PPtoWW_h #define CepGen_Processes_PPtoWW_h #include "CepGen/Processes/GenericKTProcess.h" #include "CepGen/Core/ParametersList.h" namespace CepGen { namespace Process { - /// Compute the matrix element for a CE \f$\gamma\gamma\rightarrow W^+W^-\f$ process using \f$k_T\f$-factorization approach + /// \brief Compute the matrix element for a CE \f$\gamma\gamma\rightarrow W^+W^-\f$ process using \f$k_T\f$-factorization approach + /// \note The full theoretical description of this process definition may be found in \cite Luszczak:2018ntp. class PPtoWW : public GenericKTProcess { public: PPtoWW( const ParametersList& params = ParametersList() ); ProcessPtr clone() const override { return ProcessPtr( new PPtoWW( *this ) ); } enum class Polarisation { full = 0, LL = 1, LT = 2, TL = 3, TT = 4 }; private: static const double mw_, mw2_; void preparePhaseSpace() override; double computeKTFactorisedMatrixElement() override; void fillCentralParticlesKinematics() override; double amplitudeWW( double shat, double that, double uhat, short lam1, short lam2, short lam3, short lam4 ); double onShellME( double shat, double that, double uhat ); double offShellME( double shat, double that, double uhat, double phi_sum, double phi_diff ); int method_; Polarisation pol_state_; std::vector<short> pol_w1_, pol_w2_; /// Rapidity range for the outgoing W bosons Limits rap_limits_; /// Rapidity of the first outgoing W boson double y1_; /// Rapidity of the first outgoing W boson double y2_; Limits ptdiff_limits_; /// Transverse momentum difference for the two outgoing W bosons double pt_diff_; Limits phi_pt_diff_limits_; /// Azimuthal angle difference for the two outgoing W bosons double phi_pt_diff_; /// First outgoing W boson's momentum Particle::Momentum p_w1_; /// Second outgoing W boson's momentum Particle::Momentum p_w2_; }; } } #endif diff --git a/CepGen/StructureFunctions/ALLM.h b/CepGen/StructureFunctions/ALLM.h index 77a22c8..aaf10cb 100644 --- a/CepGen/StructureFunctions/ALLM.h +++ b/CepGen/StructureFunctions/ALLM.h @@ -1,61 +1,62 @@ #ifndef CepGen_StructureFunctions_ALLM_h #define CepGen_StructureFunctions_ALLM_h #include "StructureFunctions.h" #include "SigmaRatio.h" #include <vector> namespace CepGen { namespace SF { + /// \f$F_{2/L}\f$ parameterisation by Abramowicz, Levin, Levy, and Maor \cite Abramowicz:1991xz\cite Abramowicz:1997ms class ALLM : public StructureFunctions { public: class Parameterisation { private: struct Parameters { Parameters() : a( { 0., 0., 0. } ), b( { 0., 0., 0. } ), c( { 0., 0., 0. } ) {} Parameters( const std::vector<double>& c, const std::vector<double>& a, const std::vector<double>& b ) : a( a ), b( b ), c( c ) {} std::vector<double> a, b, c; }; public: Parameterisation() : m02( 0. ), mp2( 0. ), mr2( 0. ), q02( 0. ), lambda2( 0. ) {} /// Pre-HERA data fit (694 data points) static Parameterisation allm91(); /// Fixed target and HERA photoproduction total cross sections (1356 points) static Parameterisation allm97(); static Parameterisation hht_allm(); static Parameterisation hht_allm_ft(); static Parameterisation gd07p(); static Parameterisation gd11p(); Parameters 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 ALLM::Parameterisation& param = ALLM::Parameterisation::allm97() ); ALLM& operator()( double xbj, double q2 ) override; private: Parameterisation params_; }; } } #endif diff --git a/CepGen/StructureFunctions/BlockDurandHa.h b/CepGen/StructureFunctions/BlockDurandHa.h index efe0ec7..a1c5c95 100644 --- a/CepGen/StructureFunctions/BlockDurandHa.h +++ b/CepGen/StructureFunctions/BlockDurandHa.h @@ -1,36 +1,37 @@ #ifndef CepGen_StructureFunctions_BlockDurandHa_h #define CepGen_StructureFunctions_BlockDurandHa_h #include "StructureFunctions.h" #include <array> namespace CepGen { namespace SF { + /// \f$F_2\f$ parameterisation from Block, Durand, and Ha \cite Block:2014kza class BlockDurandHa : public StructureFunctions { public: struct Parameterisation { std::array<double,3> a, b; std::array<double,2> c; double n; /// Effective mass spread parameter double lambda; /// Asymptotic log-behaviour transition scale factor double mu2; /// Squared effective mass (~VM mass) double m2; static Parameterisation standard(); }; explicit BlockDurandHa( const BlockDurandHa::Parameterisation& params = BlockDurandHa::Parameterisation::standard() ); BlockDurandHa& operator()( double xbj, double q2 ) override; private: Parameterisation params_; }; } } #endif diff --git a/CepGen/StructureFunctions/CLAS.cpp b/CepGen/StructureFunctions/CLAS.cpp index b35c5b4..032a3e1 100644 --- a/CepGen/StructureFunctions/CLAS.cpp +++ b/CepGen/StructureFunctions/CLAS.cpp @@ -1,217 +1,220 @@ #include "CepGen/StructureFunctions/CLAS.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Event/Particle.h" #include "CepGen/Core/Exception.h" namespace CepGen { namespace SF { CLAS::Parameterisation CLAS::Parameterisation::standard_proton() { Parameterisation params; params.mode = Parameterisation::proton; params.mp = mp_; params.mpi0 = ParticleProperties::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; Parameterisation::Resonance r0; r0.amplitude = 1.04; r0.mass = 1.22991; r0.width = 0.106254; r0.angular_momentum = 1; params.resonances.emplace_back( r0 ); Parameterisation::Resonance r1; r1.amplitude = 0.481327; r1.mass = 1.51015; r1.width = 0.0816620; r1.angular_momentum = 2; params.resonances.emplace_back( r1 ); Parameterisation::Resonance r2; r2.amplitude = 0.655872; r2.mass = 1.71762; r2.width = 0.125520; r2.angular_momentum = 3; params.resonances.emplace_back( r2 ); Parameterisation::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::Parameterisation CLAS::Parameterisation::standard_neutron() { Parameterisation params = standard_proton(); params.mode = Parameterisation::neutron; params.c_slac = { { 0.0640, 0.2250, 4.1060, -7.0790, 3.0550, 1.6421, 0.37636 } }; return params; } CLAS::Parameterisation CLAS::Parameterisation::standard_deuteron() { Parameterisation params = standard_proton(); params.mode = Parameterisation::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(); Parameterisation::Resonance r0; r0.amplitude = 0.74847; r0.mass = 1.2400; r0.width = 0.12115; r0.angular_momentum = 1; params.resonances.emplace_back( r0 ); Parameterisation::Resonance r1; r1.amplitude = 0.011500; r1.mass = 1.4772; r1.width = 0.0069580; r1.angular_momentum = 2; params.resonances.emplace_back( r1 ); Parameterisation::Resonance r2; r2.amplitude = 0.12662; r2.mass = 1.5233; r2.width = 0.084095; r2.angular_momentum = 3; params.resonances.emplace_back( r2 ); Parameterisation::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 CLAS::Parameterisation& params ) : StructureFunctions( Type::CLAS ), params_( params ) {} CLAS& CLAS::operator()( double xbj, double q2 ) { std::pair<double,double> 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<double,double> 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 == Parameterisation::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<double,double> CLAS::resbkg( double q2, double w ) const { const double mp2 = params_.mp*params_.mp, mpi02 = params_.mpi0*params_.mpi0; const double coef = 6.08974; double wth = params_.mp+params_.mpi0; - if ( w < wth ) return std::make_pair( 0., 0. ); - if ( w > 4. ) return std::make_pair( 1., 0. ); + 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 != Parameterisation::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.; for ( unsigned short i = 0; i < params_.resonances.size(); ++i ) { const Parameterisation::Resonance& res = params_.resonances[i]; 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; + 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( coef*qs0, ji ) )/( 1.+pow( coef*qs, ji ) ); f2resn += ai*dg/( ( w-dmi )*( w-dmi )+dg*dg ); } - f2resn *= 0.5*( 1.-params_.b[0] )*bkg2/( params_.mp*M_PI ); + f2resn *= 0.5*( 1.-params_.b[0] )*bkg2/params_.mp*M_1_PI; return std::make_pair( f2bkg, f2resn ); } } } diff --git a/CepGen/StructureFunctions/CLAS.h b/CepGen/StructureFunctions/CLAS.h index d00fa3e..5444cc3 100644 --- a/CepGen/StructureFunctions/CLAS.h +++ b/CepGen/StructureFunctions/CLAS.h @@ -1,65 +1,69 @@ #ifndef CepGen_StructureFunctions_CLAS_h #define CepGen_StructureFunctions_CLAS_h #include "CepGen/StructureFunctions/StructureFunctions.h" #include <array> #include <vector> namespace CepGen { namespace SF { - /// CLAS parameterisation developed to describe nucleon data at \f$Q^2 > 0.5\f$ GeV² and \f$x_{Bj} > 0.15\f$. - /// \note This code was provided on 2016-04-13 by Silvano Simula and - /// reflects the parametrisation used in hep-ph/0301204 (CLAS) and - /// described in hep-ph/9901360. + /// \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 StructureFunctions { public: + /// List of steering parameters for a physics case struct Parameterisation { + /// Standard parameterisation of a parton-from-neutron emission static Parameterisation standard_neutron(); + /// Standard parameterisation of a parton-from-proton emission static Parameterisation standard_proton(); + /// Standard parameterisation of a parton-from-deuteron emission static Parameterisation 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; - double mp, mpi0; + enum { neutron = 0, proton = 1, deuteron = 2 } mode; ///< Nucleon type + double mp; ///< Proton mass + double mpi0; ///< Neutral pion mass // SLAC fit parameters std::array<double,7> c_slac; // CLAS parameterisation double alpha, beta, mu, mup; std::array<double,3> x; std::array<double,4> b; std::vector<Resonance> resonances; std::array<unsigned short,4> lr; }; + /// Standard parameterisation interpolator constructor (photon from proton) explicit CLAS( const CLAS::Parameterisation& params = CLAS::Parameterisation::standard_proton() ); 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<double,double> 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² + /// \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; Parameterisation params_; }; } } #endif diff --git a/CepGen/StructureFunctions/ChristyBosted.h b/CepGen/StructureFunctions/ChristyBosted.h index 173534f..97b97ce 100644 --- a/CepGen/StructureFunctions/ChristyBosted.h +++ b/CepGen/StructureFunctions/ChristyBosted.h @@ -1,83 +1,84 @@ #ifndef CepGen_StructureFunctions_ChristyBosted_h #define CepGen_StructureFunctions_ChristyBosted_h #include "StructureFunctions.h" #include "CepGen/Physics/Constants.h" #include <array> #include <vector> namespace CepGen { namespace SF { + /// \f$F_{2/L}\f$ parameterisation by Christy and Bosted \cite Bosted:2007xd class ChristyBosted : public StructureFunctions { public: struct Parameterisation { static Parameterisation standard(); struct ResonanceParameters { struct BranchingRatios { BranchingRatios() : singlepi( 0. ), doublepi( 0. ), eta( 0. ) {} BranchingRatios( 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; }; ResonanceParameters() : 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 ) ); } BranchingRatios 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<double,5> fit_parameters; }; struct ContinuumParameters { struct DirectionParameters { DirectionParameters() : sig0( 0. ) {} DirectionParameters( double sig0, const std::vector<double>& params ) : sig0( sig0 ), fit_parameters( params ) {} double sig0; std::vector<double> fit_parameters; }; std::array<DirectionParameters,2> transverse; std::array<DirectionParameters,1> longitudinal; }; double m0; std::vector<ResonanceParameters> resonances; ContinuumParameters continuum; }; explicit ChristyBosted( const ChristyBosted::Parameterisation& params = ChristyBosted::Parameterisation::standard() ); ChristyBosted& operator()( double xbj, double q2 ) override; //--- already computed internally during F2 computation void computeFL( double xbj, double q2, const CepGen::SF::SigmaRatio& ) override {} void computeFL( double xbj, double q2, double r ) override {} private: double resmod507( char sf, double w2, double q2 ) const; Parameterisation params_; }; } } #endif diff --git a/CepGen/StructureFunctions/FioreBrasse.h b/CepGen/StructureFunctions/FioreBrasse.h index 0625c17..d1f5e2c 100644 --- a/CepGen/StructureFunctions/FioreBrasse.h +++ b/CepGen/StructureFunctions/FioreBrasse.h @@ -1,45 +1,43 @@ #ifndef CepGen_StructureFunctions_FioreBrasse_h #define CepGen_StructureFunctions_FioreBrasse_h #include "CepGen/StructureFunctions/StructureFunctions.h" #include <vector> namespace CepGen { namespace SF { + ///\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 StructureFunctions { public: struct Parameterisation { static Parameterisation standard(); static Parameterisation alternative(); struct ResonanceParameters { // ResonanceParameters( double a0, double a1, double a2, double a, double q02, float spin ) : // alpha0( a0 ), alpha1( a1 ), alpha2( a2 ), a( a ), q02( q02 ), spin( spin ) {} double alpha0, alpha1, alpha2, a, q02; float spin; }; std::vector<ResonanceParameters> resonances; double s0, norm; }; - /// Fiore-Brasse proton structure functions (F.W Brasse et al., DESY 76/11 (1976), - /// http://dx.doi.org/10.1016/0550-3213(76)90231-5) + /// Fiore \cite Fiore:2002re and Brasse \cite Brasse:1976bf proton structure functions explicit FioreBrasse( const FioreBrasse::Parameterisation& params = FioreBrasse::Parameterisation::standard() ); - /// \param[in] q2 Squared 4-momentum transfer - /// \param[in] xbj Bjorken's x - /// \cite Brasse1976413 FioreBrasse& operator()( double xbj, double q2 ) override; + /// Old implementation from LPAIR FioreBrasse& operator()( double xbj, double q2, bool old ); double W1, W2; Parameterisation params; }; } } #endif diff --git a/CepGen/StructureFunctions/LHAPDF.cpp b/CepGen/StructureFunctions/LHAPDF.cpp index 9c983e4..c251204 100644 --- a/CepGen/StructureFunctions/LHAPDF.cpp +++ b/CepGen/StructureFunctions/LHAPDF.cpp @@ -1,150 +1,159 @@ #include "CepGen/StructureFunctions/LHAPDF.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" namespace CepGen { namespace SF { constexpr std::array<short,6> LHAPDF::qtimes3_, LHAPDF::pdgid_; LHAPDF::Parameterisation::Parameterisation() : - num_flavours( 4 ), pdf_set( "cteq6" ), pdf_member( 0 ), mode( Mode::full ) + num_flavours( 4 ), pdf_set( "cteq6" ), pdf_code( 0l ), pdf_member( 0 ), mode( Mode::full ) {} - LHAPDF::Parameterisation - LHAPDF::Parameterisation::cteq6() - { - Parameterisation p; - p.num_flavours = 4; - p.pdf_set = "cteq6"; - p.pdf_member = 0; - p.mode = Mode::full; - return p; - } - LHAPDF::LHAPDF( const Parameterisation& param ) : StructureFunctions( Type::LHAPDF ), params( param ), initialised_( false ) {} LHAPDF::LHAPDF( const char* set, unsigned short member, const Parameterisation::Mode& mode ) : StructureFunctions( Type::LHAPDF ), initialised_( false ) { params.pdf_set = set; params.pdf_member = member; params.mode = mode; } + std::string + LHAPDF::description() const + { + std::ostringstream os; + os << "LHAPDF{" << params.pdf_set << ",m=" << params.pdf_member << ",mode=" << params.mode << "}"; + return os.str(); + } + void LHAPDF::initialise() { if ( initialised_ ) return; #ifdef LIBLHAPDF std::string lhapdf_version, pdf_description, pdf_type; # if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION == 6 try { + //--- check if PDF code is set + if ( params.pdf_code != 0l ) { + auto pdf = ::LHAPDF::lookupPDF( params.pdf_code ); + if ( pdf.second != 0 ) + throw CG_FATAL( "LHAPDF" ) << "Failed to retrieve PDFset with id=" << params.pdf_code << "!"; + if ( !params.pdf_set.empty() && params.pdf_set != pdf.first ) + CG_WARNING( "LHAPDF" ) << "PDF set name changed from \"" << params.pdf_set << "\" to \"" << pdf.first << "\"."; + params.pdf_set = pdf.first; + } pdf_set_ = ::LHAPDF::PDFSet( params.pdf_set ); pdf_set_.mkPDFs<std::unique_ptr<::LHAPDF::PDF> >( pdfs_ ); lhapdf_version = ::LHAPDF::version(); pdf_description = pdf_set_.description(); pdf_type = pdfs_[params.pdf_member]->type(); } catch ( const ::LHAPDF::Exception& e ) { throw CG_FATAL( "LHAPDF" ) << "Caught LHAPDF exception:\n\t" << e.what(); } # else - ::LHAPDF::initPDFSet( params.pdf_set, ::LHAPDF::LHGRID, params.pdf_member ); + if ( params.pdf_code != 0l ) + ::LHAPDF::initPDFSet( (int)params.pdf_code, params.pdf_member ); + else + ::LHAPDF::initPDFSet( params.pdf_set, ::LHAPDF::LHGRID, params.pdf_member ); lhapdf_version = ::LHAPDF::getVersion(); pdf_description = ::LHAPDF::getDescription(); # endif replace_all( pdf_description, ". ", ".\n " ); CG_INFO( "LHAPDF" ) << "LHAPDF structure functions evaluator successfully built.\n" << " * LHAPDF version: " << lhapdf_version << "\n" << " * number of flavours: " << params.num_flavours << "\n" << " * PDF set: " << params.pdf_set << "\n" << ( pdf_description.empty() ? "" : " "+pdf_description+"\n" ) << " * PDF member: " << params.pdf_member << ( pdf_type.empty() ? "" : " ("+pdf_type+")" ) << "\n" << " * quarks mode: " << params.mode; initialised_ = true; #else throw CG_FATAL( "LHAPDF" ) << "LHAPDF is not liked to this instance!"; #endif } LHAPDF& LHAPDF::operator()( double xbj, double q2 ) { #ifdef LIBLHAPDF std::pair<double,double> nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; F2 = 0.; if ( params.num_flavours == 0 || params.num_flavours > 6 ) return *this; if ( !initialised_ ) initialise(); # if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION >= 6 auto& member = *pdfs_[params.pdf_member]; if ( !member.inPhysicalRangeXQ2( xbj, q2 ) ) { CG_WARNING( "LHAPDF" ) << "(x=" << xbj << ", Q²=" << q2 << " GeV²) " << "not in physical range for PDF member " << params.pdf_member << ":\n\t" << " min: (x=" << member.xMin() << ", Q²=" << member.q2Min() << "),\n\t" << " max: (x=" << member.xMax() << ", Q²=" << member.q2Max() << ")."; return *this; } # else if ( q2 < ::LHAPDF::getQ2min( params.pdf_member ) || q2 > ::LHAPDF::getQ2max( params.pdf_member ) || xbj < ::LHAPDF::getXmin( params.pdf_member ) || xbj > ::LHAPDF::getXmax( params.pdf_member ) ) { CG_WARNING( "LHAPDF" ) << "(x=" << xbj << "/Q²=" << q2 << " GeV²) " << "not in physical range for PDF member " << params.pdf_member << ":\n" << " min: (x=" << ::LHAPDF::getXmin( params.pdf_member ) << "/Q²=" << ::LHAPDF::getQ2min( params.pdf_member ) << "),\n" << " max: (x=" << ::LHAPDF::getXmax( params.pdf_member ) << "/Q²=" << ::LHAPDF::getQ2max( params.pdf_member ) << ")."; return *this; } const double q = sqrt( q2 ); # endif for ( int i = 0; i < params.num_flavours; ++i ) { const double prefactor = 1./9.*qtimes3_[i]*qtimes3_[i]; # if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION >= 6 if ( !pdfs_[params.pdf_member]->hasFlavor( pdgid_[i] ) ) throw CG_FATAL( "LHAPDF" ) << "Flavour " << pdgid_[i] << " is unsupported!"; const double xq = member.xfxQ2( pdgid_[i], xbj, q2 ); const double xqbar = member.xfxQ2( -pdgid_[i], xbj, q2 ); # else const double xq = ::LHAPDF::xfx( xbj, q, pdgid_[i] ); const double xqbar = ::LHAPDF::xfx( xbj, q, -pdgid_[i] ); # endif switch ( params.mode ) { case Parameterisation::Mode::full: F2 += prefactor*( xq+xqbar ); break; case Parameterisation::Mode::valence: F2 += prefactor*( xq-xqbar ); break; case Parameterisation::Mode::sea: F2 += prefactor*( 2.*xqbar ); break; } } #else throw CG_FATAL( "LHAPDF" ) << "LHAPDF is not liked to this instance!"; #endif return *this; } } std::ostream& operator<<( std::ostream& os, const SF::LHAPDF::Parameterisation::Mode& mode ) { switch ( mode ) { case SF::LHAPDF::Parameterisation::Mode::full: return os << "all quarks"; case SF::LHAPDF::Parameterisation::Mode::valence: return os << "valence quarks"; case SF::LHAPDF::Parameterisation::Mode::sea: return os << "sea quarks"; } return os; } } diff --git a/CepGen/StructureFunctions/LHAPDF.h b/CepGen/StructureFunctions/LHAPDF.h index a4e264e..09f8aa1 100644 --- a/CepGen/StructureFunctions/LHAPDF.h +++ b/CepGen/StructureFunctions/LHAPDF.h @@ -1,58 +1,68 @@ #ifndef CepGen_StructureFunctions_LHAPDF_h #define CepGen_StructureFunctions_LHAPDF_h #include "StructureFunctions.h" #ifdef LIBLHAPDF #include "LHAPDF/LHAPDF.h" #endif #include <array> namespace CepGen { namespace SF { - /// Generic, tree-level import of structure functions from an external PDFs grid + /// Generic partonic level perturbative structure functions built from an external PDFs grid class LHAPDF : public StructureFunctions { public: + /// Model parameterisation struct Parameterisation { + /// Standard (usual CTEQ6) constructor Parameterisation(); - static Parameterisation cteq6(); + /// Number of quark flavours considered in the SF building unsigned short num_flavours; + /// String-type PDF identifier (default) std::string pdf_set; + /// Integer-type PDF identifier (if no string version is provided) + unsigned long pdf_code; + /// PDF set used unsigned short pdf_member; + /// Quarks types enum class Mode { full = 0, valence = 1, sea = 2 }; + /// Quarks types considered in the SF building Mode mode; }; - - explicit LHAPDF( const Parameterisation& param = Parameterisation::cteq6() ); + /// Build a calculator from its Parameterisation object + explicit LHAPDF( const Parameterisation& param = Parameterisation() ); + /// Build a calculator from a set, its member, and the contributing quarks explicit LHAPDF( const char* set, unsigned short member = 0, const Parameterisation::Mode& mode = Parameterisation::Mode::full ); LHAPDF& operator()( double xbj, double q2 ) override; - + /// Parameterisation used in this SFs calculator Parameterisation params; private: + std::string description() const override; void initialise(); bool initialised_; #ifdef LIBLHAPDF # if defined LHAPDF_MAJOR_VERSION && LHAPDF_MAJOR_VERSION >= 6 ::LHAPDF::PDFSet pdf_set_; std::vector<std::unique_ptr<::LHAPDF::PDF> > pdfs_; # endif #endif static constexpr std::array<short,6> pdgid_ = { { 1, 2, 3, 4, 5, 6 } }; static constexpr std::array<short,6> qtimes3_ = { { -1 /*d*/, 2 /*u*/, -1 /*s*/, 2 /*c*/, -1 /*b*/, 2 /*t*/ } }; }; } std::ostream& operator<<( std::ostream& os, const SF::LHAPDF::Parameterisation::Mode& mode ); } #endif diff --git a/CepGen/StructureFunctions/MSTWGrid.cpp b/CepGen/StructureFunctions/MSTWGrid.cpp index 8d20cac..41e56ec 100644 --- a/CepGen/StructureFunctions/MSTWGrid.cpp +++ b/CepGen/StructureFunctions/MSTWGrid.cpp @@ -1,113 +1,116 @@ #include "CepGen/StructureFunctions/MSTWGrid.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include <fstream> -#include <set> namespace mstw { const unsigned int Grid::good_magic = 0x5754534d; // MSTW in ASCII Grid& Grid::get( const char* filename ) { Parameterisation p; p.grid_path = filename; static Grid instance( p ); return instance; } Grid::Grid( const Parameterisation& param ) : CepGen::StructureFunctions( CepGen::SF::Type::MSTWgrid ), CepGen::GridHandler<2,2>( CepGen::GridType::logarithmic ), params( param ) { - std::set<double> q2_vals, xbj_vals; - { // file readout part std::ifstream file( params.grid_path, std::ios::binary | std::ios::in ); if ( !file.is_open() ) throw CG_FATAL( "Grid" ) << "Impossible to load grid file \"" << params.grid_path << "\"!"; file.read( reinterpret_cast<char*>( &header_ ), sizeof( header_t ) ); // first checks on the file header if ( header_.magic != good_magic ) throw CG_FATAL( "Grid" ) << "Wrong magic number retrieved: " << header_.magic << ", expecting " << good_magic << "."; if ( header_.nucleon != header_t::proton ) throw CG_FATAL( "Grid" ) << "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<char*>( &val ), sizeof( sfval_t ) ) ) { - q2_vals.insert( val.q2 ); - xbj_vals.insert( val.xbj ); + while ( file.read( reinterpret_cast<char*>( &val ), sizeof( sfval_t ) ) ) insert( { val.xbj, val.q2 }, { val.f2, val.fl } ); - } file.close(); } - if ( q2_vals.size() < 2 || xbj_vals.size() < 2 ) - throw CG_FATAL( "Grid" ) << "Invalid grid retrieved!"; - init(); + const auto& bounds = boundaries(); CG_INFO( "Grid" ) << "MSTW@" << header_.order << " grid evaluator built " << "for " << header_.nucleon << " structure functions (" << header_.cl << ")\n\t" - << "xBj in range [" << pow( 10., *xbj_vals.begin() ) << ":" << pow( 10., *xbj_vals.rbegin() ) << "]\n\t" - << " Q² in range [" << pow( 10., *q2_vals.begin() ) << ":" << pow( 10., *q2_vals.rbegin() ) << "]."; + << "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 ) << "<xbj<" << pow( 10., bounds[0].second ) << "," + << pow( 10., bounds[1].first ) << "<Q²/GeV²<" << pow( 10., bounds[1].second ) << "}"; + return os.str(); } Grid& Grid::operator()( double xbj, double q2 ) { const std::array<double,2> 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\tFL = % .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; } } diff --git a/CepGen/StructureFunctions/MSTWGrid.h b/CepGen/StructureFunctions/MSTWGrid.h index 68f31e1..42962d7 100644 --- a/CepGen/StructureFunctions/MSTWGrid.h +++ b/CepGen/StructureFunctions/MSTWGrid.h @@ -1,72 +1,82 @@ #ifndef CepGen_StructureFunctions_MSTWGrid_h #define CepGen_StructureFunctions_MSTWGrid_h #include "CepGen/IO/GridHandler.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #define DEFAULT_MSTW_GRID_PATH "External/mstw_sf_scan_nnlo.dat" /// Martin-Stirling-Thorne-Watt PDFs structure functions namespace mstw { /// A \f$F_{2,L}\f$ grid interpolator class Grid : public CepGen::StructureFunctions, 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; - order_t order; - cl_t cl; - nucleon_t nucleon; + 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, xbj; - double f2, fl; + 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 }; + /// List of parameters for this grid definition struct Parameterisation { Parameterisation() : grid_path( DEFAULT_MSTW_GRID_PATH ) {} + /// Location of the grid to be interpolated std::string grid_path; }; public: /// Retrieve the grid interpolator (singleton) static Grid& get( const char* path = DEFAULT_MSTW_GRID_PATH ); /// 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 Parameterisation params; //--- already retrieved from grid, so no need to recompute it void computeFL( double xbj, double q2, const CepGen::SF::SigmaRatio& ) override {} void computeFL( double xbj, double q2, double r ) override {} public: Grid( const Grid& ) = delete; void operator=( const GridHandler& ) = delete; private: explicit Grid( const Parameterisation& = Parameterisation() ); + std::string description() const override; static const unsigned int good_magic; static std::shared_ptr<Grid> singl_; header_t header_; }; - std::ostream& operator<<( std::ostream&, const Grid::sfval_t& ); - std::ostream& operator<<( std::ostream&, const Grid::header_t::order_t& ); - std::ostream& operator<<( std::ostream&, const Grid::header_t::cl_t& ); - std::ostream& operator<<( std::ostream&, const Grid::header_t::nucleon_t& ); + 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 } #undef DEFAULT_MSTW_GRID_PATH #endif diff --git a/CepGen/StructureFunctions/Schaefer.cpp b/CepGen/StructureFunctions/Schaefer.cpp index a56e8b3..95f943a 100644 --- a/CepGen/StructureFunctions/Schaefer.cpp +++ b/CepGen/StructureFunctions/Schaefer.cpp @@ -1,137 +1,151 @@ #include "CepGen/StructureFunctions/Schaefer.h" #include "CepGen/StructureFunctions/StructureFunctionsBuilder.h" #include "CepGen/StructureFunctions/LHAPDF.h" #include "CepGen/Core/Exception.h" #include "CepGen/Physics/Constants.h" #include "CepGen/Physics/ParticleProperties.h" namespace CepGen { namespace SF { Schaefer::Parameterisation Schaefer::Parameterisation::mstwGrid() { Parameterisation par; par.q2_cut = 9.; par.w2_hi = 4.; par.w2_lo = 3.; par.resonances_model = StructureFunctionsBuilder::get( SF::Type::ChristyBosted ); par.perturbative_model = StructureFunctionsBuilder::get( SF::Type::MSTWgrid ); par.continuum_model = StructureFunctionsBuilder::get( SF::Type::GD11p ); par.higher_twist = 0; return par; } Schaefer::Parameterisation Schaefer::Parameterisation::mstwParton() { Parameterisation par; par.q2_cut = 9.; par.w2_hi = 4.; par.w2_lo = 3.; par.resonances_model = StructureFunctionsBuilder::get( SF::Type::ChristyBosted ); par.perturbative_model = std::make_shared<SF::LHAPDF>( "MSTW2008nnlo90cl" ); par.continuum_model = StructureFunctionsBuilder::get( SF::Type::GD11p ); par.higher_twist = 1; return par; } Schaefer::Parameterisation Schaefer::Parameterisation::cteq() { Parameterisation par; par.q2_cut = 9.; par.w2_hi = 4.; par.w2_lo = 3.; par.resonances_model = StructureFunctionsBuilder::get( SF::Type::ChristyBosted ); par.perturbative_model = std::make_shared<SF::LHAPDF>( "cteq6l1" ); par.continuum_model = StructureFunctionsBuilder::get( SF::Type::GD11p ); par.higher_twist = 0; return par; } Schaefer::Schaefer( const Schaefer::Parameterisation& params ) : StructureFunctions( Type::Schaefer ), params( params ), initialised_( false ), inv_omega_range_( -1. ) {} + std::string + Schaefer::description() const + { + std::ostringstream os; + os << "LUXlike{" + << "r=" << *params.resonances_model << "," + << "p=" << *params.perturbative_model << "," + << "c=" << *params.continuum_model; + if ( params.higher_twist ) + os << ",HT"; + os << "}"; + return os.str(); + } + void Schaefer::initialise() { CG_INFO( "LUXlike" ) << "LUXlike structure functions evaluator successfully initialised.\n" << " * Q² cut: " << params.q2_cut << " GeV²\n" << " * W² ranges: " << params.w2_lo << " GeV² / " << params.w2_hi << " GeV²\n" - << " * resonance model: " << params.resonances_model->type << "\n" - << " * perturbative model: " << params.perturbative_model->type << "\n" - << " * continuum model: " << params.continuum_model->type << "\n" + << " * resonance model: " << *params.resonances_model << "\n" + << " * perturbative model: " << *params.perturbative_model << "\n" + << " * continuum model: " << *params.continuum_model << "\n" << " * higher-twist? " << std::boolalpha << params.higher_twist; inv_omega_range_ = 1./( params.w2_hi-params.w2_lo ); initialised_ = true; } Schaefer& Schaefer::operator()( double xbj, double q2 ) { if ( !initialised_ ) initialise(); std::pair<double,double> nv = { xbj, q2 }; if ( nv == old_vals_ ) return *this; old_vals_ = nv; const double w2 = mp2_+q2*( 1.-xbj )/xbj; StructureFunctions sel_sf; if ( q2 < params.q2_cut ) { if ( w2 < params.w2_lo ) sel_sf = ( *params.resonances_model )( xbj, q2 ); else if ( w2 < params.w2_hi ) { auto sf_r = ( *params.resonances_model )( xbj, q2 ); auto sf_c = ( *params.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 = ( *params.continuum_model )( xbj, q2 ); } else { if ( w2 < params.w2_hi ) sel_sf = ( *params.continuum_model )( xbj, q2 ); else { auto sf_p = ( *params.perturbative_model )( xbj, q2 ); F2 = sf_p.F2; sf_p.computeFL( xbj, q2 ); FL = sel_sf.FL; if ( params.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: " << params.w2_lo << " / " << params.w2_hi << " GeV²!"; const double omega = ( w2-params.w2_lo )*inv_omega_range_; const double omega2 = omega*omega; return 2.*omega2-omega*omega; } } } diff --git a/CepGen/StructureFunctions/Schaefer.h b/CepGen/StructureFunctions/Schaefer.h index 8ae678b..34bbf6b 100644 --- a/CepGen/StructureFunctions/Schaefer.h +++ b/CepGen/StructureFunctions/Schaefer.h @@ -1,37 +1,44 @@ #ifndef CepGen_StructureFunctions_Schaefer_h #define CepGen_StructureFunctions_Schaefer_h -#include "StructureFunctions.h" +#include "CepGen/StructureFunctions/StructureFunctions.h" #include <memory> namespace CepGen { namespace SF { + /// LUX-like hybrid modelling of \f$F_{2/L}\f$ structure functions class Schaefer : public StructureFunctions { public: + /// Standard parameterisation for this SF set struct Parameterisation { - static Parameterisation mstwGrid(); - static Parameterisation mstwParton(); - static Parameterisation cteq(); - double q2_cut, w2_lo, w2_hi; - std::shared_ptr<StructureFunctions> resonances_model, perturbative_model, continuum_model; - bool higher_twist; + static Parameterisation mstwGrid(); ///< "Standard" parameterisation with MSTW grid NNLO perturbative model + static Parameterisation mstwParton(); ///< "Standard" parameterisation with partonic MSTW perturbative model + static Parameterisation cteq(); ///< "Standard" parameterisation with partonic CTEQ perturbative model + double q2_cut; ///< Transition \f$Q^2\f$ before reaching the continuum/perturbative regions + double w2_lo; ///< Transition \f$W^2\f$ between resonances and hybrid continuum/resonances low-\f$Q^2\f$ regions + double w2_hi; ///< Transition \f$W^2\f$ between hybrid continuum/resonances and continuum low-\f$Q^2\f$ regions, or continuum and perturbative high-\f$Q^2\f$ regions + std::shared_ptr<StructureFunctions> resonances_model; ///< Resonances-dominated region (low-\f$Q^2/W^2\f$) modelling + std::shared_ptr<StructureFunctions> perturbative_model; ///< Perturbative region (high-\f$Q^2/W^2\f$) modelling + std::shared_ptr<StructureFunctions> continuum_model; ///< Continuum regions modelling + bool higher_twist; ///< Enable/disable the HT correction }; Schaefer( const Parameterisation& param = Parameterisation::mstwGrid() ); Schaefer& operator()( double xbj, double q2 ) override; Parameterisation params; private: + std::string description() const override; double rho( double w2 ) const; void initialise(); bool initialised_; double inv_omega_range_; }; } } #endif diff --git a/CepGen/StructureFunctions/SigmaRatio.cpp b/CepGen/StructureFunctions/SigmaRatio.cpp index f1f7fb3..eb874e1 100644 --- a/CepGen/StructureFunctions/SigmaRatio.cpp +++ b/CepGen/StructureFunctions/SigmaRatio.cpp @@ -1,103 +1,104 @@ #include "CepGen/StructureFunctions/SigmaRatio.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/ParticleProperties.h" #include <math.h> #include <iostream> namespace CepGen { namespace SF { const double SigmaRatio::mp_ = ParticleProperties::mass( PDG::proton ); const double SigmaRatio::mp2_ = SigmaRatio::mp_*SigmaRatio::mp_; double SigmaRatio::theta( double xbj, double q2 ) const { return 1.+12.*( q2/( q2+1. ) )*( 0.125*0.125/( 0.125*0.125+xbj*xbj ) ); } E143Ratio::Parameterisation E143Ratio::Parameterisation::standard() { Parameterisation out; out.q2_b = 0.34; out.lambda2 = 0.2*0.2; out.a = { { 0.0485, 0.5470, 2.0621, -0.3804, 0.5090, -0.0285 } }; out.b = { { 0.0481, 0.6114, -0.3509, -0.4611, 0.7172, -0.0317 } }; out.c = { { 0.0577, 0.4644, 1.8288, 12.3708, -43.1043, 41.7415 } }; return out; } E143Ratio::E143Ratio( const Parameterisation& param ) : params_( param ) {} double E143Ratio::operator()( double xbj, double q2, double& err ) const { const double u = q2/params_.q2_b; const double inv_xl = 1./log( q2/params_.lambda2 ); const double pa = ( 1.+params_.a[3]*xbj+params_.a[4]*xbj*xbj )*pow( xbj, params_.a[5] ); const double pb = ( 1.+params_.b[3]*xbj+params_.b[4]*xbj*xbj )*pow( xbj, params_.b[5] ); const double theta = SigmaRatio::theta( xbj, q2 ); const double q2_thr = params_.c[3]*xbj + params_.c[4]*xbj*xbj+params_.c[5]*xbj*xbj*xbj; // here come the three fits const double ra = params_.a[0]*inv_xl*theta + params_.a[1]/pow( pow( q2, 4 )+pow( params_.a[2], 4 ), 0.25 )*pa, rb = params_.b[0]*inv_xl*theta + ( params_.b[1]/q2+params_.b[2]/( q2*q2+0.3*0.3 ) )*pb, rc = params_.c[0]*inv_xl*theta + params_.c[1]*pow( pow( q2-q2_thr, 2 )+pow( params_.c[2], 2 ), -0.5 ); const double r = ( ra+rb+rc ) / 3.; // R is set to be the average of the three fits // numerical safety for low-Q² err = 0.0078-0.013*xbj+( 0.070-0.39*xbj+0.70*xbj*xbj )/( 1.7+q2 ); if ( q2 > params_.q2_b ) return r; return r * 0.5 * ( 3.*u-u*u*u ); } R1990Ratio::Parameterisation R1990Ratio::Parameterisation::standard() { Parameterisation out; out.lambda2 = 0.2*0.2; out.b = { { 0.0635, 0.5747, -0.3534 } }; return out; } R1990Ratio::R1990Ratio( const Parameterisation& param ) : params_( param ) {} double R1990Ratio::operator()( double xbj, double q2, double& err ) const { err = 0.; return ( params_.b[0]+SigmaRatio::theta( xbj, q2 )/log( q2/params_.lambda2 ) + params_.b[1]/q2 + params_.b[2]/( q2*q2+0.09 ) ); } double CLASRatio::operator()( double xbj, double q2, double& err ) const { // 2 kinematic regions: // - resonances ( w < 2.5 ) // - DIS ( w > 2.5 ) const double w2 = mp2_ + q2*( 1.-xbj )/xbj, w = sqrt( w2 ); const double xth = q2/( q2+2.5*2.5-mp2_ ); // xth = x( W = 2.5 GeV ) const double zeta = log( 25.*q2 ); const double xitmp = ( w < 2.5 ) ? theta( xth, q2 ) : theta( xbj, q2 ); const double tmp = 0.041*xitmp/zeta + 0.592/q2 - 0.331/( 0.09+q2*q2 ); - if ( w < 2.5 ) return tmp * pow( ( 1.-xbj )/( 1.-xth ), 3 ); + if ( w < 2.5 ) + return tmp * pow( ( 1.-xbj )/( 1.-xth ), 3 ); return tmp; } double SBRatio::operator()( double xbj, double q2, double& err ) const { err = 0.; return 0.014*q2*( exp( -0.07*q2 )+41.*exp( -0.8*q2 ) ); } } } diff --git a/CepGen/StructureFunctions/SigmaRatio.h b/CepGen/StructureFunctions/SigmaRatio.h index 22ee12f..45af95d 100644 --- a/CepGen/StructureFunctions/SigmaRatio.h +++ b/CepGen/StructureFunctions/SigmaRatio.h @@ -1,76 +1,79 @@ #ifndef CepGen_StructureFunctions_SigmaRatio_h #define CepGen_StructureFunctions_SigmaRatio_h #include <array> namespace CepGen { namespace SF { + /// A generic modelling of the \f$R=\sigma_L/\sigma_T\f$ ratio class SigmaRatio { public: SigmaRatio() {} - /// Extract the longitudinal/transverse cross section ratio and associated error for a given Q²/\f$x_{\textrm{Bj}}\f$ couple. + /// Extract the longitudinal/transverse cross section ratio and associated error for a given \f$(x_{\rm Bj},Q^2)\f$ couple. virtual double operator()( double xbj, double q2, double& err ) const = 0; protected: - /// \f$x_{\textrm{Bj}}\f$ dependence for QCD-matching of R at high-Q² + /// \f$x_{\rm Bj}\f$ dependence for QCD-matching of R at high-\f$Q^2\f$ double theta( double xbj, double q2 ) const; - static const double mp_, mp2_; + 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$ }; - // Reference: arXiv:hep-ex/9808028 + /// E143 experimental R measurement \cite Abe:1998ym class E143Ratio : public SigmaRatio { public: struct Parameterisation { double q2_b, lambda2; std::array<double,6> a, b, c; static Parameterisation standard(); }; explicit E143Ratio( const Parameterisation& param = Parameterisation::standard() ); double operator()( double xbj, double q2, double& err ) const override; private: Parameterisation params_; }; - /// \warning valid for Q² > 0.3 GeV² - // Reference: Phys.Lett. B 250 (1990) 193-198 (https://inspirehep.net/record/296980) + /** \brief SLAC experimental R measurement \cite Whitlow:1990gk + * \warning valid for \f$Q^2\f$ > 0.3 GeV\f${}^2\f$ + */ class R1990Ratio: public SigmaRatio { public: struct Parameterisation { double lambda2; std::array<double,3> b; static Parameterisation standard(); }; explicit R1990Ratio( const Parameterisation& param = Parameterisation::standard() ); double operator()( double xbj, double q2, double& err ) const override; private: Parameterisation params_; }; + /// CLAS experimental R measurement class CLASRatio : public SigmaRatio { public: CLASRatio() {} double operator()( double xbj, double q2, double& err ) const override; }; - /// Sibirtsev & Blunden parameterisation of the R ratio - // Reference: Phys.Rev. C 88,065202 (2013) + /// Sibirtsev & Blunden parameterisation of the R ratio \cite Sibirtsev:2013cga class SBRatio : public SigmaRatio { public: SBRatio() {} double operator()( double xbj, double q2, double& err ) const override; }; } } #endif diff --git a/CepGen/StructureFunctions/StructureFunctions.cpp b/CepGen/StructureFunctions/StructureFunctions.cpp index f98c2ed..6d6c31c 100644 --- a/CepGen/StructureFunctions/StructureFunctions.cpp +++ b/CepGen/StructureFunctions/StructureFunctions.cpp @@ -1,75 +1,88 @@ #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/PDG.h" #include "CepGen/Physics/ParticleProperties.h" #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include <iostream> namespace CepGen { const double StructureFunctions::mp_ = ParticleProperties::mass( PDG::proton ); const double StructureFunctions::mp2_ = StructureFunctions::mp_*StructureFunctions::mp_; double StructureFunctions::F1( double xbj, double q2 ) const { if ( xbj == 0. || q2 == 0. ) { CG_ERROR( "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; } void StructureFunctions::computeFL( double xbj, double q2, const SF::SigmaRatio& ratio ) { double r_error = 0.; computeFL( xbj, q2, ratio( xbj, q2, r_error ) ); } void StructureFunctions::computeFL( double xbj, double q2, double r ) { const double tau = 4.*xbj*xbj*mp2_/q2; FL = F2 * ( 1.+tau ) * ( r/( 1.+r ) ); } + std::string + StructureFunctions::description() const + { + std::ostringstream os; + os << type; + return os.str(); + } + /// Human-readable format of a structure function object std::ostream& operator<<( std::ostream& os, const StructureFunctions& sf ) { - return os << "F2 = " << sf.F2 << ", FL = " << sf.FL; + os << sf.description(); + if ( sf.old_vals_ != std::pair<double,double>() ) + 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 SF::Type& sf ) { switch ( sf ) { case SF::Type::Invalid: return os << "[INVALID]"; case SF::Type::Electron: return os << "electron"; case SF::Type::ElasticProton: return os << "elastic proton"; case SF::Type::SuriYennie: return os << "Suri-Yennie"; case SF::Type::SzczurekUleshchenko: return os << "Szczurek-Uleshchenko"; case SF::Type::FioreBrasse: return os << "Fiore-Brasse"; case SF::Type::ChristyBosted: return os << "Christy-Bosted"; case SF::Type::CLAS: return os << "CLAS"; case SF::Type::BlockDurandHa: return os << "BDH"; case SF::Type::ALLM91: return os << "ALLM91"; case SF::Type::ALLM97: return os << "ALLM97"; case SF::Type::GD07p: return os << "GD07p"; case SF::Type::GD11p: return os << "GD11p"; case SF::Type::Schaefer: return os << "LUXlike"; case SF::Type::MSTWgrid: return os << "MSTW (grid)"; case SF::Type::LHAPDF: return os << "LHAPDF"; } return os; } } diff --git a/CepGen/StructureFunctions/StructureFunctions.h b/CepGen/StructureFunctions/StructureFunctions.h index 0d16122..cebbddf 100644 --- a/CepGen/StructureFunctions/StructureFunctions.h +++ b/CepGen/StructureFunctions/StructureFunctions.h @@ -1,71 +1,86 @@ #ifndef CepGen_StructureFunctions_StructureFunctions_h #define CepGen_StructureFunctions_StructureFunctions_h #include "CepGen/StructureFunctions/SigmaRatio.h" #include <iostream> #include <map> namespace CepGen { + /// Structure functions modelling scope namespace SF { /// 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, LHAPDF = 401, }; } std::ostream& operator<<( std::ostream&, const SF::Type& ); class StructureFunctionsFactory; + /// Generic placeholder for the parameterisation of nucleon structure functions class StructureFunctions { public: + /// Copy constructor StructureFunctions( const StructureFunctions& sf ) : type( sf.type ), F2( sf.F2 ), FL( sf.FL ), old_vals_( sf.old_vals_ ) {} + /// Standard SF parameterisation constructor StructureFunctions( const SF::Type& type = SF::Type::Invalid, double f2 = 0., double fl = 0. ) : type( type ), F2( f2 ), FL( fl ), old_vals_({ 0., 0. }) {} ~StructureFunctions() {} + /// Human-readable description of this SF parameterisation + friend std::ostream& operator<<( std::ostream&, const StructureFunctions& ); + /// Assign from another SF parameterisation object StructureFunctions& operator=( const StructureFunctions& sf ) { type = sf.type, F2 = sf.F2, FL = sf.FL, old_vals_ = sf.old_vals_; return *this; } + /// Build a SF parameterisation for a given type static StructureFunctions builder( const SF::Type& ); + /// Compute all relevant structure functions for a given \f$(x_{\rm Bj},Q^2)\f$ couple virtual StructureFunctions& operator()( double xbj, double q2 ) { return *this; } + /// Compute the longitudinal structure function for a given point virtual void computeFL( double xbj, double q2, const SF::SigmaRatio& ratio = SF::E143Ratio() ); + /// Compute the longitudinal structure function for a given point virtual void 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; + /// Interpolation type of structure functions SF::Type type; - double F2, FL; + double F2; ///< Last computed transverse structure function value + double FL; ///< Last computed longitudinal structure function value protected: - static const double mp_, mp2_; - std::pair<double,double> old_vals_; + virtual std::string description() const; ///< Human-readable description of this SF set + 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$ + std::pair<double,double> old_vals_; ///< Last \f$(x_{\rm Bj},Q^2)\f$ couple computed private: std::string name_; }; - std::ostream& operator<<( std::ostream&, const StructureFunctions& ); } #endif diff --git a/CepGen/StructureFunctions/SuriYennie.h b/CepGen/StructureFunctions/SuriYennie.h index df29643..c2c5036 100644 --- a/CepGen/StructureFunctions/SuriYennie.h +++ b/CepGen/StructureFunctions/SuriYennie.h @@ -1,31 +1,35 @@ #ifndef CepGen_StructureFunctions_SuriYennie_h #define CepGen_StructureFunctions_SuriYennie_h #include "StructureFunctions.h" namespace CepGen { namespace SF { + /// \f$F_{1/2/E/M}\f$ modelling by Suri and Yennie \cite Suri:1971yx class SuriYennie : public StructureFunctions { public: + /// Collection of parameterisation-dependent couplings struct Parameterisation { // values extracted from experimental fits static Parameterisation standard(); static Parameterisation alternative(); double C1, C2, D1, rho2, Cp, Bp; }; explicit SuriYennie( const SuriYennie::Parameterisation& param = SuriYennie::Parameterisation::standard() ); SuriYennie& operator()( double xbj, double q2 ) override; - double F1, FE, FM; + double F1; + double FE; ///< Electric proton form factor + double FM; ///< Magnetic proton form factor private: Parameterisation params_; }; } } #endif diff --git a/CepGen/StructureFunctions/SzczurekUleshchenko.h b/CepGen/StructureFunctions/SzczurekUleshchenko.h index 38e08ec..ba6b032 100644 --- a/CepGen/StructureFunctions/SzczurekUleshchenko.h +++ b/CepGen/StructureFunctions/SzczurekUleshchenko.h @@ -1,26 +1,27 @@ #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 SF { + /// Szcurek and Uleshchenko modelling of \f$F_{1/2}\f$ \cite Szczurek:1999wp class SzczurekUleshchenko : public StructureFunctions { public: SzczurekUleshchenko(); SzczurekUleshchenko& operator()( double xbj, double q2 ) override; double F1; }; } } #endif diff --git a/CepGen/Version.h b/CepGen/Version.h index 1c81b6c..64fd762 100644 --- a/CepGen/Version.h +++ b/CepGen/Version.h @@ -1,13 +1,18 @@ #ifndef CepGen_Version_h #define CepGen_Version_h #include <string> namespace CepGen { + /// CepGen version + /// \note Format: 0xMMmmff, with + /// - MM = major version + /// - mm = minor version + /// - ff = feature(s) release const unsigned int cepgen_version = 0x000900; - + /// Human-readable version number const std::string version(); } #endif diff --git a/External/Processes/CepGenWrapper.cpp b/External/Processes/CepGenWrapper.cpp new file mode 100644 index 0000000..023699c --- /dev/null +++ b/External/Processes/CepGenWrapper.cpp @@ -0,0 +1,32 @@ +#include "CepGen/Processes/FortranProcesses.h" +#include "CepGen/Core/Exception.h" + +//================================================================================================= +// START BY LISTING ALL FORTRAN SUBROUTINES // +// usage: // +// DECLARE_FORTRAN_SUBROUTINE( subroutine_name ) // +// with the Fortran subroutine name written in lowercase (no trailing '_' necessary) // +//================================================================================================= + +DECLARE_FORTRAN_SUBROUTINE( nucl_to_ff ) + +//================================================================================================= +BEGIN_FORTRAN_PROCESSES_ENUM // +// START THE MAPPING name -> Fortran SUBROUTINE // +// usage: // +// REGISTER_FORTRAN_PROCESS( "name", subroutine_name, "description ) // +//================================================================================================= + +REGISTER_FORTRAN_PROCESS( "patoff", nucl_to_ff, "pA ↝ (g/ɣ)ɣ → f⁺f¯" ) +REGISTER_FORTRAN_PROCESS( "aptoff", nucl_to_ff, "Ap ↝ ɣ(g/ɣ) → f⁺f¯" ) +REGISTER_FORTRAN_PROCESS( "aatoff", nucl_to_ff, "AA ↝ ɣɣ → f⁺f¯" ) + +//================================================================================================= +// DO NOT EDIT BELOW THIS LINE // +std::ostringstream os; // +for ( auto& proc : Process::FortranProcessesHandler::get().list() ) // + os << "\n *) " << proc.name << ": " << proc.description; // +CG_DEBUG( "FortranProcesses" ) << "List of Fortran processes registered:" << os.str(); // +END_FORTRAN_PROCESSES_ENUM // +//================================================================================================= + diff --git a/CepGen/Processes/Fortran/nucl_to_ff.f b/External/Processes/nucl_to_ff.f similarity index 100% rename from CepGen/Processes/Fortran/nucl_to_ff.f rename to External/Processes/nucl_to_ff.f diff --git a/cmake/UseEnvironment.cmake b/cmake/UseEnvironment.cmake index 5fa5738..8432e25 100644 --- a/cmake/UseEnvironment.cmake +++ b/cmake/UseEnvironment.cmake @@ -1,104 +1,104 @@ set(LXPLUS_GCC_ENV "source /afs/cern.ch/sw/lcg/external/gcc/4.9.3/x86_64-slc6-gcc49-opt/setup.sh") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wall -cpp") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic-errors -g") else() if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic-errors -g") else() message(STATUS "gcc version >= 4.7 is required") if($ENV{HOSTNAME} MATCHES "^lxplus[0-9]+.cern.ch") message(STATUS "Compiling on LXPLUS. Did you properly source the environment variables?") message(STATUS "e.g. `${LXPLUS_GCC_ENV}`") endif() message(FATAL_ERROR "Please clean up this build environment and try again...") endif() endif() if(NOT CMAKE_VERSION VERSION_LESS 3.1) set(CMAKE_CXX_STANDARD 11) else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() if($ENV{HOSTNAME} MATCHES "^lxplus[0-9]+.cern.ch") set(BASE_DIR "/afs/cern.ch/sw/lcg/external") list(APPEND CMAKE_PREFIX_PATH "${BASE_DIR}/CMake/2.8.9/Linux-i386/share/cmake-2.8/Modules") set(GSL_DIR "${BASE_DIR}/GSL/2.2.1/x86_64-slc6-gcc48-opt") set(HEPMC_DIR "${BASE_DIR}/HepMC/2.06.08/x86_64-slc6-gcc48-opt") #set(LHAPDF_DIR "${BASE_DIR}/MCGenerators/lhapdf/5.8.9/x86_64-slc6-gcc46-opt") set(LHAPDF_DIR "${BASE_DIR}/MCGenerators_lcgcmt67c/lhapdf/6.2.0/x86_64-slc6-gcc48-opt") set(PYTHIA8_DIR "${BASE_DIR}/MCGenerators_lcgcmt67c/pythia8/230/x86_64-slc6-gcc48-opt") set(PYTHON_DIR "${BASE_DIR}/Python/2.7.4/x86_64-slc6-gcc48-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") set(ROOTSYS "${BASE_DIR}/../app/releases/ROOT/6.06.08/x86_64-slc6-gcc49-opt/root") message(STATUS "Compiling on LXPLUS. Do not forget to source the environment variables!") message(STATUS "e.g. `${LXPLUS_GCC_ENV}`") #--- 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) #--- 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 HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES lib) find_path(HEPMC_INCLUDE HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES include) else() find_library(GSL_LIB gsl REQUIRED) find_library(GSL_CBLAS_LIB gslcblas) find_library(LHAPDF LHAPDF) find_path(LHAPDF_INCLUDE LHAPDF) find_library(HEPMC_LIB HepMC) find_path(HEPMC_INCLUDE HepMC) endif() #--- 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) message(STATUS "GSL found in ${GSL_LIB}") list(APPEND CEPGEN_EXTERNAL_IO_REQS ${GSL_LIB} ${GSL_CBLAS_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) if(PYTHONLIBS_FOUND) list(APPEND CEPGEN_EXTERNAL_CARDS_REQS ${PYTHON_LIBRARIES}) add_definitions(-DPYTHON) message(STATUS "Python v${PYTHONLIBS_VERSION_STRING} found") include_directories(${PYTHON_INCLUDE_DIRS}) endif() if(PYTHIA8) - message(STATUS "Pythia8 found in ${PYTHIA8}") + message(STATUS "Pythia 8 found in ${PYTHIA8}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-misleading-indentation") list(APPEND CEPGEN_EXTERNAL_HADR_REQS ${PYTHIA8} dl) add_definitions(-DPYTHIA8) include_directories(${PYTHIA8_INCLUDE}) endif() if(HEPMC_LIB) message(STATUS "HepMC found in ${HEPMC_INCLUDE}") list(APPEND CEPGEN_EXTERNAL_IO_REQS ${HEPMC_LIB}) add_definitions(-DLIBHEPMC) include_directories(${HEPMC_INCLUDE}) endif() find_library(MUPARSER muparser) if(MUPARSER) message(STATUS "muParser found in ${MUPARSER}") list(APPEND CEPGEN_EXTERNAL_CORE_REQS ${MUPARSER}) add_definitions(-DMUPARSER) endif() set(ALPHAS_PATH ${PROJECT_SOURCE_DIR}/External) file(GLOB alphas_sources ${ALPHAS_PATH}/alphaS.f) if(alphas_sources) message(STATUS "alpha(s) evolution found in ${alphas_sources}") add_definitions(-DALPHA_S) endif() diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..cd0ecdb --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +html* +latex/* diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in new file mode 100644 index 0000000..3bae15f --- /dev/null +++ b/docs/Doxyfile.in @@ -0,0 +1,2483 @@ +# Doxyfile 1.8.14 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "CepGen" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 0.9 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "A generic central exclusive processes event generator" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/docs/small-cepgen-logo.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = @CMAKE_CURRENT_SOURCE_DIR@/docs/ + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = YES + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = @CMAKE_CURRENT_SOURCE_DIR@/docs/bibliography.bib + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @CMAKE_CURRENT_SOURCE_DIR@ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = @CMAKE_CURRENT_BINARY_DIR@ + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: https://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: https://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = LIBLHAPDF=1 PYTHON=1 \ + PYTHIA8=1 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = YES + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = YES + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/docs/bibliography.bib b/docs/bibliography.bib new file mode 100644 index 0000000..616ab5d --- /dev/null +++ b/docs/bibliography.bib @@ -0,0 +1,276 @@ +@article{Lepage:1977sw, + author = "Lepage, G. Peter", + title = "{A New Algorithm for Adaptive Multidimensional + Integration}", + journal = "J. Comput. Phys.", + volume = "27", + year = "1978", + pages = "192", + doi = "10.1016/0021-9991(78)90004-9", + reportNumber = "SLAC-PUB-1839-REV, SLAC-PUB-1839", + SLACcitation = "%%CITATION = JCTPA,27,192;%%" +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Physics processes definitions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +@inproceedings{Baranov:1991yq, + author = "Baranov, S. P. and Duenger, O. and Shooshtari, H. and + Vermaseren, J. A. M.", + title = "{LPAIR: A generator for lepton pair production}", + booktitle = "{Workshop on Physics at HERA Hamburg, Germany, October + 29-30, 1991}", + year = "1991", + pages = "1478-1482", + SLACcitation = "%%CITATION = INSPIRE-326934;%%" +} + +@article{Luszczak:2018ntp, + author = "{\L{}}uszczak, Marta and Sch{\"{a}}fer, Wolfgang and Szczurek, + Antoni", + title = "{Production of $W^+ W^-$ pairs via $\gamma^*\gamma^* \to + W^+ W^-$ subprocess with photon transverse momenta}", + journal = "JHEP", + volume = "05", + year = "2018", + pages = "064", + doi = "10.1007/JHEP05(2018)064", + eprint = "1802.03244", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + SLACcitation = "%%CITATION = ARXIV:1802.03244;%%" +} + +@article{Vermaseren:1982cz, + author = "Vermaseren, J. A. M.", + title = "{Two Photon Processes at Very High-Energies}", + journal = "Nucl. Phys.", + volume = "B229", + year = "1983", + pages = "347-371", + doi = "10.1016/0550-3213(83)90336-X", + reportNumber = "NIKHEF-H/82-15", + SLACcitation = "%%CITATION = NUPHA,B229,347;%%" +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Structure functions definitions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +@article{Abramowicz:1991xz, + author = "Abramowicz, H. and Levin, E. M. and Levy, A. and Maor, + U.", + title = "{A Parametrization of $\sigma_T(\gamma^* p)$ above the + resonance region $Q^2 \gtrapprox 0$}", + journal = "Phys. Lett. B", + volume = "269", + year = "1991", + pages = "465-476", + doi = "10.1016/0370-2693(91)90202-2", + reportNumber = "DESY-91-068", + SLACcitation = "%%CITATION = PHLTA,B269,465;%%" +} + +@article{Abramowicz:1997ms, + author = "Abramowicz, H. and Levy, A.", + title = "{The ALLM parameterization of $\sigma_{\rm tot}(\gamma^* p)$: An + Update}", + year = "1997", + eprint = "hep-ph/9712415", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "DESY-97-251", + SLACcitation = "%%CITATION = HEP-PH/9712415;%%" +} + +@article{Block:2014kza, + author = "Block, Martin M. and Durand, Loyal and Ha, Phuoc", + title = "{Connection of the virtual $\gamma^*p$ cross section of + ep deep inelastic scattering to real $\gamma p$ scattering, and + the implications for $\nu N$ and $ep$ total cross sections}", + journal = "Phys. Rev.", + volume = "D89", + year = "2014", + number = "9", + pages = "094027", + doi = "10.1103/PhysRevD.89.094027", + eprint = "1404.4530", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + SLACcitation = "%%CITATION = ARXIV:1404.4530;%%" +} + +@article{Bosted:2007xd, + author = "Bosted, P. E. and Christy, M. E.", + title = "{Empirical fit to inelastic electron-deuteron and + electron-neutron resonance region transverse + cross-sections}", + journal = "Phys. Rev. C", + volume = "77", + year = "2008", + pages = "065206", + doi = "10.1103/PhysRevC.77.065206", + eprint = "0711.0159", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "JLAB-PHY-07-744", + SLACcitation = "%%CITATION = ARXIV:0711.0159;%%" +} + +@article{Brasse:1976bf, + author = "Brasse, F. W. and Flauger, W. and Gayler, Joerg and Goel, + S. P. and Haidan, R. and Merkwitz, M. and Wriedt, H.", + title = "{Parametrization of the $q^2$ dependence of $\gamma_V p$ + total cross sections in the resonance region}", + journal = "Nucl. Phys.", + volume = "B110", + year = "1976", + pages = "413-433", + doi = "10.1016/0550-3213(76)90231-5", + reportNumber = "DESY-76-11", + SLACcitation = "%%CITATION = NUPHA,B110,413;%%" +} + +@article{Fiore:2002re, + author = "Fiore, R. and Flachi, A. and Jenkovszky, Laszlo L. and + Lengyel, A. I. and Magas, V. K.", + title = "{Explicit model realizing parton hadron duality}", + journal = "Eur. Phys. J. A", + volume = "15", + year = "2002", + pages = "505-515", + doi = "10.1140/epja/i2002-10047-3", + eprint = "hep-ph/0206027", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "UNICAL-TH-06-4, UAB-FT-529", + SLACcitation = "%%CITATION = HEP-PH/0206027;%%" +} + +@article{Osipenko:2003bu, + author = "Osipenko, M. and others", + title = "{A Kinematically complete measurement of the proton + structure function F(2) in the resonance region and + evaluation of its moments}", + collaboration = "CLAS", + journal = "Phys. Rev.", + volume = "D67", + year = "2003", + pages = "092001", + doi = "10.1103/PhysRevD.67.092001", + eprint = "hep-ph/0301204", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "JLAB-PHY-03-46", + SLACcitation = "%%CITATION = HEP-PH/0301204;%%" +} + +@article{Ricco:1998yr, + author = "Ricco, G. and Simula, S. and Battaglieri, M.", + title = "{Power corrections in the longitudinal and transverse + structure functions of proton and deuteron}", + journal = "Nucl. Phys.", + volume = "B555", + year = "1999", + pages = "306-334", + doi = "10.1016/S0550-3213(99)00302-8", + eprint = "hep-ph/9901360", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + reportNumber = "INFN-RM3-98-2", + SLACcitation = "%%CITATION = HEP-PH/9901360;%%" +} + +@article{Suri:1971yx, + author = "Suri, Ashok and Yennie, Donald R.", + title = "{THE SPACE-TIME PHENOMENOLOGY OF PHOTON ABSORPTION AND + INELASTIC ELECTRON SCATTERING}", + journal = "Annals Phys.", + volume = "72", + year = "1972", + pages = "243", + doi = "10.1016/0003-4916(72)90242-4", + reportNumber = "SLAC-PUB-0954", + SLACcitation = "%%CITATION = APNYA,72,243;%%" +} + +@article{Szczurek:1999wp, + author = "Szczurek, A. and Uleshchenko, V.", + title = "{On the range of validity of the QCD improved parton + model}", + journal = "Phys. Lett.", + volume = "B475", + year = "2000", + pages = "120-126", + doi = "10.1016/S0370-2693(00)00066-6", + eprint = "hep-ph/9911467", + archivePrefix = "arXiv", + primaryClass = "hep-ph", + SLACcitation = "%%CITATION = HEP-PH/9911467;%%" +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% R modellings definitions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +@article{Abe:1998ym, + author = "Abe, K. and others", + title = "{Measurements of R = $\sigma$(L) / $\sigma$(T) for 0.03 < + x < 0.1 and fit to world data}", + collaboration = "E143", + journal = "Phys. Lett.", + volume = "B452", + year = "1999", + pages = "194-200", + doi = "10.1016/S0370-2693(99)00244-0", + eprint = "hep-ex/9808028", + archivePrefix = "arXiv", + primaryClass = "hep-ex", + reportNumber = "SLAC-PUB-7927", + SLACcitation = "%%CITATION = HEP-EX/9808028;%%" +} + +@article{Whitlow:1990gk, + author = "Whitlow, L. W. and Rock, Stephen and Bodek, A. and + Riordan, E. M. and Dasu, S.", + title = "{A Precise extraction of R = sigma-L / sigma-T from a + global analysis of the SLAC deep inelastic e p and e d + scattering cross-sections}", + journal = "Phys. Lett.", + volume = "B250", + year = "1990", + pages = "193-198", + doi = "10.1016/0370-2693(90)91176-C", + reportNumber = "SLAC-PUB-5284, UR-1102", + SLACcitation = "%%CITATION = PHLTA,B250,193;%%" +} + +@article{Sibirtsev:2013cga, + author = "Sibirtsev, A. and Blunden, P. G.", + title = "{$Q^2$ evolution of the electric and magnetic + polarizabilities of the proton}", + journal = "Phys. Rev.", + volume = "C88", + year = "2013", + number = "6", + pages = "065202", + doi = "10.1103/PhysRevC.88.065202", + eprint = "1311.6482", + archivePrefix = "arXiv", + primaryClass = "nucl-th", + SLACcitation = "%%CITATION = ARXIV:1311.6482;%%" +} + +@article{Beringer:1900zz, + author = "Beringer, J. and others", + title = "{Review of Particle Physics (RPP)}", + collaboration = "Particle Data Group", + journal = "Phys. Rev.", + volume = "D86", + year = "2012", + pages = "010001", + doi = "10.1103/PhysRevD.86.010001", + reportNumber = "SLAC-REPRINT-2014-001", + SLACcitation = "%%CITATION = PHRVA,D86,010001;%%" +} diff --git a/docs/small-cepgen-logo.png b/docs/small-cepgen-logo.png new file mode 100644 index 0000000..a34c8e6 Binary files /dev/null and b/docs/small-cepgen-logo.png differ diff --git a/CepGen/Processes/TestProcess.h b/test/TestProcess.h similarity index 93% rename from CepGen/Processes/TestProcess.h rename to test/TestProcess.h index 24c758f..f846601 100644 --- a/CepGen/Processes/TestProcess.h +++ b/test/TestProcess.h @@ -1,44 +1,44 @@ #ifndef CepGen_Processes_TestProcess_h #define CepGen_Processes_TestProcess_h #include "CepGen/Processes/GenericProcess.h" #include "CepGen/Core/Functional.h" namespace CepGen { namespace Process { /// Generic process to test the Vegas instance template<size_t N> class TestProcess : public GenericProcess { public: TestProcess() : GenericProcess( "test", ".oO TEST PROCESS Oo.", false ), funct_( "1./(1.-cos(x*_pi)*cos(y*_pi)*cos(z*_pi))", { { "x", "y", "z" } } ) {} TestProcess( const char* formula, std::array<std::string,N> args ) : GenericProcess( "test", Form( ".oO TEST PROCESS (%s) Oo.", formula ), false ), funct_( formula, args ) {} ProcessPtr clone() const override { return ProcessPtr( new TestProcess<N>( *this ) ); } void addEventContent() override {} /// Number of dimensions on which to perform the integration - unsigned int numDimensions( const Kinematics::Mode& ) const override { return N; } + unsigned int numDimensions() const override { return N; } /// Generic formula to compute a weight out of a point in the phase space double computeWeight() override { std::array<double,N> args; std::copy_n( x_.begin(), N, args.begin() ); return funct_.eval( args ); } /// Dummy function to be called on events generation void fillKinematics( bool ) override { return; } private: Functional<N> funct_; }; } } #endif diff --git a/test/TreeInfo.h b/test/TreeInfo.h index 2b83775..060c9fe 100644 --- a/test/TreeInfo.h +++ b/test/TreeInfo.h @@ -1,154 +1,181 @@ #ifndef Test_TreeInfo_h #define Test_TreeInfo_h #include "TFile.h" #include "TTree.h" #include "Math/Vector3D.h" #include "Math/Vector4D.h" #include <string> namespace CepGen { + /// All useful information about a generation run struct TreeRun { - double sqrt_s; - double xsect, errxsect; - unsigned int num_events, litigious_events; + double sqrt_s; ///< Centre of mass energy for beam particles + double xsect; ///< Process cross section, in pb + double errxsect; ///< Uncertainty on process cross section, in pb + unsigned int num_events; ///< Number of events generated in run + unsigned int litigious_events; ///< Number of litigious events in run + /// ROOT tree used for storage/retrieval of this run information TTree* tree; TreeRun() : tree( NULL ) { clear(); } + /// Reinitialise the run tree void clear() { sqrt_s = -1.; xsect = errxsect = -1.; num_events = litigious_events = 0; } + /// Populate the run tree void create() { tree = new TTree( "run", "a tree containing information on the previous run" ); if ( !tree ) return; tree->Branch( "xsect", &xsect, "xsect/D" ); tree->Branch( "errxsect", &errxsect, "errxsect/D" ); tree->Branch( "num_events", &num_events, "num_events/i" ); tree->Branch( "litigious_events", &litigious_events, "litigious_events/i" ); tree->Branch( "sqrt_s", &sqrt_s, "sqrt_s/D" ); } + /// Fill the run tree void fill() { tree->Fill(); } + /// Attach the run tree reader to a given file void attach( const char* filename, const char* run_tree = "run" ) { attach( TFile::Open( filename ), run_tree ); } + /// Attach the run tree reader to a given tree void attach( TFile* file, const char* run_tree = "run" ) { tree = dynamic_cast<TTree*>( file->Get( run_tree ) ); if ( !tree ) return; tree->SetBranchAddress( "xsect", &xsect ); tree->SetBranchAddress( "errxsect", &errxsect ); tree->SetBranchAddress( "num_events", &num_events ); tree->SetBranchAddress( "litigious_events", &litigious_events ); tree->SetBranchAddress( "sqrt_s", &sqrt_s ); if ( tree->GetEntriesFast() > 1 ) std::cerr << "The run tree has more than one entry." << std::endl; tree->GetEntry( 0 ); } }; + /// All useful information about a generated event struct TreeEvent { // book a sufficienly large number to allow the large multiplicity // of excited proton fragmentation products - static const unsigned short maxpart = 5000; - + static const unsigned short maxpart = 5000; ///< Maximal number of particles in event + /// Tree for which the event is booked TTree* tree; + /// A pointer to the file opened for storage/retrieval std::unique_ptr<TFile> file; - float gen_time, tot_time; - int nremn_ch[2], nremn_nt[2], np; + float gen_time; ///< Event generation time + float tot_time; ///< Total event generation time + int nremn_ch[2], nremn_nt[2]; + int np; ///< Number of particles in the event std::vector<ROOT::Math::XYZTVector> momentum, *pMom; - double pt[maxpart], eta[maxpart], phi[maxpart], rapidity[maxpart]; - double E[maxpart], m[maxpart], charge[maxpart]; - int pdg_id[maxpart], parent1[maxpart], parent2[maxpart]; - int stable[maxpart], role[maxpart], status[maxpart]; + double pt[maxpart]; ///< Particles transverse momentum + double eta[maxpart]; ///< Particles pseudo-rapidity + double phi[maxpart]; ///< Particles azimutal angle + double rapidity[maxpart]; ///< Particles rapidity + double E[maxpart]; ///< Particles energy, in GeV + double m[maxpart]; ///< Particles mass, in GeV/c\f${}^2\f$ + double charge[maxpart]; ///< Particles charges, in e + int pdg_id[maxpart]; ///< Integer particles PDG id + int parent1[maxpart]; ///< First particles mother + int parent2[maxpart]; ///< Last particles mother + int stable[maxpart]; ///< Whether the particle must decay or not + int role[maxpart]; ///< Particles role in the event + int status[maxpart]; ///< Integer status code TreeEvent() : tree( nullptr ), pMom( nullptr ) { clear(); } - + /// Reinitialise the event content void clear() { gen_time = tot_time = 0.; for ( unsigned short i = 0; i < 2; ++i ) nremn_ch[i] = nremn_nt[i] = 0; np = 0; momentum.clear(); for ( unsigned short i = 0; i < maxpart; ++i ) { pt[i] = eta[i] = phi[i] = rapidity[i] = E[i] = m[i] = charge[i] = 0.; pdg_id[i] = parent1[i] = parent2[i] = stable[i] = role[i] = status[i] = 0; } } + /// Fill the tree with a new event void fill() { if ( !tree ) throw std::runtime_error( "TreeEvent: Trying to fill a non-existent tree!" ); tree->Fill(); clear(); } + /// Populate the tree and all associated branches void create( TTree* t ) { tree = t; if ( !tree ) return; tree->Branch( "npart", &np, "npart/I" ); tree->Branch( "nremn_charged", nremn_ch, "nremn_charged[2]/I" ); tree->Branch( "nremn_neutral", nremn_nt, "nremn_neutral[2]/I" ); tree->Branch( "role", role, "role[npart]/I" ); pMom = &momentum; tree->Branch( "momentum", "std::vector<ROOT::Math::LorentzVector<ROOT::Math::PxPyPzE4D<double> > >", &pMom ); tree->Branch( "pt", pt, "pt[npart]/D" ); tree->Branch( "eta", eta, "eta[npart]/D" ); tree->Branch( "phi", phi, "phi[npart]/D" ); tree->Branch( "rapidity", rapidity, "rapidity[npart]/D" ); tree->Branch( "E", E, "E[npart]/D" ); tree->Branch( "m", m, "m[npart]/D" ); tree->Branch( "charge", charge, "charge[npart]/D" ); tree->Branch( "pdg_id", pdg_id, "pdg_id[npart]/I" ); tree->Branch( "parent1", parent1, "parent1[npart]/I" ); tree->Branch( "parent2", parent2, "parent2[npart]/I" ); tree->Branch( "stable", stable, "stable[npart]/I" ); tree->Branch( "status", status, "status[npart]/I" ); tree->Branch( "generation_time", &gen_time, "generation_time/F" ); tree->Branch( "total_time", &tot_time, "total_time/F" ); } + /// Attach the event tree reader to a given file void attach( const char* filename, const char* events_tree = "events" ) { file.reset( TFile::Open( filename ) ); attach( file.get(), events_tree ); } + /// Attach the event tree reader to a given ROOT file void attach( TFile* f, const char* events_tree = "events" ) { tree = dynamic_cast<TTree*>( f->Get( events_tree ) ); attach( tree ); } + /// Attach the event tree reader to a given tree void attach( TTree* t ) { tree = t; if ( !tree ) return; tree->SetBranchAddress( "npart", &np ); tree->SetBranchAddress( "nremn_charged", nremn_ch ); tree->SetBranchAddress( "nremn_neutral", nremn_ch ); tree->SetBranchAddress( "role", role ); tree->SetBranchAddress( "momentum", &pMom ); tree->SetBranchAddress( "pt", pt ); tree->SetBranchAddress( "eta", eta ); tree->SetBranchAddress( "phi", phi ); tree->SetBranchAddress( "rapidity", rapidity ); tree->SetBranchAddress( "E", E ); tree->SetBranchAddress( "m", m ); tree->SetBranchAddress( "charge", charge ); tree->SetBranchAddress( "pdg_id", pdg_id ); tree->SetBranchAddress( "parent1", parent1 ); tree->SetBranchAddress( "parent2", parent2 ); tree->SetBranchAddress( "stable", stable ); tree->SetBranchAddress( "status", status ); tree->SetBranchAddress( "generation_time", &gen_time ); tree->SetBranchAddress( "total_time", &tot_time ); } }; } #endif diff --git a/test/abort.h b/test/abort.h index 9f53a4d..5270b9e 100644 --- a/test/abort.h +++ b/test/abort.h @@ -1,52 +1,55 @@ #ifndef CepGen_Tests_abort_h #define CepGen_Tests_abort_h #include "CepGen/Core/Exception.h" #include "CepGen/Core/utils.h" #include <csignal> namespace CepGen { extern volatile int gSignal; + /// Exception raised when the user terminates the process struct RunAbortedException : Exception { using Exception::Exception; ~RunAbortedException() override {} }; } +/// Object handling an user-driven process abortion class AbortHandler { public: AbortHandler( int flags = SA_SIGINFO ) { action_.sa_sigaction = handle_ctrl_c; sigemptyset( &action_.sa_mask ); action_.sa_flags = flags; init(); } + /// Switch on/off multithreading capabilities void setMT( bool mt_on = true ) { if ( mt_on ) action_.sa_sigaction = handle_ctrl_c_mt; else action_.sa_sigaction = handle_ctrl_c; init(); } private: static void handle_ctrl_c_mt( int signal, siginfo_t*, void* ) { CepGen::gSignal = signal; } static void handle_ctrl_c( int signal, siginfo_t*, void* ) { CepGen::gSignal = signal; throw CepGen::RunAbortedException( __PRETTY_FUNCTION__, CepGen::Exception::Type::info ) << "Run aborted."; } void init() { if ( sigaction( SIGINT, &action_, nullptr ) != 0 || sigaction( SIGTERM, &action_, nullptr ) != 0 ) throw CG_FATAL( "AbortHandler" ) << "Failed to initialise the C-c handler!"; } struct sigaction action_; }; #endif diff --git a/test/test_integrator.cpp b/test/test_integrator.cpp index 419dc6b..ba5f523 100644 --- a/test/test_integrator.cpp +++ b/test/test_integrator.cpp @@ -1,53 +1,53 @@ #include "CepGen/Generator.h" #include "CepGen/Parameters.h" -#include "CepGen/Processes/TestProcess.h" +#include "TestProcess.h" #include <iostream> using namespace std; int main( int argc, char* argv[] ) { if ( argc < 3 || string( argv[2] ) != "debug" ) CepGen::Logger::get().level = CepGen::Logger::Level::nothing; const double max_sigma = 3.0; CepGen::Generator mg; if ( argc > 1 && string( argv[1] ) == "plain" ) mg.parameters->integrator.type = CepGen::Integrator::Type::plain; if ( argc > 1 && string( argv[1] ) == "vegas" ) mg.parameters->integrator.type = CepGen::Integrator::Type::Vegas; if ( argc > 1 && string( argv[1] ) == "miser" ) mg.parameters->integrator.type = CepGen::Integrator::Type::MISER; double result, error; { // test 1 const double exact = 1.3932039296856768591842462603255; mg.parameters->setProcess( new CepGen::Process::TestProcess<3> ); mg.computeXsection( result, error ); if ( fabs( exact - result ) > max_sigma * error ) throw CG_FATAL( "main" ) << "pull = " << fabs( exact-result )/error << "."; cout << "Test 1 passed!" << endl; } { // test 2 const double exact = 2./3.; mg.parameters->setProcess( new CepGen::Process::TestProcess<2>( "x^2+y^2", { { "x", "y" } } ) ); mg.computeXsection( result, error ); if ( fabs( exact - result ) > max_sigma * error ) throw CG_FATAL( "main" ) << "pull = " << fabs( exact-result )/error << "."; cout << "Test 2 passed!" << endl; } { // test 3 const double exact = 13./12.; mg.parameters->setProcess( new CepGen::Process::TestProcess<3>( "x+y^2+z^3", { { "x", "y", "z" } } ) ); mg.computeXsection( result, error ); if ( fabs( exact - result ) > max_sigma * error ) throw CG_FATAL( "main" ) << "pull = " << fabs( exact-result )/error << "."; cout << "Test 3 passed!" << endl; } return 0; } diff --git a/test/test_physics_processes.cpp b/test/test_physics_processes.cpp index 3bbae77..bf7d458 100644 --- a/test/test_physics_processes.cpp +++ b/test/test_physics_processes.cpp @@ -1,211 +1,211 @@ #include "CepGen/Generator.h" #include "CepGen/Parameters.h" #include "CepGen/Core/ParametersList.h" #include "CepGen/Core/Timer.h" #include "CepGen/Processes/GamGamLL.h" #include "CepGen/Processes/PPtoFF.h" #include "CepGen/Processes/PPtoWW.h" #include "CepGen/StructureFunctions/StructureFunctionsBuilder.h" #include "CepGen/StructureFunctions/StructureFunctions.h" #include "CepGen/Physics/PDG.h" #include "abort.h" #include <unordered_map> #include <assert.h> #include <string.h> #include <math.h> using namespace std; int main( int argc, char* argv[] ) { typedef vector<pair<const char*,pair<double,double> > > KinematicsMap; typedef vector<pair<float, KinematicsMap> > ValuesAtCutMap; AbortHandler ctrl_c; // values defined at pt(single lepton)>15 GeV, |eta(single lepton)|<2.5, mX<1000 GeV // process -> { pt cut -> { kinematics -> ( sigma, delta(sigma) ) } } vector<pair<const char*,ValuesAtCutMap> > values_map = { //--- LPAIR values at sqrt(s) = 13 TeV { "lpair", { { 3.0, { // pt cut { "elastic", { 2.0871703e1, 3.542e-2 } }, { "singlediss", { 1.5042536e1, 3.256e-2 } }, { "doublediss", { 1.38835e1, 4.03018e-2 } } } }, { 15.0, { // pt cut { "elastic", { 4.1994803e-1, 8.328e-4 } }, { "singlediss", { 4.8504819e-1, 1.171e-3 } }, { "doublediss", { 6.35650e-1, 1.93968e-3 } } } }, } }, //--- PPtoLL values { "pptoll", { { 3.0, { // pt cut { "elastic", { 2.0936541e1, 1.4096e-2 } }, { "singlediss_su", { 1.4844881e1, 2.0723e-2 } }, // SU, qt<50 { "doublediss_su", { 1.3580637e1, 2.2497e-2 } }, // SU, qt<50 } }, { 15.0, { // pt cut { "elastic", { 4.2515888e-1, 3.0351e-4 } }, { "singlediss_su", { 4.4903253e-1, 5.8970e-4 } }, // SU, qt<50 { "doublediss_su", { 5.1923819e-1, 9.6549e-4 } }, // SU, qt<50 /*{ "2_singlediss", { 4.6710287e-1, 6.4842e-4 } }, // SU, qt<500 { "3_doublediss", { 5.6316353e-1, 1.1829e-3 } }, // SU, qt<500*/ } }, } }, //--- PPtoWW values { "pptoww", { { 0.0, { // pt cut { "elastic", { 0.273, 0.01 } }, { "elastic", { 0.273, 0.01 } }, // FIXME { "singlediss_lux", { 0.409, 0.01 } }, { "doublediss_lux", { 1.090, 0.01 } }, { "singlediss_allm", { 0.318, 0.01 } }, { "doublediss_allm", { 0.701, 0.01 } } } } } }, }; const double num_sigma = 3.0; if ( argc < 3 || strcmp( argv[2], "debug" ) != 0 ) CepGen::Logger::get().level = CepGen::Logger::Level::nothing; CepGen::Timer tmr; CepGen::Generator mg; if ( argc > 1 && strcmp( argv[1], "plain" ) == 0 ) mg.parameters->integrator.type = CepGen::Integrator::Type::plain; if ( argc > 1 && strcmp( argv[1], "vegas" ) == 0 ) mg.parameters->integrator.type = CepGen::Integrator::Type::Vegas; if ( argc > 1 && strcmp( argv[1], "miser" ) == 0 ) mg.parameters->integrator.type = CepGen::Integrator::Type::MISER; { cout << "Testing with " << mg.parameters->integrator.type << " integrator" << endl; } mg.parameters->kinematics.setSqrtS( 13.e3 ); mg.parameters->kinematics.cuts.central.eta_single.in( -2.5, 2.5 ); mg.parameters->kinematics.cuts.remnants.mass_single.max() = 1000.; //mg.parameters->integrator.ncvg = 50000; CG_INFO( "main" ) << "Initial configuration time: " << tmr.elapsed()*1.e3 << " ms."; tmr.reset(); unsigned short num_tests = 0, num_tests_passed = 0; vector<string> failed_tests, passed_tests; try { for ( const auto& values_vs_generator : values_map ) { // loop over all generators CepGen::ParametersList param; const string generator = values_vs_generator.first; if ( generator == "lpair" ) { param.set<int>( "pair", 13 ); mg.parameters->setProcess( new CepGen::Process::GamGamLL( param ) ); } else if ( generator == "pptoll" ) { param.set<int>( "pair", 13 ); mg.parameters->setProcess( new CepGen::Process::PPtoFF( param ) ); mg.parameters->kinematics.cuts.initial.qt = { 0., 50. }; } else if ( generator == "pptoww" ) { mg.parameters->setProcess( new CepGen::Process::PPtoWW ); mg.parameters->kinematics.setSqrtS( 13.e3 ); //mg.parameters->kinematics.cuts.initial.qt = { 0., 50. }; } else { CG_ERROR( "main" ) << "Unrecognized generator mode: " << values_vs_generator.first << "."; break; } for ( const auto& values_vs_cut : values_vs_generator.second ) { // loop over the single lepton pT cut mg.parameters->kinematics.cuts.central.pt_single.min() = values_vs_cut.first; for ( const auto& values_vs_kin : values_vs_cut.second ) { // loop over all possible kinematics const string kin_mode = values_vs_kin.first; if ( kin_mode.find( "elastic" ) != string::npos ) - mg.parameters->kinematics.mode = CepGen::Kinematics::Mode::ElasticElastic; + mg.parameters->kinematics.mode = CepGen::KinematicsMode::ElasticElastic; else if ( kin_mode.find( "singlediss" ) != string::npos ) - mg.parameters->kinematics.mode = CepGen::Kinematics::Mode::InelasticElastic; + mg.parameters->kinematics.mode = CepGen::KinematicsMode::InelasticElastic; else if ( kin_mode.find( "doublediss" ) != string::npos ) - mg.parameters->kinematics.mode = CepGen::Kinematics::Mode::InelasticInelastic; + mg.parameters->kinematics.mode = CepGen::KinematicsMode::InelasticInelastic; else { CG_ERROR( "main" ) << "Unrecognized kinematics mode: " << values_vs_kin.first << "."; break; } if ( kin_mode.find( "_su" ) != string::npos ) mg.parameters->kinematics.structure_functions = CepGen::StructureFunctionsBuilder::get( CepGen::SF::Type::SzczurekUleshchenko ); else if ( kin_mode.find( "_lux" ) != string::npos ) mg.parameters->kinematics.structure_functions = CepGen::StructureFunctionsBuilder::get( CepGen::SF::Type::Schaefer ); else if ( kin_mode.find( "_allm" ) != string::npos ) mg.parameters->kinematics.structure_functions = CepGen::StructureFunctionsBuilder::get( CepGen::SF::Type::ALLM97 ); else mg.parameters->kinematics.structure_functions = CepGen::StructureFunctionsBuilder::get( CepGen::SF::Type::SuriYennie ); //CG_INFO( "main" ) << mg.parameters.get(); CG_INFO( "main" ) << "Process: "<< values_vs_generator.first << "/" << values_vs_kin.first << "\n\t" << "Configuration time: " << tmr.elapsed()*1.e3 << " ms."; tmr.reset(); mg.clearRun(); const double xsec_ref = values_vs_kin.second.first; const double err_xsec_ref = values_vs_kin.second.second; double xsec_cepgen, err_xsec_cepgen; mg.computeXsection( xsec_cepgen, err_xsec_cepgen ); const double sigma = fabs( xsec_ref-xsec_cepgen ) / std::hypot( err_xsec_cepgen, err_xsec_ref ); CG_INFO( "main" ) << "Computed cross section:\n\t" << "Ref. = " << xsec_ref << " +/- " << err_xsec_ref << "\n\t" << "CepGen = " << xsec_cepgen << " +/- " << err_xsec_cepgen << "\n\t" << "Pull: " << sigma << "."; CG_INFO( "main" ) << "Computation time: " << tmr.elapsed()*1.e3 << " ms."; tmr.reset(); ostringstream oss; oss << values_vs_kin.first; string test_res = CepGen::Form( "%-10s", values_vs_generator.first )+"\t"+ CepGen::Form( "pt-gt-%.1f", values_vs_cut.first )+"\t"+ CepGen::Form( "%-16s", oss.str().c_str() )+"\t" "ref="+CepGen::Form( "%g", xsec_ref )+"\t" "got="+CepGen::Form( "%g", xsec_cepgen )+"\t" "pull="+CepGen::Form( "%+g", sigma ); if ( fabs( sigma ) < num_sigma ) { passed_tests.emplace_back( test_res ); num_tests_passed++; } else failed_tests.emplace_back( test_res ); num_tests++; cout << "Test " << num_tests_passed << "/" << num_tests << " passed!" << endl; } } } } catch ( CepGen::Exception& e ) {} if ( failed_tests.size() != 0 ) { ostringstream os_failed, os_passed; for ( const auto& fail : failed_tests ) os_failed << " (*) " << fail << endl; for ( const auto& pass : passed_tests ) os_passed << " (*) " << pass << endl; throw CG_FATAL( "main" ) << "Some tests failed!\n" << os_failed.str() << "\n" << "Passed tests:\n" << os_passed.str() << "."; } CG_INFO( "main" ) << "ALL TESTS PASSED!"; return 0; }